[Lemon-commits] [lemon_svn] deba: r3057 - hugo/trunk/lemon/bits

Lemon SVN svn at lemon.cs.elte.hu
Mon Nov 6 21:52:06 CET 2006


Author: deba
Date: Fri Nov  3 16:21:52 2006
New Revision: 3057

Modified:
   hugo/trunk/lemon/bits/variant.h

Log:
General mapping based variant type





Modified: hugo/trunk/lemon/bits/variant.h
==============================================================================
--- hugo/trunk/lemon/bits/variant.h	(original)
+++ hugo/trunk/lemon/bits/variant.h	Fri Nov  3 16:21:52 2006
@@ -21,89 +21,36 @@
 
 #include <lemon/error.h>
 
-namespace lemon {
-
-  template <bool left, bool right>
-  struct CTOr {
-    static const bool value = true;
-  };
-
-  template <>
-  struct CTOr<false, false> {
-    static const bool value = false;
-  };
-
-  template <bool left, bool right>
-  struct CTAnd {
-    static const bool value = false;
-  };
-
-  template <>
-  struct CTAnd<true, true> {
-    static const bool value = true;
-  };
-
-  template <int left, int right>
-  struct CTEqual {
-    static const bool value = false;
-  };
-
-  template <int val>
-  struct CTEqual<val, val> {
-    static const bool value = true;
-  };
+/// \file
+/// \brief Variant types
 
+namespace lemon {
 
-  template <int left, int right>
-  struct CTLess {
-    static const bool value = left < right;
-  };
-
-  template <int left>
-  struct CTLess<left, 0> {
-    static const bool value = false;
-  };
-
-  template <int right>
-  struct CTLess<0, right> {
-    static const bool value = true;
-  };
-
-  template <>
-  struct CTLess<0, 0> {
-    static const bool value = false;
-  };
-
-  template <>
-  struct CTLess<1, 1> {
-    static const bool value = false;
-  };
-
-  template <bool less, int left, int right>
-  struct CTMaxImpl {
-    static const int value = left;    
-  };
-
-  template <int left, int right>
-  struct CTMaxImpl<true, left, right> {
-    static const int value = right;
-  };
+  namespace _variant_bits {
   
-  template <int left, int right>
-  struct CTMax {
-    static const int value = 
-    CTMaxImpl<CTLess<left, right>::value, left, right>::value;
-  };
+    template <int left, int right>
+    struct CTMax {
+      static const int value = left < right ? right : left;
+    };
 
+  }
 
-  /// \brief Simple Variant type with two type
+
+  /// \brief Simple Variant type for two types
   ///
-  /// Simple Variant type with two type
+  /// Simple Variant type for two types. The Variant type is a type
+  /// safe union. The C++ has strong limitations for using unions, by
+  /// example we can not store type with non default constructor or
+  /// destructor in an union. This class always knowns the current
+  /// state of the variant and it cares for the proper construction
+  /// and destruction.
   template <typename _First, typename _Second>
   class BiVariant {
   public:
 
+    /// \brief The \c First type.
     typedef _First First;
+    /// \brief The \c Second type.
     typedef _Second Second;
 
     struct WrongStateError : public lemon::LogicError {
@@ -113,21 +60,36 @@
       }
     };
 
+    /// \brief Constructor
+    ///
+    /// This constructor initalizes to the default value of the \c First
+    /// type.
     BiVariant() {
       flag = true;
       new(reinterpret_cast<First*>(data)) First();
     }
 
+    /// \brief Constructor
+    ///
+    /// This constructor initalizes to the given value of the \c First
+    /// type.
     BiVariant(const First& first) {
       flag = true;
       new(reinterpret_cast<First*>(data)) First(first);
     }
 
+    /// \brief Constructor
+    ///
+    /// This constructor initalizes to the given value of the \c
+    /// Second type.
     BiVariant(const Second& second) {
       flag = false;
       new(reinterpret_cast<Second*>(data)) Second(second);
     }
 
+    /// \brief Copy constructor
+    ///
+    /// Copy constructor
     BiVariant(const BiVariant& bivariant) {
       flag = bivariant.flag;
       if (flag) {
@@ -137,10 +99,17 @@
       }
     }
 
+    /// \brief Destrcutor
+    ///
+    /// Destructor
     ~BiVariant() {
       destroy();
     }
 
+    /// \brief Set to the default value of the \c First type.
+    ///
+    /// This function sets the variant to the default value of the \c
+    /// First type.
     BiVariant& setFirst() {
       destroy();
       flag = true;
@@ -148,6 +117,10 @@
       return *this;
     }
 
+    /// \brief Set to the given value of the \c First type.
+    ///
+    /// This function sets the variant to the given value of the \c
+    /// First type.
     BiVariant& setFirst(const First& first) {
       destroy();
       flag = true;
@@ -155,6 +128,10 @@
       return *this;
     }
 
+    /// \brief Set to the default value of the \c Second type.
+    ///
+    /// This function sets the variant to the default value of the \c
+    /// Second type.
     BiVariant& setSecond() {
       destroy();
       flag = false;
@@ -162,6 +139,10 @@
       return *this;
     }
 
+    /// \brief Set to the given value of the \c Second type.
+    ///
+    /// This function sets the variant to the given value of the \c
+    /// Second type.
     BiVariant& setSecond(const Second& second) {
       destroy();
       flag = false;
@@ -169,15 +150,17 @@
       return *this;
     }
 
+    /// \brief Operator form of the \c setFirst()
     BiVariant& operator=(const First& first) {
       return setFirst(first);
     }
 
+    /// \brief Operator form of the \c setSecond()
     BiVariant& operator=(const Second& second) {
       return setSecond(second);
     }
 
-
+    /// \brief Assign operator
     BiVariant& operator=(const BiVariant& bivariant) {
       if (this == &bivariant) return *this;
       destroy();
@@ -190,33 +173,60 @@
       return *this;
     }
 
+    /// \brief Reference to the value
+    ///
+    /// Reference to the value of the \c First type.
+    /// \pre The BiVariant should store value of \c First type.
     First& first() {
       LEMON_ASSERT(flag, WrongStateError());
       return *reinterpret_cast<First*>(data); 
     }
 
+    /// \brief Const reference to the value
+    ///
+    /// Const reference to the value of the \c First type.
+    /// \pre The BiVariant should store value of \c First type.
     const First& first() const { 
       LEMON_ASSERT(flag, WrongStateError());
       return *reinterpret_cast<const First*>(data); 
     }
 
+    /// \brief Operator form of the \c first()
     operator First&() { return first(); }
+    /// \brief Operator form of the const \c first()
     operator const First&() const { return first(); }
 
+    /// \brief Reference to the value
+    ///
+    /// Reference to the value of the \c Second type.
+    /// \pre The BiVariant should store value of \c Second type.
     Second& second() { 
       LEMON_ASSERT(!flag, WrongStateError());
       return *reinterpret_cast<Second*>(data); 
     }
 
+    /// \brief Const reference to the value
+    ///
+    /// Const reference to the value of the \c Second type.
+    /// \pre The BiVariant should store value of \c Second type.
     const Second& second() const { 
       LEMON_ASSERT(!flag, WrongStateError());
       return *reinterpret_cast<const Second*>(data); 
     }
 
+    /// \brief Operator form of the \c second()
     operator Second&() { return second(); }
+    /// \brief Operator form of the const \c second()
     operator const Second&() const { return second(); }
 
+    /// \brief %True when the variant is in the first state
+    ///
+    /// %True when the variant stores value of the \c First type.
     bool firstState() const { return flag; }
+
+    /// \brief %True when the variant is in the second state
+    ///
+    /// %True when the variant stores value of the \c Second type.
     bool secondState() const { return !flag; }
 
   private:
@@ -229,10 +239,269 @@
       }
     }
     
