14 template<
class Subclass,
szt id,
class... Types>
class variant;
17 template<
class Subclass,
szt id,
class Type,
class... Types>
18 class variant<Subclass, id, Type, Types...> :
public variant<Subclass, id+1, Types...>
20 typedef variant<Subclass,
id+1, Types...> Super;
21 typedef typename std::remove_const<Type>::type Type_mutable;
23 operator Type&() {
return this->subc().template get<Type>(); }
24 operator const Type&()
const {
return this->subc().template get<const Type>(); }
27 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_copy_constructible<Type>::value,
int>::type=0>
28 void construct(
const Type_mutable& val) { construct_(val); }
29 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_copy_constructible<Type>::value,
int>::type=0>
30 void construct(Type_mutable& val) { construct_(val); }
31 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_move_constructible<Type>::value,
int>::type=0>
32 void construct(Type_mutable&& val) { construct_(move(val)); }
34 void construct(T&& val) { Super::construct(forward<T>(val)); }
36 template<
class... Args,
typename std::enable_if<std::is_constructible<Type, Args...>::value,
int>::type=0>
37 void construct_convert(Args&&... args) { construct_(forward<Args>(args)...); }
38 template<
class... Args,
typename mt::disable_if<std::is_constructible<Type, Args...>::value,
int>::type=0>
39 void construct_convert(Args&&... args) { Super::construct_convert(forward<Args>(args)...); }
41 void destroy() { _id() ==
id ? _val().~Type() : Super::destroy(); }
43 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_copy_assignable<Type>::value,
int>::type=0>
44 void assign(
const Type_mutable& val) {
if (_id() !=
id) assign_new(val);
else _val() = val; }
45 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_copy_assignable<Type>::value,
int>::type=0>
46 void assign(Type_mutable& val) {
if (_id() !=
id) assign_new(val);
else _val() = val; }
47 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_move_assignable<Type>::value,
int>::type=0>
48 void assign(Type_mutable&& val) {
if (_id() !=
id) assign_new(move(val));
else _val() = move(val); }
50 void assign(T&& val) { Super::assign(forward<T>(val)); }
52 template<class T, typename std::enable_if<std::is_assignable<Type&, T>::value && std::is_constructible<Type, T>::value,
int>::type=0>
53 void assign_convert(T&& val) {
if (_id() !=
id) assign_new(forward<T>(val));
else _val() = forward<T>(val); }
54 template<class T, typename mt::disable_if<std::is_assignable<Type&, T>::value && std::is_constructible<Type, T>::value,
int>::type=0>
55 void assign_convert(T&& val) { Super::assign_convert(forward<T>(val)); }
57 template<szt
id_, szt=0>
58 struct Type_ : Super::template Type_<id_> {};
59 template<szt _>
struct Type_<id,
_> {
typedef Type type; };
61 template<
class R,
class Func,
class... Args,
typename std::enable_if<mt::isCallable<Func, Type&, Args...>::value,
int>::type=0>
62 R visit(Func&& f, Args&&... args) {
if (_id() ==
id)
return f(_val(), forward<Args>(args)...);
else return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
63 template<
class R,
class Func,
class... Args,
typename mt::disable_if<mt::isCallable<Func, Type&, Args...>::value,
int>::type=0>
64 R visit(Func&& f, Args&&... args) {
return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
66 template<
class R,
class Func,
class... Args,
typename std::enable_if<mt::isCallable<Func,
const Type&, Args...>::value,
int>::type=0>
67 R visit(Func&& f, Args&&... args)
const {
if (_id() ==
id)
return f(_val(), forward<Args>(args)...);
else return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
68 template<
class R,
class Func,
class... Args,
typename mt::disable_if<mt::isCallable<Func,
const Type&, Args...>::value,
int>::type=0>
69 R visit(Func&& f, Args&&... args)
const {
return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
71 template<
class Func,
class... Args,
typename std::enable_if<mt::isCallable<Func, Type&, Args...>::value,
int>::type=0>
72 void visit(Func&& f, Args&&... args) {
if (_id() ==
id) f(_val(), forward<Args>(args)...);
else Super::visit(forward<Func>(f), forward<Args>(args)...); }
73 template<
class Func,
class... Args,
typename mt::disable_if<mt::isCallable<Func, Type&, Args...>::value,
int>::type=0>
74 void visit(Func&& f, Args&&... args) { Super::visit(forward<Func>(f), forward<Args>(args)...); }
76 template<
class Func,
class... Args,
typename std::enable_if<mt::isCallable<Func,
const Type&, Args...>::value,
int>::type=0>
77 void visit(Func&& f, Args&&... args)
const {
if (_id() ==
id) f(_val(), forward<Args>(args)...);
else Super::visit(forward<Func>(f), forward<Args>(args)...); }
78 template<
class Func,
class... Args,
typename mt::disable_if<mt::isCallable<Func,
const Type&, Args...>::value,
int>::type=0>
79 void visit(Func&& f, Args&&... args)
const { Super::visit(forward<Func>(f), forward<Args>(args)...); }
82 szt& _id() {
return this->subc()._id; }
83 const szt& _id()
const {
return this->subc()._id; }
84 void* _storage() {
return &this->subc()._storage; }
85 const void* _storage()
const {
return &this->subc()._storage; }
86 Type& _val() {
assert(_id() ==
id,
"Value not initialized");
return *
reinterpret_cast<Type*
>(_storage()); }
87 const Type& _val()
const {
assert(_id() ==
id,
"Value not initialized");
return *
reinterpret_cast<const Type*
>(_storage()); }
89 template<
class... Args>
90 void construct_(Args&&... args) { _id() = id;
new (_storage()) Type(forward<Args>(args)...); }
92 template<
class T>
void assign_new(T&& val) { this->subc().destroy(); construct_(forward<T>(val)); }
96 template<
class Subclass,
szt id,
class Type,
class... Types>
97 class variant<Subclass, id, Type&, Types...> :
public variant<Subclass,
id+1, Types...>
99 typedef variant<Subclass,
id+1, Types...> Super;
100 typedef typename std::remove_const<Type>::type Type_mutable;
102 operator Type&() {
return this->subc().template get<Type>(); }
103 operator const Type&()
const {
return this->subc().template get<const Type>(); }
106 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_const<Type>::value,
int>::type=0>
107 void construct(
const Type_mutable& val) { construct_(val); }
108 void construct(Type_mutable& val) { construct_(val); }
109 void construct(Type_mutable&& val) { construct_(move(val)); }
111 void construct(T&& val) { Super::construct(forward<T>(val)); }
113 template<class T, typename std::enable_if<std::is_convertible<typename mt::addPtr<T>::type, Type*>::value,
int>::type=0>
114 void construct_convert(T&& val) { construct_(forward<T>(val)); }
115 template<
class... Args>
116 void construct_convert(Args&&... args) { Super::construct_convert(forward<Args>(args)...); }
118 void destroy() {
if (_id() ==
id) _ptr() =
nullptr;
else Super::destroy(); }
120 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_const<Type>::value,
int>::type=0>
121 void bind(
const Type_mutable& val) { bind_(val); }
122 void bind(Type_mutable& val) { bind_(val); }
123 void bind(Type_mutable&& val) { bind_(move(val)); }
125 void bind(T&& val) { Super::bind(forward<T>(val)); }
127 template<class T, typename std::enable_if<std::is_convertible<typename mt::addPtr<T>::type, Type*>::value,
int>::type=0>
128 void bind_convert(T&& val) { bind_(forward<T>(val)); }
129 template<class T, typename mt::disable_if<std::is_convertible<typename mt::addPtr<T>::type, Type*>::value,
int>::type=0>
130 void bind_convert(T&& val) { Super::bind_convert(forward<T>(val)); }
132 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_copy_assignable<Type>::value,
int>::type=0>
133 void assign(
const Type_mutable& val) { _val() = val; }
134 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_copy_assignable<Type>::value,
int>::type=0>
135 void assign(Type_mutable& val) { _val() = val; }
136 template<class _=void, typename std::enable_if<mt::True<_>::value && std::is_move_assignable<Type>::value,
int>::type=0>
137 void assign(Type_mutable&& val) { _val() = move(val); }
139 void assign(T&& val) { Super::assign(forward<T>(val)); }
141 template<class T, typename std::enable_if<std::is_assignable<Type&, T>::value,
int>::type=0>
142 void assign_convert(T&& val) { _val() = forward<T>(val); }
143 template<class T, typename mt::disable_if<std::is_assignable<Type&, T>::value,
int>::type=0>
144 void assign_convert(T&& val) { Super::assign_convert(forward<T>(val)); }
146 template<szt
id_, szt=0>
147 struct Type_ : Super::template Type_<id_> {};
148 template<szt _>
struct Type_<id,
_> {
typedef Type& type; };
150 template<
class R,
class Func,
class... Args,
typename std::enable_if<mt::isCallable<Func, Type&, Args...>::value,
int>::type=0>
151 R visit(Func&& f, Args&&... args) {
if (_id() ==
id)
return f(_val(), forward<Args>(args)...);
else return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
152 template<
class R,
class Func,
class... Args,
typename mt::disable_if<mt::isCallable<Func, Type&, Args...>::value,
int>::type=0>
153 R visit(Func&& f, Args&&... args) {
return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
155 template<
class R,
class Func,
class... Args,
typename std::enable_if<mt::isCallable<Func,
const Type&, Args...>::value,
int>::type=0>
156 R visit(Func&& f, Args&&... args)
const {
if (_id() ==
id)
return f(_val(), forward<Args>(args)...);
else return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
157 template<
class R,
class Func,
class... Args,
typename mt::disable_if<mt::isCallable<Func,
const Type&, Args...>::value,
int>::type=0>
158 R visit(Func&& f, Args&&... args)
const {
return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
160 template<
class Func,
class... Args,
typename std::enable_if<mt::isCallable<Func, Type&, Args...>::value,
int>::type=0>
161 void visit(Func&& f, Args&&... args) {
if (_id() ==
id) f(_val(), forward<Args>(args)...);
else Super::visit(forward<Func>(f), forward<Args>(args)...); }
162 template<
class Func,
class... Args,
typename mt::disable_if<mt::isCallable<Func, Type&, Args...>::value,
int>::type=0>
163 void visit(Func&& f, Args&&... args) { Super::visit(forward<Func>(f), forward<Args>(args)...); }
165 template<
class Func,
class... Args,
typename std::enable_if<mt::isCallable<Func,
const Type&, Args...>::value,
int>::type=0>
166 void visit(Func&& f, Args&&... args)
const {
if (_id() ==
id) f(_val(), forward<Args>(args)...);
else Super::visit(forward<Func>(f), forward<Args>(args)...); }
167 template<
class Func,
class... Args,
typename mt::disable_if<mt::isCallable<Func,
const Type&, Args...>::value,
int>::type=0>
168 void visit(Func&& f, Args&&... args)
const { Super::visit(forward<Func>(f), forward<Args>(args)...); }
171 szt& _id() {
return this->subc()._id; }
172 const szt& _id()
const {
return this->subc()._id; }
173 Type*& _ptr() {
assert(_id() ==
id,
"Reference not bound");
return reinterpret_cast<Type*&
>(this->subc()._storage); }
174 Type*
const& _ptr()
const {
assert(_id() ==
id,
"Reference not bound");
return reinterpret_cast<Type* const&
>(this->subc()._storage); }
175 Type& _val() {
assert(_ptr(),
"Reference not bound");
return *_ptr(); }
176 const Type& _val()
const {
assert(_ptr(),
"Reference not bound");
return *_ptr(); }
178 template<
class T>
void construct_(T&& val) { _id() = id; _ptr() = &val; }
179 template<
class T>
void bind_(T&& val) { this->subc().destroy(); construct_(forward<T>(val)); }
183 template<
class Sub
class, szt
id>
184 class variant<Subclass, id>
188 const Subclass& subc()
const {
return static_cast<const Subclass&
>(*this); }
189 Subclass& subc() {
return static_cast<Subclass&
>(*this); }
192 void construct(T&& val) { subc().construct_convert(forward<T>(val)); }
193 template<
class... Args>
194 void construct_convert(Args&&...) { static_assert(!mt::True<Args...>::value,
"No bounded types constructible with args"); }
196 void destroy() {
error_(
"Should not get here, variant destruction failed"); }
198 template<
class T>
void bind(T&& val) { subc().bind_convert(forward<T>(val)); }
199 template<
class T>
void bind_convert(T&&) { static_assert(!mt::True<T>::value,
"No bounded reference types can bind to type"); }
201 template<
class T>
void assign(T&& val) { subc().assign_convert(forward<T>(val)); }
202 template<
class T>
void assign_convert(T&&) { static_assert(!mt::True<T>::value,
"No bounded types assignable to value"); }
205 template<szt
id_>
struct Type_ { static_assert(!mt::True_int<id_>::value,
"Invalid type id"); };
207 template<
class R,
class Func,
class... Args>
208 R visit(Func&&, Args&&...) {
throw_ VariantError() <<
"Visitor failed to accept active bounded type";
throw; }
209 template<
class R,
class Func,
class... Args>
210 R visit(Func&&, Args&&...)
const {
throw_ VariantError() <<
"Visitor failed to accept active bounded type";
throw; }
212 template<
class Func,
class... Args>
213 void visit(Func&&, Args&&...) {}
214 template<
class Func,
class... Args>
215 void visit(Func&&, Args&&...)
const {}
229 template<
class... Types>
230 class variant :
public priv::variant<variant<Types...>, 0, Types...>
243 variant(T&& val) { this->construct(forward<T>(val)); }
245 template<
class... Args>
246 variant(Args&&... args) { this->construct_convert(forward<Args>(args)...); }
249 variant(variant&& rhs) { rhs.visit(ctorMove(), *
this); }
257 template<
class T>
void bind(T&& val) { Super::bind(forward<T>(val)); }
267 variant&
operator=(T&& val) { this->assign(forward<T>(val));
return *
this; }
268 variant&
operator=(
const variant& rhs) { rhs.
visit(assignCopy(), *
this);
return *
this; }
269 variant&
operator=(variant& rhs) { rhs.
visit(assignCopy(), *
this);
return *
this; }
270 variant&
operator=(variant&& rhs) { rhs.
visit(assignMove(), *
this);
return *
this; }
278 struct Type : Super::template Type_<id> {};
284 T&
get() {
return visit<T&>([](T& val) -> T& {
return val; }); }
286 const T&
get()
const {
return visit<const T&>([](
const T& val) ->
const T& {
return val; }); }
292 template<
class R,
class Func,
class... Args>
293 R
visit(Func&& f, Args&&... args) {
return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
294 template<
class R,
class Func,
class... Args>
295 R
visit(Func&& f, Args&&... args)
const {
return Super::template visit<R>(forward<Func>(f), forward<Args>(args)...); }
298 template<
class Func,
class... Args>
299 void visit(Func&& f, Args&&... args) { Super::visit(forward<Func>(f), forward<Args>(args)...); }
300 template<
class Func,
class... Args>
301 void visit(Func&& f, Args&&... args)
const { Super::visit(forward<Func>(f), forward<Args>(args)...); }
303 friend ostream&
operator<<(ostream& os,
const variant& rhs) { rhs.
visit(toString(), os);
return os; }
306 typedef typename std::aligned_storage<
mt::max<
sizeof(Types)...>::value,
mt::max<
alignof(Types)...>::value>::type Storage;
308 struct ctorCopy {
template<
class T>
void operator()(T&& val, variant& this_) { this_.construct(val); } };
309 struct ctorMove {
template<
class T>
void operator()(T&& val, variant& this_) { this_.construct(move(val)); } };
311 struct assignCopy {
template<
class T>
void operator()(T&& val, variant& this_) { this_ = val; } };
312 struct assignMove {
template<
class T>
void operator()(T&& val, variant& this_) { this_ = move(val); } };
314 struct toString {
template<
class T>
void operator()(T&& val, ostream& os) { os << val; } };
335 template<
class Func,
class... Funcs>
339 overload_(Func&& f, Funcs&&... fs) : Func(forward<Func>(f)),
Super(forward<Funcs>(fs)...) {}
345 template<
class... Funcs>
void visit(Func &&f, Args &&...args) const
Definition: Variant.h:301
variant(const variant &rhs)
Definition: Variant.h:247
Get maximum of all arguments.
Definition: Meta.h:302
#define error_(msg)
Throw AssertionFailure with a message. Message ignored in final mode.
Definition: Debug.h:44
void visit(Func &&f, Args &&...args)
Visit for void result type. Does nothing (no throw) if the visitor does not accept the active bounded...
Definition: Variant.h:299
Multi-typed value. A variant is a value of any type from a fixed set of bounded types, the active bounded type may be changed dynamically.
Definition: Variant.h:230
variant(variant &rhs)
Definition: Variant.h:248
friend ostream & operator<<(ostream &os, const variant &rhs)
Definition: Variant.h:303
static auto _
Definition: Module.cpp:8
variant & operator=(const variant &rhs)
Definition: Variant.h:268
variant(Args &&...args)
First bounded type constructible with args is set as the value.
Definition: Variant.h:246
variant & operator=(variant &rhs)
Definition: Variant.h:269
overload_< Funcs... > overload(Funcs &&...fs)
Create an overloaded visitor functor.
Definition: Variant.h:346
#define EXCEPTION(Class)
Declares methods required for every subclass of honey::Exception.
Definition: Exception.h:17
Definition: Variant.h:322
szt size() const
Get number of bounded types.
Definition: Variant.h:275
#define assert(...)
Forwards to assert_#args. See assert_1(), assert_2().
Definition: Debug.h:24
variant & operator=(T &&val)
Attempts to copy/move-assign to any bounded type, otherwise first bounded type assignable to val is s...
Definition: Variant.h:267
friend class priv::variant
Definition: Variant.h:232
void bind(T &&val)
Bind reference to object. First bounded reference type bindable to rhs is set as the value...
Definition: Variant.h:257
overload_(Func &&f, Funcs &&...fs)
Definition: Variant.h:339
R visit(Func &&f, Args &&...args)
Visit stored value using functor. Calls functor(stored_value, args...) if such a call is valid and re...
Definition: Variant.h:293
Base exception class. Exceptions inherited from this class provide debug info and can be thrown polym...
Definition: Exception.h:45
#define throw_
Use in place of throw keyword to throw a honey::Exception object polymorphically and provide debug in...
Definition: Exception.h:11
size_t szt
Size type, shorthand for size_t.
Definition: Core.h:90
overload_< Funcs... > Super
Definition: Variant.h:338
~variant()
Definition: Variant.h:251
szt type() const
Get active bounded type id, range [0, size)
Definition: Variant.h:280
variant()
First default constructible bounded type is set as the value.
Definition: Variant.h:237
variant(T &&val)
Attempts to copy/move construct any bounded type, otherwise first bounded type constructible with val...
Definition: Variant.h:243
variant(variant &&rhs)
Definition: Variant.h:249
Get number of bounded types at compile-time.
Definition: Variant.h:273
variant & operator=(variant &&rhs)
Definition: Variant.h:270
Global Honeycomb namespace.
R visit(Func &&f, Args &&...args) const
Definition: Variant.h:295