Forked from
Core Modules / dune-common
7246 commits behind the upstream repository.
-
Markus Blatt authored
[[Imported from SVN: r4782]]
Markus Blatt authored[[Imported from SVN: r4782]]
tuples.hh 22.14 KiB
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// $Id$
#ifndef DUNE_TUPLES_HH
#define DUNE_TUPLES_HH
#include <ostream>
#include "typetraits.hh"
#include "helpertemplates.hh"
namespace Dune
{
/** @addtogroup Common
*
* @{
*/
/**
* @file
* @brief Contains classes that implement tuples.
*
* This a refined implementation of the approach defined in
* in the article "Tuples and multiple return values
* in C++" of Jaakko Järvi (Turku Centre of Computer
* Science, TUCS Technical Report No 249, March 1999,
* ISBN 952-12-0401-X, ISSN 1239-1891) available from the
* <a href="http://www.tucs.fi/publications/">TUCS publications archive</a>
* @author Markus Blatt
*/
/**
* @brief An empty class.
*/
struct Nil
{};
namespace
{
inline const Nil nullType()
{
return Nil();
}
}
template<class T>
struct TupleAccessTraits
{
typedef typename ConstantVolatileTraits<T>::ConstType& ConstType;
typedef T& NonConstType;
typedef const typename ConstantVolatileTraits<T>::UnqualifiedType& ParameterType;
};
template<class T>
struct TupleAccessTraits<T*>
{
typedef typename ConstantVolatileTraits<T>::ConstType* ConstType;
typedef T* NonConstType;
typedef T* ParameterType;
};
template<class T>
struct TupleAccessTraits<T&>
{
typedef typename ConstantVolatileTraits<T>::ConstType& ConstType;
typedef T& NonConstType;
typedef T& ParameterType;
};
/**
* @brief A tuple consisting of two objects.
*
* This is similar to std::pair
*/
template<typename T1, typename TT>
struct Pair
{
/**
* @brief The type of the first field.
*/
typedef T1 Type1;
/**
* @brief The type of the first field.
*/
typedef TT Type2;
// enum{
// /**
// * @brief The number of values we hold.
// */
// values = 2;
// };
/**
* @brief Constructor
*
* @param t1 The value of the first field.
* @param t2 The value of the second field.
*/
template<typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9>
Pair(typename TupleAccessTraits<T1>::ParameterType t1, T2& t2, T3& t3, T4& t4, T5& t5,
T6& t6, T7& t7, T8& t8, T9& t9);
/**
* @brief Constructor
*
* @param t1 The value of the first field.
* @param t2 The value of the second field.
*/
Pair(typename TupleAccessTraits<Type1>::ParameterType t1, TT& t2);
Pair();
/**
* @brief Copy Constructor for implicit type conversion
* @param other The tuple to copy.
*/
template<typename U1, typename U2>
Pair(const Pair<U1,U2>& other);
/**
* @brief Assignment operator for implicit type conversion
* @param other The tuple to assign.
*/
template<typename U1, typename U2>
Pair& operator=(const Pair<U1,U2>& other);
Pair& operator=(const Pair& other);
/**
* @brief Get the first value
* @return The first value
*/
typename TupleAccessTraits<Type1>::NonConstType first();
/**
* @brief Get the first value
* @return The first value
*/
typename TupleAccessTraits<Type1>::ConstType
first() const;
/**
* @brief Get the second value
* @return The first value
*/
typename TupleAccessTraits<Type2>::NonConstType
second();
/**
* @brief Get the first value
* @return The second value
*/
typename TupleAccessTraits<Type2>::ConstType
second() const;
/** @brief The value of the first field. */
Type1 first_;
/** @brief The value of the second field. */
Type2 second_;
};
/**
* @brief A tuple consisting of one object.
* Specialization of Pair that really is a single value.
*/
template<typename T1>
struct Pair<T1,Nil>
{
/**
* @brief The type of the first field.
*/
typedef T1 Type1;
/**
* @brief The type of the (non-existent) second field is Nil.
* This typedef is useful in template metaprogramming, since it allows
* you to specialise for Nil instead of Pair<T, Nil>
*/
typedef Nil Type2;
/**
* @brief Constructor.
* @param t1 The values for the first field.
* @param t2 The value for the second field.
*/
Pair(typename TupleAccessTraits<T1>::ParameterType first, const Nil&, const Nil&, const Nil&, const Nil&,
const Nil&, const Nil&, const Nil&, const Nil&);
/**
* @brief Constructor.
* @param t1 The values for the first field.
* @param t2 The value for the second field.
*/
Pair(typename TupleAccessTraits<T1>::ParameterType first,
const Nil&);
Pair();
/**
* @brief Copy constructor for type conversion.
*/
template<typename T2>
Pair(const Pair<T2,Nil>& other);
/**
* @brief Assignment operator for type conversion.
*/
template<typename T2>
Pair& operator=(const Pair<T2,Nil>& other);
/**
* @brief Assignment operator.
*/
Pair& operator=(const Pair& other);
/**
* @brief Get the first value
* @return The first value
*/
typename TupleAccessTraits<Type1>::NonConstType
first();
/**
* @brief Get the first value
* @return The first value
*/
typename TupleAccessTraits<Type1>::ConstType
first() const;
/** @brief The value of the first field.*/
Type1 first_;
};
/**
* @brief Converts the Tuple to a list of pairs.
*/
template<typename T1, typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9>
struct TupleToPairs
{
typedef Pair<T1, typename TupleToPairs<T2,T3,T4,T5,T6,T7,T8,T9,Nil>::Type > Type;
};
/**
* @brief Specialization for a tuple consisting only of one type.
*/
template<typename T1>
struct TupleToPairs<T1,Nil,Nil,Nil,Nil,Nil,Nil,Nil,Nil>
{
typedef Pair<T1,Nil> Type;
};
/**
* @brief A Tuple of objects.
*
* A maximum of 9 objects is supported.
*
* Use the following construction to access the individual elements.
\code
Tuple<std::string, float*, int> my_tuple;
std:string& s = Element<0>::get(my_tuple);
float* p = Element<1>::get(my_tuple);
// Access the third element in a generic way
typedef ElementType<2, Tuple<std::string, float*, int> >::Type Type;
Type& i = Element<2>::get(my_tuple);
\endcode
*/
template<typename T1, typename T2 = Nil, typename T3 = Nil,
typename T4 = Nil, typename T5 = Nil,typename T6 = Nil,
typename T7 = Nil, typename T8 = Nil, typename T9 = Nil>
class Tuple : public TupleToPairs<T1,T2,T3,T4,T5,T6,T7,T8,T9>::Type
{
public:
//! Type of the first Pair defining the Tuple
typedef typename TupleToPairs<T1,T2,T3,T4,T5,T6,T7,T8,T9>::Type FirstPair;
Tuple()
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1)
: FirstPair(t1, nullType(), nullType(), nullType(),
nullType(), nullType(), nullType(), nullType(),
nullType())
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1,
typename TupleAccessTraits<T2>::ParameterType t2)
: FirstPair(t1, t2, nullType(), nullType(),
nullType(), nullType(), nullType(), nullType(),
nullType())
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1,
typename TupleAccessTraits<T2>::ParameterType t2,
typename TupleAccessTraits<T3>::ParameterType t3)
: FirstPair(t1, t2, t3, nullType(),
nullType(), nullType(), nullType(), nullType(),
nullType())
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1,
typename TupleAccessTraits<T2>::ParameterType t2,
typename TupleAccessTraits<T3>::ParameterType t3,
typename TupleAccessTraits<T4>::ParameterType t4)
: FirstPair(t1, t2, t3, t4,
nullType(), nullType(), nullType(), nullType(),
nullType())
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1,
typename TupleAccessTraits<T2>::ParameterType t2,
typename TupleAccessTraits<T3>::ParameterType t3,
typename TupleAccessTraits<T4>::ParameterType t4,
typename TupleAccessTraits<T5>::ParameterType t5)
: FirstPair(t1, t2, t3, t4,
t5, nullType(), nullType(), nullType(),
nullType())
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1,
typename TupleAccessTraits<T2>::ParameterType t2,
typename TupleAccessTraits<T3>::ParameterType t3,
typename TupleAccessTraits<T4>::ParameterType t4,
typename TupleAccessTraits<T5>::ParameterType t5,
typename TupleAccessTraits<T6>::ParameterType t6)
: FirstPair(t1, t2, t3, t4,
t5, t6, nullType(), nullType(),
nullType())
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1,
typename TupleAccessTraits<T2>::ParameterType t2,
typename TupleAccessTraits<T3>::ParameterType t3,
typename TupleAccessTraits<T4>::ParameterType t4,
typename TupleAccessTraits<T5>::ParameterType t5,
typename TupleAccessTraits<T6>::ParameterType t6,
typename TupleAccessTraits<T7>::ParameterType t7)
: FirstPair(t1, t2, t3, t4,
t5, t6, t7, nullType(),
nullType())
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1,
typename TupleAccessTraits<T2>::ParameterType t2,
typename TupleAccessTraits<T3>::ParameterType t3,
typename TupleAccessTraits<T4>::ParameterType t4,
typename TupleAccessTraits<T5>::ParameterType t5,
typename TupleAccessTraits<T6>::ParameterType t6,
typename TupleAccessTraits<T7>::ParameterType t7,
typename TupleAccessTraits<T8>::ParameterType t8)
: FirstPair(t1, t2, t3, t4,
t5, t6, t7, t8,
nullType())
{}
Tuple(typename TupleAccessTraits<T1>::ParameterType t1,
typename TupleAccessTraits<T2>::ParameterType t2,
typename TupleAccessTraits<T3>::ParameterType t3,
typename TupleAccessTraits<T4>::ParameterType t4,
typename TupleAccessTraits<T5>::ParameterType t5,
typename TupleAccessTraits<T6>::ParameterType t6,
typename TupleAccessTraits<T7>::ParameterType t7,
typename TupleAccessTraits<T8>::ParameterType t8,
typename TupleAccessTraits<T9>::ParameterType t9)
: FirstPair(t1, t2, t3, t4, t5, t6, t7, t8, t9)
{}
template<class U1, class U2>
Tuple& operator=(const Pair<U1,U2>& other)
{
FirstPair::operator=(other);
return *this;
}
};
/**
* @brief Get the type of the N-th element of the tuple.
*/
template<int N, class Tuple>
struct ElementType;
template<int N, typename T1, typename T2>
struct ElementType<N,Pair<T1,T2> >
{
/**
* @brief The type of the N-th element of the tuple.
*/
typedef typename ElementType<N-1,T2>::Type Type;
};
/**
* @brief Get the type of the first element of the tuple.
*/
template<typename T1, typename T2>
struct ElementType<0, Pair<T1,T2> >
{
/**
* @brief The type of the first element of the tuple.
*/
typedef T1 Type;
};
/**
* @brief Get the N-th element of a tuple.
*/
template<int N>
struct Element
{
/**
* @brief Get the N-th element of the tuple.
* @param tuple The tuple whose N-th element we want.
* @return The N-th element of the tuple.
*/
template<typename T1, typename T2>
static typename TupleAccessTraits<
typename ElementType<N,Pair<T1,T2> >::Type
>::NonConstType
get(Pair<T1,T2>& tuple)
{
return Element<N-1>::get(tuple.second());
}
/**
* @brief Get the N-th element of the tuple.
* @param tuple The tuple whose N-th element we want.
* @return The N-th element of the tuple.
*/
template<typename T1, typename T2>
static typename TupleAccessTraits<
typename ElementType<N,Pair<T1,T2> >::Type
>::ConstType
get(const Pair<T1,T2>& tuple)
{
return Element<N-1>::get(tuple.second());
}
};
/**
* @brief Get the first element of a tuple.
*/
template<>
struct Element<0>
{
/**
* @brief Get the first element of the tuple.
* @param tuple The tuple whose first element we want.
* @return The first element of the tuple.
*/
template<typename T1, typename T2>
static typename TupleAccessTraits<T1>::NonConstType get(Pair<T1,T2>& tuple)
{
return tuple.first();
}
/**
* @brief Get the first element of the tuple.
* @param tuple The tuple whose first element we want.
* @return The first element of the tuple.
*/
template<typename T1, typename T2>
static typename TupleAccessTraits<T1>::ConstType get(const Pair<T1,T2>& tuple)
{
return tuple.first();
}
};
/**
* @brief Equality comparison operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple,
*/
template<typename T1, typename T2, typename U1, typename U2>
inline bool operator==(const Pair<T1,T2>& tuple1, const Pair<U1,U2>& tuple2)
{
return (tuple1.first()==tuple2.first() && tuple1.second()==tuple2.second());
}
/**
* @brief Inequality comparison operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple,
*/
template<typename T1, typename T2, typename U1, typename U2>
inline bool operator!=(const Pair<T1,T2>& tuple1, const Pair<U1,U2>& tuple2)
{
return (tuple1.first()!=tuple2.first() || tuple1.second()!=tuple2.second());
}
/**
* @brief Less operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple,
*/
template<typename T1, typename T2, typename U1, typename U2>
inline bool operator<(const Pair<T1,T2>& tuple1, const Pair<U1,U2>& tuple2)
{
return tuple1.first() < tuple2.first()
|| (tuple1.first() == tuple2.first() && tuple1.second() < tuple2.second());
}
/**
* @brief Equality comparison operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple,
*/
template<typename T1,typename U1>
inline bool operator==(const Pair<T1,Nil>& tuple1, const Pair<U1,Nil>& tuple2)
{
return (tuple1.first()==tuple2.first());
}
/**
* @brief Inequality comparison operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple,
*/
template<typename T1, typename U1>
inline bool operator!=(const Pair<T1,Nil>& tuple1, const Pair<U1,Nil>& tuple2)
{
IsTrue<IsInteroperable<T1,U1>::value>::yes();
return (tuple1.first()!=tuple2.first());
}
/**
* @brief Less operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple,
*/
template<typename T1, typename U1>
inline bool operator<(const Pair<T1,Nil>& tuple1, const Pair<U1,Nil>& tuple2)
{
return (tuple1.first()<tuple2.first());
}
/**
* @brief Equality comparison operator for tuples.
*
* @param tuple1 The first tuple.
* @param tuple2 The second tuple.
* @return False as the type of the compared objects are different.
*/
template<typename T1,typename U1, typename U2>
inline bool operator==(const Pair<T1,Nil>& tuple1, const Pair<U1,U2>& tuple2)
{
return false;
}
/**
* @brief Inequality comparison operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple.
* @return True as the type of the compared objects are different.
*/
template<typename T1, typename U1, typename U2>
inline bool operator!=(const Pair<T1,Nil>& tuple1, const Pair<U1,U2>& tuple2)
{
return true;
}
/**
* @brief Equality comparison operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple.
* @return False as the type of the compared objects are different.
*/
template<typename T1, typename T2, typename U1>
inline bool operator==(const Pair<T1,T2>& tuple1, const Pair<U1,Nil>& tuple2)
{
return false;
}
/**
* @brief Inequality comparison operator for tuples.
* @param tuple1 The first tuple.
* @param tuple2 The second tuple.
* @return True as the type of the compared objects are different.
*/
template<typename T1, typename T2, typename U1>
inline bool operator!=(const Pair<T1,T2>& tuple1, const Pair<U1,Nil>& tuple2)
{
return true;
}
/**
* @brief Create a tuple and initialize it.
* @param first The value of the first field.
* @param second The value of the second field.
*/
template<typename T1, typename T2>
inline Pair<T1,T2> makePair(const T1& first, const T2& second)
{
return Pair<T1,T2>(first, second);
}
/**
* @brief Print a pair or tuple.
*/
template<typename T1, typename T2>
inline std::ostream& operator<<(std::ostream& os, const Pair<T1,T2>& pair)
{
os<<pair.first()<<" "<<pair.second();
return os;
}
template<typename T1>
inline std::ostream& operator<<(std::ostream& os, const Pair<T1,Nil>& pair)
{
os<<pair.first();
return os;
}
template<class T1>
inline Tuple<T1&> tie(T1& t1) {
return Tuple<T1&> (t1);
}
template<class T1, class T2>
inline Tuple<T1&, T2&> tie(T1& t1, T2& t2) {
return Tuple<T1&, T2&> (t1, t2);
}
template<class T1, class T2, class T3>
inline Tuple<T1&, T2&, T3&> tie(T1& t1, T2& t2, T3& t3) {
return Tuple<T1&, T2&, T3&> (t1, t2, t3);
}
template<class T1, class T2, class T3, class T4>
inline Tuple<T1&, T2&, T3&, T4&> tie(T1& t1, T2& t2, T3& t3, T4& t4) {
return Tuple<T1&, T2&, T3&, T4&> (t1, t2, t3, t4);
}
template<class T1, class T2, class T3, class T4, class T5>
inline Tuple<T1&, T2&, T3&, T4&, T5&>
tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) {
return Tuple<T1&, T2&, T3&, T4&, T5&> (t1, t2, t3, t4, t5);
}
template<class T1, class T2, class T3, class T4, class T5, class T6>
inline Tuple<T1&, T2&, T3&, T4&, T5&, T6&>
tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6) {
return Tuple<T1&, T2&, T3&, T4&, T5&, T6&> (t1, t2, t3, t4, t5, t6);
}
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7>
inline Tuple<T1&, T2&, T3&, T4&, T5&, T6&, T7&>
tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7) {
return Tuple<T1&, T2&, T3&, T4&, T5&, T6&, T7&> (t1, t2, t3, t4, t5, t6, t7);
}
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7,
class T8>
inline Tuple<T1&, T2&, T3&, T4&, T5&, T6&, T7&, T8&>
tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8) {
return Tuple<T1&, T2&, T3&, T4&, T5&, T6&, T7&, T8&>
(t1, t2, t3, t4, t5, t6, t7, t8);
}
template<class T1, class T2, class T3, class T4, class T5, class T6, class T7,
class T8, class T9>
inline Tuple<T1&, T2&, T3&, T4&, T5&, T6&, T7&, T8&, T9&>
tie(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, T6& t6, T7& t7, T8& t8, T9& t9) {
return Tuple<T1&, T2&, T3&, T4&, T5&, T6&, T7&, T8&, T9&>
(t1, t2, t3, t4, t5, t6, t7, t8, t9);
}
template<typename T1, typename TT>
template<typename T2, typename T3, typename T4, typename T5,
typename T6, typename T7, typename T8, typename T9>
inline Pair<T1,TT>::Pair(typename TupleAccessTraits<T1>::ParameterType first,
T2& t2, T3& t3, T4& t4, T5& t5,
T6& t6, T7& t7, T8& t8, T9& t9)
: first_(first), second_(t2,t3,t4,t5,t6,t7,t8,t9, nullType())
{}
template <typename T1, typename TT>
inline Pair<T1, TT>::Pair(typename TupleAccessTraits<T1>::ParameterType first, TT& second)
: first_(first), second_(second)
{}
template<typename T1, typename T2>
inline Pair<T1,T2>::Pair()
: first_(), second_()
{}
template<typename T1, typename T2>
template<typename U1, typename U2>
inline Pair<T1,T2>::Pair(const Pair<U1,U2>& other)
: first_(other.first_), second_(other.second_)
{}
template<typename T1, typename T2>
template<typename U1, typename U2>
inline Pair<T1,T2>& Pair<T1,T2>::operator=(const Pair<U1,U2>& other)
{
first_=other.first_;
second_=other.second_;
return *this;
}
template<typename T1, typename T2>
inline Pair<T1,T2>& Pair<T1,T2>::operator=(const Pair& other)
{
first_=other.first_;
second_=other.second_;
return *this;
}
template<typename T1, typename T2>
inline typename TupleAccessTraits<T1>::NonConstType
Pair<T1,T2>::first()
{
return first_;
}
template<typename T1, typename T2>
inline typename TupleAccessTraits<T1>::ConstType
Pair<T1,T2>::first() const
{
return first_;
}
template<typename T1, typename T2>
inline typename TupleAccessTraits<T2>::NonConstType
Pair<T1,T2>::second()
{
return second_;
}
template<typename T1, typename T2>
inline typename TupleAccessTraits<T2>::ConstType
Pair<T1,T2>::second() const
{
return second_;
}
template<typename T1>
inline Pair<T1,Nil>::Pair(typename TupleAccessTraits<T1>::ParameterType first,
const Nil&, const Nil&, const Nil&, const Nil&,
const Nil&, const Nil&, const Nil&, const Nil&)
: first_(first)
{}
template <typename T1>
inline Pair<T1, Nil>::Pair(typename TupleAccessTraits<T1>::ParameterType first,
const Nil&)
: first_(first)
{}
template<typename T1>
inline Pair<T1,Nil>::Pair()
: first_()
{}
template<typename T1>
template<typename T2>
inline Pair<T1,Nil>::Pair(const Pair<T2,Nil>& other)
: first_(other.first_)
{}
template<typename T1>
template<typename T2>
Pair<T1,Nil>& Pair<T1,Nil>::operator=(const Pair<T2,Nil>& other)
{
first_ = other.first_;
return *this;
}
template<typename T1>
Pair<T1,Nil>& Pair<T1,Nil>::operator=(const Pair& other)
{
first_ = other.first_;
return *this;
}
template<typename T1>
inline typename TupleAccessTraits<T1>::NonConstType
Pair<T1,Nil>::first()
{
return first_;
}
template<typename T1>
inline typename TupleAccessTraits<T1>::ConstType
Pair<T1,Nil>::first() const
{
return first_;
}
}
#endif