-    char data[CTMax<sizeof(First), sizeof(Second)>::value];
+    char data[_variant_bits::CTMax<sizeof(First), sizeof(Second)>::value];
     bool flag;
   };
 
+  namespace _variant_bits {
+    
+    template <int _idx, typename _TypeMap>
+    struct Memory {
+
+      typedef typename _TypeMap::template Map<_idx>::Type Current;
+
+      static void destroy(int index, char* place) {
+        if (index == _idx) {
+          reinterpret_cast<Current*>(place)->~Current();
+        } else {
+          Memory<_idx - 1, _TypeMap>::destroy(index, place);
+        }
+      }
+
+      static void copy(int index, char* to, const char* from) {
+        if (index == _idx) {
+          new (reinterpret_cast<Current*>(to))
+            Current(reinterpret_cast<const Current*>(from));
+        } else {
+          Memory<_idx - 1, _TypeMap>::copy(index, to, from);
+        }
+      }
+
+    };
+
+    template <typename _TypeMap>
+    struct Memory<-1, _TypeMap> {
+
+      static void destroy(int, char*) {
+        LEMON_ASSERT(false, "Wrong Variant Index.");
+      }
+
+      static void copy(int, char*, const char*) {
+        LEMON_ASSERT(false, "Wrong Variant Index.");
+      }
+    };
+
+    template <int _idx, typename _TypeMap>
+    struct Size {
+      static const int value = 
+      CTMax<sizeof(typename _TypeMap::template Map<_idx>::Type), 
+            Size<_idx - 1, _TypeMap>::value>::value;
+    };
+
+    template <typename _TypeMap>
+    struct Size<0, _TypeMap> {
+      static const int value = 
+      sizeof(typename _TypeMap::template Map<0>::Type);
+    };
+
+  }
+
+  /// \brief Variant type
+  ///
+  /// Simple Variant type. The Variant type is a type safe union. The
+  /// C++ has strong limitations for using unions, by example we
+  /// cannot store type with non default constructor or destructor in
+  /// a union. This class always knowns the current state of the
+  /// variant and it cares for the proper construction and
+  /// destruction.
+  ///
+  /// \param _num The number of the types which can be stored in the
+  /// variant type.
+  /// \param _TypeMap This class describes the types of the Variant. The
+  /// _TypeMap::Map<index>::Type should be a valid type for each index 
+  /// in the range {0, 1, ..., _num - 1}. The \c VariantTypeMap is helper
+  /// class to define such type mappings up to 10 types.
+  ///
+  /// And the usage of the class:
+  ///\code
+  /// typedef Variant<3, VariantTypeMap<int, std::string, double> > MyVariant;
+  /// MyVariant var;
+  /// var.set<0>(12);
+  /// std::cout << var.get<0>() << std::endl;
+  /// var.set<1>("alpha");
+  /// std::cout << var.get<1>() << std::endl;
+  /// var.set<2>(0.75);
+  /// std::cout << var.get<2>() << std::endl;
+  ///\endcode
+  ///
+  /// The result of course:
+  ///\code
+  /// 12
+  /// alpha
+  /// 0.75
+  ///\endcode
+  template <int _num, typename _TypeMap>
+  class Variant {
+  public:
+
+    static const int num = _num;
+
+    typedef _TypeMap TypeMap;
+
+    struct WrongStateError : public lemon::LogicError {
+    public:
+      virtual const char* what() const throw() {
+        return "lemon::Variant::WrongStateError";
+      }
+    };
+
+    /// \brief Constructor
+    ///
+    /// This constructor initalizes to the default value of the \c type
+    /// with 0 index.
+    Variant() {
+      flag = 0;
+      new(reinterpret_cast<typename TypeMap::template Map<0>::Type*>(data)) 
+        typename TypeMap::template Map<0>::Type();
+    }
+
+
+    /// \brief Copy constructor
+    ///
+    /// Copy constructor
+    Variant(const Variant& variant) {
+      flag = variant.flag;
+      _variant_bits::Memory<num - 1, TypeMap>::copy(flag, data, variant.data);
+    }
+
+    /// \brief Assign operator
+    ///
+    /// Assign operator
+    Variant& operator=(const Variant& variant) {
+      if (this == &variant) return *this;
+      _variant_bits::Memory<num - 1, TypeMap>::
+        destroy(flag, data);
+      flag = variant.flag;
+      _variant_bits::Memory<num - 1, TypeMap>::
+        copy(flag, data, variant.data);
+      return *this;
+    }
+
+    /// \brief Destrcutor
+    ///
+    /// Destructor
+    ~Variant() {
+      _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
+    }
+
+    /// \brief Set to the default value of the type with \c _idx index.
+    ///
+    /// This function sets the variant to the default value of the
+    /// type with \c _idx index.
+    template <int _idx>
+    Variant& set() {
+      _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
+      flag = _idx;
+      new(reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>(data)) 
+        typename TypeMap::template Map<_idx>::Type();
+      return *this;
+    }
+
+    /// \brief Set to the given value of the type with \c _idx index.
+    ///
+    /// This function sets the variant to the given value of the type
+    /// with \c _idx index.
+    template <int _idx>
+    Variant& set(const typename _TypeMap::template Map<_idx>::Type& init) {
+      _variant_bits::Memory<num - 1, TypeMap>::destroy(flag, data);
+      flag = _idx;
+      new(reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>(data)) 
+        typename TypeMap::template Map<_idx>::Type(init);
+      return *this;
+    }
+
+    /// \brief Gets the current value of the type with \c _idx index.
+    ///
+    /// Gets the current value of the type with \c _idx index.
+    template <int _idx>
+    const typename TypeMap::template Map<_idx>::Type& get() const {
+      LEMON_ASSERT(_idx == flag, "Wrong Variant Index.");
+      return *reinterpret_cast<const typename TypeMap::
+        template Map<_idx>::Type*>(data); 
+    }
+
+    /// \brief Gets the current value of the type with \c _idx index.
+    ///
+    /// Gets the current value of the type with \c _idx index.
+    template <int _idx>
+    typename _TypeMap::template Map<_idx>::Type& get() {
+      LEMON_ASSERT(_idx == flag, "Wrong Variant Index.");
+      return *reinterpret_cast<typename TypeMap::template Map<_idx>::Type*>
+        (data); 
+    }
+
+    /// \brief Returns the current state of the variant.
+    ///
+    /// Returns the current state of the variant.
+    int state() const {
+      return flag;
+    }
+
+  private:
+    
+    char data[_variant_bits::Size<num - 1, TypeMap>::value];
+    int flag;
+  };
+
+  namespace _variant_bits {
+
+    template <int _index, typename _List>
+    struct Get {
+      typedef typename Get<_index - 1, typename _List::Next>::Type Type;
+    };
+
+    template <typename _List>
+    struct Get<0, _List> {
+      typedef typename _List::Type Type;
+    };
+
+    struct List {};
+    
+    template <typename _Type, typename _List>
+    struct Insert {
+      typedef _List Next;
+      typedef _Type Type;
+    };
+
+    template <int _idx, typename _T0, typename _T1, typename _T2, 
+              typename _T3, typename _T5, typename _T4, typename _T6,
+              typename _T7, typename _T8, typename _T9>
+    struct Mapper {
+      typedef List L10;
+      typedef Insert<_T9, L10> L9;
+      typedef Insert<_T8, L9> L8;
+      typedef Insert<_T7, L8> L7;
+      typedef Insert<_T6, L7> L6;
+      typedef Insert<_T5, L6> L5;
+      typedef Insert<_T4, L5> L4;
+      typedef Insert<_T3, L4> L3;
+      typedef Insert<_T2, L3> L2;
+      typedef Insert<_T1, L2> L1;
+      typedef Insert<_T0, L1> L0;
+      typedef typename Get<_idx, L0>::Type Type;
+    };
+    
+  }
+
+  /// \brief Helper class for Variant
+  ///
+  /// Helper class to define type mappings for Variant. This class
+  /// converts the template parameters to be mappable by integer.
+  /// \see Variant
+  template <
+    typename _T0, 
+    typename _T1 = void, typename _T2 = void, typename _T3 = void,
+    typename _T5 = void, typename _T4 = void, typename _T6 = void,
+    typename _T7 = void, typename _T8 = void, typename _T9 = void>
+  struct VariantTypeMap {
+    template <int _idx>
+    struct Map {
+      typedef typename _variant_bits::
+      Mapper<_idx, _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9>::Type
+      Type;
+    };
+  };
+  
 }
 
 



More information about the Lemon-commits mailing list