COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/bits/variant.h @ 2292:38d985e82205

Last change on this file since 2292:38d985e82205 was 2292:38d985e82205, checked in by Balazs Dezso, 13 years ago

General mapping based variant type

File size: 14.4 KB
Line 
1/* -*- C++ -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library
4 *
5 * Copyright (C) 2003-2006
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 *
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
12 *
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
15 * purpose.
16 *
17 */
18
19#ifndef LEMON_BITS_VARIANT_H
20#define LEMON_BITS_VARIANT_H
21
22#include <lemon/error.h>
23
24/// \file
25/// \brief Variant types
26
27namespace lemon {
28
29  namespace _variant_bits {
30 
31    template <int left, int right>
32    struct CTMax {
33      static const int value = left < right ? right : left;
34    };
35
36  }
37
38
39  /// \brief Simple Variant type for two types
40  ///
41  /// Simple Variant type for two types. The Variant type is a type
42  /// safe union. The C++ has strong limitations for using unions, by
43  /// example we can not store type with non default constructor or
44  /// destructor in an union. This class always knowns the current
45  /// state of the variant and it cares for the proper construction
46  /// and destruction.
47  template <typename _First, typename _Second>
48  class BiVariant {
49  public:
50
51    /// \brief The \c First type.
52    typedef _First First;
53    /// \brief The \c Second type.
54    typedef _Second Second;
55
56    struct WrongStateError : public lemon::LogicError {
57    public:
58      virtual const char* what() const throw() {
59        return "lemon::BiVariant::WrongStateError";
60      }
61    };
62
63    /// \brief Constructor
64    ///
65    /// This constructor initalizes to the default value of the \c First
66    /// type.
67    BiVariant() {
68      flag = true;
69      new(reinterpret_cast<First*>(data)) First();
70    }
71
72    /// \brief Constructor
73    ///
74    /// This constructor initalizes to the given value of the \c First
75    /// type.
76    BiVariant(const First& first) {
77      flag = true;
78      new(reinterpret_cast<First*>(data)) First(first);
79    }
80
81    /// \brief Constructor
82    ///
83    /// This constructor initalizes to the given value of the \c
84    /// Second type.
85    BiVariant(const Second& second) {
86      flag = false;
87      new(reinterpret_cast<Second*>(data)) Second(second);
88    }
89
90    /// \brief Copy constructor
91    ///
92    /// Copy constructor
93    BiVariant(const BiVariant& bivariant) {
94      flag = bivariant.flag;
95      if (flag) {
96        new(reinterpret_cast<First*>(data)) First(bivariant.first());     
97      } else {
98        new(reinterpret_cast<Second*>(data)) Second(bivariant.second());     
99      }
100    }
101
102    /// \brief Destrcutor
103    ///
104    /// Destructor
105    ~BiVariant() {
106      destroy();
107    }
108
109    /// \brief Set to the default value of the \c First type.
110    ///
111    /// This function sets the variant to the default value of the \c
112    /// First type.
113    BiVariant& setFirst() {
114      destroy();
115      flag = true;
116      new(reinterpret_cast<First*>(data)) First();   
117      return *this;
118    }
119
120    /// \brief Set to the given value of the \c First type.
121    ///
122    /// This function sets the variant to the given value of the \c
123    /// First type.
124    BiVariant& setFirst(const First& first) {
125      destroy();
126      flag = true;
127      new(reinterpret_cast<First*>(data)) First(first);   
128      return *this;
129    }
130
131    /// \brief Set to the default value of the \c Second type.
132    ///
133    /// This function sets the variant to the default value of the \c
134    /// Second type.
135    BiVariant& setSecond() {
136      destroy();
137      flag = false;
138      new(reinterpret_cast<Second*>(data)) Second();   
139      return *this;
140    }
141
142    /// \brief Set to the given value of the \c Second type.
143    ///
144    /// This function sets the variant to the given value of the \c
145    /// Second type.
146    BiVariant& setSecond(const Second& second) {
147      destroy();
148      flag = false;
149      new(reinterpret_cast<Second*>(data)) Second(second);   
150      return *this;
151    }
152
153    /// \brief Operator form of the \c setFirst()
154    BiVariant& operator=(const First& first) {
155      return setFirst(first);
156    }
157
158    /// \brief Operator form of the \c setSecond()
159    BiVariant& operator=(const Second& second) {
160      return setSecond(second);
161    }
162
163    /// \brief Assign operator
164    BiVariant& operator=(const BiVariant& bivariant) {
165      if (this == &bivariant) return *this;
166      destroy();
167      flag = bivariant.flag;
168      if (flag) {
169        new(reinterpret_cast<First*>(data)) First(bivariant.first());     
170      } else {
171        new(reinterpret_cast<Second*>(data)) Second(bivariant.second());     
172      }
173      return *this;
174    }
175
176    /// \brief Reference to the value
177    ///
178    /// Reference to the value of the \c First type.
179    /// \pre The BiVariant should store value of \c First type.
180    First& first() {
181      LEMON_ASSERT(flag, WrongStateError());
182      return *reinterpret_cast<First*>(data);
183    }
184
185    /// \brief Const reference to the value
186    ///
187    /// Const reference to the value of the \c First type.
188    /// \pre The BiVariant should store value of \c First type.
189    const First& first() const {
190      LEMON_ASSERT(flag, WrongStateError());
191      return *reinterpret_cast<const First*>(data);
192    }
193
194    /// \brief Operator form of the \c first()
195    operator First&() { return first(); }
196    /// \brief Operator form of the const \c first()
197    operator const First&() const { return first(); }
198
199    /// \brief Reference to the value
200    ///
201    /// Reference to the value of the \c Second type.
202    /// \pre The BiVariant should store value of \c Second type.
203    Second& second() {
204      LEMON_ASSERT(!flag, WrongStateError());
205      return *reinterpret_cast<Second*>(data);
206    }
207
208    /// \brief Const reference to the value
209    ///
210    /// Const reference to the value of the \c Second type.
211    /// \pre The BiVariant should store value of \c Second type.
212    const Second& second() const {
213      LEMON_ASSERT(!flag, WrongStateError());
214      return *reinterpret_cast<const Second*>(data);
215    }
216
217    /// \brief Operator form of the \c second()
218    operator Second&() { return second(); }
219    /// \brief Operator form of the const \c second()
220    operator const Second&() const { return second(); }
221
222    /// \brief %True when the variant is in the first state
223    ///
224    /// %True when the variant stores value of the \c First type.
225    bool firstState() const { return flag; }
226
227    /// \brief %True when the variant is in the second state
228    ///
229    /// %True when the variant stores value of the \c Second type.
230    bool secondState() const { return !flag; }
231
232  private:
233
234    void destroy() {
235      if (flag) {
236        reinterpret_cast<First*>(data)->~First();
237      } else {
238        reinterpret_cast<Second*>(data)->~Second();
239      }
240    }
241   
242    char data[_variant_bits::CTMax<sizeof(First), sizeof(Second)>::value];
243    bool flag;
244  };
245
246  namespace _variant_bits {
247   
248    template <int _idx, typename _TypeMap>
249    struct Memory {
250
251      typedef typename _TypeMap::template Map<_idx>::Type Current;
252
253      static void destroy(int index, char* place) {
254        if (index == _idx) {
255          reinterpret_cast<Current*>(place)->~Current();
256        } else {
257          Memory<_idx - 1, _TypeMap>::destroy(index, place);
258        }
259      }
260
261      static void copy(int index, char* to, const char* from) {
262        if (index == _idx) {
263          new (reinterpret_cast<Current*>(to))
264            Current(reinterpret_cast<const Current*>(from));
265        } else {
266          Memory<_idx - 1, _TypeMap>::copy(index, to, from);
267        }
268      }
269
270    };
271
272    template <typename _TypeMap>
273    struct Memory<-1, _TypeMap> {
274
275      static void destroy(int, char*) {
276        LEMON_ASSERT(false, "Wrong Variant Index.");
277      }
278
279      static void copy(int, char*, const char*) {
280        LEMON_ASSERT(false, "Wrong Variant Index.");
281      }
282    };
283
284    template <int _idx, typename _TypeMap>
285    struct Size {
286      static const int value =
287      CTMax<sizeof(typename _TypeMap::template Map<_idx>::Type),
288            Size<_idx - 1, _TypeMap>::value>::value;
289    };
290
291    template <typename _TypeMap>
292    struct Size<0, _TypeMap> {
293      static const int value =
294      sizeof(typename _TypeMap::template Map<0>::Type);
295    };
296
297  }
298
299  /// \brief Variant type
300  ///
301  /// Simple Variant type. The Variant type is a type safe union. The
302  /// C++ has strong limitations for using unions, by example we
303  /// cannot store type with non default constructor or destructor in
304  /// a union. This class always knowns the current state of the
305  /// variant and it cares for the proper construction and
306  /// destruction.
307  ///
308  /// \param _num The number of the types which can be stored in the
309  /// variant type.
310  /// \param _TypeMap This class describes the types of the Variant. The
311  /// _TypeMap::Map<index>::Type should be a valid type for each index
312  /// in the range {0, 1, ..., _num - 1}. The \c VariantTypeMap is helper
313  /// class to define such type mappings up to 10 types.
314  ///
315  /// And the usage of the class:
316  ///\code
317  /// typedef Variant<3, VariantTypeMap<int, std::string, double> > MyVariant;
318  /// MyVariant var;
319  /// var.set<0>(12);
320  /// std::cout << var.get<0>() << std::endl;
321  /// var.set<1>("alpha");
322  /// std::cout << var.get<1>() << std::endl;
323  /// var.set<2>(0.75);
324  /// std::cout << var.get<2>() << std::endl;
325  ///\endcode
326  ///
327  /// The result of course:
328  ///\code
329  /// 12
330  /// alpha
331  /// 0.75
332  ///\endcode
333  template <int _num, typename _TypeMap>
334  class Variant {
335  public:
336
337    static const int num = _num;
338
339    typedef _TypeMap TypeMap;
340
341    struct WrongStateError : public lemon::LogicError {
342    public:
343      virtual const char* what() const throw() {
344        return "lemon::Variant::WrongStateError";
345      }
346    };
347
348    /// \brief Constructor
349    ///
350    /// This constructor initalizes to the default value of the \c type
351    /// with 0 index.
352    Variant() {
353      flag = 0;
354      new(reinterpret_cast<typename TypeMap::template Map<0>::Type*>(data))
355        typename TypeMap::template Map<0>::Type();
356    }
357
358
359    /// \brief Copy constructor
360    ///
361    /// Copy constructor
362    Variant(const Variant& variant) {
363      flag = variant.flag;
364      _variant_bits::Memory<num - 1, TypeMap>::copy(flag, data, variant.data);
365    }
366
367    /// \brief Assign operator
368    ///
369    /// Assign operator
370    Variant& operator=(const Variant& variant) {
371      if (this == &variant) return *this;
372      _variant_bits::Memory<num - 1, TypeMap>::
373        destroy(flag, data);
374      flag = variant.flag;
375      _variant_bits::Memory<num - 1, TypeMap>::
376        copy(flag, data, variant.data);
377      return *this;
378    }
379
380    /// \brief Destrcutor
381    ///
382    /// Destructor
383    ~Variant() {
384      _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
385    }
386
387    /// \brief Set to the default value of the type with \c _idx index.
388    ///
389    /// This function sets the variant to the default value of the
390    /// type with \c _idx index.
391    template <int _idx>
392    Variant& set() {
393      _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
394      flag = _idx;
395      new(reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>(data))
396        typename TypeMap::template Map<_idx>::Type();
397      return *this;
398    }
399
400    /// \brief Set to the given value of the type with \c _idx index.
401    ///
402    /// This function sets the variant to the given value of the type
403    /// with \c _idx index.
404    template <int _idx>
405    Variant& set(const typename _TypeMap::template Map<_idx>::Type& init) {
406      _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
407      flag = _idx;
408      new(reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>(data))
409        typename TypeMap::template Map<_idx>::Type(init);
410      return *this;
411    }
412
413    /// \brief Gets the current value of the type with \c _idx index.
414    ///
415    /// Gets the current value of the type with \c _idx index.
416    template <int _idx>
417    const typename TypeMap::template Map<_idx>::Type& get() const {
418      LEMON_ASSERT(_idx == flag, "Wrong Variant Index.");
419      return *reinterpret_cast<const typename TypeMap::
420        template Map<_idx>::Type*>(data);
421    }
422
423    /// \brief Gets the current value of the type with \c _idx index.
424    ///
425    /// Gets the current value of the type with \c _idx index.
426    template <int _idx>
427    typename _TypeMap::template Map<_idx>::Type& get() {
428      LEMON_ASSERT(_idx == flag, "Wrong Variant Index.");
429      return *reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>
430        (data);
431    }
432
433    /// \brief Returns the current state of the variant.
434    ///
435    /// Returns the current state of the variant.
436    int state() const {
437      return flag;
438    }
439
440  private:
441   
442    char data[_variant_bits::Size<num - 1, TypeMap>::value];
443    int flag;
444  };
445
446  namespace _variant_bits {
447
448    template <int _index, typename _List>
449    struct Get {
450      typedef typename Get<_index - 1, typename _List::Next>::Type Type;
451    };
452
453    template <typename _List>
454    struct Get<0, _List> {
455      typedef typename _List::Type Type;
456    };
457
458    struct List {};
459   
460    template <typename _Type, typename _List>
461    struct Insert {
462      typedef _List Next;
463      typedef _Type Type;
464    };
465
466    template <int _idx, typename _T0, typename _T1, typename _T2,
467              typename _T3, typename _T5, typename _T4, typename _T6,
468              typename _T7, typename _T8, typename _T9>
469    struct Mapper {
470      typedef List L10;
471      typedef Insert<_T9, L10> L9;
472      typedef Insert<_T8, L9> L8;
473      typedef Insert<_T7, L8> L7;
474      typedef Insert<_T6, L7> L6;
475      typedef Insert<_T5, L6> L5;
476      typedef Insert<_T4, L5> L4;
477      typedef Insert<_T3, L4> L3;
478      typedef Insert<_T2, L3> L2;
479      typedef Insert<_T1, L2> L1;
480      typedef Insert<_T0, L1> L0;
481      typedef typename Get<_idx, L0>::Type Type;
482    };
483   
484  }
485
486  /// \brief Helper class for Variant
487  ///
488  /// Helper class to define type mappings for Variant. This class
489  /// converts the template parameters to be mappable by integer.
490  /// \see Variant
491  template <
492    typename _T0,
493    typename _T1 = void, typename _T2 = void, typename _T3 = void,
494    typename _T5 = void, typename _T4 = void, typename _T6 = void,
495    typename _T7 = void, typename _T8 = void, typename _T9 = void>
496  struct VariantTypeMap {
497    template <int _idx>
498    struct Map {
499      typedef typename _variant_bits::
500      Mapper<_idx, _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9>::Type
501      Type;
502    };
503  };
504 
505}
506
507
508#endif
Note: See TracBrowser for help on using the repository browser.