Honeycomb  0.1
Component-Model Framework
Variant.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
4 #include "Honey/Misc/Exception.h"
5 
6 namespace honey
7 {
8 
10 
12 namespace priv
13 {
14  template<class Subclass, szt id, class... Types> class variant;
15 
17  template<class Subclass, szt id, class Type, class... Types>
18  class variant<Subclass, id, Type, Types...> : public variant<Subclass, id+1, Types...>
19  {
20  typedef variant<Subclass, id+1, Types...> Super;
21  typedef typename std::remove_const<Type>::type Type_mutable;
22  public:
23  operator Type&() { return this->subc().template get<Type>(); }
24  operator const Type&() const { return this->subc().template get<const Type>(); }
25 
26  protected:
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)); }
33  template<class T>
34  void construct(T&& val) { Super::construct(forward<T>(val)); }
35 
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)...); }
40 
41  void destroy() { _id() == id ? _val().~Type() : Super::destroy(); }
42 
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); }
49  template<class T>
50  void assign(T&& val) { Super::assign(forward<T>(val)); }
51 
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)); }
56 
57  template<szt id_, szt=0>
58  struct Type_ : Super::template Type_<id_> {};
59  template<szt _> struct Type_<id, _> { typedef Type type; };
60 
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)...); }
65 
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)...); }
70 
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)...); }
75 
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)...); }
80 
81  private:
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()); }
88 
89  template<class... Args>
90  void construct_(Args&&... args) { _id() = id; new (_storage()) Type(forward<Args>(args)...); }
91 
92  template<class T> void assign_new(T&& val) { this->subc().destroy(); construct_(forward<T>(val)); }
93  };
94 
96  template<class Subclass, szt id, class Type, class... Types>
97  class variant<Subclass, id, Type&, Types...> : public variant<Subclass, id+1, Types...>
98  {
99  typedef variant<Subclass, id+1, Types...> Super;
100  typedef typename std::remove_const<Type>::type Type_mutable;
101  public:
102  operator Type&() { return this->subc().template get<Type>(); }
103  operator const Type&() const { return this->subc().template get<const Type>(); }
104 
105  protected:
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)); }
110  template<class T>
111  void construct(T&& val) { Super::construct(forward<T>(val)); }
112 
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)...); }
117 
118  void destroy() { if (_id() == id) _ptr() = nullptr; else Super::destroy(); }
119 
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)); }
124  template<class T>
125  void bind(T&& val) { Super::bind(forward<T>(val)); }
126 
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)); }
131 
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); }
138  template<class T>
139  void assign(T&& val) { Super::assign(forward<T>(val)); }
140 
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)); }
145 
146  template<szt id_, szt=0>
147  struct Type_ : Super::template Type_<id_> {};
148  template<szt _> struct Type_<id, _> { typedef Type& type; };
149 
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)...); }
154 
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)...); }
159 
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)...); }
164 
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)...); }
169 
170  private:
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(); }
177 
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)); }
180  };
181 
183  template<class Subclass, szt id>
184  class variant<Subclass, id>
185  {
186  protected:
188  const Subclass& subc() const { return static_cast<const Subclass&>(*this); }
189  Subclass& subc() { return static_cast<Subclass&>(*this); }
190 
191  template<class T>
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"); }
195 
196  void destroy() { error_("Should not get here, variant destruction failed"); }
197 
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"); }
200 
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"); }
203 
204  struct size_ : mt::Value<szt, id> {};
205  template<szt id_> struct Type_ { static_assert(!mt::True_int<id_>::value, "Invalid type id"); };
206 
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; }
211 
212  template<class Func, class... Args>
213  void visit(Func&&, Args&&...) {}
214  template<class Func, class... Args>
215  void visit(Func&&, Args&&...) const {}
216  };
217 }
221 
229 template<class... Types>
230 class variant : public priv::variant<variant<Types...>, 0, Types...>
231 {
232  template<class, szt, class...> friend class priv::variant;
233  typedef priv::variant<variant, 0, Types...> Super;
234 
235 public:
237  variant() { this->construct_convert(); }
239 
242  template<class T>
243  variant(T&& val) { this->construct(forward<T>(val)); }
245  template<class... Args>
246  variant(Args&&... args) { this->construct_convert(forward<Args>(args)...); }
247  variant(const variant& rhs) { rhs.visit(ctorCopy(), *this); }
248  variant(variant& rhs) { rhs.visit(ctorCopy(), *this); }
249  variant(variant&& rhs) { rhs.visit(ctorMove(), *this); }
250 
251  ~variant() { this->destroy(); }
252 
254 
257  template<class T> void bind(T&& val) { Super::bind(forward<T>(val)); }
258 
260 
266  template<class T>
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; }
271 
273  struct size_ : Super::size_ {};
275  szt size() const { return size_::value; };
277  template<szt id>
278  struct Type : Super::template Type_<id> {};
280  szt type() const { return _id; }
281 
283  template<class T>
284  T& get() { return visit<T&>([](T& val) -> T& { return val; }); }
285  template<class T>
286  const T& get() const { return visit<const T&>([](const T& val) -> const T& { return val; }); }
287 
289 
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)...); }
296 
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)...); }
302 
303  friend ostream& operator<<(ostream& os, const variant& rhs) { rhs.visit(toString(), os); return os; }
304 
305 private:
306  typedef typename std::aligned_storage<mt::max<sizeof(Types)...>::value, mt::max<alignof(Types)...>::value>::type Storage;
307 
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)); } };
310 
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); } };
313 
314  struct toString { template<class T> void operator()(T&& val, ostream& os) { os << val; } };
315 
316  szt _id;
317  Storage _storage;
318 };
319 
320 
321 
322 template<class... Funcs> struct overload_;
323 
325 
335 template<class Func, class... Funcs>
336 struct overload_<Func, Funcs...> : Func, overload_<Funcs...>
337 {
338  typedef overload_<Funcs...> Super;
339  overload_(Func&& f, Funcs&&... fs) : Func(forward<Func>(f)), Super(forward<Funcs>(fs)...) {}
340 };
341 
342 template<> struct overload_<> {};
343 
345 template<class... Funcs>
346 overload_<Funcs...> overload(Funcs&&... fs) { return overload_<Funcs...>(forward<Funcs>(fs)...); }
347 
348 }
349 
350 
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
std::enable_if<!b, T > disable_if
Opposite of std::enable_if.
Definition: Meta.h:62
variant(variant &rhs)
Definition: Variant.h:248
std::integral_constant< T, val > Value
Holds a constant integral value.
Definition: Meta.h:29
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
Definition: Variant.h:9
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