From 3c5fc9b44eed90a4cffe6b301b907ab23bd2403d Mon Sep 17 00:00:00 2001
From: Markus Blatt <mblatt@dune-project.org>
Date: Thu, 17 Mar 2005 10:46:45 +0000
Subject: [PATCH] tuples and multiple return values in C++.

[[Imported from SVN: r1665]]
---
 common/test/.gitignore    |   1 +
 common/test/Makefile.am   |   4 +-
 common/test/tuplestest.cc |  25 ++
 common/tuples.hh          | 482 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 511 insertions(+), 1 deletion(-)
 create mode 100644 common/test/tuplestest.cc
 create mode 100644 common/tuples.hh

diff --git a/common/test/.gitignore b/common/test/.gitignore
index eddeffb21..e3a967229 100644
--- a/common/test/.gitignore
+++ b/common/test/.gitignore
@@ -9,6 +9,7 @@ arraylisttest
 smartpointertest
 iteratorfacadetest
 sllisttest
+tuplestest
 settest
 *.gcda
 *.gcno
diff --git a/common/test/Makefile.am b/common/test/Makefile.am
index 5fea4542d..507d4daf1 100644
--- a/common/test/Makefile.am
+++ b/common/test/Makefile.am
@@ -1,7 +1,7 @@
 # $Id$
 
 TESTPROGS = parsetest test-stack arraylisttest smartpointertest \
-	sllisttest iteratorfacadetest
+	sllisttest iteratorfacadetest tuplestest
 
 # which tests to run
 TESTS = $(TESTPROGS)
@@ -24,6 +24,8 @@ arraylisttest_SOURCES = arraylisttest.cc
 
 smartpointertest_SOURCES = smartpointertest.cc
 
+tuplestest_SOURCES = tuplestest.cc
+
 # mention headers so that they are distributed too
 iteratorfacadetest_SOURCES = iteratorfacadetest.cc iteratorfacadetest.hh \
    iteratortest.hh
diff --git a/common/test/tuplestest.cc b/common/test/tuplestest.cc
new file mode 100644
index 000000000..885986680
--- /dev/null
+++ b/common/test/tuplestest.cc
@@ -0,0 +1,25 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+// $Id$
+#include <dune/common/tuples.hh>
+#include <string>
+
+using namespace Dune;
+
+template<class T>
+void test(T& tuple)
+{
+  float f = Element<0>::get(tuple);
+  int i = Element<1>::get(tuple);
+  double d = Element<2>::get(tuple);
+  char c = Element<3>::get(tuple);
+  std::string s = Element<4>::get(tuple);
+}
+
+int main(int argc, char** argv)
+{
+  Tuple<float,int,double,char,std::string> tuple;
+
+  test(tuple);
+  test(static_cast<const Tuple<float,int,double,char,std::string>&>(tuple));
+}
diff --git a/common/tuples.hh b/common/tuples.hh
new file mode 100644
index 000000000..41947b138
--- /dev/null
+++ b/common/tuples.hh
@@ -0,0 +1,482 @@
+// -*- 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
+
+namespace Dune
+{
+  /** @addtogroup Common
+   *
+   * @{
+   */
+  /**
+   * @file
+   * @brief Contains classes that implement tuples.
+   *
+   * This a refined implementation of the approach defined in
+   * in the article &quot;Tuples and multiple return values
+   * in C++&quot; of Jaakko J&auml;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
+  {};
+
+
+  /**
+   * @brief A tuple consisting of two objects.
+   *
+   * This is similar to std::pair
+   */
+  template<typename T1, typename TT>
+  class Pair
+  {
+  public:
+    /**
+     * @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(const Type1& t1, const T2& t2, const T3& t3,
+         const T4& t4, const T5& t5, const T6& t6, const T7& t7,
+         const T8& t8, const T9& t9);
+
+    /**
+     * @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<T1,TT>& operator=(const Pair<U1,U2>& other);
+
+    /**
+     * @brief Get the first value
+     * @return The first value
+     */
+    Type1& first();
+
+    /**
+     * @brief Get the first value
+     * @return The first value
+     */
+    const Type1& first() const;
+
+    /**
+     * @brief Get the second value
+     * @return The first value
+     */
+    Type2& second();
+
+    /**
+     * @brief Get the first value
+     * @return The second value
+     */
+    const Type2& second() const;
+
+  private:
+    /** @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>
+  class Pair<T1,Nil>
+  {
+  public:
+    /**
+     * @brief The type of the first field.
+     */
+    typedef T1 Type1;
+
+    /**
+     * @brief Constructor.
+     * @param t1 The values for the first field.
+     * @param t2 The value for the second field.
+     */
+    Pair(const Type1& first, const Nil&, const Nil&, const Nil&, const Nil&,
+         const Nil&, const Nil&, const Nil&, const Nil&);
+
+    /**
+     * @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<T1,Nil>& operator=(const Pair<T2,Nil>& other);
+
+    /**
+     * @brief Get the first value
+     * @return The first value
+     */
+    Type1& first();
+
+    /**
+     * @brief Get the first value
+     * @return The first value
+     */
+    const Type1& first() const;
+
+  private:
+    /** @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 suported.
+   */
+  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:
+    Tuple(const T1& t1=T1(), const T2& t2=T2(), const T3& t3=T3(),
+          const T4& t4=T4(), const T5& t5=T5(), const T6& t6=T6(),
+          const T7& t7=T7(), const T8& t8=T8(), const T9& t9=T8())
+      : TupleToPairs<T1,T2,T3,T4,T5,T6,T7,T8,T9>::Type(t1, t2, t3,
+                                                       t4, t5, t6,
+                                                       t7, t8, t9)
+    {}
+
+  };
+
+  /**
+   * @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 ElementType<N,Pair<T1,T2> >::Type& 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 const typename ElementType<N,Pair<T1,T2> >::Type& 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 T1& 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 const T1& 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 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)
+  {
+    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);
+  }
+
+  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(const Type1& first, const T2& t2, const T3& t3,
+                           const T4& t4, const T5& t5, const T6& t6,
+                           const T7& t7, const T8& t8, const T9& t9)
+    : first_(first), second_(t2,t3,t4,t5,t6,t7,t8,t9,Nil())
+  {}
+
+  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 T1& Pair<T1,T2>::first()
+  {
+    return first_;
+  }
+
+  template<typename T1, typename T2>
+  inline const T1& Pair<T1,T2>::first() const
+  {
+    return first_;
+  }
+
+
+  template<typename T1, typename T2>
+  inline T2& Pair<T1,T2>::second()
+  {
+    return second_;
+  }
+
+  template<typename T1, typename T2>
+  inline const T2& Pair<T1,T2>::second() const
+  {
+    return second_;
+  }
+
+  template<typename T1>
+  inline Pair<T1,Nil>::Pair(const Type1& first, const Nil&, const Nil&, const Nil&, const Nil&,
+                            const Nil&, const Nil&, const Nil&, const Nil&)
+    : first_(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>
+  inline T1& Pair<T1,Nil>::first()
+  {
+    return first_;
+  }
+
+  template<typename T1>
+  inline const T1& Pair<T1,Nil>::first() const
+  {
+    return first_;
+  }
+
+}
+
+#endif
-- 
GitLab