diff options
Diffstat (limited to 'include/EASTL/tuple.h')
-rw-r--r-- | include/EASTL/tuple.h | 1006 |
1 files changed, 1006 insertions, 0 deletions
diff --git a/include/EASTL/tuple.h b/include/EASTL/tuple.h new file mode 100644 index 0000000..9d27bff --- /dev/null +++ b/include/EASTL/tuple.h @@ -0,0 +1,1006 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_TUPLE_H +#define EASTL_TUPLE_H + +#include <EASTL/internal/config.h> +#include <EASTL/functional.h> +#include <EASTL/type_traits.h> +#include <EASTL/utility.h> + +#include <EASTL/internal/tuple_fwd_decls.h> + +EA_DISABLE_VC_WARNING(4623) // warning C4623: default constructor was implicitly defined as deleted +EA_DISABLE_VC_WARNING(4625) // warning C4625: copy constructor was implicitly defined as deleted +EA_DISABLE_VC_WARNING(4510) // warning C4510: default constructor could not be generated + +#if EASTL_TUPLE_ENABLED + +namespace eastl +{ +// non-recursive tuple implementation based on libc++ tuple implementation and description at +// http://mitchnull.blogspot.ca/2012/06/c11-tuple-implementation-details-part-1.html + +// TupleTypes helper +template <typename... Ts> struct TupleTypes {}; + +// tuple_size helper +template <typename T> class tuple_size {}; +template <typename T> class tuple_size<const T> : public tuple_size<T> {}; +template <typename T> class tuple_size<volatile T> : public tuple_size<T> {}; +template <typename T> class tuple_size<const volatile T> : public tuple_size<T> {}; + +template <typename... Ts> class tuple_size<TupleTypes<Ts...>> : public integral_constant<size_t, sizeof...(Ts)> {}; +template <typename... Ts> class tuple_size<tuple<Ts...>> : public integral_constant<size_t, sizeof...(Ts)> {}; + +#if EASTL_VARIABLE_TEMPLATES_ENABLED + template <class T> + EA_CONSTEXPR size_t tuple_size_v = tuple_size<T>::value; +#endif + +namespace Internal +{ + template <typename TupleIndices, typename... Ts> + struct TupleImpl; +} // namespace Internal + +template <typename Indices, typename... Ts> +class tuple_size<Internal::TupleImpl<Indices, Ts...>> : public integral_constant<size_t, sizeof...(Ts)> +{ +}; + +// tuple_element helper to be able to isolate a type given an index +template <size_t I, typename T> +class tuple_element +{ +}; + +template <size_t I> +class tuple_element<I, TupleTypes<>> +{ +public: + static_assert(I != I, "tuple_element index out of range"); +}; + +template <typename H, typename... Ts> +class tuple_element<0, TupleTypes<H, Ts...>> +{ +public: + typedef H type; +}; + +template <size_t I, typename H, typename... Ts> +class tuple_element<I, TupleTypes<H, Ts...>> +{ +public: + typedef tuple_element_t<I - 1, TupleTypes<Ts...>> type; +}; + +// specialization for tuple +template <size_t I, typename... Ts> +class tuple_element<I, tuple<Ts...>> +{ +public: + typedef tuple_element_t<I, TupleTypes<Ts...>> type; +}; + +template <size_t I, typename... Ts> +class tuple_element<I, const tuple<Ts...>> +{ +public: + typedef typename add_const<tuple_element_t<I, TupleTypes<Ts...>>>::type type; +}; + +template <size_t I, typename... Ts> +class tuple_element<I, volatile tuple<Ts...>> +{ +public: + typedef typename add_volatile<tuple_element_t<I, TupleTypes<Ts...>>>::type type; +}; + +template <size_t I, typename... Ts> +class tuple_element<I, const volatile tuple<Ts...>> +{ +public: + typedef typename add_cv<tuple_element_t<I, TupleTypes<Ts...>>>::type type; +}; + +// specialization for TupleImpl +template <size_t I, typename Indices, typename... Ts> +class tuple_element<I, Internal::TupleImpl<Indices, Ts...>> : public tuple_element<I, tuple<Ts...>> +{ +}; + +template <size_t I, typename Indices, typename... Ts> +class tuple_element<I, const Internal::TupleImpl<Indices, Ts...>> : public tuple_element<I, const tuple<Ts...>> +{ +}; + +template <size_t I, typename Indices, typename... Ts> +class tuple_element<I, volatile Internal::TupleImpl<Indices, Ts...>> : public tuple_element<I, volatile tuple<Ts...>> +{ +}; + +template <size_t I, typename Indices, typename... Ts> +class tuple_element<I, const volatile Internal::TupleImpl<Indices, Ts...>> : public tuple_element< + I, const volatile tuple<Ts...>> +{ +}; + +// attempt to isolate index given a type +template <typename T, typename Tuple> +struct tuple_index +{ +}; + +template <typename T> +struct tuple_index<T, TupleTypes<>> +{ + typedef void DuplicateTypeCheck; + tuple_index() = delete; // tuple_index should only be used for compile-time assistance, and never be instantiated + static const size_t index = 0; +}; + +template <typename T, typename... TsRest> +struct tuple_index<T, TupleTypes<T, TsRest...>> +{ + typedef int DuplicateTypeCheck; + // after finding type T in the list of types, try to find type T in TsRest. + // If we stumble back into this version of tuple_index, i.e. type T appears twice in the list of types, then DuplicateTypeCheck will be of type int, and the static_assert will fail. + // If we don't, then we'll go through the version of tuple_index above, where all of the types have been exhausted, and DuplicateTypeCheck will be void. + static_assert(is_void<typename tuple_index<T, TupleTypes<TsRest...>>::DuplicateTypeCheck>::value, "duplicate type T in tuple_vector::get<T>(); unique types must be provided in declaration, or only use get<size_t>()"); + + static const size_t index = 0; +}; + +template <typename T, typename TsHead, typename... TsRest> +struct tuple_index<T, TupleTypes<TsHead, TsRest...>> +{ + typedef typename tuple_index<T, TupleTypes<TsRest...>>::DuplicateTypeCheck DuplicateTypeCheck; + static const size_t index = tuple_index<T, TupleTypes<TsRest...>>::index + 1; +}; + +template <typename T, typename Indices, typename... Ts> +struct tuple_index<T, Internal::TupleImpl<Indices, Ts...>> : public tuple_index<T, TupleTypes<Ts...>> +{ +}; + + +namespace Internal +{ + // swallow + // + // Provides a vessel to expand variadic packs. + // + template <typename... Ts> + void swallow(Ts&&...) {} + + + // TupleLeaf + // + template <size_t I, typename ValueType, bool IsEmpty = is_empty_v<ValueType>> + class TupleLeaf; + + template <size_t I, typename ValueType, bool IsEmpty> + inline void swap(TupleLeaf<I, ValueType, IsEmpty>& a, TupleLeaf<I, ValueType, IsEmpty>& b) + { + eastl::swap(a.getInternal(), b.getInternal()); + } + + template <size_t I, typename ValueType, bool IsEmpty> + class TupleLeaf + { + public: + TupleLeaf() : mValue() {} + TupleLeaf(const TupleLeaf&) = default; + TupleLeaf& operator=(const TupleLeaf&) = delete; + + // We shouldn't need this explicit constructor as it should be handled by the template below but OSX clang + // is_constructible type trait incorrectly gives false for is_constructible<T&&, T&&>::value + explicit TupleLeaf(ValueType&& v) : mValue(eastl::move(v)) {} + + template <typename T, typename = typename enable_if<is_constructible<ValueType, T&&>::value>::type> + explicit TupleLeaf(T&& t) + : mValue(eastl::forward<T>(t)) + { + } + + template <typename T> + explicit TupleLeaf(const TupleLeaf<I, T>& t) + : mValue(t.getInternal()) + { + } + + template <typename T> + TupleLeaf& operator=(T&& t) + { + mValue = eastl::forward<T>(t); + return *this; + } + + int swap(TupleLeaf& t) + { + eastl::Internal::swap(*this, t); + return 0; + } + + ValueType& getInternal() { return mValue; } + const ValueType& getInternal() const { return mValue; } + + private: + ValueType mValue; + }; + + // TupleLeaf: Specialize for when ValueType is a reference + template <size_t I, typename ValueType, bool IsEmpty> + class TupleLeaf<I, ValueType&, IsEmpty> + { + public: + TupleLeaf(const TupleLeaf&) = default; + TupleLeaf& operator=(const TupleLeaf&) = delete; + + template <typename T, typename = typename enable_if<is_constructible<ValueType, T&&>::value>::type> + explicit TupleLeaf(T&& t) + : mValue(eastl::forward<T>(t)) + { + } + + explicit TupleLeaf(ValueType& t) : mValue(t) + { + } + + template <typename T> + explicit TupleLeaf(const TupleLeaf<I, T>& t) + : mValue(t.getInternal()) + { + } + + template <typename T> + TupleLeaf& operator=(T&& t) + { + mValue = eastl::forward<T>(t); + return *this; + } + + int swap(TupleLeaf& t) + { + eastl::Internal::swap(*this, t); + return 0; + } + + ValueType& getInternal() { return mValue; } + const ValueType& getInternal() const { return mValue; } + + private: + ValueType& mValue; + }; + + // TupleLeaf: partial specialization for when we can use the Empty Base Class Optimization + template <size_t I, typename ValueType> + class TupleLeaf<I, ValueType, true> : private ValueType + { + public: + // true_type / false_type constructors for case where ValueType is default constructible and should be value + // initialized and case where it is not + TupleLeaf(const TupleLeaf&) = default; + + template <typename T, typename = typename enable_if<is_constructible<ValueType, T&&>::value>::type> + explicit TupleLeaf(T&& t) + : ValueType(eastl::forward<T>(t)) + { + } + + template <typename T> + explicit TupleLeaf(const TupleLeaf<I, T>& t) + : ValueType(t.getInternal()) + { + } + + template <typename T> + TupleLeaf& operator=(T&& t) + { + ValueType::operator=(eastl::forward<T>(t)); + return *this; + } + + int swap(TupleLeaf& t) + { + eastl::Internal::swap(*this, t); + return 0; + } + + ValueType& getInternal() { return static_cast<ValueType&>(*this); } + const ValueType& getInternal() const { return static_cast<const ValueType&>(*this); } + + private: + TupleLeaf& operator=(const TupleLeaf&) = delete; + }; + + + + // MakeTupleTypes + // + // + template <typename TupleTypes, typename Tuple, size_t Start, size_t End> + struct MakeTupleTypesImpl; + + template <typename... Types, typename Tuple, size_t Start, size_t End> + struct MakeTupleTypesImpl<TupleTypes<Types...>, Tuple, Start, End> + { + typedef typename remove_reference<Tuple>::type TupleType; + typedef typename MakeTupleTypesImpl< + TupleTypes<Types..., typename conditional<is_lvalue_reference<Tuple>::value, + // append ref if Tuple is ref + tuple_element_t<Start, TupleType>&, + // append non-ref otherwise + tuple_element_t<Start, TupleType>>::type>, + Tuple, Start + 1, End>::type type; + }; + + template <typename... Types, typename Tuple, size_t End> + struct MakeTupleTypesImpl<TupleTypes<Types...>, Tuple, End, End> + { + typedef TupleTypes<Types...> type; + }; + + template <typename Tuple> + using MakeTupleTypes_t = typename MakeTupleTypesImpl<TupleTypes<>, Tuple, 0, + tuple_size<typename remove_reference<Tuple>::type>::value>::type; + + + // TupleImpl + // + // + template <size_t I, typename Indices, typename... Ts> + tuple_element_t<I, TupleImpl<Indices, Ts...>>& get(TupleImpl<Indices, Ts...>& t); + + template <size_t I, typename Indices, typename... Ts> + const_tuple_element_t<I, TupleImpl<Indices, Ts...>>& get(const TupleImpl<Indices, Ts...>& t); + + template <size_t I, typename Indices, typename... Ts> + tuple_element_t<I, TupleImpl<Indices, Ts...>>&& get(TupleImpl<Indices, Ts...>&& t); + + template <typename T, typename Indices, typename... Ts> + T& get(TupleImpl<Indices, Ts...>& t); + + template <typename T, typename Indices, typename... Ts> + const T& get(const TupleImpl<Indices, Ts...>& t); + + template <typename T, typename Indices, typename... Ts> + T&& get(TupleImpl<Indices, Ts...>&& t); + + template <size_t... Indices, typename... Ts> + struct TupleImpl<integer_sequence<size_t, Indices...>, Ts...> : public TupleLeaf<Indices, Ts>... + { + EA_CONSTEXPR TupleImpl() = default; + + // index_sequence changed to integer_sequence due to issues described below in VS2015 CTP 6. + // https://connect.microsoft.com/VisualStudio/feedback/details/1126958/error-in-template-parameter-pack-expansion-of-std-index-sequence + // + template <typename... Us, typename... ValueTypes> + explicit TupleImpl(integer_sequence<size_t, Indices...>, TupleTypes<Us...>, ValueTypes&&... values) + : TupleLeaf<Indices, Ts>(eastl::forward<ValueTypes>(values))... + { + } + + template <typename OtherTuple> + TupleImpl(OtherTuple&& t) + : TupleLeaf<Indices, Ts>(eastl::forward<tuple_element_t<Indices, MakeTupleTypes_t<OtherTuple>>>(get<Indices>(t)))... + { + } + + template <typename OtherTuple> + TupleImpl& operator=(OtherTuple&& t) + { + swallow(TupleLeaf<Indices, Ts>::operator=( + eastl::forward<tuple_element_t<Indices, MakeTupleTypes_t<OtherTuple>>>(get<Indices>(t)))...); + return *this; + } + + TupleImpl& operator=(const TupleImpl& t) + { + swallow(TupleLeaf<Indices, Ts>::operator=(static_cast<const TupleLeaf<Indices, Ts>&>(t).getInternal())...); + return *this; + } + + void swap(TupleImpl& t) { swallow(TupleLeaf<Indices, Ts>::swap(static_cast<TupleLeaf<Indices, Ts>&>(t))...); } + }; + + template <size_t I, typename Indices, typename... Ts> + inline tuple_element_t<I, TupleImpl<Indices, Ts...>>& get(TupleImpl<Indices, Ts...>& t) + { + typedef tuple_element_t<I, TupleImpl<Indices, Ts...>> Type; + return static_cast<Internal::TupleLeaf<I, Type>&>(t).getInternal(); + } + + template <size_t I, typename Indices, typename... Ts> + inline const_tuple_element_t<I, TupleImpl<Indices, Ts...>>& get(const TupleImpl<Indices, Ts...>& t) + { + typedef tuple_element_t<I, TupleImpl<Indices, Ts...>> Type; + return static_cast<const Internal::TupleLeaf<I, Type>&>(t).getInternal(); + } + + template <size_t I, typename Indices, typename... Ts> + inline tuple_element_t<I, TupleImpl<Indices, Ts...>>&& get(TupleImpl<Indices, Ts...>&& t) + { + typedef tuple_element_t<I, TupleImpl<Indices, Ts...>> Type; + return static_cast<Type&&>(static_cast<Internal::TupleLeaf<I, Type>&>(t).getInternal()); + } + + template <typename T, typename Indices, typename... Ts> + inline T& get(TupleImpl<Indices, Ts...>& t) + { + typedef tuple_index<T, TupleImpl<Indices, Ts...>> Index; + return static_cast<Internal::TupleLeaf<Index::index, T>&>(t).getInternal(); + } + + template <typename T, typename Indices, typename... Ts> + inline const T& get(const TupleImpl<Indices, Ts...>& t) + { + typedef tuple_index<T, TupleImpl<Indices, Ts...>> Index; + return static_cast<const Internal::TupleLeaf<Index::index, T>&>(t).getInternal(); + } + + template <typename T, typename Indices, typename... Ts> + inline T&& get(TupleImpl<Indices, Ts...>&& t) + { + typedef tuple_index<T, TupleImpl<Indices, Ts...>> Index; + return static_cast<T&&>(static_cast<Internal::TupleLeaf<Index::index, T>&>(t).getInternal()); + } + + + // TupleLike + // + // type-trait that determines if a type is an eastl::tuple or an eastl::pair. + // + template <typename T> struct TupleLike : public false_type {}; + template <typename T> struct TupleLike<const T> : public TupleLike<T> {}; + template <typename T> struct TupleLike<volatile T> : public TupleLike<T> {}; + template <typename T> struct TupleLike<const volatile T> : public TupleLike<T> {}; + + template <typename... Ts> + struct TupleLike<tuple<Ts...>> : public true_type {}; + + template <typename First, typename Second> + struct TupleLike<eastl::pair<First, Second>> : public true_type {}; + + + // TupleConvertible + // + // + // + template <bool IsSameSize, typename From, typename To> + struct TupleConvertibleImpl : public false_type + { + }; + + template <typename... FromTypes, typename... ToTypes> + struct TupleConvertibleImpl<true, TupleTypes<FromTypes...>, TupleTypes<ToTypes...>> + : public integral_constant<bool, conjunction<is_convertible<FromTypes, ToTypes>...>::value> + { + }; + + template <typename From, typename To, + bool = TupleLike<typename remove_reference<From>::type>::value, + bool = TupleLike<typename remove_reference<To>::type>::value> + struct TupleConvertible : public false_type + { + }; + + template <typename From, typename To> + struct TupleConvertible<From, To, true, true> + : public TupleConvertibleImpl<tuple_size<typename remove_reference<From>::type>::value == + tuple_size<typename remove_reference<To>::type>::value, + MakeTupleTypes_t<From>, MakeTupleTypes_t<To>> + { + }; + + + // TupleAssignable + // + // + // + template <bool IsSameSize, typename Target, typename From> + struct TupleAssignableImpl : public false_type + { + }; + + template <typename... TargetTypes, typename... FromTypes> + struct TupleAssignableImpl<true, TupleTypes<TargetTypes...>, TupleTypes<FromTypes...>> + : public bool_constant<conjunction<is_assignable<TargetTypes, FromTypes>...>::value> + { + }; + + template <typename Target, typename From, + bool = TupleLike<typename remove_reference<Target>::type>::value, + bool = TupleLike<typename remove_reference<From>::type>::value> + struct TupleAssignable : public false_type + { + }; + + template <typename Target, typename From> + struct TupleAssignable<Target, From, true, true> + : public TupleAssignableImpl< + tuple_size<typename remove_reference<Target>::type>::value == + tuple_size<typename remove_reference<From>::type>::value, + MakeTupleTypes_t<Target>, MakeTupleTypes_t<From>> + { + }; + + + // TupleImplicitlyConvertible and TupleExplicitlyConvertible + // + // helpers for constraining conditionally-explicit ctors + // + template <bool IsSameSize, typename TargetType, typename... FromTypes> + struct TupleImplicitlyConvertibleImpl : public false_type + { + }; + + + template <typename... TargetTypes, typename... FromTypes> + struct TupleImplicitlyConvertibleImpl<true, TupleTypes<TargetTypes...>, FromTypes...> + : public conjunction< + is_constructible<TargetTypes, FromTypes>..., + is_convertible<FromTypes, TargetTypes>...> + { + }; + + template <typename TargetTupleType, typename... FromTypes> + struct TupleImplicitlyConvertible + : public TupleImplicitlyConvertibleImpl< + tuple_size<TargetTupleType>::value == sizeof...(FromTypes), + MakeTupleTypes_t<TargetTupleType>, FromTypes...>::type + { + }; + + template<typename TargetTupleType, typename... FromTypes> + using TupleImplicitlyConvertible_t = enable_if_t<TupleImplicitlyConvertible<TargetTupleType, FromTypes...>::value, bool>; + + template <bool IsSameSize, typename TargetType, typename... FromTypes> + struct TupleExplicitlyConvertibleImpl : public false_type + { + }; + + template <typename... TargetTypes, typename... FromTypes> + struct TupleExplicitlyConvertibleImpl<true, TupleTypes<TargetTypes...>, FromTypes...> + : public conjunction< + is_constructible<TargetTypes, FromTypes>..., + negation<conjunction<is_convertible<FromTypes, TargetTypes>...>>> + { + }; + + template <typename TargetTupleType, typename... FromTypes> + struct TupleExplicitlyConvertible + : public TupleExplicitlyConvertibleImpl< + tuple_size<TargetTupleType>::value == sizeof...(FromTypes), + MakeTupleTypes_t<TargetTupleType>, FromTypes...>::type + { + }; + + template<typename TargetTupleType, typename... FromTypes> + using TupleExplicitlyConvertible_t = enable_if_t<TupleExplicitlyConvertible<TargetTupleType, FromTypes...>::value, bool>; + + + // TupleEqual + // + // + // + template <size_t I> + struct TupleEqual + { + template <typename Tuple1, typename Tuple2> + bool operator()(const Tuple1& t1, const Tuple2& t2) + { + static_assert(tuple_size<Tuple1>::value == tuple_size<Tuple2>::value, "comparing tuples of different sizes."); + return TupleEqual<I - 1>()(t1, t2) && get<I - 1>(t1) == get<I - 1>(t2); + } + }; + + template <> + struct TupleEqual<0> + { + template <typename Tuple1, typename Tuple2> + bool operator()(const Tuple1&, const Tuple2&) + { + return true; + } + }; + + + // TupleLess + // + // + // + template <size_t I> + struct TupleLess + { + template <typename Tuple1, typename Tuple2> + bool operator()(const Tuple1& t1, const Tuple2& t2) + { + static_assert(tuple_size<Tuple1>::value == tuple_size<Tuple2>::value, "comparing tuples of different sizes."); + return TupleLess<I - 1>()(t1, t2) || (!TupleLess<I - 1>()(t2, t1) && get<I - 1>(t1) < get<I - 1>(t2)); + } + }; + + template <> + struct TupleLess<0> + { + template <typename Tuple1, typename Tuple2> + bool operator()(const Tuple1&, const Tuple2&) + { + return false; + } + }; + + + // MakeTupleReturnImpl + // + // + // + template <typename T> struct MakeTupleReturnImpl { typedef T type; }; + template <typename T> struct MakeTupleReturnImpl<reference_wrapper<T>> { typedef T& type; }; + + template <typename T> + using MakeTupleReturn_t = typename MakeTupleReturnImpl<decay_t<T>>::type; + + + // tuple_cat helpers + // + // + // + + // TupleCat2Impl + template <typename Tuple1, typename Is1, typename Tuple2, typename Is2> + struct TupleCat2Impl; + + template <typename... T1s, size_t... I1s, typename... T2s, size_t... I2s> + struct TupleCat2Impl<tuple<T1s...>, index_sequence<I1s...>, tuple<T2s...>, index_sequence<I2s...>> + { + using ResultType = tuple<T1s..., T2s...>; + + template <typename Tuple1, typename Tuple2> + static inline ResultType DoCat2(Tuple1&& t1, Tuple2&& t2) + { + return ResultType(get<I1s>(eastl::forward<Tuple1>(t1))..., get<I2s>(eastl::forward<Tuple2>(t2))...); + } + }; + + // TupleCat2 + template <typename Tuple1, typename Tuple2> + struct TupleCat2; + + template <typename... T1s, typename... T2s> + struct TupleCat2<tuple<T1s...>, tuple<T2s...>> + { + using Is1 = make_index_sequence<sizeof...(T1s)>; + using Is2 = make_index_sequence<sizeof...(T2s)>; + using TCI = TupleCat2Impl<tuple<T1s...>, Is1, tuple<T2s...>, Is2>; + using ResultType = typename TCI::ResultType; + + template <typename Tuple1, typename Tuple2> + static inline ResultType DoCat2(Tuple1&& t1, Tuple2&& t2) + { + return TCI::DoCat2(eastl::forward<Tuple1>(t1), eastl::forward<Tuple2>(t2)); + } + }; + + // TupleCat + template <typename... Tuples> + struct TupleCat; + + template <typename Tuple1, typename Tuple2, typename... TuplesRest> + struct TupleCat<Tuple1, Tuple2, TuplesRest...> + { + using FirstResultType = typename TupleCat2<Tuple1, Tuple2>::ResultType; + using ResultType = typename TupleCat<FirstResultType, TuplesRest...>::ResultType; + + template <typename TupleArg1, typename TupleArg2, typename... TupleArgsRest> + static inline ResultType DoCat(TupleArg1&& t1, TupleArg2&& t2, TupleArgsRest&&... ts) + { + return TupleCat<FirstResultType, TuplesRest...>::DoCat( + TupleCat2<TupleArg1, TupleArg2>::DoCat2(eastl::forward<TupleArg1>(t1), eastl::forward<TupleArg2>(t2)), + eastl::forward<TupleArgsRest>(ts)...); + } + }; + + template <typename Tuple1, typename Tuple2> + struct TupleCat<Tuple1, Tuple2> + { + using TC2 = TupleCat2<Tuple1, remove_reference_t<Tuple2>>; + using ResultType = typename TC2::ResultType; + + template <typename TupleArg1, typename TupleArg2> + static inline ResultType DoCat(TupleArg1&& t1, TupleArg2&& t2) + { + return TC2::DoCat2(eastl::forward<TupleArg1>(t1), eastl::forward<TupleArg2>(t2)); + } + }; +} // namespace Internal + + + +// tuple +// +// eastl::tuple is a fixed-size container of heterogeneous values. It is a +// generalization of eastl::pair which hold only two heterogeneous values. +// +// https://en.cppreference.com/w/cpp/utility/tuple +// +template <typename... Ts> +class tuple; + +template <typename T, typename... Ts> +class tuple<T, Ts...> +{ +public: + EA_CONSTEXPR tuple() = default; + + template <typename T2 = T, + Internal::TupleImplicitlyConvertible_t<tuple, const T2&, const Ts&...> = 0> + EA_CONSTEXPR tuple(const T& t, const Ts&... ts) + : mImpl(make_index_sequence<sizeof...(Ts) + 1>{}, Internal::MakeTupleTypes_t<tuple>{}, t, ts...) + { + } + + template <typename T2 = T, + Internal::TupleExplicitlyConvertible_t<tuple, const T2&, const Ts&...> = 0> + explicit EA_CONSTEXPR tuple(const T& t, const Ts&... ts) + : mImpl(make_index_sequence<sizeof...(Ts) + 1>{}, Internal::MakeTupleTypes_t<tuple>{}, t, ts...) + { + } + + template <typename U, typename... Us, + Internal::TupleImplicitlyConvertible_t<tuple, U, Us...> = 0> + EA_CONSTEXPR tuple(U&& u, Us&&... us) + : mImpl(make_index_sequence<sizeof...(Us) + 1>{}, Internal::MakeTupleTypes_t<tuple>{}, eastl::forward<U>(u), + eastl::forward<Us>(us)...) + { + } + + template <typename U, typename... Us, + Internal::TupleExplicitlyConvertible_t<tuple, U, Us...> = 0> + explicit EA_CONSTEXPR tuple(U&& u, Us&&... us) + : mImpl(make_index_sequence<sizeof...(Us) + 1>{}, Internal::MakeTupleTypes_t<tuple>{}, eastl::forward<U>(u), + eastl::forward<Us>(us)...) + { + } + + template <typename OtherTuple, + typename enable_if<Internal::TupleConvertible<OtherTuple, tuple>::value, bool>::type = false> + tuple(OtherTuple&& t) + : mImpl(eastl::forward<OtherTuple>(t)) + { + } + + template <typename OtherTuple, + typename enable_if<Internal::TupleAssignable<tuple, OtherTuple>::value, bool>::type = false> + tuple& operator=(OtherTuple&& t) + { + mImpl.operator=(eastl::forward<OtherTuple>(t)); + return *this; + } + + void swap(tuple& t) { mImpl.swap(t.mImpl); } + +private: + typedef Internal::TupleImpl<make_index_sequence<sizeof...(Ts) + 1>, T, Ts...> Impl; + Impl mImpl; + + template <size_t I, typename... Ts_> + friend tuple_element_t<I, tuple<Ts_...>>& get(tuple<Ts_...>& t); + + template <size_t I, typename... Ts_> + friend const_tuple_element_t<I, tuple<Ts_...>>& get(const tuple<Ts_...>& t); + + template <size_t I, typename... Ts_> + friend tuple_element_t<I, tuple<Ts_...>>&& get(tuple<Ts_...>&& t); + + template <typename T_, typename... ts_> + friend T_& get(tuple<ts_...>& t); + + template <typename T_, typename... ts_> + friend const T_& get(const tuple<ts_...>& t); + + template <typename T_, typename... ts_> + friend T_&& get(tuple<ts_...>&& t); +}; + +// template specialization for an empty tuple +template <> +class tuple<> +{ +public: + void swap(tuple&) {} +}; + +template <size_t I, typename... Ts> +inline tuple_element_t<I, tuple<Ts...>>& get(tuple<Ts...>& t) +{ + return get<I>(t.mImpl); +} + +template <size_t I, typename... Ts> +inline const_tuple_element_t<I, tuple<Ts...>>& get(const tuple<Ts...>& t) +{ + return get<I>(t.mImpl); +} + +template <size_t I, typename... Ts> +inline tuple_element_t<I, tuple<Ts...>>&& get(tuple<Ts...>&& t) +{ + return get<I>(eastl::move(t.mImpl)); +} + +template <typename T, typename... Ts> +inline T& get(tuple<Ts...>& t) +{ + return get<T>(t.mImpl); +} + +template <typename T, typename... Ts> +inline const T& get(const tuple<Ts...>& t) +{ + return get<T>(t.mImpl); +} + +template <typename T, typename... Ts> +inline T&& get(tuple<Ts...>&& t) +{ + return get<T>(eastl::move(t.mImpl)); +} + +template <typename... Ts> +inline void swap(tuple<Ts...>& a, tuple<Ts...>& b) +{ + a.swap(b); +} + + +// tuple operators +// +// +template <typename... T1s, typename... T2s> +inline bool operator==(const tuple<T1s...>& t1, const tuple<T2s...>& t2) +{ + return Internal::TupleEqual<sizeof...(T1s)>()(t1, t2); +} + +template <typename... T1s, typename... T2s> +inline bool operator<(const tuple<T1s...>& t1, const tuple<T2s...>& t2) +{ + return Internal::TupleLess<sizeof...(T1s)>()(t1, t2); +} + +template <typename... T1s, typename... T2s> inline bool operator!=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t1 == t2); } +template <typename... T1s, typename... T2s> inline bool operator> (const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return t2 < t1; } +template <typename... T1s, typename... T2s> inline bool operator<=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t2 < t1); } +template <typename... T1s, typename... T2s> inline bool operator>=(const tuple<T1s...>& t1, const tuple<T2s...>& t2) { return !(t1 < t2); } + + +// tuple_cat +// +// +template <typename... Tuples> +inline typename Internal::TupleCat<Tuples...>::ResultType tuple_cat(Tuples&&... ts) +{ + return Internal::TupleCat<Tuples...>::DoCat(eastl::forward<Tuples>(ts)...); +} + + +// make_tuple +// +// +template <typename... Ts> +inline EA_CONSTEXPR tuple<Internal::MakeTupleReturn_t<Ts>...> make_tuple(Ts&&... values) +{ + return tuple<Internal::MakeTupleReturn_t<Ts>...>(eastl::forward<Ts>(values)...); +} + + +// forward_as_tuple +// +// +template <typename... Ts> +inline EA_CONSTEXPR tuple<Ts&&...> forward_as_tuple(Ts&&... ts) EA_NOEXCEPT +{ + return tuple<Ts&&...>(eastl::forward<Ts&&>(ts)...); +} + + +// ignore +// +// An object of unspecified type such that any value can be assigned to it with no effect. +// +// https://en.cppreference.com/w/cpp/utility/tuple/ignore +// +namespace Internal +{ + struct ignore_t + { + ignore_t() = default; + + template <typename T> + const ignore_t& operator=(const T&) const + { + return *this; + } + }; +}// namespace Internal + +static const Internal::ignore_t ignore; + + +// tie +// +// Creates a tuple of lvalue references to its arguments or instances of eastl::ignore. +// +// https://en.cppreference.com/w/cpp/utility/tuple/tie +// +template <typename... Ts> +inline EA_CONSTEXPR tuple<Ts&...> tie(Ts&... ts) EA_NOEXCEPT +{ + return tuple<Ts&...>(ts...); +} + + +// apply +// +// Invoke a callable object using a tuple to supply the arguments. +// +// http://en.cppreference.com/w/cpp/utility/apply +// +namespace detail +{ + template <class F, class Tuple, size_t... I> + EA_CONSTEXPR decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence<I...>) + { + return invoke(eastl::forward<F>(f), get<I>(eastl::forward<Tuple>(t))...); + } +} // namespace detail + +template <class F, class Tuple> +EA_CONSTEXPR decltype(auto) apply(F&& f, Tuple&& t) +{ + return detail::apply_impl(eastl::forward<F>(f), eastl::forward<Tuple>(t), + make_index_sequence<tuple_size_v<remove_reference_t<Tuple>>>{}); +} + +} // namespace eastl + + +/////////////////////////////////////////////////////////////// +// C++17 structured bindings support for eastl::tuple +// +#ifndef EA_COMPILER_NO_STRUCTURED_BINDING + #include <tuple> + namespace std + { + // NOTE(rparolin): Some platform implementations didn't check the standard specification and implemented the + // "tuple_size" and "tuple_element" primary template with as a struct. The standard specifies they are + // implemented with the class keyword so we provide the template specializations as a class and disable the + // generated warning. + EA_DISABLE_CLANG_WARNING(-Wmismatched-tags) + + template <class... Ts> + class tuple_size<::eastl::tuple<Ts...>> : public ::eastl::integral_constant<size_t, sizeof...(Ts)> + { + }; + + template <size_t I, class... Ts> + class tuple_element<I, ::eastl::tuple<Ts...>> : public ::eastl::tuple_element<I, ::eastl::tuple<Ts...>> + { + }; + + EA_RESTORE_CLANG_WARNING() + } +#endif + + +#endif // EASTL_TUPLE_ENABLED +EA_RESTORE_VC_WARNING() +EA_RESTORE_VC_WARNING() +EA_RESTORE_VC_WARNING() +#endif // EASTL_TUPLE_H |