/* Tuples or OctaSTD. Partially taken from the libc++ project. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OSTD_TUPLE_HH #define OSTD_TUPLE_HH #include "ostd/internal/tuple.hh" #include "ostd/types.hh" #include "ostd/type_traits.hh" #include "ostd/memory.hh" #include "ostd/utility.hh" namespace ostd { /* tuple size */ template constexpr Size TupleSize> = sizeof...(T); /* tuple element */ template struct TupleElementBase> { using Type = typename TupleElementBase>::Type; }; /* tuple leaf */ namespace detail { template> struct TupleLeaf { constexpr TupleLeaf(): p_value() { static_assert( !IsReference, "attempt to default construct a reference element in a tuple" ); } template TupleLeaf(Constant, A const &): p_value() { static_assert( !IsReference, "attempt to default construct a reference element in a tuple" ); } template TupleLeaf(Constant, A const &a): p_value(allocator_arg, a) { static_assert( !IsReference, "attempt to default construct a reference element in a tuple" ); } template TupleLeaf(Constant, A const &a): p_value(a) { static_assert( !IsReference, "attempt to default construct a reference element in a tuple" ); } template, TupleLeaf> && IsConstructible >> explicit TupleLeaf(T &&t): p_value(std::forward(t)) { static_assert( !IsReference || ( IsLvalueReference && ( IsLvalueReference || IsSame< RemoveReference, ReferenceWrapper> > ) ) || (IsRvalueReference && !IsLvalueReference), "attempt to construct a reference element in a tuple with an rvalue" ); } template explicit TupleLeaf(Constant, A const &, T &&t): p_value(std::forward(t)) { static_assert( !IsLvalueReference || ( IsLvalueReference && ( IsLvalueReference || IsSame< RemoveReference, ReferenceWrapper> > ) ), "attempt to construct a reference element in a tuple with an rvalue" ); } template explicit TupleLeaf(Constant, A const &a, T &&t): p_value(allocator_arg, a, std::forward(t)) { static_assert( !IsLvalueReference || ( IsLvalueReference && ( IsLvalueReference || IsSame< RemoveReference, ReferenceWrapper> > ) ), "attempt to construct a reference element in a tuple with an rvalue" ); } template explicit TupleLeaf(Constant, A const &a, T &&t): p_value(std::forward(t), a) { static_assert( !IsLvalueReference || ( IsLvalueReference && ( IsLvalueReference || IsSame< RemoveReference, ReferenceWrapper> > ) ), "attempt to construct a reference element in a tuple with an rvalue" ); } TupleLeaf(TupleLeaf const &) = default; TupleLeaf(TupleLeaf &&) = default; template TupleLeaf &operator=(T &&t) { p_value = std::forward(t); return *this; } void swap(TupleLeaf &t) { swap_adl(get(), t.get()); } H &get() { return p_value; } H const &get() const { return p_value; } private: TupleLeaf &operator=(TupleLeaf const &); H p_value; }; template struct TupleLeaf: private H { constexpr TupleLeaf() {} template TupleLeaf(Constant, A const &) {} template TupleLeaf(Constant, A const &a): H(allocator_arg, a) {} template TupleLeaf(Constant, A const &a): H(a) {} template, TupleLeaf> && IsConstructible >> explicit TupleLeaf(T &&t): H(std::forward(t)) {} template explicit TupleLeaf(Constant, A const &, T &&t): H(std::forward(t)) {} template explicit TupleLeaf(Constant, A const &a, T &&t): H(allocator_arg, a, std::forward(t)) {} template explicit TupleLeaf(Constant, A const &a, T &&t): H(std::forward(t), a) {} TupleLeaf(TupleLeaf const &) = default; TupleLeaf(TupleLeaf &&) = default; template TupleLeaf &operator=(T &&t) { H::operator=(std::forward(t)); return *this; } void swap(TupleLeaf &t) { swap_adl(get(), t.get()); } H &get() { return *static_cast(this); } H const &get() const { return *static_cast(this); } private: TupleLeaf &operator=(TupleLeaf const &); }; } /* namespace detail */ /* internal utils */ namespace detail { template inline void tuple_swallow(A &&...) {} template constexpr bool TupleAll = true; template constexpr bool TupleAll = B && TupleAll; template constexpr bool TupleAllDefaultConstructible = detail::Undefined(); template constexpr bool TupleAllDefaultConstructible> = TupleAll...>; } /* tuple implementation */ namespace detail { template struct TupleBase; template struct TupleBase, A...>: TupleLeaf... { constexpr TupleBase() {} template< Size ...Ia, typename ...Aa, Size ...Ib, typename ...Ab, typename ...T > explicit TupleBase( TupleIndices, TupleTypes, TupleIndices, TupleTypes, T &&...t ): TupleLeaf(std::forward(t))..., TupleLeaf()... {} template< typename Alloc, Size ...Ia, typename ...Aa, Size ...Ib, typename ...Ab, typename ...T > explicit TupleBase( AllocatorArg, Alloc const &a, TupleIndices, TupleTypes, TupleIndices, TupleTypes, T &&...t ): TupleLeaf( UsesAllocatorConstructor, a, std::forward(t) )..., TupleLeaf(UsesAllocatorConstructor, a)... {} template> >> TupleBase(T &&t): TupleLeaf( std::forward>>(get(t)) )... {} template> >> TupleBase(AllocatorArg, Alloc const &a, T &&t): TupleLeaf( UsesAllocatorConstructor< A, Alloc, TupleElement> >, a, std::forward>>(get(t)) )... {} template EnableIf>, TupleBase &> operator=(T &&t) { tuple_swallow(TupleLeaf::operator=( std::forward>>(get(t)) )...); return *this; } TupleBase(TupleBase const &) = default; TupleBase(TupleBase &&) = default; TupleBase &operator=(TupleBase const &t) { tuple_swallow(TupleLeaf::operator=( (static_cast const &>(t)).get() )...); return *this; } TupleBase &operator=(TupleBase &&t) { tuple_swallow(TupleLeaf::operator=( std::forward((static_cast &>(t)).get()) )...); return *this; } void swap(TupleBase &t) { tuple_swallow( TupleLeaf::swap(static_cast &>(t))... ); } }; } /* namespace detail */ template class Tuple { using Base = detail::TupleBase, A...>; Base p_base; template friend TupleElement> &get(Tuple &) noexcept; template friend TupleElement> const &get(Tuple const &) noexcept; template friend TupleElement> &&get(Tuple &&) noexcept; template friend TupleElement> const &&get(Tuple const &&) noexcept; public: template)...> >> Tuple() {} explicit Tuple(A const &...t): p_base( detail::MakeTupleIndices(), detail::MakeTupleTypes(), detail::MakeTupleIndices<0>(), detail::MakeTupleTypes(), t... ) {} template Tuple(AllocatorArg, Alloc const &a, A const &...t): p_base( allocator_arg, a, detail::MakeTupleIndices(), detail::MakeTupleTypes(), detail::MakeTupleIndices<0>(), detail::MakeTupleTypes(), t... ) {} template, detail::MakeTupleTypes< Tuple, (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A) > > && detail::TupleAllDefaultConstructible< detail::MakeTupleTypes< Tuple, sizeof...(A), (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A) > >, bool > = true> Tuple(T &&...t): p_base( detail::MakeTupleIndices(), detail::MakeTupleTypes(), detail::MakeTupleIndices(), detail::MakeTupleTypes(), std::forward(t)... ) {} template, detail::MakeTupleTypes< Tuple, (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A) > > && !detail::TupleConvertible< Tuple, detail::MakeTupleTypes< Tuple, (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A) > > && detail::TupleAllDefaultConstructible< detail::MakeTupleTypes< Tuple, sizeof...(A), (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A) > >, bool > = true> Tuple(T &&...t): p_base( detail::MakeTupleIndices(), detail::MakeTupleTypes(), detail::MakeTupleIndices(), detail::MakeTupleTypes(), std::forward(t)... ) {} template, detail::MakeTupleTypes< Tuple, (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A) > > && detail::TupleAllDefaultConstructible< detail::MakeTupleTypes< Tuple, sizeof...(A), (sizeof...(T) < sizeof...(A)) ? sizeof...(T) : sizeof...(A) > > >> Tuple(AllocatorArg, Alloc const &a, T &&...t): p_base( allocator_arg, a, detail::MakeTupleIndices(), detail::MakeTupleTypes(), detail::MakeTupleIndices(), detail::MakeTupleTypes(), std::forward(t)... ) {} template, bool > = true> Tuple(T &&t): p_base(std::forward(t)) {} template && !detail::TupleConvertible, bool > = true> Tuple(T &&t): p_base(std::forward(t)) {} template >> Tuple(AllocatorArg, Alloc const &a, T &&t): p_base(allocator_arg, a, std::forward(t)) {} template>> Tuple &operator=(T &&t) { p_base.operator=(std::forward(t)); return *this; } void swap(Tuple &t) { p_base.swap(t.p_base); } }; template<> class Tuple<> { public: constexpr Tuple() {} template Tuple(AllocatorArg, A const &) {} template Tuple(AllocatorArg, A const &, Tuple const &) {} void swap(Tuple &) {} }; /* get */ template inline TupleElement> &get(Tuple &t) noexcept { using Type = TupleElement>; return static_cast &>(t.p_base).get(); } template inline TupleElement> const &get(Tuple const &t) noexcept { using Type = TupleElement>; return static_cast const &>(t.p_base).get(); } template inline TupleElement> &&get(Tuple &&t) noexcept { using Type = TupleElement>; return static_cast( static_cast &&>(t.p_base).get()); } template inline TupleElement> const &&get(Tuple const &&t) noexcept { using Type = TupleElement>; return static_cast( static_cast const &&>(t.p_base).get()); } /* tie */ template inline Tuple tie(T &...t) { return Tuple(t...); } /* ignore */ namespace detail { struct Ignore { template Ignore const &operator=(T &&) const { return *this; } }; } static detail::Ignore const ignore = detail::Ignore(); /* make tuple */ namespace detail { template struct MakeTupleReturnType { using Type = T; }; template struct MakeTupleReturnType> { using Type = T &; }; template struct MakeTupleReturn { using Type = typename MakeTupleReturnType>::Type; }; } template inline Tuple::Type...> make_tuple(T &&...t) { return Tuple::Type...>(std::forward(t)...); } /* forward as tuple */ template inline Tuple forward_as_tuple(T &&...t) { return Tuple(std::forward(t)...); } /* tuple relops */ namespace detail { template struct TupleEqual { template bool operator()(T const &x, U const &y) { return TupleEqual()(x, y) && (get(x) == get(y)); } }; template<> struct TupleEqual<0> { template bool operator()(T const &, U const &) { return true; } }; } template inline bool operator==(Tuple const &x, Tuple const &y) { return detail::TupleEqual(x, y); } template inline bool operator!=(Tuple const &x, Tuple const &y) { return !(x == y); } namespace detail { template struct TupleLess { template bool operator()(T const &x, U const &y) { constexpr Size J = TupleSize - I; if (get(x) < get(y)) return true; if (get(y) < get(x)) return false; return TupleLess()(x, y); } }; template<> struct TupleLess<0> { template bool operator()(T const &, U const &) { return true; } }; } template inline bool operator<(Tuple const &x, Tuple const &y) { return detail::TupleLess(x, y); } template inline bool operator>(Tuple const &x, Tuple const &y) { return y < x; } template inline bool operator<=(Tuple const &x, Tuple const &y) { return !(y < x); } template inline bool operator>=(Tuple const &x, Tuple const &y) { return !(x < y); } /* uses alloc */ template constexpr bool UsesAllocator, A> = true; /* piecewise pair stuff */ template template Pair::Pair( PiecewiseConstruct, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ): first( std::forward(get(fa))...), second(std::forward(get(sa))... ) {} namespace detail { template template CompressedPairBase::CompressedPairBase( PiecewiseConstruct, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ): p_first(std::forward(get(fa))...), p_second(std::forward(get(sa))...) {} template template CompressedPairBase::CompressedPairBase( PiecewiseConstruct, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ): T(std::forward(get(fa))...), p_second(std::forward(get(sa))...) {} template template CompressedPairBase::CompressedPairBase( PiecewiseConstruct, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ): U(std::forward(get(sa))...), p_first(std::forward(get(fa))...) {} template template CompressedPairBase::CompressedPairBase( PiecewiseConstruct, Tuple &fa, Tuple &sa, detail::TupleIndices, detail::TupleIndices ): T(std::forward(get(fa))...), U(std::forward(get(sa))...) {} } /* namespace detail */ } /* namespace ostd */ #endif