text: //  (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock 2000.
  //  Use, modification and distribution are subject to the Boost Software License,
  //  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  //  http://www.boost.org/LICENSE_1_0.txt).
  //
  //  See http://www.boost.org/libs/utility for most recent version including documentation.
  //  see libs/utility/compressed_pair.hpp
  //
  /* Release notes:
     20 Jan 2001:
          Fixed obvious bugs (David Abrahams)
     07 Oct 2000:
        Added better single argument constructor support.
     03 Oct 2000:
        Added VC6 support (JM).
     23rd July 2000:
        Additional comments added. (JM)
     Jan 2000:
        Original version: this version crippled for use with crippled compilers
        - John Maddock Jan 2000.
  */
  
  
  #ifndef BOOST_OB_COMPRESSED_PAIR_HPP
  #define BOOST_OB_COMPRESSED_PAIR_HPP
  
  #include <algorithm>
  #ifndef BOOST_OBJECT_TYPE_TRAITS_HPP
  #include <boost/type_traits/object_traits.hpp>
  #endif
  #ifndef BOOST_SAME_TRAITS_HPP
  #include <boost/type_traits/same_traits.hpp>
  #endif
  #ifndef BOOST_CALL_TRAITS_HPP
  #include <boost/call_traits.hpp>
  #endif
  
  namespace boost
  {
  #ifdef BOOST_MSVC6_MEMBER_TEMPLATES
  //
  // use member templates to emulate
  // partial specialisation.  Note that due to
  // problems with overload resolution with VC6
  // each of the compressed_pair versions that follow
  // have one template single-argument constructor
  // in place of two specific constructors:
  //
  
  template <class T1, class T2>
  class compressed_pair;
  
  namespace detail{
  
  template <class A, class T1, class T2>
  struct best_conversion_traits
  {
     typedef char one;
     typedef char (&two)[2];
     static A a;
     static one test(T1);
     static two test(T2);
  
     enum { value = sizeof(test(a)) };
  };
  
  template <int>
  struct init_one;
  
  template <>
  struct init_one<1>
  {
     template <class A, class T1, class T2>
     static void init(const A& a, T1* p1, T2*)
     {
        *p1 = a;
     }
  };
  
  template <>
  struct init_one<2>
  {
     template <class A, class T1, class T2>
     static void init(const A& a, T1*, T2* p2)
     {
        *p2 = a;
     }
  };
  
  
  // T1 != T2, both non-empty
  template <class T1, class T2>
  class compressed_pair_0
  {
  private:
     T1 _first;
     T2 _second;
  public:
     typedef T1                                                 first_type;
     typedef T2                                                 second_type;
     typedef typename call_traits<first_type>::param_type       first_param_type;
     typedef typename call_traits<second_type>::param_type      second_param_type;
     typedef typename call_traits<first_type>::reference        first_reference;
     typedef typename call_traits<second_type>::reference       second_reference;
     typedef typename call_traits<first_type>::const_reference  first_const_reference;
     typedef typename call_traits<second_type>::const_reference second_const_reference;
  
              compressed_pair_0() : _first(), _second() {}
              compressed_pair_0(first_param_type x, second_param_type y) : _first(x), _second(y) {}
     template <class A>
     explicit compressed_pair_0(const A& val)
     {
        init_one<best_conversion_traits<A, T1, T2>::value>::init(val, &_first, &_second);
     }
     compressed_pair_0(const ::boost::compressed_pair<T1,T2>& x)
        : _first(x.first()), _second(x.second()) {}
  
  #if 0
    compressed_pair_0& operator=(const compressed_pair_0& x) {
      cout << "assigning compressed pair 0" << endl;
      _first = x._first;
      _second = x._second;
      cout << "finished assigning compressed pair 0" << endl;
      return *this;
    }
  #endif
  
     first_reference       first()       { return _first; }
     first_const_reference first() const { return _first; }
  
     second_reference       second()       { return _second; }
     second_const_reference second() const { return _second; }
  
     void swap(compressed_pair_0& y)
     {
        using std::swap;
        swap(_first, y._first);
        swap(_second, y._second);
     }
  };
  
  // T1 != T2, T2 empty
  template <class T1, class T2>
  class compressed_pair_1 : T2
  {
  private:
     T1 _first;
  public:
     typedef T1                                                 first_type;
     typedef T2                                                 second_type;
     typedef typename call_traits<first_type>::param_type       first_param_type;
     typedef typename call_traits<second_type>::param_type      second_param_type;
     typedef typename call_traits<first_type>::reference        first_reference;
     typedef typename call_traits<second_type>::reference       second_reference;
     typedef typename call_traits<first_type>::const_reference  first_const_reference;
     typedef typename call_traits<second_type>::const_reference second_const_reference;
  
              compressed_pair_1() : T2(), _first() {}
              compressed_pair_1(first_param_type x, second_param_type y) : T2(y), _first(x) {}
  
     template <class A>
     explicit compressed_pair_1(const A& val)
     {
        init_one<best_conversion_traits<A, T1, T2>::value>::init(val, &_first, static_cast<T2*>(this));
     }
  
     compressed_pair_1(const ::boost::compressed_pair<T1,T2>& x)
        : T2(x.second()), _first(x.first()) {}
  
  #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
    // Total weirdness. If the assignment to _first is moved after
    // the call to the inherited operator=, then this breaks graph/test/graph.cpp
    // by way of iterator_adaptor.
    compressed_pair_1& operator=(const compressed_pair_1& x) {
      _first = x._first;
      T2::operator=(x);
      return *this;
    }
  #endif
  
     first_reference       first()       { return _first; }
     first_const_reference first() const { return _first; }
  
     second_reference       second()       { return *this; }
     second_const_reference second() const { return *this; }
  
     void swap(compressed_pair_1& y)
     {
        // no need to swap empty base class:
        using std::swap;
        swap(_first, y._first);
     }
  };
  
  // T1 != T2, T1 empty
  template <class T1, class T2>
  class compressed_pair_2 : T1
  {
  private:
     T2 _second;
  public:
     typedef T1                                                 first_type;
     typedef T2                                                 second_type;
     typedef typename call_traits<first_type>::param_type       first_param_type;
     typedef typename call_traits<second_type>::param_type      second_param_type;
     typedef typename call_traits<first_type>::reference        first_reference;
     typedef typename call_traits<second_type>::reference       second_reference;
     typedef typename call_traits<first_type>::const_reference  first_const_reference;
     typedef typename call_traits<second_type>::const_reference second_const_reference;
  
              compressed_pair_2() : T1(), _second() {}
              compressed_pair_2(first_param_type x, second_param_type y) : T1(x), _second(y) {}
     template <class A>
     explicit compressed_pair_2(const A& val)
     {
        init_one<best_conversion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), &_second);
     }
     compressed_pair_2(const ::boost::compressed_pair<T1,T2>& x)
        : T1(x.first()), _second(x.second()) {}
  
  #if 0
    compressed_pair_2& operator=(const compressed_pair_2& x) {
      cout << "assigning compressed pair 2" << endl;
      T1::operator=(x);
      _second = x._second;
      cout << "finished assigning compressed pair 2" << endl;
      return *this;
    }
  #endif
     first_reference       first()       { return *this; }
     first_const_reference first() const { return *this; }
  
     second_reference       second()       { return _second; }
     second_const_reference second() const { return _second; }
  
     void swap(compressed_pair_2& y)
     {
        // no need to swap empty base class:
        using std::swap;
        swap(_second, y._second);
     }
  };
  
  // T1 != T2, both empty
  template <class T1, class T2>
  class compressed_pair_3 : T1, T2
  {
  public:
     typedef T1                                                 first_type;
     typedef T2                                                 second_type;
     typedef typename call_traits<first_type>::param_type       first_param_type;
     typedef typename call_traits<second_type>::param_type      second_param_type;
     typedef typename call_traits<first_type>::reference        first_reference;
     typedef typename call_traits<second_type>::reference       second_reference;
     typedef typename call_traits<first_type>::const_reference  first_const_reference;
     typedef typename call_traits<second_type>::const_reference second_const_reference;
  
              compressed_pair_3() : T1(), T2() {}
              compressed_pair_3(first_param_type x, second_param_type y) : T1(x), T2(y) {}
     template <class A>
     explicit compressed_pair_3(const A& val)
     {
        init_one<best_conversion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), static_cast<T2*>(this));
     }
     compressed_pair_3(const ::boost::compressed_pair<T1,T2>& x)
        : T1(x.first()), T2(x.second()) {}
  
     first_reference       first()       { return *this; }
     first_const_reference first() const { return *this; }
  
     second_reference       second()       { return *this; }
     second_const_reference second() const { return *this; }
  
     void swap(compressed_pair_3& y)
     {
        // no need to swap empty base classes:
     }
  };
  
  // T1 == T2, and empty
  template <class T1, class T2>
  class compressed_pair_4 : T1
  {
  public:
     typedef T1                                                 first_type;
     typedef T2                                                 second_type;
     typedef typename call_traits<first_type>::param_type       first_param_type;
     typedef typename call_traits<second_type>::param_type      second_param_type;
     typedef typename call_traits<first_type>::reference        first_reference;
     typedef typename call_traits<second_type>::reference       second_reference;
     typedef typename call_traits<first_type>::const_reference  first_const_reference;
     typedef typename call_traits<second_type>::const_reference second_const_reference;
  
              compressed_pair_4() : T1() {}
              compressed_pair_4(first_param_type x, second_param_type y) : T1(x), m_second(y) {}
     // only one single argument constructor since T1 == T2
     explicit compressed_pair_4(first_param_type x) : T1(x), m_second(x) {}
     compressed_pair_4(const ::boost::compressed_pair<T1,T2>& x)
        : T1(x.first()), m_second(x.second()) {}
  
     first_reference       first()       { return *this; }
     first_const_reference first() const { return *this; }
  
     second_reference       second()       { return m_second; }
     second_const_reference second() const { return m_second; }
  
     void swap(compressed_pair_4& y)
     {
        // no need to swap empty base classes:
     }
  private:
     T2 m_second;
  };
  
  // T1 == T2, not empty
  template <class T1, class T2>
  class compressed_pair_5
  {
  private:
     T1 _first;
     T2 _second;
  public:
     typedef T1                                                 first_type;
     typedef T2                                                 second_type;
     typedef typename call_traits<first_type>::param_type       first_param_type;
     typedef typename call_traits<second_type>::param_type      second_param_type;
     typedef typename call_traits<first_type>::reference        first_reference;
     typedef typename call_traits<second_type>::reference       second_reference;
     typedef typename call_traits<first_type>::const_reference  first_const_reference;
     typedef typename call_traits<second_type>::const_reference second_const_reference;
  
              compressed_pair_5() : _first(), _second() {}
              compressed_pair_5(first_param_type x, second_param_type y) : _first(x), _second(y) {}
     // only one single argument constructor since T1 == T2
     explicit compressed_pair_5(first_param_type x) : _first(x), _second(x) {}
     compressed_pair_5(const ::boost::compressed_pair<T1,T2>& c) 
        : _first(c.first()), _second(c.second()) {}
  
     first_reference       first()       { return _first; }
     first_const_reference first() const { return _first; }
  
     second_reference       second()       { return _second; }
     second_const_reference second() const { return _second; }
  
     void swap(compressed_pair_5& y)
     {
        using std::swap;
        swap(_first, y._first);
        swap(_second, y._second);
     }
  };
  
  template <bool e1, bool e2, bool same>
  struct compressed_pair_chooser
  {
     template <class T1, class T2>
     struct rebind
     {
        typedef compressed_pair_0<T1, T2> type;
     };
  };
  
  template <>
  struct compressed_pair_chooser<false, true, false>
  {
     template <class T1, class T2>
     struct rebind
     {
        typedef compressed_pair_1<T1, T2> type;
     };
  };
  
  template <>
  struct compressed_pair_chooser<true, false, false>
  {
     template <class T1, class T2>
     struct rebind
     {
        typedef compressed_pair_2<T1, T2> type;
     };
  };
  
  template <>
  struct compressed_pair_chooser<true, true, false>
  {
     template <class T1, class T2>
     struct rebind
     {
        typedef compressed_pair_3<T1, T2> type;
     };
  };
  
  template <>
  struct compressed_pair_chooser<true, true, true>
  {
     template <class T1, class T2>
     struct rebind
     {
        typedef compressed_pair_4<T1, T2> type;
     };
  };
  
  template <>
  struct compressed_pair_chooser<false, false, true>
  {
     template <class T1, class T2>
     struct rebind
     {
        typedef compressed_pair_5<T1, T2> type;
     };
  };
  
  template <class T1, class T2>
  struct compressed_pair_traits
  {
  private:
     typedef compressed_pair_chooser<is_empty<T1>::value, is_empty<T2>::value, is_same<T1,T2>::value> chooser;
     typedef typename chooser::template rebind<T1, T2> bound_type;
  public:
     typedef typename bound_type::type type;
  };
  
  } // namespace detail
  
  template <class T1, class T2>
  class compressed_pair : public detail::compressed_pair_traits<T1, T2>::type
  {
  private:
     typedef typename detail::compressed_pair_traits<T1, T2>::type base_type;
  public:
     typedef T1                                                 first_type;
     typedef T2                                                 second_type;
     typedef typename call_traits<first_type>::param_type       first_param_type;
     typedef typename call_traits<second_type>::param_type      second_param_type;
     typedef typename call_traits<first_type>::reference        first_reference;
     typedef typename call_traits<second_type>::reference       second_reference;
     typedef typename call_traits<first_type>::const_reference  first_const_reference;
     typedef typename call_traits<second_type>::const_reference second_const_reference;
  
              compressed_pair() : base_type() {}
              compressed_pair(first_param_type x, second_param_type y) : base_type(x, y) {}
     template <class A>
     explicit compressed_pair(const A& x) : base_type(x){}
  
     first_reference       first()       { return base_type::first(); }
     first_const_reference first() const { return base_type::first(); }
  
     second_reference       second()       { return base_type::second(); }
     second_const_reference second() const { return base_type::second(); }
  };
  
  template <class T1, class T2>
  inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
  {
     x.swap(y);
  }
  
  #else
  // no partial specialisation, no member templates:
  
  template <class T1, class T2>
  class compressed_pair
  {
  private:
     T1 _first;
     T2 _second;
  public:
     typedef T1                                                 first_type;
     typedef T2                                                 second_type;
     typedef typename call_traits<first_type>::param_type       first_param_type;
     typedef typename call_traits<second_type>::param_type      second_param_type;
     typedef typename call_traits<first_type>::reference        first_reference;
     typedef typename call_traits<second_type>::reference       second_reference;
     typedef typename call_traits<first_type>::const_reference  first_const_reference;
     typedef typename call_traits<second_type>::const_reference second_const_reference;
  
              compressed_pair() : _first(), _second() {}
              compressed_pair(first_param_type x, second_param_type y) : _first(x), _second(y) {}
     explicit compressed_pair(first_param_type x) : _first(x), _second() {}
     // can't define this in case T1 == T2:
     // explicit compressed_pair(second_param_type y) : _first(), _second(y) {}
  
     first_reference       first()       { return _first; }
     first_const_reference first() const { return _first; }
  
     second_reference       second()       { return _second; }
     second_const_reference second() const { return _second; }
  
     void swap(compressed_pair& y)
     {
        using std::swap;
        swap(_first, y._first);
        swap(_second, y._second);
     }
  };
  
  template <class T1, class T2>
  inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
  {
     x.swap(y);
  }
  
  #endif
  
  } // boost
  
  #endif // BOOST_OB_COMPRESSED_PAIR_HPP
  
  
  
  