// (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 | |