template struct TupleN; template struct IndexI__ {}; template const V& GetFromTuple(const T& t, const I&); template struct Tuple; template struct TupleN<1, A> { A a; bool operator==(const TupleN& x) const { return a == x.a; } int Compare(const TupleN& x) const { return SgnCompare(a, x.a); } void ToHash(CombineHash& h) const { h << a; } void ToString(String& r) const { r << AsString(a); } void Serialize(Stream& s) { s % a; } int GetCount() const { return 1; } Value Get(int i) const { ASSERT(i == 0); return a; } void Set(int i, const Value& v) { ASSERT(i == 0); a = v; } TupleN(const A& a) : a(a) {} TupleN() {} template operator Tuple() { Tuple t; t.a = (AA)a; return t; } }; #define TUPLE_N_METHODS(M, I) \ bool operator==(const TupleN& x) const { return Base::operator==(x) && M == x.M; } \ int Compare(const TupleN& x) const { int q = Base::Compare(x); return q ? q : SgnCompare(M, x.M); } \ \ void ToHash(CombineHash& h) const { Base::ToHash(h); h << M; } \ void ToString(String& r) const { Base::ToString(r); r << ", " << M; } \ \ void Serialize(Stream& s) { Base::Serialize(s); s % M; } \ \ int GetCount() const { return I + 1; } \ \ Value Get(int i) const { if(i == I) return M; return Base::Get(i); } \ void Set(int i, const Value& v) { if(i == I) M = v; else Base::Set(i, v); } \ \ TupleN() {} \ template struct TupleN<2, A, B> : public TupleN<1, A> { typedef TupleN<1, A> Base; B b; TUPLE_N_METHODS(b, 1); TupleN(const A& a, const B& b) : Base(a), b(b) {} template operator Tuple() { Tuple t; t.a = (AA)Base::a; t.b = b; return t; } }; template struct TupleN<3, A, B, C> : public TupleN<2, A, B> { typedef TupleN<2, A, B> Base; C c; TUPLE_N_METHODS(c, 2); TupleN(const A& a, const B& b, const C& c) : Base(a, b), c(c) {} template operator Tuple() { Tuple t; t.a = (AA)Base::a; t.b = (BB)Base::b; t.c = (CC)c; return t; } }; template struct TupleN<4, A, B, C, D> : public TupleN<3, A, B, C> { typedef TupleN<3, A, B, C> Base; D d; TUPLE_N_METHODS(d, 3); TupleN(const A& a, const B& b, const C& c, const D& d) : Base(a, b, c), d(d) {} template operator Tuple() { Tuple t; t.a = (AA)Base::a; t.b = (BB)Base::b; t.c = (CC)Base::c; t.d = (DD)d; return t; } }; #define GET_FROM_TUPLE(M, I) \ \ template \ auto GetFromTuple(const T& t, const IndexI__&) -> decltype(t.M)& \ { \ return const_cast(t).M; \ } \ \ template \ auto GetFromTupleByType(const T& t, decltype(t.M)*, const IndexI__* = NULL) -> decltype(t.M)& \ { \ return const_cast(t).M; \ } GET_FROM_TUPLE(a, 0) GET_FROM_TUPLE(b, 1) GET_FROM_TUPLE(c, 2) GET_FROM_TUPLE(d, 3) template struct Tuple : public TupleN { private: typedef TupleN Base; friend void AssertMoveable0(Tuple *) {} public: template const auto& Get() const { return GetFromTuple(*this, IndexI__()); } template auto& Get() { return GetFromTuple(*this, IndexI__()); } template const T& Get() const { return GetFromTupleByType(*this, (T*)NULL); } template T& Get() { return GetFromTupleByType(*this, (T*)NULL); } int GetCount() const { return Base::GetCount(); } bool operator==(const Tuple& x) const { return Base::operator==(x); } bool operator!=(const Tuple& x) const { return !operator==(x); } int Compare(const Tuple& x) const { return Base::Compare(x); } bool operator<=(const Tuple& x) const { return Compare(x) <= 0; } bool operator>=(const Tuple& x) const { return Compare(x) >= 0; } bool operator<(const Tuple& x) const { return Compare(x) < 0; } bool operator>(const Tuple& x) const { return Compare(x) > 0; } hash_t GetHashValue() const { CombineHash h; Base::ToHash(h); return h; } void Serialize(Stream& s) { Base::Serialize(s); } String ToString() const { String h = "("; Base::ToString(h); h << ")"; return h; } Value Get(int i) const { return Base::Get(i); } void Set(int i, const Value& v) { return Base::Set(i, v); } ValueArray GetArray() const { ValueArray va; for(int i = 0; i < GetCount(); i++) va.Add(Get(i)); return va; } void SetArray(const ValueArray& va) { for(int i = 0; i < va.GetCount(); i++) Set(i, va[i]); } Tuple() {} Tuple(const Args... args) : Base(args...) {}; }; template Tuple MakeTuple(const Args... args) { return Tuple(args...); } template inline T *FindTuple(T *x, int n, const U& key) { while(n--) { if(x->a == key) return x; x++; } return NULL; } template struct Tie2 { A& a; B& b; void operator=(const Tuple& s) { a = s.a; b = s.b; } Tie2(A& a, B& b) : a(a), b(b) {} }; template Tie2 Tie(A& a, B& b) { return Tie2(a, b); } template struct Tie3 { A& a; B& b; C& c; void operator=(const Tuple& s) { a = s.a; b = s.b; c = s.c; } Tie3(A& a, B& b, C& c) : a(a), b(b), c(c) {} }; template Tie3 Tie(A& a, B& b, C& c) { return Tie3(a, b, c); } template struct Tie4 { A& a; B& b; C& c; D& d; void operator=(const Tuple& s) { a = s.a; b = s.b; c = s.c; d = s.d; } Tie4(A& a, B& b, C& c, D& d) : a(a), b(b), c(c), d(d) {} }; template Tie4 Tie(A& a, B& b, C& c, D& d) { return Tie4(a, b, c, d); } // Backward compatibility template using Tuple2 = Tuple; template using Tuple3 = Tuple; template using Tuple4 = Tuple;