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) Lumiera.org
5  2008, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
51 #ifndef LIB_VARIANT_O_H
52 #define LIB_VARIANT_O_H
53 
54 
56 #include "lib/meta/generator.hpp"
57 #include "lib/nocopy.hpp"
58 
59 
60 
61 
62 namespace lib {
63 
64  namespace variant {
65 
66  using lib::meta::count;
67  using lib::meta::maxSize;
69 
79  template<typename TYPES>
80  struct Holder
81  {
82 
83  enum { TYPECNT = count<TYPES>::value
84  , SIZE = maxSize<TYPES>::value
85  };
86 
87 
89  struct Buffer
90  {
91  char buffer_[SIZE];
92  uint which_;
93 
94  Buffer() : which_(TYPECNT) {}
95 
96  void*
97  put (void)
98  {
99  deleteCurrent();
100  return 0;
101  }
102 
103  void
104  deleteCurrent (); // depends on the Deleter, see below
105  };
106 
107  template<typename T, class BASE, uint idx>
108  struct PlacementAdapter : BASE
109  {
110  T&
111  put (T const& toStore)
112  {
113  BASE::deleteCurrent(); // remove old content, if any
114  //
115  T& storedObj = *new(BASE::buffer_) T (toStore);
116  BASE::which_ = idx; // remember the actual type selected
117  return storedObj;
118  }
119 
120  using BASE::put; // inherited alternate put() for other types T
121  };
122 
123  typedef InstantiateWithIndex< TYPES
125  , Buffer
126  >
127  Storage;
128 
129 
130 
132  template<class FUNCTOR>
133  struct CaseSelect
134  {
135  typedef typename FUNCTOR::Ret Ret;
136  typedef Ret (Func)(Buffer&);
137 
138  Func* table_[TYPECNT];
139 
140  CaseSelect ()
141  {
142  for (uint i=0; i<TYPECNT; ++i)
143  table_[i] = 0;
144  }
145 
146  template<typename T>
147  static Ret
148  trampoline (Buffer& storage)
149  {
150  T& content = reinterpret_cast<T&> (storage.buffer_);
151  return FUNCTOR::access (content);
152  }
153 
154  Ret
155  invoke (Buffer& storage)
156  {
157  if (TYPECNT <= storage.which_)
158  return FUNCTOR::ifEmpty ();
159  else
160  {
161  Func& access = *table_[storage.which_];
162  return access (storage);
163  }
164  }
165  };
166 
167 
170  template< class T, class BASE, uint i >
171  struct CasePrepare
172  : BASE
173  {
174  CasePrepare () : BASE()
175  {
176  BASE::table_[i] = &BASE::template trampoline<T>;
177  }
178  };
179 
180 
188  template<class FUNCTOR>
189  static typename FUNCTOR::Ret
190  access (Buffer& buf)
191  {
192  typedef InstantiateWithIndex< TYPES
193  , CasePrepare
195  >
196  Accessor;
197  static Accessor select_case;
198  return select_case.invoke(buf);
199  }
200 
201 
202  struct Deleter
203  {
204  typedef void Ret;
205 
206  template<typename T>
207  static void access (T& elem) { elem.~T(); }
208 
209  static void ifEmpty () { }
210  };
211  };
212 
213 
214  template<typename TYPES>
215  inline void
217  {
218  access<Deleter>(*this); // remove old content, if any
219  which_ = TYPECNT; // mark as empty
220  }
221 
222  } // namespace variant
223 
224 
225 
226 
227 
228 
229 
230 
250  template< typename TYPES
251  , template<typename> class Access
252  >
253  class VariantO
255  {
256 
258  typedef typename Holder::Deleter Deleter;
259 
260 
264 
265 
266  public:
267  void reset () { holder_.deleteCurrent();}
268 
275  template<typename SRC>
276  VariantO&
277  operator= (SRC src)
278  {
279  if (src) holder_.put (src); // see Holder::PlacementAdaptor::put
280  else reset();
281  return *this;
282  }
283 
291  template<typename TAR>
292  TAR
293  get ()
294  {
295  typedef Access<TAR> Extractor;
296  return Holder::template access<Extractor> (this->holder_);
297  }
298  };
299 
300 } // namespace lib
301 #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:263
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
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:174
Storage to hold the actual value.
Definition: variant-o.hpp:89
initialise the dispatcher (trampoline) for the case of accessing type T
Definition: variant-o.hpp:171
provide a dispatcher table based visitation mechanism
Definition: variant-o.hpp:133
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:190
internal helper used to build a variant storage wrapper.
Definition: variant-o.hpp:80
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:253