From b496d130abeecc548ca502a0fc491df7809e8112 Mon Sep 17 00:00:00 2001 From: q66 Date: Sat, 11 Jul 2015 02:38:11 +0100 Subject: [PATCH] initial implementation of tuples --- octa/internal/tuple.hh | 282 ++++++++++++++++++++++++++ octa/tuple.hh | 444 +++++++++++++++++++++++++++++++++++++++++ octa/utility.hh | 64 ++++++ 3 files changed, 790 insertions(+) create mode 100644 octa/internal/tuple.hh create mode 100644 octa/tuple.hh diff --git a/octa/internal/tuple.hh b/octa/internal/tuple.hh new file mode 100644 index 0000000..9ab83a3 --- /dev/null +++ b/octa/internal/tuple.hh @@ -0,0 +1,282 @@ +/* Some tuple internals for inclusion from various headers. Partially + * taken from the libc++ project. + * + * This file is part of OctaSTD. See COPYING.md for futher information. + */ + +#ifndef OCTA_INTERNAL_TUPLE_HH +#define OCTA_INTERNAL_TUPLE_HH + +#include "octa/types.hh" +#include "octa/type_traits.hh" + +namespace octa { + +template class Tuple; +template struct Pair; +template struct Array; + +/* tuple size */ + +template struct TupleSize; + +template struct TupleSize: public TupleSize {}; +template struct TupleSize: public TupleSize {}; +template struct TupleSize: public TupleSize {}; + +/* tuple element */ + +namespace detail { + template struct TupleElementBase; + template + struct TupleElementBase { + using Type = AddConst::Type>; + }; + template + struct TupleElementBase { + using Type = AddVolatile::Type>; + }; + template + struct TupleElementBase { + using Type = AddCv::Type>; + }; +} + +template +using TupleElement = typename detail::TupleElementBase::Type; + +/* is tuple-like */ + +template struct IsTupleLike: False {}; +template struct IsTupleLike: IsTupleLike {}; +template struct IsTupleLike: IsTupleLike {}; +template struct IsTupleLike: IsTupleLike {}; + +/* tuple specializations */ + +template struct IsTupleLike>: True {}; + +template +TupleElement> &get(Tuple &); + +template +const TupleElement> &get(const Tuple &); + +template +TupleElement> &&get(Tuple &&); + +/* pair specializations */ + +template struct IsTupleLike>: True {}; + +template +TupleElement> &get(Pair &); + +template +const TupleElement> &get(const Pair &); + +template +TupleElement> &&get(Pair &&); + +/* array specializations */ + +template struct IsTupleLike>: True {}; + +template +T &get(Array &); + +template +const T &get(const Array &); + +template +T &&get(Array &&); + +/* make tuple indices */ + +namespace detail { + template struct TupleIndices {}; + + template struct MakeTupleIndicesBase; + + template + struct MakeTupleIndicesBase, E> { + using Type = typename MakeTupleIndicesBase, E>::Type; + }; + + template + struct MakeTupleIndicesBase, E> { + using Type = TupleIndices; + }; + + template + struct MakeTupleIndicesImpl { + static_assert(S <= E, "MakeTupleIndices input error"); + using Type = typename MakeTupleIndicesBase, E>::Type; + }; + + template + using MakeTupleIndices = typename MakeTupleIndicesImpl::Type; +} + +/* tuple types */ + +namespace detail { + template struct TupleTypes {}; + + template struct TupleElementBase> { + public: + static_assert(I == 0, "TupleElement index out of range"); + static_assert(I != 0, "TupleElement index out of range"); + }; + + template + struct TupleElementBase<0, TupleTypes> { + public: + using Type = H; + }; + + template + struct TupleElementBase> { + public: + using Type = typename TupleElementBase>::Type; + }; +} + +template struct TupleSize>: + IntegralConstant {}; + +template struct IsTupleLike>: True {}; + +/* make tuple types */ + +namespace detail { + template + struct MakeTupleTypesBase; + + template + struct MakeTupleTypesBase, T, S, E> { + using TR = RemoveReference; + using Type = typename MakeTupleTypesBase::value, + TupleElement &, + TupleElement>>, T, S + 1, E>::Type; + }; + + template + struct MakeTupleTypesBase, T, E, E> { + using Type = TupleTypes; + }; + + template + struct MakeTupleTypesImpl { + static_assert(S <= E, "MakeTupleTypes input error"); + using Type = typename MakeTupleTypesBase, T, S, E>::Type; + }; + + template>::value, Size S = 0> + using MakeTupleTypes = typename MakeTupleTypesImpl::Type; +} + +/* tuple convertible */ + +namespace detail { + template + struct TupleConvertibleBase: False {}; + + template + struct TupleConvertibleBase, TupleTypes>: + IntegralConstant::value && + TupleConvertibleBase, + TupleTypes>::value> {}; + + template<> + struct TupleConvertibleBase, TupleTypes<>>: True {}; + + template + struct TupleConvertibleApply: False {}; + + template + struct TupleConvertibleApply: TupleConvertibleBase< + MakeTupleTypes, MakeTupleTypes + > {}; + + template>::value, + bool = IsTupleLike::value> + struct TupleConvertible: False {}; + + template + struct TupleConvertible: TupleConvertibleApply< + TupleSize>::value == TupleSize::value, T, U + > {}; +} + +/* tuple constructible */ + +namespace detail { + template + struct TupleConstructibleBase: False {}; + + template + struct TupleConstructibleBase, TupleTypes>: + IntegralConstant::value && + TupleConstructibleBase, + TupleTypes>::value> {}; + + template<> + struct TupleConstructibleBase, TupleTypes<>>: True {}; + + template + struct TupleConstructibleApply: False {}; + + template + struct TupleConstructibleApply: TupleConstructibleBase< + MakeTupleTypes, MakeTupleTypes + > {}; + + template>::value, + bool = IsTupleLike::value> + struct TupleConstructible: False {}; + + template + struct TupleConstructible: TupleConstructibleApply< + TupleSize>::value == TupleSize::value, T, U + > {}; +} + +/* tuple assignable */ + +namespace detail { + template + struct TupleAssignableBase: False {}; + + template + struct TupleAssignableBase, TupleTypes>: + IntegralConstant::value && + TupleAssignableBase, + TupleTypes>::value> {}; + + template<> + struct TupleAssignableBase, TupleTypes<>>: True {}; + + template + struct TupleAssignableApply: False {}; + + template + struct TupleAssignableApply: TupleAssignableBase< + MakeTupleTypes, MakeTupleTypes + > {}; + + template>::value, + bool = IsTupleLike::value> + struct TupleAssignable: False {}; + + template + struct TupleAssignable: TupleAssignableApply< + TupleSize>::value == TupleSize::value, T, U + > {}; +} + +} /* namespace octa */ + +#endif \ No newline at end of file diff --git a/octa/tuple.hh b/octa/tuple.hh new file mode 100644 index 0000000..64acabd --- /dev/null +++ b/octa/tuple.hh @@ -0,0 +1,444 @@ +/* Tuples or OctaSTD. Partially taken from the libc++ project. + * + * This file is part of OctaSTD. See COPYING.md for futher information. + */ + +#ifndef OCTA_TUPLE_HH +#define OCTA_TUPLE_HH + +#include "octa/internal/tuple.hh" + +#include "octa/types.hh" +#include "octa/type_traits.hh" +#include "octa/memory.hh" +#include "octa/utility.hh" + +namespace octa { + +/* tuple size */ + +template struct TupleSize>: + IntegralConstant {}; + +/* tuple element */ + +namespace detail { + template + struct TupleElementBase> { + using Type = typename TupleElementBase>::Type; + }; +} + +/* tuple leaf */ + +namespace detail { + template::value> + struct TupleLeaf { + constexpr TupleLeaf(): p_value() { + static_assert(!IsReference::value, + "attempt to default construct a reference element in a tuple"); + } + + template + TupleLeaf(IntegralConstant, const A &): p_value() { + static_assert(!IsReference::value, + "attempt to default construct a reference element in a tuple"); + } + template + TupleLeaf(IntegralConstant, const A &a): p_value(allocator_arg, a) { + static_assert(!IsReference::value, + "attempt to default construct a reference element in a tuple"); + } + template + TupleLeaf(IntegralConstant, const A &a): p_value(a) { + static_assert(!IsReference::value, + "attempt to default construct a reference element in a tuple"); + } + + template, TupleLeaf>>, + IsConstructible>::value>> + explicit TupleLeaf(T &&t): p_value(forward(t)) { + static_assert(!IsReference::value || + (IsLvalueReference::value && + (IsLvalueReference::value || + IsSame, + ReferenceWrapper> + >::value)) || + (IsRvalueReference::value && + !IsLvalueReference::value), + "attempt to construct a reference element in a tuple with an rvalue"); + } + + template + explicit TupleLeaf(IntegralConstant, const A &, T &&t): + p_value(forward(t)) { + static_assert(!IsLvalueReference::value || + (IsLvalueReference::value && + (IsLvalueReference::value || + IsSame, + ReferenceWrapper> + >::value)), + "attempt to construct a reference element in a tuple with an rvalue"); + } + + template + explicit TupleLeaf(IntegralConstant, const A &a, T &&t): + p_value(allocator_arg, a, forward(t)) { + static_assert(!IsLvalueReference::value || + (IsLvalueReference::value && + (IsLvalueReference::value || + IsSame, + ReferenceWrapper> + >::value)), + "attempt to construct a reference element in a tuple with an rvalue"); + } + + template + explicit TupleLeaf(IntegralConstant, const A &a, T &&t): + p_value(forward(t), a) { + static_assert(!IsLvalueReference::value || + (IsLvalueReference::value && + (IsLvalueReference::value || + IsSame, + ReferenceWrapper> + >::value)), + "attempt to construct a reference element in a tuple with an rvalue"); + } + + TupleLeaf(const TupleLeaf &) = default; + TupleLeaf(TupleLeaf &&) = default; + + template + TupleLeaf &operator=(T &&t) { + p_value = forward(t); + return *this; + } + + void swap(TupleLeaf &t) { + octa::swap(get(), t.get()); + } + + H &get() { return p_value; } + const H &get() const { return p_value; } + + private: + TupleLeaf &operator=(const TupleLeaf &); + H p_value; + }; + + template + struct TupleLeaf: private H { + constexpr TupleLeaf() {} + + template + TupleLeaf(IntegralConstant, const A &) {} + + template + TupleLeaf(IntegralConstant, const A &a): + H(allocator_arg, a) {} + + template + TupleLeaf(IntegralConstant, const A &a): H(a) {} + + template, TupleLeaf>>, + IsConstructible + >::value> + > explicit TupleLeaf(T &&t): H(forward(t)) {} + + template + explicit TupleLeaf(IntegralConstant, const A &, T &&t): + H(forward(t)) {} + + template + explicit TupleLeaf(IntegralConstant, const A &a, T &&t): + H(allocator_arg, a, forward(t)) {} + + template + explicit TupleLeaf(IntegralConstant, const A &a, T &&t): + H(forward(t), a) {} + + TupleLeaf(const TupleLeaf &) = default; + TupleLeaf(TupleLeaf &&) = default; + + template + TupleLeaf &operator=(T &&t) { + H::operator=(forward(t)); + return *this; + } + + void swap(TupleLeaf &t) { + octa::swap(get(), t.get()); + } + + H &get() { return (H &)*this; } + const H &get() const { return (const H &)*this; } + + private: + TupleLeaf &operator=(const TupleLeaf &); + }; +} /* namespace detail */ + +/* internal utils */ + +namespace detail { + template + inline void tuple_swallow(A &&...) {} + + template + struct TupleAll: IsSame, TupleAll<(A, true)...>> {}; + + template + struct TupleAllDefaultConstructible; + + template + struct TupleAllDefaultConstructible>: + TupleAll::value...> {}; +} + +/* tuple implementation */ + +namespace detail { + template struct TupleBase; + + template + struct TupleBase, A...>: TupleLeaf... { + constexpr TupleBase() {} + + template + explicit TupleBase(TupleIndices, TupleTypes, + TupleIndices, TupleTypes, + T &&...t): + TupleLeaf(forward(t))..., + TupleLeaf()... {} + + template + explicit TupleBase(AllocatorArg, const Alloc &a, + TupleIndices, TupleTypes, + TupleIndices, TupleTypes, + T &&...t): + TupleLeaf(UsesAllocatorConstructor(), a, + forward(t))..., + TupleLeaf(UsesAllocatorConstructor(), a)... + {} + + template>::value + >> TupleBase(T &&t): TupleLeaf(forward< + TupleElement> + >(get(t)))... {} + + template>::value + >> TupleBase(AllocatorArg, const Alloc &a, T &&t): + TupleLeaf(UsesAllocatorConstructor< + A, Alloc, TupleElement> + >(), a, forward>>(get(t)))... + {} + + template + EnableIf>::value, TupleBase &> + operator=(T &&t) { + tuple_swallow(TupleLeaf::operator=(forward< + TupleElement> + >(get(t)))...); + return *this; + } + + TupleBase(const TupleBase &) = default; + TupleBase(TupleBase &&) = default; + + TupleBase &operator=(const TupleBase &t) { + tuple_swallow(TupleLeaf::operator=(((const TupleLeaf &)t).get())...); + return *this; + } + + TupleBase &operator=(TupleBase &&t) { + tuple_swallow(TupleLeaf::operator=(forward + (((const TupleLeaf &)t).get()))...); + return *this; + } + + void swap(TupleBase &t) { + tuple_swallow(TupleLeaf::swap((TupleLeaf &)t)...); + } + }; +} /* namespace detail */ + +template +class Tuple { + using Base = detail::TupleBase, A...>; + Base p_base; + + template + friend TupleElement> &get(Tuple &); + + template + friend TupleElement> &get(const Tuple &); + + template + friend TupleElement> &get(Tuple &&); + +public: + template::value)...>::value + >> Tuple() {} + + explicit Tuple(const A &...t): + p_base(detail::MakeTupleIndices(), + detail::MakeTupleTypes(), + detail::MakeTupleIndices<0>(), + detail::MakeTupleTypes(), t...) {} + + template + Tuple(AllocatorArg, const Alloc &a, const A &...t): + p_base(allocator_arg, a, + detail::MakeTupleIndices(), + detail::MakeTupleTypes(), + detail::MakeTupleIndices<0>(), + detail::MakeTupleTypes(), t...) {} + + template, + detail::MakeTupleTypes + >::value && + detail::TupleAllDefaultConstructible< + detail::MakeTupleTypes + >::value, bool + > = true> + Tuple(T &&...t): + p_base(detail::MakeTupleIndices(), + detail::MakeTupleTypes(), + detail::MakeTupleIndices(), + detail::MakeTupleTypes(), + forward(t)...) {} + + template, + detail::MakeTupleTypes + >::value && + !detail::TupleConvertible< + Tuple, + detail::MakeTupleTypes + >::value && + detail::TupleAllDefaultConstructible< + detail::MakeTupleTypes + >::value, bool + > = true> + Tuple(T &&...t): + p_base(detail::MakeTupleIndices(), + detail::MakeTupleTypes(), + detail::MakeTupleIndices(), + detail::MakeTupleTypes(), + forward(t)...) {} + + template, + detail::MakeTupleTypes + >::value && + detail::TupleAllDefaultConstructible< + detail::MakeTupleTypes + >::value + >> Tuple(AllocatorArg, const Alloc &a, T &&...t): + p_base(detail::MakeTupleIndices(), + detail::MakeTupleTypes(), + detail::MakeTupleIndices(), + detail::MakeTupleTypes(), + forward(t)...) {} + + template::value, bool + > = true> Tuple(T &&t): p_base(forward(t)) {} + + template::value && + !detail::TupleConvertible::value, bool + > = true> Tuple(T &&t): p_base(forward(t)) {} + + template::value + >> Tuple(AllocatorArg, const Alloc &a, T &&t): + p_base(allocator_arg, a, forward(t)) {} + + template::value + >> Tuple &operator=(T &&t) { + p_base.operator=(forward(t)); + return *this; + } + + void swap(Tuple &t) { + p_base.swap(t.p_base); + } +}; + +template<> class Tuple<> { +public: + constexpr Tuple() {} + template Tuple(AllocatorArg, const A &) {} + template Tuple(AllocatorArg, const A &, const Tuple &) {} + void swap(Tuple &) {} +}; + +/* get */ + +template +inline TupleElement> &get(Tuple &t) { + using Type = TupleElement>; + return ((detail::TupleLeaf &)t.p_base).get(); +} + +template +inline const TupleElement> &get(const Tuple &t) { + using Type = TupleElement>; + return ((const detail::TupleLeaf &)t.p_base).get(); +} + +template +inline TupleElement> &&get(Tuple &&t) { + using Type = TupleElement>; + return ((detail::TupleLeaf &&)t.p_base).get(); +} + +/* tie */ + +template +inline Tuple tie(T &...t) { + return Tuple(t...); +} + +} /* namespace octa */ + +#endif \ No newline at end of file diff --git a/octa/utility.hh b/octa/utility.hh index 5919d44..45b85c2 100644 --- a/octa/utility.hh +++ b/octa/utility.hh @@ -9,6 +9,7 @@ #include #include "octa/type_traits.hh" +#include "octa/internal/tuple.hh" namespace octa { @@ -166,6 +167,69 @@ Pair::Type, >(forward(a), forward(b));; } +template +struct TupleSize>: IntegralConstant {}; + +template +struct TupleSize>: IntegralConstant {}; + +namespace detail { + template + struct TupleElementBase<0, Pair> { + using Type = T; + }; + + template + struct TupleElementBase<1, Pair> { + using Type = U; + }; + + template + struct TupleElementBase<0, const Pair> { + using Type = const T; + }; + + template + struct TupleElementBase<1, const Pair> { + using Type = const U; + }; + + template struct GetPair; + + template<> struct GetPair<0> { + template + static T &get(Pair &p) { return p.first; } + template + static const T &get(const Pair &p) { return p.first; } + template + static T &&get(Pair &&p) { return forward(p.first); } + }; + + template<> struct GetPair<1> { + template + static U &get(Pair &p) { return p.second; } + template + static const U &get(const Pair &p) { return p.second; } + template + static U &&get(Pair &&p) { return forward(p.second); } + }; +} + +template +TupleElement> &get(Pair &p) { + return detail::GetPair::get(p); +} + +template +const TupleElement> &get(const Pair &p) { + return detail::GetPair::get(p); +} + +template +TupleElement> &&get(Pair &&p) { + return detail::GetPair::get(move(p)); +} + namespace detail { template, RemoveCv>::value,