deba@2177: /* -*- C++ -*-
deba@2177:  *
deba@2177:  * This file is a part of LEMON, a generic C++ optimization library
deba@2177:  *
deba@2177:  * Copyright (C) 2003-2006
deba@2177:  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@2177:  * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@2177:  *
deba@2177:  * Permission to use, modify and distribute this software is granted
deba@2177:  * provided that this copyright notice appears in all copies. For
deba@2177:  * precise terms see the accompanying LICENSE file.
deba@2177:  *
deba@2177:  * This software is provided "AS IS" with no warranty of any kind,
deba@2177:  * express or implied, and with no claim as to its suitability for any
deba@2177:  * purpose.
deba@2177:  *
deba@2177:  */
deba@2177: 
deba@2177: #ifndef LEMON_BITS_VARIANT_H
deba@2177: #define LEMON_BITS_VARIANT_H
deba@2177: 
deba@2177: #include <lemon/error.h>
deba@2177: 
deba@2177: namespace lemon {
deba@2177: 
deba@2177:   template <bool left, bool right>
deba@2177:   struct CTOr {
deba@2177:     static const bool value = true;
deba@2177:   };
deba@2177: 
deba@2177:   template <>
deba@2177:   struct CTOr<false, false> {
deba@2177:     static const bool value = false;
deba@2177:   };
deba@2177: 
deba@2177:   template <bool left, bool right>
deba@2177:   struct CTAnd {
deba@2177:     static const bool value = false;
deba@2177:   };
deba@2177: 
deba@2177:   template <>
deba@2177:   struct CTAnd<true, true> {
deba@2177:     static const bool value = true;
deba@2177:   };
deba@2177: 
deba@2177:   template <int left, int right>
deba@2177:   struct CTEqual {
deba@2177:     static const bool value = false;
deba@2177:   };
deba@2177: 
deba@2177:   template <int val>
deba@2177:   struct CTEqual<val, val> {
deba@2177:     static const bool value = true;
deba@2177:   };
deba@2177: 
deba@2177: 
deba@2177:   template <int left, int right>
deba@2177:   struct CTLess {
deba@2177:     static const bool value = left < right;
deba@2177:   };
deba@2177: 
deba@2177:   template <int left>
deba@2177:   struct CTLess<left, 0> {
deba@2177:     static const bool value = false;
deba@2177:   };
deba@2177: 
deba@2177:   template <int right>
deba@2177:   struct CTLess<0, right> {
deba@2177:     static const bool value = true;
deba@2177:   };
deba@2177: 
deba@2177:   template <>
deba@2177:   struct CTLess<0, 0> {
deba@2177:     static const bool value = false;
deba@2177:   };
deba@2177: 
deba@2177:   template <>
deba@2177:   struct CTLess<1, 1> {
deba@2177:     static const bool value = false;
deba@2177:   };
deba@2177: 
deba@2177:   template <bool less, int left, int right>
deba@2177:   struct CTMaxImpl {
deba@2177:     static const int value = left;    
deba@2177:   };
deba@2177: 
deba@2177:   template <int left, int right>
deba@2177:   struct CTMaxImpl<true, left, right> {
deba@2177:     static const int value = right;
deba@2177:   };
deba@2177:   
deba@2177:   template <int left, int right>
deba@2177:   struct CTMax {
deba@2177:     static const int value = 
deba@2177:     CTMaxImpl<CTLess<left, right>::value, left, right>::value;
deba@2177:   };
deba@2177: 
deba@2177: 
deba@2177:   /// \brief Simple Variant type with two type
deba@2177:   ///
deba@2177:   /// Simple Variant type with two type
deba@2177:   template <typename _First, typename _Second>
deba@2177:   class BiVariant {
deba@2177:   public:
deba@2177: 
deba@2177:     typedef _First First;
deba@2177:     typedef _Second Second;
deba@2177: 
deba@2177:     struct WrongStateError : public lemon::LogicError {
deba@2177:     public:
deba@2177:       virtual const char* what() const throw() {
deba@2177:         return "lemon::BiVariant::WrongStateError";
deba@2177:       }
deba@2177:     };
deba@2177: 
deba@2177:     BiVariant() {
deba@2177:       flag = true;
deba@2177:       new(reinterpret_cast<First*>(data)) First();
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant(const First& first) {
deba@2177:       flag = true;
deba@2177:       new(reinterpret_cast<First*>(data)) First(first);
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant(const Second& second) {
deba@2177:       flag = false;
deba@2177:       new(reinterpret_cast<Second*>(data)) Second(second);
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant(const BiVariant& bivariant) {
deba@2177:       flag = bivariant.flag;
deba@2177:       if (flag) {
deba@2177:         new(reinterpret_cast<First*>(data)) First(bivariant.first());      
deba@2177:       } else {
deba@2177:         new(reinterpret_cast<Second*>(data)) Second(bivariant.second());      
deba@2177:       }
deba@2177:     }
deba@2177: 
deba@2177:     ~BiVariant() {
deba@2177:       destroy();
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant& setFirst() {
deba@2177:       destroy();
deba@2177:       flag = true;
deba@2177:       new(reinterpret_cast<First*>(data)) First();   
deba@2177:       return *this;
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant& setFirst(const First& first) {
deba@2177:       destroy();
deba@2177:       flag = true;
deba@2177:       new(reinterpret_cast<First*>(data)) First(first);   
deba@2177:       return *this;
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant& setSecond() {
deba@2177:       destroy();
deba@2177:       flag = false;
deba@2177:       new(reinterpret_cast<Second*>(data)) Second();   
deba@2177:       return *this;
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant& setSecond(const Second& second) {
deba@2177:       destroy();
deba@2177:       flag = false;
deba@2177:       new(reinterpret_cast<Second*>(data)) Second(second);   
deba@2177:       return *this;
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant& operator=(const First& first) {
deba@2177:       return setFirst(first);
deba@2177:     }
deba@2177: 
deba@2177:     BiVariant& operator=(const Second& second) {
deba@2177:       return setSecond(second);
deba@2177:     }
deba@2177: 
deba@2177: 
deba@2177:     BiVariant& operator=(const BiVariant& bivariant) {
deba@2177:       if (this == &bivariant) return *this;
deba@2177:       destroy();
deba@2177:       flag = bivariant.flag;
deba@2177:       if (flag) {
deba@2177:         new(reinterpret_cast<First*>(data)) First(bivariant.first());      
deba@2177:       } else {
deba@2177:         new(reinterpret_cast<Second*>(data)) Second(bivariant.second());      
deba@2177:       }
deba@2177:       return *this;
deba@2177:     }
deba@2177: 
deba@2177:     First& first() {
deba@2177:       LEMON_ASSERT(flag, WrongStateError());
deba@2177:       return *reinterpret_cast<First*>(data); 
deba@2177:     }
deba@2177: 
deba@2177:     const First& first() const { 
deba@2177:       LEMON_ASSERT(flag, WrongStateError());
deba@2177:       return *reinterpret_cast<const First*>(data); 
deba@2177:     }
deba@2177: 
deba@2177:     operator First&() { return first(); }
deba@2177:     operator const First&() const { return first(); }
deba@2177: 
deba@2177:     Second& second() { 
deba@2177:       LEMON_ASSERT(!flag, WrongStateError());
deba@2177:       return *reinterpret_cast<Second*>(data); 
deba@2177:     }
deba@2177: 
deba@2177:     const Second& second() const { 
deba@2177:       LEMON_ASSERT(!flag, WrongStateError());
deba@2177:       return *reinterpret_cast<const Second*>(data); 
deba@2177:     }
deba@2177: 
deba@2177:     operator Second&() { return second(); }
deba@2177:     operator const Second&() const { return second(); }
deba@2177: 
deba@2177:     bool firstState() const { return flag; }
deba@2177:     bool secondState() const { return !flag; }
deba@2177: 
deba@2177:   private:
deba@2177: 
deba@2177:     void destroy() {
deba@2177:       if (flag) {
deba@2177:         reinterpret_cast<First*>(data)->~First();
deba@2177:       } else {
deba@2177:         reinterpret_cast<Second*>(data)->~Second();
deba@2177:       }
deba@2177:     }
deba@2177:     
deba@2177:     char data[CTMax<sizeof(First), sizeof(Second)>::value];
deba@2177:     bool flag;
deba@2177:   };
deba@2177: 
deba@2177: }
deba@2177: 
deba@2177: 
deba@2177: #endif