/////////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_UTILITY_H #define EASTL_UTILITY_H #include #include #include #include #include #include #include #include #include #include // 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 inline void swap(T& a, T& b) EA_NOEXCEPT_IF(eastl::is_nothrow_move_constructible::value && eastl::is_nothrow_move_assignable::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 , /// as it's dependent on the swap algorithm, which is at a higher level than /// type traits. /// /// Example usage: /// static_assert(is_swappable::value, "int should be swappable"); /// #if defined(EA_COMPILER_NO_DECLTYPE) #define EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE 0 template 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 struct is_swappable : public integral_constant(), eastl::declval())), 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 EA_CONSTEXPR bool is_swappable_v = is_swappable::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 , /// 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 struct is_nothrow_swappable_helper_noexcept_wrapper { const static bool value = noexcept(swap(eastl::declval(), eastl::declval())); }; template struct is_nothrow_swappable_helper : public eastl::integral_constant::value> {}; // Don't prefix swap with eastl:: as we want to allow user-defined swaps via argument-dependent lookup. template struct is_nothrow_swappable_helper : public eastl::false_type {}; template struct is_nothrow_swappable : public eastl::is_nothrow_swappable_helper::value> {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED template EA_CONSTEXPR bool is_nothrow_swappable_v = is_nothrow_swappable::value; #endif /// is_swappable_with /// /// template ::value || eastl::is_void::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(), eastl::declval())), eastl::unused>::value && !eastl::is_same(), eastl::declval())), eastl::unused>::value; }; template struct is_swappable_with_helper { static const bool value = false; }; template struct is_swappable_with : public eastl::bool_constant::value> {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED template EA_CONSTEXPR bool is_swappable_with_v = is_swappable_with::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 struct is_nothrow_swappable_with_helper { static const bool value = false; }; #else #define EASTL_TYPE_TRAIT_is_nothrow_swappable_with_CONFORMANCE 1 template ::value || eastl::is_void::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(), eastl::declval())) && noexcept(swap(eastl::declval(), eastl::declval())); }; template struct is_nothrow_swappable_with_helper { static const bool value = false; }; #endif template struct is_nothrow_swappable_with : public eastl::bool_constant::value> {}; #if EASTL_VARIABLE_TEMPLATES_ENABLED template EA_CONSTEXPR bool is_nothrow_swappable_with_v = is_nothrow_swappable_with::value; #endif // iter_swap helper functions // template struct iter_swap_impl { // Handles the false case, where *a and *b are different types. template static void iter_swap(ForwardIterator1 a, ForwardIterator2 b) { typedef typename eastl::iterator_traits::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 { template 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 inline void iter_swap(ForwardIterator1 a, ForwardIterator2 b) { typedef typename eastl::iterator_traits::value_type value_type_a; typedef typename eastl::iterator_traits::value_type value_type_b; typedef typename eastl::iterator_traits::reference reference_a; typedef typename eastl::iterator_traits::reference reference_b; eastl::iter_swap_impl::value, eastl::is_same::value, eastl::is_same::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 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 inline void swap(T (&a)[N], T (&b)[N]) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable::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 inline T exchange(T& obj, U&& new_value) { T old_value = eastl::move(obj); obj = eastl::forward(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 EA_CONSTEXPR typename eastl::add_const::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 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 inline bool operator!=(const T& x, const T& y) { return !(x == y); } template inline bool operator>(const T& x, const T& y) { return (y < x); } template inline bool operator<=(const T& x, const T& y) { return !(y < x); } template 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 struct pair { typedef T1 first_type; typedef T2 second_type; typedef pair this_type; T1 first; T2 second; template && eastl::is_default_constructible_v>> EA_CONSTEXPR pair() : first(), second() { } #if EASTL_ENABLE_PAIR_FIRST_ELEMENT_CONSTRUCTOR template >> 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::pair(T1&&) [with T1 = const int&; T2 = const int&]' cannot be overloaded // error: with 'eastl::pair::pair(const T1&) [with T1 = const int&; T2 = const int&]' #if !defined(EA_COMPILER_GNUC) template >> 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 using single_pair_ctor_sfinae = eastl::enable_if_t>; #else template using single_pair_ctor_sfinae = void; #endif template > 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::pair(T1&&) [with T1 = const int&; T2 = const int&]' cannot be overloaded // error: with 'eastl::pair::pair(const T1&) [with T1 = const int&; T2 = const int&]' #if !defined(EA_COMPILER_GNUC) template > 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>> 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>> EA_CPP14_CONSTEXPR pair(const pair& p) : first(p.first), second(p.second) { } template && eastl::is_convertible_v>> EA_CPP14_CONSTEXPR pair(U&& u, V&& v) : first(eastl::forward(u)), second(eastl::forward(v)) { } template >> EA_CPP14_CONSTEXPR pair(U&& x, const T2& y) : first(eastl::forward(x)), second(y) { } template >> EA_CPP14_CONSTEXPR pair(const T1& x, V&& y) : first(x), second(eastl::forward(y)) { } template && eastl::is_convertible_v>> EA_CPP14_CONSTEXPR pair(pair&& p) : first(eastl::forward(p.first)), second(eastl::forward(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 && eastl::is_constructible_v>> pair(eastl::piecewise_construct_t pwc, eastl::tuple first_args, eastl::tuple second_args) : pair(pwc, eastl::move(first_args), eastl::move(second_args), eastl::make_index_sequence(), eastl::make_index_sequence()) { } private: // NOTE(rparolin): Internal constructor used to expand the index_sequence required to expand the tuple elements. template pair(eastl::piecewise_construct_t, eastl::tuple first_args, eastl::tuple second_args, eastl::index_sequence, eastl::index_sequence) : first(eastl::forward(eastl::get(first_args))...) , second(eastl::forward(eastl::get(second_args))...) { } public: pair& operator=(const pair& p) EA_NOEXCEPT_IF(eastl::is_nothrow_copy_assignable_v&& eastl::is_nothrow_copy_assignable_v) { first = p.first; second = p.second; return *this; } template && eastl::is_convertible_v>> pair& operator=(const pair& p) { first = p.first; second = p.second; return *this; } pair& operator=(pair&& p) EA_NOEXCEPT_IF(eastl::is_nothrow_move_assignable_v&& eastl::is_nothrow_move_assignable_v) { first = eastl::forward(p.first); second = eastl::forward(p.second); return *this; } template && eastl::is_convertible_v>> pair& operator=(pair&& p) { first = eastl::forward(p.first); second = eastl::forward(p.second); return *this; } void swap(pair& p) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable_v&& eastl::is_nothrow_swappable_v) { 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 struct use_self // : public unary_function // 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 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 struct use_second // : public unary_function // 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 EA_CPP14_CONSTEXPR inline bool operator==(const pair& a, const pair& b) { return ((a.first == b.first) && (a.second == b.second)); } template EA_CPP14_CONSTEXPR inline bool operator<(const pair& a, const pair& 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 EA_CPP14_CONSTEXPR inline bool operator!=(const pair& a, const pair& b) { return !(a == b); } template EA_CPP14_CONSTEXPR inline bool operator>(const pair& a, const pair& b) { return b < a; } template EA_CPP14_CONSTEXPR inline bool operator>=(const pair& a, const pair& b) { return !(a < b); } template EA_CPP14_CONSTEXPR inline bool operator<=(const pair& a, const pair& 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(charPtr, charPtr); /// template EA_CPP14_CONSTEXPR inline pair::type>::type, typename eastl::remove_reference_wrapper::type>::type> make_pair(T1&& a, T2&& b) { typedef typename eastl::remove_reference_wrapper::type>::type T1Type; typedef typename eastl::remove_reference_wrapper::type>::type T2Type; return eastl::pair(eastl::forward(a), eastl::forward(b)); } // Without the following, VC++ fails to compile code like this: pair p = eastl::make_pair("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 EA_CPP14_CONSTEXPR inline pair make_pair( const T1& a, const T2& b, typename eastl::enable_if::value && !eastl::is_array::value>::type* = 0) { return eastl::pair(a, b); } #endif // For backwards compatibility template EA_CPP14_CONSTEXPR inline pair::type>::type, typename eastl::remove_reference_wrapper::type>::type> make_pair_ref(T1&& a, T2&& b) { typedef typename eastl::remove_reference_wrapper::type>::type T1Type; typedef typename eastl::remove_reference_wrapper::type>::type T2Type; return eastl::pair(eastl::forward(a), eastl::forward(b)); } #if EASTL_TUPLE_ENABLED template class tuple_size> : public integral_constant { }; template class tuple_size> : public integral_constant { }; template class tuple_element<0, pair> { public: typedef T1 type; }; template class tuple_element<1, pair> { public: typedef T2 type; }; template class tuple_element<0, const pair> { public: typedef const T1 type; }; template class tuple_element<1, const pair> { public: typedef const T2 type; }; template struct GetPair; template <> struct GetPair<0> { template static EA_CONSTEXPR T1& getInternal(pair& p) { return p.first; } template static EA_CONSTEXPR const T1& getInternal(const pair& p) { return p.first; } template static EA_CONSTEXPR T1&& getInternal(pair&& p) { return eastl::forward(p.first); } }; template <> struct GetPair<1> { template static EA_CONSTEXPR T2& getInternal(pair& p) { return p.second; } template static EA_CONSTEXPR const T2& getInternal(const pair& p) { return p.second; } template static EA_CONSTEXPR T2&& getInternal(pair&& p) { return eastl::forward(p.second); } }; template tuple_element_t>& get(pair& p) { return GetPair::getInternal(p); } template const tuple_element_t>& get(const pair& p) { return GetPair::getInternal(p); } template tuple_element_t>&& get(pair&& p) { return GetPair::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 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 tuple_size<::eastl::pair> : public ::eastl::integral_constant { }; template class tuple_element> : public ::eastl::tuple_element> { }; EA_RESTORE_CLANG_WARNING() } #endif EA_RESTORE_VC_WARNING(); #endif // Header include guard