diff options
Diffstat (limited to 'include/EASTL/utility.h')
-rw-r--r-- | include/EASTL/utility.h | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/include/EASTL/utility.h b/include/EASTL/utility.h new file mode 100644 index 0000000..cc546fb --- /dev/null +++ b/include/EASTL/utility.h @@ -0,0 +1,872 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef EASTL_UTILITY_H +#define EASTL_UTILITY_H + + +#include <EASTL/internal/config.h> +#include <EASTL/type_traits.h> +#include <EASTL/iterator.h> +#include <EASTL/internal/functional_base.h> +#include <EASTL/internal/move_help.h> +#include <EABase/eahave.h> + +#include <EASTL/internal/integer_sequence.h> +#include <EASTL/internal/tuple_fwd_decls.h> +#include <EASTL/internal/in_place_t.h> +#include <EASTL/internal/piecewise_construct_t.h> + + +// 4619 - There is no warning number 'number'. +// 4217 - Member template functions cannot be used for copy-assignment or copy-construction. +// 4512 - 'class' : assignment operator could not be generated. // This disabling would best be put elsewhere. +EA_DISABLE_VC_WARNING(4619 4217 4512); + + +#if defined(EA_PRAGMA_ONCE_SUPPORTED) + #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. +#endif + + + +namespace eastl +{ + + /// swap + /// + /// Assigns the contents of a to b and the contents of b to a. + /// A temporary instance of type T is created and destroyed + /// in the process. + /// + /// This function is used by numerous other algorithms, and as + /// such it may in some cases be feasible and useful for the user + /// to implement an override version of this function which is + /// more efficient in some way. + /// + + template <typename T> + inline void swap(T& a, T& b) EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible<T>::value && eastl::is_nothrow_move_assignable<T>::value) + { + T temp(EASTL_MOVE(a)); // EASTL_MOVE uses EASTL::move when available, else is a no-op. + a = EASTL_MOVE(b); + b = EASTL_MOVE(temp); + } + + + /// is_swappable + /// + /// Determines if two types can be swapped via the swap function. This determines + /// only if there is a swap function that matches the types and not if the assignments + /// within the swap implementation are valid. + /// Returns false for pre-C++11 compilers that don't support decltype. + /// + /// This is a type trait, but it's not currently found within <type_traits.h>, + /// as it's dependent on the swap algorithm, which is at a higher level than + /// type traits. + /// + /// Example usage: + /// static_assert(is_swappable<int>::value, "int should be swappable"); + /// + #if defined(EA_COMPILER_NO_DECLTYPE) + #define EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE 0 + + template <typename> + struct is_swappable + : public eastl::false_type {}; + #else + #define EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE 1 + + // We declare this version of 'eastl::swap' to make compile-time existance checks for swap functions possible. + // + #if EASTL_VARIADIC_TEMPLATES_ENABLED + eastl::unused swap(eastl::argument_sink, eastl::argument_sink); + #else + // Compilers that do not support variadic templates suffer from a bug with variable arguments list that + // causes the construction of aligned types in unaligned memory. To prevent the aligned type construction we + // accept the parameters by reference. + eastl::unused swap(eastl::argument_sink&, eastl::argument_sink&); + #endif + + template <typename T> + struct is_swappable + : public integral_constant<bool, !eastl::is_same<decltype(swap(eastl::declval<T&>(), eastl::declval<T&>())), eastl::unused>::value> {}; // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. + #endif + + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template <class T> + EA_CONSTEXPR bool is_swappable_v = is_swappable<T>::value; + #endif + + + + /// is_nothrow_swappable + /// + /// Evaluates to true if is_swappable, and swap is a nothrow function. + /// returns false for pre-C++11 compilers that don't support nothrow. + /// + /// This is a type trait, but it's not currently found within <type_traits.h>, + /// as it's dependent on the swap algorithm, which is at a higher level than + /// type traits. + /// + #define EASTL_TYPE_TRAIT_is_nothrow_swappable_CONFORMANCE EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE + + template <typename T> + struct is_nothrow_swappable_helper_noexcept_wrapper + { const static bool value = noexcept(swap(eastl::declval<T&>(), eastl::declval<T&>())); }; + + template <typename T, bool> + struct is_nothrow_swappable_helper + : public eastl::integral_constant<bool, is_nothrow_swappable_helper_noexcept_wrapper<T>::value> {}; // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. + + template <typename T> + struct is_nothrow_swappable_helper<T, false> + : public eastl::false_type {}; + + template <typename T> + struct is_nothrow_swappable + : public eastl::is_nothrow_swappable_helper<T, eastl::is_swappable<T>::value> {}; + + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template <class T> + EA_CONSTEXPR bool is_nothrow_swappable_v = is_nothrow_swappable<T>::value; + #endif + + + + /// is_swappable_with + /// + /// + template <typename T, typename U, bool OneTypeIsVoid = (eastl::is_void<T>::value || eastl::is_void<U>::value)> + struct is_swappable_with_helper + { + // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. + static const bool value = + !eastl::is_same<decltype(swap(eastl::declval<T>(), eastl::declval<U>())), eastl::unused>::value && + !eastl::is_same<decltype(swap(eastl::declval<U>(), eastl::declval<T>())), eastl::unused>::value; + }; + + template <typename T, typename U> + struct is_swappable_with_helper<T,U, true> { static const bool value = false; }; + + template<typename T, typename U> + struct is_swappable_with + : public eastl::bool_constant<is_swappable_with_helper<T, U>::value> {}; + + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template <class T, class U> + EA_CONSTEXPR bool is_swappable_with_v = is_swappable_with<T, U>::value; + #endif + + + + /// is_nothrow_swappable_with + /// + /// + #if defined(EA_COMPILER_NO_DECLTYPE) || defined(EA_COMPILER_NO_NOEXCEPT) + #define EASTL_TYPE_TRAIT_is_nothrow_swappable_with_CONFORMANCE 0 + template <typename T, typename U> + struct is_nothrow_swappable_with_helper { static const bool value = false; }; + #else + #define EASTL_TYPE_TRAIT_is_nothrow_swappable_with_CONFORMANCE 1 + template <typename T, typename U, bool OneTypeIsVoid = (eastl::is_void<T>::value || eastl::is_void<U>::value)> + struct is_nothrow_swappable_with_helper + { + // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. + static const bool value = noexcept(swap(eastl::declval<T>(), eastl::declval<U>())) && + noexcept(swap(eastl::declval<U>(), eastl::declval<T>())); + }; + + template <typename T, typename U> + struct is_nothrow_swappable_with_helper<T,U, true> { static const bool value = false; }; + #endif + + template <typename T, typename U> + struct is_nothrow_swappable_with : public eastl::bool_constant<is_nothrow_swappable_with_helper<T, U>::value> {}; + + #if EASTL_VARIABLE_TEMPLATES_ENABLED + template <class T, class U> + EA_CONSTEXPR bool is_nothrow_swappable_with_v = is_nothrow_swappable_with<T, U>::value; + #endif + + + + // iter_swap helper functions + // + template <bool bTypesAreEqual> + struct iter_swap_impl + { + // Handles the false case, where *a and *b are different types. + template <typename ForwardIterator1, typename ForwardIterator2> + static void iter_swap(ForwardIterator1 a, ForwardIterator2 b) + { + typedef typename eastl::iterator_traits<ForwardIterator1>::value_type value_type_a; + + value_type_a temp(EASTL_MOVE(*a)); // EASTL_MOVE uses EASTL::move when available, else is a no-op. + *a = EASTL_MOVE(*b); + *b = EASTL_MOVE(temp); + } + }; + + template <> + struct iter_swap_impl<true> + { + template <typename ForwardIterator1, typename ForwardIterator2> + static void iter_swap(ForwardIterator1 a, ForwardIterator2 b) + { + swap(*a, *b); // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. + } + }; + + + /// iter_swap + /// + /// Swaps the values of the elements the given iterators are pointing to. + /// + /// Equivalent to swap(*a, *b), though the user can provide an override to + /// iter_swap that is independent of an override which may exist for swap. + /// + /// We provide a version of iter_swap which uses swap when the swapped types + /// are equal but a manual implementation otherwise. We do this because the + /// C++ standard defect report says that iter_swap(a, b) must be implemented + /// as swap(*a, *b) when possible. + /// + template <typename ForwardIterator1, typename ForwardIterator2> + inline void iter_swap(ForwardIterator1 a, ForwardIterator2 b) + { + typedef typename eastl::iterator_traits<ForwardIterator1>::value_type value_type_a; + typedef typename eastl::iterator_traits<ForwardIterator2>::value_type value_type_b; + typedef typename eastl::iterator_traits<ForwardIterator1>::reference reference_a; + typedef typename eastl::iterator_traits<ForwardIterator2>::reference reference_b; + + eastl::iter_swap_impl<eastl::type_and<eastl::is_same<value_type_a, value_type_b>::value, eastl::is_same<value_type_a&, reference_a>::value, eastl::is_same<value_type_b&, reference_b>::value >::value >::iter_swap(a, b); + } + + + + /// swap_ranges + /// + /// Swaps each of the elements in the range [first1, last1) with the + /// corresponding element in the range [first2, first2 + (last1 - first1)). + /// + /// Effects: For each nonnegative integer n < (last1 - first1), + /// performs: swap(*(first1 + n), *(first2 + n)). + /// + /// Requires: The two ranges [first1, last1) and [first2, first2 + (last1 - first1)) + /// shall not overlap. + /// + /// Returns: first2 + (last1 - first1). That is, returns the end of the second range. + /// + /// Complexity: Exactly 'last1 - first1' swaps. + /// + template <typename ForwardIterator1, typename ForwardIterator2> + inline ForwardIterator2 + swap_ranges(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2) + { + for(; first1 != last1; ++first1, ++first2) + iter_swap(first1, first2); // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. + return first2; + } + + + /// swap + /// + /// C++11 array swap + /// http://en.cppreference.com/w/cpp/algorithm/swap + /// + template <typename T, size_t N> + inline void + swap(T (&a)[N], T (&b)[N]) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable<T>::value) + { + eastl::swap_ranges(a, a + N, b); + } + + + /// exchange + /// + /// Replaces the value of the first argument with the new value provided. + /// The return value is the previous value of first argument. + /// + /// http://en.cppreference.com/w/cpp/utility/exchange + /// + template <typename T, typename U = T> + inline T exchange(T& obj, U&& new_value) + { + T old_value = eastl::move(obj); + obj = eastl::forward<U>(new_value); + return old_value; + } + + + /// as_const + /// + /// Converts a 'T&' into a 'const T&' which simplifies calling const functions on non-const objects. + /// + /// http://en.cppreference.com/w/cpp/utility/as_const + /// + /// C++ proposal paper: + /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4380.html + /// + template <class T> + EA_CONSTEXPR typename eastl::add_const<T>::type& as_const(T& t) EA_NOEXCEPT + { return t; } + + // The C++17 forbids 'eastl::as_const' from accepting rvalues. Passing an rvalue reference to 'eastl::as_const' + // generates an 'const T&' or const lvalue reference to a temporary object. + template <class T> + void as_const(const T&&) = delete; + + + /////////////////////////////////////////////////////////////////////// + /// rel_ops + /// + /// rel_ops allow the automatic generation of operators !=, >, <=, >= from + /// just operators == and <. These are intentionally in the rel_ops namespace + /// so that they don't conflict with other similar operators. To use these + /// operators, add "using namespace std::rel_ops;" to an appropriate place in + /// your code, usually right in the function that you need them to work. + /// In fact, you will very likely have collision problems if you put such + /// using statements anywhere other than in the .cpp file like so and may + /// also have collisions when you do, as the using statement will affect all + /// code in the module. You need to be careful about use of rel_ops. + /// + namespace rel_ops + { + template <typename T> + inline bool operator!=(const T& x, const T& y) + { return !(x == y); } + + template <typename T> + inline bool operator>(const T& x, const T& y) + { return (y < x); } + + template <typename T> + inline bool operator<=(const T& x, const T& y) + { return !(y < x); } + + template <typename T> + inline bool operator>=(const T& x, const T& y) + { return !(x < y); } + } + + + /////////////////////////////////////////////////////////////////////// + /// pair_first_construct + /// + /// Disambiguates when a user is requesting the 'single first element' pair constructor. + /// + struct pair_first_construct_t {}; + EA_CONSTEXPR pair_first_construct_t pair_first_construct = pair_first_construct_t(); + + + /////////////////////////////////////////////////////////////////////// + /// pair + /// + /// Implements a simple pair, just like the C++ std::pair. + /// + template <typename T1, typename T2> + struct pair + { + typedef T1 first_type; + typedef T2 second_type; + typedef pair<T1, T2> this_type; + + T1 first; + T2 second; + + template <typename TT1 = T1, + typename TT2 = T2, + class = eastl::enable_if_t<eastl::is_default_constructible_v<TT1> && + eastl::is_default_constructible_v<TT2>>> + EA_CONSTEXPR pair() + : first(), second() + { + } + + #if EASTL_ENABLE_PAIR_FIRST_ELEMENT_CONSTRUCTOR + template <typename TT1 = T1, typename TT2 = T2, typename = eastl::enable_if_t<eastl::is_default_constructible_v<TT2>>> + EA_CPP14_CONSTEXPR pair(const TT1& x) + : first(x), second() + { + } + + // GCC has a bug with overloading rvalue and lvalue function templates. + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54425 + // + // error: 'eastl::pair<T1, T2>::pair(T1&&) [with T1 = const int&; T2 = const int&]' cannot be overloaded + // error: with 'eastl::pair<T1, T2>::pair(const T1&) [with T1 = const int&; T2 = const int&]' + #if !defined(EA_COMPILER_GNUC) + template <typename TT2 = T2, typename = eastl::enable_if_t<eastl::is_default_constructible_v<TT2>>> + EA_CPP14_CONSTEXPR pair(T1&& x) + : first(eastl::move(x)), second() + { + } + #endif + #endif + + + // NOTE(rparolin): + // This is a workaround to a compiler intrinic bug which fails to correctly identify a nested class using + // non-static data member initialization as default constructible. + // + // See bug submitted to LLVM for more details. + // https://bugs.llvm.org/show_bug.cgi?id=38374 + #if !defined(EA_COMPILER_CLANG) + template<typename T> + using single_pair_ctor_sfinae = eastl::enable_if_t<eastl::is_default_constructible_v<T>>; + #else + template<typename> + using single_pair_ctor_sfinae = void; + #endif + + template <typename TT1 = T1, typename TT2 = T2, typename = single_pair_ctor_sfinae<TT2>> + EA_CPP14_CONSTEXPR pair(pair_first_construct_t, const TT1& x) + : first(x), second() + { + } + + // GCC has a bug with overloading rvalue and lvalue function templates. + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54425 + // + // error: 'eastl::pair<T1, T2>::pair(T1&&) [with T1 = const int&; T2 = const int&]' cannot be overloaded + // error: with 'eastl::pair<T1, T2>::pair(const T1&) [with T1 = const int&; T2 = const int&]' + #if !defined(EA_COMPILER_GNUC) + template <typename TT2 = T2, typename = single_pair_ctor_sfinae<TT2>> + EA_CPP14_CONSTEXPR pair(pair_first_construct_t, T1&& x) + : first(eastl::move(x)), second() + { + } + #endif + + template < + typename TT1 = T1, + typename TT2 = T2, + class = eastl::enable_if_t<eastl::is_copy_constructible_v<TT1> && eastl::is_copy_constructible_v<TT2>>> + EA_CPP14_CONSTEXPR pair(const T1& x, const T2& y) + : first(x), second(y) + { + } + + EA_CPP14_CONSTEXPR pair(pair&& p) = default; + EA_CPP14_CONSTEXPR pair(const pair&) = default; + + template < + typename U, + typename V, + class = eastl::enable_if_t<eastl::is_convertible_v<const U&, T1> && eastl::is_convertible_v<const V&, T2>>> + EA_CPP14_CONSTEXPR pair(const pair<U, V>& p) + : first(p.first), second(p.second) + { + } + + template <typename U, + typename V, + typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1> && eastl::is_convertible_v<V, T2>>> + EA_CPP14_CONSTEXPR pair(U&& u, V&& v) + : first(eastl::forward<U>(u)), second(eastl::forward<V>(v)) + { + } + + template <typename U, typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1>>> + EA_CPP14_CONSTEXPR pair(U&& x, const T2& y) + : first(eastl::forward<U>(x)), second(y) + { + } + + template <typename V, typename = eastl::enable_if_t<eastl::is_convertible_v<V, T2>>> + EA_CPP14_CONSTEXPR pair(const T1& x, V&& y) + : first(x), second(eastl::forward<V>(y)) + { + } + + template <typename U, + typename V, + typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1> && eastl::is_convertible_v<V, T2>>> + EA_CPP14_CONSTEXPR pair(pair<U, V>&& p) + : first(eastl::forward<U>(p.first)), second(eastl::forward<V>(p.second)) + { + } + + // Initializes first with arguments of types Args1... obtained by forwarding the elements of first_args and + // initializes second with arguments of types Args2... obtained by forwarding the elements of second_args. + template <class... Args1, + class... Args2, + typename = eastl::enable_if_t<eastl::is_constructible_v<first_type, Args1&&...> && + eastl::is_constructible_v<second_type, Args2&&...>>> + pair(eastl::piecewise_construct_t pwc, eastl::tuple<Args1...> first_args, eastl::tuple<Args2...> second_args) + : pair(pwc, + eastl::move(first_args), + eastl::move(second_args), + eastl::make_index_sequence<sizeof...(Args1)>(), + eastl::make_index_sequence<sizeof...(Args2)>()) + { + } + + private: + // NOTE(rparolin): Internal constructor used to expand the index_sequence required to expand the tuple elements. + template <class... Args1, class... Args2, size_t... I1, size_t... I2> + pair(eastl::piecewise_construct_t, + eastl::tuple<Args1...> first_args, + eastl::tuple<Args2...> second_args, + eastl::index_sequence<I1...>, + eastl::index_sequence<I2...>) + : first(eastl::forward<Args1>(eastl::get<I1>(first_args))...) + , second(eastl::forward<Args2>(eastl::get<I2>(second_args))...) + { + } + + public: + pair& operator=(const pair& p) + EA_NOEXCEPT_IF(eastl::is_nothrow_copy_assignable_v<T1>&& eastl::is_nothrow_copy_assignable_v<T2>) + { + first = p.first; + second = p.second; + return *this; + } + + template <typename U, + typename V, + typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1> && eastl::is_convertible_v<V, T2>>> + pair& operator=(const pair<U, V>& p) + { + first = p.first; + second = p.second; + return *this; + } + + pair& operator=(pair&& p) + EA_NOEXCEPT_IF(eastl::is_nothrow_move_assignable_v<T1>&& eastl::is_nothrow_move_assignable_v<T2>) + { + first = eastl::forward<T1>(p.first); + second = eastl::forward<T2>(p.second); + return *this; + } + + template <typename U, + typename V, + typename = eastl::enable_if_t<eastl::is_convertible_v<U, T1> && eastl::is_convertible_v<V, T2>>> + pair& operator=(pair<U, V>&& p) + { + first = eastl::forward<U>(p.first); + second = eastl::forward<V>(p.second); + return *this; + } + + void swap(pair& p) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable_v<T1>&& eastl::is_nothrow_swappable_v<T2>) + { + eastl::iter_swap(&first, &p.first); + eastl::iter_swap(&second, &p.second); + } + }; + + #define EASTL_PAIR_CONFORMANCE 1 + + + + /// use_self + /// + /// operator()(x) simply returns x. Used in sets, as opposed to maps. + /// This is a template policy implementation; it is an alternative to + /// the use_first template implementation. + /// + /// The existance of use_self may seem odd, given that it does nothing, + /// but these kinds of things are useful, virtually required, for optimal + /// generic programming. + /// + template <typename T> + struct use_self // : public unary_function<T, T> // Perhaps we want to make it a subclass of unary_function. + { + typedef T result_type; + + const T& operator()(const T& x) const + { return x; } + }; + + /// use_first + /// + /// operator()(x) simply returns x.first. Used in maps, as opposed to sets. + /// This is a template policy implementation; it is an alternative to + /// the use_self template implementation. This is the same thing as the + /// SGI SGL select1st utility. + /// + template <typename Pair> + struct use_first + { + typedef Pair argument_type; + typedef typename Pair::first_type result_type; + + const result_type& operator()(const Pair& x) const + { return x.first; } + }; + + /// use_second + /// + /// operator()(x) simply returns x.second. + /// This is the same thing as the SGI SGL select2nd utility + /// + template <typename Pair> + struct use_second // : public unary_function<Pair, typename Pair::second_type> // Perhaps we want to make it a subclass of unary_function. + { + typedef Pair argument_type; + typedef typename Pair::second_type result_type; + + const result_type& operator()(const Pair& x) const + { return x.second; } + }; + + + + + + /////////////////////////////////////////////////////////////////////// + // global operators + /////////////////////////////////////////////////////////////////////// + + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline bool operator==(const pair<T1, T2>& a, const pair<T1, T2>& b) + { + return ((a.first == b.first) && (a.second == b.second)); + } + + + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline bool operator<(const pair<T1, T2>& a, const pair<T1, T2>& b) + { + // Note that we use only operator < in this expression. Otherwise we could + // use the simpler: return (a.m1 == b.m1) ? (a.m2 < b.m2) : (a.m1 < b.m1); + // The user can write a specialization for this operator to get around this + // in cases where the highest performance is required. + return ((a.first < b.first) || (!(b.first < a.first) && (a.second < b.second))); + } + + + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline bool operator!=(const pair<T1, T2>& a, const pair<T1, T2>& b) + { + return !(a == b); + } + + + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline bool operator>(const pair<T1, T2>& a, const pair<T1, T2>& b) + { + return b < a; + } + + + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline bool operator>=(const pair<T1, T2>& a, const pair<T1, T2>& b) + { + return !(a < b); + } + + + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline bool operator<=(const pair<T1, T2>& a, const pair<T1, T2>& b) + { + return !(b < a); + } + + + + + /////////////////////////////////////////////////////////////////////// + /// make_pair / make_pair_ref + /// + /// make_pair is the same as std::make_pair specified by the C++ standard. + /// If you look at the C++ standard, you'll see that it specifies T& instead of T. + /// However, it has been determined that the C++ standard is incorrect and has + /// flagged it as a defect (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#181). + /// In case you feel that you want a more efficient version that uses references, + /// we provide the make_pair_ref function below, though C++11 move support + /// makes that no longer necessary. + /// + /// Note: You don't usually need to use make_pair in order to make a pair. + /// The following code is equivalent, and the latter avoids one more level of inlining: + /// return make_pair(charPtr, charPtr); + /// return pair<char*, char*>(charPtr, charPtr); + /// + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline pair<typename eastl::remove_reference_wrapper<typename eastl::decay<T1>::type>::type, + typename eastl::remove_reference_wrapper<typename eastl::decay<T2>::type>::type> + make_pair(T1&& a, T2&& b) + { + typedef typename eastl::remove_reference_wrapper<typename eastl::decay<T1>::type>::type T1Type; + typedef typename eastl::remove_reference_wrapper<typename eastl::decay<T2>::type>::type T2Type; + + return eastl::pair<T1Type, T2Type>(eastl::forward<T1>(a), eastl::forward<T2>(b)); + } + + + // Without the following, VC++ fails to compile code like this: pair<const char*, int> p = eastl::make_pair<const char*, int>("hello", 0); + // We define a const reference version alternative to the above. "hello" is of type char const(&)[6] (array of 6 const chars), + // but VC++ decays it to const char* and allows this make_pair to be called with that. VC++ fails below with make_pair("hello", "people") + // because you can't assign arrays and until we have a better solution we just disable this make_pair specialization for when T1 or T2 + // are of type char const(&)[]. + #if defined(_MSC_VER) + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline pair<T1, T2> make_pair( + const T1& a, + const T2& b, + typename eastl::enable_if<!eastl::is_array<T1>::value && !eastl::is_array<T2>::value>::type* = 0) + { + return eastl::pair<T1, T2>(a, b); + } + #endif + + // For backwards compatibility + template <typename T1, typename T2> + EA_CPP14_CONSTEXPR inline pair<typename eastl::remove_reference_wrapper<typename eastl::decay<T1>::type>::type, + typename eastl::remove_reference_wrapper<typename eastl::decay<T2>::type>::type> + make_pair_ref(T1&& a, T2&& b) + { + typedef typename eastl::remove_reference_wrapper<typename eastl::decay<T1>::type>::type T1Type; + typedef typename eastl::remove_reference_wrapper<typename eastl::decay<T2>::type>::type T2Type; + + return eastl::pair<T1Type, T2Type>(eastl::forward<T1>(a), eastl::forward<T2>(b)); + } + +#if EASTL_TUPLE_ENABLED + + template <typename T1, typename T2> + class tuple_size<pair<T1, T2>> : public integral_constant<size_t, 2> + { + }; + + template <typename T1, typename T2> + class tuple_size<const pair<T1, T2>> : public integral_constant<size_t, 2> + { + }; + + template <typename T1, typename T2> + class tuple_element<0, pair<T1, T2>> + { + public: + typedef T1 type; + }; + + template <typename T1, typename T2> + class tuple_element<1, pair<T1, T2>> + { + public: + typedef T2 type; + }; + + template <typename T1, typename T2> + class tuple_element<0, const pair<T1, T2>> + { + public: + typedef const T1 type; + }; + + template <typename T1, typename T2> + class tuple_element<1, const pair<T1, T2>> + { + public: + typedef const T2 type; + }; + + template <size_t I> + struct GetPair; + + template <> + struct GetPair<0> + { + template <typename T1, typename T2> + static EA_CONSTEXPR T1& getInternal(pair<T1, T2>& p) + { + return p.first; + } + + template <typename T1, typename T2> + static EA_CONSTEXPR const T1& getInternal(const pair<T1, T2>& p) + { + return p.first; + } + + template <typename T1, typename T2> + static EA_CONSTEXPR T1&& getInternal(pair<T1, T2>&& p) + { + return eastl::forward<T1>(p.first); + } + }; + + template <> + struct GetPair<1> + { + template <typename T1, typename T2> + static EA_CONSTEXPR T2& getInternal(pair<T1, T2>& p) + { + return p.second; + } + + template <typename T1, typename T2> + static EA_CONSTEXPR const T2& getInternal(const pair<T1, T2>& p) + { + return p.second; + } + + template <typename T1, typename T2> + static EA_CONSTEXPR T2&& getInternal(pair<T1, T2>&& p) + { + return eastl::forward<T2>(p.second); + } + }; + + template <size_t I, typename T1, typename T2> + tuple_element_t<I, pair<T1, T2>>& get(pair<T1, T2>& p) + { + return GetPair<I>::getInternal(p); + } + + template <size_t I, typename T1, typename T2> + const tuple_element_t<I, pair<T1, T2>>& get(const pair<T1, T2>& p) + { + return GetPair<I>::getInternal(p); + } + + template <size_t I, typename T1, typename T2> + tuple_element_t<I, pair<T1, T2>>&& get(pair<T1, T2>&& p) + { + return GetPair<I>::getInternal(eastl::move(p)); + } + +#endif // EASTL_TUPLE_ENABLED + + +} // namespace eastl + +/////////////////////////////////////////////////////////////// +// C++17 structured bindings support for eastl::pair +// +#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::pair<Ts...>> : public ::eastl::integral_constant<size_t, sizeof...(Ts)> + { + }; + + template <size_t I, class... Ts> + class tuple_element<I, ::eastl::pair<Ts...>> : public ::eastl::tuple_element<I, ::eastl::pair<Ts...>> + { + }; + + EA_RESTORE_CLANG_WARNING() + } +#endif + + +EA_RESTORE_VC_WARNING(); + + +#endif // Header include guard |