hobbes
a language, embedded compiler, and runtime for efficient dynamic expression evaluation, data storage and analysis
variant.H
Go to the documentation of this file.
1 /****
2  * variant : yet another POD variant implementation
3  ****/
4 
5 #ifndef HOBBES_UTIL_VARIANT_HPP_INCLUDED
6 #define HOBBES_UTIL_VARIANT_HPP_INCLUDED
7 
8 #include <string.h>
9 
10 namespace hobbes {
11 
12 // some simple compile-time logic
13 template <bool f, typename T, typename F>
14  struct TIfF { };
15 template <typename T, typename F>
16  struct TIfF<true, T, F> { typedef T type; };
17 template <typename T, typename F>
18  struct TIfF<false, T, F> { typedef F type; };
19 
20 // sizeof as a type-level function
21 template <typename T>
22  struct TSizeOfF {
23  static const size_t value = sizeof(T);
24  };
25 
26 // alignof as a type-level function
27 template <typename T>
28  struct TAlignOfF {
29  static const size_t value = alignof(T);
30  };
31 
32 // find a maximum property of a sequence of types
33 template <template <class> class SzP, typename T0, typename ... Ts>
34  struct maximum {
35  static const size_t value = SzP<T0>::value;
36  typedef T0 type;
37  };
38 
39 template <template <class> class SzP, typename T0, typename T1, typename ... Ts>
40  struct maximum<SzP, T0, T1, Ts...> : public maximum<SzP, typename TIfF<SzP<T1>::value < SzP<T0>::value, T0, T1>::type, Ts...> {
41  };
42 
43 // count a number of type arguments
44 template <typename ... Ts>
45  struct CountF {
46  static const size_t value = sizeof...(Ts);
47  };
48 
49 // find ctor index by type equality
50 template <typename T, typename ... Ctors>
51  struct CtorIndexOf {
52  static const uint32_t value = 0;
53  };
54 template <typename T, typename ... Ctors>
55  struct CtorIndexOf<T, T, Ctors...> {
56  static const uint32_t value = 0;
57  };
58 template <typename T, typename Ctor, typename ... Ctors>
59  struct CtorIndexOf<T, Ctor, Ctors...> {
60  static const uint32_t value = 1 + CtorIndexOf<T, Ctors...>::value;
61  };
62 
63 // get the first type in a sequence
64 template <typename T, typename ... Ts>
65  struct First {
66  typedef T type;
67  };
68 
69 // a variantSplit-like copy-constructor selector
70 template <typename ... Ctors>
71  struct CCtorAt0 {
72  static void invoke(uint32_t,void*,const void*) { } // shouldn't be possible
73  };
74 template <typename Ctor, typename ... Ctors>
75  struct CCtorAt0<Ctor, Ctors...> {
76  static void invoke(uint32_t t, void* to, const void* from) {
77  if (t == 0) {
78  new (to) Ctor(*((const Ctor*)from));
79  } else {
80  CCtorAt0<Ctors...>::invoke(t-1, to, from);
81  }
82  }
83  };
84 
85 // a variantSplit-like destructor selector
86 template <typename ... Ctors>
87  struct DtorAt0 {
88  static void invoke(uint32_t,void*) { } // shouldn't be possible
89  };
90 template <typename Ctor, typename ... Ctors>
91  struct DtorAt0<Ctor, Ctors...> {
92  static void invoke(uint32_t t, void* p) {
93  if (t == 0) {
94  ((Ctor*)p)->~Ctor();
95  } else {
96  DtorAt0<Ctors...>::invoke(t-1, p);
97  }
98  }
99  };
100 
101 // a simple tagged variant representation
102 template <typename ... Ctors>
103  class variant {
104  public:
105  static_assert(sizeof...(Ctors) > 0, "Empty variants are impossible to construct");
106 
107  variant() : tag(0) {
108  new (this->storage) typename First<Ctors...>::type();
109  }
110  template <typename T>
111  variant(const T& t) : tag(CtorIndexOf<T, Ctors...>::value) {
112  static_assert(CtorIndexOf<T, Ctors...>::value < sizeof...(Ctors), "Constructor type isn't part of variant");
113  new (this->storage) T(t);
114  }
115  variant(const variant<Ctors...>& rhs) : tag(rhs.tag) {
116  CCtorAt0<Ctors...>::invoke(this->tag, this->storage, rhs.storage);
117  }
118 
120  DtorAt0<Ctors...>::invoke(this->tag, this->storage);
121  }
122 
123  variant<Ctors...>& operator=(const variant<Ctors...>& rhs) {
124  if (this != &rhs) {
125  DtorAt0<Ctors...>::invoke(this->tag, this->storage);
126  this->tag = rhs.tag;
127  CCtorAt0<Ctors...>::invoke(this->tag, this->storage, rhs.storage);
128  }
129  return *this;
130  }
131 
132  template <typename T>
133  T* get() { return findByCtor<T>(); }
134  template <typename T>
135  const T* get() const { return findByCtor<T>(); }
136  private:
137  uint32_t tag;
138  union {
139  char storage[maximum<TSizeOfF, Ctors...>::value];
140  typename maximum<TAlignOfF, Ctors...>::type maxAlignedT;
141  };
142 
143  template <typename T>
144  T* findByCtor() const {
145  static_assert(CtorIndexOf<T, Ctors...>::value < sizeof...(Ctors), "Constructor type isn't part of variant");
146 
147  if (this->tag == CtorIndexOf<T, Ctors...>::value) {
148  return (T*)(this->storage);
149  } else {
150  return 0;
151  }
152  }
153  };
154 
155 template <typename T, typename ... Ctors>
156  T* get(variant<Ctors...>& v) {
157  return v.template get<T>();
158  }
159 template <typename T, typename ... Ctors>
160  const T* get(const variant<Ctors...>& v) {
161  return v.template get<T>();
162  }
163 
164 // the trivially true proposition -- ie: C's "void" with its one value constructible
165 struct unit { unit() { } };
166 
167 }
168 
169 #endif
170 
Definition: variant.H:14
F type
Definition: variant.H:18
uint32_t tag
Definition: variant.H:137
T0 type
Definition: variant.H:36
variant< Ctors... > & operator=(const variant< Ctors... > &rhs)
Definition: variant.H:123
T * findByCtor() const
Definition: variant.H:144
~variant()
Definition: variant.H:119
Definition: boot.H:7
Definition: variant.H:34
char storage[maximum< TSizeOfF, Ctors... >::value]
Definition: variant.H:139
variant(const T &t)
Definition: variant.H:111
variant()
Definition: variant.H:107
Definition: variant.H:22
else
Definition: variant.H:95
unit()
Definition: variant.H:165
Definition: variant.H:165
maximum< TAlignOfF, Ctors... >::type maxAlignedT
Definition: variant.H:140
Definition: variant.H:103
variant(const variant< Ctors... > &rhs)
Definition: variant.H:115
T type
Definition: variant.H:16
Definition: variant.H:28