Lumiera  0.pre.03
»edit your freedom«
variant-o.hpp
Go to the documentation of this file.
1 /*
2  VARIANT.hpp - simple variant wrapper (typesafe union)
3 
4  Copyright (C)
5  2008, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
42 #ifndef LIB_VARIANT_O_H
43 #define LIB_VARIANT_O_H
44 
45 
47 #include "lib/meta/generator.hpp"
48 #include "lib/nocopy.hpp"
49 
50 
51 
52 
53 namespace lib {
54 
55  namespace variant {
56 
57  using lib::meta::count;
58  using lib::meta::maxSize;
60 
70  template<typename TYPES>
71  struct Holder
72  {
73 
74  enum { TYPECNT = count<TYPES>::value
75  , SIZE = maxSize<TYPES>::value
76  };
77 
78 
80  struct Buffer
81  {
82  char buffer_[SIZE];
83  uint which_;
84 
85  Buffer() : which_(TYPECNT) {}
86 
87  void*
88  put (void)
89  {
90  deleteCurrent();
91  return 0;
92  }
93 
94  void
95  deleteCurrent (); // depends on the Deleter, see below
96  };
97 
98  template<typename T, class BASE, uint idx>
99  struct PlacementAdapter : BASE
100  {
101  T&
102  put (T const& toStore)
103  {
104  BASE::deleteCurrent(); // remove old content, if any
105  //
106  T& storedObj = *new(BASE::buffer_) T (toStore);
107  BASE::which_ = idx; // remember the actual type selected
108  return storedObj;
109  }
110 
111  using BASE::put; // inherited alternate put() for other types T
112  };
113 
114  typedef InstantiateWithIndex< TYPES
116  , Buffer
117  >
118  Storage;
119 
120 
121 
123  template<class FUNCTOR>
124  struct CaseSelect
125  {
126  typedef typename FUNCTOR::Ret Ret;
127  typedef Ret (Func)(Buffer&);
128 
129  Func* table_[TYPECNT];
130 
131  CaseSelect ()
132  {
133  for (uint i=0; i<TYPECNT; ++i)
134  table_[i] = 0;
135  }
136 
137  template<typename T>
138  static Ret
139  trampoline (Buffer& storage)
140  {
141  T& content = reinterpret_cast<T&> (storage.buffer_);
142  return FUNCTOR::access (content);
143  }
144 
145  Ret
146  invoke (Buffer& storage)
147  {
148  if (TYPECNT <= storage.which_)
149  return FUNCTOR::ifEmpty ();
150  else
151  {
152  Func& access = *table_[storage.which_];
153  return access (storage);
154  }
155  }
156  };
157 
158 
161  template< class T, class BASE, uint i >
162  struct CasePrepare
163  : BASE
164  {
165  CasePrepare () : BASE()
166  {
167  BASE::table_[i] = &BASE::template trampoline<T>;
168  }
169  };
170 
171 
179  template<class FUNCTOR>
180  static typename FUNCTOR::Ret
181  access (Buffer& buf)
182  {
183  typedef InstantiateWithIndex< TYPES
184  , CasePrepare
186  >
187  Accessor;
188  static Accessor select_case;
189  return select_case.invoke(buf);
190  }
191 
192 
193  struct Deleter
194  {
195  typedef void Ret;
196 
197  template<typename T>
198  static void access (T& elem) { elem.~T(); }
199 
200  static void ifEmpty () { }
201  };
202  };
203 
204 
205  template<typename TYPES>
206  inline void
208  {
209  access<Deleter>(*this); // remove old content, if any
210  which_ = TYPECNT; // mark as empty
211  }
212 
213  } // namespace variant
214 
215 
216 
217 
218 
219 
220 
221 
241  template< typename TYPES
242  , template<typename> class Access
243  >
244  class VariantO
246  {
247 
249  typedef typename Holder::Deleter Deleter;
250 
251 
255 
256 
257  public:
258  void reset () { holder_.deleteCurrent();}
259 
266  template<typename SRC>
267  VariantO&
268  operator= (SRC src)
269  {
270  if (src) holder_.put (src); // see Holder::PlacementAdaptor::put
271  else reset();
272  return *this;
273  }
274 
282  template<typename TAR>
283  TAR
284  get ()
285  {
286  typedef Access<TAR> Extractor;
287  return Holder::template access<Extractor> (this->holder_);
288  }
289  };
290 
291 } // namespace lib
292 #endif
Holder::Storage holder_
storage: buffer holding either an "empty" marker, or an instance of one of the configured payload typ...
Definition: variant-o.hpp:254
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
Helpers for working with lib::meta::Types (i.e.
Metaprogramming: simple helpers for working with lists-of-types.
Implementation namespace for support and library code.
Metafunction " max( sizeof(T) ) for T in TYPES ".
A Variation of InstantiateChained providing an incremented Index value template parameter.
Definition: generator.hpp:165
Storage to hold the actual value.
Definition: variant-o.hpp:80
initialise the dispatcher (trampoline) for the case of accessing type T
Definition: variant-o.hpp:162
provide a dispatcher table based visitation mechanism
Definition: variant-o.hpp:124
Mix-Ins to allow or prohibit various degrees of copying and cloning.
static FUNCTOR::Ret access(Buffer &buf)
access the variant&#39;s inline buffer, using the configured access functor.
Definition: variant-o.hpp:181
internal helper used to build a variant storage wrapper.
Definition: variant-o.hpp:71
Metafunction counting the number of Types in the collection.
A variant wrapper (typesafe union) capable of holding a value of any of a bounded collection of types...
Definition: variant-o.hpp:244