Console Library 8.0.0
A header-only library that makes C++ simple
Loading...
Searching...
No Matches
box.h
Go to the documentation of this file.
1
8
9/*
10Copyright (c) 2026 MrXie1109
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions:
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29*/
30
31#pragma once
32#include <cstdlib>
33#include <memory>
34#include <ostream>
35#include <type_traits>
36#include <typeinfo>
37#include <utility>
38#include <vector>
39
40#include "../core/csexc.h"
41#include "../text/repr.h"
42#include "../text/strpp.h"
43
44namespace console {
51 class Item {
52 private:
54 struct Base {
55 virtual ~Base() {}
56 virtual Base *clone() const = 0;
57 virtual void print(std::ostream &) const = 0;
58 virtual void print(std::wostream &) const = 0;
59 virtual std::string str() const = 0;
60 virtual std::wstring wstr() const = 0;
61 virtual const std::type_info &type() const = 0;
62 };
63
68 template <typename T>
69 struct Derived : Base {
71
76 Derived(const T &v) : value(v) {}
77
82 Derived(T &&v) : value(std::move(v)) {}
83
88 Base *clone() const override { return new Derived(value); }
89
94 void print(std::ostream &os) const override { repr(value, os); }
95 void print(std::wostream &os) const override {
96 auto s = str();
97 os << std::wstring(s.begin(), s.end());
98 }
99
104 std::string str() const override {
105 std::ostringstream oss;
106 repr(value, oss);
107 return oss.str();
108 }
109
110 std::wstring wstr() const override {
111 auto s = str();
112 return std::wstring(s.begin(), s.end());
113 }
114
119 const std::type_info &type() const override { return typeid(T); }
120 };
121
123
124 public:
126 Item() : ptr(nullptr) {}
127
133 template <class T,
134 class = typename std::enable_if<
135 !std::is_same<typename std::decay<T>::type, Item>::value>::type>
136 Item(T &&value) :
137 ptr(new Derived<typename std::decay<T>::type>(
138 std::forward<T>(value))) {}
139
144 Item(const Item &other) :
145 ptr(other.ptr ? other.ptr->clone() : nullptr) {}
146
151 Item(Item &&other) noexcept : ptr(other.ptr) { other.ptr = nullptr; }
152
159 template <class T>
160 T &get() {
161 if (ptr == nullptr) throw TypeError("empty item");
162 if (typeid(T) != ptr->type())
163 throw TypeError(std::string("type mismatch: ")
164 + tiname(typeid(T)) + " and "
165 + tiname(ptr->type()));
166 return ((Derived<T> *)ptr)->value;
167 }
168
175 template <class T>
177 return ((Derived<T> *)ptr)->value;
178 }
179
186 template <class T>
187 const T &get() const {
188 if (ptr == nullptr) throw TypeError("empty item");
189 if (typeid(T) != ptr->type())
190 throw TypeError(std::string("type mismatch: ")
191 + typeid(T).name() + " and "
192 + ptr->type().name());
193 return ((Derived<T> *)ptr)->value;
194 }
195
202 template <class T>
203 const T &unsafe_get() const {
204 return ((Derived<T> *)ptr)->value;
205 }
206
212 const Item &operator=(const Item &other) {
213 if (this != &other) {
214 Base *new_ptr = other.ptr ? other.ptr->clone() : nullptr;
215 delete ptr;
216 ptr = new_ptr;
217 }
218 return *this;
219 }
220
226 const Item &operator=(Item &&other) noexcept {
227 if (this != &other) {
228 delete ptr;
229 ptr = other.ptr;
230 other.ptr = nullptr;
231 }
232 return *this;
233 }
234
241 friend std::ostream &operator<<(std::ostream &os, const Item &item) {
242 item.ptr->print(os);
243 return os;
244 }
245
252 friend std::wostream &operator<<(std::wostream &os, const Item &item) {
253 item.ptr->print(os);
254 return os;
255 }
256
261 std::string str() const { return ptr->str(); }
262 std::wstring wstr() const { return ptr->wstr(); }
263
265 ~Item() { delete ptr; }
266 };
267
274 class Box : public std::vector<Item> {
275 public:
281 template <class... Args>
282 explicit Box(Args &&...args) {
283 int _[] = {0, (emplace_back(std::forward<Args>(args)), 0)...};
284 (void)_;
285 }
286
295 template <class T>
296 T &get(size_t index) {
297 if (index >= size()) throw IndexError("index out of range");
298 return std::vector<Item>::operator[](index).get<T>();
299 }
300
309 template <class T>
310 const T &get(size_t index) const {
311 if (index >= size()) throw IndexError("index out of range");
312 return std::vector<Item>::operator[](index).get<T>();
313 }
314
322 template <class T>
323 T &unsafe_get(size_t index) {
324 return std::vector<Item>::operator[](index).unsafe_get<T>();
325 }
326
334 template <class T>
335 const T &unsafe_get(size_t index) const {
336 return std::vector<Item>::operator[](index).unsafe_get<T>();
337 }
338
345 template <class... Args>
346 void unpack(Args &...args) const {
347 if (sizeof...(Args) != size())
348 throw TypeError("unpack: argument count mismatch");
349 size_t i = 0;
350 int _[] = {0, ((args = get<Args>(i++)), 0)...};
351 (void)_;
352 }
353
360 template <class... Args>
361 void unsafe_unpack(Args &...args) const {
362 size_t i = 0;
363 int _[] = {0, ((args = unsafe_get<Args>(i++)), 0)...};
364 (void)_;
365 }
366
373 friend std::ostream &operator<<(std::ostream &os, const Box &box) {
374 if (box.empty()) return os << "()";
375 auto it = box.begin();
376 os << '(' << *it;
377 while (++it != box.end()) os << ", " << *it;
378 return os << ')';
379 }
380
387 friend std::wostream &operator<<(std::wostream &os, const Box &box) {
388 if (box.empty()) return os << L"()";
389 auto it = box.begin();
390 os << L'(' << *it;
391 while (++it != box.end()) os << L", " << *it;
392 return os << L')';
393 }
394 };
395}
void unpack(Args &...args) const
将 Box 中的元素按顺序解包到多个变量中(类型安全)。
Definition box.h:346
T & get(size_t index)
类型安全地获取指定索引处的元素(非常量版本)。
Definition box.h:296
Box(Args &&...args)
从任意数量、任意类型的值构造 Box。
Definition box.h:282
friend std::wostream & operator<<(std::wostream &os, const Box &box)
将 Box 输出到宽字符流。
Definition box.h:387
friend std::ostream & operator<<(std::ostream &os, const Box &box)
将 Box 输出到流,格式类似于元组 (elem1, elem2, ...)。
Definition box.h:373
void unsafe_unpack(Args &...args) const
将 Box 中的元素按顺序解包到多个变量中(不安全版本)。
Definition box.h:361
const T & get(size_t index) const
类型安全地获取指定索引处的元素(常量版本)。
Definition box.h:310
T & unsafe_get(size_t index)
不安全地获取指定索引处的元素(非常量版本)。
Definition box.h:323
const T & unsafe_get(size_t index) const
不安全地获取指定索引处的元素(常量版本)。
Definition box.h:335
IndexError(const std::string &msg)
构造 IndexError。
Definition csexc.h:153
可存储任意类型单个对象的类型擦除包装器。
Definition box.h:51
T & unsafe_get()
不安全地获取存储值的引用(非常量版本)。
Definition box.h:176
Item(Item &&other) noexcept
移动构造函数。
Definition box.h:151
friend std::ostream & operator<<(std::ostream &os, const Item &item)
将 Item 输出到流。
Definition box.h:241
~Item()
析构函数,释放内部堆内存。
Definition box.h:265
Item()
默认构造一个空 Item(ptr 为 nullptr)。
Definition box.h:126
const T & get() const
类型安全地获取存储值的引用(常量版本)。
Definition box.h:187
Item(const Item &other)
拷贝构造函数。
Definition box.h:144
T & get()
类型安全地获取存储值的引用(非常量版本)。
Definition box.h:160
const Item & operator=(const Item &other)
拷贝赋值运算符。
Definition box.h:212
std::string str() const
返回 Item 的字符串表示。
Definition box.h:261
const Item & operator=(Item &&other) noexcept
移动赋值运算符。
Definition box.h:226
std::wstring wstr() const
Definition box.h:262
friend std::wostream & operator<<(std::wostream &os, const Item &item)
将 Item 输出到宽字符流。
Definition box.h:252
const T & unsafe_get() const
不安全地获取存储值的引用(常量版本)。
Definition box.h:203
Base * ptr
指向实际存储数据的指针(堆上对象)。
Definition box.h:122
Item(T &&value)
从任意类型构造 Item(万能引用)。
Definition box.h:136
TypeError(const std::string &msg)
构造 TypeError。
Definition csexc.h:102
定义 console 库使用的自定义异常类层次结构。
std::enable_if< is_string< typenamestd::decay< T >::type >::value >::type repr(T &&value, std::basic_ostream< CharT, Traits > &os=std::cout)
输出字符串类型(std::string, const char* 等)的表示,带双引号。
Definition repr.h:97
std::string tiname(const std::type_info &ti)
tiname_impl 的 char 版别名。
Definition repr.h:74
本库所有组件所在的顶层命名空间。
@ T
Definition kb.h:99
@ L
Definition kb.h:91
提供类似 Python 的 repr() 函数,用于生成对象的可读字符串表示。
提供字符串处理工具函数和格式化类。
虚基类,定义了所有派生类必须实现的接口。
Definition box.h:54
virtual std::wstring wstr() const =0
virtual const std::type_info & type() const =0
virtual void print(std::ostream &) const =0
virtual void print(std::wostream &) const =0
virtual Base * clone() const =0
virtual std::string str() const =0
virtual ~Base()
Definition box.h:55
模板派生类,具体存储类型 T 的值。
Definition box.h:69
void print(std::wostream &os) const override
Definition box.h:95
std::string str() const override
返回存储值的字符串表示。
Definition box.h:104
T value
实际存储的值
Definition box.h:70
Base * clone() const override
克隆当前对象(堆上分配)。
Definition box.h:88
Derived(const T &v)
从左值构造 Derived。
Definition box.h:76
void print(std::ostream &os) const override
将存储的值输出到流(使用 repr 函数)。
Definition box.h:94
const std::type_info & type() const override
获取存储值的类型信息。
Definition box.h:119
Derived(T &&v)
从右值构造 Derived。
Definition box.h:82
std::wstring wstr() const override
Definition box.h:110