diff --git a/CMakeLists.txt b/CMakeLists.txt index e3eb4442..acc0d294 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,11 @@ include(CommonCppFlags) # Library definition #------------------------------------------------------------------------------------------- file(GLOB EASTL_SOURCES "source/*.cpp") -add_library(EASTL ${EASTL_SOURCES}) +file(GLOB_RECURSE EASTL_HEADERS "include/EASTL/**.h") +add_library(EASTL ${EASTL_SOURCES} ${EASTL_HEADERS}) + +# include both source and headers in the files tab in Visual Studio +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Header Files" FILES ${EASTL_HEADERS}) if (MSVC) set(EASTL_NATVIS_DIR "doc") diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 9ef8c669..af76aede 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -47,8 +47,13 @@ endif() #------------------------------------------------------------------------------------------- # Source files #------------------------------------------------------------------------------------------- -file(GLOB EASTLBENCHMARK_SOURCES "source/*.cpp" "../test/source/EASTLTestAllocator.cpp" "../test/source/EASTLTest.cpp") -set(SOURCES ${EASTLBENCHMARK_SOURCES}) +file(GLOB EASTLBENCHMARK_SOURCES "source/*.cpp") +file(GLOB EASTLTEST_SOURCES "../test/source/EASTLTestAllocator.cpp" "../test/source/EASTLTest.cpp") +file(GLOB EASTLBENCHMARK_HEADERS "source/*.h") +set(SOURCES ${EASTLBENCHMARK_SOURCES} ${EASTLTEST_SOURCES} ${EASTLBENCHMARK_HEADERS}) + +# include both source and headers in the files view in Visual Studio +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Header Files" FILES ${EASTLBENCHMARK_HEADERS}) #------------------------------------------------------------------------------------------- # Defines @@ -73,7 +78,7 @@ endif() #------------------------------------------------------------------------------------------- # Executable definition #------------------------------------------------------------------------------------------- -add_executable(EASTLBenchmarks ${EASTLBENCHMARK_SOURCES}) +add_executable(EASTLBenchmarks ${SOURCES}) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) diff --git a/benchmark/source/BenchmarkAlgorithm.cpp b/benchmark/source/BenchmarkAlgorithm.cpp index 57e155ea..4c960ba8 100644 --- a/benchmark/source/BenchmarkAlgorithm.cpp +++ b/benchmark/source/BenchmarkAlgorithm.cpp @@ -66,6 +66,13 @@ namespace std__ namespace { + // Exists for the purpose testing PODs that are larger than built-in types. + template + struct SizedPOD + { + char memory[kSize]; + }; + void TestFindEndStd(EA::StdC::Stopwatch& stopwatch, const std::string& sTest, const char* pSearchStringBegin, const char* pSearchStringEnd) { stopwatch.Restart(); diff --git a/doc/EASTL.natvis b/doc/EASTL.natvis index c3e94db1..e1ec96dc 100644 --- a/doc/EASTL.natvis +++ b/doc/EASTL.natvis @@ -242,7 +242,7 @@ {*mpNode} - mpNode + *(eastl::ListNode<$T1>*)mpNode @@ -299,7 +299,7 @@ {*mpNode} - *mpNode + *(eastl::SListNode<$T1>*)mpNode @@ -320,9 +320,9 @@ - {*mpNode} + {*($T1*)mpNode} - *mpNode + *($T1*)mpNode @@ -399,9 +399,9 @@ - {*mpNode} + {*(eastl::rbtree_node<$T1>*)mpNode} - mpNode + *(eastl::rbtree_node<$T1>*)mpNode @@ -432,6 +432,30 @@ + + + [{mnElementCount}] {{}} + [{mnElementCount}] {{ ... }} + + + + + + entry->mValue.second + + entry = entry->mpNext + + + bucketIndex++ + + entry = mpBucketArray[bucketIndex] + + + + + + {mValue}, {*mpNext} {mValue} @@ -568,6 +592,12 @@ + + {mAtomic} + + mAtomic + + {mFlag.mAtomic} diff --git a/include/EASTL/algorithm.h b/include/EASTL/algorithm.h index 6257514f..06f1e504 100644 --- a/include/EASTL/algorithm.h +++ b/include/EASTL/algorithm.h @@ -49,7 +49,7 @@ /////////////////////////////////////////////////////////////////////////////// // Optimizations // -// There are a number of opportunities for opptimizations that we take here +// There are a number of opportunities for optimizations that we take here // in this library. The most obvious kinds are those that subsitute memcpy // in the place of a conventional loop for data types with which this is // possible. The algorithms here are optimized to a higher level than currently @@ -62,7 +62,7 @@ // The various things we look to take advantage of in order to implement // optimizations include: // - Taking advantage of random access iterators. -// - Taking advantage of POD (plain old data) data types. +// - Taking advantage of trivially copyable data types (types for which it is safe to memcpy or memmove). // - Taking advantage of type_traits in general. // - Reducing branching and taking advantage of likely branch predictions. // - Taking advantage of issues related to pointer and reference aliasing. @@ -200,6 +200,8 @@ // sort_heap Found in heap.h // stable_sort Found in sort.h // stable_sort Found in sort.h +// partition Found in sort.h +// stable_partition Found in sort.h // swap // swap_ranges // transform @@ -212,6 +214,8 @@ // is_permutation // next_permutation // next_permutation +// is_partitioned +// partition_point // // Algorithms from the C++ standard that we don't implement are listed here. // Most of these items are absent because they aren't used very often. @@ -224,11 +228,9 @@ // inplace_merge // partial_sort_copy // partial_sort_copy -// paritition // prev_permutation // prev_permutation // search_n -// stable_partition // unique_copy // unique_copy // @@ -810,18 +812,18 @@ namespace eastl template inline T&& median_impl(T&& a, T&& b, T&& c) { - if(eastl::less()(a, b)) + if(a < b) { - if(eastl::less()(b, c)) + if(b < c) return eastl::forward(b); - else if(eastl::less()(a, c)) + else if(a < c) return eastl::forward(c); else return eastl::forward(a); } - else if(eastl::less()(a, c)) + else if(a < c) return eastl::forward(a); - else if(eastl::less()(b, c)) + else if(b < c) return eastl::forward(c); return eastl::forward(b); } @@ -1074,8 +1076,14 @@ namespace eastl // as it turns out that the latter results in unequal distribution probabilities. // http://www.cigital.com/papers/download/developer_gambling.php - for(RandomAccessIterator i = first + 1; i < last; ++i) + const difference_type swapMax = eastl::distance(first, last); + + // deliberately start at 1. + for (difference_type swapIter = 1; swapIter < swapMax; ++swapIter) + { + RandomAccessIterator i = first + swapIter; iter_swap(i, first + (difference_type)rng((eastl_size_t)((i - first) + 1))); + } } @@ -1254,8 +1262,12 @@ namespace eastl template static T* move_or_copy_backward(const T* first, const T* last, T* resultEnd) { - return (T*)memmove(resultEnd - (last - first), first, (size_t)((uintptr_t)last - (uintptr_t)first)); + const size_t n = (size_t)((uintptr_t)last - (uintptr_t)first); // We could use memcpy here if there's no range overlap, but memcpy is rarely much faster than memmove. + if (n > 0) + return (T*)memmove(resultEnd - (last - first), first, n); + else + return resultEnd; } }; @@ -1607,7 +1619,7 @@ namespace eastl for(; first1 != last1; ++first1) { - if(eastl::find_if(first2, last2, eastl::bind1st(predicate, *first1)) == last2) + if(eastl::find_if(first2, last2, [&predicate, first1](value_type& rhs) { return predicate(*first1, rhs); }) == last2) break; } @@ -1647,10 +1659,10 @@ namespace eastl { BidirectionalIterator1 it1(last1); - while((--it1 != first1) && (eastl::find_if(first2, last2, eastl::bind1st(predicate, *it1)) == last2)) + while((--it1 != first1) && (eastl::find_if(first2, last2, [&predicate, it1](value_type& rhs) { return predicate(*it1, rhs); }) == last2)) ; // Do nothing - if((it1 != first1) || (eastl::find_if(first2, last2, eastl::bind1st(predicate, *it1)) != last2)) + if((it1 != first1) || (eastl::find_if(first2, last2, [&predicate, it1](value_type& rhs) { return predicate(*it1, rhs); }) != last2)) return it1; } @@ -1690,10 +1702,10 @@ namespace eastl { BidirectionalIterator1 it1(last1); - while((--it1 != first1) && (eastl::find_if(first2, last2, eastl::bind1st(predicate, *it1)) != last2)) + while((--it1 != first1) && (eastl::find_if(first2, last2, [&predicate, it1](value_type& rhs) { return predicate(*it1, rhs); }) != last2)) ; // Do nothing - if((it1 != first1) || (eastl::find_if(first2, last2, eastl::bind1st(predicate, *it1))) != last2) + if((it1 != first1) || (eastl::find_if(first2, last2, [&predicate, it1](value_type& rhs) { return predicate(*it1, rhs); })) != last2) return it1; } @@ -2008,7 +2020,10 @@ namespace eastl lexicographical_compare(const char* first1, const char* last1, const char* first2, const char* last2) { const ptrdiff_t n1(last1 - first1), n2(last2 - first2); - const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + const size_t n = (size_t)eastl::min_alt(n1, n2); + if (n == 0) // don't call memcmp with n == 0 + return false; + const int result = memcmp(first1, first2, n); return result ? (result < 0) : (n1 < n2); } @@ -2016,7 +2031,10 @@ namespace eastl lexicographical_compare(char* first1, char* last1, char* first2, char* last2) { const ptrdiff_t n1(last1 - first1), n2(last2 - first2); - const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + const size_t n = (size_t)eastl::min_alt(n1, n2); + if (n == 0) // don't call memcmp with n == 0 + return false; + const int result = memcmp(first1, first2, n); return result ? (result < 0) : (n1 < n2); } @@ -2024,7 +2042,10 @@ namespace eastl lexicographical_compare(const unsigned char* first1, const unsigned char* last1, const unsigned char* first2, const unsigned char* last2) { const ptrdiff_t n1(last1 - first1), n2(last2 - first2); - const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + const size_t n = (size_t)eastl::min_alt(n1, n2); + if (n == 0) // don't call memcmp with n == 0 + return false; + const int result = memcmp(first1, first2, n); return result ? (result < 0) : (n1 < n2); } @@ -2032,7 +2053,10 @@ namespace eastl lexicographical_compare(unsigned char* first1, unsigned char* last1, unsigned char* first2, unsigned char* last2) { const ptrdiff_t n1(last1 - first1), n2(last2 - first2); - const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + const size_t n = (size_t)eastl::min_alt(n1, n2); + if (n == 0) // don't call memcmp with n == 0 + return false; + const int result = memcmp(first1, first2, n); return result ? (result < 0) : (n1 < n2); } @@ -2040,7 +2064,10 @@ namespace eastl lexicographical_compare(const signed char* first1, const signed char* last1, const signed char* first2, const signed char* last2) { const ptrdiff_t n1(last1 - first1), n2(last2 - first2); - const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + const size_t n = (size_t)eastl::min_alt(n1, n2); + if (n == 0) // don't call memcmp with n == 0 + return false; + const int result = memcmp(first1, first2, n); return result ? (result < 0) : (n1 < n2); } @@ -2048,7 +2075,10 @@ namespace eastl lexicographical_compare(signed char* first1, signed char* last1, signed char* first2, signed char* last2) { const ptrdiff_t n1(last1 - first1), n2(last2 - first2); - const int result = memcmp(first1, first2, (size_t)eastl::min_alt(n1, n2)); + const size_t n = (size_t)eastl::min_alt(n1, n2); + if (n == 0) // don't call memcmp with n == 0 + return false; + const int result = memcmp(first1, first2, n); return result ? (result < 0) : (n1 < n2); } @@ -4037,7 +4067,7 @@ namespace eastl /// - There's a basic ForwardIterator implementation (rotate_general_impl) which is /// a fallback implementation that's not as fast as others but works for all cases. /// - There's a slightly better BidirectionalIterator implementation. - /// - We have specialized versions for rotating elements that are is_trivially_move_assignable. + /// - We have specialized versions for rotating elements that are trivially copyable. /// These versions will use memmove for when we have a RandomAccessIterator. /// - We have a specialized version for rotating by only a single position, as that allows us /// (with any iterator type) to avoid a lot of logic involved with algorithms like "flipping hands" @@ -4084,7 +4114,7 @@ namespace eastl value_type temp(eastl::move(*first)); ForwardIterator result = eastl::move(eastl::next(first), last, first); // Note that while our template type is BidirectionalIterator, if the actual - *result = eastl::move(temp); // iterator is a RandomAccessIterator then this move will be a memmove for trivial types. + *result = eastl::move(temp); // iterator is a RandomAccessIterator then this move will be a memmove for trivially copyable types. return result; // result points to the final element in the range. } @@ -4098,12 +4128,12 @@ namespace eastl BidirectionalIterator beforeLast = eastl::prev(last); value_type temp(eastl::move(*beforeLast)); BidirectionalIterator result = eastl::move_backward(first, beforeLast, last); // Note that while our template type is BidirectionalIterator, if the actual - *first = eastl::move(temp); // iterator is a RandomAccessIterator then this move will be a memmove for trivial types. + *first = eastl::move(temp); // iterator is a RandomAccessIterator then this move will be a memmove for trivially copyable types. return result; // result points to the first element in the range. } - template + template struct rotate_helper { template @@ -4272,10 +4302,10 @@ namespace eastl typedef typename eastl::iterator_traits::iterator_category IC; typedef typename eastl::iterator_traits::value_type value_type; - return Internal::rotate_helper::value || // This is the best way of telling if we can move types via memmove, but without a conforming C++11 compiler it usually returns false. - eastl::is_pod::value || // This is a more conservative way of telling if we can move types via memmove, and most compilers support it, but it doesn't have as full of coverage as is_trivially_move_assignable. - eastl::is_scalar::value> // This is the most conservative means and works with all compilers, but works only for scalars. - ::rotate_impl(first, middle, last); + // the implementations for is_trivially_copyable types simply check whether we have a single element to rotate and if so, + // defer to either move_rotate_left_by_one or move_rotate_right_by_one, which are optimized for trivially copyable types. + // otherwise, use the same implementation as non-trivially copyable types. + return Internal::rotate_helper::value>::rotate_impl(first, middle, last); } return first; @@ -4320,23 +4350,69 @@ namespace eastl } + /// is_partitioned + /// + /// Returns true if all the elements in the range [first, last) is empty, or is + /// partitioned by predicate. Being partitioned means that all elements v for which + /// predicate(v) evaluates to true appear before any elements for which predicate(v) + /// is false. + /// + template + EA_CONSTEXPR bool is_partitioned(InputIterator first, InputIterator last, UnaryPredicate predicate) + { + for (; first != last; ++first) + { + if (!predicate(*first)) + { + // advance the iterator, we don't need to call the predicate on this item + // again in the "false" loop below. + ++first; + break; + } + } + for (; first != last; ++first) + { + if (predicate(*first)) + { + return false; + } + } + return true; + } -} // namespace eastl - - -#endif // Header include guard - - - - - - - - - - - + /// partition_point + /// + /// Precondition: for this function to work correctly the input range [first, last) + /// must be partitioned by the predicate. i.e. all values for which predicate(v) is + /// true should precede any value in the range for which predicate(v) is false. + /// + /// Returns: the iterator past the end of the first partition within [first, last) or + /// last if all elements satisfy the predicate. + /// + /// Note: this is a more general version of lower_bound. + template + EA_CONSTEXPR ForwardIterator partition_point(ForwardIterator first, ForwardIterator last, UnaryPredicate predicate) + { + // Just binary chop our way to the first one where predicate(x) is false + for (auto length = eastl::distance(first, last); 0 < length;) + { + const auto half = length / 2; + const auto middle = eastl::next(first, half); + if (predicate(*middle)) + { + first = eastl::next(middle); + length -= (half + 1); + } + else + { + length = half; + } + } + return first; + } +} // namespace eastl +#endif // Header include guard diff --git a/include/EASTL/array.h b/include/EASTL/array.h index 34ad07d2..218170c6 100644 --- a/include/EASTL/array.h +++ b/include/EASTL/array.h @@ -17,6 +17,7 @@ #include +#include #include #include #include @@ -69,18 +70,17 @@ namespace eastl typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. typedef ptrdiff_t difference_type; - public: enum { - count = N + count EASTL_REMOVE_AT_2024_APRIL = N }; // Note that the member data is intentionally public. // This allows for aggregate initialization of the // object (e.g. array a = { 0, 3, 2, 4 }; ) - value_type mValue[N ? N : 1]; + // do not use this member directly (use data() instead). + value_type mValue[N]; - public: // We intentionally provide no constructor, destructor, or assignment operator. void fill(const value_type& value); @@ -128,6 +128,92 @@ namespace eastl }; // class array + // declaring a C-style array of size 0 is not valid C++. + // thus, we have to declare this partial specialization: + template + struct array + { + public: + typedef array this_type; + typedef T value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef eastl::reverse_iterator reverse_iterator; + typedef eastl::reverse_iterator const_reverse_iterator; + typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. + typedef ptrdiff_t difference_type; + + enum + { + count EASTL_REMOVE_AT_2024_APRIL = 0 + }; + + // We intentionally provide no constructor, destructor, or assignment operator. + + void fill(const value_type& value) {} + + // Unlike the swap function for other containers, array::swap takes linear time, + // may exit via an exception, and does not cause iterators to become associated with the other container. + void swap(this_type& x) EA_NOEXCEPT {} + + EA_CPP14_CONSTEXPR iterator begin() EA_NOEXCEPT { return nullptr; } + EA_CPP14_CONSTEXPR const_iterator begin() const EA_NOEXCEPT { return nullptr; } + EA_CPP14_CONSTEXPR const_iterator cbegin() const EA_NOEXCEPT { return nullptr; } + + EA_CPP14_CONSTEXPR iterator end() EA_NOEXCEPT { return nullptr; } + EA_CPP14_CONSTEXPR const_iterator end() const EA_NOEXCEPT { return nullptr; } + EA_CPP14_CONSTEXPR const_iterator cend() const EA_NOEXCEPT { return nullptr; } + + EA_CPP14_CONSTEXPR reverse_iterator rbegin() EA_NOEXCEPT { return reverse_iterator(nullptr); } + EA_CPP14_CONSTEXPR const_reverse_iterator rbegin() const EA_NOEXCEPT { return const_reverse_iterator(nullptr); } + EA_CPP14_CONSTEXPR const_reverse_iterator crbegin() const EA_NOEXCEPT { return const_reverse_iterator(nullptr); } + + EA_CPP14_CONSTEXPR reverse_iterator rend() EA_NOEXCEPT { return reverse_iterator(nullptr); } + EA_CPP14_CONSTEXPR const_reverse_iterator rend() const EA_NOEXCEPT { return const_reverse_iterator(nullptr); } + EA_CPP14_CONSTEXPR const_reverse_iterator crend() const EA_NOEXCEPT { return const_reverse_iterator(nullptr); } + + EA_CPP14_CONSTEXPR bool empty() const EA_NOEXCEPT { return true; } + EA_CPP14_CONSTEXPR size_type size() const EA_NOEXCEPT { return 0; } + EA_CPP14_CONSTEXPR size_type max_size() const EA_NOEXCEPT { return 0; } + + EA_CPP14_CONSTEXPR T* data() EA_NOEXCEPT { return nullptr; } + EA_CPP14_CONSTEXPR const T* data() const EA_NOEXCEPT { return nullptr; } + + EA_CPP14_CONSTEXPR reference operator[](size_type i) { return *data(); } + EA_CPP14_CONSTEXPR const_reference operator[](size_type i) const { return *data(); } + EA_CPP14_CONSTEXPR const_reference at(size_type i) const + { +#if EASTL_EXCEPTIONS_ENABLED + throw std::out_of_range("array::at -- out of range"); +#elif EASTL_ASSERT_ENABLED + EASTL_FAIL_MSG("array::at -- out of range"); +#endif + return *data(); + } + EA_CPP14_CONSTEXPR reference at(size_type i) + { +#if EASTL_EXCEPTIONS_ENABLED + throw std::out_of_range("array::at -- out of range"); +#elif EASTL_ASSERT_ENABLED + EASTL_FAIL_MSG("array::at -- out of range"); +#endif + return *data(); + } + + EA_CPP14_CONSTEXPR reference front() { return *data(); } + EA_CPP14_CONSTEXPR const_reference front() const { return *data(); } + + EA_CPP14_CONSTEXPR reference back() { return *data(); } + EA_CPP14_CONSTEXPR const_reference back() const { return *data(); } + + bool validate() const { return true; } + int validate_iterator(const_iterator i) const { return isf_none; } + + }; // class array + + /////////////////////////////////////////////////////////////////////////// // template deduction guides @@ -444,6 +530,38 @@ namespace eastl } #endif + /////////////////////////////////////////////////////////////////////// + // non-member functions + /////////////////////////////////////////////////////////////////////// + + template + EA_NODISCARD EA_CONSTEXPR T& get(array& value) EA_NOEXCEPT + { + static_assert(I < N, "array index out of bounds"); + return value.mValue[I]; + } + + template + EA_NODISCARD EA_CONSTEXPR T&& get(array&& value) EA_NOEXCEPT + { + static_assert(I < N, "array index out of bounds"); + return move(value.mValue[I]); + } + + template + EA_NODISCARD EA_CONSTEXPR const T& get(const array& value) EA_NOEXCEPT + { + static_assert(I < N, "array index out of bounds"); + return value.mValue[I]; + } + + template + EA_NODISCARD EA_CONSTEXPR const T&& get(const array&& value) EA_NOEXCEPT + { + static_assert(I < N, "array index out of bounds"); + return move(value.mValue[I]); + } + template inline void swap(array& a, array& b) { @@ -487,93 +605,48 @@ namespace eastl #if EASTL_TUPLE_ENABLED - template - class tuple_size> : public integral_constant - { - }; - - template - class tuple_size> : public integral_constant - { - }; - - template - class tuple_element> - { - public: - using type = T; - }; - - template - class tuple_element> - { - public: - using type = const T; - }; + /////////////////////////////////////////////////////////////////////// + // helper classes + /////////////////////////////////////////////////////////////////////// - template - struct GetArray - { - template - static EA_CONSTEXPR T& getInternal(array& a) - { - return a[I]; - } + template + struct tuple_size> : public integral_constant {}; - template - static EA_CONSTEXPR const T& getInternal(const array& a) - { - return a[I]; - } + namespace internal { + template + struct tuple_element {}; - template - static EA_CONSTEXPR T&& getInternal(array&& a) - { - return eastl::forward(a[I]); - } + template + struct tuple_element> { + using type = T; }; - - template - EA_CONSTEXPR tuple_element_t>& get(array& p) - { - return GetArray::getInternal(p); - } - - template - EA_CONSTEXPR const tuple_element_t>& get(const array& p) - { - return GetArray::getInternal(p); } - template - EA_CONSTEXPR tuple_element_t>&& get(array&& p) - { - return GetArray::getInternal(eastl::move(p)); - } + template + struct tuple_element> : internal::tuple_element {}; #endif // EASTL_TUPLE_ENABLED - - } // namespace eastl -/////////////////////////////////////////////////////////////// -// C++17 structured binding support for eastl::array -// +/////////////////////////////////////////////////////////////////////// +// C++17 structured bindings support for eastl::array +/////////////////////////////////////////////////////////////////////// + #ifndef EA_COMPILER_NO_STRUCTURED_BINDING - #include +// we can't forward declare tuple_size and tuple_element because some std implementations +// don't declare it in the std namespace, but instead alias it. +#include - template - class std::tuple_size<::eastl::array> : public ::eastl::integral_constant - { - }; +namespace std +{ - template - struct std::tuple_element> - { - static_assert(I < N, "index is out of bounds"); - using type = T; - }; -#endif // EA_COMPILER_NO_STRUCTURED_BINDING +template +struct tuple_size> : public integral_constant {}; + +template +struct tuple_element> : public eastl::tuple_element> {}; +} +#endif #endif // Header include guard diff --git a/include/EASTL/bonus/list_map.h b/include/EASTL/bonus/list_map.h index 8a080d6d..3c3f74ca 100644 --- a/include/EASTL/bonus/list_map.h +++ b/include/EASTL/bonus/list_map.h @@ -75,12 +75,18 @@ namespace eastl typedef Reference reference; typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category; +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + private: + base_node_type* mpNode; +#else public: node_type* mpNode; +#endif public: list_map_iterator(); list_map_iterator(const base_node_type* pNode); + // Note: this isn't always a copy constructor, iterator is not always equal to this_type list_map_iterator(const iterator& x); reference operator*() const; @@ -92,6 +98,32 @@ namespace eastl this_type& operator--(); this_type operator--(int); + private: + // This is a temp helper function for the deprecation. + // It should be removed when the deprecation window ends. +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + base_node_type* toInternalNodeType(base_node_type* node) { return node; } +#else + node_type* toInternalNodeType(base_node_type* node) { return static_cast(node); } +#endif + + template + friend bool operator==(const list_map_iterator&, const list_map_iterator&); + + template + friend bool operator!=(const list_map_iterator&, const list_map_iterator&); + + template + friend bool operator!=(const list_map_iterator&, const list_map_iterator&); + + // list_map uses mpNode + template + friend class list_map; + + // for the "copy" constructor, which uses non-const iterator even in the + // const_iterator case. + friend iterator; + friend const_iterator; }; // list_map_iterator @@ -396,7 +428,7 @@ namespace eastl template inline list_map_iterator::list_map_iterator(const base_node_type* pNode) - : mpNode(static_cast(const_cast(pNode))) + : mpNode(toInternalNodeType(const_cast(pNode))) { // Empty } @@ -404,7 +436,7 @@ namespace eastl template inline list_map_iterator::list_map_iterator(const iterator& x) - : mpNode(const_cast(x.mpNode)) + : mpNode(x.mpNode) { // Empty } @@ -414,7 +446,7 @@ namespace eastl inline typename list_map_iterator::reference list_map_iterator::operator*() const { - return mpNode->mValue; + return static_cast(mpNode)->mValue; } @@ -422,7 +454,7 @@ namespace eastl inline typename list_map_iterator::pointer list_map_iterator::operator->() const { - return &mpNode->mValue; + return &static_cast(mpNode)->mValue; } @@ -430,7 +462,7 @@ namespace eastl inline typename list_map_iterator::this_type& list_map_iterator::operator++() { - mpNode = static_cast(mpNode->mpNext); + mpNode = toInternalNodeType(mpNode->mpNext); return *this; } @@ -440,7 +472,7 @@ namespace eastl list_map_iterator::operator++(int) { this_type temp(*this); - mpNode = static_cast(mpNode->mpNext); + mpNode = toInternalNodeType(mpNode->mpNext); return temp; } @@ -449,7 +481,7 @@ namespace eastl inline typename list_map_iterator::this_type& list_map_iterator::operator--() { - mpNode = static_cast(mpNode->mpPrev); + mpNode = toInternalNodeType(mpNode->mpPrev); return *this; } @@ -459,7 +491,7 @@ namespace eastl list_map_iterator::operator--(int) { this_type temp(*this); - mpNode = static_cast(mpNode->mpPrev); + mpNode = toInternalNodeType(mpNode->mpPrev); return temp; } diff --git a/include/EASTL/bonus/tuple_vector.h b/include/EASTL/bonus/tuple_vector.h index 6ade75af..9cbb14b4 100644 --- a/include/EASTL/bonus/tuple_vector.h +++ b/include/EASTL/bonus/tuple_vector.h @@ -270,8 +270,8 @@ struct TupleVecLeaf void DoInsertRange(T* pSrcBegin, T* pSrcEnd, T* pDestBegin, size_type numDataElements) { - size_type pos = pDestBegin - mpData; - size_type n = pSrcEnd - pSrcBegin; + size_type pos = static_cast(pDestBegin - mpData); + size_type n = static_cast(pSrcEnd - pSrcBegin); T* pDataEnd = mpData + numDataElements; const size_type nExtra = numDataElements - pos; if (n < nExtra) // If the inserted values are entirely within initialized memory (i.e. are before mpEnd)... @@ -340,14 +340,11 @@ struct TupleVecIterCompatible, TupleTypes> : // storing - and harmoniously updating on each modification - a full tuple of pointers to the tupleVec's data template struct TupleVecIter, Ts...> - : public iterator, eastl_size_t, tuple, tuple> { private: typedef TupleVecIter, Ts...> this_type; typedef eastl_size_t size_type; - typedef iterator, eastl_size_t, tuple, tuple> iter_type; - template friend struct TupleVecIter; @@ -357,11 +354,11 @@ struct TupleVecIter, Ts...> template friend class move_iterator; public: - typedef typename iter_type::iterator_category iterator_category; - typedef typename iter_type::value_type value_type; - typedef typename iter_type::difference_type difference_type; - typedef typename iter_type::pointer pointer; - typedef typename iter_type::reference reference; + typedef EASTL_ITC_NS::random_access_iterator_tag iterator_category; + typedef tuple value_type; + typedef eastl_size_t difference_type; + typedef tuple pointer; + typedef tuple reference; TupleVecIter() = default; @@ -648,7 +645,7 @@ class TupleVecImpl, Ts...> : public TupleV if (EASTL_UNLIKELY(first > last || first == nullptr || last == nullptr)) EASTL_FAIL_MSG("tuple_vector::assign from tuple array -- invalid ptrs"); #endif - size_type newNumElements = last - first; + size_type newNumElements = static_cast(last - first); if (newNumElements > mNumCapacity) { this_type temp(first, last, get_allocator()); @@ -871,7 +868,7 @@ class TupleVecImpl, Ts...> : public TupleV EASTL_FAIL_MSG("tuple_vector::insert -- invalid source pointers"); #endif size_type posIdx = pos - cbegin(); - size_type numToInsert = last - first; + size_type numToInsert = static_cast(last - first); size_type oldNumElements = mNumElements; size_type newNumElements = oldNumElements + numToInsert; size_type oldNumCapacity = mNumCapacity; @@ -986,7 +983,7 @@ class TupleVecImpl, Ts...> : public TupleV { DoReallocate(oldNumElements, eastl::max(GetNewCapacity(oldNumCapacity), n)); } - swallow((eastl::uninitialized_default_fill_n(TupleVecLeaf::mpData + oldNumElements, n - oldNumElements), 0)...); + swallow((eastl::uninitialized_value_construct_n(TupleVecLeaf::mpData + oldNumElements, n - oldNumElements), 0)...); } else { @@ -1330,7 +1327,7 @@ class TupleVecImpl, Ts...> : public TupleV { DoConditionalReallocate(0, mNumCapacity, n); mNumElements = n; - swallow((eastl::uninitialized_default_fill_n(TupleVecLeaf::mpData, n), 0)...); + swallow((eastl::uninitialized_value_construct_n(TupleVecLeaf::mpData, n), 0)...); } void DoInitFromTupleArray(const value_tuple* first, const value_tuple* last) @@ -1339,7 +1336,7 @@ class TupleVecImpl, Ts...> : public TupleV if (EASTL_UNLIKELY(first > last || first == nullptr || last == nullptr)) EASTL_FAIL_MSG("tuple_vector::ctor from tuple array -- invalid ptrs"); #endif - size_type newNumElements = last - first; + size_type newNumElements = static_cast(last - first); DoConditionalReallocate(0, mNumCapacity, newNumElements); mNumElements = newNumElements; DoUninitializedCopyFromTupleArray(begin(), end(), first); diff --git a/include/EASTL/deque.h b/include/EASTL/deque.h index 9a812c9c..c8da31c0 100644 --- a/include/EASTL/deque.h +++ b/include/EASTL/deque.h @@ -237,10 +237,10 @@ namespace eastl DequeIterator(const iterator& x, Increment); DequeIterator(const iterator& x, Decrement); - this_type copy(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait has_trivial_relocate, + this_type copy(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait is_trivially_copyable, this_type copy(const iterator& first, const iterator& last, false_type); // false means it does not. - void copy_backward(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait has_trivial_relocate, + void copy_backward(const iterator& first, const iterator& last, true_type); // true means that value_type has the type_trait is_trivially_copyable, void copy_backward(const iterator& first, const iterator& last, false_type); // false means it does not. void SetSubarray(T** pCurrentArrayPtr); @@ -275,13 +275,13 @@ namespace eastl //kNodeSize = kDequeSubarraySize * sizeof(T) /// Disabled because it prevents the ability to do this: struct X{ eastl::deque mDequeOfSelf; }; }; + protected: enum Side /// Defines the side of the deque: front or back. { kSideFront, /// Identifies the front side of the deque. kSideBack /// Identifies the back side of the deque. }; - protected: T** mpPtrArray; // Array of pointers to subarrays. size_type mnPtrArraySize; // Possibly we should store this as T** mpArrayEnd. iterator mItBegin; // Where within the subarrays is our beginning. @@ -352,6 +352,14 @@ namespace eastl typedef typename base_type::difference_type difference_type; typedef typename base_type::allocator_type allocator_type; + using base_type::npos; + +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + static_assert(!is_const::value, "deque::value_type must be non-const."); + static_assert(!is_volatile::value, "deque::value_type must be non-volatile."); +#endif + + protected: using base_type::kSideFront; using base_type::kSideBack; using base_type::mpPtrArray; @@ -359,7 +367,6 @@ namespace eastl using base_type::mItBegin; using base_type::mItEnd; using base_type::mAllocator; - using base_type::npos; using base_type::DoAllocateSubarray; using base_type::DoFreeSubarray; using base_type::DoFreeSubarrays; @@ -378,6 +385,8 @@ namespace eastl deque(this_type&& x, const allocator_type& allocator); deque(std::initializer_list ilist, const allocator_type& allocator = EASTL_DEQUE_DEFAULT_ALLOCATOR); + // note: this has pre-C++11 semantics: + // this constructor is equivalent to the constructor deque(static_cast(first), static_cast(last)) if InputIterator is an integral type. template deque(InputIterator first, InputIterator last); // allocator arg removed because VC7.1 fails on the default arg. To do: Make a second version of this function without a default arg. @@ -455,11 +464,14 @@ namespace eastl iterator insert(const_iterator position, const value_type& value); iterator insert(const_iterator position, value_type&& value); - void insert(const_iterator position, size_type n, const value_type& value); + iterator insert(const_iterator position, size_type n, const value_type& value); iterator insert(const_iterator position, std::initializer_list ilist); + // note: this has pre-C++11 semantics: + // this function is equivalent to insert(const_iterator position, static_cast(first), static_cast(last)) if InputIterator is an integral type. + // ie. same as insert(const_iterator position, size_type n, const value_type& value) template - void insert(const_iterator position, InputIterator first, InputIterator last); + iterator insert(const_iterator position, InputIterator first, InputIterator last); iterator erase(const_iterator position); iterator erase(const_iterator first, const_iterator last); @@ -496,15 +508,18 @@ namespace eastl void DoAssignValues(size_type n, const value_type& value); template - void DoInsert(const const_iterator& position, Integer n, Integer value, true_type); + iterator DoInsert(const const_iterator& position, Integer n, Integer value, true_type); template - void DoInsert(const const_iterator& position, const InputIterator& first, const InputIterator& last, false_type); + iterator DoInsert(const const_iterator& position, const InputIterator& first, const InputIterator& last, false_type); template - void DoInsertFromIterator(const_iterator position, const InputIterator& first, const InputIterator& last, EASTL_ITC_NS::forward_iterator_tag); + iterator DoInsertFromIterator(const_iterator position, const InputIterator& first, const InputIterator& last, EASTL_ITC_NS::input_iterator_tag); - void DoInsertValues(const_iterator position, size_type n, const value_type& value); + template + iterator DoInsertFromIterator(const_iterator position, const ForwardIterator& first, const ForwardIterator& last, EASTL_ITC_NS::forward_iterator_tag); + + iterator DoInsertValues(const_iterator position, size_type n, const value_type& value); void DoSwap(this_type& x); }; // class deque @@ -1791,7 +1806,7 @@ namespace eastl iterator oldBegin (mItBegin, typename iterator::Increment()); const iterator oldBeginPlus1(oldBegin, typename iterator::Increment()); - oldBegin.copy(oldBeginPlus1, newPosition, eastl::has_trivial_relocate()); + oldBegin.copy(oldBeginPlus1, newPosition, eastl::is_trivially_copyable()); } else { @@ -1802,7 +1817,7 @@ namespace eastl iterator oldBack (mItEnd, typename iterator::Decrement()); const iterator oldBackMinus1(oldBack, typename iterator::Decrement()); - oldBack.copy_backward(itPosition, oldBackMinus1, eastl::has_trivial_relocate()); + oldBack.copy_backward(itPosition, oldBackMinus1, eastl::is_trivially_copyable()); } *itPosition = eastl::move(valueSaved); @@ -1897,17 +1912,19 @@ namespace eastl template - void deque::insert(const_iterator position, size_type n, const value_type& value) + typename deque::iterator + deque::insert(const_iterator position, size_type n, const value_type& value) { - DoInsertValues(position, n, value); + return DoInsertValues(position, n, value); } template template - void deque::insert(const_iterator position, InputIterator first, InputIterator last) + typename deque::iterator + deque::insert(const_iterator position, InputIterator first, InputIterator last) { - DoInsert(position, first, last, is_integral()); // The C++ standard requires this sort of behaviour, as InputIterator might actually be Integer and 'first' is really 'count' and 'last' is really 'value'. + return DoInsert(position, first, last, is_integral()); // The C++ standard requires this sort of behaviour, as InputIterator might actually be Integer and 'first' is really 'count' and 'last' is really 'value'. } @@ -1939,12 +1956,12 @@ namespace eastl if(i < (difference_type)(size() / 2)) // Should we move the front entries forward or the back entries backward? We divide the range in half. { - itNext.copy_backward(mItBegin, itPosition, eastl::has_trivial_relocate()); + itNext.copy_backward(mItBegin, itPosition, eastl::is_trivially_copyable()); pop_front(); } else { - itPosition.copy(itNext, mItEnd, eastl::has_trivial_relocate()); + itPosition.copy(itNext, mItEnd, eastl::is_trivially_copyable()); pop_back(); } @@ -1976,7 +1993,7 @@ namespace eastl const iterator itNewBegin(mItBegin + n); value_type** const pPtrArrayBegin = mItBegin.mpCurrentArrayPtr; - itLast.copy_backward(mItBegin, itFirst, eastl::has_trivial_relocate()); + itLast.copy_backward(mItBegin, itFirst, eastl::is_trivially_copyable()); for(; mItBegin != itNewBegin; ++mItBegin) // Question: If value_type is a POD type, will the compiler generate this loop at all? mItBegin.mpCurrent->~value_type(); // If so, then we need to make a specialization for destructing PODs. @@ -1990,7 +2007,7 @@ namespace eastl iterator itNewEnd(mItEnd - n); value_type** const pPtrArrayEnd = itNewEnd.mpCurrentArrayPtr + 1; - itFirst.copy(itLast, mItEnd, eastl::has_trivial_relocate()); + itFirst.copy(itLast, mItEnd, eastl::is_trivially_copyable()); for(iterator itTemp(itNewEnd); itTemp != mItEnd; ++itTemp) itTemp.mpCurrent->~value_type(); @@ -2136,9 +2153,9 @@ namespace eastl try { #endif - // We have little choice but to turn through the source iterator and call + // We have little choice but to iterate through the source iterator and call // push_back for each item. It can be slow because it will keep reallocating the - // container memory as we go. We are not allowed to use distance() on an InputIterator. + // container memory as we go (every kDequeSubarraySize elements). We are not allowed to use distance() on an InputIterator. for(; first != last; ++first) // InputIterators by definition actually only allow you to iterate through them once. { // Thus the standard *requires* that we do this (inefficient) implementation. push_back(*first); // Luckily, InputIterators are in practice almost never used, so this code will likely never get executed. @@ -2172,8 +2189,9 @@ namespace eastl #endif for(pPtrArrayCurrent = mItBegin.mpCurrentArrayPtr; pPtrArrayCurrent < mItEnd.mpCurrentArrayPtr; ++pPtrArrayCurrent) // Copy to the known-to-be-completely-used subarrays. { - // We implment an algorithm here whereby we use uninitialized_copy() and advance() instead of just iterating from first to last and constructing as we go. The reason for this is that we can take advantage of POD data types and implement construction as memcpy operations. - ForwardIterator current(first); // To do: Implement a specialization of this algorithm for non-PODs which eliminates the need for 'current'. + // We implment an algorithm here whereby we use uninitialized_copy() and advance() instead of just iterating from first to last and constructing as we go. + // The reason for this is that we can take advantage of trivially copyable data types and implement construction as memcpy operations. + ForwardIterator current(first); // To do: Implement a specialization of this algorithm for non-trivially copyable types which eliminates the need for 'current'. eastl::advance(current, kDequeSubarraySize); eastl::uninitialized_copy((non_const_iterator_type)first, (non_const_iterator_type)current, (non_const_value_type*)*pPtrArrayCurrent); @@ -2275,24 +2293,60 @@ namespace eastl template template - void deque::DoInsert(const const_iterator& position, Integer n, Integer value, true_type) + typename deque::iterator + deque::DoInsert(const const_iterator& position, Integer n, Integer value, true_type) { - DoInsertValues(position, (size_type)n, (value_type)value); + return DoInsertValues(position, (size_type)n, (value_type)value); } template template - void deque::DoInsert(const const_iterator& position, const InputIterator& first, const InputIterator& last, false_type) + typename deque::iterator + deque::DoInsert(const const_iterator& position, const InputIterator& first, const InputIterator& last, false_type) { typedef typename eastl::iterator_traits::iterator_category IC; - DoInsertFromIterator(position, first, last, IC()); + return DoInsertFromIterator(position, first, last, IC()); } - template template - void deque::DoInsertFromIterator(const_iterator position, const InputIterator& first, const InputIterator& last, EASTL_ITC_NS::forward_iterator_tag) + typename deque::iterator + deque::DoInsertFromIterator(const_iterator position, const InputIterator& first, const InputIterator& last, EASTL_ITC_NS::input_iterator_tag) + { + const difference_type index = eastl::distance(cbegin(), position); +#if EASTL_EXCEPTIONS_ENABLED + try + { +#endif + // We have little choice but to iterate through the source iterator and call + // insert for each item. It can be slow because it will keep reallocating the + // container memory as we go (every kDequeSubarraySize elements). We are not + // allowed to use distance() on an InputIterator. InputIterators by definition + // actually only allow you to iterate through them once. Thus the standard + // *requires* that we do this (inefficient) implementation. Luckily, + // InputIterators are in practice almost never used, so this code will likely + // never get executed. + for (InputIterator iter = first; iter != last; ++iter) + { + position = insert(position, *iter) + 1; + } +#if EASTL_EXCEPTIONS_ENABLED + } + catch (...) + { + erase(cbegin() + index, position); + throw; + } +#endif + + return begin() + index; + } + + template + template + typename deque::iterator + deque::DoInsertFromIterator(const_iterator position, const ForwardIterator& first, const ForwardIterator& last, EASTL_ITC_NS::forward_iterator_tag) { const size_type n = (size_type)eastl::distance(first, last); @@ -2319,10 +2373,13 @@ namespace eastl throw; } #endif + + return mItBegin; } else if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If inserting at the end (i.e. appending)... { const iterator itNewEnd(DoReallocSubarray(n, kSideBack)); // mItEnd to itNewEnd refers to memory that isn't initialized yet; so it's not truly a valid iterator. Or at least not a dereferencable one. + const iterator itFirstInserted(mItEnd); #if EASTL_EXCEPTIONS_ENABLED try @@ -2341,6 +2398,8 @@ namespace eastl throw; } #endif + + return itFirstInserted; } else { @@ -2370,7 +2429,7 @@ namespace eastl } else // Else the newly inserted items are going within the newly allocated area at the front. { - InputIterator mid(first); + ForwardIterator mid(first); eastl::advance(mid, (difference_type)n - nInsertionIndex); eastl::uninitialized_copy_copy(mItBegin, itPosition, first, mid, itNewBegin); // This can throw. @@ -2410,7 +2469,7 @@ namespace eastl } else { - InputIterator mid(first); + ForwardIterator mid(first); eastl::advance(mid, nPushedCount); eastl::uninitialized_copy_copy(mid, last, itPosition, mItEnd, mItEnd); @@ -2426,12 +2485,15 @@ namespace eastl } #endif } + + return iterator(mItBegin + nInsertionIndex); } } template - void deque::DoInsertValues(const_iterator position, size_type n, const value_type& value) + typename deque::iterator + deque::DoInsertValues(const_iterator position, size_type n, const value_type& value) { #if EASTL_ASSERT_ENABLED if(EASTL_UNLIKELY(!(validate_iterator(position) & isf_valid))) @@ -2461,10 +2523,13 @@ namespace eastl throw; } #endif + + return mItBegin; } else if(EASTL_UNLIKELY(position.mpCurrent == mItEnd.mpCurrent)) // If inserting at the end (i.e. appending)... { const iterator itNewEnd(DoReallocSubarray(n, kSideBack)); + const iterator itFirstInserted(mItEnd); #if EASTL_EXCEPTIONS_ENABLED try @@ -2483,6 +2548,8 @@ namespace eastl throw; } #endif + + return itFirstInserted; } else { @@ -2528,6 +2595,8 @@ namespace eastl throw; } #endif + + return iterator(mItBegin + nInsertionIndex); } else // Else the insertion index is in the back half of the deque, so grow the deque at the back. { @@ -2562,6 +2631,8 @@ namespace eastl throw; } #endif + + return iterator(mItBegin + nInsertionIndex); } } } diff --git a/include/EASTL/fixed_hash_map.h b/include/EASTL/fixed_hash_map.h index b94ea541..c8087c18 100644 --- a/include/EASTL/fixed_hash_map.h +++ b/include/EASTL/fixed_hash_map.h @@ -95,10 +95,11 @@ namespace eastl enum { kMaxSize = nodeCount }; - using base_type::mAllocator; using base_type::clear; protected: + using base_type::mAllocator; + node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket. char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. @@ -186,10 +187,11 @@ namespace eastl enum { kMaxSize = nodeCount }; - using base_type::mAllocator; using base_type::clear; protected: + using base_type::mAllocator; + node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket. char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. @@ -330,7 +332,7 @@ namespace eastl inline fixed_hash_map:: fixed_hash_map(const this_type& x) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer)) { mAllocator.copy_overflow_allocator(x.mAllocator); @@ -352,7 +354,7 @@ namespace eastl inline fixed_hash_map:: fixed_hash_map(this_type&& x) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer)) { // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. mAllocator.copy_overflow_allocator(x.mAllocator); @@ -375,7 +377,7 @@ namespace eastl inline fixed_hash_map:: fixed_hash_map(this_type&& x, const overflow_allocator_type& overflowAllocator) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) { // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. mAllocator.copy_overflow_allocator(x.mAllocator); @@ -617,7 +619,7 @@ namespace eastl inline fixed_hash_multimap:: fixed_hash_multimap(const this_type& x) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(),fixed_allocator_type(NULL, mBucketBuffer)) + x.key_eq(),fixed_allocator_type(NULL, mBucketBuffer)) { mAllocator.copy_overflow_allocator(x.mAllocator); @@ -639,7 +641,7 @@ namespace eastl inline fixed_hash_multimap:: fixed_hash_multimap(this_type&& x) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(),fixed_allocator_type(NULL, mBucketBuffer)) + x.key_eq(),fixed_allocator_type(NULL, mBucketBuffer)) { // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. mAllocator.copy_overflow_allocator(x.mAllocator); @@ -662,7 +664,7 @@ namespace eastl inline fixed_hash_multimap:: fixed_hash_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) { // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. mAllocator.copy_overflow_allocator(x.mAllocator); diff --git a/include/EASTL/fixed_hash_set.h b/include/EASTL/fixed_hash_set.h index fa2783ad..1b259600 100644 --- a/include/EASTL/fixed_hash_set.h +++ b/include/EASTL/fixed_hash_set.h @@ -95,9 +95,9 @@ namespace eastl enum { kMaxSize = nodeCount }; + protected: using base_type::mAllocator; - protected: node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket. char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. @@ -183,9 +183,9 @@ namespace eastl enum { kMaxSize = nodeCount }; + protected: using base_type::mAllocator; - protected: node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket. char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements. @@ -325,7 +325,7 @@ namespace eastl inline fixed_hash_set:: fixed_hash_set(const this_type& x) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer)) { mAllocator.copy_overflow_allocator(x.mAllocator); @@ -346,7 +346,7 @@ namespace eastl template inline fixed_hash_set::fixed_hash_set(this_type&& x) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer)) { // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. mAllocator.copy_overflow_allocator(x.mAllocator); @@ -368,7 +368,7 @@ namespace eastl template inline fixed_hash_set::fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), - x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + x.hash_function(), x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) { // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. mAllocator.copy_overflow_allocator(x.mAllocator); @@ -598,7 +598,7 @@ namespace eastl inline fixed_hash_multiset:: fixed_hash_multiset(const this_type& x) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer)) { mAllocator.copy_overflow_allocator(x.mAllocator); @@ -619,7 +619,7 @@ namespace eastl template inline fixed_hash_multiset::fixed_hash_multiset(this_type&& x) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(), - x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer)) + x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer)) { // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. mAllocator.copy_overflow_allocator(x.mAllocator); @@ -641,7 +641,7 @@ namespace eastl template inline fixed_hash_multiset::fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator) : base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), - x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) + x.hash_function(), x.key_eq(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator)) { // This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here. mAllocator.copy_overflow_allocator(x.mAllocator); diff --git a/include/EASTL/fixed_string.h b/include/EASTL/fixed_string.h index f646302b..68e5eea5 100644 --- a/include/EASTL/fixed_string.h +++ b/include/EASTL/fixed_string.h @@ -88,19 +88,20 @@ namespace eastl enum { kMaxSize = nodeCount - 1 }; // -1 because we need to save one element for the silent terminating null. using base_type::npos; - using base_type::mPair; using base_type::append; using base_type::resize; using base_type::clear; using base_type::capacity; using base_type::size; using base_type::sprintf_va_list; + using base_type::get_allocator; + + protected: + using base_type::mPair; using base_type::DoAllocate; using base_type::DoFree; using base_type::internalLayout; - using base_type::get_allocator; - protected: union // We define a union in order to avoid strict pointer aliasing issues with compilers like GCC. { value_type mArray[1]; @@ -672,6 +673,24 @@ namespace eastl get_allocator().set_overflow_allocator(allocator); } + template + inline size_t hash_string(const T* p) + { + unsigned int c, result = 2166136261U; + while ((c = *p++) != 0) // To consider: limit p to at most 256 chars. + result = (result * 16777619) ^ c; + return (size_t)result; + } + + template + struct hash> + { + size_t operator()(const fixed_string& x) const + { + return hash_string(x.c_str()); + } + }; + /////////////////////////////////////////////////////////////////////// // global operators diff --git a/include/EASTL/fixed_substring.h b/include/EASTL/fixed_substring.h index e186cfc1..5ff51368 100644 --- a/include/EASTL/fixed_substring.h +++ b/include/EASTL/fixed_substring.h @@ -87,12 +87,12 @@ namespace eastl typedef typename base_type::const_iterator const_iterator; using base_type::npos; - using base_type::mPair; - using base_type::AllocateSelf; - using base_type::internalLayout; using base_type::get_allocator; private: + using base_type::mPair; + using base_type::AllocateSelf; + using base_type::internalLayout; void SetInternalHeapLayout(value_type* pBeginPtr, size_type nSize, size_type nCap) { diff --git a/include/EASTL/fixed_vector.h b/include/EASTL/fixed_vector.h index 1dc482bd..1fd2c61f 100644 --- a/include/EASTL/fixed_vector.h +++ b/include/EASTL/fixed_vector.h @@ -67,7 +67,7 @@ namespace eastl /// fixedVector.resize(200); /// fixedVector.clear(); /// - template ::type> + template ::type> class fixed_vector : public vector > { public: @@ -86,22 +86,27 @@ namespace eastl enum { kMaxSize = nodeCount }; using base_type::get_allocator; - using base_type::mpBegin; - using base_type::mpEnd; - using base_type::internalCapacityPtr; using base_type::resize; using base_type::clear; using base_type::size; using base_type::assign; using base_type::npos; - using base_type::DoAllocate; - using base_type::DoFree; - using base_type::DoAssign; - using base_type::DoAssignFromIterator; + +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + static_assert(!is_const::value, "fixed_vector value_type must be non-const."); + static_assert(!is_volatile::value, "fixed_vector value_type must be non-volatile."); +#endif protected: aligned_buffer_type mBuffer; + using base_type::mpBegin; + using base_type::mpEnd; + using base_type::internalCapacityPtr; + using base_type::DoAllocate; + using base_type::DoFree; + using base_type::DoAssign; + public: fixed_vector(); explicit fixed_vector(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true. @@ -468,7 +473,7 @@ namespace eastl template inline void* fixed_vector::push_back_uninitialized() { - return DoPushBackUninitialized(typename type_select::type()); + return DoPushBackUninitialized(typename conditional::type()); } @@ -491,7 +496,7 @@ namespace eastl template inline void fixed_vector::push_back(const value_type& value) { - DoPushBack(typename type_select::type(), value); + DoPushBack(typename conditional::type(), value); } @@ -516,7 +521,7 @@ namespace eastl template inline typename fixed_vector::reference fixed_vector::push_back() { - return DoPushBack(typename type_select::type()); + return DoPushBack(typename conditional::type()); } @@ -543,7 +548,7 @@ namespace eastl template inline void fixed_vector::push_back(value_type&& value) { - DoPushBackMove(typename type_select::type(), eastl::move(value)); + DoPushBackMove(typename conditional::type(), eastl::move(value)); } diff --git a/include/EASTL/functional.h b/include/EASTL/functional.h index 6fa34893..a39778b7 100644 --- a/include/EASTL/functional.h +++ b/include/EASTL/functional.h @@ -27,7 +27,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////// template - struct plus : public binary_function + struct plus { EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const { return a + b; } @@ -45,7 +45,7 @@ namespace eastl }; template - struct minus : public binary_function + struct minus { EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const { return a - b; } @@ -63,7 +63,7 @@ namespace eastl }; template - struct multiplies : public binary_function + struct multiplies { EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const { return a * b; } @@ -81,7 +81,7 @@ namespace eastl }; template - struct divides : public binary_function + struct divides { EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const { return a / b; } @@ -99,7 +99,7 @@ namespace eastl }; template - struct modulus : public binary_function + struct modulus { EA_CPP14_CONSTEXPR T operator()(const T& a, const T& b) const { return a % b; } @@ -117,7 +117,7 @@ namespace eastl }; template - struct negate : public unary_function + struct negate { EA_CPP14_CONSTEXPR T operator()(const T& a) const { return -a; } @@ -135,7 +135,7 @@ namespace eastl }; template - struct equal_to : public binary_function + struct equal_to { EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const { return a == b; } @@ -159,7 +159,7 @@ namespace eastl } template - struct not_equal_to : public binary_function + struct not_equal_to { EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const { return a != b; } @@ -201,7 +201,7 @@ namespace eastl /// such as that used in the EAStdC Strcmp function. /// template - struct str_equal_to : public binary_function + struct str_equal_to { EA_CPP14_CONSTEXPR bool operator()(T a, T b) const { @@ -215,7 +215,7 @@ namespace eastl }; template - struct greater : public binary_function + struct greater { EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const { return a > b; } @@ -260,7 +260,7 @@ namespace eastl /// such as that used in the EAStdC Strcmp function. /// template - struct str_less : public binary_function + struct str_less { bool operator()(T a, T b) const { @@ -287,7 +287,7 @@ namespace eastl }; template - struct greater_equal : public binary_function + struct greater_equal { EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const { return a >= b; } @@ -310,7 +310,7 @@ namespace eastl } template - struct less_equal : public binary_function + struct less_equal { EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const { return a <= b; } @@ -333,7 +333,7 @@ namespace eastl } template - struct logical_and : public binary_function + struct logical_and { EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const { return a && b; } @@ -350,7 +350,7 @@ namespace eastl }; template - struct logical_or : public binary_function + struct logical_or { EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const { return a || b; } @@ -367,7 +367,7 @@ namespace eastl }; template - struct logical_not : public unary_function + struct logical_not { EA_CPP14_CONSTEXPR bool operator()(const T& a) const { return !a; } @@ -390,8 +390,9 @@ namespace eastl /////////////////////////////////////////////////////////////////////// + // deprecated. consider using the specialization equal_to<> instead. template - struct equal_to_2 : public binary_function + struct EASTL_REMOVE_AT_2024_APRIL equal_to_2 { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a == b; } @@ -402,7 +403,7 @@ namespace eastl }; template - struct not_equal_to_2 : public binary_function + struct EASTL_REMOVE_AT_2024_APRIL not_equal_to_2 { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a != b; } @@ -414,7 +415,7 @@ namespace eastl template - struct less_2 : public binary_function + struct EASTL_REMOVE_AT_2024_APRIL less_2 { EA_CPP14_CONSTEXPR bool operator()(const T& a, const U& b) const { return a < b; } @@ -424,11 +425,12 @@ namespace eastl { return b < a; } }; + EASTL_INTERNAL_DISABLE_DEPRECATED() // '*': was declared deprecated /// unary_negate /// template - class unary_negate : public unary_function + class EASTL_REMOVE_AT_2024_APRIL unary_negate { protected: Predicate mPredicate; @@ -440,7 +442,7 @@ namespace eastl }; template - inline EA_CPP14_CONSTEXPR unary_negate not1(const Predicate& predicate) + EASTL_REMOVE_AT_2024_APRIL inline EA_CPP14_CONSTEXPR unary_negate not1(const Predicate& predicate) { return unary_negate(predicate); } @@ -448,7 +450,7 @@ namespace eastl /// binary_negate /// template - class binary_negate : public binary_function + class EASTL_REMOVE_AT_2024_APRIL binary_negate { protected: Predicate mPredicate; @@ -460,7 +462,7 @@ namespace eastl }; template - inline EA_CPP14_CONSTEXPR binary_negate not2(const Predicate& predicate) + EASTL_REMOVE_AT_2024_APRIL inline EA_CPP14_CONSTEXPR binary_negate not2(const Predicate& predicate) { return binary_negate(predicate); } @@ -468,7 +470,7 @@ namespace eastl /// unary_compose /// template - struct unary_compose : public unary_function + struct EASTL_REMOVE_AT_2024_APRIL unary_compose { protected: Operation1 op1; @@ -486,17 +488,16 @@ namespace eastl }; template - inline unary_compose + EASTL_REMOVE_AT_2024_APRIL inline unary_compose compose1(const Operation1& op1, const Operation2& op2) { return unary_compose(op1,op2); } - /// binary_compose /// template - class binary_compose : public unary_function + class EASTL_REMOVE_AT_2024_APRIL binary_compose { protected: Operation1 op1; @@ -526,7 +527,7 @@ namespace eastl template - inline binary_compose + EASTL_REMOVE_AT_2024_APRIL inline binary_compose compose2(const Operation1& op1, const Operation2& op2, const Operation3& op3) { return binary_compose(op1, op2, op3); @@ -550,7 +551,8 @@ namespace eastl /// random_shuffle(pArrayBegin, pArrayEnd, randInstance); /// template - class pointer_to_unary_function : public unary_function + class EASTL_REMOVE_AT_2024_APRIL pointer_to_unary_function + : public unary_function { protected: Result (*mpFunction)(Arg); @@ -576,8 +578,8 @@ namespace eastl /// transform(pIntArrayBegin, pIntArrayEnd, pIntArrayBegin, ptr_fun(factorial)); /// template - inline pointer_to_unary_function - ptr_fun(Result (*pFunction)(Arg)) + EASTL_REMOVE_AT_2024_APRIL inline pointer_to_unary_function + ptr_fun(Result (*pFunction)(Arg)) { return pointer_to_unary_function(pFunction); } @@ -595,7 +597,8 @@ namespace eastl /// work in many cases where the system requires a function object. /// template - class pointer_to_binary_function : public binary_function + class EASTL_REMOVE_AT_2024_APRIL pointer_to_binary_function + : public binary_function { protected: Result (*mpFunction)(Arg1, Arg2); @@ -619,7 +622,7 @@ namespace eastl /// transform(pIntArray1Begin, pIntArray1End, pIntArray2Begin, pIntArray1Begin, ptr_fun(multiply)); /// template - inline pointer_to_binary_function + EASTL_REMOVE_AT_2024_APRIL inline pointer_to_binary_function ptr_fun(Result (*pFunction)(Arg1, Arg2)) { return pointer_to_binary_function(pFunction); } @@ -647,7 +650,8 @@ namespace eastl /// Member function with no arguments. /// template - class mem_fun_t : public unary_function + class EASTL_REMOVE_AT_2024_APRIL mem_fun_t + : public unary_function { public: typedef Result (T::*MemberFunction)(); @@ -673,7 +677,8 @@ namespace eastl /// Member function with one argument. /// template - class mem_fun1_t : public binary_function + class EASTL_REMOVE_AT_2024_APRIL mem_fun1_t + : public binary_function { public: typedef Result (T::*MemberFunction)(Argument); @@ -702,7 +707,8 @@ namespace eastl /// The C++ standard is in error and this has been recognized by the defect group. /// template - class const_mem_fun_t : public unary_function + class EASTL_REMOVE_AT_2024_APRIL const_mem_fun_t + : public unary_function { public: typedef Result (T::*MemberFunction)() const; @@ -731,7 +737,8 @@ namespace eastl /// The C++ standard is in error and this has been recognized by the defect group. /// template - class const_mem_fun1_t : public binary_function + class EASTL_REMOVE_AT_2024_APRIL const_mem_fun1_t + : public binary_function { public: typedef Result (T::*MemberFunction)(Argument) const; @@ -764,28 +771,28 @@ namespace eastl /// Note: using conventional inlining here to avoid issues on GCC/Linux /// template - inline mem_fun_t + EASTL_REMOVE_AT_2024_APRIL inline mem_fun_t mem_fun(Result (T::*MemberFunction)()) { return eastl::mem_fun_t(MemberFunction); } template - inline mem_fun1_t + EASTL_REMOVE_AT_2024_APRIL inline mem_fun1_t mem_fun(Result (T::*MemberFunction)(Argument)) { return eastl::mem_fun1_t(MemberFunction); } template - inline const_mem_fun_t + EASTL_REMOVE_AT_2024_APRIL inline const_mem_fun_t mem_fun(Result (T::*MemberFunction)() const) { return eastl::const_mem_fun_t(MemberFunction); } template - inline const_mem_fun1_t + EASTL_REMOVE_AT_2024_APRIL inline const_mem_fun1_t mem_fun(Result (T::*MemberFunction)(Argument) const) { return eastl::const_mem_fun1_t(MemberFunction); @@ -804,7 +811,8 @@ namespace eastl /// mem_fun_ref_t /// template - class mem_fun_ref_t : public unary_function + class EASTL_REMOVE_AT_2024_APRIL mem_fun_ref_t + : public unary_function { public: typedef Result (T::*MemberFunction)(); @@ -828,7 +836,8 @@ namespace eastl /// mem_fun1_ref_t /// template - class mem_fun1_ref_t : public binary_function + class EASTL_REMOVE_AT_2024_APRIL mem_fun1_ref_t + : public binary_function { public: typedef Result (T::*MemberFunction)(Argument); @@ -852,7 +861,8 @@ namespace eastl /// const_mem_fun_ref_t /// template - class const_mem_fun_ref_t : public unary_function + class EASTL_REMOVE_AT_2024_APRIL const_mem_fun_ref_t + : public unary_function { public: typedef Result (T::*MemberFunction)() const; @@ -876,7 +886,8 @@ namespace eastl /// const_mem_fun1_ref_t /// template - class const_mem_fun1_ref_t : public binary_function + class EASTL_REMOVE_AT_2024_APRIL const_mem_fun1_ref_t + : public binary_function { public: typedef Result (T::*MemberFunction)(Argument) const; @@ -906,33 +917,34 @@ namespace eastl /// Note: using conventional inlining here to avoid issues on GCC/Linux /// template - inline mem_fun_ref_t + EASTL_REMOVE_AT_2024_APRIL inline mem_fun_ref_t mem_fun_ref(Result (T::*MemberFunction)()) { return eastl::mem_fun_ref_t(MemberFunction); } template - inline mem_fun1_ref_t + EASTL_REMOVE_AT_2024_APRIL inline mem_fun1_ref_t mem_fun_ref(Result (T::*MemberFunction)(Argument)) { return eastl::mem_fun1_ref_t(MemberFunction); } template - inline const_mem_fun_ref_t + EASTL_REMOVE_AT_2024_APRIL inline const_mem_fun_ref_t mem_fun_ref(Result (T::*MemberFunction)() const) { return eastl::const_mem_fun_ref_t(MemberFunction); } template - inline const_mem_fun1_ref_t + EASTL_REMOVE_AT_2024_APRIL inline const_mem_fun1_ref_t mem_fun_ref(Result (T::*MemberFunction)(Argument) const) { return eastl::const_mem_fun1_ref_t(MemberFunction); } + EASTL_INTERNAL_RESTORE_DEPRECATED() // not_fn_ret // not_fn_ret is a implementation specified return type of eastl::not_fn. @@ -1228,7 +1240,7 @@ namespace eastl { typedef String string_type; typedef typename String::value_type value_type; - typedef typename eastl::add_unsigned::type unsigned_value_type; + typedef typename eastl::make_unsigned::type unsigned_value_type; size_t operator()(const string_type& s) const { diff --git a/include/EASTL/hash_map.h b/include/EASTL/hash_map.h index e7cad7b0..91e7dad0 100644 --- a/include/EASTL/hash_map.h +++ b/include/EASTL/hash_map.h @@ -94,7 +94,7 @@ namespace eastl /// /// Example find_as usage (namespaces omitted for brevity): /// hash_map hashMap; - /// i = hashMap.find_as("hello", hash(), equal_to_2()); + /// i = hashMap.find_as("hello", hash(), equal_to<>()); /// template , typename Predicate = eastl::equal_to, typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false> diff --git a/include/EASTL/hash_set.h b/include/EASTL/hash_set.h index 3215d363..0b470dd2 100644 --- a/include/EASTL/hash_set.h +++ b/include/EASTL/hash_set.h @@ -94,7 +94,7 @@ namespace eastl /// /// Example find_as usage (namespaces omitted for brevity): /// hash_set hashSet; - /// i = hashSet.find_as("hello", hash(), equal_to_2()); + /// i = hashSet.find_as("hello", hash(), equal_to<>()); /// template , typename Predicate = eastl::equal_to, typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false> diff --git a/include/EASTL/heap.h b/include/EASTL/heap.h index a8e4260e..f0e770b9 100644 --- a/include/EASTL/heap.h +++ b/include/EASTL/heap.h @@ -55,7 +55,7 @@ namespace eastl inline void promote_heap_impl(RandomAccessIterator first, Distance topPosition, Distance position, T value) { for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>. - (position > topPosition) && eastl::less()(*(first + parentPosition), value); + (position > topPosition) && (*(first + parentPosition) < value); parentPosition = (position - 1) >> 1) { *(first + position) = eastl::forward(*(first + parentPosition)); // Swap the node with its parent. @@ -170,7 +170,7 @@ namespace eastl for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2) { - if(eastl::less()(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children. + if(*(first + childPosition) < *(first + (childPosition - 1))) // Choose the larger of the two children. --childPosition; *(first + position) = eastl::forward(*(first + childPosition)); // Swap positions with this child. position = childPosition; diff --git a/include/EASTL/internal/atomic/atomic.h b/include/EASTL/internal/atomic/atomic.h index eb27d2d9..7dcd10f7 100644 --- a/include/EASTL/internal/atomic/atomic.h +++ b/include/EASTL/internal/atomic/atomic.h @@ -48,9 +48,6 @@ */ -#include "atomic_push_compiler_options.h" - - namespace eastl { @@ -59,6 +56,17 @@ namespace internal { +// 'class' : multiple assignment operators specified +EA_DISABLE_VC_WARNING(4522); + +// misaligned atomic operation may incur significant performance penalty +// The above warning is emitted in earlier versions of clang incorrectly. +// All eastl::atomic objects are size aligned. +// This is static and runtime asserted. +// Thus we disable this warning. +EA_DISABLE_CLANG_WARNING(-Watomic-alignment); + + template struct is_atomic_lockfree_size { @@ -243,10 +251,10 @@ struct atomic : protected eastl::internal::atomic_pointer_width }; -} // namespace eastl - +EA_RESTORE_VC_WARNING(); -#include "atomic_pop_compiler_options.h" +EA_RESTORE_CLANG_WARNING(); +} // namespace eastl #endif /* EASTL_ATOMIC_INTERNAL_H */ diff --git a/include/EASTL/internal/atomic/atomic_base_width.h b/include/EASTL/internal/atomic/atomic_base_width.h index ac76097b..1a66d8ae 100644 --- a/include/EASTL/internal/atomic/atomic_base_width.h +++ b/include/EASTL/internal/atomic/atomic_base_width.h @@ -11,9 +11,6 @@ #endif -#include "atomic_push_compiler_options.h" - - namespace eastl { @@ -22,6 +19,17 @@ namespace internal { +// 'class' : multiple assignment operators specified +EA_DISABLE_VC_WARNING(4522); + +// misaligned atomic operation may incur significant performance penalty +// The above warning is emitted in earlier versions of clang incorrectly. +// All eastl::atomic objects are size aligned. +// This is static and runtime asserted. +// Thus we disable this warning. +EA_DISABLE_CLANG_WARNING(-Watomic-alignment); + + template struct atomic_base_width; @@ -333,14 +341,14 @@ namespace internal EASTL_ATOMIC_BASE_WIDTH_SPECIALIZE(16, 128) #endif +EA_RESTORE_VC_WARNING(); -} // namespace internal - +EA_RESTORE_CLANG_WARNING(); -} // namespace eastl +} // namespace internal -#include "atomic_pop_compiler_options.h" +} // namespace eastl #endif /* EASTL_ATOMIC_INTERNAL_BASE_WIDTH_H */ diff --git a/include/EASTL/internal/atomic/atomic_flag.h b/include/EASTL/internal/atomic/atomic_flag.h index eed448ae..6be2069f 100644 --- a/include/EASTL/internal/atomic/atomic_flag.h +++ b/include/EASTL/internal/atomic/atomic_flag.h @@ -11,13 +11,21 @@ #endif -#include "atomic_push_compiler_options.h" - - namespace eastl { +// 'class' : multiple assignment operators specified +EA_DISABLE_VC_WARNING(4522); + +// misaligned atomic operation may incur significant performance penalty +// The above warning is emitted in earlier versions of clang incorrectly. +// All eastl::atomic objects are size aligned. +// This is static and runtime asserted. +// Thus we disable this warning. +EA_DISABLE_CLANG_WARNING(-Watomic-alignment); + + class atomic_flag { public: /* ctors */ @@ -160,11 +168,11 @@ class atomic_flag eastl::atomic mFlag; }; +EA_RESTORE_VC_WARNING(); -} // namespace eastl - +EA_RESTORE_CLANG_WARNING(); -#include "atomic_pop_compiler_options.h" +} // namespace eastl #endif /* EASTL_ATOMIC_INTERNA_ATOMIC_FLAG_H */ diff --git a/include/EASTL/internal/atomic/atomic_integral.h b/include/EASTL/internal/atomic/atomic_integral.h index a9c96c79..8ec2ed74 100644 --- a/include/EASTL/internal/atomic/atomic_integral.h +++ b/include/EASTL/internal/atomic/atomic_integral.h @@ -11,9 +11,6 @@ #endif -#include "atomic_push_compiler_options.h" - - namespace eastl { @@ -22,6 +19,17 @@ namespace internal { +// 'class' : multiple assignment operators specified +EA_DISABLE_VC_WARNING(4522); + +// misaligned atomic operation may incur significant performance penalty +// The above warning is emitted in earlier versions of clang incorrectly. +// All eastl::atomic objects are size aligned. +// This is static and runtime asserted. +// Thus we disable this warning. +EA_DISABLE_CLANG_WARNING(-Watomic-alignment); + + #define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(funcName) \ template \ T funcName(T /*arg*/, Order /*order*/) EA_NOEXCEPT \ @@ -330,14 +338,14 @@ namespace internal EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128) #endif +EA_RESTORE_VC_WARNING(); -} // namespace internal - +EA_RESTORE_CLANG_WARNING(); -} // namespace eastl +} // namespace internal -#include "atomic_pop_compiler_options.h" +} // namespace eastl #endif /* EASTL_ATOMIC_INTERNAL_INTEGRAL_H */ diff --git a/include/EASTL/internal/atomic/atomic_pointer.h b/include/EASTL/internal/atomic/atomic_pointer.h index c0b19e66..279fa1ba 100644 --- a/include/EASTL/internal/atomic/atomic_pointer.h +++ b/include/EASTL/internal/atomic/atomic_pointer.h @@ -11,9 +11,6 @@ #endif -#include "atomic_push_compiler_options.h" - - namespace eastl { @@ -22,6 +19,17 @@ namespace internal { +// 'class' : multiple assignment operators specified +EA_DISABLE_VC_WARNING(4522); + +// misaligned atomic operation may incur significant performance penalty +// The above warning is emitted in earlier versions of clang incorrectly. +// All eastl::atomic objects are size aligned. +// This is static and runtime asserted. +// Thus we disable this warning. +EA_DISABLE_CLANG_WARNING(-Watomic-alignment); + + template struct atomic_pointer_base; @@ -268,14 +276,14 @@ namespace internal EASTL_ATOMIC_POINTER_WIDTH_SPECIALIZE(8, 64) #endif +EA_RESTORE_VC_WARNING(); -} // namespace internal - +EA_RESTORE_CLANG_WARNING(); -} // namespace eastl +} // namespace internal -#include "atomic_pop_compiler_options.h" +} // namespace eastl #endif /* EASTL_ATOMIC_INTERNAL_POINTER_H */ diff --git a/include/EASTL/internal/atomic/atomic_pop_compiler_options.h b/include/EASTL/internal/atomic/atomic_pop_compiler_options.h deleted file mode 100644 index 92f241a1..00000000 --- a/include/EASTL/internal/atomic/atomic_pop_compiler_options.h +++ /dev/null @@ -1,11 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -///////////////////////////////////////////////////////////////////////////// - - -/* NOTE: No Header Guard */ - - -EA_RESTORE_VC_WARNING(); - -EA_RESTORE_CLANG_WARNING(); diff --git a/include/EASTL/internal/atomic/atomic_push_compiler_options.h b/include/EASTL/internal/atomic/atomic_push_compiler_options.h deleted file mode 100644 index c5a54715..00000000 --- a/include/EASTL/internal/atomic/atomic_push_compiler_options.h +++ /dev/null @@ -1,17 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -///////////////////////////////////////////////////////////////////////////// - - -/* NOTE: No Header Guard */ - - -// 'class' : multiple assignment operators specified -EA_DISABLE_VC_WARNING(4522); - -// misaligned atomic operation may incur significant performance penalty -// The above warning is emitted in earlier versions of clang incorrectly. -// All eastl::atomic objects are size aligned. -// This is static and runtime asserted. -// Thus we disable this warning. -EA_DISABLE_CLANG_WARNING(-Watomic-alignment); diff --git a/include/EASTL/internal/atomic/atomic_size_aligned.h b/include/EASTL/internal/atomic/atomic_size_aligned.h index f5033758..c272335d 100644 --- a/include/EASTL/internal/atomic/atomic_size_aligned.h +++ b/include/EASTL/internal/atomic/atomic_size_aligned.h @@ -11,9 +11,6 @@ #endif -#include "atomic_push_compiler_options.h" - - namespace eastl { @@ -22,6 +19,17 @@ namespace internal { +// 'class' : multiple assignment operators specified +EA_DISABLE_VC_WARNING(4522); + +// misaligned atomic operation may incur significant performance penalty +// The above warning is emitted in earlier versions of clang incorrectly. +// All eastl::atomic objects are size aligned. +// This is static and runtime asserted. +// Thus we disable this warning. +EA_DISABLE_CLANG_WARNING(-Watomic-alignment); + + #define EASTL_ATOMIC_SIZE_ALIGNED_STATIC_ASSERT_CMPXCHG_IMPL(funcName) \ template \ bool funcName(T& /*expected*/, T /*desired*/, \ @@ -184,14 +192,14 @@ namespace internal EA_ALIGN(sizeof(T)) mutable T mAtomic; }; +EA_RESTORE_VC_WARNING(); -} // namespace internal - +EA_RESTORE_CLANG_WARNING(); -} // namespace eastl +} // namespace internal -#include "atomic_pop_compiler_options.h" +} // namespace eastl #endif /* EASTL_ATOMIC_INTERNAL_SIZE_ALIGNED_H */ diff --git a/include/EASTL/internal/char_traits.h b/include/EASTL/internal/char_traits.h index 62fe79b9..d6bb690d 100644 --- a/include/EASTL/internal/char_traits.h +++ b/include/EASTL/internal/char_traits.h @@ -230,7 +230,10 @@ namespace eastl inline int Compare(const char* p1, const char* p2, size_t n) { - return memcmp(p1, p2, n); + if (n > 0) + return memcmp(p1, p2, n); + else + return 0; } @@ -278,6 +281,7 @@ namespace eastl } + // If either pDestination or pSource is an invalid or null pointer, the behavior is undefined, even if (pSourceEnd - pSource) is zero. template inline T* CharStringUninitializedCopy(const T* pSource, const T* pSourceEnd, T* pDestination) { diff --git a/include/EASTL/internal/config.h b/include/EASTL/internal/config.h index 0564e18f..bf849dec 100644 --- a/include/EASTL/internal/config.h +++ b/include/EASTL/internal/config.h @@ -89,8 +89,8 @@ /////////////////////////////////////////////////////////////////////////////// #ifndef EASTL_VERSION - #define EASTL_VERSION "3.20.02" - #define EASTL_VERSION_N 32002 + #define EASTL_VERSION "3.21.12" + #define EASTL_VERSION_N 32112 #endif @@ -1051,24 +1051,6 @@ namespace eastl /////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// EASTL_LIST_PROXY_ENABLED -// -#if !defined(EASTL_LIST_PROXY_ENABLED) - // GCC with -fstrict-aliasing has bugs (or undocumented functionality in their - // __may_alias__ implementation. The compiler gets confused about function signatures. - // VC8 (1400) doesn't need the proxy because it has built-in smart debugging capabilities. - #if defined(EASTL_DEBUG) && !defined(__GNUC__) && (!defined(_MSC_VER) || (_MSC_VER < 1400)) - #define EASTL_LIST_PROXY_ENABLED 1 - #define EASTL_LIST_PROXY_MAY_ALIAS EASTL_MAY_ALIAS - #else - #define EASTL_LIST_PROXY_ENABLED 0 - #define EASTL_LIST_PROXY_MAY_ALIAS - #endif -#endif - - - /////////////////////////////////////////////////////////////////////////////// // EASTL_STD_ITERATOR_CATEGORY_ENABLED // @@ -1595,9 +1577,25 @@ namespace eastl #include #define EASTL_SIZE_T size_t #define EASTL_SSIZE_T intptr_t + + // printf format specifiers for use with eastl_size_t + #define EASTL_PRIdSIZE "zd" + #define EASTL_PRIiSIZE "zi" + #define EASTL_PRIoSIZE "zo" + #define EASTL_PRIuSIZE "zu" + #define EASTL_PRIxSIZE "zx" + #define EASTL_PRIXSIZE "zX" #else #define EASTL_SIZE_T uint32_t #define EASTL_SSIZE_T int32_t + + // printf format specifiers for use with eastl_size_t + #define EASTL_PRIdSIZE PRId32 + #define EASTL_PRIiSIZE PRIi32 + #define EASTL_PRIoSIZE PRIo32 + #define EASTL_PRIuSIZE PRIu32 + #define EASTL_PRIxSIZE PRIx32 + #define EASTL_PRIXSIZE PRIX32 #endif #endif @@ -1852,46 +1850,38 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept #define EASTL_OPTIONAL_ENABLED 0 #endif - -/// EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE -#if defined(__clang__) - // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11 - #if !__is_identifier(__has_unique_object_representations) - #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1 +/// EASTL_HAS_INTRINSIC(x) +/// does the compiler intrinsic (MSVC terminology) or builtin (Clang / GCC terminology) exist? +/// where `x` does not include the leading "__" +#if defined(EA_COMPILER_CLANG) + // see https://clang.llvm.org/docs/LanguageExtensions.html#type-trait-primitives + #if EA_COMPILER_VERSION >= 1000 + #define EASTL_HAS_INTRINSIC(x) EA_COMPILER_HAS_BUILTIN(__ ## x) + #elif EA_COMPILER_VERSION >= 600 + // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11 + #define EASTL_HAS_INTRINSIC(x) !__is_identifier(__ ## x) #else - #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0 + // note: only works for a subset of builtins + #define EASTL_HAS_INTRINSIC(x) EA_COMPILER_HAS_FEATURE(x) #endif -#elif defined(_MSC_VER) && (_MSC_VER >= 1913) // VS2017 15.6+ +#else +#define EASTL_HAS_INTRINSIC(x) EA_COMPILER_HAS_BUILTIN(__ ## x) +#endif + +/// EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE +#if EASTL_HAS_INTRINSIC(has_unique_object_representations) || (defined(_MSC_VER) && (_MSC_VER >= 1913)) // VS2017 15.6+ #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 1 #else #define EASTL_HAS_UNIQUE_OBJECT_REPRESENTATIONS_AVAILABLE 0 #endif -#if defined(__clang__) - // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11 - #if !__is_identifier(__is_final) - #define EASTL_IS_FINAL_AVAILABLE 1 - #else - #define EASTL_IS_FINAL_AVAILABLE 0 - #endif -#elif defined(_MSC_VER) && (_MSC_VER >= 1914) // VS2017 15.7+ - #define EASTL_IS_FINAL_AVAILABLE 1 -#elif defined(EA_COMPILER_GNUC) +#if EASTL_HAS_INTRINSIC(is_final) || defined(EA_COMPILER_GNUC) || (defined(_MSC_VER) && (_MSC_VER >= 1914)) // VS2017 15.7+ #define EASTL_IS_FINAL_AVAILABLE 1 #else #define EASTL_IS_FINAL_AVAILABLE 0 #endif -#if defined(__clang__) - // NB: !__is_identifier() is correct: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970#c11 - #if !__is_identifier(__is_aggregate) - #define EASTL_IS_AGGREGATE_AVAILABLE 1 - #else - #define EASTL_IS_AGGREGATE_AVAILABLE 0 - #endif -#elif defined(_MSC_VER) && (_MSC_VER >= 1915) // VS2017 15.8+ - #define EASTL_IS_AGGREGATE_AVAILABLE 1 -#elif defined(EA_COMPILER_GNUC) +#if EASTL_HAS_INTRINSIC(is_aggregate) || defined(EA_COMPILER_GNUC) || (defined(_MSC_VER) && (_MSC_VER >= 1915)) // VS2017 15.8+ #define EASTL_IS_AGGREGATE_AVAILABLE 1 #else #define EASTL_IS_AGGREGATE_AVAILABLE 0 @@ -1933,6 +1923,32 @@ typedef EASTL_SSIZE_T eastl_ssize_t; // Signed version of eastl_size_t. Concept #define EASTL_CONSTEXPR_BIT_CAST_SUPPORTED 0 #endif +// EASTL deprecation macros: +// +// EASTL_DEPRECATIONS_FOR_2024_APRIL +// This macro is provided as a means to disable warnings temporarily (in particular if a user is compiling with warnings as errors). +// All deprecations raised by this macro (when it is EA_ENABLED) are scheduled for removal approximately April 2024. + +#ifndef EASTL_DEPRECATIONS_FOR_2024_APRIL + #define EASTL_DEPRECATIONS_FOR_2024_APRIL EA_ENABLED +#endif + +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + #define EASTL_REMOVE_AT_2024_APRIL EA_DEPRECATED +#else + #define EASTL_REMOVE_AT_2024_APRIL +#endif + +// For internal (to EASTL) use only (ie. tests). +#define EASTL_INTERNAL_DISABLE_DEPRECATED() \ + EA_DISABLE_VC_WARNING(4996); \ + EA_DISABLE_CLANG_WARNING(-Wdeprecated-declarations); \ + EA_DISABLE_GCC_WARNING(-Wdeprecated-declarations); +// For internal (to EASTL) use only (ie. tests). +#define EASTL_INTERNAL_RESTORE_DEPRECATED() \ + EA_RESTORE_CLANG_WARNING(); \ + EA_RESTORE_VC_WARNING(); \ + EA_RESTORE_GCC_WARNING(); #endif // Header include guard diff --git a/include/EASTL/internal/copy_help.h b/include/EASTL/internal/copy_help.h index 0b2c1b83..0dab26bd 100644 --- a/include/EASTL/internal/copy_help.h +++ b/include/EASTL/internal/copy_help.h @@ -33,9 +33,12 @@ namespace eastl /// doesn't target overlapping memory and so memcpy would be usable. /// /// We can use memmove/memcpy if the following hold true: - /// InputIterator and OutputIterator are of the same type. + /// InputIterator and OutputIterator have the same value type. /// InputIterator and OutputIterator are of type contiguous_iterator_tag or simply are pointers (the two are virtually synonymous). - /// is_trivially_copyable::value is true. i.e. the constructor T(const T& t) (or T(T&& t) if present) can be replaced by memmove(this, &t, sizeof(T)) + /// is_trivially_copyable::value is true. i.e. from the standard (http://www.eel.is/c++draft/basic.types.general#2): + /// For any object (other than a potentially-overlapping subobject) of trivially copyable type T, whether or not the object + /// holds a valid value of type T, the underlying bytes making up the object can be copied into an array of char, unsigned char, + /// or std::byte [footnote: By using, for example, the library functions std::memcpy or std::memmove]. /// /// copy normally differs from move, but there is a case where copy is the same as move: when copy is /// used with a move_iterator. We handle that case here by detecting that copy is being done with a @@ -128,10 +131,10 @@ namespace eastl // is_same<> directly. #if !EASTL_STD_ITERATOR_CATEGORY_ENABLED || defined(EA_COMPILER_CPP20_ENABLED) template - using is_contiguous_iterator_helper = eastl::is_same; + using is_contiguous_iterator = eastl::is_same; #else template - using is_contiguous_iterator_helper = eastl::false_type; + using is_contiguous_iterator = eastl::false_type; #endif template @@ -143,8 +146,8 @@ namespace eastl static constexpr bool value = eastl::is_trivially_copyable::value && eastl::is_same::value && - (eastl::is_pointer::value || is_contiguous_iterator_helper::value) && - (eastl::is_pointer::value || is_contiguous_iterator_helper::value); + (eastl::is_pointer::value || is_contiguous_iterator::value) && + (eastl::is_pointer::value || is_contiguous_iterator::value); }; } diff --git a/include/EASTL/internal/fixed_pool.h b/include/EASTL/internal/fixed_pool.h index 61c05570..9f252d24 100644 --- a/include/EASTL/internal/fixed_pool.h +++ b/include/EASTL/internal/fixed_pool.h @@ -606,7 +606,7 @@ namespace eastl class fixed_node_allocator { public: - typedef typename type_select, fixed_pool>::type pool_type; + typedef typename conditional, fixed_pool>::type pool_type; typedef fixed_node_allocator this_type; typedef OverflowAllocator overflow_allocator_type; @@ -938,7 +938,7 @@ namespace eastl class fixed_hashtable_allocator { public: - typedef typename type_select, fixed_pool>::type pool_type; + typedef typename conditional, fixed_pool>::type pool_type; typedef fixed_hashtable_allocator this_type; typedef OverflowAllocator overflow_allocator_type; diff --git a/include/EASTL/internal/function.h b/include/EASTL/internal/function.h index ace71d87..b7b6ab69 100644 --- a/include/EASTL/internal/function.h +++ b/include/EASTL/internal/function.h @@ -158,6 +158,14 @@ namespace eastl lhs.swap(rhs); } +#ifdef __cpp_deduction_guides + template + function(ReturnType(*)(Args...)) -> function; + + template + function(Callable) -> function>; +#endif + } // namespace eastl #endif // EASTL_FUNCTION_H diff --git a/include/EASTL/internal/function_detail.h b/include/EASTL/internal/function_detail.h index 3ee36677..da3eb3eb 100644 --- a/include/EASTL/internal/function_detail.h +++ b/include/EASTL/internal/function_detail.h @@ -33,6 +33,36 @@ EA_RESTORE_ALL_VC_WARNINGS() #endif +#define EASTL_EMPTY_FUNCTION_QUALIFIER + +// https://en.cppreference.com/w/cpp/language/noexcept_spec +// The noexcept-specification is a part of the function type in C++17 and above, but not before. +#if defined(EA_COMPILER_CPP17_ENABLED) +#define EASTL_GENERATE_MEMBER_FUNCTION_NOEXCEPT_VARIANTS(PATTERN, OTHER_QUALIFIER) \ + PATTERN(OTHER_QUALIFIER EASTL_EMPTY_FUNCTION_QUALIFIER) \ + PATTERN(OTHER_QUALIFIER noexcept) +#else +#define EASTL_GENERATE_MEMBER_FUNCTION_NOEXCEPT_VARIANTS(PATTERN, OTHER_QUALIFIER) \ + PATTERN(OTHER_QUALIFIER EASTL_EMPTY_FUNCTION_QUALIFIER) +#endif + +#define EASTL_GENERATE_MEMBER_FUNCTION_REF_VARIANTS(PATTERN, OTHER_QUALIFIER) \ + EASTL_GENERATE_MEMBER_FUNCTION_NOEXCEPT_VARIANTS(PATTERN, OTHER_QUALIFIER EASTL_EMPTY_FUNCTION_QUALIFIER) \ + EASTL_GENERATE_MEMBER_FUNCTION_NOEXCEPT_VARIANTS(PATTERN, OTHER_QUALIFIER &) \ + EASTL_GENERATE_MEMBER_FUNCTION_NOEXCEPT_VARIANTS(PATTERN, OTHER_QUALIFIER &&) + +#define EASTL_GENERATE_MEMBER_FUNCTION_VOLATILE_VARIANTS(PATTERN, OTHER_QUALIFIER) \ + EASTL_GENERATE_MEMBER_FUNCTION_REF_VARIANTS(PATTERN, OTHER_QUALIFIER EASTL_EMPTY_FUNCTION_QUALIFIER) \ + EASTL_GENERATE_MEMBER_FUNCTION_REF_VARIANTS(PATTERN, OTHER_QUALIFIER volatile) + +#define EASTL_GENERATE_MEMBER_FUNCTION_CONST_VARIANTS(PATTERN) \ + EASTL_GENERATE_MEMBER_FUNCTION_VOLATILE_VARIANTS(PATTERN, EASTL_EMPTY_FUNCTION_QUALIFIER) \ + EASTL_GENERATE_MEMBER_FUNCTION_VOLATILE_VARIANTS(PATTERN, const) + +// Helper to generate all combination of qualifiers you can apply to member functions. +// PATTERN must be a macro that will receive as an argument a possible combination of qualifiers and generate a pattern from it. +#define EASTL_GENERATE_MEMBER_FUNCTION_VARIANTS(PATTERN) EASTL_GENERATE_MEMBER_FUNCTION_CONST_VARIANTS(PATTERN) + namespace eastl { #if EASTL_EXCEPTIONS_ENABLED @@ -666,8 +696,24 @@ namespace eastl InvokeFuncPtr mInvokeFuncPtr = &DefaultInvoker; }; - } // namespace internal + template + struct extract_signature_from_callable; + + #define EASTL_EXTRACT_SIGNATURE_PATTERN(QUALIFIERS) \ + template \ + struct extract_signature_from_callable \ + { \ + using type = ReturnType(Args...); \ + }; + + EASTL_GENERATE_MEMBER_FUNCTION_VARIANTS(EASTL_EXTRACT_SIGNATURE_PATTERN) + // Helper + template + using extract_signature_from_callable_t = typename extract_signature_from_callable::type; + + } // namespace internal + } // namespace eastl #endif // EASTL_FUNCTION_DETAIL_H diff --git a/include/EASTL/internal/functional_base.h b/include/EASTL/internal/functional_base.h index de446db1..366c1f75 100644 --- a/include/EASTL/internal/functional_base.h +++ b/include/EASTL/internal/functional_base.h @@ -181,25 +181,25 @@ namespace eastl template - struct unary_function + struct EASTL_REMOVE_AT_2024_APRIL unary_function { - typedef Argument argument_type; - typedef Result result_type; + EASTL_REMOVE_AT_2024_APRIL typedef Argument argument_type; + EASTL_REMOVE_AT_2024_APRIL typedef Result result_type; }; template - struct binary_function + struct EASTL_REMOVE_AT_2024_APRIL binary_function { - typedef Argument1 first_argument_type; - typedef Argument2 second_argument_type; - typedef Result result_type; + EASTL_REMOVE_AT_2024_APRIL typedef Argument1 first_argument_type; + EASTL_REMOVE_AT_2024_APRIL typedef Argument2 second_argument_type; + EASTL_REMOVE_AT_2024_APRIL typedef Result result_type; }; /// less template - struct less : public binary_function + struct less { EA_CPP14_CONSTEXPR bool operator()(const T& a, const T& b) const { return a < b; } @@ -361,7 +361,7 @@ namespace eastl /// bind1st /// template - class binder1st : public unary_function + class EASTL_REMOVE_AT_2024_APRIL binder1st : public unary_function { protected: typename Operation::first_argument_type value; @@ -379,18 +379,19 @@ namespace eastl }; + EASTL_INTERNAL_DISABLE_DEPRECATED() // 'eastl::binder1st': was declared deprecated template - inline binder1st bind1st(const Operation& op, const T& x) + EASTL_REMOVE_AT_2024_APRIL inline binder1st bind1st(const Operation& op, const T& x) { typedef typename Operation::first_argument_type value; return binder1st(op, value(x)); } - + EASTL_INTERNAL_RESTORE_DEPRECATED() /// bind2nd /// template - class binder2nd : public unary_function + class EASTL_REMOVE_AT_2024_APRIL binder2nd : public unary_function { protected: Operation op; @@ -408,12 +409,14 @@ namespace eastl }; + EASTL_INTERNAL_DISABLE_DEPRECATED() // 'eastl::binder2nd': was declared deprecated template - inline binder2nd bind2nd(const Operation& op, const T& x) + EASTL_REMOVE_AT_2024_APRIL inline binder2nd bind2nd(const Operation& op, const T& x) { typedef typename Operation::second_argument_type value; return binder2nd(op, value(x)); } + EASTL_INTERNAL_RESTORE_DEPRECATED() } // namespace eastl diff --git a/include/EASTL/internal/hashtable.h b/include/EASTL/internal/hashtable.h index 077f5b48..bc64bcf6 100644 --- a/include/EASTL/internal/hashtable.h +++ b/include/EASTL/internal/hashtable.h @@ -210,8 +210,8 @@ namespace eastl typedef node_iterator this_type; typedef typename base_type::node_type node_type; typedef Value value_type; - typedef typename type_select::type pointer; - typedef typename type_select::type reference; + typedef typename conditional::type pointer; + typedef typename conditional::type reference; typedef ptrdiff_t difference_type; typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; @@ -315,8 +315,8 @@ namespace eastl typedef hashtable_iterator this_type_non_const; typedef typename base_type::node_type node_type; typedef Value value_type; - typedef typename type_select::type pointer; - typedef typename type_select::type reference; + typedef typename conditional::type pointer; + typedef typename conditional::type reference; typedef ptrdiff_t difference_type; typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; @@ -532,8 +532,8 @@ namespace eastl H1 hash_function() const { return H1(); } - Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard - { return mEqual; } // has specified in its hashtable (unordered_*) proposal. + EASTL_REMOVE_AT_2024_APRIL Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard + { return mEqual; } // has specified in its hashtable (unordered_*) proposal. const Equal& key_eq() const { return mEqual; } @@ -622,8 +622,8 @@ namespace eastl H1 hash_function() const { return m_h1; } - Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard - { return mEqual; } // has specified in its hashtable (unordered_*) proposal. + EASTL_REMOVE_AT_2024_APRIL Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard + { return mEqual; } // has specified in its hashtable (unordered_*) proposal. const Equal& key_eq() const { return mEqual; } @@ -693,8 +693,8 @@ namespace eastl H1 hash_function() const { return m_h1; } - Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard - { return mEqual; } // has specified in its hashtable (unordered_*) proposal. + EASTL_REMOVE_AT_2024_APRIL Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard + { return mEqual; } // has specified in its hashtable (unordered_*) proposal. const Equal& key_eq() const { return mEqual; } @@ -845,7 +845,7 @@ namespace eastl typedef hashtable_iterator iterator; typedef hashtable_iterator const_iterator; typedef hash_node node_type; - typedef typename type_select, iterator>::type insert_return_type; + typedef typename conditional, iterator>::type insert_return_type; typedef hashtable this_type; typedef RehashPolicy rehash_policy_type; @@ -869,7 +869,7 @@ namespace eastl enum { // This enumeration is deprecated in favor of eastl::kHashtableAllocFlagBuckets. - kAllocFlagBuckets = eastl::kHashtableAllocFlagBuckets // Flag to allocator which indicates that we are allocating buckets and not nodes. + kAllocFlagBuckets EASTL_REMOVE_AT_2024_APRIL = eastl::kHashtableAllocFlagBuckets // Flag to allocator which indicates that we are allocating buckets and not nodes. }; protected: @@ -1024,6 +1024,7 @@ namespace eastl // // Ideally we would remove this overload as it deprecated and removed in C++17 but it currently causes // performance regressions for hashtables with complex keys (keys that allocate resources). + EASTL_INTERNAL_DISABLE_DEPRECATED() // 'is_literal_type_v

': was declared deprecated template && eastl::is_constructible_v>> insert_return_type insert(P&& otherValue); + EASTL_INTERNAL_RESTORE_DEPRECATED() // Non-standard extension template // See comments below for the const value_type& equivalent to this function. @@ -1083,7 +1085,7 @@ namespace eastl /// /// Example usage (note that the predicate uses string as first type and char* as second): /// hash_set hashSet; - /// hashSet.find_as("hello", hash(), equal_to_2()); + /// hashSet.find_as("hello", hash(), equal_to<>()); /// template iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate); @@ -1270,15 +1272,11 @@ namespace eastl // this allows to save some performance, especially with heavy hash functions eastl::pair DoInsertKey(true_type, const key_type& key, hash_code_t c); iterator DoInsertKey(false_type, const key_type& key, hash_code_t c); - eastl::pair DoInsertKey(true_type, key_type&& key, hash_code_t c); - iterator DoInsertKey(false_type, key_type&& key, hash_code_t c); // We keep DoInsertKey overload without third parameter, for compatibility with older revisions of EASTL (3.12.07 and earlier) // It used to call get_hash_code as a first call inside the DoInsertKey. eastl::pair DoInsertKey(true_type, const key_type& key) { return DoInsertKey(true_type(), key, get_hash_code(key)); } iterator DoInsertKey(false_type, const key_type& key) { return DoInsertKey(false_type(), key, get_hash_code(key)); } - eastl::pair DoInsertKey(true_type, key_type&& key) { return DoInsertKey(true_type(), eastl::move(key), get_hash_code(key)); } - iterator DoInsertKey(false_type, key_type&& key) { return DoInsertKey(false_type(), eastl::move(key), get_hash_code(key)); } void DoRehash(size_type nBucketCount); node_type* DoFindNode(node_type* pNode, const key_type& k, hash_code_t c) const; @@ -1781,13 +1779,13 @@ namespace eastl /// hashtable_find /// - /// Helper function that defaults to using hash and equal_to_2. + /// Helper function that defaults to using hash and equal_to<>. /// This makes it so that by default you don't need to provide these. /// Note that the default hash functions may not be what you want, though. /// /// Example usage. Instead of this: /// hash_set hashSet; - /// hashSet.find("hello", hash(), equal_to_2()); + /// hashSet.find("hello", hash(), equal_to<>()); /// /// You can use this: /// hash_set hashSet; @@ -1795,11 +1793,11 @@ namespace eastl /// template inline typename H::iterator hashtable_find(H& hashTable, U u) - { return hashTable.find_as(u, eastl::hash(), eastl::equal_to_2()); } + { return hashTable.find_as(u, eastl::hash(), eastl::equal_to<>()); } template inline typename H::const_iterator hashtable_find(const H& hashTable, U u) - { return hashTable.find_as(u, eastl::hash(), eastl::equal_to_2()); } + { return hashTable.find_as(u, eastl::hash(), eastl::equal_to<>()); } @@ -1811,7 +1809,7 @@ namespace eastl { return eastl::hashtable_find(*this, other); } // VC++ doesn't appear to like the following, though it seems correct to me. // So we implement the workaround above until we can straighten this out. - //{ return find_as(other, eastl::hash(), eastl::equal_to_2()); } + //{ return find_as(other, eastl::hash(), eastl::equal_to<>()); } template (), eastl::equal_to_2()); } + //{ return find_as(other, eastl::hash(), eastl::equal_to<>()); } @@ -2526,94 +2524,6 @@ namespace eastl } - template - eastl::pair::iterator, bool> - hashtable::DoInsertKey(true_type, key_type&& key, const hash_code_t c) // true_type means bUniqueKeys is true. - { - size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); - node_type* const pNode = DoFindNode(mpBucketArray[n], key, c); - - if(pNode == NULL) - { - const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); - - // Allocate the new node before doing the rehash so that we don't - // do a rehash if the allocation throws. - node_type* const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); - set_code(pNodeNew, c); // This is a no-op for most hashtables. - - #if EASTL_EXCEPTIONS_ENABLED - try - { - #endif - if(bRehash.first) - { - n = (size_type)bucket_index(key, c, (uint32_t)bRehash.second); - DoRehash(bRehash.second); - } - - EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); - pNodeNew->mpNext = mpBucketArray[n]; - mpBucketArray[n] = pNodeNew; - ++mnElementCount; - - return eastl::pair(iterator(pNodeNew, mpBucketArray + n), true); - #if EASTL_EXCEPTIONS_ENABLED - } - catch(...) - { - DoFreeNode(pNodeNew); - throw; - } - #endif - } - - return eastl::pair(iterator(pNode, mpBucketArray + n), false); - } - - - template - typename hashtable::iterator - hashtable::DoInsertKey(false_type, key_type&& key, const hash_code_t c) // false_type means bUniqueKeys is false. - { - const eastl::pair bRehash = mRehashPolicy.GetRehashRequired((uint32_t)mnBucketCount, (uint32_t)mnElementCount, (uint32_t)1); - - if(bRehash.first) - DoRehash(bRehash.second); - - const size_type n = (size_type)bucket_index(key, c, (uint32_t)mnBucketCount); - - node_type* const pNodeNew = DoAllocateNodeFromKey(eastl::move(key)); - set_code(pNodeNew, c); // This is a no-op for most hashtables. - - // To consider: Possibly make this insertion not make equal elements contiguous. - // As it stands now, we insert equal values contiguously in the hashtable. - // The benefit is that equal_range can work in a sensible manner and that - // erase(value) can more quickly find equal values. The downside is that - // this insertion operation taking some extra time. How important is it to - // us that equal_range span all equal items? - node_type* const pNodePrev = DoFindNode(mpBucketArray[n], key, c); - - if(pNodePrev == NULL) - { - EASTL_ASSERT((void**)mpBucketArray != &gpEmptyBucketArray[0]); - pNodeNew->mpNext = mpBucketArray[n]; - mpBucketArray[n] = pNodeNew; - } - else - { - pNodeNew->mpNext = pNodePrev->mpNext; - pNodePrev->mpNext = pNodeNew; - } - - ++mnElementCount; - - return iterator(pNodeNew, mpBucketArray + n); - } - - template template @@ -3070,7 +2980,7 @@ namespace eastl // template - inline bool operator<(const hashtable& a, + EASTL_REMOVE_AT_2024_APRIL inline bool operator<(const hashtable& a, const hashtable& b) { // This requires hash table elements to support operator<. Since the hash table @@ -3082,7 +2992,7 @@ namespace eastl template - inline bool operator>(const hashtable& a, + EASTL_REMOVE_AT_2024_APRIL inline bool operator>(const hashtable& a, const hashtable& b) { return b < a; @@ -3091,7 +3001,7 @@ namespace eastl template - inline bool operator<=(const hashtable& a, + EASTL_REMOVE_AT_2024_APRIL inline bool operator<=(const hashtable& a, const hashtable& b) { return !(b < a); @@ -3100,7 +3010,7 @@ namespace eastl template - inline bool operator>=(const hashtable& a, + EASTL_REMOVE_AT_2024_APRIL inline bool operator>=(const hashtable& a, const hashtable& b) { return !(a < b); diff --git a/include/EASTL/internal/intrusive_hashtable.h b/include/EASTL/internal/intrusive_hashtable.h index dccca5b1..291a527e 100644 --- a/include/EASTL/internal/intrusive_hashtable.h +++ b/include/EASTL/internal/intrusive_hashtable.h @@ -87,8 +87,8 @@ namespace eastl typedef Value value_type; typedef Value node_type; typedef ptrdiff_t difference_type; - typedef typename type_select::type pointer; - typedef typename type_select::type reference; + typedef typename conditional::type pointer; + typedef typename conditional::type reference; typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; public: @@ -196,8 +196,8 @@ namespace eastl typedef intrusive_hashtable_iterator this_type; typedef intrusive_hashtable_iterator this_type_non_const; typedef typename base_type::value_type value_type; - typedef typename type_select::type pointer; - typedef typename type_select::type reference; + typedef typename conditional::type pointer; + typedef typename conditional::type reference; typedef ptrdiff_t difference_type; typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; @@ -237,7 +237,7 @@ namespace eastl /// the use_self template implementation, which is used for sets. /// template - struct use_intrusive_key // : public unary_function // Perhaps we want to make it a subclass of unary_function. + struct use_intrusive_key { typedef Key result_type; @@ -271,8 +271,8 @@ namespace eastl typedef intrusive_node_iterator const_local_iterator; typedef intrusive_hashtable_iterator iterator; typedef intrusive_hashtable_iterator const_iterator; - typedef typename type_select, iterator>::type insert_return_type; - typedef typename type_select, + typedef typename conditional, iterator>::type insert_return_type; + typedef typename conditional, eastl::use_intrusive_key >::type extract_key; enum @@ -393,7 +393,7 @@ namespace eastl /// /// Example usage (namespaces omitted for brevity): /// hash_set hashSet; - /// hashSet.find_as("hello", hash(), equal_to_2()); + /// hashSet.find_as("hello", hash(), equal_to<>()); /// template iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate); @@ -422,8 +422,8 @@ namespace eastl Hash hash_function() const { return mHash; } - Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard - { return mEqual; } // has specified in its hashtable (unordered_*) proposal. + EASTL_REMOVE_AT_2024_APRIL Equal equal_function() const // Deprecated. Use key_eq() instead, as key_eq is what the new C++ standard + { return mEqual; } // has specified in its hashtable (unordered_*). const key_equal& key_eq() const { return mEqual; } @@ -552,13 +552,13 @@ namespace eastl /// intrusive_hashtable_find /// - /// Helper function that defaults to using hash and equal_to_2. + /// Helper function that defaults to using hash and equal_to<>. /// This makes it so that by default you don't need to provide these. /// Note that the default hash functions may not be what you want, though. /// /// Example usage. Instead of this: /// hash_set hashSet; - /// hashSet.find("hello", hash(), equal_to_2()); + /// hashSet.find("hello", hash(), equal_to<>()); /// /// You can use this: /// hash_set hashSet; @@ -566,11 +566,11 @@ namespace eastl /// template inline typename H::iterator intrusive_hashtable_find(H& hashTable, const U& u) - { return hashTable.find_as(u, eastl::hash(), eastl::equal_to_2()); } + { return hashTable.find_as(u, eastl::hash(), eastl::equal_to<>()); } template inline typename H::const_iterator intrusive_hashtable_find(const H& hashTable, const U& u) - { return hashTable.find_as(u, eastl::hash(), eastl::equal_to_2()); } + { return hashTable.find_as(u, eastl::hash(), eastl::equal_to<>()); } @@ -581,7 +581,7 @@ namespace eastl { return eastl::intrusive_hashtable_find(*this, other); } // VC++ doesn't appear to like the following, though it seems correct to me. // So we implement the workaround above until we can straighten this out. - //{ return find_as(other, eastl::hash(), eastl::equal_to_2()); } + //{ return find_as(other, eastl::hash(), eastl::equal_to<>()); } template @@ -591,7 +591,7 @@ namespace eastl { return eastl::intrusive_hashtable_find(*this, other); } // VC++ doesn't appear to like the following, though it seems correct to me. // So we implement the workaround above until we can straighten this out. - //{ return find_as(other, eastl::hash(), eastl::equal_to_2()); } + //{ return find_as(other, eastl::hash(), eastl::equal_to<>()); } template diff --git a/include/EASTL/internal/mem_fn.h b/include/EASTL/internal/mem_fn.h index 1d3e7b3f..942cb918 100644 --- a/include/EASTL/internal/mem_fn.h +++ b/include/EASTL/internal/mem_fn.h @@ -26,6 +26,7 @@ // //===----------------------------------------------------------------------===// +EASTL_INTERNAL_DISABLE_DEPRECATED() // 'eastl::unary_function' / 'binary_function': was declared deprecated namespace eastl { @@ -127,7 +128,7 @@ namespace eastl : public maybe_derive_from_unary_function, public maybe_derive_from_binary_function { - typedef typename T::result_type result_type; + EASTL_REMOVE_AT_2024_APRIL typedef typename T::result_type result_type; }; template @@ -143,9 +144,9 @@ namespace eastl struct weak_result_type : public weak_result_type_imp { }; // 0 argument case - template struct weak_result_type { typedef R result_type; }; - template struct weak_result_type { typedef R result_type; }; - template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; // 1 argument case template struct weak_result_type : public unary_function { }; @@ -167,13 +168,13 @@ namespace eastl // 3 or more arguments #if EASTL_VARIADIC_TEMPLATES_ENABLED - template struct weak_result_type { typedef R result_type; }; - template struct weak_result_type { typedef R result_type; }; - template struct weak_result_type { typedef R result_type; }; - template struct weak_result_type { typedef R result_type; }; - template struct weak_result_type { typedef R result_type; }; - template struct weak_result_type { typedef R result_type; }; - template struct weak_result_type { typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; + template struct weak_result_type { EASTL_REMOVE_AT_2024_APRIL typedef R result_type; }; #endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -301,4 +302,6 @@ namespace eastl } // namespace eastl +EASTL_INTERNAL_RESTORE_DEPRECATED() + #endif // EASTL_INTERNAL_MEM_FN_H diff --git a/include/EASTL/internal/red_black_tree.h b/include/EASTL/internal/red_black_tree.h index 5b29b7ca..74962e86 100644 --- a/include/EASTL/internal/red_black_tree.h +++ b/include/EASTL/internal/red_black_tree.h @@ -162,15 +162,23 @@ namespace eastl typedef Reference reference; typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category; +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + private: + base_node_type* mpNode; +#else public: node_type* mpNode; +#endif public: rbtree_iterator(); - explicit rbtree_iterator(const node_type* pNode); + explicit rbtree_iterator(const base_node_type* pNode); + // Note: this isn't always a copy constructor, iterator is not always equal to this_type rbtree_iterator(const iterator& x); + // Note: this isn't always a copy assignment operator, iterator is not always equal to this_type rbtree_iterator& operator=(const iterator& x); + // Calling these on the end() of a tree invokes undefined behavior. reference operator*() const; pointer operator->() const; @@ -179,7 +187,33 @@ namespace eastl rbtree_iterator& operator--(); rbtree_iterator operator--(int); + private: + // This is a temp helper function for the deprecation. + // It should be removed when the deprecation window ends. +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + base_node_type* toInternalNodeType(base_node_type* node) { return node; } +#else + node_type* toInternalNodeType(base_node_type* node) { return static_cast(node); } +#endif + + template + friend bool operator==(const rbtree_iterator&, const rbtree_iterator&); + template + friend bool operator!=(const rbtree_iterator&, const rbtree_iterator&); + + template + friend bool operator!=(const rbtree_iterator&, const rbtree_iterator&); + + // rbtree uses mpNode. + template + friend class rbtree; + + // for the "copy" constructor, which uses non-const iterator even in the + // const_iterator case. + friend iterator; + friend const_iterator; }; // rbtree_iterator @@ -396,7 +430,7 @@ namespace eastl typedef value_type* pointer; typedef const value_type* const_pointer; - typedef typename type_select, rbtree_iterator >::type iterator; typedef rbtree_iterator const_iterator; @@ -405,7 +439,7 @@ namespace eastl typedef Allocator allocator_type; typedef Compare key_compare; - typedef typename type_select, iterator>::type insert_return_type; // map/set::insert return a pair, multimap/multiset::iterator return an iterator. + typedef typename conditional, iterator>::type insert_return_type; // map/set::insert return a pair, multimap/multiset::iterator return an iterator. typedef rbtree this_type; typedef rb_base base_type; @@ -547,7 +581,7 @@ namespace eastl /// /// Example usage (note that the compare uses string as first type and char* as second): /// set strings; - /// strings.find_as("hello", less_2()); + /// strings.find_as("hello", less<>()); /// template iterator find_as(const U& u, Compare2 compare2); template const_iterator find_as(const U& u, Compare2 compare2) const; @@ -571,10 +605,10 @@ namespace eastl node_type* DoCreateNode(Args&&... args); node_type* DoCreateNode(const value_type& value); node_type* DoCreateNode(value_type&& value); - node_type* DoCreateNode(const node_type* pNodeSource, node_type* pNodeParent); + node_type* DoCreateNode(const node_type* pNodeSource, rbtree_node_base* pNodeParent); - node_type* DoCopySubtree(const node_type* pNodeSource, node_type* pNodeDest); - void DoNukeSubtree(node_type* pNode); + rbtree_node_base* DoCopySubtree(const node_type* pNodeSource, rbtree_node_base* pNodeDest); + void DoNukeSubtree(rbtree_node_base* pNode); template eastl::pair DoInsertValue(true_type, Args&&... args); @@ -586,8 +620,8 @@ namespace eastl iterator DoInsertValue(false_type, value_type&& value); template - iterator DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, Args&&... args); - iterator DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, node_type* pNodeNew); + iterator DoInsertValueImpl(rbtree_node_base* pNodeParent, bool bForceToLeft, const key_type& key, Args&&... args); + iterator DoInsertValueImpl(rbtree_node_base* pNodeParent, bool bForceToLeft, const key_type& key, node_type* pNodeNew); eastl::pair DoInsertKey(true_type, const key_type& key); iterator DoInsertKey(false_type, const key_type& key); @@ -603,13 +637,13 @@ namespace eastl iterator DoInsertKey(true_type, const_iterator position, const key_type& key); // By design we return iterator and not a pair. iterator DoInsertKey(false_type, const_iterator position, const key_type& key); - iterator DoInsertKeyImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key); + iterator DoInsertKeyImpl(rbtree_node_base* pNodeParent, bool bForceToLeft, const key_type& key); - node_type* DoGetKeyInsertionPositionUniqueKeys(bool& canInsert, const key_type& key); - node_type* DoGetKeyInsertionPositionNonuniqueKeys(const key_type& key); + rbtree_node_base* DoGetKeyInsertionPositionUniqueKeys(bool& canInsert, const key_type& key); + rbtree_node_base* DoGetKeyInsertionPositionNonuniqueKeys(const key_type& key); - node_type* DoGetKeyInsertionPositionUniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key); - node_type* DoGetKeyInsertionPositionNonuniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key); + rbtree_node_base* DoGetKeyInsertionPositionUniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key); + rbtree_node_base* DoGetKeyInsertionPositionNonuniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key); }; // rbtree @@ -650,8 +684,8 @@ namespace eastl template - rbtree_iterator::rbtree_iterator(const node_type* pNode) - : mpNode(static_cast(const_cast(pNode))) { } + rbtree_iterator::rbtree_iterator(const base_node_type* pNode) + : mpNode(toInternalNodeType(const_cast(pNode))) { } template @@ -669,20 +703,24 @@ namespace eastl template typename rbtree_iterator::reference rbtree_iterator::operator*() const - { return mpNode->mValue; } + { + return static_cast(mpNode)->mValue; + } template typename rbtree_iterator::pointer rbtree_iterator::operator->() const - { return &mpNode->mValue; } + { + return &static_cast(mpNode)->mValue; + } template typename rbtree_iterator::this_type& rbtree_iterator::operator++() { - mpNode = static_cast(RBTreeIncrement(mpNode)); + mpNode = toInternalNodeType(RBTreeIncrement(mpNode)); return *this; } @@ -692,7 +730,7 @@ namespace eastl rbtree_iterator::operator++(int) { this_type temp(*this); - mpNode = static_cast(RBTreeIncrement(mpNode)); + mpNode = toInternalNodeType(RBTreeIncrement(mpNode)); return temp; } @@ -701,7 +739,7 @@ namespace eastl typename rbtree_iterator::this_type& rbtree_iterator::operator--() { - mpNode = static_cast(RBTreeDecrement(mpNode)); + mpNode = toInternalNodeType(RBTreeDecrement(mpNode)); return *this; } @@ -711,7 +749,7 @@ namespace eastl rbtree_iterator::operator--(int) { this_type temp(*this); - mpNode = static_cast(RBTreeDecrement(mpNode)); + mpNode = toInternalNodeType(RBTreeDecrement(mpNode)); return temp; } @@ -793,7 +831,7 @@ namespace eastl if(x.mAnchor.mpNodeParent) // mAnchor.mpNodeParent is the rb_tree root node. { - mAnchor.mpNodeParent = DoCopySubtree((const node_type*)x.mAnchor.mpNodeParent, (node_type*)&mAnchor); + mAnchor.mpNodeParent = DoCopySubtree((const node_type*)x.mAnchor.mpNodeParent, &mAnchor); mAnchor.mpNodeRight = RBTreeGetMaxChild(mAnchor.mpNodeParent); mAnchor.mpNodeLeft = RBTreeGetMinChild(mAnchor.mpNodeParent); mnSize = x.mnSize; @@ -897,37 +935,37 @@ namespace eastl template inline typename rbtree::iterator rbtree::begin() EA_NOEXCEPT - { return iterator(static_cast(mAnchor.mpNodeLeft)); } + { return iterator(mAnchor.mpNodeLeft); } template inline typename rbtree::const_iterator rbtree::begin() const EA_NOEXCEPT - { return const_iterator(static_cast(const_cast(mAnchor.mpNodeLeft))); } + { return const_iterator(mAnchor.mpNodeLeft); } template inline typename rbtree::const_iterator rbtree::cbegin() const EA_NOEXCEPT - { return const_iterator(static_cast(const_cast(mAnchor.mpNodeLeft))); } + { return const_iterator(mAnchor.mpNodeLeft); } template inline typename rbtree::iterator rbtree::end() EA_NOEXCEPT - { return iterator(static_cast(&mAnchor)); } + { return iterator(&mAnchor); } template inline typename rbtree::const_iterator rbtree::end() const EA_NOEXCEPT - { return const_iterator(static_cast(const_cast(&mAnchor))); } + { return const_iterator(&mAnchor); } template inline typename rbtree::const_iterator rbtree::cend() const EA_NOEXCEPT - { return const_iterator(static_cast(const_cast(&mAnchor))); } + { return const_iterator(&mAnchor); } template @@ -982,7 +1020,7 @@ namespace eastl if(x.mAnchor.mpNodeParent) // mAnchor.mpNodeParent is the rb_tree root node. { - mAnchor.mpNodeParent = DoCopySubtree((const node_type*)x.mAnchor.mpNodeParent, (node_type*)&mAnchor); + mAnchor.mpNodeParent = DoCopySubtree((const node_type*)x.mAnchor.mpNodeParent, &mAnchor); mAnchor.mpNodeRight = RBTreeGetMaxChild(mAnchor.mpNodeParent); mAnchor.mpNodeLeft = RBTreeGetMinChild(mAnchor.mpNodeParent); mnSize = x.mnSize; @@ -1210,16 +1248,16 @@ namespace eastl } template - typename rbtree::node_type* + rbtree_node_base* rbtree::DoGetKeyInsertionPositionUniqueKeys(bool& canInsert, const key_type& key) { // This code is essentially a slightly modified copy of the the rbtree::insert // function whereby this version takes a key and not a full value_type. extract_key extractKey; - node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. - node_type* pLowerBound = (node_type*)&mAnchor; // Set it to the container end for now. - node_type* pParent; // This will be where we insert the new node. + rbtree_node_base* pCurrent = mAnchor.mpNodeParent; // Start with the root node. + rbtree_node_base* pLowerBound = &mAnchor; // Set it to the container end for now. + rbtree_node_base* pParent; // This will be where we insert the new node. bool bValueLessThanNode = true; // If the tree is empty, this will result in an insertion at the front. @@ -1228,27 +1266,27 @@ namespace eastl // end(), which we treat like a position which is greater than the value. while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. { - bValueLessThanNode = compare(key, extractKey(pCurrent->mValue)); + bValueLessThanNode = compare(key, extractKey(static_cast(pCurrent)->mValue)); pLowerBound = pCurrent; if(bValueLessThanNode) { - EASTL_VALIDATE_COMPARE(!compare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane. - pCurrent = (node_type*)pCurrent->mpNodeLeft; + EASTL_VALIDATE_COMPARE(!compare(extractKey(static_cast(pCurrent)->mValue), key)); // Validate that the compare function is sane. + pCurrent = pCurrent->mpNodeLeft; } else - pCurrent = (node_type*)pCurrent->mpNodeRight; + pCurrent = pCurrent->mpNodeRight; } pParent = pLowerBound; // pLowerBound is actually upper bound right now (i.e. it is > value instead of <=), but we will make it the lower bound below. if(bValueLessThanNode) // If we ended up on the left side of the last parent node... { - if(EASTL_LIKELY(pLowerBound != (node_type*)mAnchor.mpNodeLeft)) // If the tree was empty or if we otherwise need to insert at the very front of the tree... + if(EASTL_LIKELY(pLowerBound != mAnchor.mpNodeLeft)) // If the tree was empty or if we otherwise need to insert at the very front of the tree... { // At this point, pLowerBound points to a node which is > than value. // Move it back by one, so that it points to a node which is <= value. - pLowerBound = (node_type*)RBTreeDecrement(pLowerBound); + pLowerBound = RBTreeDecrement(pLowerBound); } else { @@ -1258,9 +1296,10 @@ namespace eastl } // Since here we require values to be unique, we will do nothing if the value already exists. - if(compare(extractKey(pLowerBound->mValue), key)) // If the node is < the value (i.e. if value is >= the node)... + node_type* const pLowerBoundFullNode = static_cast(pLowerBound); + if(compare(extractKey(pLowerBoundFullNode->mValue), key)) // If the node is < the value (i.e. if value is >= the node)... { - EASTL_VALIDATE_COMPARE(!compare(key, extractKey(pLowerBound->mValue))); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!compare(key, extractKey(pLowerBoundFullNode->mValue))); // Validate that the compare function is sane. canInsert = true; return pParent; } @@ -1272,25 +1311,25 @@ namespace eastl template - typename rbtree::node_type* + rbtree_node_base* rbtree::DoGetKeyInsertionPositionNonuniqueKeys(const key_type& key) { // This is the pathway for insertion of non-unique keys (multimap and multiset, but not map and set). - node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. - node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + rbtree_node_base* pCurrent = mAnchor.mpNodeParent; // Start with the root node. + rbtree_node_base* pRangeEnd = &mAnchor; // Set it to the container end for now. extract_key extractKey; while(pCurrent) { pRangeEnd = pCurrent; - if(compare(key, extractKey(pCurrent->mValue))) + if(compare(key, extractKey(static_cast(pCurrent)->mValue))) { - EASTL_VALIDATE_COMPARE(!compare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane. - pCurrent = (node_type*)pCurrent->mpNodeLeft; + EASTL_VALIDATE_COMPARE(!compare(extractKey(static_cast(pCurrent)->mValue), key)); // Validate that the compare function is sane. + pCurrent = pCurrent->mpNodeLeft; } else - pCurrent = (node_type*)pCurrent->mpNodeRight; + pCurrent = pCurrent->mpNodeRight; } return pRangeEnd; @@ -1304,7 +1343,7 @@ namespace eastl extract_key extractKey; key_type key(extractKey(value)); bool canInsert; - node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); if(canInsert) { @@ -1322,7 +1361,7 @@ namespace eastl { extract_key extractKey; key_type key(extractKey(value)); - node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); return DoInsertValueImpl(pPosition, false, key, eastl::move(value)); } @@ -1341,7 +1380,7 @@ namespace eastl const key_type& key = extract_key{}(pNodeNew->mValue); bool canInsert; - node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); if(canInsert) { @@ -1366,7 +1405,7 @@ namespace eastl node_type* const pNodeNew = DoCreateNode(eastl::forward(args)...); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized. const key_type& key = extract_key{}(pNodeNew->mValue); - node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); return DoInsertValueImpl(pPosition, false, key, pNodeNew); } @@ -1375,17 +1414,16 @@ namespace eastl template template typename rbtree::iterator - rbtree::DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, Args&&... args) + rbtree::DoInsertValueImpl(rbtree_node_base* pNodeParent, bool bForceToLeft, const key_type& key, Args&&... args) { node_type* const pNodeNew = DoCreateNode(eastl::forward(args)...); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized. - return DoInsertValueImpl(pNodeParent, bForceToLeft, key, pNodeNew); } template typename rbtree::iterator - rbtree::DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, node_type* pNodeNew) + rbtree::DoInsertValueImpl(rbtree_node_base* pNodeParent, bool bForceToLeft, const key_type& key, node_type* pNodeNew) { EASTL_ASSERT_MSG(pNodeNew != nullptr, "node to insert to the rbtree must not be null"); @@ -1395,7 +1433,7 @@ namespace eastl // The reason we may want to have bForceToLeft == true is that pNodeParent->mValue and value may be equal. // In that case it doesn't matter what side we insert on, except that the C++ LWG #233 improvement report // suggests that we should use the insert hint position to force an ordering. So that's what we do. - if(bForceToLeft || (pNodeParent == &mAnchor) || compare(key, extractKey(pNodeParent->mValue))) + if(bForceToLeft || (pNodeParent == &mAnchor) || compare(key, extractKey(static_cast(pNodeParent)->mValue))) side = kRBTreeSideLeft; else side = kRBTreeSideRight; @@ -1415,7 +1453,7 @@ namespace eastl // Note that we return a pair and not an iterator. This is because the C++ standard for map // and set is to return a pair and not just an iterator. bool canInsert; - node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key); if(canInsert) { @@ -1431,15 +1469,14 @@ namespace eastl typename rbtree::iterator rbtree::DoInsertKey(false_type, const key_type& key) // false_type means keys are not unique. { - node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); - + rbtree_node_base* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key); return DoInsertKeyImpl(pPosition, false, key); } template - typename rbtree::node_type* + rbtree_node_base* rbtree::DoGetKeyInsertionPositionUniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key) { extract_key extractKey; @@ -1452,17 +1489,17 @@ namespace eastl // To consider: Change this so that 'position' specifies the position after // where the insertion goes and not the position before where the insertion goes. // Doing so would make this more in line with user expectations and with LWG #233. - const bool bPositionLessThanValue = compare(extractKey(position.mpNode->mValue), key); + const bool bPositionLessThanValue = compare(extractKey(*position), key); if(bPositionLessThanValue) // If (value > *position)... { - EASTL_VALIDATE_COMPARE(!compare(key, extractKey(position.mpNode->mValue))); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!compare(key, extractKey(*position))); // Validate that the compare function is sane. - const bool bValueLessThanNext = compare(key, extractKey(itNext.mpNode->mValue)); + const bool bValueLessThanNext = compare(key, extractKey(*itNext)); if(bValueLessThanNext) // If value < *itNext... { - EASTL_VALIDATE_COMPARE(!compare(extractKey(itNext.mpNode->mValue), key)); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!compare(extractKey(*itNext), key)); // Validate that the compare function is sane. if(position.mpNode->mpNodeRight) { @@ -1476,14 +1513,14 @@ namespace eastl } bForceToLeft = false; - return NULL; // The above specified hint was not useful, then we do a regular insertion. + return nullptr; // The above specified hint was not useful, then we do a regular insertion. } - if(mnSize && compare(extractKey(((node_type*)mAnchor.mpNodeRight)->mValue), key)) + if(mnSize && compare(extractKey(static_cast(mAnchor.mpNodeRight)->mValue), key)) { - EASTL_VALIDATE_COMPARE(!compare(key, extractKey(((node_type*)mAnchor.mpNodeRight)->mValue))); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!compare(key, extractKey(static_cast(mAnchor.mpNodeRight)->mValue))); // Validate that the compare function is sane. bForceToLeft = false; - return (node_type*)mAnchor.mpNodeRight; + return mAnchor.mpNodeRight; } bForceToLeft = false; @@ -1492,7 +1529,7 @@ namespace eastl template - typename rbtree::node_type* + rbtree_node_base* rbtree::DoGetKeyInsertionPositionNonuniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key) { extract_key extractKey; @@ -1505,8 +1542,8 @@ namespace eastl // To consider: Change this so that 'position' specifies the position after // where the insertion goes and not the position before where the insertion goes. // Doing so would make this more in line with user expectations and with LWG #233. - if(!compare(key, extractKey(position.mpNode->mValue)) && // If value >= *position && - !compare(extractKey(itNext.mpNode->mValue), key)) // if value <= *itNext... + if(!compare(key, extractKey(*position)) && // If value >= *position && + !compare(extractKey(*itNext), key)) // if value <= *itNext... { if(position.mpNode->mpNodeRight) // If there are any nodes to the right... [this expression will always be true as long as we aren't at the end()] { @@ -1519,19 +1556,19 @@ namespace eastl } bForceToLeft = false; - return NULL; // The above specified hint was not useful, then we do a regular insertion. + return nullptr; // The above specified hint was not useful, then we do a regular insertion. } // This pathway shouldn't be commonly executed, as the user shouldn't be calling // this hinted version of insert if the user isn't providing a useful hint. - if(mnSize && !compare(key, extractKey(((node_type*)mAnchor.mpNodeRight)->mValue))) // If we are non-empty and the value is >= the last node... + if(mnSize && !compare(key, extractKey(static_cast(mAnchor.mpNodeRight)->mValue))) // If we are non-empty and the value is >= the last node... { bForceToLeft =false; - return (node_type*)mAnchor.mpNodeRight; + return mAnchor.mpNodeRight; } bForceToLeft = false; - return NULL; + return nullptr; } template @@ -1548,7 +1585,7 @@ namespace eastl const key_type& key(extract_key{}(pNodeNew->mValue)); bool bForceToLeft; - node_type* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key); if (!pPosition) { @@ -1582,7 +1619,7 @@ namespace eastl const key_type& key(extract_key{}(pNodeNew->mValue)); bool bForceToLeft; - node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key); if (!pPosition) { @@ -1606,7 +1643,7 @@ namespace eastl extract_key extractKey; key_type key(extractKey(value)); bool bForceToLeft; - node_type* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key); if(pPosition) return DoInsertValueImpl(pPosition, bForceToLeft, key, eastl::move(value)); @@ -1626,7 +1663,7 @@ namespace eastl extract_key extractKey; key_type key(extractKey(value)); bool bForceToLeft; - node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key); if(pPosition) return DoInsertValueImpl(pPosition, bForceToLeft, key, eastl::move(value)); @@ -1640,7 +1677,7 @@ namespace eastl rbtree::DoInsertKey(true_type, const_iterator position, const key_type& key) // true_type means keys are unique. { bool bForceToLeft; - node_type* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key); if(pPosition) return DoInsertKeyImpl(pPosition, bForceToLeft, key); @@ -1658,7 +1695,7 @@ namespace eastl // We follow the same approach as SGI STL/STLPort and use the position as // a forced insertion position for the value when possible. bool bForceToLeft; - node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key); + rbtree_node_base* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key); if(pPosition) return DoInsertKeyImpl(pPosition, bForceToLeft, key); @@ -1669,7 +1706,7 @@ namespace eastl template typename rbtree::iterator - rbtree::DoInsertKeyImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key) + rbtree::DoInsertKeyImpl(rbtree_node_base* pNodeParent, bool bForceToLeft, const key_type& key) { RBTreeSide side; extract_key extractKey; @@ -1677,7 +1714,7 @@ namespace eastl // The reason we may want to have bForceToLeft == true is that pNodeParent->mValue and value may be equal. // In that case it doesn't matter what side we insert on, except that the C++ LWG #233 improvement report // suggests that we should use the insert hint position to force an ordering. So that's what we do. - if(bForceToLeft || (pNodeParent == &mAnchor) || compare(key, extractKey(pNodeParent->mValue))) + if(bForceToLeft || (pNodeParent == &mAnchor) || compare(key, extractKey(static_cast(pNodeParent)->mValue))) side = kRBTreeSideLeft; else side = kRBTreeSideRight; @@ -1740,7 +1777,7 @@ namespace eastl --mnSize; // Interleave this between the two references to itNext. We expect no exceptions to occur during the code below. ++position; RBTreeErase(iErase.mpNode, &mAnchor); - DoFreeNode(iErase.mpNode); + DoFreeNode(static_cast(iErase.mpNode)); return iterator(position.mpNode); } @@ -1772,7 +1809,7 @@ namespace eastl } clear(); - return iterator((node_type*)&mAnchor); // Same as: return end(); + return iterator(&mAnchor); // Same as: return end(); } @@ -1822,26 +1859,26 @@ namespace eastl // find a lot with trees, but very uncommonly call lower_bound. extract_key extractKey; - node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. - node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + rbtree_node_base* pCurrent = mAnchor.mpNodeParent; // Start with the root node. + rbtree_node_base* pRangeEnd = &mAnchor; // Set it to the container end for now. while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. { - if(EASTL_LIKELY(!compare(extractKey(pCurrent->mValue), key))) // If pCurrent is >= key... + if(EASTL_LIKELY(!compare(extractKey(static_cast(pCurrent)->mValue), key))) // If pCurrent is >= key... { pRangeEnd = pCurrent; - pCurrent = (node_type*)pCurrent->mpNodeLeft; + pCurrent = pCurrent->mpNodeLeft; } else { - EASTL_VALIDATE_COMPARE(!compare(key, extractKey(pCurrent->mValue))); // Validate that the compare function is sane. - pCurrent = (node_type*)pCurrent->mpNodeRight; + EASTL_VALIDATE_COMPARE(!compare(key, extractKey(static_cast(pCurrent)->mValue))); // Validate that the compare function is sane. + pCurrent = pCurrent->mpNodeRight; } } - if(EASTL_LIKELY((pRangeEnd != &mAnchor) && !compare(key, extractKey(pRangeEnd->mValue)))) + if(EASTL_LIKELY((pRangeEnd != &mAnchor) && !compare(key, extractKey(static_cast(pRangeEnd)->mValue)))) return iterator(pRangeEnd); - return iterator((node_type*)&mAnchor); + return iterator(&mAnchor); } @@ -1861,26 +1898,26 @@ namespace eastl { extract_key extractKey; - node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. - node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + rbtree_node_base* pCurrent = mAnchor.mpNodeParent; // Start with the root node. + rbtree_node_base* pRangeEnd = &mAnchor; // Set it to the container end for now. while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. { - if(EASTL_LIKELY(!compare2(extractKey(pCurrent->mValue), u))) // If pCurrent is >= u... + if(EASTL_LIKELY(!compare2(extractKey(static_cast(pCurrent)->mValue), u))) // If pCurrent is >= u... { pRangeEnd = pCurrent; - pCurrent = (node_type*)pCurrent->mpNodeLeft; + pCurrent = pCurrent->mpNodeLeft; } else { - EASTL_VALIDATE_COMPARE(!compare2(u, extractKey(pCurrent->mValue))); // Validate that the compare function is sane. - pCurrent = (node_type*)pCurrent->mpNodeRight; + EASTL_VALIDATE_COMPARE(!compare2(u, extractKey(static_cast(pCurrent)->mValue))); // Validate that the compare function is sane. + pCurrent = pCurrent->mpNodeRight; } } - if(EASTL_LIKELY((pRangeEnd != &mAnchor) && !compare2(u, extractKey(pRangeEnd->mValue)))) + if(EASTL_LIKELY((pRangeEnd != &mAnchor) && !compare2(u, extractKey(static_cast(pRangeEnd)->mValue)))) return iterator(pRangeEnd); - return iterator((node_type*)&mAnchor); + return iterator(&mAnchor); } @@ -1900,20 +1937,20 @@ namespace eastl { extract_key extractKey; - node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. - node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + rbtree_node_base* pCurrent = mAnchor.mpNodeParent; // Start with the root node. + rbtree_node_base* pRangeEnd = &mAnchor; // Set it to the container end for now. while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. { - if(EASTL_LIKELY(!compare(extractKey(pCurrent->mValue), key))) // If pCurrent is >= key... + if(EASTL_LIKELY(!compare(extractKey(static_cast(pCurrent)->mValue), key))) // If pCurrent is >= key... { pRangeEnd = pCurrent; - pCurrent = (node_type*)pCurrent->mpNodeLeft; + pCurrent = pCurrent->mpNodeLeft; } else { - EASTL_VALIDATE_COMPARE(!compare(key, extractKey(pCurrent->mValue))); // Validate that the compare function is sane. - pCurrent = (node_type*)pCurrent->mpNodeRight; + EASTL_VALIDATE_COMPARE(!compare(key, extractKey(static_cast(pCurrent)->mValue))); // Validate that the compare function is sane. + pCurrent = pCurrent->mpNodeRight; } } @@ -1936,19 +1973,19 @@ namespace eastl { extract_key extractKey; - node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node. - node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now. + rbtree_node_base* pCurrent = mAnchor.mpNodeParent; // Start with the root node. + rbtree_node_base* pRangeEnd = &mAnchor; // set it to the container end for now. while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree. { - if(EASTL_LIKELY(compare(key, extractKey(pCurrent->mValue)))) // If key is < pCurrent... + if(EASTL_LIKELY(compare(key, extractKey(static_cast(pCurrent)->mValue)))) // If key is < pCurrent... { - EASTL_VALIDATE_COMPARE(!compare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!compare(extractKey(static_cast(pCurrent)->mValue), key)); // Validate that the compare function is sane. pRangeEnd = pCurrent; - pCurrent = (node_type*)pCurrent->mpNodeLeft; + pCurrent = pCurrent->mpNodeLeft; } else - pCurrent = (node_type*)pCurrent->mpNodeRight; + pCurrent = pCurrent->mpNodeRight; } return iterator(pRangeEnd); @@ -2229,7 +2266,7 @@ namespace eastl template typename rbtree::node_type* - rbtree::DoCreateNode(const node_type* pNodeSource, node_type* pNodeParent) + rbtree::DoCreateNode(const node_type* pNodeSource, rbtree_node_base* pNodeParent) { node_type* const pNode = DoCreateNode(pNodeSource->mValue); @@ -2243,8 +2280,8 @@ namespace eastl template - typename rbtree::node_type* - rbtree::DoCopySubtree(const node_type* pNodeSource, node_type* pNodeDest) + rbtree_node_base* + rbtree::DoCopySubtree(const node_type* pNodeSource, rbtree_node_base* pNodeDest) { node_type* const pNewNodeRoot = DoCreateNode(pNodeSource, pNodeDest); @@ -2254,13 +2291,13 @@ namespace eastl #endif // Copy the right side of the tree recursively. if(pNodeSource->mpNodeRight) - pNewNodeRoot->mpNodeRight = DoCopySubtree((const node_type*)pNodeSource->mpNodeRight, pNewNodeRoot); + pNewNodeRoot->mpNodeRight = DoCopySubtree(static_cast(pNodeSource->mpNodeRight), pNewNodeRoot); - node_type* pNewNodeLeft; + rbtree_node_base* pNewNodeLeft; - for(pNodeSource = (node_type*)pNodeSource->mpNodeLeft, pNodeDest = pNewNodeRoot; + for(pNodeSource = static_cast(pNodeSource->mpNodeLeft), pNodeDest = pNewNodeRoot; pNodeSource; - pNodeSource = (node_type*)pNodeSource->mpNodeLeft, pNodeDest = pNewNodeLeft) + pNodeSource = static_cast(pNodeSource->mpNodeLeft), pNodeDest = pNewNodeLeft) { pNewNodeLeft = DoCreateNode(pNodeSource, pNodeDest); @@ -2268,7 +2305,7 @@ namespace eastl // Copy the right side of the tree recursively. if(pNodeSource->mpNodeRight) - pNewNodeLeft->mpNodeRight = DoCopySubtree((const node_type*)pNodeSource->mpNodeRight, pNewNodeLeft); + pNewNodeLeft->mpNodeRight = DoCopySubtree(static_cast(pNodeSource->mpNodeRight), pNewNodeLeft); } #if EASTL_EXCEPTIONS_ENABLED } @@ -2284,14 +2321,14 @@ namespace eastl template - void rbtree::DoNukeSubtree(node_type* pNode) + void rbtree::DoNukeSubtree(rbtree_node_base* pNode) { while(pNode) // Recursively traverse the tree and destroy items as we go. { - DoNukeSubtree((node_type*)pNode->mpNodeRight); + DoNukeSubtree(pNode->mpNodeRight); - node_type* const pNodeLeft = (node_type*)pNode->mpNodeLeft; - DoFreeNode(pNode); + node_type* const pNodeLeft = static_cast(pNode->mpNodeLeft); + DoFreeNode(static_cast(pNode)); pNode = pNodeLeft; } } diff --git a/include/EASTL/internal/tuple_fwd_decls.h b/include/EASTL/internal/tuple_fwd_decls.h index a2c773cd..d88163ab 100644 --- a/include/EASTL/internal/tuple_fwd_decls.h +++ b/include/EASTL/internal/tuple_fwd_decls.h @@ -15,19 +15,33 @@ namespace eastl class tuple; template - class tuple_size; + struct tuple_size; + +#if EASTL_VARIABLE_TEMPLATES_ENABLED + template + EA_CONSTEXPR size_t tuple_size_v = tuple_size::value; +#endif template - class tuple_element; + struct tuple_element; template using tuple_element_t = typename tuple_element::type; + template struct is_lvalue_reference; + + template + struct conditional; + + template struct add_lvalue_reference; + + template struct remove_reference; + // const typename for tuple_element_t, for when tuple or TupleImpl cannot itself be const template using const_tuple_element_t = typename conditional< is_lvalue_reference>::value, - add_lvalue_reference_t>>, + typename add_lvalue_reference>::type>::type, const tuple_element_t >::type; diff --git a/include/EASTL/internal/type_compound.h b/include/EASTL/internal/type_compound.h index 339dc8e1..9871f43c 100644 --- a/include/EASTL/internal/type_compound.h +++ b/include/EASTL/internal/type_compound.h @@ -88,7 +88,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // is_array_of_known_bounds // - // Not part of the C++11 Standard. + // Deprecated in C++20. Use is_bounded_array. + // // is_array_of_known_bounds::value is true if T is an array and is // of known bounds. is_array_of_unknown_bounds::value == true, // while is_array_of_unknown_bounds::value = false. @@ -96,14 +97,15 @@ namespace eastl /////////////////////////////////////////////////////////////////////// template - struct is_array_of_known_bounds + struct EASTL_REMOVE_AT_2024_APRIL is_array_of_known_bounds : public eastl::integral_constant::value != 0> {}; /////////////////////////////////////////////////////////////////////// // is_array_of_unknown_bounds // - // Not part of the C++11 Standard. + // Deprecated in C++20. Use is_unbounded_array. + // // is_array_of_unknown_bounds::value is true if T is an array but is // of unknown bounds. is_array_of_unknown_bounds::value == false, // while is_array_of_unknown_bounds::value = true. @@ -111,7 +113,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////// template - struct is_array_of_unknown_bounds + struct EASTL_REMOVE_AT_2024_APRIL is_array_of_unknown_bounds : public eastl::integral_constant::value && (eastl::extent::value == 0)> {}; @@ -218,7 +220,7 @@ namespace eastl template struct is_pointer_helper : public true_type{}; template - struct is_pointer_value : public type_and::value, type_not::value>::value> {}; + struct is_pointer_value : public bool_constant::value && !is_member_pointer::value> {}; template struct is_pointer : public integral_constant::value>{}; @@ -348,7 +350,7 @@ namespace eastl template struct is_union : public false_type{}; #endif - #define EASTL_DECLARE_UNION(T) namespace eastl{ template <> struct is_union : public true_type{}; template <> struct is_union : public true_type{}; } + #define EASTL_DECLARE_UNION(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL is_union : public true_type{}; template <> struct is_union : public true_type{}; } #if EASTL_VARIABLE_TEMPLATES_ENABLED template diff --git a/include/EASTL/internal/type_fundamental.h b/include/EASTL/internal/type_fundamental.h index c99b70cf..f1b3a090 100644 --- a/include/EASTL/internal/type_fundamental.h +++ b/include/EASTL/internal/type_fundamental.h @@ -153,10 +153,10 @@ namespace eastl #define EASTL_DECLARE_INTEGRAL(T) \ namespace eastl{ \ - template <> struct is_integral : public true_type{}; \ - template <> struct is_integral : public true_type{}; \ - template <> struct is_integral : public true_type{}; \ - template <> struct is_integral : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_integral : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_integral : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_integral : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_integral : public true_type{}; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -188,10 +188,10 @@ namespace eastl #define EASTL_DECLARE_FLOATING_POINT(T) \ namespace eastl{ \ - template <> struct is_floating_point : public true_type{}; \ - template <> struct is_floating_point : public true_type{}; \ - template <> struct is_floating_point : public true_type{}; \ - template <> struct is_floating_point : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_floating_point : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_floating_point : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_floating_point : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_floating_point : public true_type{}; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -294,10 +294,12 @@ namespace eastl template struct is_enum_helper2 { + EASTL_INTERNAL_DISABLE_DEPRECATED() typedef type_or::value, is_reference::value, is_class::value> selector; typedef is_enum_helper helper_t; typedef typename add_reference::type ref_t; typedef typename helper_t::template nest result; + EASTL_INTERNAL_RESTORE_DEPRECATED() }; template @@ -314,7 +316,7 @@ namespace eastl EA_CONSTEXPR bool is_enum_v = is_enum::value; #endif - #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct is_enum : public true_type{}; template <> struct is_enum : public true_type{}; } + #define EASTL_DECLARE_ENUM(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL is_enum : public true_type{}; template <> struct EASTL_REMOVE_AT_2024_APRIL is_enum : public true_type{}; } diff --git a/include/EASTL/internal/type_pod.h b/include/EASTL/internal/type_pod.h index fef5511a..0cdf5d5f 100644 --- a/include/EASTL/internal/type_pod.h +++ b/include/EASTL/internal/type_pod.h @@ -2,6 +2,14 @@ // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// +// Implementation Notes: +// The compiler builtins (Clang terminology) and intrinsics (MSVC terminology) are documented here (as of 2023): +// Clang: +// https://clang.llvm.org/docs/LanguageExtensions.html#type-trait-primitives +// GCC: +// https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Type-Traits.html#Type-Traits +// MSVC (no actual documentation, but searchable here): +// https://github.com/microsoft/STL/blob/main/stl/inc/type_traits #ifndef EASTL_INTERNAL_TYPE_POD_H #define EASTL_INTERNAL_TYPE_POD_H @@ -75,14 +83,9 @@ namespace eastl // - T is the type of an array of objects E for which is_pod::value == true // // is_pod may only be applied to complete types. - // - // Without some help from the compiler or user, is_pod will not report - // that a struct or class is a POD, but will correctly report that - // built-in types such as int are PODs. The user can help the compiler - // by using the EASTL_DECLARE_POD macro on a class. /////////////////////////////////////////////////////////////////////// - #if defined(EA_COMPILER_MSVC) + #if defined(EA_COMPILER_MSVC) && !defined(EA_COMPILER_CLANG_CL) #define EASTL_TYPE_TRAIT_is_pod_CONFORMANCE 1 // is_pod is conforming. Actually as of VS2008 it is apparently not fully conforming, as it flags the following as a non-pod: struct Pod{ Pod(){} }; EA_DISABLE_VC_WARNING(4647) @@ -108,16 +111,16 @@ namespace eastl template struct is_POD : public is_pod{}; // Backwards compatibility. - #define EASTL_DECLARE_IS_POD(T, isPod) \ - namespace eastl { \ - template <> struct is_pod : public eastl::integral_constant { }; \ - template <> struct is_pod : public eastl::integral_constant { }; \ - template <> struct is_pod : public eastl::integral_constant { }; \ - template <> struct is_pod : public eastl::integral_constant { }; \ + #define EASTL_DECLARE_IS_POD(T, isPod) \ + namespace eastl { \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_pod : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_pod : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_pod : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_pod : public eastl::integral_constant { }; \ } // Old style macro, for bacwards compatibility: - #define EASTL_DECLARE_POD(T) namespace eastl{ template <> struct is_pod : public true_type{}; template <> struct is_pod : public true_type{}; } + #define EASTL_DECLARE_POD(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL is_pod : public true_type{}; template <> struct EASTL_REMOVE_AT_2024_APRIL is_pod : public true_type{}; } #if EASTL_VARIABLE_TEMPLATES_ENABLED template @@ -147,20 +150,22 @@ namespace eastl #define EASTL_DECLARE_IS_STANDARD_LAYOUT(T, isStandardLayout) \ namespace eastl { \ - template <> struct is_standard_layout : public eastl::integral_constant { }; \ - template <> struct is_standard_layout : public eastl::integral_constant { }; \ - template <> struct is_standard_layout : public eastl::integral_constant { }; \ - template <> struct is_standard_layout : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_standard_layout : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_standard_layout : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_standard_layout : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_standard_layout : public eastl::integral_constant { }; \ } // Old style macro, for bacwards compatibility: - #define EASTL_DECLARE_STANDARD_LAYOUT(T) namespace eastl{ template <> struct is_standard_layout : public true_type{}; template <> struct is_standard_layout : public true_type{}; } + #define EASTL_DECLARE_STANDARD_LAYOUT(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL is_standard_layout : public true_type{}; template <> struct EASTL_REMOVE_AT_2024_APRIL is_standard_layout : public true_type{}; } /////////////////////////////////////////////////////////////////////// // has_trivial_constructor // + // Deprecated. Use is_trivially_default_constructible for the std conforming alternative. + // // has_trivial_constructor::value == true if and only if T is a class // or struct that has a trivial constructor. A constructor is trivial if // - it is implicitly defined by the compiler, and @@ -186,27 +191,32 @@ namespace eastl #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. template - struct has_trivial_constructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_constructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(__clang__) && EASTL_HAS_INTRINSIC(is_trivially_constructible) + #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. + + template + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_constructor : public eastl::integral_constant::value>{}; #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 1 // has_trivial_constructor is conforming. template - struct has_trivial_constructor : public eastl::integral_constant::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_constructor : public eastl::integral_constant::value>{}; #else #define EASTL_TYPE_TRAIT_has_trivial_constructor_CONFORMANCE 0 // has_trivial_constructor is not fully conforming. Can return false negatives. // With current compilers, this is all we can do. template - struct has_trivial_constructor : public eastl::is_pod {}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_constructor : public eastl::is_pod {}; #endif #define EASTL_DECLARE_HAS_TRIVIAL_CONSTRUCTOR(T, hasTrivialConstructor) \ namespace eastl { \ - template <> struct has_trivial_constructor : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_constructor : public eastl::integral_constant { }; \ } // Old style macro, for bacwards compatibility: - #define EASTL_DECLARE_TRIVIAL_CONSTRUCTOR(T) namespace eastl{ template <> struct has_trivial_constructor : public true_type{}; template <> struct has_trivial_constructor : public true_type{}; } + #define EASTL_DECLARE_TRIVIAL_CONSTRUCTOR(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_constructor : public true_type{}; template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_constructor : public true_type{}; } @@ -214,6 +224,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // has_trivial_copy // + // Deprecated. Use is_trivially_copy_constructible for the std conforming alternative. + // // has_trivial_copy::value == true if and only if T is a class or // struct that has a trivial copy constructor. A copy constructor is // trivial if @@ -246,26 +258,31 @@ namespace eastl #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. template - struct has_trivial_copy : public eastl::integral_constant::value) && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_copy : public eastl::integral_constant::value) && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(__clang__) && EASTL_HAS_INTRINSIC(is_trivially_copyable) + #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. + + template + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_copy : public eastl::integral_constant::value) && (!eastl::is_volatile::value && !eastl::is_reference::value)>{}; #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 1 // has_trivial_copy is conforming. template - struct has_trivial_copy : public eastl::integral_constant::value) && (!eastl::is_volatile::value && !eastl::is_reference::value)>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_copy : public eastl::integral_constant::value) && (!eastl::is_volatile::value && !eastl::is_reference::value)>{}; #else #define EASTL_TYPE_TRAIT_has_trivial_copy_CONFORMANCE 0 // has_trivial_copy is not fully conforming. Can return false negatives. template - struct has_trivial_copy : public eastl::integral_constant::value && !eastl::is_volatile::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_copy : public eastl::integral_constant::value && !eastl::is_volatile::value>{}; #endif #define EASTL_DECLARE_HAS_TRIVIAL_COPY(T, hasTrivialCopy) \ namespace eastl { \ - template <> struct has_trivial_copy : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_copy : public eastl::integral_constant { }; \ } // Old style macro, for bacwards compatibility: - #define EASTL_DECLARE_TRIVIAL_COPY(T) namespace eastl{ template <> struct has_trivial_copy : public true_type{}; template <> struct has_trivial_copy : public true_type{}; } + #define EASTL_DECLARE_TRIVIAL_COPY(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_copy : public true_type{}; template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_copy : public true_type{}; } @@ -273,6 +290,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // has_trivial_assign // + // Deprecated. Use is_trivially_assignable, is_trivially_move_assignable or is_trivially_copy_assignable as a std conforming alternative. + // // has_trivial_assign::value == true if and only if T is a class or // struct that has a trivial copy assignment operator. A copy assignment // operator is trivial if: @@ -296,28 +315,33 @@ namespace eastl #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. template - struct has_trivial_assign : public integral_constant::value) && !eastl::is_const::value && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_assign : public integral_constant::value) && !eastl::is_const::value && !eastl::is_volatile::value && !eastl::is_hat_type::value>{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(__clang__) && EASTL_HAS_INTRINSIC(is_trivially_assignable) + #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. + + template + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_assign : public integral_constant::type, typename add_lvalue_reference::type) || eastl::is_pod::value) && !eastl::is_const::value && !eastl::is_volatile::value>{}; #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming. template - struct has_trivial_assign : public integral_constant::value) && !eastl::is_const::value && !eastl::is_volatile::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_assign : public integral_constant::value) && !eastl::is_const::value && !eastl::is_volatile::value>{}; #else #define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 0 // is_pod is not fully conforming. Can return false negatives. template - struct has_trivial_assign : public integral_constant::value && !is_const::value && !is_volatile::value >{}; #endif #define EASTL_DECLARE_HAS_TRIVIAL_ASSIGN(T, hasTrivialAssign) \ namespace eastl { \ - template <> struct has_trivial_assign : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_assign : public eastl::integral_constant { }; \ } // Old style macro, for bacwards compatibility: - #define EASTL_DECLARE_TRIVIAL_ASSIGN(T) namespace eastl{ template <> struct has_trivial_assign : public true_type{}; template <> struct has_trivial_assign : public true_type{}; } + #define EASTL_DECLARE_TRIVIAL_ASSIGN(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_assign : public true_type{}; template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_assign : public true_type{}; } @@ -325,6 +349,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // has_trivial_destructor // + // Deprecated. Use is_trivially_destructible for the std conforming alternative. + // // has_trivial_destructor::value == true if and only if T is a class // or struct that has a trivial destructor. A destructor is trivial if // - it is implicitly defined by the compiler, and @@ -340,36 +366,43 @@ namespace eastl // report that a class or struct has a trivial destructor. // The user can use EASTL_DECLARE_TRIVIAL_DESTRUCTOR to help the compiler. /////////////////////////////////////////////////////////////////////// - + + EASTL_INTERNAL_DISABLE_DEPRECATED() #if defined(_MSC_VER) && (_MSC_VER >= 1600) && !defined(EA_COMPILER_CLANG_CL) #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. template - struct has_trivial_destructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_destructor : public eastl::integral_constant::value) && !eastl::is_hat_type::value>{}; + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(__clang__) && EASTL_HAS_INTRINSIC(is_trivially_destructible) + #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. + + template + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_destructor : public eastl::integral_constant::value>{}; #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming. template - struct has_trivial_destructor : public eastl::integral_constant::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_destructor : public eastl::integral_constant::value>{}; #else #define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 0 // is_pod is not fully conforming. Can return false negatives. // With current compilers, this is all we can do. template - struct has_trivial_destructor : public eastl::is_pod{}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_destructor : public eastl::is_pod{}; #endif + EASTL_INTERNAL_RESTORE_DEPRECATED() #define EASTL_DECLARE_HAS_TRIVIAL_DESTRUCTOR(T, hasTrivialDestructor) \ namespace eastl { \ - template <> struct has_trivial_destructor : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_destructor : public eastl::integral_constant { }; \ } // Old style macro, for bacwards compatibility: - #define EASTL_DECLARE_TRIVIAL_DESTRUCTOR(T) namespace eastl{ template <> struct has_trivial_destructor : public true_type{}; template <> struct has_trivial_destructor : public true_type{}; } + #define EASTL_DECLARE_TRIVIAL_DESTRUCTOR(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_destructor : public true_type{}; template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_destructor : public true_type{}; } #if EASTL_VARIABLE_TEMPLATES_ENABLED template - EA_CONSTEXPR bool has_trivial_destructor_v = has_trivial_destructor::value; + EASTL_REMOVE_AT_2024_APRIL EA_CONSTEXPR bool has_trivial_destructor_v = has_trivial_destructor::value; #endif @@ -381,6 +414,8 @@ namespace eastl // move functionality supercedes this functionality and we want to // migrate away from it in the future. // + // Deprecated. Use is_trivially_copyable for the std conforming alternative. + // // A trivially relocatable object is one that can be safely memmove'd // to uninitialized memory. construction, assignment, and destruction // properties are not addressed by this trait. A type that has the @@ -390,14 +425,17 @@ namespace eastl // trait, but this is not strictly guaranteed. // // The user can use EASTL_DECLARE_TRIVIAL_RELOCATE to help the compiler. + // /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_has_trivial_relocate_CONFORMANCE 0 // is_pod is not fully conforming. Can return false negatives. + EASTL_INTERNAL_DISABLE_DEPRECATED() template - struct has_trivial_relocate : public eastl::bool_constant && !eastl::is_volatile_v> {}; + struct EASTL_REMOVE_AT_2024_APRIL has_trivial_relocate : public eastl::bool_constant && !eastl::is_volatile_v> {}; + EASTL_INTERNAL_RESTORE_DEPRECATED() - #define EASTL_DECLARE_TRIVIAL_RELOCATE(T) namespace eastl{ template <> struct has_trivial_relocate : public true_type{}; template <> struct has_trivial_relocate : public true_type{}; } + #define EASTL_DECLARE_TRIVIAL_RELOCATE(T) namespace eastl{ template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_relocate : public true_type{}; template <> struct EASTL_REMOVE_AT_2024_APRIL has_trivial_relocate : public true_type{}; } @@ -405,6 +443,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // has_nothrow_constructor // + // Deprecated. Use is_nothrow_constructible::value for the std conforming alternative. + // // has_nothrow_constructor::value == true if and only if T is a // class or struct whose default constructor has an empty throw specification. // @@ -412,11 +452,18 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(__clang__) && EASTL_HAS_INTRINSIC(is_nothrow_constructible) #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 1 template - struct has_nothrow_constructor + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_constructor + : public eastl::integral_constant{}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 1 + + template + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_constructor : public eastl::integral_constant{}; #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(_MSC_VER) @@ -425,19 +472,19 @@ namespace eastl #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 0 template // This is mistakenly returning true for an unbounded array of scalar type. - struct has_nothrow_constructor : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_constructor : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; #else #define EASTL_TYPE_TRAIT_has_nothrow_constructor_CONFORMANCE 0 // has_nothrow_constructor is not fully conforming. Can return false negatives. template - struct has_nothrow_constructor // To do: Improve this to include other types that can work. + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_constructor // To do: Improve this to include other types that can work. { static const bool value = eastl::is_scalar::type>::value || eastl::is_reference::value; }; #endif #define EASTL_DECLARE_HAS_NOTHROW_CONSTRUCTOR(T, hasNothrowConstructor) \ namespace eastl { \ - template <> struct has_nothrow_constructor : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_constructor : public eastl::integral_constant { }; \ } @@ -445,6 +492,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // has_nothrow_copy // + // Deprecated. Use is_nothrow_copy_constructible for the std conforming alternative. + // // has_nothrow_copy::value == true if and only if T is a class or // struct whose copy constructor has an empty throw specification. // @@ -452,11 +501,17 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(__clang__) && EASTL_HAS_INTRINSIC(is_nothrow_constructible) + #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 1 + + template + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_copy : public eastl::integral_constant::type)>{}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 1 template - struct has_nothrow_copy : public eastl::integral_constant{}; + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_copy : public eastl::integral_constant{}; #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(_MSC_VER) // Microsoft's implementation of __has_nothrow_copy is crippled and returns true only if T is a class that has a copy constructor. @@ -464,19 +519,19 @@ namespace eastl #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 0 template - struct has_nothrow_copy : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_copy : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; #else #define EASTL_TYPE_TRAIT_has_nothrow_copy_CONFORMANCE 0 // has_nothrow_copy is not fully conforming. Can return false negatives. template - struct has_nothrow_copy // To do: Improve this to include other types that can work. + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_copy // To do: Improve this to include other types that can work. { static const bool value = eastl::is_scalar::type>::value || eastl::is_reference::value; }; #endif #define EASTL_DECLARE_HAS_NOTHROW_COPY(T, hasNothrowCopy) \ namespace eastl { \ - template <> struct has_nothrow_copy : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_copy : public eastl::integral_constant { }; \ } @@ -484,6 +539,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // has_nothrow_assign // + // Deprecated. Use is_nothrow_assignable::value for the std conforming alternative. + // // has_nothrow_assign::value == true if and only if T is a class or // struct whose copy assignment operator has an empty throw specification. // @@ -491,11 +548,17 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(__clang__) && EASTL_HAS_INTRINSIC(is_nothrow_assignable) + #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 1 + + template + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_assign : public eastl::integral_constant::type, typename eastl::add_lvalue_reference::type)>{}; + + #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(EA_COMPILER_GNUC) || defined(__clang__)) #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 1 template - struct has_nothrow_assign : public eastl::integral_constant{}; + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_assign : public eastl::integral_constant{}; #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && defined(_MSC_VER) // Microsoft's implementation of __has_nothrow_assign is crippled and returns true only if T is a class that has an assignment operator. @@ -503,18 +566,18 @@ namespace eastl #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 0 template // This is mistakenly returning true for an unbounded array of scalar type. - struct has_nothrow_assign : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_assign : public eastl::integral_constant::type>::value || eastl::is_reference::value>{}; #else #define EASTL_TYPE_TRAIT_has_nothrow_assign_CONFORMANCE 0 // has_nothrow_assign is not fully conforming. Can return false negatives. template - struct has_nothrow_assign // To do: Improve this to include other types that can work. + struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_assign // To do: Improve this to include other types that can work. { static const bool value = eastl::is_scalar::type>::value || eastl::is_reference::value; } ; #endif #define EASTL_DECLARE_HAS_NOTHROW_ASSIGN(T, hasNothrowAssign) \ namespace eastl { \ - template <> struct has_nothrow_assign : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_nothrow_assign : public eastl::integral_constant { }; \ } @@ -548,16 +611,23 @@ namespace eastl #define EASTL_DECLARE_HAS_VIRTUAL_DESTRUCTOR(T, hasVirtualDestructor) \ namespace eastl { \ - template <> struct has_virtual_destructor : public eastl::integral_constant { }; \ - template <> struct has_virtual_destructor : public eastl::integral_constant { }; \ - template <> struct has_virtual_destructor : public eastl::integral_constant { }; \ - template <> struct has_virtual_destructor : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_virtual_destructor : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_virtual_destructor : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_virtual_destructor : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL has_virtual_destructor : public eastl::integral_constant { }; \ } /////////////////////////////////////////////////////////////////////// // is_literal_type // + // Deprecated in C++17. Removed from the standard in C++20. + // + // From https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0174r2.html: + // The is_literal type trait offers negligible value to generic code, as what is really needed is the ability to know + // that a specific construction would produce constant initialization. The core term of a literal type having at least + // one constexpr constructor is too weak to be used meaningfully. + // // See the C++11 Standard, section 2.9,p10. // A type is a literal type if it is: // - a scalar type; or @@ -575,7 +645,7 @@ namespace eastl #define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 1 template - struct is_literal_type : public eastl::integral_constant{}; + struct EASTL_REMOVE_AT_2024_APRIL is_literal_type : public eastl::integral_constant{}; #elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)) || (defined(_MSC_VER) && (_MSC_VER >= 1700))) // VS2012+ #if defined(EA_COMPILER_GNUC) && (!defined(EA_COMPILER_CPP11_ENABLED) || (EA_COMPILER_VERSION < 4007)) @@ -585,7 +655,7 @@ namespace eastl #endif template - struct is_literal_type : public eastl::integral_constant{}; + struct EASTL_REMOVE_AT_2024_APRIL is_literal_type : public eastl::integral_constant{}; #else #define EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE 0 @@ -596,12 +666,14 @@ namespace eastl // while false positives are not OK for us to generate. template // This is not a complete implementation and will be true for only some literal types (the basic ones). - struct is_literal_type : public eastl::integral_constant::type>::type>::value>{}; + struct EASTL_REMOVE_AT_2024_APRIL is_literal_type : public eastl::integral_constant::type>::type>::value>{}; #endif #if EASTL_VARIABLE_TEMPLATES_ENABLED + EASTL_INTERNAL_DISABLE_DEPRECATED() // '*': was declared deprecated template - EA_CONSTEXPR bool is_literal_type_v = is_literal_type::value; + EASTL_REMOVE_AT_2024_APRIL EA_CONSTEXPR bool is_literal_type_v = is_literal_type::value; + EASTL_INTERNAL_RESTORE_DEPRECATED() #endif @@ -648,10 +720,10 @@ namespace eastl #define EASTL_DECLARE_IS_ABSTRACT(T, isAbstract) \ namespace eastl { \ - template <> struct is_abstract : public eastl::integral_constant { }; \ - template <> struct is_abstract : public eastl::integral_constant { }; \ - template <> struct is_abstract : public eastl::integral_constant { }; \ - template <> struct is_abstract : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_abstract : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_abstract : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_abstract : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_abstract : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -710,10 +782,10 @@ namespace eastl #define EASTL_DECLARE_IS_TRIVIALLY_COPYABLE(T, isTriviallyCopyable) \ namespace eastl { \ - template <> struct is_trivially_copyable : public eastl::integral_constant { }; \ - template <> struct is_trivially_copyable : public eastl::integral_constant { }; \ - template <> struct is_trivially_copyable : public eastl::integral_constant { }; \ - template <> struct is_trivially_copyable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_copyable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_copyable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_copyable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_copyable : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -755,18 +827,22 @@ namespace eastl template eastl::false_type is(argument_sink, Args&& ...); + EASTL_INTERNAL_DISABLE_DEPRECATED() // Except for scalars and references (handled below), check for constructibility via decltype. template struct is_constructible_helper_2 // argument_sink will catch all T that is not constructible from the Args and denote false_type : public eastl::identity(), eastl::declval()...))>::type {}; + EASTL_INTERNAL_RESTORE_DEPRECATED() template struct is_constructible_helper_2 : public eastl::is_scalar {}; + EASTL_INTERNAL_DISABLE_DEPRECATED() template // We handle the case of multiple arguments below (by disallowing them). struct is_constructible_helper_2 : public eastl::identity::can(eastl::declval()))>::type {}; + EASTL_INTERNAL_RESTORE_DEPRECATED() // Scalars and references can be constructed only with 0 or 1 argument. e.g the following is an invalid expression: int(17, 23) template @@ -782,6 +858,7 @@ namespace eastl struct is_constructible_helper_1 : public false_type {}; + EASTL_INTERNAL_DISABLE_DEPRECATED() // is_constructible template struct is_constructible @@ -790,6 +867,7 @@ namespace eastl eastl::is_function::type>::value || eastl::has_void_arg::value), T, Args...> {}; + EASTL_INTERNAL_RESTORE_DEPRECATED() // Array types are constructible if constructed with no arguments and if their element type is default-constructible template @@ -807,7 +885,7 @@ namespace eastl // You need to manually declare const/volatile variants individually if you want them. #define EASTL_DECLARE_IS_CONSTRUCTIBLE(T, U, isConstructible) \ namespace eastl { \ - template <> struct is_constructible : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_constructible : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -968,10 +1046,10 @@ namespace eastl #define EASTL_DECLARE_IS_TRIVIALLY_CONSTRUCTIBLE(T, isTriviallyConstructible) \ namespace eastl { \ - template <> struct is_trivially_constructible : public eastl::integral_constant { }; \ - template <> struct is_trivially_constructible : public eastl::integral_constant { }; \ - template <> struct is_trivially_constructible : public eastl::integral_constant { }; \ - template <> struct is_trivially_constructible : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_constructible : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_constructible : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_constructible : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_constructible : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -984,7 +1062,7 @@ namespace eastl // is_trivially_default_constructible // // is_trivially_constructible::value is true. - // This is thus identical to is_trivially_constructible. + // This is thus identical to is_trivially_constructible::value. /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_is_trivially_default_constructible_CONFORMANCE EASTL_TYPE_TRAIT_is_trivially_constructible_CONFORMANCE @@ -1074,6 +1152,8 @@ namespace eastl : public eastl::integral_constant::value> {}; #else + // could use __is_nothrow_constructible(T, Args...), if available, instead of this implementation. + #if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION < 4008) #define EASTL_TYPE_TRAIT_is_nothrow_constructible_CONFORMANCE 0 // GCC up to v4.7's noexcept is broken and fails to generate true for the case of compiler-generated constructors. #else @@ -1127,7 +1207,7 @@ namespace eastl #define EASTL_DECLARE_IS_NOTHROW_CONSTRUCTIBLE(T, isNothrowConstructible) \ namespace eastl{ \ - template <> struct is_nothrow_constructible : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_constructible : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -1154,14 +1234,6 @@ namespace eastl #endif - - /////////////////////////////////////////////////////////////////////// - // is_nothrow_default_constructible - /////////////////////////////////////////////////////////////////////// - // TODO(rparolin): implement type-trait - - - /////////////////////////////////////////////////////////////////////// // is_copy_constructible // @@ -1250,7 +1322,7 @@ namespace eastl #define EASTL_DECLARE_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE(T, isTrivallyMoveConstructible) \ namespace eastl{ \ - template <> struct is_trivially_move_constructible : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_move_constructible : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -1335,7 +1407,7 @@ namespace eastl // #define EASTL_DECLARE_IS_ASSIGNABLE(T, U, isAssignable) \ namespace eastl { \ - template <> struct is_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_assignable : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -1347,6 +1419,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // is_lvalue_assignable + // + // Deprecated. Use is_copy_assignable instead. // // This is an EASTL extension function which is like is_assignable but // works for arbitrary assignments and not just rvalue assignments. @@ -1360,13 +1434,13 @@ namespace eastl #define EASTL_TYPE_TRAIT_is_lvalue_assignable_CONFORMANCE EASTL_TYPE_TRAIT_is_assignable_CONFORMANCE template - struct is_lvalue_assignable + struct EASTL_REMOVE_AT_2024_APRIL is_lvalue_assignable : public eastl::is_assignable::type, typename eastl::add_lvalue_reference::type>::type> {}; #define EASTL_DECLARE_IS_LVALUE_ASSIGNABLE(T, U, isLvalueAssignable) \ namespace eastl { \ - template <> struct is_lvalue_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_lvalue_assignable : public eastl::integral_constant { }; \ } @@ -1457,7 +1531,7 @@ namespace eastl // #define EASTL_DECLARE_IS_TRIVIALLY_ASSIGNABLE(T, U, isTriviallyAssignable) \ namespace eastl { \ - template <> struct is_trivially_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_assignable : public eastl::integral_constant { }; \ } @@ -1523,10 +1597,10 @@ namespace eastl #define EASTL_DECLARE_IS_NOTHROW_ASSIGNABLE(T, isNothrowAssignable) \ namespace eastl{ \ - template <> struct is_nothrow_assignable : public eastl::integral_constant { }; \ - template <> struct is_nothrow_assignable : public eastl::integral_constant { }; \ - template <> struct is_nothrow_assignable : public eastl::integral_constant { }; \ - template <> struct is_nothrow_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_assignable : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -1587,7 +1661,7 @@ namespace eastl #define EASTL_DECLARE_IS_TRIVIALLY_COPY_ASSIGNABLE(T, isTriviallyCopyAssignable) \ namespace eastl { \ - template <> struct is_trivially_copy_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_copy_assignable : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -1629,10 +1703,10 @@ namespace eastl #define EASTL_DECLARE_IS_MOVE_ASSIGNABLE(T, isMoveAssignable) \ namespace eastl{ \ - template <> struct is_move_assignable : public eastl::integral_constant { }; \ - template <> struct is_move_assignable : public eastl::integral_constant { }; \ - template <> struct is_move_assignable : public eastl::integral_constant { }; \ - template <> struct is_move_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_move_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_move_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_move_assignable : public eastl::integral_constant { }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_move_assignable : public eastl::integral_constant { }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -1706,11 +1780,13 @@ namespace eastl // user needs to use EASTL_DECLARE_IS_NOT_DESTRUCTIBLE to cause is_destructible::value // to be false. + EASTL_INTERNAL_DISABLE_DEPRECATED() template struct is_destructible : public eastl::integral_constant::value && !eastl::is_void::value && !eastl::is_function::value> {}; + EASTL_INTERNAL_RESTORE_DEPRECATED() #else #define EASTL_TYPE_TRAIT_is_destructible_CONFORMANCE 1 @@ -1720,11 +1796,13 @@ namespace eastl template ::type, typename V = decltype(eastl::declval().~U())> eastl::true_type destructible_test_function(int); + EASTL_INTERNAL_DISABLE_DEPRECATED() template ::value || // Exclude these types from being considered destructible. eastl::is_void::value || eastl::is_function::value> struct is_destructible_helper : public eastl::identity(0))>::type {}; // Need to wrap decltype with identity because some compilers otherwise don't like the bare decltype usage. + EASTL_INTERNAL_RESTORE_DEPRECATED() template struct is_destructible_helper @@ -1751,10 +1829,10 @@ namespace eastl #define EASTL_DECLARE_IS_DESTRUCTIBLE(T, isDestructible) \ namespace eastl{ \ - template <> struct is_destructible : public eastl::integral_constant{}; \ - template <> struct is_destructible : public eastl::integral_constant{}; \ - template <> struct is_destructible : public eastl::integral_constant{}; \ - template <> struct is_destructible : public eastl::integral_constant{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_destructible : public eastl::integral_constant{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_destructible : public eastl::integral_constant{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_destructible : public eastl::integral_constant{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_destructible : public eastl::integral_constant{}; \ } @@ -1774,7 +1852,7 @@ namespace eastl // /////////////////////////////////////////////////////////////////////// - #if defined(_MSC_VER) && (_MSC_VER >= 1920) + #if EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && ((defined(_MSC_VER) && (_MSC_VER >= 1920)) || (defined(__clang__) && EASTL_HAS_INTRINSIC(is_trivially_destructible))) #define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE 1 template @@ -1802,10 +1880,10 @@ namespace eastl #define EASTL_DECLARE_IS_TRIVIALLY_DESTRUCTIBLE(T, isTriviallyDestructible) \ namespace eastl{ \ - template <> struct is_trivially_destructible : public eastl::integral_constant{}; \ - template <> struct is_trivially_destructible : public eastl::integral_constant{}; \ - template <> struct is_trivially_destructible : public eastl::integral_constant{}; \ - template <> struct is_trivially_destructible : public eastl::integral_constant{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_destructible : public eastl::integral_constant{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_destructible : public eastl::integral_constant{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_destructible : public eastl::integral_constant{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_trivially_destructible : public eastl::integral_constant{}; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED @@ -1897,10 +1975,10 @@ namespace eastl #define EASTL_DECLARE_IS_NOTHROW_DESTRUCTIBLE(T, isNoThrowDestructible) \ namespace eastl{ \ - template <> struct is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ - template <> struct is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ - template <> struct is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ - template <> struct is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_nothrow_destructible { static const bool value = isNoThrowDestructible; }; \ } #if EASTL_VARIABLE_TEMPLATES_ENABLED diff --git a/include/EASTL/internal/type_properties.h b/include/EASTL/internal/type_properties.h index 78bdfcaf..0ea2fef5 100644 --- a/include/EASTL/internal/type_properties.h +++ b/include/EASTL/internal/type_properties.h @@ -107,9 +107,6 @@ namespace eastl // is_signed::value == true if T is a (possibly cv-qualified) floating-point or signed integer type. // // Used to determine if a type is signed. - // Given that there are some user-made classes which emulate integral - // types, we provide the EASTL_DECLARE_SIGNED macro to allow you to - // set a given class to be identified as a signed type. /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_is_signed_CONFORMANCE 1 // is_signed is conforming. @@ -137,10 +134,10 @@ namespace eastl #define EASTL_DECLARE_SIGNED(T) \ namespace eastl{ \ - template <> struct is_signed : public true_type{}; \ - template <> struct is_signed : public true_type{}; \ - template <> struct is_signed : public true_type{}; \ - template <> struct is_signed : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_signed : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_signed : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_signed : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_signed : public true_type{}; \ } @@ -151,9 +148,6 @@ namespace eastl // is_unsigned::value == true if T is a (possibly cv-qualified) bool or unsigned integer type. // // Used to determine if a type is unsigned. - // Given that there are some user-made classes which emulate integral - // types, we provide the EASTL_DECLARE_UNSIGNED macro to allow you to - // set a given class to be identified as an unsigned type. /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_is_unsigned_CONFORMANCE 1 // is_unsigned is conforming. @@ -181,10 +175,10 @@ namespace eastl #define EASTL_DECLARE_UNSIGNED(T) \ namespace eastl{ \ - template <> struct is_unsigned : public true_type{}; \ - template <> struct is_unsigned : public true_type{}; \ - template <> struct is_unsigned : public true_type{}; \ - template <> struct is_unsigned : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_unsigned : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_unsigned : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_unsigned : public true_type{}; \ + template <> struct EASTL_REMOVE_AT_2024_APRIL is_unsigned : public true_type{}; \ } /////////////////////////////////////////////////////////////////////// @@ -373,13 +367,17 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // result_of // + // Deprecated in C++17. + // + // Use invoke_result instead. + // See https://en.cppreference.com/w/cpp/types/result_of#Notes for an explanation of issues with result_of. /////////////////////////////////////////////////////////////////////// #define EASTL_TYPE_TRAIT_result_of_CONFORMANCE 1 // result_of is conforming. - template struct result_of; + template struct EASTL_REMOVE_AT_2024_APRIL result_of; template - struct result_of + struct EASTL_REMOVE_AT_2024_APRIL result_of { typedef decltype(eastl::declval()(eastl::declval()...)) type; }; @@ -389,7 +387,7 @@ namespace eastl #define EASTL_RESULT_OF_T(T) typename result_of::type #else template - using result_of_t = typename result_of::type; + using result_of_t EASTL_REMOVE_AT_2024_APRIL = typename result_of::type; #define EASTL_RESULT_OF_T(T) result_of_t #endif diff --git a/include/EASTL/internal/type_transformations.h b/include/EASTL/internal/type_transformations.h index 5454cfad..cacf0b39 100644 --- a/include/EASTL/internal/type_transformations.h +++ b/include/EASTL/internal/type_transformations.h @@ -260,12 +260,12 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // add_signed // - // This is not a C++11 type trait, and is here for backwards compatibility + // Deprecated. This is not a C++11 type trait, and is here for backwards compatibility // only. Use the C++11 make_unsigned type trait instead. /////////////////////////////////////////////////////////////////////// template - struct add_signed : public make_signed + struct EASTL_REMOVE_AT_2024_APRIL add_signed : public make_signed { typedef typename eastl::make_signed::type type; }; @@ -431,7 +431,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // add_unsigned // - // This is not a C++11 type trait, and is here for backwards compatibility + // Deprecated. This is not a C++11 type trait, and is here for backwards compatibility // only. Use the C++11 make_unsigned type trait instead. // // Adds unsigned-ness to the given type. @@ -442,7 +442,7 @@ namespace eastl /////////////////////////////////////////////////////////////////////// template - struct add_unsigned : public make_unsigned + struct EASTL_REMOVE_AT_2024_APRIL add_unsigned : public make_unsigned { typedef typename eastl::make_signed::type type; }; @@ -559,6 +559,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // aligned_storage + // + // Deprecated in C++23. // // The aligned_storage transformation trait provides a type that is // suitably aligned to store an object whose size is does not exceed length @@ -651,6 +653,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // aligned_union + // + // Deprecated in C++23. // // The member typedef type shall be a POD type suitable for use as // uninitialized storage for any object whose type is listed in Types; diff --git a/include/EASTL/intrusive_list.h b/include/EASTL/intrusive_list.h index dc0129f3..d919b723 100644 --- a/include/EASTL/intrusive_list.h +++ b/include/EASTL/intrusive_list.h @@ -94,6 +94,9 @@ namespace eastl { + template + class intrusive_list; + /// intrusive_list_node /// /// By design this must be a POD, as user structs will be inheriting from @@ -108,7 +111,7 @@ namespace eastl #if EASTL_VALIDATE_INTRUSIVE_LIST intrusive_list_node() // Implemented inline because GCC can't deal with member functions { // of may-alias classes being defined outside the declaration. - mpNext = mpPrev = NULL; + mpNext = mpPrev = nullptr; } ~intrusive_list_node() @@ -134,29 +137,83 @@ namespace eastl typedef intrusive_list_iterator const_iterator; typedef T value_type; typedef T node_type; + typedef intrusive_list_node base_node_type; typedef ptrdiff_t difference_type; typedef Pointer pointer; typedef Reference reference; typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category; - +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + private: + base_node_type* mpNode; +#else public: - pointer mpNode; // Needs to be public for operator==() to work + pointer mpNode; +#endif public: intrusive_list_iterator(); - explicit intrusive_list_iterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type. + + // Note: you can also construct an iterator from T* via this, since T should inherit from + // intrusive_list_node. + explicit intrusive_list_iterator(const base_node_type* pNode); + // Note: this isn't always a copy constructor, iterator is not always equal to this_type intrusive_list_iterator(const iterator& x); + // Note: this isn't always a copy assignment operator, iterator is not always equal to this_type intrusive_list_iterator& operator=(const iterator& x); + // Calling these on the end() of a list invokes undefined behavior. reference operator*() const; pointer operator->() const; + // Returns a pointer to the fully typed node (the same as operator->) this is useful when + // iterating a list to destroy all the nodes, calling this on the end() of a list results in + // undefined behavior. + pointer nodePtr() const; + intrusive_list_iterator& operator++(); intrusive_list_iterator& operator--(); intrusive_list_iterator operator++(int); intrusive_list_iterator operator--(int); + // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. + // Thus we provide additional template paremeters here to support this. The defect report does not + // require us to support comparisons between reverse_iterators and const_reverse_iterators. + template + bool operator==(const intrusive_list_iterator& other) const + { + return mpNode == other.mpNode; + } + + template + inline bool operator!=(const intrusive_list_iterator& other) const + { + return mpNode != other.mpNode; + } + + // We provide a version of operator!= for the case where the iterators are of the + // same type. This helps prevent ambiguity errors in the presence of rel_ops. + inline bool operator!=(const intrusive_list_iterator other) const { return mpNode != other.mpNode; } + + private: + + // This is a temp helper function for the deprecation. + // It should be removed when the deprecation window ends. +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + base_node_type* toInternalNodeType(base_node_type* node) { return node; } +#else + pointer toInternalNodeType(base_node_type* node) { return static_cast(node); } +#endif + + // for the "copy" constructor, which uses non-const iterator even in the + // const_iterator case. Also, some of the internal member functions in + // intrusive_list want to use mpNode. + friend const_iterator; + friend intrusive_list; + + // for the comparison operators. + template + friend class intrusive_list_iterator; }; // class intrusive_list_iterator @@ -312,6 +369,17 @@ namespace eastl // bool validate() const; // Inherited from parent. int validate_iterator(const_iterator i) const; + private: + // This is a helper function to assist with the deprecation, + // it should be removed after the deprecation window ends. +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + intrusive_list_node* toListNode(intrusive_list_node* node) { return node; } +#else + intrusive_list_node* toListNode(const node_type* node) + { + return static_cast(const_cast(node)); + } +#endif }; // intrusive_list @@ -328,7 +396,7 @@ namespace eastl // #if EASTL_VALIDATE_INTRUSIVE_LIST // inline intrusive_list_node::intrusive_list_node() // { - // mpNext = mpPrev = NULL; + // mpNext = mpPrev = nullptr; // } // // inline intrusive_list_node::~intrusive_list_node() @@ -349,14 +417,14 @@ namespace eastl inline intrusive_list_iterator::intrusive_list_iterator() { #if EASTL_DEBUG - mpNode = NULL; + mpNode = nullptr; #endif } template - inline intrusive_list_iterator::intrusive_list_iterator(pointer pNode) - : mpNode(pNode) + inline intrusive_list_iterator::intrusive_list_iterator(const base_node_type* pNode) + : mpNode(toInternalNodeType(const_cast(pNode))) { // Empty } @@ -381,7 +449,7 @@ namespace eastl inline typename intrusive_list_iterator::reference intrusive_list_iterator::operator*() const { - return *mpNode; + return *static_cast(mpNode); } @@ -389,7 +457,14 @@ namespace eastl inline typename intrusive_list_iterator::pointer intrusive_list_iterator::operator->() const { - return mpNode; + return static_cast(mpNode); + } + + template + inline typename intrusive_list_iterator::pointer + intrusive_list_iterator::nodePtr() const + { + return static_cast(mpNode); } @@ -397,7 +472,7 @@ namespace eastl inline typename intrusive_list_iterator::this_type& intrusive_list_iterator::operator++() { - mpNode = static_cast(mpNode->mpNext); + mpNode = toInternalNodeType(mpNode->mpNext); return *this; } @@ -407,7 +482,7 @@ namespace eastl intrusive_list_iterator::operator++(int) { intrusive_list_iterator it(*this); - mpNode = static_cast(mpNode->mpNext); + mpNode = toInternalNodeType(mpNode->mpNext); return it; } @@ -416,7 +491,7 @@ namespace eastl inline typename intrusive_list_iterator::this_type& intrusive_list_iterator::operator--() { - mpNode = static_cast(mpNode->mpPrev); + mpNode = toInternalNodeType(mpNode->mpPrev); return *this; } @@ -426,42 +501,10 @@ namespace eastl intrusive_list_iterator::operator--(int) { intrusive_list_iterator it(*this); - mpNode = static_cast(mpNode->mpPrev); + mpNode = toInternalNodeType(mpNode->mpPrev); return it; } - - // The C++ defect report #179 requires that we support comparisons between const and non-const iterators. - // Thus we provide additional template paremeters here to support this. The defect report does not - // require us to support comparisons between reverse_iterators and const_reverse_iterators. - template - inline bool operator==(const intrusive_list_iterator& a, - const intrusive_list_iterator& b) - { - return a.mpNode == b.mpNode; - } - - - template - inline bool operator!=(const intrusive_list_iterator& a, - const intrusive_list_iterator& b) - { - return a.mpNode != b.mpNode; - } - - - // We provide a version of operator!= for the case where the iterators are of the - // same type. This helps prevent ambiguity errors in the presence of rel_ops. - template - inline bool operator!=(const intrusive_list_iterator& a, - const intrusive_list_iterator& b) - { - return a.mpNode != b.mpNode; - } - - - - /////////////////////////////////////////////////////////////////////// // intrusive_list_base /////////////////////////////////////////////////////////////////////// @@ -475,7 +518,7 @@ namespace eastl { #if EASTL_VALIDATE_INTRUSIVE_LIST clear(); - mAnchor.mpNext = mAnchor.mpPrev = NULL; + mAnchor.mpNext = mAnchor.mpPrev = nullptr; #endif } @@ -510,7 +553,7 @@ namespace eastl while(pNode != &mAnchor) { intrusive_list_node* const pNextNode = pNode->mpNext; - pNode->mpNext = pNode->mpPrev = NULL; + pNode->mpNext = pNode->mpPrev = nullptr; pNode = pNextNode; } #endif @@ -530,7 +573,7 @@ namespace eastl #if EASTL_VALIDATE_INTRUSIVE_LIST if(pNode != &mAnchor) - pNode->mpNext = pNode->mpPrev = NULL; + pNode->mpNext = pNode->mpPrev = nullptr; #if EASTL_ASSERT_ENABLED else EASTL_FAIL_MSG("intrusive_list::pop_front(): empty list."); @@ -550,7 +593,7 @@ namespace eastl #if EASTL_VALIDATE_INTRUSIVE_LIST if(pNode != &mAnchor) - pNode->mpNext = pNode->mpPrev = NULL; + pNode->mpNext = pNode->mpPrev = nullptr; #if EASTL_ASSERT_ENABLED else EASTL_FAIL_MSG("intrusive_list::pop_back(): empty list."); @@ -593,84 +636,84 @@ namespace eastl template inline typename intrusive_list::iterator intrusive_list::begin() EA_NOEXCEPT { - return iterator(static_cast(mAnchor.mpNext)); + return iterator(mAnchor.mpNext); } template inline typename intrusive_list::const_iterator intrusive_list::begin() const EA_NOEXCEPT { - return const_iterator(static_cast(mAnchor.mpNext)); + return const_iterator(mAnchor.mpNext); } template inline typename intrusive_list::const_iterator intrusive_list::cbegin() const EA_NOEXCEPT { - return const_iterator(static_cast(mAnchor.mpNext)); + return const_iterator(mAnchor.mpNext); } template inline typename intrusive_list::iterator intrusive_list::end() EA_NOEXCEPT { - return iterator(static_cast(&mAnchor)); + return iterator(&mAnchor); } template inline typename intrusive_list::const_iterator intrusive_list::end() const EA_NOEXCEPT { - return const_iterator(static_cast(&mAnchor)); + return const_iterator(&mAnchor); } template inline typename intrusive_list::const_iterator intrusive_list::cend() const EA_NOEXCEPT { - return const_iterator(static_cast(&mAnchor)); + return const_iterator(&mAnchor); } template inline typename intrusive_list::reverse_iterator intrusive_list::rbegin() EA_NOEXCEPT { - return reverse_iterator(iterator(static_cast(&mAnchor))); + return reverse_iterator(iterator(&mAnchor)); } template inline typename intrusive_list::const_reverse_iterator intrusive_list::rbegin() const EA_NOEXCEPT { - return const_reverse_iterator(const_iterator(static_cast(&mAnchor))); + return const_reverse_iterator(const_iterator(&mAnchor)); } template inline typename intrusive_list::const_reverse_iterator intrusive_list::crbegin() const EA_NOEXCEPT { - return const_reverse_iterator(const_iterator(static_cast(&mAnchor))); + return const_reverse_iterator(const_iterator(&mAnchor)); } template inline typename intrusive_list::reverse_iterator intrusive_list::rend() EA_NOEXCEPT { - return reverse_iterator(iterator(static_cast(mAnchor.mpNext))); + return reverse_iterator(iterator(mAnchor.mpNext)); } template inline typename intrusive_list::const_reverse_iterator intrusive_list::rend() const EA_NOEXCEPT { - return const_reverse_iterator(const_iterator(static_cast(mAnchor.mpNext))); + return const_reverse_iterator(const_iterator(mAnchor.mpNext)); } template inline typename intrusive_list::const_reverse_iterator intrusive_list::crend() const EA_NOEXCEPT { - return const_reverse_iterator(const_iterator(static_cast(mAnchor.mpNext))); + return const_reverse_iterator(const_iterator(mAnchor.mpNext)); } @@ -771,10 +814,10 @@ namespace eastl for(intrusive_list_node* p = (T*)mAnchor.mpNext; p != &mAnchor; p = p->mpNext) { if(p == &x) - return iterator(static_cast(p)); + return iterator(p); } - return iterator((T*)&mAnchor); + return iterator(&mAnchor); } @@ -784,10 +827,10 @@ namespace eastl for(const intrusive_list_node* p = mAnchor.mpNext; p != &mAnchor; p = p->mpNext) { if(p == &x) - return const_iterator(static_cast(p)); + return const_iterator(p); } - return const_iterator((T*)&mAnchor); + return const_iterator(&mAnchor); } @@ -799,8 +842,9 @@ namespace eastl EASTL_FAIL_MSG("intrusive_list::insert(): element already on a list."); #endif - intrusive_list_node& next = *const_cast(pos.mpNode); - intrusive_list_node& prev = *static_cast(next.mpPrev); + intrusive_list_node& next = *toListNode(pos.mpNode); + intrusive_list_node& prev = *next.mpPrev; + prev.mpNext = next.mpPrev = &x; x.mpPrev = &prev; x.mpNext = &next; @@ -813,17 +857,17 @@ namespace eastl inline typename intrusive_list::iterator intrusive_list::erase(const_iterator pos) { - intrusive_list_node& prev = *static_cast(pos.mpNode->mpPrev); - intrusive_list_node& next = *static_cast(pos.mpNode->mpNext); + intrusive_list_node& prev = *pos.mpNode->mpPrev; + intrusive_list_node& next = *pos.mpNode->mpNext; prev.mpNext = &next; next.mpPrev = &prev; #if EASTL_VALIDATE_INTRUSIVE_LIST - iterator ii(const_cast(pos.mpNode)); - ii.mpNode->mpPrev = ii.mpNode->mpNext = NULL; + iterator ii(pos.mpNode); + ii.mpNode->mpPrev = ii.mpNode->mpNext = nullptr; #endif - return iterator(static_cast(&next)); + return iterator(&next); } @@ -831,20 +875,20 @@ namespace eastl inline typename intrusive_list::iterator intrusive_list::erase(const_iterator first, const_iterator last) { - intrusive_list_node& prev = *static_cast(first.mpNode->mpPrev); - intrusive_list_node& next = *const_cast(last.mpNode); + intrusive_list_node& prev = *(first.mpNode->mpPrev); + intrusive_list_node& next = *toListNode(last.mpNode); #if EASTL_VALIDATE_INTRUSIVE_LIST // need to clear out all the next/prev pointers in the elements; // this makes this operation O(n) instead of O(1), sadly, although // it's technically amortized O(1) since you could count yourself // as paying this cost with each insert. - intrusive_list_node* pCur = const_cast(first.mpNode); + intrusive_list_node* pCur = toListNode(first.mpNode); while(pCur != &next) { intrusive_list_node* const pCurNext = pCur->mpNext; - pCur->mpPrev = pCur->mpNext = NULL; + pCur->mpPrev = pCur->mpNext = nullptr; pCur = pCurNext; } #endif @@ -852,7 +896,7 @@ namespace eastl prev.mpNext = &next; next.mpPrev = &prev; - return iterator(const_cast(last.mpNode)); + return iterator(last.mpNode); } @@ -900,7 +944,7 @@ namespace eastl x.mAnchor.mpNext->mpPrev = x.mAnchor.mpPrev->mpNext = &x.mAnchor; #if EASTL_VALIDATE_INTRUSIVE_LIST - temp.mpPrev = temp.mpNext = NULL; + temp.mpPrev = temp.mpNext = nullptr; #endif } @@ -920,7 +964,7 @@ namespace eastl oldPrev.mpNext = &oldNext; // Relink item into new list. - intrusive_list_node& newNext = *const_cast(pos.mpNode); + intrusive_list_node& newNext = *toListNode(pos.mpNode); intrusive_list_node& newPrev = *newNext.mpPrev; newPrev.mpNext = &value; @@ -937,10 +981,10 @@ namespace eastl // Note: &x == this is prohibited, so self-insertion is not a problem. if(x.mAnchor.mpNext != &x.mAnchor) // If the list 'x' isn't empty... { - intrusive_list_node& next = *const_cast(pos.mpNode); - intrusive_list_node& prev = *static_cast(next.mpPrev); - intrusive_list_node& insertPrev = *static_cast(x.mAnchor.mpNext); - intrusive_list_node& insertNext = *static_cast(x.mAnchor.mpPrev); + intrusive_list_node& next = *toListNode(pos.mpNode); + intrusive_list_node& prev = *next.mpPrev; + intrusive_list_node& insertPrev = *x.mAnchor.mpNext; + intrusive_list_node& insertNext = *x.mAnchor.mpPrev; prev.mpNext = &insertPrev; insertPrev.mpPrev = &prev; @@ -963,7 +1007,7 @@ namespace eastl // this function expects a valid iterator from the source list, // and thus the list cannot be empty in such a situation. - iterator ii(const_cast(i.mpNode)); // Make a temporary non-const version. + iterator ii(i.mpNode); // Make a temporary non-const version. if(pos != ii) { @@ -974,7 +1018,7 @@ namespace eastl oldPrev.mpNext = &oldNext; // Relink item into new list. - intrusive_list_node& newNext = *const_cast(pos.mpNode); + intrusive_list_node& newNext = *toListNode(pos.mpNode); intrusive_list_node& newPrev = *newNext.mpPrev; newPrev.mpNext = ii.mpNode; @@ -991,16 +1035,16 @@ namespace eastl // Note: &x == this is prohibited, so self-insertion is not a problem. if(first != last) { - intrusive_list_node& insertPrev = *const_cast(first.mpNode); - intrusive_list_node& insertNext = *static_cast(last.mpNode->mpPrev); + intrusive_list_node& insertPrev = *toListNode(first.mpNode); + intrusive_list_node& insertNext = *last.mpNode->mpPrev; // remove from old list insertNext.mpNext->mpPrev = insertPrev.mpPrev; insertPrev.mpPrev->mpNext = insertNext.mpNext; // insert into this list - intrusive_list_node& next = *const_cast(pos.mpNode); - intrusive_list_node& prev = *static_cast(next.mpPrev); + intrusive_list_node& next = *toListNode(pos.mpNode); + intrusive_list_node& prev = *next.mpPrev; prev.mpNext = &insertPrev; insertPrev.mpPrev = &prev; @@ -1019,7 +1063,7 @@ namespace eastl next.mpPrev = &prev; #if EASTL_VALIDATE_INTRUSIVE_LIST - value.mpPrev = value.mpNext = NULL; + value.mpPrev = value.mpNext = nullptr; #endif } @@ -1140,8 +1184,7 @@ namespace eastl // if((i != end()) && (++i != end())) // If the size is >= 2 (without calling the more expensive size() function)... // Faster, more inlinable version of the 'if' statement: - if((static_cast(mAnchor.mpNext) != &mAnchor) && - (static_cast(mAnchor.mpNext) != static_cast(mAnchor.mpPrev))) + if ((mAnchor.mpNext != &mAnchor) && (mAnchor.mpNext != mAnchor.mpPrev)) { // Split the array into 2 roughly equal halves. this_type leftList; // This should cause no memory allocation. @@ -1189,8 +1232,7 @@ namespace eastl // if((i != end()) && (++i != end())) // If the size is >= 2 (without calling the more expensive size() function)... // Faster, more inlinable version of the 'if' statement: - if((static_cast(mAnchor.mpNext) != &mAnchor) && - (static_cast(mAnchor.mpNext) != static_cast(mAnchor.mpPrev))) + if ((mAnchor.mpNext != &mAnchor) && (mAnchor.mpNext != mAnchor.mpPrev)) { // Split the array into 2 roughly equal halves. this_type leftList; // This should cause no memory allocation. diff --git a/include/EASTL/iterator.h b/include/EASTL/iterator.h index 6c268aa1..dfd5a22c 100644 --- a/include/EASTL/iterator.h +++ b/include/EASTL/iterator.h @@ -77,14 +77,19 @@ namespace eastl struct forward_iterator_tag : public input_iterator_tag { }; struct bidirectional_iterator_tag : public forward_iterator_tag { }; struct random_access_iterator_tag : public bidirectional_iterator_tag { }; - struct contiguous_iterator_tag : public random_access_iterator_tag { }; // Extension to the C++ standard. Contiguous ranges are more than random access, they are physically contiguous. + // Originally an extension to the C++ standard, standardized in C++20. + // Contiguous ranges are more than random access, they are physically contiguous. + // Note: Pointers are contiguous but the specialization of iterator_traits for pointers defines + // iterator_traits::iterator_category as random_access_iterator_tag and thus users must + // explicitly check both the iterator_category and the type. + struct contiguous_iterator_tag : public random_access_iterator_tag { }; #endif // struct iterator template - struct iterator + struct EASTL_REMOVE_AT_2024_APRIL iterator { typedef Category iterator_category; typedef T value_type; @@ -249,11 +254,7 @@ namespace eastl /// beginning of an array. /// template - class reverse_iterator : public iterator::iterator_category, - typename eastl::iterator_traits::value_type, - typename eastl::iterator_traits::difference_type, - typename eastl::iterator_traits::pointer, - typename eastl::iterator_traits::reference> + class reverse_iterator { private: using base_wrapped_iterator_type = @@ -261,10 +262,12 @@ namespace eastl eastl::is_iterator_wrapper::value>::iterator_type; public: - typedef Iterator iterator_type; - typedef typename eastl::iterator_traits::pointer pointer; - typedef typename eastl::iterator_traits::reference reference; - typedef typename eastl::iterator_traits::difference_type difference_type; + typedef Iterator iterator_type; + typedef typename eastl::iterator_traits::iterator_category iterator_category; + typedef typename eastl::iterator_traits::value_type value_type; + typedef typename eastl::iterator_traits::difference_type difference_type; + typedef typename eastl::iterator_traits::pointer pointer; + typedef typename eastl::iterator_traits::reference reference; protected: Iterator mIterator; @@ -662,12 +665,17 @@ namespace eastl /// assign a value to it, it calls push_back on the container with the value. /// template - class back_insert_iterator : public iterator + class back_insert_iterator { public: typedef back_insert_iterator this_type; typedef Container container_type; typedef typename Container::const_reference const_reference; + typedef EASTL_ITC_NS::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; protected: Container& container; @@ -719,12 +727,17 @@ namespace eastl /// assign a value to it, it calls push_front on the container with the value. /// template - class front_insert_iterator : public iterator + class front_insert_iterator { public: typedef front_insert_iterator this_type; typedef Container container_type; typedef typename Container::const_reference const_reference; + typedef EASTL_ITC_NS::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; protected: Container& container; @@ -784,12 +797,17 @@ namespace eastl /// iterator p, and the new range will be inserted immediately before p. /// template - class insert_iterator : public iterator + class insert_iterator { public: typedef Container container_type; typedef typename Container::iterator iterator_type; typedef typename Container::const_reference const_reference; + typedef EASTL_ITC_NS::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; protected: Container& container; diff --git a/include/EASTL/list.h b/include/EASTL/list.h index be99c015..1daa38dc 100644 --- a/include/EASTL/list.h +++ b/include/EASTL/list.h @@ -105,54 +105,15 @@ namespace eastl void insert_range(ListNodeBase* pFirst, ListNodeBase* pFinal) EA_NOEXCEPT; // Differs from splice in that first/final aren't in another list. static void remove_range(ListNodeBase* pFirst, ListNodeBase* pFinal) EA_NOEXCEPT; // - } EASTL_LIST_PROXY_MAY_ALIAS; - - - #if EASTL_LIST_PROXY_ENABLED - - /// ListNodeBaseProxy - /// - /// In debug builds, we define ListNodeBaseProxy to be the same thing as - /// ListNodeBase, except it is templated on the parent ListNode class. - /// We do this because we want users in debug builds to be able to easily - /// view the list's contents in a debugger GUI. We do this only in a debug - /// build for the reasons described above: that ListNodeBase needs to be - /// as efficient as possible and not cause code bloat or extra function - /// calls (inlined or not). - /// - /// ListNodeBaseProxy *must* be separate from its parent class ListNode - /// because the list class must have a member node which contains no T value. - /// It is thus incorrect for us to have one single ListNode class which - /// has mpNext, mpPrev, and mValue. So we do a recursive template trick in - /// the definition and use of SListNodeBaseProxy. - /// - template - struct ListNodeBaseProxy - { - LN* mpNext; - LN* mpPrev; - }; - - template - struct ListNode : public ListNodeBaseProxy< ListNode > - { - T mValue; - }; - - #else + }; - EA_DISABLE_VC_WARNING(4625 4626) - template - struct ListNode : public ListNodeBase - { + EA_DISABLE_VC_WARNING(4625 4626) + template + struct ListNode : public ListNodeBase + { T mValue; }; - EA_RESTORE_VC_WARNING() - - #endif - - - + EA_RESTORE_VC_WARNING() /// ListIterator /// @@ -165,13 +126,14 @@ namespace eastl typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. typedef ptrdiff_t difference_type; typedef T value_type; + typedef ListNodeBase base_node_type; typedef ListNode node_type; typedef Pointer pointer; typedef Reference reference; typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category; public: - node_type* mpNode; + base_node_type* mpNode; public: ListIterator() EA_NOEXCEPT; @@ -209,11 +171,7 @@ namespace eastl typedef ListNode node_type; typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. typedef ptrdiff_t difference_type; - #if EASTL_LIST_PROXY_ENABLED - typedef ListNodeBaseProxy< ListNode > base_node_type; - #else - typedef ListNodeBase base_node_type; // We use ListNodeBase instead of ListNode because we don't want to create a T. - #endif + typedef ListNodeBase base_node_type; // We use ListNodeBase instead of ListNode because we don't want to create a T. protected: eastl::compressed_pair mNodeAllocator; @@ -278,6 +236,18 @@ namespace eastl typedef ListBase base_type; typedef list this_type; + protected: + using base_type::mNodeAllocator; + using base_type::DoAllocateNode; + using base_type::DoFreeNode; + using base_type::DoClear; + using base_type::DoInit; +#if EASTL_LIST_SIZE_CACHE + using base_type::mSize; +#endif + using base_type::internalNode; + using base_type::internalAllocator; + public: typedef T value_type; typedef T* pointer; @@ -294,17 +264,7 @@ namespace eastl typedef typename base_type::node_type node_type; typedef typename base_type::base_node_type base_node_type; - using base_type::mNodeAllocator; - using base_type::DoAllocateNode; - using base_type::DoFreeNode; - using base_type::DoClear; - using base_type::DoInit; using base_type::get_allocator; - #if EASTL_LIST_SIZE_CACHE - using base_type::mSize; - #endif - using base_type::internalNode; - using base_type::internalAllocator; public: list(); @@ -597,7 +557,7 @@ namespace eastl template inline ListIterator::ListIterator(const ListNodeBase* pNode) EA_NOEXCEPT - : mpNode(static_cast((ListNode*)const_cast(pNode))) // All this casting is in the name of making runtime debugging much easier on the user. + : mpNode(const_cast(pNode)) { // Empty } @@ -605,7 +565,7 @@ namespace eastl template inline ListIterator::ListIterator(const iterator& x) EA_NOEXCEPT - : mpNode(const_cast(x.mpNode)) + : mpNode(const_cast(x.mpNode)) { // Empty } @@ -631,7 +591,7 @@ namespace eastl inline typename ListIterator::reference ListIterator::operator*() const EA_NOEXCEPT { - return mpNode->mValue; + return static_cast(mpNode)->mValue; } @@ -639,7 +599,7 @@ namespace eastl inline typename ListIterator::pointer ListIterator::operator->() const EA_NOEXCEPT { - return &mpNode->mValue; + return &static_cast(mpNode)->mValue; } @@ -647,7 +607,7 @@ namespace eastl inline typename ListIterator::this_type& ListIterator::operator++() EA_NOEXCEPT { - mpNode = static_cast(mpNode->mpNext); + mpNode = mpNode->mpNext; return *this; } @@ -657,7 +617,7 @@ namespace eastl ListIterator::operator++(int) EA_NOEXCEPT { this_type temp(*this); - mpNode = static_cast(mpNode->mpNext); + mpNode = mpNode->mpNext; return temp; } @@ -666,7 +626,7 @@ namespace eastl inline typename ListIterator::this_type& ListIterator::operator--() EA_NOEXCEPT { - mpNode = static_cast(mpNode->mpPrev); + mpNode = mpNode->mpPrev; return *this; } @@ -676,7 +636,7 @@ namespace eastl ListIterator::operator--(int) EA_NOEXCEPT { this_type temp(*this); - mpNode = static_cast(mpNode->mpPrev); + mpNode = mpNode->mpPrev; return temp; } @@ -787,20 +747,20 @@ namespace eastl template inline void ListBase::DoInit() EA_NOEXCEPT { - internalNode().mpNext = (ListNode*)&internalNode(); - internalNode().mpPrev = (ListNode*)&internalNode(); + internalNode().mpNext = &internalNode(); + internalNode().mpPrev = &internalNode(); } template inline void ListBase::DoClear() { - node_type* p = static_cast(internalNode().mpNext); + base_node_type* p = internalNode().mpNext; while(p != &internalNode()) { - node_type* const pTemp = p; - p = static_cast(p->mpNext); + node_type* const pTemp = static_cast(p); + p = p->mpNext; pTemp->~node_type(); EASTLFree(internalAllocator(), pTemp, sizeof(node_type)); } @@ -832,7 +792,7 @@ namespace eastl inline list::list(size_type n, const allocator_type& allocator) : base_type(allocator) { - DoInsertValues((ListNodeBase*)&internalNode(), n, value_type()); + DoInsertValues(&internalNode(), n, value_type()); } @@ -840,7 +800,7 @@ namespace eastl inline list::list(size_type n, const value_type& value, const allocator_type& allocator) : base_type(allocator) { - DoInsertValues((ListNodeBase*)&internalNode(), n, value); + DoInsertValues(&internalNode(), n, value); } @@ -848,7 +808,7 @@ namespace eastl inline list::list(const this_type& x) : base_type(x.internalAllocator()) { - DoInsert((ListNodeBase*)&internalNode(), const_iterator((ListNodeBase*)x.internalNode().mpNext), const_iterator((ListNodeBase*)&x.internalNode()), false_type()); + DoInsert(&internalNode(), const_iterator(x.internalNode().mpNext), const_iterator(&x.internalNode()), false_type()); } @@ -856,7 +816,7 @@ namespace eastl inline list::list(const this_type& x, const allocator_type& allocator) : base_type(allocator) { - DoInsert((ListNodeBase*)&internalNode(), const_iterator((ListNodeBase*)x.internalNode().mpNext), const_iterator((ListNodeBase*)&x.internalNode()), false_type()); + DoInsert(&internalNode(), const_iterator(x.internalNode().mpNext), const_iterator(&x.internalNode()), false_type()); } @@ -880,7 +840,7 @@ namespace eastl inline list::list(std::initializer_list ilist, const allocator_type& allocator) : base_type(allocator) { - DoInsert((ListNodeBase*)&internalNode(), ilist.begin(), ilist.end(), false_type()); + DoInsert(&internalNode(), ilist.begin(), ilist.end(), false_type()); } @@ -889,8 +849,8 @@ namespace eastl list::list(InputIterator first, InputIterator last) : base_type(EASTL_LIST_DEFAULT_ALLOCATOR) { - //insert(const_iterator((ListNodeBase*)&internalNode()), first, last); - DoInsert((ListNodeBase*)&internalNode(), first, last, is_integral()); + //insert(const_iterator(&internalNode()), first, last); + DoInsert(&internalNode(), first, last, is_integral()); } @@ -898,7 +858,7 @@ namespace eastl typename list::iterator inline list::begin() EA_NOEXCEPT { - return iterator((ListNodeBase*)internalNode().mpNext); + return iterator(internalNode().mpNext); } @@ -906,7 +866,7 @@ namespace eastl inline typename list::const_iterator list::begin() const EA_NOEXCEPT { - return const_iterator((ListNodeBase*)internalNode().mpNext); + return const_iterator(internalNode().mpNext); } @@ -914,7 +874,7 @@ namespace eastl inline typename list::const_iterator list::cbegin() const EA_NOEXCEPT { - return const_iterator((ListNodeBase*)internalNode().mpNext); + return const_iterator(internalNode().mpNext); } @@ -922,7 +882,7 @@ namespace eastl inline typename list::iterator list::end() EA_NOEXCEPT { - return iterator((ListNodeBase*)&internalNode()); + return iterator(&internalNode()); } @@ -930,7 +890,7 @@ namespace eastl inline typename list::const_iterator list::end() const EA_NOEXCEPT { - return const_iterator((ListNodeBase*)&internalNode()); + return const_iterator(&internalNode()); } @@ -938,7 +898,7 @@ namespace eastl inline typename list::const_iterator list::cend() const EA_NOEXCEPT { - return const_iterator((ListNodeBase*)&internalNode()); + return const_iterator(&internalNode()); } @@ -946,7 +906,7 @@ namespace eastl inline typename list::reverse_iterator list::rbegin() EA_NOEXCEPT { - return reverse_iterator((ListNodeBase*)&internalNode()); + return reverse_iterator(&internalNode()); } @@ -954,7 +914,7 @@ namespace eastl inline typename list::const_reverse_iterator list::rbegin() const EA_NOEXCEPT { - return const_reverse_iterator((ListNodeBase*)&internalNode()); + return const_reverse_iterator(&internalNode()); } @@ -962,7 +922,7 @@ namespace eastl inline typename list::const_reverse_iterator list::crbegin() const EA_NOEXCEPT { - return const_reverse_iterator((ListNodeBase*)&internalNode()); + return const_reverse_iterator(&internalNode()); } @@ -970,7 +930,7 @@ namespace eastl inline typename list::reverse_iterator list::rend() EA_NOEXCEPT { - return reverse_iterator((ListNodeBase*)internalNode().mpNext); + return reverse_iterator(internalNode().mpNext); } @@ -978,7 +938,7 @@ namespace eastl inline typename list::const_reverse_iterator list::rend() const EA_NOEXCEPT { - return const_reverse_iterator((ListNodeBase*)internalNode().mpNext); + return const_reverse_iterator(internalNode().mpNext); } @@ -986,7 +946,7 @@ namespace eastl inline typename list::const_reverse_iterator list::crend() const EA_NOEXCEPT { - return const_reverse_iterator((ListNodeBase*)internalNode().mpNext); + return const_reverse_iterator(internalNode().mpNext); } @@ -1069,17 +1029,17 @@ namespace eastl return mSize; #else #if EASTL_DEBUG - const ListNodeBase* p = (ListNodeBase*)internalNode().mpNext; + const ListNodeBase* p = internalNode().mpNext; size_type n = 0; - while(p != (ListNodeBase*)&internalNode()) + while(p != &internalNode()) { ++n; - p = (ListNodeBase*)p->mpNext; + p = p->mpNext; } return n; #else // The following optimizes to slightly better code than the code above. - return (size_type)eastl::distance(const_iterator((ListNodeBase*)internalNode().mpNext), const_iterator((ListNodeBase*)&internalNode())); + return (size_type)eastl::distance(const_iterator(internalNode().mpNext), const_iterator(&internalNode())); #endif #endif } @@ -1194,7 +1154,7 @@ namespace eastl template void list::resize(size_type n, const value_type& value) { - iterator current((ListNodeBase*)internalNode().mpNext); + iterator current(internalNode().mpNext); size_type i = 0; while((current.mpNode != &internalNode()) && (i < n)) @@ -1203,9 +1163,9 @@ namespace eastl ++i; } if(i == n) - erase(current, (ListNodeBase*)&internalNode()); + erase(current, &internalNode()); else - insert((ListNodeBase*)&internalNode(), n - i, value); + insert(&internalNode(), n - i, value); } @@ -1220,21 +1180,21 @@ namespace eastl template void list::emplace_front(Args&&... args) { - DoInsertValue((ListNodeBase*)internalNode().mpNext, eastl::forward(args)...); + DoInsertValue(internalNode().mpNext, eastl::forward(args)...); } template template void list::emplace_back(Args&&... args) { - DoInsertValue((ListNodeBase*)&internalNode(), eastl::forward(args)...); + DoInsertValue(&internalNode(), eastl::forward(args)...); } template inline void list::push_front(const value_type& value) { - DoInsertValue((ListNodeBase*)internalNode().mpNext, value); + DoInsertValue(internalNode().mpNext, value); } @@ -1250,7 +1210,7 @@ namespace eastl list::push_front() { node_type* const pNode = DoCreateNode(); - ((ListNodeBase*)pNode)->insert((ListNodeBase*)internalNode().mpNext); + pNode->insert(internalNode().mpNext); #if EASTL_LIST_SIZE_CACHE ++mSize; #endif @@ -1262,7 +1222,7 @@ namespace eastl inline void* list::push_front_uninitialized() { node_type* const pNode = DoAllocateNode(); - ((ListNodeBase*)pNode)->insert((ListNodeBase*)internalNode().mpNext); + pNode->insert(internalNode().mpNext); #if EASTL_LIST_SIZE_CACHE ++mSize; #endif @@ -1278,14 +1238,14 @@ namespace eastl EASTL_FAIL_MSG("list::pop_front -- empty container"); #endif - DoErase((ListNodeBase*)internalNode().mpNext); + DoErase(internalNode().mpNext); } template inline void list::push_back(const value_type& value) { - DoInsertValue((ListNodeBase*)&internalNode(), value); + DoInsertValue(&internalNode(), value); } @@ -1301,7 +1261,7 @@ namespace eastl list::push_back() { node_type* const pNode = DoCreateNode(); - ((ListNodeBase*)pNode)->insert((ListNodeBase*)&internalNode()); + pNode->insert(&internalNode()); #if EASTL_LIST_SIZE_CACHE ++mSize; #endif @@ -1313,7 +1273,7 @@ namespace eastl inline void* list::push_back_uninitialized() { node_type* const pNode = DoAllocateNode(); - ((ListNodeBase*)pNode)->insert((ListNodeBase*)&internalNode()); + pNode->insert(&internalNode()); #if EASTL_LIST_SIZE_CACHE ++mSize; #endif @@ -1329,7 +1289,7 @@ namespace eastl EASTL_FAIL_MSG("list::pop_back -- empty container"); #endif - DoErase((ListNodeBase*)internalNode().mpPrev); + DoErase(internalNode().mpPrev); } @@ -1347,12 +1307,12 @@ namespace eastl inline typename list::iterator list::insert(const_iterator position) { - node_type* const pNode = DoCreateNode(value_type()); - ((ListNodeBase*)pNode)->insert((ListNodeBase*)position.mpNode); + ListNodeBase* const pNode = DoCreateNode(value_type()); + pNode->insert(position.mpNode); #if EASTL_LIST_SIZE_CACHE ++mSize; #endif - return (ListNodeBase*)pNode; + return pNode; } @@ -1360,12 +1320,12 @@ namespace eastl inline typename list::iterator list::insert(const_iterator position, const value_type& value) { - node_type* const pNode = DoCreateNode(value); - ((ListNodeBase*)pNode)->insert((ListNodeBase*)position.mpNode); + ListNodeBase* const pNode = DoCreateNode(value); + pNode->insert(position.mpNode); #if EASTL_LIST_SIZE_CACHE ++mSize; #endif - return (ListNodeBase*)pNode; + return pNode; } @@ -1382,7 +1342,7 @@ namespace eastl { iterator itPrev(position.mpNode); --itPrev; - DoInsertValues((ListNodeBase*)position.mpNode, n, value); + DoInsertValues(position.mpNode, n, value); return ++itPrev; // Inserts in front of position, returns iterator to new elements. } @@ -1394,7 +1354,7 @@ namespace eastl { iterator itPrev(position.mpNode); --itPrev; - DoInsert((ListNodeBase*)position.mpNode, first, last, is_integral()); + DoInsert(position.mpNode, first, last, is_integral()); return ++itPrev; // Inserts in front of position, returns iterator to new elements. } @@ -1405,7 +1365,7 @@ namespace eastl { iterator itPrev(position.mpNode); --itPrev; - DoInsert((ListNodeBase*)position.mpNode, ilist.begin(), ilist.end(), false_type()); + DoInsert(position.mpNode, ilist.begin(), ilist.end(), false_type()); return ++itPrev; // Inserts in front of position, returns iterator to new elements. } @@ -1415,7 +1375,7 @@ namespace eastl list::erase(const_iterator position) { ++position; - DoErase((ListNodeBase*)position.mpNode->mpPrev); + DoErase(position.mpNode->mpPrev); return iterator(position.mpNode); } @@ -1459,7 +1419,7 @@ namespace eastl template typename list::size_type list::remove(const value_type& value) { - iterator current((ListNodeBase*)internalNode().mpNext); + iterator current(internalNode().mpNext); size_type numRemoved = 0; while(current.mpNode != &internalNode()) @@ -1469,7 +1429,7 @@ namespace eastl else { ++current; - DoErase((ListNodeBase*)current.mpNode->mpPrev); + DoErase(current.mpNode->mpPrev); ++numRemoved; } } @@ -1482,13 +1442,13 @@ namespace eastl inline typename list::size_type list::remove_if(Predicate predicate) { size_type numRemoved = 0; - for(iterator first((ListNodeBase*)internalNode().mpNext), last((ListNodeBase*)&internalNode()); first != last; ) + for(iterator first(internalNode().mpNext), last(&internalNode()); first != last; ) { iterator temp(first); ++temp; - if(predicate(first.mpNode->mValue)) + if(predicate(static_cast(first.mpNode)->mValue)) { - DoErase((ListNodeBase*)first.mpNode); + DoErase(first.mpNode); ++numRemoved; } first = temp; @@ -1519,13 +1479,13 @@ namespace eastl #if EASTL_LIST_SIZE_CACHE if(x.mSize) { - ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)x.internalNode().mpNext, (ListNodeBase*)&x.internalNode()); + (position.mpNode)->splice(x.internalNode().mpNext, &x.internalNode()); mSize += x.mSize; x.mSize = 0; } #else if(!x.empty()) - ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)x.internalNode().mpNext, (ListNodeBase*)&x.internalNode()); + (position.mpNode)->splice(x.internalNode().mpNext, &x.internalNode()); #endif } else @@ -1551,7 +1511,7 @@ namespace eastl ++i2; if((position != i) && (position != i2)) { - ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)i.mpNode, (ListNodeBase*)i2.mpNode); + (position.mpNode)->splice(i.mpNode, i2.mpNode); #if EASTL_LIST_SIZE_CACHE ++mSize; @@ -1584,13 +1544,13 @@ namespace eastl if(n) { - ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)first.mpNode, (ListNodeBase*)last.mpNode); + (position.mpNode)->splice(first.mpNode, last.mpNode); mSize += n; x.mSize -= n; } #else if(first != last) - ((ListNodeBase*)position.mpNode)->splice((ListNodeBase*)first.mpNode, (ListNodeBase*)last.mpNode); + (position.mpNode)->splice(first.mpNode, last.mpNode); #endif } else @@ -1709,7 +1669,7 @@ namespace eastl while(++next != last) { if(*first == *next) - DoErase((ListNodeBase*)next.mpNode); + DoErase(next.mpNode); else first = next; next = first; @@ -1732,7 +1692,7 @@ namespace eastl while(++next != last) { if(predicate(*first, *next)) - DoErase((ListNodeBase*)next.mpNode); + DoErase(next.mpNode); else first = next; next = first; @@ -1938,9 +1898,9 @@ namespace eastl } if(first == last) - erase(const_iterator((ListNodeBase*)pNode), (ListNodeBase*)&internalNode()); + erase(const_iterator(pNode), &internalNode()); else - DoInsert((ListNodeBase*)&internalNode(), first, last, false_type()); + DoInsert(&internalNode(), first, last, false_type()); } @@ -1956,9 +1916,9 @@ namespace eastl } if(n) - DoInsertValues((ListNodeBase*)&internalNode(), n, value); + DoInsertValues(&internalNode(), n, value); else - erase(const_iterator((ListNodeBase*)pNode), (ListNodeBase*)&internalNode()); + erase(const_iterator(pNode), &internalNode()); } @@ -1992,7 +1952,7 @@ namespace eastl inline void list::DoInsertValue(ListNodeBase* pNode, Args&&... args) { node_type* const pNodeNew = DoCreateNode(eastl::forward(args)...); - ((ListNodeBase*)pNodeNew)->insert(pNode); + pNodeNew->insert(pNode); #if EASTL_LIST_SIZE_CACHE ++mSize; #endif diff --git a/include/EASTL/map.h b/include/EASTL/map.h index 7824250b..22637fe4 100644 --- a/include/EASTL/map.h +++ b/include/EASTL/map.h @@ -111,9 +111,9 @@ namespace eastl value_compare(Compare c) : compare(c) {} public: - typedef bool result_type; - typedef value_type first_argument_type; - typedef value_type second_argument_type; + EASTL_REMOVE_AT_2024_APRIL typedef bool result_type; + EASTL_REMOVE_AT_2024_APRIL typedef value_type first_argument_type; + EASTL_REMOVE_AT_2024_APRIL typedef value_type second_argument_type; bool operator()(const value_type& x, const value_type& y) const { return compare(x.first, y.first); } @@ -232,9 +232,9 @@ namespace eastl value_compare(Compare c) : compare(c) {} public: - typedef bool result_type; - typedef value_type first_argument_type; - typedef value_type second_argument_type; + EASTL_REMOVE_AT_2024_APRIL typedef bool result_type; + EASTL_REMOVE_AT_2024_APRIL typedef value_type first_argument_type; + EASTL_REMOVE_AT_2024_APRIL typedef value_type second_argument_type; bool operator()(const value_type& x, const value_type& y) const { return compare(x.first, y.first); } @@ -390,7 +390,7 @@ namespace eastl // result is a range of size zero or one. const iterator itLower(lower_bound(key)); - if((itLower == end()) || compare(key, itLower.mpNode->mValue.first)) // If at the end or if (key is < itLower)... + if((itLower == end()) || compare(key, itLower->first)) // If at the end or if (key is < itLower)... return eastl::pair(itLower, itLower); iterator itUpper(itLower); @@ -406,7 +406,7 @@ namespace eastl // See equal_range above for comments. const const_iterator itLower(lower_bound(key)); - if((itLower == end()) || compare(key, itLower.mpNode->mValue.first)) // If at the end or if (key is < itLower)... + if((itLower == end()) || compare(key, itLower->first)) // If at the end or if (key is < itLower)... return eastl::pair(itLower, itLower); const_iterator itUpper(itLower); @@ -529,7 +529,7 @@ namespace eastl map::try_emplace_forward(KFwd&& key, Args&&... args) { bool canInsert; - node_type* const pPosition = base_type::DoGetKeyInsertionPositionUniqueKeys(canInsert, key); + rbtree_node_base* const pPosition = base_type::DoGetKeyInsertionPositionUniqueKeys(canInsert, key); if (!canInsert) { return pair(iterator(pPosition), false); @@ -566,7 +566,7 @@ namespace eastl map::try_emplace_forward(const_iterator hint, KFwd&& key, Args&&... args) { bool bForceToLeft; - node_type* const pPosition = base_type::DoGetKeyInsertionPositionUniqueKeysHint(hint, bForceToLeft, key); + rbtree_node_base* const pPosition = base_type::DoGetKeyInsertionPositionUniqueKeysHint(hint, bForceToLeft, key); if (!pPosition) { @@ -711,7 +711,7 @@ namespace eastl const iterator itLower(lower_bound(key)); iterator itUpper(itLower); - while((itUpper != end()) && !compare(key, itUpper.mpNode->mValue.first)) + while((itUpper != end()) && !compare(key, itUpper->first)) ++itUpper; return eastl::pair(itLower, itUpper); @@ -728,7 +728,7 @@ namespace eastl const const_iterator itLower(lower_bound(key)); const_iterator itUpper(itLower); - while((itUpper != end()) && !compare(key, itUpper.mpNode->mValue.first)) + while((itUpper != end()) && !compare(key, itUpper->first)) ++itUpper; return eastl::pair(itLower, itUpper); @@ -769,15 +769,6 @@ namespace eastl } #endif -#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) - template - inline synth_three_way_result> operator<=>(const multimap& a, - const multimap& b) - { - return eastl::lexicographical_compare_three_way(a.begin(), a.end(), b.begin(), b.end(), synth_three_way{}); - } -#endif - } // namespace eastl diff --git a/include/EASTL/memory.h b/include/EASTL/memory.h index ab2798f7..79e55ff4 100644 --- a/include/EASTL/memory.h +++ b/include/EASTL/memory.h @@ -7,7 +7,6 @@ // are found in the header: // // Temporary memory: -// get_temporary_buffer // return_temporary_buffer // // Utility: @@ -29,9 +28,6 @@ // uninitialized_fill_n // uninitialized_value_construct // uninitialized_value_construct_n -// uninitialized_default_fill - Extention to standard functionality. -// uninitialized_default_fill_n - Extention to standard functionality. -// uninitialized_relocate - Extention to standard functionality. // uninitialized_copy_ptr - Extention to standard functionality. // uninitialized_move_ptr - Extention to standard functionality. // uninitialized_move_ptr_if_noexcept- Extention to standard functionality. @@ -42,8 +38,8 @@ // uninitialized_copy_copy - Extention to standard functionality. // // In-place destructor helpers: -// destruct(T*) - Non-standard extension. -// destruct(first, last) - Non-standard extension. +// destruct(T*) - Non-standard extension. Equivalent to destroy_at(T*) +// destruct(first, last) - Non-standard extension. Equivalent to destroy(first, last) // destroy_at(T*) // destroy(first, last) // destroy_n(first, n) @@ -59,6 +55,14 @@ // // Pointers // pointer_traits +// +// Deprecations: +// uninitialized_relocate - Use one of the other uninitialized_xxxx functions with move semantics. +// uninitialized_default_fill - Use uninitialized_value_construct instead. +// uninitialized_default_fill_n - Use uninitialized_value_construct_n instead. +// +// Deprecated in C++17: +// get_temporary_buffer // /////////////////////////////////////////////////////////////////////////////// @@ -126,6 +130,7 @@ namespace eastl /// return_temporary_buffer(pr.first); /// template + EASTL_REMOVE_AT_2024_APRIL eastl::pair get_temporary_buffer(ptrdiff_t n, size_t alignment = 1, size_t alignmentOffset = 0, const char* pName = EASTL_TEMP_DEFAULT_NAME) { EASTLAllocatorType allocator(*EASTLAllocatorDefault(), pName); @@ -327,12 +332,18 @@ namespace eastl /// of an output iterator (24.2.4). template - class raw_storage_iterator : public iterator + class EASTL_REMOVE_AT_2024_APRIL raw_storage_iterator { protected: OutputIterator mIterator; public: + typedef EASTL_ITC_NS::output_iterator_tag iterator_category; + typedef void value_type; + typedef void difference_type; + typedef void pointer; + typedef void reference; + explicit raw_storage_iterator(OutputIterator iterator) : mIterator(iterator) { @@ -439,10 +450,10 @@ namespace eastl template static T* do_move_start(T* first, T* last, T* dest) { - if (EASTL_UNLIKELY(first == last)) + if (first != last) + return (T*)memcpy(dest, first, (size_t)((uintptr_t)last - (uintptr_t)first)) + (last - first); + else return dest; - - return (T*)memcpy(dest, first, (size_t)((uintptr_t)last - (uintptr_t)first)) + (last - first); } template @@ -459,6 +470,7 @@ namespace eastl }; } + EASTL_INTERNAL_DISABLE_DEPRECATED() // 'has_trivial_relocate': was declared deprecated /// uninitialized_relocate_start, uninitialized_relocate_commit, uninitialized_relocate_abort /// @@ -487,46 +499,52 @@ namespace eastl /// uninitialized_relocate_commit(first, last, dest); /// template - inline ForwardIteratorDest uninitialized_relocate_start(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + EASTL_REMOVE_AT_2024_APRIL inline ForwardIteratorDest uninitialized_relocate_start(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) { typedef typename eastl::iterator_traits::iterator_category IC; typedef typename eastl::iterator_traits::value_type value_type_input; typedef typename eastl::iterator_traits::value_type value_type_output; + EASTL_INTERNAL_DISABLE_DEPRECATED() const bool bHasTrivialMove = type_and::value, is_pointer::value, is_pointer::value, is_same::value>::value; + EASTL_INTERNAL_RESTORE_DEPRECATED() return Internal::uninitialized_relocate_impl::do_move_start(first, last, dest); } template - inline ForwardIteratorDest uninitialized_relocate_commit(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + EASTL_REMOVE_AT_2024_APRIL inline ForwardIteratorDest uninitialized_relocate_commit(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) { typedef typename eastl::iterator_traits::iterator_category IC; typedef typename eastl::iterator_traits::value_type value_type_input; typedef typename eastl::iterator_traits::value_type value_type_output; + EASTL_INTERNAL_DISABLE_DEPRECATED() const bool bHasTrivialMove = type_and::value, is_pointer::value, is_pointer::value, is_same::value>::value; + EASTL_INTERNAL_RESTORE_DEPRECATED() return Internal::uninitialized_relocate_impl::do_move_commit(first, last, dest); } template - inline ForwardIteratorDest uninitialized_relocate_abort(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + EASTL_REMOVE_AT_2024_APRIL inline ForwardIteratorDest uninitialized_relocate_abort(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) { typedef typename eastl::iterator_traits::iterator_category IC; typedef typename eastl::iterator_traits::value_type value_type_input; typedef typename eastl::iterator_traits::value_type value_type_output; + EASTL_INTERNAL_DISABLE_DEPRECATED() const bool bHasTrivialMove = type_and::value, is_pointer::value, is_pointer::value, is_same::value>::value; + EASTL_INTERNAL_RESTORE_DEPRECATED() return Internal::uninitialized_relocate_impl::do_move_abort(first, last, dest); } @@ -536,7 +554,7 @@ namespace eastl /// See above for documentation. /// template - inline ForwardIteratorDest uninitialized_relocate(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) + EASTL_REMOVE_AT_2024_APRIL inline ForwardIteratorDest uninitialized_relocate(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) { ForwardIteratorDest result = uninitialized_relocate_start(first, last, dest); eastl::uninitialized_relocate_commit(first, last, dest); @@ -544,6 +562,7 @@ namespace eastl return result; } + EASTL_INTERNAL_RESTORE_DEPRECATED() @@ -552,36 +571,66 @@ namespace eastl // namespace Internal { - template - inline ForwardIterator uninitialized_copy_impl(InputIterator first, InputIterator last, ForwardIterator dest, true_type) - { - return eastl::copy(first, last, dest); // The copy() in turn will use memcpy for POD types. - } - - template - inline ForwardIterator uninitialized_copy_impl(InputIterator first, InputIterator last, ForwardIterator dest, false_type) + template + struct uninitialized_copy_impl { - typedef typename eastl::iterator_traits::value_type value_type; - ForwardIterator currentDest(dest); + template + static ForwardIterator impl(InputIterator first, InputIterator last, ForwardIterator dest) + { + typedef typename eastl::iterator_traits::value_type value_type; + ForwardIterator currentDest(dest); - #if EASTL_EXCEPTIONS_ENABLED +#if EASTL_EXCEPTIONS_ENABLED try { - #endif - for(; first != last; ++first, ++currentDest) +#endif + for (; first != last; ++first, ++currentDest) ::new(static_cast(eastl::addressof(*currentDest))) value_type(*first); - #if EASTL_EXCEPTIONS_ENABLED +#if EASTL_EXCEPTIONS_ENABLED } - catch(...) + catch (...) { - for(; dest < currentDest; ++dest) + for (; dest < currentDest; ++dest) (*dest).~value_type(); throw; } - #endif +#endif - return currentDest; - } + return currentDest; + } + }; + + template<> + struct uninitialized_copy_impl + { + template + static ForwardIterator impl(InputIterator first, InputIterator last, ForwardIterator dest) + { + typedef typename eastl::iterator_traits::value_type value_type; + + for (; first != last; ++first, ++dest) + memmove(eastl::addressof(*dest), eastl::addressof(*first), sizeof(value_type)); + + return dest; + } + }; + + template<> + struct uninitialized_copy_impl + { + template + static ForwardIterator impl(InputIterator first, InputIterator last, ForwardIterator dest) + { + typedef typename eastl::iterator_traits::value_type value_type; + + if (EASTL_UNLIKELY(first == last)) + return dest; + + auto count = (last - first); + memmove(eastl::addressof(*dest), eastl::addressof(*first), sizeof(value_type) * count); + return dest + count; + } + }; } /// uninitialized_copy @@ -601,10 +650,20 @@ namespace eastl template inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result) { - typedef typename eastl::iterator_traits::value_type value_type; - - // We use is_trivial, which in the C++11 Standard means is_trivially_copyable and is_trivially_default_constructible. - return Internal::uninitialized_copy_impl(first, last, result, eastl::is_trivial()); + typedef typename eastl::iterator_traits::iterator_category IIC; + typedef typename eastl::iterator_traits::iterator_category OIC; + typedef typename eastl::iterator_traits::value_type value_type_input; + typedef typename eastl::iterator_traits::value_type value_type_output; + + // isTriviallyCopyable identifies if (non-overlapping) objects may be safely copied by means of memcpy/memmove. + const bool isTriviallyCopyable = eastl::is_same::value && eastl::is_trivially_copyable::value; + // ie. is eastl::addressof(*first) valid? ie. invalid for iterators that return value_type&&. + const bool isInputIteratorReferenceAddressable = eastl::is_convertible::type, typename eastl::iterator_traits::reference>::value; + // can memcpy/memmove a contiguous block, not just the individual elements? + const bool areIteratorsContiguous = (eastl::is_pointer::value || internal::is_contiguous_iterator::value) && + (eastl::is_pointer::value || internal::is_contiguous_iterator::value); + + return Internal::uninitialized_copy_impl::impl(first, last, result); } @@ -675,12 +734,7 @@ namespace eastl template inline Result uninitialized_copy_ptr(First first, Last last, Result result) { - typedef typename eastl::iterator_traits >::value_type value_type; - const generic_iterator i(Internal::uninitialized_copy_impl(eastl::generic_iterator(first), // generic_iterator makes a pointer act like an iterator. - eastl::generic_iterator(last), - eastl::generic_iterator(result), - eastl::is_trivially_copy_assignable())); - return i.base(); + return eastl::uninitialized_copy(first, last, result); } @@ -695,7 +749,7 @@ namespace eastl template inline ForwardIterator uninitialized_move_impl(InputIterator first, InputIterator last, ForwardIterator dest, true_type) { - return eastl::copy(first, last, dest); // The copy() in turn will use memcpy for is_trivially_copy_assignable (e.g. POD) types. + return eastl::copy(first, last, dest); // The copy() in turn will use memcpy for trivially copyable types. } template @@ -739,7 +793,7 @@ namespace eastl const generic_iterator i(Internal::uninitialized_move_impl(eastl::generic_iterator(first), // generic_iterator makes a pointer act like an iterator. eastl::generic_iterator(last), eastl::generic_iterator(dest), - eastl::is_trivially_copy_assignable())); // is_trivially_copy_assignable identifies if copy assignment would be as valid as move assignment, which means we have the opportunity to memcpy/memmove optimization. + eastl::is_trivially_copyable())); // is_trivially_copyable identifies if (non-overlapping) objects may be safely copied by means of memcpy/memmove. return i.base(); } @@ -815,6 +869,8 @@ namespace eastl // This is the behavior we intend below. EA_DISABLE_VC_WARNING(4345) /// uninitialized_default_fill + /// + /// Deprecated. Use uninitialized_value_construct for the std conforming alternative. /// /// Default-constructs the elements in the destination range. /// Returns void. It wouldn't be useful to return the end of the destination range, @@ -825,7 +881,7 @@ namespace eastl /// void uninitialized_default_fill(ForwardIterator destinationFirst, ForwardIterator destinationLast); /// template - inline void uninitialized_default_fill(ForwardIterator first, ForwardIterator last) + EASTL_REMOVE_AT_2024_APRIL inline void uninitialized_default_fill(ForwardIterator first, ForwardIterator last) { typedef typename eastl::iterator_traits::value_type value_type; ForwardIterator currentDest(first); @@ -849,6 +905,8 @@ namespace eastl /// uninitialized_default_fill_n /// + /// Deprecated. Use uninitialized_value_construct_n for the std conforming alternative. + /// /// Default-constructs the range of [first, first + n). /// Returns void as per the C++ standard, though returning the end input iterator /// value may be of use. @@ -885,16 +943,13 @@ namespace eastl template inline void uninitialized_default_fill_n_impl(ForwardIterator first, Count n, true_type) { - if (EASTL_UNLIKELY(n == 0)) - return; - typedef typename eastl::iterator_traits::value_type value_type; memset(first, 0, sizeof(value_type) * n); } } template - inline void uninitialized_default_fill_n(ForwardIterator first, Count n) + EASTL_REMOVE_AT_2024_APRIL inline void uninitialized_default_fill_n(ForwardIterator first, Count n) { typedef typename eastl::iterator_traits::value_type value_type; Internal::uninitialized_default_fill_n_impl(first, n, is_scalar()); @@ -1361,7 +1416,7 @@ namespace eastl inline void destruct(ForwardIterator first, ForwardIterator last) { typedef typename eastl::iterator_traits::value_type value_type; - destruct_impl(first, last, eastl::has_trivial_destructor()); + destruct_impl(first, last, eastl::is_trivially_destructible()); } diff --git a/include/EASTL/optional.h b/include/EASTL/optional.h index 15cacd08..2c86515f 100644 --- a/include/EASTL/optional.h +++ b/include/EASTL/optional.h @@ -219,6 +219,10 @@ namespace eastl } optional(const optional& other) + // This silences the warning about the base class not being explicitly initialised in the copy constructor + // We call the default constructor instead of the copy constructor because we're about to stomp the memory + // that would be copied + : base_type() { engaged = other.engaged; @@ -230,6 +234,8 @@ namespace eastl } optional(optional&& other) + // See comments above + : base_type() { engaged = other.engaged; @@ -683,10 +689,10 @@ namespace eastl template struct hash> { - typedef eastl::optional argument_type; - typedef size_t result_type; + EASTL_REMOVE_AT_2024_APRIL typedef eastl::optional argument_type; + EASTL_REMOVE_AT_2024_APRIL typedef size_t result_type; - result_type operator()(const argument_type& opt) const EA_NOEXCEPT + size_t operator()(const eastl::optional& opt) const EA_NOEXCEPT { if (opt) return eastl::hash()(*opt); diff --git a/include/EASTL/queue.h b/include/EASTL/queue.h index 8b29555c..76e33452 100644 --- a/include/EASTL/queue.h +++ b/include/EASTL/queue.h @@ -122,7 +122,7 @@ namespace eastl void push(value_type&& x); template - EA_DEPRECATED void emplace_back(Args&&... args); // backwards compatibility + EASTL_REMOVE_AT_2024_APRIL void emplace_back(Args&&... args); // backwards compatibility template decltype(auto) emplace(Args&&... args); diff --git a/include/EASTL/safe_ptr.h b/include/EASTL/safe_ptr.h index 344ded8b..8acdf2ef 100644 --- a/include/EASTL/safe_ptr.h +++ b/include/EASTL/safe_ptr.h @@ -57,7 +57,7 @@ namespace eastl public: // Deprecated, as its name is misleading: - bool has_references() const; /// Returns true if there is at most one reference (by a smart_ptr) to us. + EASTL_REMOVE_AT_2024_APRIL bool has_references() const; /// Returns true if there is at most one reference (by a smart_ptr) to us. }; diff --git a/include/EASTL/set.h b/include/EASTL/set.h index 8256162c..127ecfb9 100644 --- a/include/EASTL/set.h +++ b/include/EASTL/set.h @@ -591,7 +591,7 @@ namespace eastl const iterator itLower(lower_bound(k)); iterator itUpper(itLower); - while((itUpper != end()) && !compare(k, itUpper.mpNode->mValue)) + while((itUpper != end()) && !compare(k, *itUpper)) ++itUpper; return eastl::pair(itLower, itUpper); diff --git a/include/EASTL/shared_ptr.h b/include/EASTL/shared_ptr.h index e7eb778e..3ac9bc77 100644 --- a/include/EASTL/shared_ptr.h +++ b/include/EASTL/shared_ptr.h @@ -1672,9 +1672,8 @@ namespace eastl template struct owner_less< shared_ptr > - : public eastl::binary_function, shared_ptr, bool> { - typedef bool result_type; + EASTL_REMOVE_AT_2024_APRIL typedef bool result_type; bool operator()(shared_ptr const& a, shared_ptr const& b) const { return a.owner_before(b); } @@ -1688,9 +1687,8 @@ namespace eastl template struct owner_less< weak_ptr > - : public eastl::binary_function, weak_ptr, bool> { - typedef bool result_type; + EASTL_REMOVE_AT_2024_APRIL typedef bool result_type; bool operator()(weak_ptr const& a, weak_ptr const& b) const { return a.owner_before(b); } diff --git a/include/EASTL/slist.h b/include/EASTL/slist.h index dc3c447f..3fab11e5 100644 --- a/include/EASTL/slist.h +++ b/include/EASTL/slist.h @@ -84,47 +84,14 @@ namespace eastl struct SListNodeBase { SListNodeBase* mpNext; - } EASTL_LIST_PROXY_MAY_ALIAS; - - - #if EASTL_LIST_PROXY_ENABLED - - /// SListNodeBaseProxy - /// - /// In debug builds, we define SListNodeBaseProxy to be the same thing as - /// SListNodeBase, except it is templated on the parent SListNode class. - /// We do this because we want users in debug builds to be able to easily - /// view the slist's contents in a debugger GUI. We do this only in a debug - /// build for the reasons described above: that SListNodeBase needs to be - /// as efficient as possible and not cause code bloat or extra function - /// calls (inlined or not). - /// - /// SListNodeBaseProxy *must* be separate from its parent class SListNode - /// because the slist class must have a member node which contains no T value. - /// It is thus incorrect for us to have one single SListNode class which - /// has both mpNext and mValue. So we do a recursive template trick in the - /// definition and use of SListNodeBaseProxy. - /// - template - struct SListNodeBaseProxy - { - SLN* mpNext; - }; + }; - template - struct SListNode : public SListNodeBaseProxy< SListNode > - { - T mValue; - }; - - #else - template - struct SListNode : public SListNodeBase - { - T mValue; - }; - #endif + template + struct SListNode : public SListNodeBase + { + T mValue; + }; /// SListIterator /// @@ -137,13 +104,14 @@ namespace eastl typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. typedef ptrdiff_t difference_type; typedef T value_type; + typedef SListNodeBase base_node_type; typedef SListNode node_type; typedef Pointer pointer; typedef Reference reference; typedef EASTL_ITC_NS::forward_iterator_tag iterator_category; public: - node_type* mpNode; + base_node_type* mpNode; public: SListIterator(); @@ -172,11 +140,7 @@ namespace eastl typedef SListNode node_type; typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t. typedef ptrdiff_t difference_type; - #if EASTL_LIST_PROXY_ENABLED - typedef SListNodeBaseProxy< SListNode > base_node_type; - #else - typedef SListNodeBase base_node_type; // We use SListNodeBase instead of SListNode because we don't want to create a T. - #endif + typedef SListNodeBase base_node_type; // We use SListNodeBase instead of SListNode because we don't want to create a T. protected: eastl::compressed_pair mNodeAllocator; @@ -242,6 +206,17 @@ namespace eastl typedef SListBase base_type; typedef slist this_type; + protected: + using base_type::mNodeAllocator; + using base_type::DoEraseAfter; + using base_type::DoAllocateNode; + using base_type::DoFreeNode; +#if EASTL_SLIST_SIZE_CACHE + using base_type::mSize; +#endif + using base_type::internalNode; + using base_type::internalAllocator; + public: typedef T value_type; typedef value_type* pointer; @@ -256,16 +231,6 @@ namespace eastl typedef typename base_type::node_type node_type; typedef typename base_type::base_node_type base_node_type; - using base_type::mNodeAllocator; - using base_type::DoEraseAfter; - using base_type::DoAllocateNode; - using base_type::DoFreeNode; - #if EASTL_SLIST_SIZE_CACHE - using base_type::mSize; - #endif - using base_type::internalNode; - using base_type::internalAllocator; - public: slist(); slist(const allocator_type& allocator); @@ -380,8 +345,8 @@ namespace eastl // The following splice_after funcions are deprecated, as they don't allow for recognizing // the allocator, cannot maintain the source mSize, and are not in the C++11 Standard definition // of std::forward_list (which is the equivalent of this class). - void splice_after(const_iterator position, const_iterator before_first, const_iterator before_last); // before_first and before_last come from a source container. - void splice_after(const_iterator position, const_iterator previous); // previous comes from a source container. + EASTL_REMOVE_AT_2024_APRIL void splice_after(const_iterator position, const_iterator before_first, const_iterator before_last); // before_first and before_last come from a source container. + EASTL_REMOVE_AT_2024_APRIL void splice_after(const_iterator position, const_iterator previous); // previous comes from a source container. // Sorting functionality // This is independent of the global sort algorithms, as lists are @@ -538,7 +503,7 @@ namespace eastl template inline SListIterator::SListIterator(const SListNodeBase* pNode) - : mpNode(static_cast((SListNode*)const_cast(pNode))) // All this casting is in the name of making runtime debugging much easier on the user. + : mpNode(const_cast(pNode)) { // Empty } @@ -546,7 +511,7 @@ namespace eastl template inline SListIterator::SListIterator(const iterator& x) - : mpNode(const_cast(x.mpNode)) + : mpNode(const_cast(x.mpNode)) { // Empty } @@ -556,7 +521,7 @@ namespace eastl inline typename SListIterator::reference SListIterator::operator*() const { - return mpNode->mValue; + return static_cast(mpNode)->mValue; } @@ -564,7 +529,7 @@ namespace eastl inline typename SListIterator::pointer SListIterator::operator->() const { - return &mpNode->mValue; + return &static_cast(mpNode)->mValue; } @@ -572,7 +537,7 @@ namespace eastl inline typename SListIterator::this_type& SListIterator::operator++() { - mpNode = static_cast(mpNode->mpNext); + mpNode = mpNode->mpNext; return *this; } @@ -582,7 +547,7 @@ namespace eastl SListIterator::operator++(int) { this_type temp(*this); - mpNode = static_cast(mpNode->mpNext); + mpNode = mpNode->mpNext; return temp; } @@ -647,7 +612,7 @@ namespace eastl template inline SListBase::~SListBase() { - DoEraseAfter((SListNodeBase*)&internalNode(), NULL); + DoEraseAfter(&internalNode(), NULL); } @@ -694,7 +659,7 @@ namespace eastl SListNodeBase* SListBase::DoEraseAfter(SListNodeBase* pNode) { node_type* const pNodeNext = static_cast((base_node_type*)pNode->mpNext); - SListNodeBase* const pNodeNextNext = (SListNodeBase*)pNodeNext->mpNext; + SListNodeBase* const pNodeNextNext = pNodeNext->mpNext; pNode->mpNext = pNodeNextNext; pNodeNext->~node_type(); @@ -752,7 +717,7 @@ namespace eastl inline slist::slist(size_type n, const allocator_type& allocator) : base_type(allocator) { - DoInsertValuesAfter((SListNodeBase*)&internalNode(), n, value_type()); + DoInsertValuesAfter(&internalNode(), n, value_type()); } @@ -760,7 +725,7 @@ namespace eastl inline slist::slist(size_type n, const value_type& value, const allocator_type& allocator) : base_type(allocator) { - DoInsertValuesAfter((SListNodeBase*)&internalNode(), n, value); + DoInsertValuesAfter(&internalNode(), n, value); } @@ -768,7 +733,7 @@ namespace eastl inline slist::slist(const slist& x) : base_type(x.internalAllocator()) { - DoInsertAfter((SListNodeBase*)&internalNode(), const_iterator((SListNodeBase*)x.internalNode().mpNext), const_iterator(NULL), false_type()); + DoInsertAfter(&internalNode(), const_iterator(x.internalNode().mpNext), const_iterator(NULL), false_type()); } @@ -791,7 +756,7 @@ namespace eastl inline slist::slist(std::initializer_list ilist, const allocator_type& allocator) : base_type(allocator) { - DoInsertAfter((SListNodeBase*)&internalNode(), ilist.begin(), ilist.end()); + DoInsertAfter(&internalNode(), ilist.begin(), ilist.end()); } @@ -800,7 +765,7 @@ namespace eastl inline slist::slist(InputIterator first, InputIterator last) : base_type(EASTL_SLIST_DEFAULT_ALLOCATOR) { - DoInsertAfter((SListNodeBase*)&internalNode(), first, last); + DoInsertAfter(&internalNode(), first, last); } @@ -808,7 +773,7 @@ namespace eastl inline typename slist::iterator slist::begin() EA_NOEXCEPT { - return iterator((SListNodeBase*)internalNode().mpNext); + return iterator(internalNode().mpNext); } @@ -816,7 +781,7 @@ namespace eastl inline typename slist::const_iterator slist::begin() const EA_NOEXCEPT { - return const_iterator((SListNodeBase*)internalNode().mpNext); + return const_iterator(internalNode().mpNext); } @@ -824,7 +789,7 @@ namespace eastl inline typename slist::const_iterator slist::cbegin() const EA_NOEXCEPT { - return const_iterator((SListNodeBase*)internalNode().mpNext); + return const_iterator(internalNode().mpNext); } @@ -856,7 +821,7 @@ namespace eastl inline typename slist::iterator slist::before_begin() EA_NOEXCEPT { - return iterator((SListNodeBase*)&internalNode()); + return iterator(&internalNode()); } @@ -864,7 +829,7 @@ namespace eastl inline typename slist::const_iterator slist::before_begin() const EA_NOEXCEPT { - return const_iterator((SListNodeBase*)&internalNode()); + return const_iterator(&internalNode()); } @@ -872,7 +837,7 @@ namespace eastl inline typename slist::const_iterator slist::cbefore_begin() const EA_NOEXCEPT { - return const_iterator((SListNodeBase*)&internalNode()); + return const_iterator(&internalNode()); } @@ -880,7 +845,7 @@ namespace eastl inline typename slist::iterator slist::previous(const_iterator position) { - return iterator(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode)); + return iterator(SListNodeGetPrevious(&internalNode(), position.mpNode)); } @@ -888,7 +853,7 @@ namespace eastl inline typename slist::const_iterator slist::previous(const_iterator position) const { - return const_iterator(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode)); + return const_iterator(SListNodeGetPrevious(&internalNode(), position.mpNode)); } @@ -926,14 +891,14 @@ namespace eastl template void slist::emplace_front(Args&&... args) { - DoInsertValueAfter((SListNodeBase*)&internalNode(), eastl::forward(args)...); + DoInsertValueAfter(&internalNode(), eastl::forward(args)...); } template inline void slist::push_front(const value_type& value) { - SListNodeInsertAfter((SListNodeBase*)&internalNode(), (SListNodeBase*)DoCreateNode(value)); + SListNodeInsertAfter(&internalNode(), DoCreateNode(value)); #if EASTL_SLIST_SIZE_CACHE ++mSize; #endif @@ -944,7 +909,7 @@ namespace eastl inline typename slist::reference slist::push_front() { - SListNodeInsertAfter((SListNodeBase*)&internalNode(), (SListNodeBase*)DoCreateNode()); + SListNodeInsertAfter(&internalNode(), DoCreateNode()); #if EASTL_SLIST_SIZE_CACHE ++mSize; #endif @@ -1079,14 +1044,14 @@ namespace eastl inline typename slist::size_type slist::size() const EA_NOEXCEPT { - return SListNodeGetSize((SListNodeBase*)internalNode().mpNext); + return SListNodeGetSize(internalNode().mpNext); } template inline void slist::clear() EA_NOEXCEPT { - DoEraseAfter((SListNodeBase*)&internalNode(), NULL); + DoEraseAfter(&internalNode(), NULL); } @@ -1107,7 +1072,7 @@ namespace eastl template void slist::resize(size_type n, const value_type& value) { - SListNodeBase* pNode = (SListNodeBase*)&internalNode(); + SListNodeBase* pNode = &internalNode(); for(; pNode->mpNext && (n > 0); --n) pNode = pNode->mpNext; @@ -1130,7 +1095,7 @@ namespace eastl inline typename slist::iterator slist::insert(const_iterator position) { - return iterator((SListNodeBase*)DoInsertValueAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), value_type())); + return iterator(DoInsertValueAfter(SListNodeGetPrevious(&internalNode(), position.mpNode), value_type())); } @@ -1138,7 +1103,7 @@ namespace eastl inline typename slist::iterator slist::insert(const_iterator position, const value_type& value) { - return iterator((SListNodeBase*)DoInsertValueAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), value)); + return iterator(DoInsertValueAfter(SListNodeGetPrevious(&internalNode(), position.mpNode), value)); } @@ -1146,7 +1111,7 @@ namespace eastl inline void slist::insert(const_iterator position, size_type n, const value_type& value) { // To do: get rid of DoAssignValues and put its implementation directly here. - DoInsertValuesAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), n, value); + DoInsertValuesAfter(SListNodeGetPrevious(&internalNode(), position.mpNode), n, value); } @@ -1154,7 +1119,7 @@ namespace eastl template inline void slist::insert(const_iterator position, InputIterator first, InputIterator last) { - DoInsertAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), first, last); + DoInsertAfter(SListNodeGetPrevious(&internalNode(), position.mpNode), first, last); } @@ -1170,7 +1135,7 @@ namespace eastl inline typename slist::iterator slist::insert_after(const_iterator position, const value_type& value) { - return iterator((SListNodeBase*)DoInsertValueAfter((SListNodeBase*)position.mpNode, value)); + return iterator(DoInsertValueAfter(position.mpNode, value)); } @@ -1178,7 +1143,7 @@ namespace eastl inline typename slist::iterator slist::insert_after(const_iterator position, size_type n, const value_type& value) { - return iterator((SListNodeBase*)DoInsertValuesAfter((SListNodeBase*)position.mpNode, n, value)); + return iterator(DoInsertValuesAfter(position.mpNode, n, value)); } @@ -1186,7 +1151,7 @@ namespace eastl inline typename slist::iterator slist::insert_after(const_iterator position, std::initializer_list ilist) { - return iterator((SListNodeBase*)DoInsertAfter((SListNodeBase*)position.mpNode, ilist.begin(), ilist.end(), false_type())); + return iterator(DoInsertAfter(position.mpNode, ilist.begin(), ilist.end(), false_type())); } @@ -1195,7 +1160,7 @@ namespace eastl inline typename slist::iterator slist::insert_after(const_iterator position, InputIterator first, InputIterator last) { - return iterator((SListNodeBase*)DoInsertAfter((SListNodeBase*)position.mpNode, first, last)); + return iterator(DoInsertAfter(position.mpNode, first, last)); } @@ -1212,7 +1177,7 @@ namespace eastl inline typename slist::iterator slist::emplace_after(const_iterator position, Args&&... args) { - return iterator((SListNodeBase*)DoInsertValueAfter(position.mpNode, eastl::forward(args)...)); + return iterator(DoInsertValueAfter(position.mpNode, eastl::forward(args)...)); } @@ -1220,7 +1185,7 @@ namespace eastl inline typename slist::iterator slist::erase(const_iterator position) { - return DoEraseAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode)); + return DoEraseAfter(SListNodeGetPrevious(&internalNode(), position.mpNode)); } @@ -1228,7 +1193,7 @@ namespace eastl inline typename slist::iterator slist::erase(const_iterator first, const_iterator last) { - return DoEraseAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)first.mpNode), (SListNodeBase*)last.mpNode); + return DoEraseAfter(SListNodeGetPrevious(&internalNode(), first.mpNode), last.mpNode); } @@ -1236,7 +1201,7 @@ namespace eastl inline typename slist::iterator slist::erase_after(const_iterator position) { - return iterator(DoEraseAfter((SListNodeBase*)position.mpNode)); + return iterator(DoEraseAfter(position.mpNode)); } @@ -1244,7 +1209,7 @@ namespace eastl inline typename slist::iterator slist::erase_after(const_iterator before_first, const_iterator last) { - return iterator(DoEraseAfter((SListNodeBase*)before_first.mpNode, (SListNodeBase*)last.mpNode)); + return iterator(DoEraseAfter(before_first.mpNode, last.mpNode)); } @@ -1258,7 +1223,7 @@ namespace eastl { if (static_cast(pNode->mpNext)->mValue == value) { - DoEraseAfter((SListNodeBase*)pNode); // This will take care of modifying pNode->mpNext. + DoEraseAfter(pNode); // This will take care of modifying pNode->mpNext. ++numErased; } else @@ -1278,7 +1243,7 @@ namespace eastl { if (predicate(static_cast(pNode->mpNext)->mValue)) { - DoEraseAfter((SListNodeBase*)pNode); // This will take care of modifying pNode->mpNext. + DoEraseAfter(pNode); // This will take care of modifying pNode->mpNext. ++numErased; } else @@ -1303,9 +1268,9 @@ namespace eastl { if(internalAllocator() == x.internalAllocator()) { - SListNodeSpliceAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), - (SListNodeBase*)&x.internalNode(), - SListNodeGetPrevious((SListNodeBase*)&x.internalNode(), NULL)); + SListNodeSpliceAfter(SListNodeGetPrevious(&internalNode(), position.mpNode), + &x.internalNode(), + SListNodeGetPrevious(&x.internalNode(), NULL)); #if EASTL_SLIST_SIZE_CACHE mSize += x.mSize; @@ -1326,9 +1291,9 @@ namespace eastl { if(internalAllocator() == x.internalAllocator()) { - SListNodeSpliceAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), - SListNodeGetPrevious((SListNodeBase*)&x.internalNode(), (SListNodeBase*)i.mpNode), - (SListNodeBase*)i.mpNode); + SListNodeSpliceAfter(SListNodeGetPrevious(&internalNode(), position.mpNode), + SListNodeGetPrevious(&x.internalNode(), i.mpNode), + i.mpNode); #if EASTL_SLIST_SIZE_CACHE ++mSize; @@ -1356,9 +1321,9 @@ namespace eastl x.mSize -= n; #endif - SListNodeSpliceAfter(SListNodeGetPrevious((SListNodeBase*)&internalNode(), (SListNodeBase*)position.mpNode), - SListNodeGetPrevious((SListNodeBase*)&x.internalNode(), (SListNodeBase*)first.mpNode), - SListNodeGetPrevious((SListNodeBase*)first.mpNode, (SListNodeBase*)last.mpNode)); + SListNodeSpliceAfter(SListNodeGetPrevious(&internalNode(), position.mpNode), + SListNodeGetPrevious(&x.internalNode(), first.mpNode), + SListNodeGetPrevious(first.mpNode, last.mpNode)); } else { @@ -1395,7 +1360,7 @@ namespace eastl { if(internalAllocator() == x.internalAllocator()) { - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)&x.internalNode()); + SListNodeSpliceAfter(position.mpNode, &x.internalNode()); #if EASTL_SLIST_SIZE_CACHE mSize += x.mSize; @@ -1416,7 +1381,7 @@ namespace eastl { if(internalAllocator() == x.internalAllocator()) { - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)i.mpNode); + SListNodeSpliceAfter(position.mpNode, i.mpNode); #if EASTL_SLIST_SIZE_CACHE mSize++; @@ -1445,7 +1410,7 @@ namespace eastl x.mSize -= n; #endif - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)first.mpNode, (SListNodeBase*)last.mpNode); + SListNodeSpliceAfter(position.mpNode, first.mpNode, last.mpNode); } else { @@ -1488,7 +1453,7 @@ namespace eastl // it may come from some other list. We have no choice but to implement an O(n) // brute-force search in our list for 'previous'. - iterator i((SListNodeBase*)&internalNode()); + iterator i(&internalNode()); iterator iEnd(NULL); for( ; i != iEnd; ++i) @@ -1504,7 +1469,7 @@ namespace eastl #endif // Insert the range of [before_first + 1, before_last + 1) after position. - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)before_first.mpNode, (SListNodeBase*)before_last.mpNode); + SListNodeSpliceAfter(position.mpNode, before_first.mpNode, before_last.mpNode); } } @@ -1520,7 +1485,7 @@ namespace eastl // it may come from some other list. We have no choice but to implement an O(n) // brute-force search in our list for 'previous'. - iterator i((SListNodeBase*)&internalNode()); + iterator i(&internalNode()); iterator iEnd(NULL); for( ; i != iEnd; ++i) @@ -1536,7 +1501,7 @@ namespace eastl #endif // Insert the element at previous + 1 after position. - SListNodeSpliceAfter((SListNodeBase*)position.mpNode, (SListNodeBase*)previous.mpNode, (SListNodeBase*)previous.mpNode->mpNext); + SListNodeSpliceAfter(position.mpNode, previous.mpNode, previous.mpNode->mpNext); } @@ -1562,7 +1527,7 @@ namespace eastl inline void slist::reverse() EA_NOEXCEPT { if(internalNode().mpNext) - internalNode().mpNext = static_cast((base_node_type*)SListNodeReverse((SListNodeBase*)internalNode().mpNext)); + internalNode().mpNext = static_cast((base_node_type*)SListNodeReverse(internalNode().mpNext)); } @@ -1626,19 +1591,19 @@ namespace eastl void slist::DoAssign(InputIterator first, InputIterator last, false_type) { base_node_type* pNodePrev = &internalNode(); - node_type* pNode = static_cast(internalNode().mpNext); + base_node_type* pNode = internalNode().mpNext; for(; pNode && (first != last); ++first) { - pNode->mValue = *first; + static_cast(pNode)->mValue = *first; pNodePrev = pNode; - pNode = static_cast(pNode->mpNext); + pNode = pNode->mpNext; } if(first == last) - DoEraseAfter((SListNodeBase*)pNodePrev, NULL); + DoEraseAfter(pNodePrev, NULL); else - DoInsertAfter((SListNodeBase*)pNodePrev, first, last); + DoInsertAfter(pNodePrev, first, last); } @@ -1646,19 +1611,19 @@ namespace eastl void slist::DoAssignValues(size_type n, const value_type& value) { base_node_type* pNodePrev = &internalNode(); - node_type* pNode = static_cast(internalNode().mpNext); + base_node_type* pNode = internalNode().mpNext; for(; pNode && (n > 0); --n) { - pNode->mValue = value; + static_cast(pNode)->mValue = value; pNodePrev = pNode; - pNode = static_cast(pNode->mpNext); + pNode = pNode->mpNext; } if(n) - DoInsertValuesAfter((SListNodeBase*)pNodePrev, n, value); + DoInsertValuesAfter(pNodePrev, n, value); else - DoEraseAfter((SListNodeBase*)pNodePrev, NULL); + DoEraseAfter(pNodePrev, NULL); } @@ -1687,7 +1652,7 @@ namespace eastl { for(; first != last; ++first) { - pNode = SListNodeInsertAfter((SListNodeBase*)pNode, (SListNodeBase*)DoCreateNode(*first)); + pNode = SListNodeInsertAfter(pNode, DoCreateNode(*first)); #if EASTL_SLIST_SIZE_CACHE ++mSize; #endif @@ -1702,11 +1667,11 @@ namespace eastl slist::DoInsertValueAfter(SListNodeBase* pNode) { #if EASTL_SLIST_SIZE_CACHE - pNode = SListNodeInsertAfter((SListNodeBase*)pNode, (SListNodeBase*)DoCreateNode()); + pNode = SListNodeInsertAfter(pNode, DoCreateNode()); ++mSize; return static_cast((base_node_type*)pNode); #else - return static_cast((base_node_type*)SListNodeInsertAfter((SListNodeBase*)pNode, (SListNodeBase*)DoCreateNode())); + return static_cast((base_node_type*)SListNodeInsertAfter(pNode, DoCreateNode())); #endif } @@ -1716,7 +1681,7 @@ namespace eastl inline typename slist::node_type* slist::DoInsertValueAfter(SListNodeBase* pNode, Args&&... args) { - SListNodeBase* pNodeNew = (SListNodeBase*)DoCreateNode(eastl::forward(args)...); + SListNodeBase* pNodeNew = DoCreateNode(eastl::forward(args)...); pNode = SListNodeInsertAfter(pNode, pNodeNew); #if EASTL_LIST_SIZE_CACHE ++mSize; // Increment the size after the node creation because we need to assume an exception can occur in the creation. @@ -1731,7 +1696,7 @@ namespace eastl { for(size_type i = 0; i < n; ++i) { - pNode = SListNodeInsertAfter((SListNodeBase*)pNode, (SListNodeBase*)DoCreateNode(value)); + pNode = SListNodeInsertAfter(pNode, DoCreateNode(value)); #if EASTL_SLIST_SIZE_CACHE ++mSize; // We don't do a single mSize += n at the end because an exception may result in only a partial range insertion. #endif diff --git a/include/EASTL/sort.h b/include/EASTL/sort.h index fb1c6e5d..1ed646cc 100644 --- a/include/EASTL/sort.h +++ b/include/EASTL/sort.h @@ -288,9 +288,8 @@ namespace eastl if(first != last) { - RandomAccessIterator iCurrent, iBack, iSorted, iInsertFirst; - difference_type nSize = last - first; - difference_type nSpace = 1; // nSpace is the 'h' value of the ShellSort algorithm. + const difference_type nSize = last - first; + difference_type nSpace = 1; // nSpace is the 'h' value of the ShellSort algorithm. while(nSpace < nSize) nSpace = (nSpace * 3) + 1; // This is the Knuth 'h' sequence: 1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720, 797161, 2391484, 7174453, 21523360, 64570081, 193710244, @@ -299,13 +298,18 @@ namespace eastl { for(difference_type i = 0; i < nSpace; i++) { - iInsertFirst = first + i; + const RandomAccessIterator iInsertFirst = first + i; - for(iSorted = iInsertFirst + nSpace; iSorted < last; iSorted += nSpace) + // Note: we can only move the iterator forward if we know we won't overrun the + // end(), otherwise we can invoke undefined behaviour. So we need to check we + // have enough space before moving the iterator. + RandomAccessIterator iSorted = iInsertFirst; + while(distance(iSorted, last) > nSpace) { - iBack = iCurrent = iSorted; - - for(; (iCurrent != iInsertFirst) && compare(*iCurrent, *(iBack -= nSpace)); iCurrent = iBack) + iSorted += nSpace; + + RandomAccessIterator iCurrent = iSorted; + for(RandomAccessIterator iBack = iSorted - nSpace; (iCurrent != iInsertFirst) && compare(*iCurrent, *iBack); iCurrent = iBack, iBack -= nSpace) { EASTL_VALIDATE_COMPARE(!compare(*iBack, *iCurrent)); // Validate that the compare function is sane. eastl::iter_swap(iCurrent, iBack); @@ -715,20 +719,18 @@ namespace eastl template inline RandomAccessIterator get_partition_impl(RandomAccessIterator first, RandomAccessIterator last, T&& pivotValue) { - using PureT = decay_t; - for(; ; ++first) { - while(eastl::less()(*first, pivotValue)) + while(*first < pivotValue) { - EASTL_VALIDATE_COMPARE(!eastl::less()(pivotValue, *first)); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!(pivotValue < *first)); // Validate that the compare function is sane. ++first; } --last; - while(eastl::less()(pivotValue, *last)) + while(pivotValue < *last) { - EASTL_VALIDATE_COMPARE(!eastl::less()(*last, pivotValue)); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!(*last < pivotValue)); // Validate that the compare function is sane. --last; } @@ -815,9 +817,9 @@ namespace eastl RandomAccessIterator end(current), prev(current); value_type value(eastl::forward(*current)); - for(--prev; eastl::less()(value, *prev); --end, --prev) // We skip checking for (prev >= first) because quick_sort (our caller) makes this unnecessary. + for(--prev; value < *prev; --end, --prev) // We skip checking for (prev >= first) because quick_sort (our caller) makes this unnecessary. { - EASTL_VALIDATE_COMPARE(!eastl::less()(*prev, value)); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!(*prev < value)); // Validate that the compare function is sane. *end = eastl::forward(*prev); } @@ -862,9 +864,9 @@ namespace eastl for(RandomAccessIterator i = middle; i < last; ++i) { - if(eastl::less()(*i, *first)) + if(*i < *first) { - EASTL_VALIDATE_COMPARE(!eastl::less()(*first, *i)); // Validate that the compare function is sane. + EASTL_VALIDATE_COMPARE(!(*first < *i)); // Validate that the compare function is sane. value_type temp(eastl::forward(*i)); *i = eastl::forward(*first); eastl::adjust_heap @@ -1542,9 +1544,17 @@ namespace eastl // To consider: Convert the implementation to use first/last instead of first/size. const intptr_t size = (intptr_t)(last - first); - - if(size < 64) + if (size == 0) + { + // This branch is necessary because the expression `first + 1` below is undefined + // behaviour when first is nullptr (for example when it is the begin() iterator of an + // empty vector). + return; + } + else if (size < 64) + { insertion_sort_already_started(first, first + size, first + 1, compare); + } else { tim_sort_run run_stack[kTimSortStackSize]; @@ -1664,10 +1674,10 @@ namespace eastl RandomAccessIterator temp; uint32_t i; - bool doSeparateHistogramCalculation = true; - uint32_t j; - for (j = 0; j < (8 * sizeof(IntegerType)); j += DigitBits) + + constexpr uint32_t kMaxDigitBits = 8 * sizeof(IntegerType); + for (uint32_t j = 0; j < kMaxDigitBits; j += DigitBits) { if (doSeparateHistogramCalculation) { @@ -1690,7 +1700,8 @@ namespace eastl doSeparateHistogramCalculation = false; // If this is the last digit position, then don't calculate a histogram - if (j == (8 * sizeof(IntegerType) - DigitBits)) + const uint32_t jNext = j + DigitBits; + if (jNext >= kMaxDigitBits) { bucketPosition[0] = 0; for (i = 0; i < numBuckets - 1; i++) @@ -1716,15 +1727,14 @@ namespace eastl } bucketSize[numBuckets - 1] = 0; - uint32_t jNext = j + DigitBits; for (temp = srcFirst; temp != last; ++temp) { - IntegerType key = extractKey(*temp); + const IntegerType key = extractKey(*temp); const size_t digit = (key >> j) & bucketMask; buffer[bucketPosition[digit]++] = *temp; // Update histogram for the next scatter operation - ++bucketSize[(extractKey(*temp) >> jNext) & bucketMask]; + ++bucketSize[(key >> jNext) & bucketMask]; } } diff --git a/include/EASTL/span.h b/include/EASTL/span.h index 9c47f5b3..ef2a1351 100644 --- a/include/EASTL/span.h +++ b/include/EASTL/span.h @@ -54,6 +54,16 @@ namespace eastl // template struct SubspanExtent : eastl::integral_constant {}; + + // is_eastl_array + // + // is an eastl::array with elements T? + // NOT the same as is_array, which is a type trait for the C-style array type. + template + struct is_eastl_array : public eastl::false_type {}; + + template + struct is_eastl_array, T> : public eastl::true_type {}; } template @@ -99,7 +109,7 @@ namespace eastl // template using SfinaeForGenericContainers = - enable_if_t && !is_same_v> && + enable_if_t && !Internal::is_eastl_array::value && !is_array_v && Internal::HasSizeAndData::value && is_convertible_v()))> (*)[], element_type (*)[]>>; diff --git a/include/EASTL/string.h b/include/EASTL/string.h index 3a70b79f..d6e39216 100644 --- a/include/EASTL/string.h +++ b/include/EASTL/string.h @@ -876,7 +876,7 @@ namespace eastl template inline basic_string::basic_string(const view_type& sv, const allocator_type& allocator) - : basic_string(sv.data(), sv.size(), allocator) + : basic_string(sv.data(), static_cast(sv.size()), allocator) { } @@ -1962,7 +1962,8 @@ namespace eastl const size_type n = (size_type)(pEnd - pBegin); if(n <= internalLayout().GetSize()) { - memmove(internalLayout().BeginPtr(), pBegin, (size_t)n * sizeof(value_type)); + if(n) + memmove(internalLayout().BeginPtr(), pBegin, (size_t)n * sizeof(value_type)); erase(internalLayout().BeginPtr() + n, internalLayout().EndPtr()); } else diff --git a/include/EASTL/string_view.h b/include/EASTL/string_view.h index f600e501..7eccc788 100644 --- a/include/EASTL/string_view.h +++ b/include/EASTL/string_view.h @@ -451,23 +451,22 @@ namespace eastl // global operators - // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error - // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline) - // template - // inline EA_CONSTEXPR bool operator==(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0); - // } - // - // // type_identity_t is used in this context to forcefully trigger conversion operators towards basic_string_view. - // // Mostly we want basic_string::operator basic_string_view() to kick-in to be able to compare strings and string_views. - // template - // inline EA_CONSTEXPR bool operator==(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0); - // } + // Extra template parameter is to get around a known limitation in MSVC's ABI (name decoration) + template + inline EA_CONSTEXPR bool operator==(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT + { + return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0); + } + + // type_identity_t is used in this context to forcefully trigger conversion operators towards basic_string_view. + // Mostly we want basic_string::operator basic_string_view() to kick-in to be able to compare strings and string_views. + template + inline EA_CONSTEXPR bool operator==(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT + { + return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0); + } - template + template inline EA_CONSTEXPR bool operator==(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT { return (lhs.size() == rhs.size()) && (lhs.compare(rhs) == 0); @@ -488,231 +487,102 @@ namespace eastl } #else - template - inline EA_CONSTEXPR bool operator==(typename basic_string_view::const_pointer lhs, basic_string_view rhs) EA_NOEXCEPT - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - typedef basic_string_view view_type; - return static_cast(lhs) == rhs; - } - - template - inline EA_CONSTEXPR bool operator==(basic_string_view lhs, typename basic_string_view::const_pointer rhs) EA_NOEXCEPT - { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - typedef basic_string_view view_type; - return lhs == static_cast(rhs); - } - - // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error - // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline) - // template - // inline EA_CONSTEXPR bool operator!=(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return !(lhs == rhs); - // } - // - // template - // inline EA_CONSTEXPR bool operator!=(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return !(lhs == rhs); - // } - - template - inline EA_CONSTEXPR bool operator!=(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT + // Extra template parameter is to get around a known limitation in MSVC's ABI (name decoration) + template + inline EA_CONSTEXPR bool operator!=(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT { return !(lhs == rhs); } - - template - inline EA_CONSTEXPR bool operator!=(typename basic_string_view::const_pointer lhs, basic_string_view rhs) EA_NOEXCEPT + + template + inline EA_CONSTEXPR bool operator!=(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - return !(lhs == rhs); } template - inline EA_CONSTEXPR bool operator!=(basic_string_view lhs, typename basic_string_view::const_pointer rhs) EA_NOEXCEPT + inline EA_CONSTEXPR bool operator!=(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - return !(lhs == rhs); } - // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error - // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline) - // template - // inline EA_CONSTEXPR bool operator<(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return lhs.compare(rhs) < 0; - // } - // - // template - // inline EA_CONSTEXPR bool operator<(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return lhs.compare(rhs) < 0; - // } - - template - inline EA_CONSTEXPR bool operator<(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT + // Extra template parameter is to get around a known limitation in MSVC's ABI (name decoration) + template + inline EA_CONSTEXPR bool operator<(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT { return lhs.compare(rhs) < 0; } - - template - inline EA_CONSTEXPR bool operator<(typename basic_string_view::const_pointer lhs, basic_string_view rhs) EA_NOEXCEPT + + template + inline EA_CONSTEXPR bool operator<(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - typedef basic_string_view view_type; - return static_cast(lhs) < rhs; + return lhs.compare(rhs) < 0; } template - inline EA_CONSTEXPR bool operator<(basic_string_view lhs, typename basic_string_view::const_pointer rhs) EA_NOEXCEPT + inline EA_CONSTEXPR bool operator<(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - - typedef basic_string_view view_type; - return lhs < static_cast(rhs); + return lhs.compare(rhs) < 0; } - // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error - // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline) - // template - // inline EA_CONSTEXPR bool operator<=(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return !(rhs < lhs); - // } - // - // template - // inline EA_CONSTEXPR bool operator<=(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return !(rhs < lhs); - // } - - template - inline EA_CONSTEXPR bool operator<=(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT + // Extra template parameter is to get around a known limitation in MSVC's ABI (name decoration) + template + inline EA_CONSTEXPR bool operator<=(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT { return !(rhs < lhs); } - - template - inline EA_CONSTEXPR bool operator<=(typename basic_string_view::const_pointer lhs, basic_string_view rhs) EA_NOEXCEPT + + template + inline EA_CONSTEXPR bool operator<=(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - return !(rhs < lhs); } template - inline EA_CONSTEXPR bool operator<=(basic_string_view lhs, typename basic_string_view::const_pointer rhs) EA_NOEXCEPT + inline EA_CONSTEXPR bool operator<=(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - return !(rhs < lhs); } - // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error - // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline) - // template - // inline EA_CONSTEXPR bool operator>(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return rhs < lhs; - // } - // - // template - // inline EA_CONSTEXPR bool operator>(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return rhs < lhs; - // } - - template - inline EA_CONSTEXPR bool operator>(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT + // Extra template parameter is to get around a known limitation in MSVC's ABI (name decoration) + template + inline EA_CONSTEXPR bool operator>(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT { return rhs < lhs; } - - template - inline EA_CONSTEXPR bool operator>(typename basic_string_view::const_pointer lhs, basic_string_view rhs) EA_NOEXCEPT + + template + inline EA_CONSTEXPR bool operator>(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - return rhs < lhs; } template - inline EA_CONSTEXPR bool operator>(basic_string_view lhs, typename basic_string_view::const_pointer rhs) EA_NOEXCEPT + inline EA_CONSTEXPR bool operator>(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - return rhs < lhs; } - // Disabling symmetric comparisons that require conversions, since they are causing an internal compiler error - // when compiled using MSVC when certain flags are enabled (/Zi /O2 /Zc:inline) - // template - // inline EA_CONSTEXPR bool operator>=(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return !(lhs < rhs); - // } - // - // template - // inline EA_CONSTEXPR bool operator>=(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT - // { - // return !(lhs < rhs); - // } - - template - inline EA_CONSTEXPR bool operator>=(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT + // Extra template parameter is to get around a known limitation in MSVC's ABI (name decoration) + template + inline EA_CONSTEXPR bool operator>=(basic_string_view lhs, basic_string_view rhs) EA_NOEXCEPT { return !(lhs < rhs); } - - template - inline EA_CONSTEXPR bool operator>=(typename basic_string_view::const_pointer lhs, basic_string_view rhs) EA_NOEXCEPT + + template + inline EA_CONSTEXPR bool operator>=(type_identity_t> lhs, basic_string_view rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - return !(lhs < rhs); } template - inline EA_CONSTEXPR bool operator>=(basic_string_view lhs, typename basic_string_view::const_pointer rhs) EA_NOEXCEPT + inline EA_CONSTEXPR bool operator>=(basic_string_view lhs, type_identity_t> rhs) EA_NOEXCEPT { - // Workaround for basic_string_view comparisons that require conversions, - // since they are causing an internal compiler error when compiled using - // MSVC when certain flags are enabled (/Zi /O2 /Zc:inline). - return !(lhs < rhs); } #endif - // string_view / wstring_view + // string_view / wstring_view typedef basic_string_view string_view; typedef basic_string_view wstring_view; diff --git a/include/EASTL/tuple.h b/include/EASTL/tuple.h index 3cbf644a..b913db24 100644 --- a/include/EASTL/tuple.h +++ b/include/EASTL/tuple.h @@ -28,18 +28,13 @@ namespace eastl template struct TupleTypes {}; // tuple_size helper -template class tuple_size {}; -template class tuple_size : public tuple_size {}; -template class tuple_size : public tuple_size {}; -template class tuple_size : public tuple_size {}; +template struct tuple_size {}; +template struct tuple_size : public tuple_size {}; +template struct tuple_size : public tuple_size {}; +template struct tuple_size : public tuple_size {}; -template class tuple_size> : public integral_constant {}; -template class tuple_size> : public integral_constant {}; - -#if EASTL_VARIABLE_TEMPLATES_ENABLED - template - EA_CONSTEXPR size_t tuple_size_v = tuple_size::value; -#endif +template struct tuple_size> : public integral_constant {}; +template struct tuple_size> : public integral_constant {}; namespace Internal { @@ -48,32 +43,32 @@ namespace Internal } // namespace Internal template -class tuple_size> : public integral_constant +struct tuple_size> : public integral_constant { }; // tuple_element helper to be able to isolate a type given an index template -class tuple_element +struct tuple_element { }; template -class tuple_element> +struct tuple_element> { public: static_assert(I != I, "tuple_element index out of range"); }; template -class tuple_element<0, TupleTypes> +struct tuple_element<0, TupleTypes> { public: typedef H type; }; template -class tuple_element> +struct tuple_element> { public: typedef tuple_element_t> type; @@ -81,28 +76,28 @@ class tuple_element> // specialization for tuple template -class tuple_element> +struct tuple_element> { public: typedef tuple_element_t> type; }; template -class tuple_element> +struct tuple_element> { public: typedef typename add_const>>::type type; }; template -class tuple_element> +struct tuple_element> { public: typedef typename add_volatile>>::type type; }; template -class tuple_element> +struct tuple_element> { public: typedef typename add_cv>>::type type; @@ -110,22 +105,22 @@ class tuple_element> // specialization for TupleImpl template -class tuple_element> : public tuple_element> +struct tuple_element> : public tuple_element> { }; template -class tuple_element> : public tuple_element> +struct tuple_element> : public tuple_element> { }; template -class tuple_element> : public tuple_element> +struct tuple_element> : public tuple_element> { }; template -class tuple_element> : public tuple_element< +struct tuple_element> : public tuple_element< I, const volatile tuple> { }; @@ -195,7 +190,6 @@ namespace Internal { 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 @@ -209,7 +203,7 @@ namespace Internal } template - explicit TupleLeaf(const TupleLeaf& t) + explicit TupleLeaf(const TupleLeaf& t) : mValue(t.getInternal()) { } @@ -239,9 +233,12 @@ namespace Internal class TupleLeaf : 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; + 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::value + explicit TupleLeaf(ValueType&& v) : ValueType(eastl::forward(v)) {} template ::value>::type> explicit TupleLeaf(T&& t) @@ -250,7 +247,7 @@ namespace Internal } template - explicit TupleLeaf(const TupleLeaf& t) + explicit TupleLeaf(const TupleLeaf& t) : ValueType(t.getInternal()) { } @@ -270,9 +267,6 @@ namespace Internal ValueType& getInternal() { return static_cast(*this); } const ValueType& getInternal() const { return static_cast(*this); } - - private: - TupleLeaf& operator=(const TupleLeaf&) = delete; }; @@ -602,79 +596,6 @@ namespace Internal template using MakeTupleReturn_t = typename MakeTupleReturnImpl>::type; - - // tuple_cat helpers - // - // - // - - // TupleCat2Impl - template - struct TupleCat2Impl; - - template - struct TupleCat2Impl, index_sequence, tuple, index_sequence> - { - using ResultType = tuple; - - template - static inline ResultType DoCat2(Tuple1&& t1, Tuple2&& t2) - { - return ResultType(get(eastl::forward(t1))..., get(eastl::forward(t2))...); - } - }; - - // TupleCat2 - template - struct TupleCat2; - - template - struct TupleCat2, tuple> - { - using Is1 = make_index_sequence; - using Is2 = make_index_sequence; - using TCI = TupleCat2Impl, Is1, tuple, Is2>; - using ResultType = typename TCI::ResultType; - - template - static inline ResultType DoCat2(Tuple1&& t1, Tuple2&& t2) - { - return TCI::DoCat2(eastl::forward(t1), eastl::forward(t2)); - } - }; - - // TupleCat - template - struct TupleCat; - - template - struct TupleCat - { - using FirstResultType = typename TupleCat2::ResultType; - using ResultType = typename TupleCat::ResultType; - - template - static inline ResultType DoCat(TupleArg1&& t1, TupleArg2&& t2, TupleArgsRest&&... ts) - { - return TupleCat::DoCat( - TupleCat2::DoCat2(eastl::forward(t1), eastl::forward(t2)), - eastl::forward(ts)...); - } - }; - - template - struct TupleCat - { - using TC2 = TupleCat2>; - using ResultType = typename TC2::ResultType; - - template - static inline ResultType DoCat(TupleArg1&& t1, TupleArg2&& t2) - { - return TC2::DoCat2(eastl::forward(t1), eastl::forward(t2)); - } - }; - #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) template constexpr auto TupleThreeWay(const tuple& t1, const tuple& t2, index_sequence is) @@ -853,13 +774,112 @@ template inline bool operator<=(const tuple inline bool operator>=(const tuple& t1, const tuple& t2) { return !(t1 < t2); } #endif +namespace Internal +{ + // tuple_cat helpers + // + // + // + + // TupleCat2Impl + template + struct TupleCat2Impl; + + template + struct TupleCat2Impl, index_sequence, tuple, index_sequence> + { + using ResultType = tuple; + + template + static inline ResultType DoCat2(Tuple1&& t1, Tuple2&& t2) + { + return ResultType(get(eastl::forward(t1))..., get(eastl::forward(t2))...); + } + }; + + // TupleCat2 + template + struct TupleCat2; + + template + struct TupleCat2, tuple> + { + using Is1 = make_index_sequence; + using Is2 = make_index_sequence; + using TCI = TupleCat2Impl, Is1, tuple, Is2>; + using ResultType = typename TCI::ResultType; + + template + static inline ResultType DoCat2(Tuple1&& t1, Tuple2&& t2) + { + return TCI::DoCat2(eastl::forward(t1), eastl::forward(t2)); + } + }; + + // TupleCat + template + struct TupleCat; + + template + struct TupleCat + { + using TC2 = TupleCat2; + using FirstResultType = typename TupleCat2::ResultType; + using ResultType = typename TupleCat::ResultType; + + template + static inline ResultType DoCat(TupleArg1&& t1, TupleArg2&& t2, TupleArgsRest&&... ts) + { + return TupleCat::DoCat( + TC2::DoCat2(eastl::forward(t1), eastl::forward(t2)), + eastl::forward(ts)...); + } + }; + + template + struct TupleCat + { + using TC2 = TupleCat2; + using ResultType = typename TC2::ResultType; + + template + static inline ResultType DoCat(TupleArg1&& t1, TupleArg2&& t2) + { + return TC2::DoCat2(eastl::forward(t1), eastl::forward(t2)); + } + }; + + template + struct TupleCat> + { + using ResultType = tuple; + + template + static inline tuple DoCat(TupleArg&& t) + { + return eastl::forward(t); + } + }; + + template <> + struct TupleCat<> + { + using ResultType = tuple<>; + + static inline tuple<> DoCat() + { + return {}; + } + }; +} + // tuple_cat // // template -inline typename Internal::TupleCat::ResultType tuple_cat(Tuples&&... ts) +inline typename Internal::TupleCat...>::ResultType tuple_cat(Tuples&&... ts) { - return Internal::TupleCat::DoCat(eastl::forward(ts)...); + return Internal::TupleCat...>::DoCat(eastl::forward(ts)...); } @@ -930,7 +950,7 @@ namespace detail template EA_CONSTEXPR decltype(auto) apply_impl(F&& f, Tuple&& t, index_sequence) { - return invoke(eastl::forward(f), get(eastl::forward(t))...); + return eastl::invoke(eastl::forward(f), get(eastl::forward(t))...); } } // namespace detail @@ -948,26 +968,21 @@ EA_CONSTEXPR decltype(auto) apply(F&& f, Tuple&& t) // C++17 structured bindings support for eastl::tuple // #ifndef EA_COMPILER_NO_STRUCTURED_BINDING - #include +// we can't forward declare tuple_size and tuple_element because some std implementations +// don't declare it in the std namespace, but instead alias it. +#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::tuple> : public ::eastl::integral_constant + struct tuple_size<::eastl::tuple> : public ::eastl::integral_constant { }; template - class tuple_element> : public ::eastl::tuple_element> + struct tuple_element> : public ::eastl::tuple_element> { }; - - EA_RESTORE_CLANG_WARNING() } #endif diff --git a/include/EASTL/type_traits.h b/include/EASTL/type_traits.h index 73d2216f..f09986f7 100644 --- a/include/EASTL/type_traits.h +++ b/include/EASTL/type_traits.h @@ -28,14 +28,6 @@ // * Allowing for different logic pathways based on data types. // * Allowing for compile-type assertions about data type expectations. // -// Most of the type traits are automatically detected and implemented by the compiler. -// However, EASTL allows for the user to explicitly give the compiler hints about -// type traits that the compiler cannot know, via the EASTL_DECLARE declarations. -// If the user has a class that is relocatable (i.e. can safely use memcpy to copy values), -// the user can use the EASTL_DECLARE_TRIVIAL_RELOCATE declaration to tell the compiler -// that the class can be copied via memcpy. This will automatically significantly speed -// up some containers and algorithms that use that class. -// // Here is an example of using type traits to tell if a value is a floating point // value or not: // @@ -44,11 +36,12 @@ // assert(is_floating_point::value); // } // -// Here is an example of declaring a class as relocatable and using it in a vector. -// -// EASTL_DECLARE_TRIVIAL_RELOCATE(Widget); // Usually you put this at the Widget class declaration. +// In this example, if Widget is trivally copyable. // vector wVector; -// wVector.erase(wVector.begin()); // This operation will be optimized via using memcpy. +// .. add elements ... +// wVector.erase(wVector.begin()); +// The vector::erase() operation will optimize the moving of [begin() + 1, end()) to [begin(), end()) +// by using memcpy instead of explicitly calling the copy constructor of each element. // // The following is a full list of the currently recognized type traits. Most of these // are implemented as of this writing, but if there is one that is missing, feel free @@ -87,7 +80,6 @@ // is_trivially_copyable // is_standard_layout // is_pod T is a POD type. -// is_literal_type // is_empty T is an empty class. // is_polymorphic T is a polymorphic class. // is_abstract T is an abstract class. @@ -158,7 +150,6 @@ // conditional // common_type // underlying_type -// result_of // // integral_constant // bool_constant @@ -166,14 +157,8 @@ // false_type // // EASTL extension type traits -// identity Simply sets T as type. // is_aligned Defined as true if the type has alignment requirements greater than default alignment, which is taken to be 8. is_aligned is not found in Boost nor C++11, though alignment_of is. // union_cast Allows for easy-to-read casting between types that are unrelated but have binary equivalence. The classic use case is converting between float and int32_t bit representations. -// is_array_of_known_bounds -// is_array_of_unknown_bounds -// add_signed Deprecated in favor of make_signed. -// add_unsigned Deprecated in favor of make_unsigned. -// add_reference // yes_type // no_type // is_swappable Found in @@ -188,6 +173,12 @@ // is_detected_convertible Check that the type we obtain after expanding some arguments (Args) over a constraint (Op) is convertible to Expected. // // Deprecated pre-C++11 type traits +// add_reference Deprecated in favor of add_lvalue_reference(_t). +// add_signed Deprecated in favor of make_signed. +// add_unsigned Deprecated in favor of make_unsigned. +// identity Simply sets T as type. Use type_identity(_t) instead. +// is_array_of_known_bounds Deprecated in favor of is_bounded_array. +// is_array_of_unknown_bounds Deprecated in favor of is_unbounded_array. // has_trivial_constructor The default constructor for T is trivial. // has_trivial_copy The copy constructor for T is trivial. // has_trivial_assign The assignment operator for T is trivial. @@ -197,14 +188,9 @@ // has_nothrow_assign The assignment operator for T has an empty exception specification or can otherwise be deduced never to throw an exception. // *has_trivial_relocate T can be moved to a new location via bitwise copy. Note that C++11 rvalue/move functionality supercedes this. // -// * has_trivial_relocate is not found in Boost nor the pre-C++ standard update proposal. -// However, it is somewhat useful in pre-C++11 environments (prior to move semantics) -// for allowing the generation of optimized object moving operations. It is similar to -// the is_pod type trait, but goes further and allows non-pod classes to be categorized -// as relocatable. Such categorization is something that no compiler can do, as only -// the user can know if it is such. Thus EASTL_DECLARE_TRIVIAL_RELOCATE is provided to -// allow the user to give the compiler a hint. However, C++11 rvalue/move functionality -// supercedes this and will eventually fully displace it. +// Deprecated in C++17 +// is_literal_type Deprecated: use constexpr if to determine whether an expression is constant evaluated. +// result_of Deprecated: use invoke_result instead. // /////////////////////////////////////////////////////////////////////////////// @@ -344,6 +330,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // type_select // + // Deprecated in C++17. Use conditional::type instead. + // // This is used to declare a type from one of two type options. // The result is based on the condition type. This has certain uses // in template metaprogramming. @@ -354,14 +342,14 @@ namespace eastl // using ChosenType = type_select_t, ChoiceAType, ChoiceBType>; // template - struct type_select { typedef ConditionIsTrueType type; }; + struct EASTL_REMOVE_AT_2024_APRIL type_select { typedef ConditionIsTrueType type; }; template - struct type_select { typedef ConditionIsFalseType type; }; + struct EASTL_REMOVE_AT_2024_APRIL type_select { typedef ConditionIsFalseType type; }; #if EASTL_VARIABLE_TEMPLATES_ENABLED template - using type_select_t = typename type_select::type; + using type_select_t EASTL_REMOVE_AT_2024_APRIL = typename type_select::type; #endif @@ -379,32 +367,40 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // type_or // + // Deprecated in C++17. Use disjunction instead. + // Note type_or has boolean non-type template parameters + // whereas disjunction has type template parameters (most commonly bool_constant). + // // This is a utility class for creating composite type traits. // template - struct type_or; + struct EASTL_REMOVE_AT_2024_APRIL type_or; template - struct type_or { static const bool value = true; }; + struct EASTL_REMOVE_AT_2024_APRIL type_or { static const bool value = true; }; template <> - struct type_or { static const bool value = false; }; + struct EASTL_REMOVE_AT_2024_APRIL type_or { static const bool value = false; }; /////////////////////////////////////////////////////////////////////// // type_and // + // Deprecated in C++17. Use conjunction instead. + // Note type_and has boolean non-type template parameters + // whereas conjunction has type template parameters (most commonly bool_constant). + // // This is a utility class for creating composite type traits. // template - struct type_and; + struct EASTL_REMOVE_AT_2024_APRIL type_and; template - struct type_and{ static const bool value = false; }; + struct EASTL_REMOVE_AT_2024_APRIL type_and{ static const bool value = false; }; template <> - struct type_and{ static const bool value = true; }; + struct EASTL_REMOVE_AT_2024_APRIL type_and{ static const bool value = true; }; @@ -414,7 +410,7 @@ namespace eastl // This is a utility class for creating composite type traits. // template - struct type_equal{ static const bool value = (b1 == b2); }; + struct EASTL_REMOVE_AT_2024_APRIL type_equal{ static const bool value = (b1 == b2); }; @@ -424,20 +420,24 @@ namespace eastl // This is a utility class for creating composite type traits. // template - struct type_not_equal{ static const bool value = (b1 != b2); }; + struct EASTL_REMOVE_AT_2024_APRIL type_not_equal{ static const bool value = (b1 != b2); }; /////////////////////////////////////////////////////////////////////// // type_not // + // Deprecated in C++17. Use negation instead. + // Note type_not has a boolean non-type template parameter + // whereas negation has a type template parameter (most commonly bool_constant). + // // This is a utility class for creating composite type traits. // template - struct type_not{ static const bool value = true; }; + struct EASTL_REMOVE_AT_2024_APRIL type_not{ static const bool value = true; }; template <> - struct type_not{ static const bool value = false; }; + struct EASTL_REMOVE_AT_2024_APRIL type_not{ static const bool value = false; }; @@ -572,11 +572,11 @@ namespace eastl // backwards compatibility. // template - struct identity { using type = T; }; + struct EASTL_REMOVE_AT_2024_APRIL identity { using type = T; }; #if EASTL_VARIABLE_TEMPLATES_ENABLED template - using identity_t = typename identity::type; + using identity_t EASTL_REMOVE_AT_2024_APRIL = typename identity::type; #endif @@ -795,6 +795,8 @@ namespace eastl /////////////////////////////////////////////////////////////////////// // add_reference + // + // Deprecated. Use add_lvalue_reference_t instead. // // Add reference to a type. // @@ -816,7 +818,7 @@ namespace eastl template struct add_reference_impl{ typedef T type; }; #endif - template struct add_reference { typedef typename add_reference_impl::type type; }; + template struct EASTL_REMOVE_AT_2024_APRIL add_reference { typedef typename add_reference_impl::type type; }; diff --git a/include/EASTL/utility.h b/include/EASTL/utility.h index 1e6b9223..1312f0a0 100644 --- a/include/EASTL/utility.h +++ b/include/EASTL/utility.h @@ -243,7 +243,7 @@ namespace eastl 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); + eastl::iter_swap_impl, eastl::is_same, eastl::is_same>::value >::iter_swap(a, b); } @@ -537,6 +537,8 @@ namespace eastl EA_CPP14_CONSTEXPR pair(pair&& p) = default; EA_CPP14_CONSTEXPR pair(const pair&) = default; + EA_CPP14_CONSTEXPR pair& operator=(const pair&) = default; + EA_CPP14_CONSTEXPR pair& operator=(pair&&) = default; template < typename U, @@ -604,14 +606,6 @@ namespace eastl } 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>> @@ -622,14 +616,6 @@ namespace eastl 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>> @@ -662,7 +648,7 @@ namespace eastl /// generic programming. /// template - struct use_self // : public unary_function // Perhaps we want to make it a subclass of unary_function. + struct use_self { typedef T result_type; @@ -693,7 +679,7 @@ namespace eastl /// 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. + struct use_second { typedef Pair argument_type; typedef typename Pair::second_type result_type; @@ -827,38 +813,38 @@ namespace eastl #if EASTL_TUPLE_ENABLED template - class tuple_size> : public integral_constant + struct tuple_size> : public integral_constant { }; template - class tuple_size> : public integral_constant + struct tuple_size> : public integral_constant { }; template - class tuple_element<0, pair> + struct tuple_element<0, pair> { public: typedef T1 type; }; template - class tuple_element<1, pair> + struct tuple_element<1, pair> { public: typedef T2 type; }; template - class tuple_element<0, const pair> + struct tuple_element<0, const pair> { public: typedef const T1 type; }; template - class tuple_element<1, const pair> + struct tuple_element<1, const pair> { public: typedef const T2 type; @@ -938,26 +924,21 @@ namespace eastl // C++17 structured bindings support for eastl::pair // #ifndef EA_COMPILER_NO_STRUCTURED_BINDING - #include +// we can't forward declare tuple_size and tuple_element because some std implementations +// don't declare it in the std namespace, but instead alias it. +#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 + struct tuple_size<::eastl::pair> : public ::eastl::integral_constant { }; template - class tuple_element> : public ::eastl::tuple_element> + struct tuple_element> : public ::eastl::tuple_element> { }; - - EA_RESTORE_CLANG_WARNING() } #endif diff --git a/include/EASTL/variant.h b/include/EASTL/variant.h index 8f30c05c..50616b6c 100644 --- a/include/EASTL/variant.h +++ b/include/EASTL/variant.h @@ -1288,6 +1288,7 @@ namespace eastl }; + template struct visitor_r { @@ -1310,7 +1311,6 @@ namespace eastl eastl::get(eastl::forward(variant))); } }; - template<> struct visitor_r : public visitor_r {}; template<> struct visitor_r : public visitor_r {}; template<> struct visitor_r : public visitor_r {}; @@ -1366,9 +1366,10 @@ namespace eastl } #endif } + EA_RESTORE_VC_WARNING() template - static EA_CONSTEXPR void visit_static_assert_check(Variants&&... variants) + static EA_CONSTEXPR void visit_static_assert_check(Variants&&...) { static_assert(sizeof...(Variants) > 0, "`visit` at least one variant instance must be passed as an argument to the visit function"); @@ -1376,7 +1377,6 @@ namespace eastl static_assert(conjunction_v>...>, "`visit` all variants passed to eastl::visit() must have the same type"); } - EA_RESTORE_VC_WARNING() // visit // diff --git a/include/EASTL/vector.h b/include/EASTL/vector.h index b6ca8dcf..509ab31e 100644 --- a/include/EASTL/vector.h +++ b/include/EASTL/vector.h @@ -138,6 +138,8 @@ namespace eastl static const size_type kMaxSize = (size_type)-2; /// -1 is reserved for 'npos'. It also happens to be slightly beneficial that kMaxSize is a value less than -1, as it helps us deal with potential integer wraparound issues. #endif + size_type GetNewCapacity(size_type currentCapacity); + protected: T* mpBegin; T* mpEnd; @@ -162,7 +164,6 @@ namespace eastl protected: T* DoAllocate(size_type n); void DoFree(T* p, size_type n); - size_type GetNewCapacity(size_type currentCapacity); }; // VectorBase @@ -179,6 +180,15 @@ namespace eastl typedef VectorBase base_type; typedef vector this_type; + protected: + using base_type::mpBegin; + using base_type::mpEnd; + using base_type::mCapacityAllocator; + using base_type::DoAllocate; + using base_type::DoFree; + using base_type::internalCapacityPtr; + using base_type::internalAllocator; + public: typedef T value_type; typedef T* pointer; @@ -193,15 +203,13 @@ namespace eastl typedef typename base_type::difference_type difference_type; typedef typename base_type::allocator_type allocator_type; - using base_type::mpBegin; - using base_type::mpEnd; - using base_type::mCapacityAllocator; using base_type::npos; using base_type::GetNewCapacity; - using base_type::DoAllocate; - using base_type::DoFree; - using base_type::internalCapacityPtr; - using base_type::internalAllocator; + +#if EA_IS_ENABLED(EASTL_DEPRECATIONS_FOR_2024_APRIL) + static_assert(!is_const::value, "vector value_type must be non-const."); + static_assert(!is_volatile::value, "vector value_type must be non-volatile."); +#endif public: vector() EA_NOEXCEPT_IF(EA_NOEXCEPT_EXPR(EASTL_VECTOR_DEFAULT_ALLOCATOR)); @@ -214,6 +222,8 @@ namespace eastl vector(this_type&& x, const allocator_type& allocator); vector(std::initializer_list ilist, const allocator_type& allocator = EASTL_VECTOR_DEFAULT_ALLOCATOR); + // note: this has pre-C++11 semantics: + // this constructor is equivalent to the constructor vector(static_cast(first), static_cast(last), allocator) if InputIterator is an integral type. template vector(InputIterator first, InputIterator last, const allocator_type& allocator = EASTL_VECTOR_DEFAULT_ALLOCATOR); @@ -290,6 +300,9 @@ namespace eastl iterator insert(const_iterator position, value_type&& value); iterator insert(const_iterator position, std::initializer_list ilist); + // note: this has pre-C++11 semantics: + // this function is equivalent to insert(const_iterator position, static_cast(first), static_cast(last)) if InputIterator is an integral type. + // ie. same as insert(const_iterator position, size_type n, const value_type& value) template iterator insert(const_iterator position, InputIterator first, InputIterator last); @@ -519,7 +532,7 @@ namespace eastl inline vector::vector(size_type n, const allocator_type& allocator) : base_type(n, allocator) { - eastl::uninitialized_default_fill_n(mpBegin, n); + eastl::uninitialized_value_construct_n(mpBegin, n); mpEnd = mpBegin + n; } @@ -1414,8 +1427,7 @@ namespace eastl internalCapacityPtr() = mpBegin + n; mpEnd = internalCapacityPtr(); - typedef typename eastl::remove_const::type non_const_value_type; // If T is a const type (e.g. const int) then we need to initialize it as if it were non-const. - eastl::uninitialized_fill_n_ptr((non_const_value_type*)mpBegin, n, value); + eastl::uninitialized_fill_n_ptr(mpBegin, n, value); } @@ -1447,8 +1459,7 @@ namespace eastl internalCapacityPtr() = mpBegin + n; mpEnd = internalCapacityPtr(); - typedef typename eastl::remove_const::type non_const_value_type; // If T is a const type (e.g. const int) then we need to initialize it as if it were non-const. - eastl::uninitialized_copy_ptr(first, last, (non_const_value_type*)mpBegin); + eastl::uninitialized_copy_ptr(first, last, mpBegin); } @@ -1815,7 +1826,7 @@ namespace eastl pointer pNewEnd = eastl::uninitialized_move_ptr_if_noexcept(mpBegin, mpEnd, pNewData); #endif - eastl::uninitialized_default_fill_n(pNewEnd, n); + eastl::uninitialized_value_construct_n(pNewEnd, n); pNewEnd += n; eastl::destruct(mpBegin, mpEnd); @@ -1827,7 +1838,7 @@ namespace eastl } else { - eastl::uninitialized_default_fill_n(mpEnd, n); + eastl::uninitialized_value_construct_n(mpEnd, n); mpEnd += n; } } diff --git a/include/EASTL/vector_map.h b/include/EASTL/vector_map.h index 14dec48d..cd714a70 100644 --- a/include/EASTL/vector_map.h +++ b/include/EASTL/vector_map.h @@ -19,6 +19,10 @@ // that the modification of the container potentially invalidates all // existing iterators into the container, unlike what happens with conventional // sets and maps. +// +// This type could conceptually use a eastl::array as its underlying container, +// however the current design requires an allocator aware container. +// Consider using a fixed_vector instead. ////////////////////////////////////////////////////////////////////////////// @@ -68,26 +72,23 @@ namespace eastl /// Our adapter for the comparison function in the template parameters. /// template - class map_value_compare : public binary_function + class map_value_compare : public Compare { public: - Compare c; + explicit map_value_compare(const Compare& x) + : Compare(x) {} - map_value_compare(const Compare& x) - : c(x) {} - - public: bool operator()(const Value& a, const Value& b) const - { return c(a.first, b.first); } + { return Compare::operator()(a.first, b.first); } bool operator()(const Value& a, const Key& b) const - { return c(a.first, b); } + { return Compare::operator()(a.first, b); } bool operator()(const Key& a, const Value& b) const - { return c(a, b.first); } + { return Compare::operator()(a, b.first); } bool operator()(const Key& a, const Key& b) const - { return c(a, b); } + { return Compare::operator()(a, b); } }; // map_value_compare @@ -102,9 +103,9 @@ namespace eastl /// existing iterators into the container, unlike what happens with conventional /// sets and maps. /// - /// Note that the erase functions return iterator and not void. This allows for - /// more efficient use of the container and is consistent with the C++ language - /// defect report #130 (DR 130) + /// This type could conceptually use a eastl::array as its underlying container, + /// however the current design requires an allocator aware container. + /// Consider using a fixed_vector instead. /// /// Note that we set the value_type to be pair and not pair. /// This means that the underlying container (e.g vector) is a container of pair. @@ -120,7 +121,7 @@ namespace eastl template , typename Allocator = EASTLAllocatorType, typename RandomAccessContainer = eastl::vector, Allocator> > - class vector_map : public RandomAccessContainer + class vector_map : protected map_value_compare, Compare>, public RandomAccessContainer { public: typedef RandomAccessContainer base_type; @@ -147,9 +148,6 @@ namespace eastl using base_type::end; using base_type::get_allocator; - protected: - value_compare mValueCompare; // To do: Make this variable go away via the zero base size optimization. - public: // We have an empty ctor and a ctor that takes an allocator instead of one for both // because this way our RandomAccessContainer wouldn't be required to have an constructor @@ -267,6 +265,10 @@ namespace eastl mapped_type& operator[](const key_type& k); mapped_type& operator[](key_type&& k); + // aka. the standard's at() member function. + mapped_type& at_key(const key_type& k); + const mapped_type& at_key(const key_type& k) const; + // Functions which are disallowed due to being unsafe. void push_back(const value_type& value) = delete; reference push_back() = delete; @@ -301,7 +303,7 @@ namespace eastl template inline vector_map::vector_map() - : base_type(), mValueCompare(C()) + : value_compare(C()), base_type() { get_allocator().set_name(EASTL_VECTOR_MAP_DEFAULT_NAME); } @@ -309,7 +311,7 @@ namespace eastl template inline vector_map::vector_map(const allocator_type& allocator) - : base_type(allocator), mValueCompare(C()) + : value_compare(C()), base_type(allocator) { // Empty } @@ -317,7 +319,7 @@ namespace eastl template inline vector_map::vector_map(const key_compare& comp, const allocator_type& allocator) - : base_type(allocator), mValueCompare(comp) + : value_compare(comp), base_type(allocator) { // Empty } @@ -325,7 +327,7 @@ namespace eastl template inline vector_map::vector_map(const this_type& x) - : base_type(x), mValueCompare(x.mValueCompare) + : value_compare(x), base_type(x) { // Empty } @@ -333,23 +335,25 @@ namespace eastl template inline vector_map::vector_map(this_type&& x) - : base_type(eastl::move(x)), mValueCompare(x.mValueCompare) + // careful to only copy / move the distinct base sub-objects of x: + : value_compare(static_cast(x)), base_type(eastl::move(static_cast(x))) { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + // Empty. Note: x is left with empty contents but its original value_compare instead of the default one. } template inline vector_map::vector_map(this_type&& x, const allocator_type& allocator) - : base_type(eastl::move(x), allocator), mValueCompare(x.mValueCompare) + // careful to only copy / move the distinct base sub-objects of x: + : value_compare(static_cast(x)), base_type(eastl::move(static_cast(x)), allocator) { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + // Empty. Note: x is left with empty contents but its original value_compare instead of the default one. } template inline vector_map::vector_map(std::initializer_list ilist, const key_compare& compare, const allocator_type& allocator) - : base_type(allocator), mValueCompare(compare) + : value_compare(compare), base_type(allocator) { insert(ilist.begin(), ilist.end()); } @@ -358,7 +362,7 @@ namespace eastl template template inline vector_map::vector_map(InputIterator first, InputIterator last) - : base_type(EASTL_VECTOR_MAP_DEFAULT_ALLOCATOR), mValueCompare(key_compare()) + : value_compare(key_compare()), base_type(EASTL_VECTOR_MAP_DEFAULT_ALLOCATOR) { insert(first, last); } @@ -367,7 +371,7 @@ namespace eastl template template inline vector_map::vector_map(InputIterator first, InputIterator last, const key_compare& compare) - : base_type(EASTL_VECTOR_MAP_DEFAULT_ALLOCATOR), mValueCompare(compare) + : value_compare(compare), base_type(EASTL_VECTOR_MAP_DEFAULT_ALLOCATOR) { insert(first, last); } @@ -378,7 +382,7 @@ namespace eastl vector_map::operator=(const this_type& x) { base_type::operator=(x); - mValueCompare = value_compare(x.mValueCompare); + value_compare::operator=(x); return *this; } @@ -387,8 +391,9 @@ namespace eastl inline vector_map& vector_map::operator=(this_type&& x) { - base_type::operator=(eastl::move(x)); - eastl::swap(mValueCompare, x.mValueCompare); + base_type::operator=(eastl::move(static_cast(x))); + using eastl::swap; + swap(static_cast(*this), static_cast(x)); return *this; } @@ -407,7 +412,8 @@ namespace eastl inline void vector_map::swap(this_type& x) { base_type::swap(x); - eastl::swap(mValueCompare, x.mValueCompare); + using eastl::swap; + swap(static_cast(*this), static_cast(x)); } @@ -415,7 +421,7 @@ namespace eastl inline const typename vector_map::key_compare& vector_map::key_comp() const { - return mValueCompare.c; + return static_cast(*this); } @@ -423,7 +429,7 @@ namespace eastl inline typename vector_map::key_compare& vector_map::key_comp() { - return mValueCompare.c; + return static_cast(*this); } @@ -431,7 +437,7 @@ namespace eastl inline const typename vector_map::value_compare& vector_map::value_comp() const { - return mValueCompare; + return static_cast(*this); } @@ -439,7 +445,7 @@ namespace eastl inline typename vector_map::value_compare& vector_map::value_comp() { - return mValueCompare; + return static_cast(*this); } @@ -478,7 +484,7 @@ namespace eastl { const iterator itLB(lower_bound(value.first)); - if((itLB != end()) && !mValueCompare(value, *itLB)) + if((itLB != end()) && !value_compare::operator()(value, *itLB)) return eastl::pair(itLB, false); return eastl::pair(base_type::insert(itLB, value), true); @@ -493,7 +499,7 @@ namespace eastl value_type value(eastl::forward

(otherValue)); const iterator itLB(lower_bound(value.first)); - if((itLB != end()) && !mValueCompare(value, *itLB)) + if((itLB != end()) && !value_compare::operator()(value, *itLB)) return eastl::pair(itLB, false); return eastl::pair(base_type::insert(itLB, eastl::move(value)), true); @@ -507,7 +513,7 @@ namespace eastl value_type value(eastl::pair_first_construct, otherValue); const iterator itLB(lower_bound(value.first)); - if((itLB != end()) && !mValueCompare(value, *itLB)) + if((itLB != end()) && !value_compare::operator()(value, *itLB)) return eastl::pair(itLB, false); return eastl::pair(base_type::insert(itLB, eastl::move(value)), true); @@ -520,7 +526,7 @@ namespace eastl value_type value(eastl::pair_first_construct, eastl::move(otherValue)); const iterator itLB(lower_bound(value.first)); - if((itLB != end()) && !mValueCompare(value, *itLB)) + if((itLB != end()) && !value_compare::operator()(value, *itLB)) return eastl::pair(itLB, false); return eastl::pair(base_type::insert(itLB, eastl::move(value)), true); @@ -536,9 +542,9 @@ namespace eastl // We do a test to see if the position is correct. If so then we insert, // if not then we ignore the input position. - if((position == end()) || mValueCompare(value, *position)) // If the element at position is greater than value... + if((position == end()) || value_compare::operator()(value, *position)) // If the element at position is greater than value... { - if((position == begin()) || mValueCompare(*(position - 1), value)) // If the element before position is less than value... + if((position == begin()) || value_compare::operator()(*(position - 1), value)) // If the element before position is less than value... return base_type::insert(position, value); } @@ -556,9 +562,9 @@ namespace eastl typename vector_map::iterator vector_map::insert(const_iterator position, value_type&& value) { - if((position == end()) || mValueCompare(value, *position)) // If the element at position is greater than value... + if((position == end()) || value_compare::operator()(value, *position)) // If the element at position is greater than value... { - if((position == begin()) || mValueCompare(*(position - 1), value)) // If the element before position is less than value... + if((position == begin()) || value_compare::operator()(*(position - 1), value)) // If the element before position is less than value... return base_type::insert(position, eastl::move(value)); } @@ -692,7 +698,7 @@ namespace eastl inline typename vector_map::iterator vector_map::lower_bound(const key_type& k) { - return eastl::lower_bound(begin(), end(), k, mValueCompare); + return eastl::lower_bound(begin(), end(), k, static_cast(*this)); } @@ -700,7 +706,7 @@ namespace eastl inline typename vector_map::const_iterator vector_map::lower_bound(const key_type& k) const { - return eastl::lower_bound(begin(), end(), k, mValueCompare); + return eastl::lower_bound(begin(), end(), k, static_cast(*this)); } @@ -708,7 +714,7 @@ namespace eastl inline typename vector_map::iterator vector_map::upper_bound(const key_type& k) { - return eastl::upper_bound(begin(), end(), k, mValueCompare); + return eastl::upper_bound(begin(), end(), k, static_cast(*this)); } @@ -716,7 +722,7 @@ namespace eastl inline typename vector_map::const_iterator vector_map::upper_bound(const key_type& k) const { - return eastl::upper_bound(begin(), end(), k, mValueCompare); + return eastl::upper_bound(begin(), end(), k, static_cast(*this)); } @@ -730,7 +736,7 @@ namespace eastl // result is a range of size zero or one. const iterator itLower(lower_bound(k)); - if((itLower == end()) || mValueCompare(k, *itLower)) // If at the end or if (k is < itLower)... + if((itLower == end()) || value_compare::operator()(k, *itLower)) // If at the end or if (k is < itLower)... return eastl::pair(itLower, itLower); iterator itUpper(itLower); @@ -748,7 +754,7 @@ namespace eastl // result is a range of size zero or one. const const_iterator itLower(lower_bound(k)); - if((itLower == end()) || mValueCompare(k, *itLower)) // If at the end or if (k is < itLower)... + if((itLower == end()) || value_compare::operator()(k, *itLower)) // If at the end or if (k is < itLower)... return eastl::pair(itLower, itLower); const_iterator itUpper(itLower); @@ -822,6 +828,33 @@ namespace eastl } + template + inline typename vector_map::mapped_type& + vector_map::at_key(const key_type& k) + { + // use the use const version of ::at to remove duplication + return const_cast(const_cast const*>(this)->at_key(k)); + } + + template + inline const typename vector_map::mapped_type& + vector_map::at_key(const key_type& k) const + { + const_iterator itLB(lower_bound(k)); + + if ((itLB == end()) || key_comp()(k, itLB->first)) + { +#if EASTL_EXCEPTIONS_ENABLED + throw std::out_of_range("vector_map::at key does not exist"); +#else + EASTL_FAIL_MSG("vector_map::at key does not exist"); +#endif + } + + return itLB->second; + } + + /////////////////////////////////////////////////////////////////////////// // global operators diff --git a/include/EASTL/vector_multimap.h b/include/EASTL/vector_multimap.h index 235f6718..3079517a 100644 --- a/include/EASTL/vector_multimap.h +++ b/include/EASTL/vector_multimap.h @@ -19,6 +19,10 @@ // that the modification of the container potentially invalidates all // existing iterators into the container, unlike what happens with conventional // sets and maps. +// +// This type could conceptually use a eastl::array as its underlying container, +// however the current design requires an allocator aware container. +// Consider using a fixed_vector instead. ////////////////////////////////////////////////////////////////////////////// @@ -68,31 +72,26 @@ namespace eastl /// Our adapter for the comparison function in the template parameters. /// template - class multimap_value_compare : public binary_function + class multimap_value_compare : public Compare { public: - Compare c; + explicit multimap_value_compare(const Compare& x) + : Compare(x) {} - multimap_value_compare(const Compare& x) - : c(x) {} - - public: bool operator()(const Value& a, const Value& b) const - { return c(a.first, b.first); } + { return Compare::operator()(a.first, b.first); } bool operator()(const Value& a, const Key& b) const - { return c(a.first, b); } + { return Compare::operator()(a.first, b); } bool operator()(const Key& a, const Value& b) const - { return c(a, b.first); } + { return Compare::operator()(a, b.first); } bool operator()(const Key& a, const Key& b) const - { return c(a, b); } + { return Compare::operator()(a, b); } }; // multimap_value_compare - - /// vector_multimap /// /// Implements a multimap via a random access container such as a vector. @@ -102,9 +101,9 @@ namespace eastl /// existing iterators into the container, unlike what happens with conventional /// sets and maps. /// - /// Note that the erase functions return iterator and not void. This allows for - /// more efficient use of the container and is consistent with the C++ language - /// defect report #130 (DR 130) + /// This type could conceptually use a eastl::array as its underlying container, + /// however the current design requires an allocator aware container. + /// Consider using a fixed_vector instead. /// /// Note that we set the value_type to be pair and not pair. /// This means that the underlying container (e.g vector) is a container of pair. @@ -120,7 +119,7 @@ namespace eastl template , typename Allocator = EASTLAllocatorType, typename RandomAccessContainer = eastl::vector, Allocator> > - class vector_multimap : public RandomAccessContainer + class vector_multimap : protected multimap_value_compare, Compare>, public RandomAccessContainer { public: typedef RandomAccessContainer base_type; @@ -146,9 +145,6 @@ namespace eastl using base_type::end; using base_type::get_allocator; - protected: - value_compare mValueCompare; - public: // We have an empty ctor and a ctor that takes an allocator instead of one for both // because this way our RandomAccessContainer wouldn't be required to have an constructor @@ -262,7 +258,7 @@ namespace eastl const iterator itLower(lower_bound(k)); iterator itUpper(itLower); - while((itUpper != end()) && !mValueCompare(k, *itUpper)) + while((itUpper != end()) && !value_compare::operator()(k, *itUpper)) ++itUpper; return eastl::pair(itLower, itUpper); @@ -302,7 +298,7 @@ namespace eastl template inline vector_multimap::vector_multimap() - : base_type(), mValueCompare(C()) + : value_compare(C()), base_type() { #if EASTL_NAME_ENABLED get_allocator().set_name(EASTL_VECTOR_MULTIMAP_DEFAULT_NAME); @@ -312,7 +308,7 @@ namespace eastl template inline vector_multimap::vector_multimap(const allocator_type& allocator) - : base_type(allocator), mValueCompare(C()) + : value_compare(C()), base_type(allocator) { // Empty } @@ -320,7 +316,7 @@ namespace eastl template inline vector_multimap::vector_multimap(const key_compare& comp, const allocator_type& allocator) - : base_type(allocator), mValueCompare(comp) + : value_compare(comp), base_type(allocator) { // Empty } @@ -328,7 +324,7 @@ namespace eastl template inline vector_multimap::vector_multimap(const this_type& x) - : base_type(x), mValueCompare(x.mValueCompare) + : value_compare(x), base_type(x) { // Empty } @@ -336,23 +332,25 @@ namespace eastl template inline vector_multimap::vector_multimap(this_type&& x) - : base_type(eastl::move(x)), mValueCompare(x.mValueCompare) + // careful to only copy / move the distinct base sub-objects of x: + : value_compare(static_cast(x)), base_type(eastl::move(static_cast(x))) { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + // Empty. Note: x is left with empty contents but its original value_compare instead of the default one. } template inline vector_multimap::vector_multimap(this_type&& x, const allocator_type& allocator) - : base_type(eastl::move(x), allocator), mValueCompare(x.mValueCompare) + // careful to only copy / move the distinct base sub-objects of x: + : value_compare(static_cast(x)), base_type(eastl::move(static_cast(x)), allocator) { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + // Empty. Note: x is left with empty contents but its original value_compare instead of the default one. } template inline vector_multimap::vector_multimap(std::initializer_list ilist, const key_compare& compare, const allocator_type& allocator) - : base_type(allocator), mValueCompare(compare) + : value_compare(compare), base_type(allocator) { insert(ilist.begin(), ilist.end()); } @@ -361,7 +359,7 @@ namespace eastl template template inline vector_multimap::vector_multimap(InputIterator first, InputIterator last) - : base_type(EASTL_VECTOR_MULTIMAP_DEFAULT_ALLOCATOR), mValueCompare(key_compare()) + : value_compare(key_compare()), base_type(EASTL_VECTOR_MULTIMAP_DEFAULT_ALLOCATOR) { insert(first, last); } @@ -370,7 +368,7 @@ namespace eastl template template inline vector_multimap::vector_multimap(InputIterator first, InputIterator last, const key_compare& compare) - : base_type(EASTL_VECTOR_MULTIMAP_DEFAULT_ALLOCATOR), mValueCompare(compare) + : value_compare(compare), base_type(EASTL_VECTOR_MULTIMAP_DEFAULT_ALLOCATOR) { insert(first, last); } @@ -381,7 +379,7 @@ namespace eastl vector_multimap::operator=(const this_type& x) { base_type::operator=(x); - mValueCompare = value_compare(x.mValueCompare); + value_compare::operator=(x); return *this; } @@ -391,7 +389,8 @@ namespace eastl vector_multimap::operator=(this_type&& x) { base_type::operator=(eastl::move(x)); - eastl::swap(mValueCompare, x.mValueCompare); + using eastl::swap; + swap(static_cast(*this), static_cast(x)); return *this; } @@ -410,7 +409,8 @@ namespace eastl inline void vector_multimap::swap(this_type& x) { base_type::swap(x); - eastl::swap(mValueCompare, x.mValueCompare); + using eastl::swap; + swap(static_cast(*this), static_cast(x)); } @@ -418,7 +418,7 @@ namespace eastl inline const typename vector_multimap::key_compare& vector_multimap::key_comp() const { - return mValueCompare.c; + return static_cast(*this); } @@ -426,7 +426,7 @@ namespace eastl inline typename vector_multimap::key_compare& vector_multimap::key_comp() { - return mValueCompare.c; + return static_cast(*this); } @@ -434,7 +434,7 @@ namespace eastl inline const typename vector_multimap::value_compare& vector_multimap::value_comp() const { - return mValueCompare; + return static_cast(*this); } @@ -442,7 +442,7 @@ namespace eastl inline typename vector_multimap::value_compare& vector_multimap::value_comp() { - return mValueCompare; + return static_cast(*this); } @@ -522,9 +522,9 @@ namespace eastl // We do a test to see if the position is correct. If so then we insert, // if not then we ignore the input position. However, - if((position == end()) || !mValueCompare(*position, value)) // If value is <= the element at position... + if((position == end()) || !value_compare::operator()(*position, value)) // If value is <= the element at position... { - if((position == begin()) || !mValueCompare(value, *(position - 1))) // If value is >= the element before position... + if((position == begin()) || !value_compare::operator()(value, *(position - 1))) // If value is >= the element before position... return base_type::insert(position, value); } @@ -537,9 +537,9 @@ namespace eastl inline typename vector_multimap::iterator vector_multimap::insert(const_iterator position, value_type&& value) { - if((position == end()) || !mValueCompare(*position, value)) // If value is <= the element at position... + if((position == end()) || !value_compare::operator()(*position, value)) // If value is <= the element at position... { - if((position == begin()) || !mValueCompare(value, *(position - 1))) // If value is >= the element before position... + if((position == begin()) || !value_compare::operator()(value, *(position - 1))) // If value is >= the element before position... return base_type::insert(position, eastl::move(value)); } @@ -678,7 +678,7 @@ namespace eastl inline typename vector_multimap::iterator vector_multimap::lower_bound(const key_type& k) { - return eastl::lower_bound(begin(), end(), k, mValueCompare); + return eastl::lower_bound(begin(), end(), k, static_cast(*this)); } @@ -686,7 +686,7 @@ namespace eastl inline typename vector_multimap::const_iterator vector_multimap::lower_bound(const key_type& k) const { - return eastl::lower_bound(begin(), end(), k, mValueCompare); + return eastl::lower_bound(begin(), end(), k, static_cast(*this)); } @@ -694,7 +694,7 @@ namespace eastl inline typename vector_multimap::iterator vector_multimap::upper_bound(const key_type& k) { - return eastl::upper_bound(begin(), end(), k, mValueCompare); + return eastl::upper_bound(begin(), end(), k, static_cast(*this)); } @@ -702,7 +702,7 @@ namespace eastl inline typename vector_multimap::const_iterator vector_multimap::upper_bound(const key_type& k) const { - return eastl::upper_bound(begin(), end(), k, mValueCompare); + return eastl::upper_bound(begin(), end(), k, static_cast(*this)); } @@ -710,7 +710,7 @@ namespace eastl inline eastl::pair::iterator, typename vector_multimap::iterator> vector_multimap::equal_range(const key_type& k) { - return eastl::equal_range(begin(), end(), k, mValueCompare); + return eastl::equal_range(begin(), end(), k, static_cast(*this)); } @@ -718,7 +718,7 @@ namespace eastl inline eastl::pair::const_iterator, typename vector_multimap::const_iterator> vector_multimap::equal_range(const key_type& k) const { - return eastl::equal_range(begin(), end(), k, mValueCompare); + return eastl::equal_range(begin(), end(), k, static_cast(*this)); } @@ -731,7 +731,7 @@ namespace eastl const iterator itLower(lower_bound(k)); iterator itUpper(itLower); - while((itUpper != end()) && !mValueCompare(k, *itUpper)) + while((itUpper != end()) && !value_compare::operator()(k, *itUpper)) ++itUpper; return eastl::pair(itLower, itUpper); @@ -746,7 +746,7 @@ namespace eastl const const_iterator itLower(lower_bound(k)); const_iterator itUpper(itLower); - while((itUpper != end()) && !mValueCompare(k, *itUpper)) + while((itUpper != end()) && !value_compare::operator()(k, *itUpper)) ++itUpper; return eastl::pair(itLower, itUpper); diff --git a/include/EASTL/vector_multiset.h b/include/EASTL/vector_multiset.h index 7fd10a57..9c7a6490 100644 --- a/include/EASTL/vector_multiset.h +++ b/include/EASTL/vector_multiset.h @@ -19,6 +19,10 @@ // that the modification of the container potentially invalidates all // existing iterators into the container, unlike what happens with conventional // sets and maps. +// +// This type could conceptually use a eastl::array as its underlying container, +// however the current design requires an allocator aware container. +// Consider using a fixed_vector instead. ////////////////////////////////////////////////////////////////////////////// @@ -72,6 +76,10 @@ namespace eastl /// that the modification of the container potentially invalidates all /// existing iterators into the container, unlike what happens with conventional /// sets and maps. + /// + /// This type could conceptually use a eastl::array as its underlying container, + /// however the current design requires an allocator aware container. + /// Consider using a fixed_vector instead. /// /// To consider: std::multiset has the limitation that values in the set cannot /// be modified, with the idea that modifying them would change their sort @@ -82,13 +90,9 @@ namespace eastl /// classes use 'mutable' as needed. See the C++ standard defect report /// #103 (DR 103) for a discussion of this. /// - /// Note that the erase functions return iterator and not void. This allows for - /// more efficient use of the container and is consistent with the C++ language - /// defect report #130 (DR 130) - /// template , typename Allocator = EASTLAllocatorType, typename RandomAccessContainer = eastl::vector > - class vector_multiset : public RandomAccessContainer + class vector_multiset : protected Compare, public RandomAccessContainer { public: typedef RandomAccessContainer base_type; @@ -113,9 +117,6 @@ namespace eastl using base_type::end; using base_type::get_allocator; - protected: - value_compare mCompare; // To consider: Declare this instead as: 'key_compare mKeyCompare' - public: // We have an empty ctor and a ctor that takes an allocator instead of one for both // because this way our RandomAccessContainer wouldn't be required to have an constructor @@ -223,7 +224,7 @@ namespace eastl const iterator itLower(lower_bound(k)); iterator itUpper(itLower); - while((itUpper != end()) && !mCompare(k, *itUpper)) + while((itUpper != end()) && !value_compare::operator()(k, *itUpper)) ++itUpper; return eastl::pair(itLower, itUpper); @@ -264,7 +265,7 @@ namespace eastl template inline vector_multiset::vector_multiset() - : base_type(), mCompare(C()) + : value_compare(), base_type() { get_allocator().set_name(EASTL_VECTOR_MULTISET_DEFAULT_NAME); } @@ -272,7 +273,7 @@ namespace eastl template inline vector_multiset::vector_multiset(const allocator_type& allocator) - : base_type(allocator), mCompare(C()) + : value_compare(), base_type(allocator) { // Empty } @@ -280,7 +281,7 @@ namespace eastl template inline vector_multiset::vector_multiset(const key_compare& comp, const allocator_type& allocator) - : base_type(allocator), mCompare(comp) + : value_compare(comp), base_type(allocator) { // Empty } @@ -289,7 +290,7 @@ namespace eastl template template inline vector_multiset::vector_multiset(InputIterator first, InputIterator last) - : base_type(EASTL_VECTOR_MULTISET_DEFAULT_ALLOCATOR), mCompare(key_compare()) + : value_compare(), base_type(EASTL_VECTOR_MULTISET_DEFAULT_ALLOCATOR) { insert(first, last); } @@ -298,7 +299,7 @@ namespace eastl template template inline vector_multiset::vector_multiset(InputIterator first, InputIterator last, const key_compare& compare) - : base_type(EASTL_VECTOR_MULTISET_DEFAULT_ALLOCATOR), mCompare(compare) + : value_compare(compare), base_type(EASTL_VECTOR_MULTISET_DEFAULT_ALLOCATOR) { insert(first, last); } @@ -306,7 +307,7 @@ namespace eastl template inline vector_multiset::vector_multiset(const this_type& x) - : base_type(x), mCompare(x.mCompare) + : value_compare(x), base_type(x) { // Empty } @@ -314,22 +315,24 @@ namespace eastl template inline vector_multiset::vector_multiset(this_type&& x) - : base_type(eastl::move(x)), mCompare(x.mCompare) + // careful to only copy / move the distinct base sub-objects of x: + : value_compare(static_cast(x)), base_type(eastl::move(static_cast(x))) { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + // Empty. Note: x is left with empty contents but its original value_compare instead of the default one. } template inline vector_multiset::vector_multiset(this_type&& x, const allocator_type& allocator) - : base_type(eastl::move(x), allocator), mCompare(x.mCompare) + // careful to only copy / move the distinct base sub-objects of x: + : value_compare(static_cast(x)), base_type(eastl::move(static_cast(x)), allocator) { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + // Empty. Note: x is left with empty contents but its original value_compare instead of the default one. } template inline vector_multiset::vector_multiset(std::initializer_list ilist, const key_compare& compare, const allocator_type& allocator) - : base_type(allocator), mCompare(compare) + : value_compare(compare), base_type(allocator) { insert(ilist.begin(), ilist.end()); } @@ -340,7 +343,7 @@ namespace eastl vector_multiset::operator=(const this_type& x) { base_type::operator=(x); - mCompare = value_compare(x.mCompare); + value_compare::operator=(x); return *this; } @@ -350,7 +353,8 @@ namespace eastl vector_multiset::operator=(this_type&& x) { base_type::operator=(eastl::move(x)); - eastl::swap(mCompare, x.mCompare); + using eastl::swap; + swap(static_cast(*this), static_cast(x)); return *this; } @@ -369,7 +373,8 @@ namespace eastl inline void vector_multiset::swap(this_type& x) { base_type::swap(x); - eastl::swap(mCompare, x.mCompare); + using eastl::swap; + swap(static_cast(*this), static_cast(x)); } @@ -377,7 +382,7 @@ namespace eastl inline const typename vector_multiset::key_compare& vector_multiset::key_comp() const { - return mCompare; + return static_cast(*this); } @@ -385,7 +390,7 @@ namespace eastl inline typename vector_multiset::key_compare& vector_multiset::key_comp() { - return mCompare; + return static_cast(*this); } @@ -393,7 +398,7 @@ namespace eastl inline const typename vector_multiset::value_compare& vector_multiset::value_comp() const { - return mCompare; + return static_cast(*this); } @@ -401,7 +406,7 @@ namespace eastl inline typename vector_multiset::value_compare& vector_multiset::value_comp() { - return mCompare; + return static_cast(*this); } @@ -468,9 +473,9 @@ namespace eastl // We do a test to see if the position is correct. If so then we insert, // if not then we ignore the input position. However, - if((position == end()) || !mCompare(*position, value)) // If value is <= the element at position... + if((position == end()) || !value_compare::operator()(*position, value)) // If value is <= the element at position... { - if((position == begin()) || !mCompare(value, *(position - 1))) // If value is >= the element before position... + if((position == begin()) || !value_compare::operator()(value, *(position - 1))) // If value is >= the element before position... return base_type::insert(position, value); } @@ -483,9 +488,9 @@ namespace eastl typename vector_multiset::iterator vector_multiset::insert(const_iterator position, value_type&& value) { - if((position == end()) || !mCompare(*position, value)) // If value is <= the element at position... + if((position == end()) || !value_compare::operator()(*position, value)) // If value is <= the element at position... { - if((position == begin()) || !mCompare(value, *(position - 1))) // If value is >= the element before position... + if((position == begin()) || !value_compare::operator()(value, *(position - 1))) // If value is >= the element before position... return base_type::insert(position, eastl::move(value)); } @@ -609,7 +614,7 @@ namespace eastl inline typename vector_multiset::iterator vector_multiset::lower_bound(const key_type& k) { - return eastl::lower_bound(begin(), end(), k, mCompare); + return eastl::lower_bound(begin(), end(), k, static_cast(*this)); } @@ -617,7 +622,7 @@ namespace eastl inline typename vector_multiset::const_iterator vector_multiset::lower_bound(const key_type& k) const { - return eastl::lower_bound(begin(), end(), k, mCompare); + return eastl::lower_bound(begin(), end(), k, static_cast(*this)); } @@ -625,7 +630,7 @@ namespace eastl inline typename vector_multiset::iterator vector_multiset::upper_bound(const key_type& k) { - return eastl::upper_bound(begin(), end(), k, mCompare); + return eastl::upper_bound(begin(), end(), k, static_cast(*this)); } @@ -633,7 +638,7 @@ namespace eastl inline typename vector_multiset::const_iterator vector_multiset::upper_bound(const key_type& k) const { - return eastl::upper_bound(begin(), end(), k, mCompare); + return eastl::upper_bound(begin(), end(), k, static_cast(*this)); } @@ -641,7 +646,7 @@ namespace eastl inline eastl::pair::iterator, typename vector_multiset::iterator> vector_multiset::equal_range(const key_type& k) { - return eastl::equal_range(begin(), end(), k, mCompare); + return eastl::equal_range(begin(), end(), k, static_cast(*this)); } @@ -649,7 +654,7 @@ namespace eastl inline eastl::pair::const_iterator, typename vector_multiset::const_iterator> vector_multiset::equal_range(const key_type& k) const { - return eastl::equal_range(begin(), end(), k, mCompare); + return eastl::equal_range(begin(), end(), k, static_cast(*this)); } @@ -662,7 +667,7 @@ namespace eastl const iterator itLower(lower_bound(k)); iterator itUpper(itLower); - while((itUpper != end()) && !mCompare(k, *itUpper)) + while((itUpper != end()) && !value_compare::operator()(k, *itUpper)) ++itUpper; return eastl::pair(itLower, itUpper); @@ -677,7 +682,7 @@ namespace eastl const const_iterator itLower(lower_bound(k)); const_iterator itUpper(itLower); - while((itUpper != end()) && !mCompare(k, *itUpper)) + while((itUpper != end()) && !value_compare::operator()(k, *itUpper)) ++itUpper; return eastl::pair(itLower, itUpper); diff --git a/include/EASTL/vector_set.h b/include/EASTL/vector_set.h index c03ec556..611ba7ab 100644 --- a/include/EASTL/vector_set.h +++ b/include/EASTL/vector_set.h @@ -19,6 +19,10 @@ // that the modification of the container potentially invalidates all // existing iterators into the container, unlike what happens with conventional // sets and maps. +// +// This type could conceptually use a eastl::array as its underlying container, +// however the current design requires an allocator aware container. +// Consider using a fixed_vector instead. ////////////////////////////////////////////////////////////////////////////// @@ -73,6 +77,10 @@ namespace eastl /// that the modification of the container potentially invalidates all /// existing iterators into the container, unlike what happens with conventional /// sets and maps. + /// + /// This type could conceptually use a eastl::array as its underlying container, + /// however the current design requires an allocator aware container. + /// Consider using a fixed_vector instead. /// /// To consider: std::set has the limitation that values in the set cannot /// be modified, with the idea that modifying them would change their sort @@ -83,13 +91,9 @@ namespace eastl /// classes use 'mutable' as needed. See the C++ standard defect report /// #103 (DR 103) for a discussion of this. /// - /// Note that the erase functions return iterator and not void. This allows for - /// more efficient use of the container and is consistent with the C++ language - /// defect report #130 (DR 130) - /// template , typename Allocator = EASTLAllocatorType, typename RandomAccessContainer = eastl::vector > - class vector_set : public RandomAccessContainer + class vector_set : protected Compare, public RandomAccessContainer { public: typedef RandomAccessContainer base_type; @@ -115,9 +119,6 @@ namespace eastl using base_type::end; using base_type::get_allocator; - protected: - value_compare mCompare; // To consider: Declare this instead as: 'key_compare mKeyCompare' - public: // We have an empty ctor and a ctor that takes an allocator instead of one for both // because this way our RandomAccessContainer wouldn't be required to have an constructor @@ -258,7 +259,7 @@ namespace eastl template inline vector_set::vector_set() - : base_type(), mCompare(C()) + : value_compare(), base_type() { get_allocator().set_name(EASTL_VECTOR_SET_DEFAULT_NAME); } @@ -266,7 +267,7 @@ namespace eastl template inline vector_set::vector_set(const allocator_type& allocator) - : base_type(allocator), mCompare(C()) + : value_compare(), base_type(allocator) { // Empty } @@ -274,7 +275,7 @@ namespace eastl template inline vector_set::vector_set(const key_compare& compare, const allocator_type& allocator) - : base_type(allocator), mCompare(compare) + : value_compare(compare), base_type(allocator) { // Empty } @@ -282,7 +283,7 @@ namespace eastl template inline vector_set::vector_set(const this_type& x) - : base_type(x), mCompare(x.mCompare) + : value_compare(x), base_type(x) { // Empty } @@ -290,23 +291,25 @@ namespace eastl template inline vector_set::vector_set(this_type&& x) - : base_type(eastl::move(x)), mCompare(x.mCompare) + // careful to only copy / move the distinct base sub-objects of x: + : value_compare(static_cast(x)), base_type(eastl::move(static_cast(x))) { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + // Empty. Note: x is left with empty contents but its original value_compare instead of the default one. } template inline vector_set::vector_set(this_type&& x, const allocator_type& allocator) - : base_type(eastl::move(x), allocator), mCompare(x.mCompare) + // careful to only copy / move the distinct base sub-objects of x: + : value_compare(static_cast(x)), base_type(eastl::move(static_cast(x)), allocator) { - // Empty. Note: x is left with empty contents but its original mValueCompare instead of the default one. + // Empty. Note: x is left with empty contents but its original value_compare instead of the default one. } template inline vector_set::vector_set(std::initializer_list ilist, const key_compare& compare, const allocator_type& allocator) - : base_type(allocator), mCompare(compare) + : value_compare(compare), base_type(allocator) { insert(ilist.begin(), ilist.end()); } @@ -315,7 +318,7 @@ namespace eastl template template inline vector_set::vector_set(InputIterator first, InputIterator last) - : base_type(EASTL_VECTOR_SET_DEFAULT_ALLOCATOR), mCompare(key_compare()) + : value_compare(), base_type(EASTL_VECTOR_SET_DEFAULT_ALLOCATOR) { insert(first, last); } @@ -324,7 +327,7 @@ namespace eastl template template inline vector_set::vector_set(InputIterator first, InputIterator last, const key_compare& compare) - : base_type(EASTL_VECTOR_SET_DEFAULT_ALLOCATOR), mCompare(compare) + : value_compare(compare), base_type(EASTL_VECTOR_SET_DEFAULT_ALLOCATOR) { insert(first, last); } @@ -335,7 +338,7 @@ namespace eastl vector_set::operator=(const this_type& x) { base_type::operator=(x); - mCompare = value_compare(x.mCompare); + value_compare::operator=(x); return *this; } @@ -345,7 +348,8 @@ namespace eastl vector_set::operator=(this_type&& x) { base_type::operator=(eastl::move(x)); - eastl::swap(mCompare, x.mCompare); + using eastl::swap; + swap(static_cast(*this), static_cast(x)); return *this; } @@ -364,7 +368,8 @@ namespace eastl inline void vector_set::swap(this_type& x) { base_type::swap(x); - eastl::swap(mCompare, x.mCompare); + using eastl::swap; + swap(static_cast(*this), static_cast(x)); } @@ -372,7 +377,7 @@ namespace eastl inline const typename vector_set::key_compare& vector_set::key_comp() const { - return mCompare; + return static_cast(*this); } @@ -380,7 +385,7 @@ namespace eastl inline typename vector_set::key_compare& vector_set::key_comp() { - return mCompare; + return static_cast(*this); } @@ -388,7 +393,7 @@ namespace eastl inline const typename vector_set::value_compare& vector_set::value_comp() const { - return mCompare; + return static_cast(*this); } @@ -396,7 +401,7 @@ namespace eastl inline typename vector_set::value_compare& vector_set::value_comp() { - return mCompare; + return static_cast(*this); } @@ -435,7 +440,7 @@ namespace eastl { const iterator itLB(lower_bound(value)); - if((itLB != end()) && !mCompare(value, *itLB)) + if((itLB != end()) && !value_compare::operator()(value, *itLB)) return eastl::pair(itLB, false); return eastl::pair(base_type::insert(itLB, value), true); } @@ -449,7 +454,7 @@ namespace eastl value_type value(eastl::forward

(otherValue)); const iterator itLB(lower_bound(value)); - if((itLB != end()) && !mCompare(value, *itLB)) + if((itLB != end()) && !value_compare::operator()(value, *itLB)) return eastl::pair(itLB, false); return eastl::pair(base_type::insert(itLB, eastl::move(value)), true); } @@ -464,9 +469,9 @@ namespace eastl // We do a test to see if the position is correct. If so then we insert, // if not then we ignore the input position. - if((position == end()) || mCompare(value, *position)) // If the element at position is greater than value... + if((position == end()) || value_compare::operator()(value, *position)) // If the element at position is greater than value... { - if((position == begin()) || mCompare(*(position - 1), value)) // If the element before position is less than value... + if((position == begin()) || value_compare::operator()(*(position - 1), value)) // If the element before position is less than value... return base_type::insert(position, value); } @@ -485,9 +490,9 @@ namespace eastl vector_set::insert(const_iterator position, value_type&& value) { // See the other version of this function for documentation. - if((position == end()) || mCompare(value, *position)) // If the element at position is greater than value... + if((position == end()) || value_compare::operator()(value, *position)) // If the element at position is greater than value... { - if((position == begin()) || mCompare(*(position - 1), value)) // If the element before position is less than value... + if((position == begin()) || value_compare::operator()(*(position - 1), value)) // If the element before position is less than value... return base_type::insert(position, eastl::move(value)); } @@ -621,7 +626,7 @@ namespace eastl inline typename vector_set::iterator vector_set::lower_bound(const key_type& k) { - return eastl::lower_bound(begin(), end(), k, mCompare); + return eastl::lower_bound(begin(), end(), k, static_cast(*this)); } @@ -629,7 +634,7 @@ namespace eastl inline typename vector_set::const_iterator vector_set::lower_bound(const key_type& k) const { - return eastl::lower_bound(begin(), end(), k, mCompare); + return eastl::lower_bound(begin(), end(), k, static_cast(*this)); } @@ -637,7 +642,7 @@ namespace eastl inline typename vector_set::iterator vector_set::upper_bound(const key_type& k) { - return eastl::upper_bound(begin(), end(), k, mCompare); + return eastl::upper_bound(begin(), end(), k, static_cast(*this)); } @@ -645,7 +650,7 @@ namespace eastl inline typename vector_set::const_iterator vector_set::upper_bound(const key_type& k) const { - return eastl::upper_bound(begin(), end(), k, mCompare); + return eastl::upper_bound(begin(), end(), k, static_cast(*this)); } @@ -659,7 +664,7 @@ namespace eastl // result is a range of size zero or one. const iterator itLower(lower_bound(k)); - if((itLower == end()) || mCompare(k, *itLower)) // If at the end or if (k is < itLower)... + if((itLower == end()) || value_compare::operator()(k, *itLower)) // If at the end or if (k is < itLower)... return eastl::pair(itLower, itLower); iterator itUpper(itLower); @@ -677,7 +682,7 @@ namespace eastl // result is a range of size zero or one. const const_iterator itLower(lower_bound(k)); - if((itLower == end()) || mCompare(k, *itLower)) // If at the end or if (k is < itLower)... + if((itLower == end()) || value_compare::operator()(k, *itLower)) // If at the end or if (k is < itLower)... return eastl::pair(itLower, itLower); const_iterator itUpper(itLower); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ff16189f..0dcee127 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -44,8 +44,9 @@ endif() #------------------------------------------------------------------------------------------- # Source files #------------------------------------------------------------------------------------------- -file(GLOB EASTLTEST_SOURCES "source/*.cpp" "source/*.inl" "source/*.h") -set(SOURCES ${EASTLTEST_SOURCES}) +file(GLOB EASTLTEST_SOURCES "source/*.cpp") +file(GLOB EASTLTEST_HEADERS "source/*.inl" "source/*.h") +set(SOURCES ${EASTLTEST_SOURCES} ${EASTLTEST_HEADERS}) # Compile a subset of tests with explicit char8_t support if available. if (EASTL_CHAR8T_FLAG) @@ -57,6 +58,9 @@ if (EASTL_CHAR8T_FLAG) COMPILE_DEFINITIONS "EASTL_EXPECT_CHAR8T_SUPPORT") endif() +# include both source and headers in the files view in Visual Studio +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX "Header Files" FILES ${EASTLTEST_HEADERS}) + #------------------------------------------------------------------------------------------- # Executable definition #------------------------------------------------------------------------------------------- diff --git a/test/source/EASTLTest.h b/test/source/EASTLTest.h index fca6b2c0..4daa3512 100644 --- a/test/source/EASTLTest.h +++ b/test/source/EASTLTest.h @@ -482,6 +482,19 @@ struct TestObject { return (sTOCount == 0) && (sTODtorCount == sTOCtorCount) && (sMagicErrorCount == 0); } + + TestObject& operator++() + { + ++mX; + return *this; + } + + TestObject operator++(int) const + { + TestObject temp(*this); + ++temp; + return temp; + } }; // Operators @@ -519,33 +532,6 @@ template struct use_mX { int operator()(const T& t) const { return -/////////////////////////////////////////////////////////////////////////////// -// SizedPOD -// -// Exists for the purpose testing PODs that are larger than built-in types. -// -template -struct SizedPOD -{ - char memory[kSize]; -}; - - - -/////////////////////////////////////////////////////////////////////////////// -/// ConstType -/// -/// Used to test const type containers (e.g. vector). -/// -class ConstType -{ -public: - ConstType(int value) : mDummy(value) {}; - int mDummy; -}; - - - /////////////////////////////////////////////////////////////////////////////// /// TestObjectHash @@ -784,7 +770,65 @@ int CompareContainers(const T1& t1, const T2& t2, const char* ppName, } +template +bool VerifySequence(InputIterator1 firstActual, InputIterator1 lastActual, InputIterator2 firstExpected, InputIterator2 lastExpected, const char* pName) +{ + size_t numMatching = 0; + + while ((firstActual != lastActual) && (firstExpected != lastExpected) && (*firstActual == *firstExpected)) + { + ++firstActual; + ++firstExpected; + ++numMatching; + } + if (firstActual == lastActual && firstExpected == lastExpected) + { + return true; + } + else if (firstActual != lastActual && firstExpected == lastExpected) + { + size_t numActual = numMatching, numExpected = numMatching; + for (; firstActual != lastActual; ++firstActual) + ++numActual; + if (pName) + EASTLTest_Printf("[%s] Too many elements: expected %u, found %u\n", pName, numExpected, numActual); + else + EASTLTest_Printf("Too many elements: expected %u, found %u\n", numExpected, numActual); + return false; + } + else if (firstActual == lastActual && firstExpected != lastExpected) + { + size_t numActual = numMatching, numExpected = numMatching; + for (; firstExpected != lastExpected; ++firstExpected) + ++numExpected; + if (pName) + EASTLTest_Printf("[%s] Too few elements: expected %u, found %u\n", pName, numExpected, numActual); + else + EASTLTest_Printf("Too few elements: expected %u, found %u\n", numExpected, numActual); + return false; + } + else // if (firstActual != lastActual && firstExpected != lastExpected) + { + if (pName) + EASTLTest_Printf("[%s] Mismatch at index %u\n", pName, numMatching); + else + EASTLTest_Printf("Mismatch at index %u\n", numMatching); + return false; + } +} + +template +bool VerifySequence(InputIterator firstActual, InputIterator lastActual, std::initializer_list initList, const char* pName) +{ + return VerifySequence(firstActual, lastActual, initList.begin(), initList.end(), pName); +} + +template +bool VerifySequence(const Container& container, std::initializer_list initList, const char* pName) +{ + return VerifySequence(container.begin(), container.end(), initList.begin(), initList.end(), pName); +} /// VerifySequence @@ -1564,6 +1608,129 @@ struct MoveOnlyTypeDefaultCtor int mVal; }; +struct TriviallyCopyableWithCopy { + // non-trivial default ctor + TriviallyCopyableWithCopy(unsigned int v = 0) noexcept : mValue(v) {} + + // all eligible (for trivial copyability) copy ctor/move ctor/copy assignment/move assignment are trivial + TriviallyCopyableWithCopy(const TriviallyCopyableWithCopy&) = default; + TriviallyCopyableWithCopy& operator=(const TriviallyCopyableWithCopy&) = default; + + // remaining copy ctor/move ctor/copy assignment/move assignment are deleted + TriviallyCopyableWithCopy(TriviallyCopyableWithCopy&&) = delete; + TriviallyCopyableWithCopy& operator=(TriviallyCopyableWithCopy&&) = delete; + + friend bool operator==(const TriviallyCopyableWithCopy& lhs, const TriviallyCopyableWithCopy& rhs) { return lhs.mValue == rhs.mValue; } + +public: + unsigned int mValue; + + // intentionally not a standard-layout class: + // standard-layout requires all non-static data members have the same access control. +private: + char ch{ 'C' }; +}; +static_assert(eastl::is_default_constructible::value, "TriviallyCopyableWithCopy"); +static_assert(eastl::is_trivially_copyable::value, "TriviallyCopyableWithCopy"); +static_assert(!eastl::is_standard_layout::value, "TriviallyCopyableWithCopy"); + +struct TriviallyCopyableWithMove { + // non-trivial default ctor + TriviallyCopyableWithMove(unsigned int v = 0) noexcept : mValue(v) {} + + // all eligible (for trivial copyability) copy ctor/move ctor/copy assignment/move assignment are trivial + TriviallyCopyableWithMove(TriviallyCopyableWithMove&&) = default; + TriviallyCopyableWithMove& operator=(TriviallyCopyableWithMove&&) = default; + + // remaining copy ctor/move ctor/copy assignment/move assignment are deleted + TriviallyCopyableWithMove(const TriviallyCopyableWithMove&) = delete; + TriviallyCopyableWithMove& operator=(const TriviallyCopyableWithMove&) = delete; + + friend bool operator==(const TriviallyCopyableWithMove& lhs, const TriviallyCopyableWithMove& rhs) { return lhs.mValue == rhs.mValue; } + +public: + unsigned int mValue; + + // intentionally not a standard-layout class: + // standard-layout requires all non-static data members have the same access control. +private: + char ch{ 'C' }; +}; +static_assert(eastl::is_default_constructible::value, "TriviallyCopyableWithMove"); +static_assert(eastl::is_trivially_copyable::value, "TriviallyCopyableWithMove"); +static_assert(!eastl::is_standard_layout::value, "TriviallyCopyableWithMove"); + +struct TriviallyCopyableWithCopyCtor { + TriviallyCopyableWithCopyCtor(unsigned int v) noexcept : mValue(v) {} + + TriviallyCopyableWithCopyCtor(const TriviallyCopyableWithCopyCtor&) = default; + + TriviallyCopyableWithCopyCtor() = delete; + TriviallyCopyableWithCopyCtor(TriviallyCopyableWithCopyCtor&&) = delete; + TriviallyCopyableWithCopyCtor& operator=(const TriviallyCopyableWithCopyCtor&) = delete; + TriviallyCopyableWithCopyCtor& operator=(TriviallyCopyableWithCopyCtor&&) = delete; + + friend bool operator==(const TriviallyCopyableWithCopyCtor& lhs, const TriviallyCopyableWithCopyCtor& rhs) { return lhs.mValue == rhs.mValue; } + + unsigned int mValue; +}; +static_assert(eastl::is_trivially_copyable::value, "TriviallyCopyableWithCopyCtor"); +static_assert(eastl::is_standard_layout::value, "TriviallyCopyableWithCopyCtor"); + +struct TriviallyCopyableWithCopyAssign { + TriviallyCopyableWithCopyAssign(unsigned int v) noexcept : mValue(v) {} + + TriviallyCopyableWithCopyAssign& operator=(const TriviallyCopyableWithCopyAssign&) = default; + + TriviallyCopyableWithCopyAssign() = delete; + TriviallyCopyableWithCopyAssign(const TriviallyCopyableWithCopyAssign&) = delete; + TriviallyCopyableWithCopyAssign(TriviallyCopyableWithCopyAssign&&) = delete; + TriviallyCopyableWithCopyAssign& operator=(TriviallyCopyableWithCopyAssign&&) = delete; + + friend bool operator==(const TriviallyCopyableWithCopyAssign& lhs, const TriviallyCopyableWithCopyAssign& rhs) { return lhs.mValue == rhs.mValue; } + + unsigned int mValue; +}; +static_assert(eastl::is_trivially_copyable::value, "TriviallyCopyableWithCopyAssign"); +static_assert(eastl::is_standard_layout::value, "TriviallyCopyableWithCopyAssign"); + +struct TriviallyCopyableWithMoveCtor { + TriviallyCopyableWithMoveCtor(unsigned int v) noexcept : mValue(v) {} + + TriviallyCopyableWithMoveCtor(TriviallyCopyableWithMoveCtor&&) = default; + + TriviallyCopyableWithMoveCtor() = delete; + TriviallyCopyableWithMoveCtor(const TriviallyCopyableWithMoveCtor&) = delete; + TriviallyCopyableWithMoveCtor& operator=(const TriviallyCopyableWithMoveCtor&) = delete; + TriviallyCopyableWithMoveCtor& operator=(TriviallyCopyableWithMoveCtor&&) = delete; + + friend bool operator==(const TriviallyCopyableWithMoveCtor& lhs, const TriviallyCopyableWithMoveCtor& rhs) { return lhs.mValue == rhs.mValue; } + + unsigned int mValue; +}; +static_assert(eastl::is_trivially_copyable::value, "TriviallyCopyableWithMoveCtor"); +static_assert(eastl::is_standard_layout::value, "TriviallyCopyableWithMoveCtor"); + +struct TriviallyCopyableWithMoveAssign { + TriviallyCopyableWithMoveAssign(unsigned int v) noexcept : mValue(v) {} + + TriviallyCopyableWithMoveAssign& operator=(TriviallyCopyableWithMoveAssign&&) = default; + + TriviallyCopyableWithMoveAssign() = delete; + TriviallyCopyableWithMoveAssign(const TriviallyCopyableWithMoveAssign&) = delete; + TriviallyCopyableWithMoveAssign(TriviallyCopyableWithMoveAssign&&) = delete; + TriviallyCopyableWithMoveAssign& operator=(const TriviallyCopyableWithMoveAssign&) = delete; + + friend bool operator==(const TriviallyCopyableWithMoveAssign& lhs, const TriviallyCopyableWithMoveAssign& rhs) { return lhs.mValue == rhs.mValue; } + + unsigned int mValue; +}; +static_assert(eastl::is_trivially_copyable::value, "TriviallyCopyableWithMoveAssign"); +static_assert(eastl::is_standard_layout::value, "TriviallyCopyableWithMoveAssign"); + +// useful for testing empty base optimization of types +struct NoDataMembers {}; +static_assert(eastl::is_empty::value, "empty"); ////////////////////////////////////////////////////////////////////////////// diff --git a/test/source/EASTLTestAllocator.cpp b/test/source/EASTLTestAllocator.cpp index 0f03d8ac..8deabac5 100644 --- a/test/source/EASTLTestAllocator.cpp +++ b/test/source/EASTLTestAllocator.cpp @@ -135,14 +135,12 @@ void* InternalMalloc(size_t size) { - void* mem = nullptr; - auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator(); #ifdef EA_DEBUG - mem = allocator.MallocDebug(size, 0, 0, gUnattributedNewTag, UNATTRIBUTED_NEW_FILE, UNATTRIBUTED_NEW_LINE); + void* mem = allocator.MallocAlignedDebug(size, alignof(std::max_align_t), 0, 0, 0, gUnattributedNewTag, UNATTRIBUTED_NEW_FILE, UNATTRIBUTED_NEW_LINE); #else - mem = allocator.Malloc(size); + void* mem = allocator.MallocAligned(size, alignof(std::max_align_t));; #endif if(mem == nullptr) @@ -153,14 +151,12 @@ void* InternalMalloc(size_t size, const char* name, int flags, unsigned debugFlags, const char* file, int line) { - void* mem = nullptr; - auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator(); #ifdef EA_DEBUG - mem = allocator.MallocDebug(size, flags, debugFlags, name, file, line); + void* mem = allocator.MallocAlignedDebug(size, alignof(std::max_align_t), 0, flags, debugFlags, name, file, line); #else - mem = allocator.Malloc(size, flags); + void* mem = allocator.MallocAligned(size, alignof(std::max_align_t), 0, flags);; EA_UNUSED(debugFlags); EA_UNUSED(file); EA_UNUSED(line); diff --git a/test/source/EASTLTestIterators.h b/test/source/EASTLTestIterators.h new file mode 100644 index 00000000..21bc3de2 --- /dev/null +++ b/test/source/EASTLTestIterators.h @@ -0,0 +1,97 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// Input concepts (see https://en.cppreference.com/w/cpp/named_req#Iterator): +// - input, eg. std::istream_iterator, not part of EASTL. +// - forward, eg. hash_map::iterator +// - bidirectional, eg. list::iterator +// - random access, eg. deque::iterator +// - contiguous, eg. vector::iterator +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef EASTL_TEST_ITERATORS_H +#define EASTL_TEST_ITERATORS_H + +#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 + +struct EndSentinel {}; + +// a LegacyInputIterator that increments a referenced Integer. +// this iterator cannot be made a forward iterator or stronger because it is a single pass iterator. +template +class InputIterator +{ +protected: + Integer* mInt{nullptr}; + Integer mEnd{0}; + +public: + typedef ptrdiff_t difference_type; + typedef Integer value_type; + typedef Integer* pointer; + typedef Integer& reference; + typedef EASTL_ITC_NS::input_iterator_tag iterator_category; + + explicit InputIterator(Integer* i) noexcept + : mInt(i), mEnd(0) { } + + explicit InputIterator(EndSentinel, Integer end) noexcept + : mInt(nullptr), mEnd(end) { } + + InputIterator() = default; + InputIterator(const InputIterator& x) = default; + InputIterator(InputIterator&& x) = default; + InputIterator& operator=(const InputIterator& x) = default; + InputIterator& operator=(InputIterator&& x) = default; + + reference operator*() const + { + return *mInt; + } + + pointer operator->() const + { + return mInt; + } + + InputIterator& operator++() + { + ++(*mInt); + return *this; + } + + InputIterator operator++(int) const + { + // seeing as this is a single pass iterator, ie. the iterator modifies the source, pre- and post- increment are equivalent. + // we iterate the copy, and even though this member function is const, the modification is visible by this object. + InputIterator temp(*this); + ++temp; + return temp; + } + + template + friend inline bool operator==(const InputIterator& a, const InputIterator& b); + +}; // class InputIterator + +template +inline bool operator==(const InputIterator& a, const InputIterator& b) +{ + return /* is iterator == sentinel? */ (a.mInt && !b.mInt && *a.mInt == b.mEnd) || + /* are iterators equal? */ (a.mInt && b.mInt && a.mInt == b.mInt) || + /* are sentinels equal? */ (!a.mInt && !b.mInt && a.mEnd == b.mEnd); +} + +// LegacyInputIterator +template +inline bool operator!=(const InputIterator& a, const InputIterator& b) +{ + return !(a == b); +} + +#endif // Header include guard diff --git a/test/source/TestAlgorithm.cpp b/test/source/TestAlgorithm.cpp index a0f64da2..eeb53ae2 100644 --- a/test/source/TestAlgorithm.cpp +++ b/test/source/TestAlgorithm.cpp @@ -90,7 +90,7 @@ enum TestMinMaxEnum // A version of greater that uses operator < instead of operator >. // template -struct Greater : public eastl::binary_function +struct Greater { bool operator()(const T& a, const T& b) const { return (b < a); } @@ -111,7 +111,7 @@ struct DivisibleBy /////////////////////////////////////////////////////////////////////////////// // TestObjectNegate // -struct TestObjectNegate : public eastl::unary_function +struct TestObjectNegate { TestObject operator()(const TestObject& a) const { return TestObject(-a.mX); } @@ -867,13 +867,14 @@ int TestAlgorithm() int intArray1[] = { 9, 1, 9, 9, 9, 9, 1, 1, 9, 9 }; int intArray2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - copy_if(intArray1, intArray1 + 0, intArray2, bind2nd(equal_to(), (int)1)); + auto equal_to_1 = [](int i) { return i == 1; }; + copy_if(intArray1, intArray1 + 0, intArray2, equal_to_1); EATEST_VERIFY(VerifySequence(intArray2, intArray2 + 10, int(), "copy_if", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1)); - copy_if(intArray1, intArray1 + 9, intArray2, bind2nd(equal_to(), (int)1)); + copy_if(intArray1, intArray1 + 9, intArray2, equal_to_1); EATEST_VERIFY(VerifySequence(intArray2, intArray2 + 10, int(), "copy_if", 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1)); - copy_if(intArray1 + 1, intArray1 + 9, intArray1 + 0, bind2nd(equal_to(), (int)1)); // Copy over self. + copy_if(intArray1 + 1, intArray1 + 9, intArray1 + 0, equal_to_1); // Copy over self. EATEST_VERIFY(VerifySequence(intArray1, intArray1 + 10, int(), "copy_if", 1, 1, 1, 9, 9, 9, 1, 1, 9, 9, -1)); } @@ -895,6 +896,9 @@ int TestAlgorithm() int intArray1[] = { 3, 2, 6, 5, 4, 1 }; int intArray2[] = { 0, 0, 0, 0, 0, 0 }; + copy_backward(intArray1, intArray1 + 0, (int*) nullptr); + EATEST_VERIFY(VerifySequence(intArray2, intArray2 + 6, int(), "copy_backward", 0, 0, 0, 0, 0, 0, -1)); + copy_backward(intArray1, intArray1 + 0, intArray2 + 0); EATEST_VERIFY(VerifySequence(intArray2, intArray2 + 6, int(), "copy_backward", 0, 0, 0, 0, 0, 0, -1)); @@ -952,18 +956,20 @@ int TestAlgorithm() int intArray[] = { 3, 2, 6, 5, 4, 1, 2, 4, 5, 4, 1, 2 }; // Count all items whose value is less than three. - ptrdiff_t n = count_if(intArray, intArray, bind2nd(less(), (int)3)); // No-op + auto less_than_3 = [](int i) { return i < 3; }; + ptrdiff_t n = count_if(intArray, intArray, less_than_3); // No-op EATEST_VERIFY(n == 0); - n = count_if(intArray, intArray + 12, bind2nd(less(), (int)3)); + n = count_if(intArray, intArray + 12, less_than_3); EATEST_VERIFY(n == 5); // Count all items whose value is less than three. TestObject toArray[] = { TestObject(1), TestObject(3), TestObject(1), TestObject(4), TestObject(2), TestObject(5) }; - n = count_if(toArray, toArray, bind2nd(less(), TestObject(3))); // No-op + auto less_than_testobject_3 = [](const TestObject& lhs) { return lhs < TestObject(3); }; + n = count_if(toArray, toArray, less_than_testobject_3); // No-op EATEST_VERIFY(n == 0); - n = count_if(toArray, toArray + 6, bind2nd(less(), TestObject(3))); + n = count_if(toArray, toArray + 6, less_than_testobject_3); EATEST_VERIFY(n == 3); @@ -976,9 +982,9 @@ int TestAlgorithm() intList.push_front(2); intList.push_front(5); - n = count_if(intList.begin(), intList.begin(), bind2nd(less(), (int)3)); // No-op + n = count_if(intList.begin(), intList.begin(), less_than_3); // No-op EATEST_VERIFY(n == 0); - n = count_if(intList.begin(), intList.end(), bind2nd(less(), (int)3)); + n = count_if(intList.begin(), intList.end(), less_than_3); EATEST_VERIFY(n == 3); } @@ -1146,27 +1152,27 @@ int TestAlgorithm() int intArray[] = { 3, 2, 6, 5, 4, 1, 2, 4, 5, 4, 1, 2 }; // Find an item which is equal to 1. - int* pInt = find_if(intArray, intArray, bind2nd(equal_to(), (int)1)); // No-op + int* pInt = find_if(intArray, intArray, [](int i) { return i == 1; }); // No-op EATEST_VERIFY(pInt == (intArray)); - pInt = find_if(intArray, intArray + 12, bind2nd(equal_to(), (int)1)); + pInt = find_if(intArray, intArray + 12, [](int i) { return i == 1; }); EATEST_VERIFY(pInt == (intArray + 5)); - pInt = find_if(intArray, intArray + 12, bind2nd(equal_to(), (int)99)); + pInt = find_if(intArray, intArray + 12, [](int i) { return i == 99; }); EATEST_VERIFY(pInt == (intArray + 12)); - pInt = find_if_not(intArray, intArray + 12, bind2nd(equal_to(), (int)3)); + pInt = find_if_not(intArray, intArray + 12, [](int i) { return i == 3; }); EATEST_VERIFY(pInt == (intArray + 1)); // Find an item which is equal to 1. TestObject toArray[] = { TestObject(4), TestObject(3), TestObject(2), TestObject(1), TestObject(2), TestObject(5) }; - TestObject* pTO = find_if(toArray, toArray, bind2nd(equal_to(), TestObject(1))); // No-op + TestObject* pTO = find_if(toArray, toArray, [](const TestObject& lhs) { return lhs == TestObject(1); }); // No-op EATEST_VERIFY(pTO == (toArray)); - pTO = find_if(toArray, toArray + 6, bind2nd(equal_to(), TestObject(1))); + pTO = find_if(toArray, toArray + 6, [](const TestObject& lhs) { return lhs == TestObject(1); }); EATEST_VERIFY(pTO == (toArray + 3)); - pTO = find_if(toArray, toArray + 6, bind2nd(equal_to(), TestObject(99))); + pTO = find_if(toArray, toArray + 6, [](const TestObject& lhs) { return lhs == TestObject(99); }); EATEST_VERIFY(pTO == (toArray + 6)); - pTO = find_if_not(toArray, toArray + 6, bind2nd(equal_to(), TestObject(4))); + pTO = find_if_not(toArray, toArray + 6, [](const TestObject& lhs) { return lhs == TestObject(4); }); EATEST_VERIFY(pTO == (toArray + 1)); // Find an item which is equal to 1. @@ -1179,14 +1185,14 @@ int TestAlgorithm() intList.push_front(5); // The list is now: { 5, 2, 1, 2, 3, 4 } - slist::iterator it = find_if(intList.begin(), intList.begin(), bind2nd(equal_to(), (int)1)); // No-op + slist::iterator it = find_if(intList.begin(), intList.begin(), [](int i) { return i == 1; }); // No-op EATEST_VERIFY(it == intList.begin()); - it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)1)); + it = find_if(intList.begin(), intList.end(), [](int i) { return i == 1; }); EATEST_VERIFY(*it == 1); - it = find_if(intList.begin(), intList.end(), bind2nd(equal_to(), (int)99)); + it = find_if(intList.begin(), intList.end(), [](int i) { return i == 99; }); EATEST_VERIFY(it == intList.end()); - it = find_if_not(intList.begin(), intList.end(), bind2nd(equal_to(), (int)5)); + it = find_if_not(intList.begin(), intList.end(), [](int i) { return i == 5; }); EATEST_VERIFY(*it == 2); } @@ -1509,6 +1515,16 @@ int TestAlgorithm() EATEST_VERIFY( b); } + { + // bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) + // bool lexicographical_compare(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, Compare compare) + + char* cstr = nullptr; + + bool b = lexicographical_compare(cstr, cstr, cstr, cstr); + EATEST_VERIFY(!b); + } + #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) { // lexicographical_compare_three_way(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, Compare compare) @@ -1791,9 +1807,9 @@ int TestAlgorithm() EATEST_VERIFY((intArray[1] == 99) && (intArray[7] == 99)); // Convert 99s to 88s. - replace_if(intArray, intArray, bind2nd(equal_to(), (int)99), 88); // No-op + replace_if(intArray, intArray, [](int i) { return i == 99; }, 88); // No-op EATEST_VERIFY((intArray[1] == 99) && (intArray[7] == 99)); - replace_if(intArray, intArray + 8, bind2nd(equal_to(), (int)99), 88); + replace_if(intArray, intArray + 8, [](int i) { return i == 99; }, 88); EATEST_VERIFY((intArray[1] == 88) && (intArray[7] == 88)); @@ -1823,13 +1839,13 @@ int TestAlgorithm() EATEST_VERIFY(*it == TestObject(99)); // Convert 99s to 88s. - replace_if(toList.begin(), toList.begin(), bind2nd(equal_to(), TestObject(99)), TestObject(88)); // No-op + replace_if(toList.begin(), toList.begin(), [](const TestObject& lhs) { return lhs == TestObject(99); }, TestObject(88)); // No-op it = toList.begin(); advance(it, 1); EATEST_VERIFY(*it == TestObject(99)); advance(it, 6); EATEST_VERIFY(*it == TestObject(99)); - replace_if(toList.begin(), toList.end(), bind2nd(equal_to(), TestObject(99)), TestObject(88)); + replace_if(toList.begin(), toList.end(), [](const TestObject& lhs) { return lhs == TestObject(99); }, TestObject(88)); it = toList.begin(); advance(it, 1); EATEST_VERIFY(*it == TestObject(88)); @@ -1856,12 +1872,12 @@ int TestAlgorithm() EATEST_VERIFY(VerifySequence(intArray2, intArray2 + 12, int(), "remove_copy", 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, -1)); - pInt = remove_copy_if(intArray1, intArray1, intArray2, bind2nd(equal_to(), (int)0)); // No-op + pInt = remove_copy_if(intArray1, intArray1, intArray2, [](int i) { return i == 0; }); // No-op EATEST_VERIFY(pInt == intArray2); EATEST_VERIFY(VerifySequence(intArray1, intArray1 + 12, int(), "remove_copy_if", 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, -1)); EATEST_VERIFY(VerifySequence(intArray2, intArray2 + 12, int(), "remove_copy_if", 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, -1)); - pInt = remove_copy_if(intArray1, intArray1 + 12, intArray2, bind2nd(equal_to(), (int)0)); + pInt = remove_copy_if(intArray1, intArray1 + 12, intArray2, [](int i) { return i == 0; }); EATEST_VERIFY(pInt == intArray2 + 6); EATEST_VERIFY(VerifySequence(intArray1, intArray1 + 12, int(), "remove_copy_if", 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, -1)); EATEST_VERIFY(VerifySequence(intArray2, intArray2 + 12, int(), "remove_copy_if", 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, -1)); @@ -1935,12 +1951,12 @@ int TestAlgorithm() int intArray[12] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1}; vector output; auto func = [&output](int a) { output.push_back(a); }; - int* pInt = apply_and_remove_if(intArray, intArray, func, bind2nd(equal_to(), (int)1)); + int* pInt = apply_and_remove_if(intArray, intArray, func, [](int i) { return i == 1; }); EATEST_VERIFY(pInt == intArray); EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove_if", 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, -1)); EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", -1)); - pInt = apply_and_remove_if(intArray, intArray + 12, func, bind2nd(equal_to(), (int)1)); + pInt = apply_and_remove_if(intArray, intArray + 12, func, [](int i) { return i == 1; }); EATEST_VERIFY(pInt == intArray + 6); EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "apply_and_remove_if", 0, 0, 0, 0, 0, 0, -1)); EATEST_VERIFY( @@ -1952,12 +1968,12 @@ int TestAlgorithm() int intArray[12] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; vector output; auto func = [&output](int a) { output.push_back(a); }; - int* pInt = apply_and_remove_if(intArray, intArray, func, bind2nd(equal_to(), (int)1)); + int* pInt = apply_and_remove_if(intArray, intArray, func, [](int i) { return i == 1; }); EATEST_VERIFY(pInt == intArray); EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove_if", 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1)); EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", -1)); - pInt = apply_and_remove_if(intArray, intArray + 12, func, bind2nd(equal_to(), (int)1)); + pInt = apply_and_remove_if(intArray, intArray + 12, func, [](int i) { return i == 1; }); EATEST_VERIFY(pInt == intArray + 12); EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove_if", 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, -1)); @@ -2557,7 +2573,42 @@ int TestAlgorithm() } } - { + { + // template + // bool is_partitioned(InputIterator first, InputIterator last, UnaryPredicate predicate) + + // template + // ForwardIterator partition_point(ForwardIterator first, ForwardIterator last, UnaryPredicate predicate) + + const auto isEven = [](int i) { return i % 2 == 0; }; + + // These are all partitioned, even first and then odd. + vector v1 = {0, 2, 4, 5, 7, 9, 11}; + vector v2 = {1, 3, 5, 7, 9}; + vector v3 = {2, 4, 8, 100, 102}; + vector v4 = {2, 4, 8, 100, 103}; + EATEST_VERIFY(is_partitioned(v1.begin(), v1.end(), isEven)); + EATEST_VERIFY(is_partitioned(v2.begin(), v2.end(), isEven)); + EATEST_VERIFY(is_partitioned(v3.begin(), v3.end(), isEven)); + EATEST_VERIFY(is_partitioned(v4.begin(), v4.end(), isEven)); + + EATEST_VERIFY(distance(v1.begin(), partition_point(v1.begin(), v1.end(), isEven)) == 3); + EATEST_VERIFY(distance(v2.begin(), partition_point(v2.begin(), v2.end(), isEven)) == 0); + EATEST_VERIFY(distance(v3.begin(), partition_point(v3.begin(), v3.end(), isEven)) == 5); + EATEST_VERIFY(distance(v4.begin(), partition_point(v4.begin(), v4.end(), isEven)) == 4); + + // These are all not partitioned: + vector v5 = {0, 2, 3, 4, 5, 7, 9, 11}; + vector v6 = {1, 3, 5, 7, 9, 2}; + vector v7 = {2, 4, 3, 8, 100, 102}; + vector v8 = {2, 4, 8, 5, 100, 103}; + EATEST_VERIFY(!is_partitioned(v5.begin(), v5.end(), isEven)); + EATEST_VERIFY(!is_partitioned(v6.begin(), v6.end(), isEven)); + EATEST_VERIFY(!is_partitioned(v7.begin(), v7.end(), isEven)); + EATEST_VERIFY(!is_partitioned(v8.begin(), v8.end(), isEven)); + } + + { //template //bool next_permutation(BidirectionalIterator first, BidirectionalIterator last); diff --git a/test/source/TestArray.cpp b/test/source/TestArray.cpp index ca05b675..04f4f76b 100644 --- a/test/source/TestArray.cpp +++ b/test/source/TestArray.cpp @@ -15,11 +15,21 @@ using namespace eastl; // Template instantations. // These tell the compiler to compile all the functions for the given class. -template struct eastl::array; -template struct eastl::array; // VC++ fails to compile due to error generated by the swap function. C2718: http://msdn.microsoft.com/en-us/library/vstudio/sxe76d9e.aspx +template struct eastl::array; +template struct eastl::array; +template struct eastl::array; // VC++ fails to compile due to error generated by the swap function. C2718: http://msdn.microsoft.com/en-us/library/vstudio/sxe76d9e.aspx template class TP; +// test whether typename tuple_element::type is defined: +template +struct has_tuple_element_type : false_type {}; + +template +struct has_tuple_element_type::type>> : true_type {}; + +static_assert(eastl::is_aggregate>::value, "must be an aggregate"); +static_assert(eastl::is_aggregate>::value, "must be an aggregate"); int TestArray() { @@ -29,7 +39,7 @@ int TestArray() array a = { { 0, 1, 2, 3, 4 } }; array b = { { 0, 1, 2, 3 } }; array c = { { 4, 3, 2, 1, 0 } }; - array d = { { 0 } }; + array d = {}; VERIFY(!a.empty()); VERIFY(a.size() == 5); @@ -149,13 +159,15 @@ int TestArray() VERIFY(deduced.size() == 5); #endif + eastl::array empty_array; + VERIFY(empty_array.size() == 0); // array with 0 elements is empty + // structured binding { eastl::array aCopy = a; auto&& [a0, a1, a2, a3, a4] = aCopy; - VERIFY(a0 == aCopy[0]); VERIFY(a1 == aCopy[1]); VERIFY(a2 == aCopy[2]); VERIFY(a3 == aCopy[3]); @@ -242,6 +254,80 @@ int TestArray() #endif } + // tuple_size / tuple_element + { + static_assert(tuple_size_v> == 0, "tuple_size"); + static_assert(tuple_size_v> == 1, "tuple_size"); + static_assert(tuple_size_v> == 2, "tuple_size"); + static_assert(tuple_size_v> == 3, "tuple_size"); + + static_assert(is_same_v>, int>, "tuple_element_t"); + static_assert(is_same_v>, int>, "tuple_element_t"); + static_assert(is_same_v>, int>, "tuple_element_t"); + + static_assert(has_tuple_element_type<3, array>::value, "tuple_element_t"); + + // tuple_element_t with the following parameters is a compile error: + static_assert(!has_tuple_element_type<0, array>::value, "tuple_element_t"); + static_assert(!has_tuple_element_type<1, array>::value, "tuple_element_t"); + static_assert(!has_tuple_element_type<10, array>::value, "tuple_element_t"); + } + + // get() + { + { + eastl::array arr{ 1, 3 }; + get<0>(arr) = 4; + VERIFY(arr[0] == 4); + } + + { + const eastl::array arr{ 5, 6, -10 }; + VERIFY(get<2>(arr) == -10); + VERIFY(get<0>(eastl::array{7, 8}) == 7); + VERIFY(get<1>(eastl::array{7, 8}) == 8); + } + } + +#ifndef EA_COMPILER_NO_STRUCTURED_BINDING + // C++17 structured binding + { + { + eastl::array arr{ 1, 3 }; + auto [a, b] = arr; // get(array&&) + VERIFY(a == 1); + VERIFY(b == 3); + auto& [c, d] = arr; // get(array&) + VERIFY(c == 1); + VERIFY(d == 3); + c = 5; + d = 6; + VERIFY(arr[0] == 5); + VERIFY(arr[1] == 6); + } + + { + eastl::array arr{ 0, 2, 4, 6, 8 }; + const auto [a, b, c, d, e] = arr; // get(const array&&) + VERIFY(a == 0); + VERIFY(b == 2); + VERIFY(c == 4); + VERIFY(d == 6); + VERIFY(e == 8); + const auto& [f,g,h,i,j] = arr; // get(const array&) + VERIFY(f == 0); + VERIFY(g == 2); + VERIFY(h == 4); + VERIFY(i == 6); + VERIFY(j == 8); + arr[0] = 5; + arr[1] = 6; + VERIFY(f == 5); + VERIFY(g == 6); + } + } +#endif + // to_array { { diff --git a/test/source/TestAtomicAsm.cpp b/test/source/TestAtomicAsm.cpp index d4db04e6..ca8c60bb 100644 --- a/test/source/TestAtomicAsm.cpp +++ b/test/source/TestAtomicAsm.cpp @@ -4381,7 +4381,7 @@ EA_NO_INLINE static void TestCompilerBarrierDataDependency() } { - void* p = (void*)0xdeadbeef; + void* p = (void*)(uintptr_t)0xdeadbeef; eastl::compiler_barrier_data_dependency(p); } diff --git a/test/source/TestBitVector.cpp b/test/source/TestBitVector.cpp index ba3ae8c9..e11174d9 100644 --- a/test/source/TestBitVector.cpp +++ b/test/source/TestBitVector.cpp @@ -173,6 +173,28 @@ int TestBitVector() } } + { + // move constructor/assignment + const eastl_size_t kTestSize = 100; + const eastl_size_t kTestIncrement = 5; + bitvector<> bv1(kTestSize, false); + bitvector<> bv2(kTestSize, false); + for (eastl_size_t i = 0; i < kTestSize; i += kTestIncrement) + { + bv1[i] = true; + bv2[i] = true; + } + + bitvector<> bv3(std::move(bv1)); + bitvector<> bv4(kTestSize / 2, true); + bv4 = std::move(bv2); + + for (eastl_size_t i = 0; i < kTestSize; i++) + { + EATEST_VERIFY(bv3[i] == (i % kTestIncrement == 0)); + EATEST_VERIFY(bv4[i] == (i % kTestIncrement == 0)); + } + } { // iterator begin(); diff --git a/test/source/TestCharTraits.cpp b/test/source/TestCharTraits.cpp index bbcab54f..6b58454b 100644 --- a/test/source/TestCharTraits.cpp +++ b/test/source/TestCharTraits.cpp @@ -5,12 +5,36 @@ #include "EASTLTest.h" #include #include +#include template int TestCharTraits() { int nErrorCount = 0; + + // Compare(const T* p1, const T* p2, size_t n) + // Compare(const char* p1, const char* p2, size_t n) + { + auto create = [](const char* cstr, eastl_size_t sz) + { + eastl::basic_string result; + result.assign_convert(cstr, sz - 1); + return result; + }; + + eastl::basic_string empty; + eastl::basic_string abc = create("abc", 4); + eastl::basic_string abd = create("abd", 4); + eastl::basic_string ABC = create("ABC", 4); + EATEST_VERIFY(eastl::Compare(empty.data(), empty.data(), 0) == 0); + EATEST_VERIFY(eastl::Compare(abc.data(), abc.data(), 3) == 0); + EATEST_VERIFY(eastl::Compare(abc.data(), abd.data(), 3) < 0); + EATEST_VERIFY(eastl::Compare(abd.data(), abc.data(), 3) > 0); + EATEST_VERIFY(eastl::Compare(ABC.data(), abc.data(), 3) < 0); + EATEST_VERIFY(eastl::Compare(empty.data(), abc.data(), 0) == 0); + } + return nErrorCount; } @@ -22,7 +46,11 @@ int TestCharTraits() int nErrorCount = 0; nErrorCount += TestCharTraits(); + // eastl::DecodePart() is not implemented for (un)signed char. + //nErrorCount += TestCharTraits(); + //nErrorCount += TestCharTraits(); nErrorCount += TestCharTraits(); + nErrorCount += TestCharTraits(); nErrorCount += TestCharTraits(); nErrorCount += TestCharTraits(); diff --git a/test/source/TestDeque.cpp b/test/source/TestDeque.cpp index e3f4ab6b..cf324cbf 100644 --- a/test/source/TestDeque.cpp +++ b/test/source/TestDeque.cpp @@ -4,6 +4,7 @@ #include "EASTLTest.h" +#include "EASTLTestIterators.h" #include #include #include @@ -13,70 +14,15 @@ #include #include "ConceptImpls.h" -#if !defined(EA_COMPILER_NO_STANDARD_CPP_LIBRARY) - EA_DISABLE_ALL_VC_WARNINGS() - #include - #include - #include - #include - #include - EA_RESTORE_ALL_VC_WARNINGS() -#endif - using namespace eastl; - -/////////////////////////////////////////////////////////////////////////////// -// DequeObject -// -struct DequeObject -{ - int mX; // Value for the DequeObject. - uint32_t mMagicValue; // - static int sDOCount; // Count of all current existing DequeObjects. - static int sMagicErrorCount; // Number of magic number mismatch errors. - - DequeObject(int x = 0) : mX(x), mMagicValue(kMagicValue) - { ++sDOCount; } - - DequeObject(const DequeObject& dequeObject) : mX(dequeObject.mX), mMagicValue(kMagicValue) - { ++sDOCount; } - - DequeObject& operator=(const DequeObject& dequeObject) - { - mX = dequeObject.mX; - return *this; - } - - ~DequeObject() - { - if(mMagicValue != kMagicValue) - ++sMagicErrorCount; - mMagicValue = 0; - --sDOCount; - } -}; - -int DequeObject::sDOCount = 0; -int DequeObject::sMagicErrorCount = 0; - - -bool operator==(const DequeObject& de1, const DequeObject& de2) - { return de1.mX == de2.mX; } - -bool operator<(const DequeObject& de1, const DequeObject& de2) - { return de1.mX < de2.mX; } -/////////////////////////////////////////////////////////////////////////////// - - - // Template instantations. // These tell the compiler to compile all the functions for the given class. template class eastl::deque; -template class eastl::deque; +template class eastl::deque; // Test compiler issue that appeared in VS2012 relating to deque::kAlignment. @@ -95,157 +41,81 @@ struct StructWithContainerOfStructs /////////////////////////////////////////////////////////////////////////////// -typedef eastl::deque EIntDeque; -typedef eastl::deque EIntDeque1; -typedef eastl::deque EIntDeque32768; - - -typedef eastl::deque EDODeque; -typedef eastl::deque EDODeque1; -typedef eastl::deque EDODeque32768; - - -#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY - typedef std::deque SIntDeque; - typedef std::deque SDODeque; -#endif -/////////////////////////////////////////////////////////////////////////////// - - - -#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY - - -template -int CompareDeques(const D1& d1, const D2& d2, const char* pTestName) -{ - int nErrorCount = 0; - - // Compare emptiness. - VERIFY(d1.empty() == d2.empty()); - - // Compare sizes. - const size_t nSize1 = d1.size(); - const size_t nSize2 = d2.size(); - - VERIFY(nSize1 == nSize2); - if(nSize1 != nSize2) - EASTLTest_Printf("%s: Deque size difference: %u, %u", pTestName, (unsigned)nSize1, (unsigned)nSize2); - - // Compare values. - if(nSize1 == nSize2) - { - // Test operator[] - for(unsigned i = 0; i < nSize1; i++) - { - const typename D1::value_type& t1 = d1[i]; - const typename D2::value_type& t2 = d2[i]; - - VERIFY(t1 == t2); - if(!(t1 == t2)) - { - EASTLTest_Printf("%s: Deque index difference at index %d", pTestName, i); - break; - } - } - - // Test iteration - typename D1::const_iterator it1 = d1.begin(); - typename D2::const_iterator it2 = d2.begin(); - - for(unsigned j = 0; it1 != d1.end(); ++it1, ++it2, ++j) - { - const typename D1::value_type& t1 = *it1; - const typename D2::value_type& t2 = *it2; - - VERIFY(t1 == t2); - if(!(t1 == t2)) - { - EASTLTest_Printf("%s: Deque iterator difference at index %d", pTestName, j); - break; - } - } - - // Test reverse iteration - typename D1::const_reverse_iterator itr1 = d1.rbegin(); - typename D2::const_reverse_iterator itr2 = d2.rbegin(); - - for(typename D1::size_type j = d1.size() - 1; itr1 != d1.rend(); ++itr1, ++itr2, --j) - { - const typename D1::value_type& t1 = *itr1; - const typename D2::value_type& t2 = *itr2; - - VERIFY(t1 == t2); - if(!(t1 == t2)) - { - EASTLTest_Printf("%s: Deque reverse iterator difference at index %u", pTestName, (unsigned)j); - break; - } - } - } - - return nErrorCount; -} +typedef eastl::deque IntDeque; +typedef eastl::deque IntDeque1; +typedef eastl::deque IntDeque32768; +typedef eastl::deque TestObjectDeque; +typedef eastl::deque TestObjectDeque1; +typedef eastl::deque TestObjectDeque32768; /////////////////////////////////////////////////////////////////////////////// // TestDequeConstruction // -template +template int TestDequeConstruction() { + typedef typename Deque::value_type value_type; + typedef typename Deque::size_type size_type; + int nErrorCount = 0; { - D1 d1A; - D2 d2A; - nErrorCount += CompareDeques(d1A, d2A, "Deque ctor"); + // constructors + Deque dA; + EATEST_VERIFY(dA.size() == 0); - D1 d1B((typename D1::size_type)0); - D2 d2B((typename D2::size_type)0); - nErrorCount += CompareDeques(d1B, d2B, "Deque ctor"); + Deque dB((size_type)0); + EATEST_VERIFY(dB.size() == 0); - D1 d1C(1000); - D2 d2C(1000); - nErrorCount += CompareDeques(d1C, d2C, "Deque ctor"); + Deque dC(1000); + EATEST_VERIFY(dC.size() == 1000); + for (const auto& elem : dC) + EATEST_VERIFY(elem == value_type()); - D1 d1D(2000, 1); - D2 d2D(2000, 1); - nErrorCount += CompareDeques(d1D, d2D, "Deque ctor"); + Deque dD(2000, value_type(1)); + EATEST_VERIFY(dD.size() == 2000); + for (const auto& elem : dD) + EATEST_VERIFY(elem == value_type(1)); - D1 d1E(d1C); - D2 d2E(d2C); - nErrorCount += CompareDeques(d1E, d2E, "Deque ctor"); + Deque dE(dC); + EATEST_VERIFY(dE.size() == 1000); + for (const auto& elem : dE) + EATEST_VERIFY(elem == value_type()); - D1 d1F(d1C.begin(), d1C.end()); - D2 d2F(d2C.begin(), d2C.end()); - nErrorCount += CompareDeques(d1F, d2F, "Deque ctor"); + Deque dF(dC.begin(), dC.end()); + EATEST_VERIFY(dF.size() == 1000); + for (const auto& elem : dF) + EATEST_VERIFY(elem == value_type()); // operator= - d1E = d1D; - d2E = d2D; - nErrorCount += CompareDeques(d1D, d2D, "Deque operator="); - nErrorCount += CompareDeques(d1E, d2E, "Deque operator="); + dE = dD; + EATEST_VERIFY(dE.size() == 2000); + for (const auto& elem : dE) + EATEST_VERIFY(elem == value_type(1)); // swap - d1E.swap(d1D); - d2E.swap(d2D); - nErrorCount += CompareDeques(d1D, d2D, "Deque swap"); - nErrorCount += CompareDeques(d1E, d2E, "Deque swap"); + dE.swap(dC); + EATEST_VERIFY(dE.size() == 1000); + for (const auto& elem : dE) + EATEST_VERIFY(elem == value_type()); + EATEST_VERIFY(dC.size() == 2000); + for (const auto& elem : dC) + EATEST_VERIFY(elem == value_type(1)); // clear - d1A.clear(); - d2A.clear(); - nErrorCount += CompareDeques(d1A, d2A, "Deque clear"); + dA.clear(); + EATEST_VERIFY(dA.size() == 0); + EATEST_VERIFY(dA.empty()); - d1B.clear(); - d2B.clear(); - nErrorCount += CompareDeques(d1B, d2B, "Deque clear"); + dB.clear(); + EATEST_VERIFY(dB.size() == 0); + EATEST_VERIFY(dB.empty()); } - VERIFY(DequeObject::sDOCount == 0); - VERIFY(DequeObject::sMagicErrorCount == 0); + EATEST_VERIFY(TestObject::sTOCount == 0); + EATEST_VERIFY(TestObject::sMagicErrorCount == 0); return nErrorCount; } @@ -255,200 +125,186 @@ int TestDequeConstruction() /////////////////////////////////////////////////////////////////////////////// // TestDequeSimpleMutation // -template +template int TestDequeSimpleMutation() { + typedef typename Deque::value_type value_type; + typedef typename Deque::size_type size_type; + int nErrorCount = 0; { - D1 d1; - D2 d2; + Deque d; // push_back(value_type&) // front // back - for(int i = 0; i < 1000; i++) + for (int i = 0; i < 1000; i++) { - d1.push_back(i); - d2.push_back(i); - VERIFY(d1.front() == d2.front()); - VERIFY(d1.back() == d2.back()); + d.push_back(value_type(i)); + EATEST_VERIFY(d.back() == value_type(i)); } - nErrorCount += CompareDeques(d1, d2, "Deque push_back(value_type&)"); + EATEST_VERIFY(d.front() == value_type(0)); // operator[] // at() - for(typename D1::size_type i = 0, iEnd = d1.size(); i < iEnd; i++) + for (unsigned int i = 0; i < d.size(); ++i) { - VERIFY(d1[(unsigned)i] == d2[(unsigned)i]); - VERIFY(d1.at((unsigned)i) == d2.at((unsigned)i)); + EATEST_VERIFY(d[i] == value_type(i)); + EATEST_VERIFY(d.at(i) == value_type(i)); } + } + + { + Deque d; // push_back() - for(int i = 0; i < 1000; i++) + // this overloads is an EASTL extension. + for (int i = 0; i < 1000; i++) { - d1.push_back(int()); - typename D2::value_type& ref = d2.push_back(); // d2 here must be the EASTL version. - VERIFY(d1.front() == d2.front()); - VERIFY(d1.back() == d2.back()); - VERIFY(&ref == &d2.back()); + value_type& ref = d.push_back(); + EATEST_VERIFY(&ref == &d.back()); + EATEST_VERIFY(d.back() == value_type()); } - nErrorCount += CompareDeques(d1, d2, "Deque push_back()"); + EATEST_VERIFY(d.front() == value_type()); // operator[] // at() - for(typename D1::size_type i = 0, iEnd = d1.size(); i < iEnd; i++) + for (size_type i = 0, iEnd = d.size(); i < iEnd; i++) { - VERIFY(d1[(unsigned)i] == d2[(unsigned)i]); - VERIFY(d1.at((unsigned)i) == d2.at((unsigned)i)); + EATEST_VERIFY(d[i] == value_type()); + EATEST_VERIFY(d.at(i) == value_type()); } + } + + { + Deque d; // push_front(value_type&) - for(int i = 0; i < 1000; i++) + for (int i = 0; i < 1000; i++) { - d1.push_front(i); - d2.push_front(i); - VERIFY(d1.front() == d2.front()); - VERIFY(d1.back() == d2.back()); + d.push_front(value_type(i)); + EATEST_VERIFY(d.front() == value_type(i)); } - nErrorCount += CompareDeques(d1, d2, "Deque push_front(value_type&)"); // operator[] // at() - for(typename D1::size_type i = 0, iEnd = d1.size(); i < iEnd; i++) + EATEST_VERIFY(d.size() == 1000); + for (int i = 0; i < 1000; i++) { - VERIFY(d1[(unsigned)i] == d2[(unsigned)i]); - VERIFY(d1.at((unsigned)i) == d2.at((unsigned)i)); + EATEST_VERIFY(d[1000 - 1 - i] == value_type(i)); + EATEST_VERIFY(d.at(1000 - 1 - i) == value_type(i)); } + } + + { + Deque d; // push_front() - for(int i = 0; i < 1000; i++) + // this overloads is an EASTL extension. + for (int i = 0; i < 1000; i++) { - d1.push_front(int()); - typename D2::value_type& ref = d2.push_front(); - VERIFY(d1.front() == d2.front()); - VERIFY(d1.back() == d2.back()); - VERIFY(&ref == &d2.front()); + value_type& ref = d.push_front(); + EATEST_VERIFY(&ref == &d.front()); + EATEST_VERIFY(d.front() == value_type()); } - nErrorCount += CompareDeques(d1, d2, "Deque push_front()"); + EATEST_VERIFY(d.back() == value_type()); // operator[] // at() - for(typename D1::size_type i = 0, iEnd = d1.size(); i < iEnd; i++) + for (size_type i = 0, iEnd = d.size(); i < iEnd; i++) { - VERIFY(d1[(unsigned)i] == d2[(unsigned)i]); - VERIFY(d1.at((unsigned)i) == d2.at((unsigned)i)); + EATEST_VERIFY(d[i] == value_type()); + EATEST_VERIFY(d.at(i) == value_type()); } // pop_back() - for(int i = 0; i < 500; i++) + for (int i = 0; i < 500; i++) { - d1.pop_back(); - d2.pop_back(); - VERIFY(d1.front() == d2.front()); - VERIFY(d1.back() == d2.back()); - } - nErrorCount += CompareDeques(d1, d2, "Deque pop_back()"); - - // operator[] - // at() - for(typename D1::size_type i = 0, iEnd = d1.size(); i < iEnd; i++) - { - VERIFY(d1[(unsigned)i] == d2[(unsigned)i]); - VERIFY(d1.at((unsigned)i) == d2.at((unsigned)i)); + d.pop_back(); } + EATEST_VERIFY(d.size() == 500); + for (const auto& elem : d) + EATEST_VERIFY(elem == value_type()); // pop_front() - for(int i = 0; i < 500; i++) + for (int i = 0; i < 500; i++) { - d1.pop_front(); - d2.pop_front(); - VERIFY(d1.front() == d2.front()); - VERIFY(d1.back() == d2.back()); + d.pop_front(); } - nErrorCount += CompareDeques(d1, d2, "Deque pop_front()"); + EATEST_VERIFY(d.size() == 0); + } - // operator[] - // at() - for(typename D1::size_type i = 0, iEnd = d1.size(); i < iEnd; i++) - { - VERIFY(d1[(unsigned)i] == d2[(unsigned)i]); - VERIFY(d1.at((unsigned)i) == d2.at((unsigned)i)); - } + { + Deque d; // resize(value_type&) for(int i = 0; i < 500; i++) { - d1.resize(d1.size() + 3, i); - d2.resize(d2.size() + 3, i); - VERIFY(d1.front() == d2.front()); - VERIFY(d1.back() == d2.back()); + d.resize(d.size() + 3, value_type(i)); + EATEST_VERIFY(d.size() == size_type((i + 1) * 3)); } - nErrorCount += CompareDeques(d1, d2, "Deque resize(value_type&)"); + + EATEST_VERIFY(d.size() == 1500); - // operator[] - // at() - for(typename D1::size_type i = 0, iEnd = d1.size(); i < iEnd; i++) + for (int i = 0; i < 500; ++i) { - VERIFY(d1[(unsigned)i] == d2[(unsigned)i]); - VERIFY(d1.at((unsigned)i) == d2.at((unsigned)i)); + EATEST_VERIFY(d[i * 3 + 0] == value_type(i)); + EATEST_VERIFY(d[i * 3 + 1] == value_type(i)); + EATEST_VERIFY(d[i * 3 + 2] == value_type(i)); } // resize() for(int i = 0; i < 500; i++) { - d1.resize(d1.size() - 2); - d2.resize(d2.size() - 2); - VERIFY(d1.front() == d2.front()); - VERIFY(d1.back() == d2.back()); - } - nErrorCount += CompareDeques(d1, d2, "Deque resize()"); - - // operator[] - // at() - for(typename D1::size_type i = 0, iEnd = d1.size(); i < iEnd; i++) - { - VERIFY(d1[(unsigned)i] == d2[(unsigned)i]); - VERIFY(d1.at((unsigned)i) == d2.at((unsigned)i)); + d.resize(d.size() - 2); + EATEST_VERIFY(d.size() == size_type(1500 - ((i + 1) * 2))); } + EATEST_VERIFY(d.size() == 500); } - VERIFY(DequeObject::sDOCount == 0); - VERIFY(DequeObject::sMagicErrorCount == 0); + EATEST_VERIFY(TestObject::sTOCount == 0); + EATEST_VERIFY(TestObject::sMagicErrorCount == 0); return nErrorCount; } - /////////////////////////////////////////////////////////////////////////////// // TestDequeComplexMutation // -template +template int TestDequeComplexMutation() { + typedef typename Deque::value_type value_type; + typedef typename Deque::size_type size_type; + typedef typename Deque::iterator iterator; + typedef typename Deque::reverse_iterator reverse_iterator; + int nErrorCount = 0; { - D1 d1; - D2 d2; + Deque d; ////////////////////////////////////////////////////////////////// // void assign(size_type n, const value_type& value); ////////////////////////////////////////////////////////////////// - d1.assign(100, 1); - d2.assign(100, 1); - nErrorCount += CompareDeques(d1, d2, "Deque assign(size_type n, const value_type& value)"); + d.assign(100, 1); + EATEST_VERIFY(d.size() == 100); + for (const auto& elem : d) + EATEST_VERIFY(elem == value_type(1)); - d1.assign(50, 2); - d2.assign(50, 2); - nErrorCount += CompareDeques(d1, d2, "Deque assign(size_type n, const value_type& value)"); + d.assign(50, 2); + EATEST_VERIFY(d.size() == 50); + for (const auto& elem : d) + EATEST_VERIFY(elem == value_type(2)); - d1.assign(150, 2); - d2.assign(150, 2); - nErrorCount += CompareDeques(d1, d2, "Deque assign(size_type n, const value_type& value)"); + d.assign(150, 3); + EATEST_VERIFY(d.size() == 150); + for (const auto& elem : d) + EATEST_VERIFY(elem == value_type(3)); @@ -457,161 +313,151 @@ int TestDequeComplexMutation() // void assign(InputIterator first, InputIterator last); ////////////////////////////////////////////////////////////////// - std::list intList1; + list valueList; for(int i = 0; i < 100; i++) - intList1.push_back(i); - - eastl::list intList2; - for(int i = 0; i < 100; i++) - intList2.push_back(i); - - d1.assign(intList1.begin(), intList1.end()); - d2.assign(intList2.begin(), intList2.end()); - nErrorCount += CompareDeques(d1, d2, "Deque assign(InputIterator first, InputIterator last)"); + valueList.push_back(value_type(i)); + d.assign(valueList.begin(), valueList.end()); + EATEST_VERIFY(d.size() == 100); + for (int i = 0; i < 100; i++) + EATEST_VERIFY(d[i] == value_type(i)); ////////////////////////////////////////////////////////////////// // iterator insert(iterator position, const value_type& value); ////////////////////////////////////////////////////////////////// - d1.insert(d1.begin(), d1[1]); - d2.insert(d2.begin(), d2[1]); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, const value_type& value)"); - - d1.insert(d1.end(), d1[d1.size() - 2]); - d2.insert(d2.end(), d2[d2.size() - 2]); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, const value_type& value)"); - - typename D1::iterator itD1NearBegin = d1.begin(); - typename D2::iterator itD2NearBegin = d2.begin(); + iterator itFirstInserted = d.insert(d.begin(), d[1]); + EATEST_VERIFY(itFirstInserted == d.begin()); + EATEST_VERIFY(d[0] == value_type(1)); - std::advance(itD1NearBegin, 1); - eastl::advance(itD2NearBegin, 1); + value_type value = d[d.size() - 2]; + itFirstInserted = d.insert(d.end(), value); + EATEST_VERIFY(itFirstInserted == d.end() - 1); + EATEST_VERIFY(*(d.end() - 1) == value); - d1.insert(itD1NearBegin, d1[3]); - d2.insert(itD2NearBegin, d2[3]); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, const value_type& value)"); + iterator itNearBegin = d.begin(); + advance(itNearBegin, 1); - typename D1::iterator itD1NearEnd = d1.begin(); - typename D2::iterator itD2NearEnd = d2.begin(); + value = d[3]; + itFirstInserted = d.insert(itNearBegin, value); + EATEST_VERIFY(itFirstInserted == d.begin() + 1); + EATEST_VERIFY(d[1] == value); - std::advance(itD1NearEnd, d1.size() - 1); - eastl::advance(itD2NearEnd, d2.size() - 1); + iterator itNearEnd = d.begin(); + advance(itNearEnd, d.size() - 1); - d1.insert(itD1NearEnd, d1[d1.size() - 2]); - d2.insert(itD2NearEnd, d2[d2.size() - 2]); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, const value_type& value)"); + value = d[d.size() - 2]; + itFirstInserted = d.insert(itNearEnd, value); + EATEST_VERIFY(itFirstInserted == d.end() - 2); + EATEST_VERIFY(d[d.size() - 2] == value); ////////////////////////////////////////////////////////////////// - // void insert(iterator position, size_type n, const value_type& value); + // iterator insert(iterator position, size_type n, const value_type& value); ////////////////////////////////////////////////////////////////// - d1.insert(d1.begin(), d1.size() * 2, 3); // Insert a large number of items at the front. - d2.insert(d2.begin(), d2.size() * 2, 3); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, size_type n, const value_type& value)"); + itFirstInserted = d.insert(d.begin(), d.size() * 2, value_type(3)); // Insert a large number of items at the front. + EATEST_VERIFY(itFirstInserted == d.begin()); + for (size_type i = 0; i < d.size() / 2; i++) + EATEST_VERIFY(d[i] == value_type(3)); - d1.insert(d1.end(), d1.size() * 2, 3); // Insert a large number of items at the end. - d2.insert(d2.end(), d2.size() * 2, 3); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, size_type n, const value_type& value)"); + itFirstInserted = d.insert(d.end(), d.size() * 2, value_type(3)); // Insert a large number of items at the end. + EATEST_VERIFY(itFirstInserted == d.begin() + (d.size() / 3)); + for (size_type i = 0; i < d.size() / 2; i++) + EATEST_VERIFY(d[d.size() - 1 - i] == value_type(3)); - itD1NearBegin = d1.begin(); - itD2NearBegin = d2.begin(); + itNearBegin = d.begin(); + advance(itNearBegin, 3); - std::advance(itD1NearBegin, 3); - eastl::advance(itD2NearBegin, 3); + itFirstInserted = d.insert(itNearBegin, 3, value_type(4)); + EATEST_VERIFY(itFirstInserted == d.begin() + 3); + EATEST_VERIFY(VerifySequence(d.begin() + 3, d.begin() + 6, { value_type(4), value_type(4), value_type(4) }, "insert()")); - d1.insert(itD1NearBegin, 3, 4); - d2.insert(itD2NearBegin, 3, 4); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, size_type n, const value_type& value)"); + itNearEnd = d.begin(); + advance(itNearEnd, d.size() - 1); - itD1NearEnd = d1.begin(); - itD2NearEnd = d2.begin(); + itFirstInserted = d.insert(d.end(), 5, value_type(6)); + EATEST_VERIFY(itFirstInserted == d.end() - 5); + EATEST_VERIFY(VerifySequence(d.end() - 5, d.end(), { value_type(6), value_type(6), value_type(6), value_type(6), value_type(6) }, "insert()")); - std::advance(itD1NearEnd, d1.size() - 1); - eastl::advance(itD2NearEnd, d2.size() - 1); - - d1.insert(d1.end(), 5, 6); - d2.insert(d2.end(), 5, 6); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, size_type n, const value_type& value)"); + EATEST_VERIFY(d.begin() == d.insert(d.begin(), 0, value_type(9))); ////////////////////////////////////////////////////////////////// // template - // void insert(iterator position, InputIterator first, InputIterator last); + // iterator insert(iterator position, InputIterator first, InputIterator last); ////////////////////////////////////////////////////////////////// - itD1NearBegin = d1.begin(); - itD2NearBegin = d2.begin(); + itNearBegin = d.begin(); + advance(itNearBegin, 3); - std::advance(itD1NearBegin, 3); - eastl::advance(itD2NearBegin, 3); + itFirstInserted = d.insert(itNearBegin, valueList.begin(), valueList.end()); + for (int i = 0; i < 100; ++i, ++itFirstInserted) + EATEST_VERIFY(*itFirstInserted == value_type(i)); - d1.insert(itD1NearBegin, intList1.begin(), intList1.end()); - d2.insert(itD2NearBegin, intList2.begin(), intList2.end()); - nErrorCount += CompareDeques(d1, d2, "Deque insert(iterator position, InputIterator first, InputIterator last)"); + value_type x(0); + itFirstInserted = d.insert(d.begin(), InputIterator(&x), InputIterator(EndSentinel(), value_type(5))); + EATEST_VERIFY(itFirstInserted == d.begin()); + EATEST_VERIFY(VerifySequence(d.begin(), d.begin() + 5, { value_type(0), value_type(1), value_type(2), value_type(3), value_type(4) }, "deque::insert() with input iterators")); + auto inputEnd = InputIterator(EndSentinel(), value_type(5)); + EATEST_VERIFY(d.begin() == d.insert(d.begin(), inputEnd, inputEnd)); + value_type* itContiguous = nullptr; + EATEST_VERIFY(d.begin() == d.insert(d.begin(), itContiguous, itContiguous)); ////////////////////////////////////////////////////////////////// // iterator erase(iterator position); ////////////////////////////////////////////////////////////////// - itD1NearBegin = d1.begin(); - itD2NearBegin = d2.begin(); + itNearBegin = d.begin(); - while(itD1NearBegin != d1.end()) // Run a loop whereby we erase every third element. + size_type sizeBeforeErase = d.size(); + while(itNearBegin != d.end()) // Run a loop whereby we erase every fourth element. { - for(int i = 0; (i < 3) && (itD1NearBegin != d1.end()); ++i) + for(int i = 0; (i < 3) && (itNearBegin != d.end()); ++i) { - ++itD1NearBegin; - ++itD2NearBegin; + ++itNearBegin; } - if(itD1NearBegin != d1.end()) + if(itNearBegin != d.end()) { - itD1NearBegin = d1.erase(itD1NearBegin); - itD2NearBegin = d2.erase(itD2NearBegin); - nErrorCount += CompareDeques(d1, d2, "Deque erase(iterator position)"); + itNearBegin = d.erase(itNearBegin); } } + EATEST_VERIFY(sizeBeforeErase - (sizeBeforeErase / 4) == d.size()); ////////////////////////////////////////////////////////////////// // iterator erase(iterator first, iterator last); ////////////////////////////////////////////////////////////////// - itD1NearBegin = d1.begin(); - itD2NearBegin = d2.begin(); + itNearBegin = d.begin(); - while(itD1NearBegin != d1.end()) // Run a loop whereby we erase spans of elements. + while(itNearBegin != d.end()) // Run a loop whereby we erase spans of elements. { - typename D1::iterator itD1Saved = itD1NearBegin; - typename D2::iterator itD2Saved = itD2NearBegin; + iterator itSaved = itNearBegin; - for(int i = 0; (i < 11) && (itD1NearBegin != d1.end()); ++i) + size_type numElementsToErase = 0; + for(; (numElementsToErase < 22) && (itNearBegin != d.end()); ++numElementsToErase) { - ++itD1NearBegin; - ++itD2NearBegin; + ++itNearBegin; } - if(itD1NearBegin != d1.end()) + if(itNearBegin != d.end()) { - itD1NearBegin = d1.erase(itD1Saved, itD1NearBegin); - itD2NearBegin = d2.erase(itD2Saved, itD2NearBegin); - nErrorCount += CompareDeques(d1, d2, "Deque erase(iterator position)"); + size_type numElementsPrior = d.size(); + itNearBegin = d.erase(itSaved, itNearBegin); + EATEST_VERIFY(d.size() == numElementsPrior - numElementsToErase); } - for(int i = 0; (i < 17) && (itD1NearBegin != d1.end()); ++i) + for(int i = 0; (i < 17) && (itNearBegin != d.end()); ++i) { - ++itD1NearBegin; - ++itD2NearBegin; + ++itNearBegin; } - } - } @@ -621,99 +467,93 @@ int TestDequeComplexMutation() // reverse_iterator erase(reverse_iterator first, reverse_iterator last); ////////////////////////////////////////////////////////////////// - //D1 d1Erase; - D2 d2Erase; + Deque dErase; for(int i = 0; i < 20; i++) { - typename D2::value_type val(i); - d2Erase.push_back(val); + value_type val(i); + dErase.push_back(val); } - VERIFY((d2Erase.size() == 20) && (d2Erase[0] == 0) && (d2Erase[19] == 19)); + EATEST_VERIFY((dErase.size() == 20) && (dErase[0] == value_type(0)) && (dErase[19] == value_type(19))); - typename D2::reverse_iterator r2A = d2Erase.rbegin(); - typename D2::reverse_iterator r2B = r2A + 3; - d2Erase.erase(r2A, r2B); - VERIFY((d2Erase.size() == 17)); - VERIFY((d2Erase[0] == 0)); - VERIFY((d2Erase[16] == 16)); + reverse_iterator rA = dErase.rbegin(); + reverse_iterator rB = rA + 3; + dErase.erase(rA, rB); + EATEST_VERIFY((dErase.size() == 17)); + EATEST_VERIFY((dErase[0] == value_type(0))); + EATEST_VERIFY((dErase[16] == value_type(16))); - r2B = d2Erase.rend(); - r2A = r2B - 3; - d2Erase.erase(r2A, r2B); - VERIFY((d2Erase.size() == 14)); - VERIFY((d2Erase[0] == 3)); - VERIFY((d2Erase[13] == 16)); + rB = dErase.rend(); + rA = rB - 3; + dErase.erase(rA, rB); + EATEST_VERIFY((dErase.size() == 14)); + EATEST_VERIFY((dErase[0] == value_type(3))); + EATEST_VERIFY((dErase[13] == value_type(16))); - r2B = d2Erase.rend() - 1; - d2Erase.erase(r2B); - VERIFY((d2Erase.size() == 13)); - VERIFY((d2Erase[0] == 4)); - VERIFY((d2Erase[12] == 16)); + rB = dErase.rend() - 1; + dErase.erase(rB); + EATEST_VERIFY((dErase.size() == 13)); + EATEST_VERIFY((dErase[0] == value_type(4))); + EATEST_VERIFY((dErase[12] == value_type(16))); - r2B = d2Erase.rbegin(); - d2Erase.erase(r2B); - VERIFY((d2Erase.size() == 12)); - VERIFY((d2Erase[0] == 4)); - VERIFY((d2Erase[11] == 15)); + rB = dErase.rbegin(); + dErase.erase(rB); + EATEST_VERIFY((dErase.size() == 12)); + EATEST_VERIFY((dErase[0] == value_type(4))); + EATEST_VERIFY((dErase[11] == value_type(15))); - r2A = d2Erase.rbegin(); - r2B = d2Erase.rend(); - d2Erase.erase(r2A, r2B); - VERIFY(d2Erase.size() == 0); + rA = dErase.rbegin(); + rB = dErase.rend(); + dErase.erase(rA, rB); + EATEST_VERIFY(dErase.size() == 0); } - VERIFY(DequeObject::sDOCount == 0); - VERIFY(DequeObject::sMagicErrorCount == 0); + EATEST_VERIFY(TestObject::sTOCount == 0); + EATEST_VERIFY(TestObject::sMagicErrorCount == 0); return nErrorCount; } -#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY - int TestDeque() { int nErrorCount = 0; - #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY - { // Test construction - nErrorCount += TestDequeConstruction(); - nErrorCount += TestDequeConstruction(); - nErrorCount += TestDequeConstruction(); - - nErrorCount += TestDequeConstruction(); - nErrorCount += TestDequeConstruction(); - nErrorCount += TestDequeConstruction(); - } + { // Test construction + nErrorCount += TestDequeConstruction(); + nErrorCount += TestDequeConstruction(); + nErrorCount += TestDequeConstruction(); + nErrorCount += TestDequeConstruction(); + nErrorCount += TestDequeConstruction(); + nErrorCount += TestDequeConstruction(); + } - { // Test simple mutating functionality. - nErrorCount += TestDequeSimpleMutation(); - nErrorCount += TestDequeSimpleMutation(); - nErrorCount += TestDequeSimpleMutation(); + { // Test simple mutating functionality. + nErrorCount += TestDequeSimpleMutation(); + nErrorCount += TestDequeSimpleMutation(); + nErrorCount += TestDequeSimpleMutation(); - nErrorCount += TestDequeSimpleMutation(); - nErrorCount += TestDequeSimpleMutation(); - nErrorCount += TestDequeSimpleMutation(); - } + nErrorCount += TestDequeSimpleMutation(); + nErrorCount += TestDequeSimpleMutation(); + nErrorCount += TestDequeSimpleMutation(); + } - { // Test complex mutating functionality. - nErrorCount += TestDequeComplexMutation(); - nErrorCount += TestDequeComplexMutation(); - nErrorCount += TestDequeComplexMutation(); + { // Test complex mutating functionality. + nErrorCount += TestDequeComplexMutation(); + nErrorCount += TestDequeComplexMutation(); + nErrorCount += TestDequeComplexMutation(); - nErrorCount += TestDequeComplexMutation(); - nErrorCount += TestDequeComplexMutation(); - nErrorCount += TestDequeComplexMutation(); - } - #endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY + nErrorCount += TestDequeComplexMutation(); + nErrorCount += TestDequeComplexMutation(); + nErrorCount += TestDequeComplexMutation(); + } // test deque support of move-only types { @@ -801,16 +641,16 @@ int TestDeque() // iterator insert(iterator position, std::initializer_list ilist); #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) eastl::deque intDeque = { 0, 1, 2 }; - EATEST_VERIFY(VerifySequence(intDeque.begin(), intDeque.end(), int(), "deque std::initializer_list", 0, 1, 2, -1)); + EATEST_VERIFY(VerifySequence(intDeque, { 0, 1, 2 }, "deque std::initializer_list")); intDeque = { 13, 14, 15 }; - EATEST_VERIFY(VerifySequence(intDeque.begin(), intDeque.end(), int(), "deque std::initializer_list", 13, 14, 15, -1)); + EATEST_VERIFY(VerifySequence(intDeque, { 13, 14, 15 }, "deque std::initializer_list")); intDeque.assign({ 16, 17, 18 }); - EATEST_VERIFY(VerifySequence(intDeque.begin(), intDeque.end(), int(), "deque std::initializer_list", 16, 17, 18, -1)); + EATEST_VERIFY(VerifySequence(intDeque, { 16, 17, 18 }, "deque std::initializer_list")); eastl::deque::iterator it = intDeque.insert(intDeque.begin(), { 14, 15 }); - EATEST_VERIFY(VerifySequence(intDeque.begin(), intDeque.end(), int(), "deque std::initializer_list", 14, 15, 16, 17, 18, -1)); + EATEST_VERIFY(VerifySequence(intDeque, { 14, 15, 16, 17, 18 }, "deque std::initializer_list")); EATEST_VERIFY(*it == 14); #endif } @@ -917,13 +757,13 @@ int TestDeque() { // Regression of kDequeSubarraySize calculations - VERIFY(EIntDeque::kSubarraySize >= 4); - VERIFY(EIntDeque1::kSubarraySize == 1); - VERIFY(EIntDeque32768::kSubarraySize == 32768); + EATEST_VERIFY(IntDeque::kSubarraySize >= 4); + EATEST_VERIFY(IntDeque1::kSubarraySize == 1); + EATEST_VERIFY(IntDeque32768::kSubarraySize == 32768); - VERIFY(EDODeque::kSubarraySize >= 2); - VERIFY(EDODeque1::kSubarraySize == 1); - VERIFY(EDODeque32768::kSubarraySize == 32768); + EATEST_VERIFY(TestObjectDeque::kSubarraySize >= 2); + EATEST_VERIFY(TestObjectDeque1::kSubarraySize == 1); + EATEST_VERIFY(TestObjectDeque32768::kSubarraySize == 32768); } @@ -987,32 +827,21 @@ int TestDeque() allocVolumeX2 = maX.mAllocVolume; // Save the allocated volume after 1001 iterations. allocVolumeY2 = maY.mAllocVolume; - VERIFY((allocVolumeX1 == allocVolumeX2) && (allocVolumeX2 < 350)); // Test that the volume has not changed and is below some nominal value. - VERIFY((allocVolumeY1 == allocVolumeY2) && (allocVolumeY2 < 350)); // This value is somewhat arbitrary and slightly hardware dependent (e.g. 32 vs. 64 bit). I bumped it up from 300 to 350 when Linux64 showed it to be 320, which was ~still OK. - } - - - { // Regression of user error report for the case of deque. - eastl::vector ctorValues; - - for(int v = 0; v < 10; v++) - ctorValues.push_back(v); - - eastl::deque testStruct(ctorValues.begin(), ctorValues.end()); - eastl::deque testInt(ctorValues.begin(), ctorValues.end()); + EATEST_VERIFY((allocVolumeX1 == allocVolumeX2) && (allocVolumeX2 < 350)); // Test that the volume has not changed and is below some nominal value. + EATEST_VERIFY((allocVolumeY1 == allocVolumeY2) && (allocVolumeY2 < 350)); // This value is somewhat arbitrary and slightly hardware dependent (e.g. 32 vs. 64 bit). I bumped it up from 300 to 350 when Linux64 showed it to be 320, which was ~still OK. } { // Regression to verify that const deque works. const eastl::deque constIntDeque1; - VERIFY(constIntDeque1.empty()); + EATEST_VERIFY(constIntDeque1.empty()); int intArray[3] = { 37, 38, 39 }; const eastl::deque constIntDeque2(intArray, intArray + 3); - VERIFY(constIntDeque2.size() == 3); + EATEST_VERIFY(constIntDeque2.size() == 3); const eastl::deque constIntDeque3(4, 37); - VERIFY(constIntDeque3.size() == 4); + EATEST_VERIFY(constIntDeque3.size() == 4); const eastl::deque constIntDeque4; const eastl::deque constIntDeque5 = constIntDeque4; @@ -1025,7 +854,7 @@ int TestDeque() auto prev = d.get_allocator().getActiveAllocationSize(); d.shrink_to_fit(); - VERIFY(d.get_allocator().getActiveAllocationSize() < prev); + EATEST_VERIFY(d.get_allocator().getActiveAllocationSize() < prev); } { @@ -1043,7 +872,12 @@ int TestDeque() }; EA_RESTORE_VC_WARNING() + EASTL_INTERNAL_DISABLE_DEPRECATED() // 'eastl::has_trivial_relocate': was declared deprecated static_assert(eastl::has_trivial_relocate::value == false, "failure"); + EASTL_INTERNAL_RESTORE_DEPRECATED() + static_assert(eastl::is_trivial::value == false, "failure"); + static_assert(eastl::is_trivially_constructible::value == false, "failure"); + static_assert(eastl::is_trivially_copyable::value == false, "failure"); eastl::deque d; @@ -1054,7 +888,7 @@ int TestDeque() d.erase(d.begin() + 1); } #ifndef EASTL_OPENSOURCE - VERIFY(gEASTLTest_AllocationCount == prevAllocCount); + EATEST_VERIFY(gEASTLTest_AllocationCount == prevAllocCount); #endif } @@ -1064,34 +898,56 @@ int TestDeque() eastl::deque d = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto numErased = eastl::erase(d, 2); - VERIFY((d == eastl::deque{1, 3, 4, 5, 6, 7, 8, 9})); - VERIFY(numErased == 1); + EATEST_VERIFY((d == eastl::deque{1, 3, 4, 5, 6, 7, 8, 9})); + EATEST_VERIFY(numErased == 1); numErased = eastl::erase(d, 7); - VERIFY((d == eastl::deque{1, 3, 4, 5, 6, 8, 9})); - VERIFY(numErased == 1); + EATEST_VERIFY((d == eastl::deque{1, 3, 4, 5, 6, 8, 9})); + EATEST_VERIFY(numErased == 1); numErased = eastl::erase(d, 9); - VERIFY((d == eastl::deque{1, 3, 4, 5, 6, 8})); - VERIFY(numErased == 1); + EATEST_VERIFY((d == eastl::deque{1, 3, 4, 5, 6, 8})); + EATEST_VERIFY(numErased == 1); numErased = eastl::erase(d, 5); - VERIFY((d == eastl::deque{1, 3, 4, 6, 8})); - VERIFY(numErased == 1); + EATEST_VERIFY((d == eastl::deque{1, 3, 4, 6, 8})); + EATEST_VERIFY(numErased == 1); numErased = eastl::erase(d, 3); - VERIFY((d == eastl::deque{1, 4, 6, 8})); - VERIFY(numErased == 1); + EATEST_VERIFY((d == eastl::deque{1, 4, 6, 8})); + EATEST_VERIFY(numErased == 1); } { eastl::deque d = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto numErased = eastl::erase_if(d, [](auto i) { return i % 2 == 0; }); - VERIFY((d == eastl::deque{1, 3, 5, 7, 9})); - VERIFY(numErased == 4); + EATEST_VERIFY((d == eastl::deque{1, 3, 5, 7, 9})); + EATEST_VERIFY(numErased == 4); } } + { + eastl::deque d1; + eastl::deque d2{d1}; + } + + { + eastl::deque d1; + eastl::deque d2{ eastl::move(d1) }; + } + + { + // unusual type - not well supported: eastl containers implicitly assume that ctor and operator= are both defined. + eastl::deque d1; + eastl::deque d2{ d1 }; + } + + { + // unusual type - not well supported: eastl containers implicitly assume that ctor and operator= are both defined. + eastl::deque d1; + eastl::deque d2{ eastl::move(d1) }; + } + #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) { // Test <=> @@ -1100,21 +956,21 @@ int TestDeque() eastl::deque d3 = {1, 2, 3, 4, 5}; eastl::deque d4 = {10}; - VERIFY(d1 != d2); - VERIFY(d1 < d2); - VERIFY(d1 != d3); - VERIFY(d1 > d3); - VERIFY(d4 > d1); - VERIFY(d4 > d2); - VERIFY(d4 > d3); - - VERIFY((d1 <=> d2) != 0); - VERIFY((d1 <=> d2) < 0); - VERIFY((d1 <=> d3) != 0); - VERIFY((d1 <=> d3) > 0); - VERIFY((d4 <=> d1) > 0); - VERIFY((d4 <=> d2) > 0); - VERIFY((d4 <=> d3) > 0); + EATEST_VERIFY(d1 != d2); + EATEST_VERIFY(d1 < d2); + EATEST_VERIFY(d1 != d3); + EATEST_VERIFY(d1 > d3); + EATEST_VERIFY(d4 > d1); + EATEST_VERIFY(d4 > d2); + EATEST_VERIFY(d4 > d3); + + EATEST_VERIFY((d1 <=> d2) != 0); + EATEST_VERIFY((d1 <=> d2) < 0); + EATEST_VERIFY((d1 <=> d3) != 0); + EATEST_VERIFY((d1 <=> d3) > 0); + EATEST_VERIFY((d4 <=> d1) > 0); + EATEST_VERIFY((d4 <=> d2) > 0); + EATEST_VERIFY((d4 <=> d3) > 0); } #endif diff --git a/test/source/TestFixedString.cpp b/test/source/TestFixedString.cpp index 8528dc77..3eff54e4 100644 --- a/test/source/TestFixedString.cpp +++ b/test/source/TestFixedString.cpp @@ -217,6 +217,50 @@ int TestFixedString() EATEST_VERIFY(sW.capacity() == 63); // 63 because the 64 includes the terminating 0, but capacity() subtracts the terminating 0 usage. } + { + string s("frost"); + size_t sHash = eastl::hash{}(s); + + // char + fixed_string fsc1("frost"); + fixed_string fsc2("bite"); + fixed_string fsc3("bite"); + + size_t fsc1Hash = eastl::hash>{}(fsc1); + size_t fsc2Hash = eastl::hash>{}(fsc2); + size_t fsc3Hash = eastl::hash>{}(fsc3); + + EATEST_VERIFY(fsc1Hash == sHash); + EATEST_VERIFY(fsc1Hash != fsc2Hash); + EATEST_VERIFY(fsc2Hash == fsc3Hash); + + // wchar_t + fixed_string fswc1(L"frost"); + fixed_string fswc2(L"bite"); + fixed_string fswc3(L"bite"); + + size_t fswc1Hash = eastl::hash>{}(fswc1); + size_t fswc2Hash = eastl::hash>{}(fswc2); + size_t fswc3Hash = eastl::hash>{}(fswc3); + + EATEST_VERIFY(fswc1Hash == sHash); + EATEST_VERIFY(fswc1Hash != fswc2Hash); + EATEST_VERIFY(fswc2Hash == fswc3Hash); + + // char8_t + fixed_string fsc81("frost"); + fixed_string fsc82("bite"); + fixed_string fsc83("bite"); + + size_t fsc81Hash = eastl::hash>{}(fsc81); + size_t fsc82Hash = eastl::hash>{}(fsc82); + size_t fsc83Hash = eastl::hash>{}(fsc83); + + EATEST_VERIFY(fsc81Hash == sHash); + EATEST_VERIFY(fsc81Hash != fsc82Hash); + EATEST_VERIFY(fsc82Hash == fsc83Hash); + } + { typedef fixed_string FixedString64; diff --git a/test/source/TestFixedVector.cpp b/test/source/TestFixedVector.cpp index aeb3ba2b..9ead65bc 100644 --- a/test/source/TestFixedVector.cpp +++ b/test/source/TestFixedVector.cpp @@ -230,7 +230,8 @@ int TestFixedVector() // Test for potential bug reported Sep. 19, 2006. typedef eastl::fixed_vector FixedVector; FixedVector v; - int* p = (int*)(uintptr_t)0; + int arr[100] = {}; + int* p = arr; for(int i = 0; i < 100; i++, p++) v.push_back(p); diff --git a/test/source/TestFunctional.cpp b/test/source/TestFunctional.cpp index 1e25200e..4c7d834c 100644 --- a/test/source/TestFunctional.cpp +++ b/test/source/TestFunctional.cpp @@ -17,6 +17,9 @@ EA_DISABLE_ALL_VC_WARNINGS() #include EA_RESTORE_ALL_VC_WARNINGS() +// contains tests for library features that are deprecated +EASTL_INTERNAL_DISABLE_DEPRECATED() // *: was declared deprecated + namespace { @@ -135,6 +138,10 @@ int TestHashHelper(T val) return nErrorCount; } +// Required to test library functions that require the binary_function interface despite our removal of them from function objects such as eastl::less +template +struct binary_function_adaptor : public eastl::binary_function, BinaryFunction {}; + /////////////////////////////////////////////////////////////////////////////// // TestFunctional // @@ -408,10 +415,10 @@ int TestFunctional() TestClass tc0, tc1, tc2; TestClass* tcArray[3] = { &tc0, &tc1, &tc2 }; - for_each(tcArray, tcArray + 3, mem_fun(&TestClass::Increment)); + for_each(tcArray, tcArray + 3, mem_fn(&TestClass::Increment)); EATEST_VERIFY((tc0.mX == 38) && (tc1.mX == 38) && (tc2.mX == 38)); - for_each(tcArray, tcArray + 3, mem_fun(&TestClass::IncrementConst)); + for_each(tcArray, tcArray + 3, mem_fn(&TestClass::IncrementConst)); EATEST_VERIFY((tc0.mX == 39) && (tc1.mX == 39) && (tc2.mX == 39)); } @@ -423,11 +430,11 @@ int TestFunctional() int intArray1[3] = { -1, 0, 2 }; int intArray2[3] = { -9, -9, -9 }; - transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fun(&TestClass::MultiplyBy)); + transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fn(&TestClass::MultiplyBy)); EATEST_VERIFY((intArray2[0] == -37) && (intArray2[1] == 0) && (intArray2[2] == 74)); intArray2[0] = intArray2[1] = intArray2[2] = -9; - transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fun(&TestClass::MultiplyByConst)); + transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fn(&TestClass::MultiplyByConst)); EATEST_VERIFY((intArray2[0] == -37) && (intArray2[1] == 0) && (intArray2[2] == 74)); } @@ -436,10 +443,10 @@ int TestFunctional() // mem_fun_ref (no argument version) TestClass tcArray[3]; - for_each(tcArray, tcArray + 3, mem_fun_ref(&TestClass::Increment)); + for_each(tcArray, tcArray + 3, mem_fn(&TestClass::Increment)); EATEST_VERIFY((tcArray[0].mX == 38) && (tcArray[1].mX == 38) && (tcArray[2].mX == 38)); - for_each(tcArray, tcArray + 3, mem_fun_ref(&TestClass::IncrementConst)); + for_each(tcArray, tcArray + 3, mem_fn(&TestClass::IncrementConst)); EATEST_VERIFY((tcArray[0].mX == 39) && (tcArray[1].mX == 39) && (tcArray[2].mX == 39)); } @@ -450,11 +457,11 @@ int TestFunctional() int intArray1[3] = { -1, 0, 2 }; int intArray2[3] = { -9, -9, -9 }; - transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fun_ref(&TestClass::MultiplyBy)); + transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fn(&TestClass::MultiplyBy)); EATEST_VERIFY((intArray2[0] == -37) && (intArray2[1] == 0) && (intArray2[2] == 74)); intArray2[0] = intArray2[1] = intArray2[2] = -9; - transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fun_ref(&TestClass::MultiplyByConst)); + transform(tcArray, tcArray + 3, intArray1, intArray2, mem_fn(&TestClass::MultiplyByConst)); EATEST_VERIFY((intArray2[0] == -37) && (intArray2[1] == 0) && (intArray2[2] == 74)); } @@ -485,10 +492,10 @@ int TestFunctional() list L; eastl::list::iterator in_range = - eastl::find_if(L.begin(), L.end(), - eastl::compose2(eastl::logical_and(), - eastl::bind2nd(eastl::greater_equal(), 1), - eastl::bind2nd(eastl::less_equal(), 10))); + eastl::find_if(L.begin(), L.end(), + eastl::compose2(binary_function_adaptor, bool, bool, bool>(), + eastl::bind2nd(binary_function_adaptor, int, int, bool>(), 1), + eastl::bind2nd(binary_function_adaptor, int, int, bool>(), 10))); EATEST_VERIFY(in_range == L.end()); } @@ -1095,6 +1102,78 @@ int TestFunctional() EATEST_VERIFY(sCtorCount == sDtorCount); } + + #ifdef __cpp_deduction_guides + // eastl::function deduction guides + { + // Function pointer + { + eastl::function f{TestIntRet}; + static_assert(eastl::is_same_v>, "unexpected deduced function type."); + } + + // Member function pointer + { + // No ref-qualifiers + { + struct CallableType + { + bool operator()(int*) + { + return false; + } + } callable; + + eastl::function f{callable}; + static_assert(eastl::is_same_v>, "unexpected deduced function type."); + } + + + #define CHECK_DEDUCED_TYPE(QUALIFIERS) \ + { \ + struct CallableType \ + { \ + bool operator()(int*) QUALIFIERS \ + { \ + return false; \ + } \ + } callable; \ + eastl::function f{callable}; \ + static_assert(eastl::is_same_v>, "unexpected deduced function type."); \ + } + + // Some of the following tests are disabled because you cannot create an eastl::function out of a callable with those qualifiers. + // The problem isn't due to the deduction guides themselves but the implementation of eastl::function and eastl::invoke_impl. + // TODO: as soon as all of this permutations are working, we should be able to use EASTL_GENERATE_MEMBER_FUNCTION_VARIANTS in + // function_detail.h to generate all of those. + CHECK_DEDUCED_TYPE(const) + CHECK_DEDUCED_TYPE(volatile) + CHECK_DEDUCED_TYPE(const volatile) + // CHECK_RETURN_TYPE(&) + CHECK_DEDUCED_TYPE(const&) + // CHECK_RETURN_TYPE(volatile&) + // CHECK_RETURN_TYPE(const volatile&) + // CHECK_RETURN_TYPE(&&) + // CHECK_RETURN_TYPE(const&&) + // CHECK_RETURN_TYPE(volatile&&) + // CHECK_RETURN_TYPE(const volatile&&) + CHECK_DEDUCED_TYPE(noexcept) + CHECK_DEDUCED_TYPE(const noexcept) + CHECK_DEDUCED_TYPE(volatile noexcept) + CHECK_DEDUCED_TYPE(const volatile noexcept) + // CHECK_RETURN_TYPE(& noexcept) + CHECK_DEDUCED_TYPE(const& noexcept) + // CHECK_RETURN_TYPE(volatile& noexcept) + // CHECK_RETURN_TYPE(const volatile& noexcept) + // CHECK_RETURN_TYPE(&& noexcept) + // CHECK_RETURN_TYPE(const&& noexcept) + // CHECK_RETURN_TYPE(volatile&& noexcept) + // CHECK_RETURN_TYPE(const volatile&& noexcept) + + #undef CHECK_DEDUCED_TYPE + } + } + #endif // __cpp_deduction_guides } // Checking _MSC_EXTENSIONS is required because the Microsoft calling convention classifiers are only available when @@ -1527,3 +1606,5 @@ static_assert(!eastl::is_invocable_r::va static_assert(!eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); static_assert(eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); static_assert(eastl::is_invocable_r::value, "incorrect value for is_invocable_r"); + +EASTL_INTERNAL_RESTORE_DEPRECATED() diff --git a/test/source/TestHash.cpp b/test/source/TestHash.cpp index 1bcf9962..c94c8f06 100644 --- a/test/source/TestHash.cpp +++ b/test/source/TestHash.cpp @@ -993,7 +993,7 @@ int TestHash() else EATEST_VERIFY(it == hashSet.end()); - it = hashSet.find_as(pString, hash(), equal_to_2()); + it = hashSet.find_as(pString, hash(), equal_to<>()); if(i < kCount) EATEST_VERIFY(it != hashSet.end()); else @@ -1383,11 +1383,8 @@ int TestHash() { Key() {} Key(Key&&) {} - Key(const Key&&) {} - bool operator==(const Key&) const { return true; } - - private: Key(const Key&) {} + bool operator==(const Key&) const { return true; } }; EA_RESTORE_VC_WARNING() diff --git a/test/source/TestIntrusiveHash.cpp b/test/source/TestIntrusiveHash.cpp index f089aabe..f8887eb8 100644 --- a/test/source/TestIntrusiveHash.cpp +++ b/test/source/TestIntrusiveHash.cpp @@ -348,10 +348,10 @@ int TestIntrusiveHash() // iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate); // const_iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate) const; - itf = ihmSW1.find_as(SetWidgetComparable(7), SWCHash(), eastl::equal_to_2()); + itf = ihmSW1.find_as(SetWidgetComparable(7), SWCHash(), eastl::equal_to<>()); VERIFY(itf->mX == 7); - itfc = ihmSW1Const.find_as(SetWidgetComparable(7), SWCHash(), eastl::equal_to_2()); + itfc = ihmSW1Const.find_as(SetWidgetComparable(7), SWCHash(), eastl::equal_to<>()); VERIFY(itfc->mX == 7); @@ -628,10 +628,10 @@ int TestIntrusiveHash() // iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate); // const_iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate) const; - itf = ihmMW1.find_as(7.f, eastl::hash(), eastl::equal_to_2()); + itf = ihmMW1.find_as(7.f, eastl::hash(), eastl::equal_to<>()); VERIFY(itf->mKey == 7); - itfc = ihmMW1Const.find_as(7.f, eastl::hash(), eastl::equal_to_2()); + itfc = ihmMW1Const.find_as(7.f, eastl::hash(), eastl::equal_to<>()); VERIFY(itfc->mKey == 7); diff --git a/test/source/TestIterator.cpp b/test/source/TestIterator.cpp index b6c6f76c..da318fdd 100644 --- a/test/source/TestIterator.cpp +++ b/test/source/TestIterator.cpp @@ -354,7 +354,7 @@ int TestIterator() EATEST_VERIFY(intSetIterator == eastl::end(intSet)); eastl::array intArray; - eastl::array::iterator intArrayIterator = eastl::begin(intArray); + eastl::array::iterator intArrayIterator = eastl::begin(intArray); EATEST_VERIFY(intArrayIterator == eastl::end(intArray)); eastl::intrusive_list intIList; @@ -455,12 +455,12 @@ int TestIterator() static_assert((eastl::is_iterator_wrapper::value == false), "is_iterator_wrapper failure"); static_assert((eastl::is_iterator_wrapper::value == false), "is_iterator_wrapper failure"); static_assert((eastl::is_iterator_wrapper::value == false), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper::iterator>::value == false), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper*>::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper::iterator>::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper*>::value == false), "is_iterator_wrapper failure"); static_assert((eastl::is_iterator_wrapper >::value == false), "is_iterator_wrapper failure"); static_assert((eastl::is_iterator_wrapper >::value == true), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper::iterator> >::value == true), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper::iterator> >::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper::iterator> >::value == true), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper::iterator> >::value == false), "is_iterator_wrapper failure"); static_assert((eastl::is_iterator_wrapper >::value == false), "is_iterator_wrapper failure"); static_assert((eastl::is_iterator_wrapper> >::value == true), "is_iterator_wrapper failure"); } diff --git a/test/source/TestListMap.cpp b/test/source/TestListMap.cpp index 3d48133f..f883fafc 100644 --- a/test/source/TestListMap.cpp +++ b/test/source/TestListMap.cpp @@ -199,12 +199,12 @@ int TestListMap() testStringMap.push_back(eastl::string("hello"), 750); EATEST_VERIFY(testStringMap.size() == 1); - strIter = testStringMap.find_as("hello", eastl::less_2()); + strIter = testStringMap.find_as("hello", eastl::less<>()); EATEST_VERIFY(strIter != testStringMap.end()); EATEST_VERIFY(strIter->first == "hello"); EATEST_VERIFY(strIter->second == 750); - strIter = testStringMap.find_as("fake_string", eastl::less_2()); + strIter = testStringMap.find_as("fake_string", eastl::less<>()); EATEST_VERIFY(strIter == testStringMap.end()); EATEST_VERIFY(testStringMap.validate()); } diff --git a/test/source/TestMap.cpp b/test/source/TestMap.cpp index 0df8c884..abab2db3 100644 --- a/test/source/TestMap.cpp +++ b/test/source/TestMap.cpp @@ -31,14 +31,18 @@ template class eastl::multimap; // typedef eastl::map VM1; typedef eastl::map VM4; +typedef eastl::map VM7; typedef eastl::multimap VMM1; typedef eastl::multimap VMM4; +typedef eastl::multimap VMM7; #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY typedef std::map VM3; typedef std::map VM6; + typedef std::map VM9; typedef std::multimap VMM3; typedef std::multimap VMM6; + typedef std::multimap VMM9; #endif /////////////////////////////////////////////////////////////////////////////// @@ -66,15 +70,33 @@ int TestMap() nErrorCount += TestMapMutation(); nErrorCount += TestMapMutation(); } + + // Note: some std:: libraries throw UBSAN errors with Align64. + // So we only run these tests when UBSAN is not enabled to + // keep our UBSAN builds clean. + #if !EA_UBSAN_ENABLED + { + // Construction + nErrorCount += TestMapConstruction(); + nErrorCount += TestMapConstruction(); + + // Mutation + nErrorCount += TestMapMutation(); + nErrorCount += TestMapMutation(); + } + #endif // !EA_UBSAN_ENABLED + #endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY { // Test searching functionality. nErrorCount += TestMapSearch(); nErrorCount += TestMapSearch(); + nErrorCount += TestMapSearch(); nErrorCount += TestMapSearch(); nErrorCount += TestMapSearch(); + nErrorCount += TestMapSearch(); } @@ -90,6 +112,13 @@ int TestMap() nErrorCount += TestMapCpp17>(); } + { + // Tests for element access: operator[] and at() + nErrorCount += TestMapAccess(); + nErrorCount += TestMapAccess(); + nErrorCount += TestMapAccess(); + } + { // Misc tests @@ -116,7 +145,7 @@ int TestMap() { // User reports that EASTL_VALIDATE_COMPARE_ENABLED / EASTL_COMPARE_VALIDATE isn't compiling for this case. eastl::map m; - m.find_as(EA_CHAR8("some string"), eastl::equal_to_2()); + m.find_as(EA_CHAR8("some string"), eastl::equal_to<>()); } { @@ -125,10 +154,10 @@ int TestMap() m[ip] = 0; - auto it = m.find_as(ip, eastl::less_2{}); + auto it = m.find_as(ip, eastl::less<>{}); EATEST_VERIFY(it != m.end()); - it = m.find_as((int*)(uintptr_t)0xDEADC0DE, eastl::less_2{}); + it = m.find_as((int*)(uintptr_t)0xDEADC0DE, eastl::less<>{}); EATEST_VERIFY(it != m.end()); } @@ -144,37 +173,6 @@ int TestMap() EATEST_VERIFY(v.validate()); } - { - typedef eastl::map IntIntMap; - IntIntMap map1; - map1[1] = 1; - map1[3] = 3; - - #if EASTL_EXCEPTIONS_ENABLED - EATEST_VERIFY_THROW(map1.at(0)); - EATEST_VERIFY_THROW(map1.at(2)); - EATEST_VERIFY_THROW(map1.at(4)); - #endif - map1[0] = 1; - #if EASTL_EXCEPTIONS_ENABLED - EATEST_VERIFY_NOTHROW(map1.at(0)); - EATEST_VERIFY_NOTHROW(map1.at(1)); - EATEST_VERIFY_NOTHROW(map1.at(3)); - #endif - EATEST_VERIFY(map1.at(0) == 1); - EATEST_VERIFY(map1.at(1) == 1); - EATEST_VERIFY(map1.at(3) == 3); - - const IntIntMap map2; - const IntIntMap map3(map1); - - #if EASTL_EXCEPTIONS_ENABLED - EATEST_VERIFY_THROW(map2.at(0)); - EATEST_VERIFY_NOTHROW(map3.at(0)); - #endif - EATEST_VERIFY(map3.at(0) == 1); - } - // User regression test { #if !EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR diff --git a/test/source/TestMap.h b/test/source/TestMap.h index 8d480cff..0f2de8d9 100644 --- a/test/source/TestMap.h +++ b/test/source/TestMap.h @@ -597,17 +597,17 @@ int TestMapSearch() for(i = 0; i < 1000; i++) { TC k = typename T1::key_type(i); - it = t1A.find_as(k, eastl::less_2()); + it = t1A.find_as(k, eastl::less<>()); EATEST_VERIFY(it != t1A.end()); EATEST_VERIFY(it->first == k); EATEST_VERIFY(it->second == k); } - it = t1A.find_as(TC(typename T1::key_type(-1)), eastl::less_2()); + it = t1A.find_as(TC(typename T1::key_type(-1)), eastl::less<>()); EATEST_VERIFY(it == t1A.end()); - it = t1A.find_as(TC(typename T1::key_type(1001)), eastl::less_2()); + it = t1A.find_as(TC(typename T1::key_type(1001)), eastl::less<>()); EATEST_VERIFY(it == t1A.end()); @@ -1388,6 +1388,52 @@ int TestMapCpp17() return nErrorCount; } +/////////////////////////////////////////////////////////////////////////////// +// TestMapAccess +// +// This function is designed to work with map, fixed_map, hash_map, fixed_hash_map, unordered_map. +// +// Tests for element access: operator[] and at() +template +int TestMapAccess() +{ + int nErrorCount = 0; + + typedef T1 TOMap; + typedef typename TOMap::key_type key_type; + typedef typename TOMap::mapped_type mapped_type; + + TOMap map1; + map1[key_type(1)] = mapped_type(1); + map1[key_type(3)] = mapped_type(3); + +#if EASTL_EXCEPTIONS_ENABLED + EATEST_VERIFY_THROW(map1.at(key_type(0))); + EATEST_VERIFY_THROW(map1.at(key_type(2))); + EATEST_VERIFY_THROW(map1.at(key_type(4))); +#endif + map1[key_type(0)] = mapped_type(1); +#if EASTL_EXCEPTIONS_ENABLED + EATEST_VERIFY_NOTHROW(map1.at(key_type(0))); + EATEST_VERIFY_NOTHROW(map1.at(key_type(1))); + EATEST_VERIFY_NOTHROW(map1.at(key_type(3))); +#endif + EATEST_VERIFY(map1.at(key_type(0)) == mapped_type(1)); + EATEST_VERIFY(map1.at(key_type(1)) == mapped_type(1)); + EATEST_VERIFY(map1.at(key_type(3)) == mapped_type(3)); + + const TOMap map2; + const TOMap map3(map1); + +#if EASTL_EXCEPTIONS_ENABLED + EATEST_VERIFY_THROW(map2.at(key_type(0))); + EATEST_VERIFY_NOTHROW(map3.at(key_type(0))); +#endif + EATEST_VERIFY(map3.at(key_type(0)) == mapped_type(1)); + + return nErrorCount; +} + template struct HashContainerReserveTest diff --git a/test/source/TestMemory.cpp b/test/source/TestMemory.cpp index 77caf9f2..607305f4 100644 --- a/test/source/TestMemory.cpp +++ b/test/source/TestMemory.cpp @@ -162,6 +162,7 @@ int TestMemory() TestObject::Reset(); + EASTL_INTERNAL_DISABLE_DEPRECATED() // 'eastl::get_temporary_buffer': was declared deprecated { // get_temporary_buffer(ptrdiff_t n, size_t alignment, size_t alignmentOffset, char* pName); @@ -174,6 +175,7 @@ int TestMemory() memset(pr2.first, 0, 300 * sizeof(TestObject)); return_temporary_buffer(pr2.first, pr2.second); } + EASTL_INTERNAL_RESTORE_DEPRECATED() EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); @@ -392,6 +394,7 @@ int TestMemory() // inline ForwardIteratorDest uninitialized_relocate(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) // This test does little more than verify that the code compiles. + EASTL_INTERNAL_DISABLE_DEPRECATED() // '*': was declared deprecated int* pEnd = eastl::uninitialized_relocate_start((int*)NULL, (int*)NULL, (int*)NULL); EATEST_VERIFY(pEnd == NULL); @@ -403,15 +406,35 @@ int TestMemory() pEnd = eastl::uninitialized_relocate((int*)NULL, (int*)NULL, (int*)NULL); EATEST_VERIFY(pEnd == NULL); + EASTL_INTERNAL_RESTORE_DEPRECATED() - // template - // ForwardIterator uninitialized_copy(InputIterator sourceFirst, InputIterator sourceLast, ForwardIterator destination); + { + // template + // ForwardIterator uninitialized_copy(InputIterator sourceFirst, InputIterator sourceLast, ForwardIterator destination); - pEnd = eastl::uninitialized_copy((int*)NULL, (int*)NULL, (int*)NULL); - EATEST_VERIFY(pEnd == NULL); + pEnd = eastl::uninitialized_copy((int*)NULL, (int*)NULL, (int*)NULL); + EATEST_VERIFY(pEnd == NULL); + + int intArray1[] = { 3, 2, 6, 5, 4, 1 }; + int intArray2[] = { 1, 2, 3, 4, 5, 6 }; + + uninitialized_copy(intArray2, intArray2 + 6, intArray1); + EATEST_VERIFY(VerifySequence(intArray1, intArray1 + 6, int(), "uninitialized_copy", 1, 2, 3, 4, 5, 6, -1)); + + uninitialized_copy(eastl::move_iterator{ intArray2 }, eastl::move_iterator{ intArray2 + 6 }, intArray1); + EATEST_VERIFY(VerifySequence(intArray1, intArray1 + 6, int(), "uninitialized_copy", 1, 2, 3, 4, 5, 6, -1)); + } + + { + // uninitialized_copy_n + int intArray1[] = { 3, 2, 6, 5, 4, 1 }; + int intArray2[] = { 1, 2, 3, 4, 5, 6 }; + uninitialized_copy_n(intArray2, 6, intArray1); + EATEST_VERIFY(VerifySequence(intArray1, intArray1 + 6, int(), "uninitialized_copy_n", 1, 2, 3, 4, 5, 6, -1)); + } // template @@ -421,12 +444,16 @@ int TestMemory() EATEST_VERIFY(pEnd == NULL); + { + // template + // void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& value) - // template - // void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& value) - - eastl::uninitialized_fill((int*)NULL, (int*)NULL, (int)0); + eastl::uninitialized_fill((int*)NULL, (int*)NULL, (int)0); + int intArray[] = { 3, 2, 6, 5, 4, 1 }; + uninitialized_fill(intArray, intArray + 6, 4); + EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "uninitialized_fill", 4, 4, 4, 4, 4, 4, -1)); + } // template @@ -435,12 +462,16 @@ int TestMemory() eastl::uninitialized_fill_ptr((int*)NULL, (int*)NULL, (int)0); + { + // template + // void uninitialized_fill_n(ForwardIterator first, Count n, const T& value) - // template - // void uninitialized_fill_n(ForwardIterator first, Count n, const T& value) - - eastl::uninitialized_fill_n((int*)NULL, (int)0, (int)0); + eastl::uninitialized_fill_n((int*)NULL, (int)0, (int)0); + int intArray[] = { 3, 2, 6, 5, 4, 1 }; + uninitialized_fill_n(intArray, 6, 5); + EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "uninitialized_fill_n", 5, 5, 5, 5, 5, 5, -1)); + } // template @@ -502,6 +533,10 @@ int TestMemory() eastl::uninitialized_value_construct(pTestMemory, pTestMemory + 10); EATEST_VERIFY(TestObject::sTODefaultCtorCount == 10); + + int intArray[] = { 3, 2, 6, 5, 4, 1 }; + uninitialized_value_construct(intArray, intArray + 6); + EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "uninitialized_value_construct", 0, 0, 0, 0, 0, 0, -1)); } // uninitialized_value_construct_n @@ -513,6 +548,10 @@ int TestMemory() auto endIter = eastl::uninitialized_value_construct_n(pTestMemory, 5); EATEST_VERIFY(TestObject::sTODefaultCtorCount == 5); EATEST_VERIFY(endIter == (pTestMemory + 5)); + + int intArray[] = { 3, 2, 6, 5, 4, 1 }; + uninitialized_value_construct_n(intArray, 6); + EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "uninitialized_value_construct_n", 0, 0, 0, 0, 0, 0, -1)); } // Verify that uninitialized_value_construct does not do any additional initialization besides zero-initialization. @@ -568,6 +607,26 @@ int TestMemory() } } + { + // uninitialized_move + + int intArray1[] = { 3, 2, 6, 5, 4, 1 }; + int intArray2[] = { 1, 2, 3, 4, 5, 6 }; + + uninitialized_move(intArray2, intArray2 + 6, intArray1); + EATEST_VERIFY(VerifySequence(intArray1, intArray1 + 6, int(), "uninitialized_move", 1, 2, 3, 4, 5, 6, -1)); + } + + { + // uninitialized_move_n + + int intArray1[] = { 3, 2, 6, 5, 4, 1 }; + int intArray2[] = { 1, 2, 3, 4, 5, 6 }; + + uninitialized_move_n(intArray2, 6, intArray1); + EATEST_VERIFY(VerifySequence(intArray1, intArray1 + 6, int(), "uninitialized_move_n", 1, 2, 3, 4, 5, 6, -1)); + } + // template // void destruct(T* p) { @@ -737,14 +796,14 @@ int TestMemory() space = 64; ptr = 0; - ptr = (char*)ptr - space; + ptr = (void*)((uintptr_t)ptr - (uintptr_t)space); ptrSaved = ptr; pResult = eastl::align(1, space + 1, ptr, space); // Possible alignment, impossible size due to wraparound. EATEST_VERIFY((pResult == NULL) && (ptr == ptrSaved)); space = 64; ptr = 0; - ptr = (char*)ptr - space; + ptr = (void*)((uintptr_t)ptr - (uintptr_t)space); ptrSaved = ptr; pResult = eastl::align(space * 2, 32, ptr, space); // Impossible alignment due to wraparound, possible size. EATEST_VERIFY((pResult == NULL) && (ptr == ptrSaved)); diff --git a/test/source/TestOptional.cpp b/test/source/TestOptional.cpp index 36307ad0..58cff5ab 100644 --- a/test/source/TestOptional.cpp +++ b/test/source/TestOptional.cpp @@ -38,18 +38,62 @@ struct destructor_test }; bool destructor_test::destructor_ran = false; +///////////////////////////////////////////////////////////////////////////// +struct copy_test +{ + copy_test() = default; + + copy_test(const copy_test& ct) + { + was_copied = true; + value = ct.value; + } + + copy_test& operator=(const copy_test& ct) + { + was_copied = true; + value = ct.value; + + return *this; + } + + // issue a compiler error if container tries to move + copy_test(copy_test const&&) = delete; + copy_test& operator=(const copy_test&&) = delete; + + static bool was_copied; + + int value; +}; + +bool copy_test::was_copied = false; + ///////////////////////////////////////////////////////////////////////////// struct move_test { move_test() = default; - move_test(move_test&&) { was_moved = true; } - move_test& operator=(move_test&&) { was_moved = true; return *this;} - // issue a compiler error is container tries to copy + move_test(move_test&& mt) + { + was_moved = true; + value = mt.value; + } + + move_test& operator=(move_test&& mt) + { + was_moved = true; + value = mt.value; + + return *this; + } + + // issue a compiler error if container tries to copy move_test(move_test const&) = delete; move_test& operator=(const move_test&) = delete; static bool was_moved; + + int value; }; bool move_test::was_moved = false; @@ -107,7 +151,9 @@ int TestOptional() VERIFY(is_empty::value); #if EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE + EASTL_INTERNAL_DISABLE_DEPRECATED() // 'is_literal_type': was declared deprecated VERIFY(is_literal_type::value); + EASTL_INTERNAL_RESTORE_DEPRECATED() #endif #if EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE @@ -279,11 +325,33 @@ int TestOptional() } } - { - move_test t; - optional o(eastl::move(t)); - VERIFY(move_test::was_moved); - } + { + copy_test c; + c.value = 42; + + optional o1(c); + VERIFY(copy_test::was_copied); + + copy_test::was_copied = false; + + optional o2(o1); + VERIFY(copy_test::was_copied); + VERIFY(o2->value == 42); + } + + { + move_test t; + t.value = 42; + + optional o1(eastl::move(t)); + VERIFY(move_test::was_moved); + + move_test::was_moved = false; + + optional o2(eastl::move(o1)); + VERIFY(move_test::was_moved); + VERIFY(o2->value == 42); + } { forwarding_testft(1.f); diff --git a/test/source/TestSet.h b/test/source/TestSet.h index 16f55c7a..eaccb54f 100644 --- a/test/source/TestSet.h +++ b/test/source/TestSet.h @@ -571,16 +571,16 @@ int TestSetSearch() for(i = 0; i < 1000; i++) { TC k = typename T1::key_type(i); - it = t1A.find_as(k, eastl::less_2()); + it = t1A.find_as(k, eastl::less<>()); VERIFY(it != t1A.end()); VERIFY(*it == k); } - it = t1A.find_as(TC(typename T1::key_type(-1)), eastl::less_2()); + it = t1A.find_as(TC(typename T1::key_type(-1)), eastl::less<>()); VERIFY(it == t1A.end()); - it = t1A.find_as(TC(typename T1::key_type(1001)), eastl::less_2()); + it = t1A.find_as(TC(typename T1::key_type(1001)), eastl::less<>()); VERIFY(it == t1A.end()); diff --git a/test/source/TestSort.cpp b/test/source/TestSort.cpp index 114a73b3..3751b881 100644 --- a/test/source/TestSort.cpp +++ b/test/source/TestSort.cpp @@ -177,22 +177,8 @@ namespace eastl return x; } }; - - struct TestNoLessOperator - { - int i {}; - }; } // namespace Internal - template <> - struct less - { - bool operator()(const Internal::TestNoLessOperator& lhs, const Internal::TestNoLessOperator& rhs) const noexcept - { - return lhs.i < rhs.i; - } - }; - } // namespace eastl int TestSort() @@ -814,7 +800,7 @@ int TestSort() } { - // Test checking that deque sorting can compile. + // EATEST_VERIFY deque sorting can compile. deque intDeque; vector intVector; @@ -822,25 +808,6 @@ int TestSort() stable_sort(intVector.begin(), intVector.end()); } - { - // Test checking that sorting containers having elements of a type without an operator< compiles correctly - - vector noLessVector; - - stable_sort(noLessVector.begin(), noLessVector.end()); - bubble_sort(noLessVector.begin(), noLessVector.end()); - shaker_sort(noLessVector.begin(), noLessVector.end()); - insertion_sort(noLessVector.begin(), noLessVector.end()); - selection_sort(noLessVector.begin(), noLessVector.end()); - shell_sort(noLessVector.begin(), noLessVector.end()); - comb_sort(noLessVector.begin(), noLessVector.end()); - heap_sort(noLessVector.begin(), noLessVector.end()); - merge_sort(noLessVector.begin(), noLessVector.end(), *get_default_allocator(nullptr)); - quick_sort(noLessVector.begin(), noLessVector.end()); - - vector buffer; - tim_sort_buffer(noLessVector.begin(), noLessVector.end(), buffer.data()); -} { // Test sorting of a container of pointers to objects as opposed to a container of objects themselves. diff --git a/test/source/TestString.inl b/test/source/TestString.inl index 3a59e68d..430cef9e 100644 --- a/test/source/TestString.inl +++ b/test/source/TestString.inl @@ -266,6 +266,48 @@ int TEST_STRING_NAME() VERIFY(str == LITERAL("Hello, 42 42 42 42 42 42 42 42 42")); VERIFY(str.validate()); } + + { + constexpr eastl_ssize_t signedValue = -42; + StringType str(typename StringType::CtorSprintf(), LITERAL("Hello, %" EASTL_PRIdSIZE), signedValue); + VERIFY(str == LITERAL("Hello, -42")); + VERIFY(str.validate()); + } + + { + constexpr eastl_ssize_t signedValue = -42; + StringType str(typename StringType::CtorSprintf(), LITERAL("Hello, %" EASTL_PRIiSIZE), signedValue); + VERIFY(str == LITERAL("Hello, -42")); + VERIFY(str.validate()); + } + + { + constexpr eastl_size_t unsignedValue = 42u; + StringType str(typename StringType::CtorSprintf(), LITERAL("Hello, 0%" EASTL_PRIoSIZE), unsignedValue); + VERIFY(str == LITERAL("Hello, 052")); + VERIFY(str.validate()); + } + + { + constexpr eastl_size_t unsignedValue = 42u; + StringType str(typename StringType::CtorSprintf(), LITERAL("Hello, %" EASTL_PRIuSIZE), unsignedValue); + VERIFY(str == LITERAL("Hello, 42")); + VERIFY(str.validate()); + } + + { + constexpr eastl_size_t unsignedValue = 42u; + StringType str(typename StringType::CtorSprintf(), LITERAL("Hello, 0x%" EASTL_PRIxSIZE), unsignedValue); + VERIFY(str == LITERAL("Hello, 0x2a")); + VERIFY(str.validate()); + } + + { + constexpr eastl_size_t unsignedValue = 42u; + StringType str(typename StringType::CtorSprintf(), LITERAL("Hello, 0x%" EASTL_PRIXSIZE), unsignedValue); + VERIFY(str == LITERAL("Hello, 0x2A")); + VERIFY(str.validate()); + } #endif } diff --git a/test/source/TestTuple.cpp b/test/source/TestTuple.cpp index 6a7647e1..6f583415 100644 --- a/test/source/TestTuple.cpp +++ b/test/source/TestTuple.cpp @@ -340,20 +340,95 @@ int TestTuple() tie(a, ignore, b) = make_tuple(1, 3, 5); EATEST_VERIFY(a == 1 && b == 5.0f); - // tuple_cat - auto tcatRes = tuple_cat(make_tuple(1, 2.0f), make_tuple(3.0, true)); - EATEST_VERIFY(get<0>(tcatRes) == 1 && get<1>(tcatRes) == 2.0f && get<2>(tcatRes) == 3.0 && - get<3>(tcatRes) == true); - - auto tcatRes2 = tuple_cat(make_tuple(1, 2.0f), make_tuple(3.0, true), make_tuple(5u, '6')); - EATEST_VERIFY(get<0>(tcatRes2) == 1 && get<1>(tcatRes2) == 2.0f && get<2>(tcatRes2) == 3.0 && - get<3>(tcatRes2) == true && get<4>(tcatRes2) == 5u && get<5>(tcatRes2) == '6'); - auto aCattedRefTuple = tuple_cat(make_tuple(1), tie(a, ignore, b)); get<1>(aCattedRefTuple) = 2; EATEST_VERIFY(a == 2); } + // tuple_cat + { + // zero args + { + auto result = tuple_cat(); + static_assert(eastl::is_same_v>, "type mismatch"); + } + + // one arg - l-value + { + tuple t{42, true}; + + auto result = tuple_cat(t); + + static_assert(eastl::is_same_v>, "type mismatch"); + + EATEST_VERIFY(get<0>(result) == 42); + EATEST_VERIFY(get<1>(result)); + } + + // one arg - r-value + { + tuple> t{42, new bool(true)}; + + auto result = tuple_cat(eastl::move(t)); + + static_assert(eastl::is_same_v>>, "type mismatch"); + + EATEST_VERIFY(get<0>(result) == 42); + EATEST_VERIFY(get<1>(result) != nullptr && *get<1>(result)); + EATEST_VERIFY(get<1>(t) == nullptr); + } + + // two args - l-values + { + tuple t1{42, true}; + tuple t2{3.14f, 1337}; + + auto result = tuple_cat(t1, t2); + + static_assert(eastl::is_same_v>, "type mismatch"); + + EATEST_VERIFY(get<0>(result) == 42); + EATEST_VERIFY(get<1>(result)); + EATEST_VERIFY(get<2>(result) == 3.14f); + EATEST_VERIFY(get<3>(result) == 1337); + } + + // two args - r-values + { + tuple> t1{42, new bool(true)}; + tuple, int> t2{new float(3.14f), 1337}; + + auto result = tuple_cat(eastl::move(t1), eastl::move(t2)); + + static_assert(eastl::is_same_v, unique_ptr, int>>, "type mismatch"); + + EATEST_VERIFY(get<0>(result) == 42); + EATEST_VERIFY(get<1>(result) != nullptr && *get<1>(result)); + EATEST_VERIFY(get<1>(t1) == nullptr); + EATEST_VERIFY(get<2>(result) != nullptr && *get<2>(result) == 3.14f); + EATEST_VERIFY(get<3>(result) == 1337); + EATEST_VERIFY(get<0>(t2) == nullptr); + } + + // More than two parameters and empty tuples. + { + tuple t1{42, true}; + tuple, int> t2{new float(3.14f), 1337}; + tuple<> t3{}; + tuple> t4{new short(10)}; + + auto result = tuple_cat(t1, eastl::move(t2), t3, eastl::move(t4)); + + static_assert(eastl::is_same_v, int, unique_ptr>>, "type mismatch"); + + EATEST_VERIFY(get<0>(result) == 42); + EATEST_VERIFY(get<1>(result)); + EATEST_VERIFY(get<2>(result) != nullptr && *get<2>(result) == 3.14f); + EATEST_VERIFY(get<3>(result) == 1337); + EATEST_VERIFY(get<4>(result) != nullptr && *get<4>(result) == 10); + } + } + { // Empty tuple tuple<> emptyTuple; @@ -551,20 +626,6 @@ int TestTuple() } #endif - // user regression for tuple_cat - { - void* empty = nullptr; - auto t = eastl::make_tuple(empty, true); - auto tc = eastl::tuple_cat(eastl::make_tuple("asd", 1), t); - - static_assert(eastl::is_same_v>, "type mismatch"); - - EATEST_VERIFY(eastl::string("asd") == eastl::get<0>(tc)); - EATEST_VERIFY(eastl::get<1>(tc) == 1); - EATEST_VERIFY(eastl::get<2>(tc) == nullptr); - EATEST_VERIFY(eastl::get<3>(tc) == true); - } - // user reported regression that exercises type_traits trying to pull out the element_type from "fancy pointers" { auto up = eastl::make_unique(100); @@ -575,6 +636,34 @@ int TestTuple() static_assert(eastl::is_same_v, eastl::unique_ptr>); } + // user reported issue that a tuple was not default constructible if a tuple element type had no members (ie. is_empty_v). + { + tuple<> emptyTuple; + EA_UNUSED(emptyTuple); + + tuple tupleWithEmptyMember; + EA_UNUSED(tupleWithEmptyMember); + tuple tupleWithEmptyMember2; + EA_UNUSED(tupleWithEmptyMember2); + tuple tupleWithEmptyMember3; + EA_UNUSED(tupleWithEmptyMember3); + + static_assert(sizeof(tuple) <= sizeof(tuple)); + static_assert(sizeof(tuple) <= sizeof(tuple)); + + tuple tupleWithEmptyMember4(NoDataMembers{}); + EA_UNUSED(tupleWithEmptyMember4); + + struct EmptyNoDefaultCtor + { + EmptyNoDefaultCtor() = delete; + EmptyNoDefaultCtor(int) {} + }; + + tuple tupleWithEmptyMember5(EmptyNoDefaultCtor{3}); + EA_UNUSED(tupleWithEmptyMember5); + } + return nErrorCount; } diff --git a/test/source/TestTypeTraits.cpp b/test/source/TestTypeTraits.cpp index 2670e244..0c8190e8 100644 --- a/test/source/TestTypeTraits.cpp +++ b/test/source/TestTypeTraits.cpp @@ -13,6 +13,8 @@ using namespace eastl; +EASTL_INTERNAL_DISABLE_DEPRECATED() // *: was declared deprecated + bool GetType(const true_type&) { @@ -634,6 +636,8 @@ int TestTypeTraits() static_assert(is_bounded_array::value == false, "is_bounded_array failure"); static_assert(is_bounded_array::value == true, "is_bounded_array failure"); static_assert(is_bounded_array::value == false, "is_bounded_array failure"); + static_assert(is_bounded_array::value == false, "is_bounded_array failure"); + static_assert(is_bounded_array::value == false, "is_bounded_array failure"); static_assert(is_bounded_array::value == false, "is_bounded_array failure"); EATEST_VERIFY(GetType(is_bounded_array()) == false); @@ -652,6 +656,8 @@ int TestTypeTraits() static_assert(is_unbounded_array::value == false, "is_unbounded_array failure"); static_assert(is_unbounded_array::value == false, "is_unbounded_array failure"); static_assert(is_unbounded_array::value == true, "is_unbounded_array failure"); + static_assert(is_unbounded_array::value == false, "is_unbounded_array failure"); + static_assert(is_unbounded_array::value == false, "is_unbounded_array failure"); static_assert(is_unbounded_array::value == false, "is_unbounded_array failure"); EATEST_VERIFY(GetType(is_unbounded_array()) == false); @@ -660,6 +666,7 @@ int TestTypeTraits() EATEST_VERIFY(GetType(is_unbounded_array()) == false); + // is_reference static_assert(is_reference::value == true, "is_reference failure"); EATEST_VERIFY(GetType(is_reference()) == true); @@ -1343,12 +1350,14 @@ int TestTypeTraits() static_assert(is_array_of_known_bounds::value == false, "is_array_of_known_bounds failure"); static_assert(is_array_of_known_bounds::value == true, "is_array_of_known_bounds failure"); static_assert(is_array_of_known_bounds::value == false, "is_array_of_known_bounds failure"); + static_assert(is_array_of_known_bounds::value == false, "is_array_of_known_bounds failure"); - static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_known_bounds failure"); - static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_known_bounds failure"); - static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_known_bounds failure"); - static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_known_bounds failure"); - static_assert(is_array_of_unknown_bounds::value == true, "is_array_of_known_bounds failure"); + static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_unknown_bounds failure"); + static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_unknown_bounds failure"); + static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_unknown_bounds failure"); + static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_unknown_bounds failure"); + static_assert(is_array_of_unknown_bounds::value == true, "is_array_of_unknown_bounds failure"); + static_assert(is_array_of_unknown_bounds::value == false, "is_array_of_unknown_bounds failure"); // is_trivially_copyable @@ -2437,3 +2446,5 @@ int TestTypeTraits() return nErrorCount; } + +EASTL_INTERNAL_RESTORE_DEPRECATED() // *: was declared deprecated diff --git a/test/source/TestUtility.cpp b/test/source/TestUtility.cpp index e9027e5e..1a90e19b 100644 --- a/test/source/TestUtility.cpp +++ b/test/source/TestUtility.cpp @@ -16,6 +16,10 @@ inline bool operator==(const BasicObject& t1, const BasicObject& t2) { return t1 inline bool operator<(const BasicObject& t1, const BasicObject& t2) { return t1.mX < t2.mX; } +static_assert(eastl::is_trivially_copyable_v>, "EASTL extension, pair is trivially copyable."); +static_assert(eastl::is_trivially_copyable_v>, "EASTL extension, pair is trivially copyable."); +static_assert(eastl::is_trivially_copyable_v>, "EASTL extension, pair is trivially copyable."); + /////////////////////////////////////////////////////////////////////////////// // TestUtilityPair // diff --git a/test/source/TestVector.cpp b/test/source/TestVector.cpp index 69cdb523..05f72e89 100644 --- a/test/source/TestVector.cpp +++ b/test/source/TestVector.cpp @@ -1433,16 +1433,6 @@ int TestVector() EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); - { // Regression of user error report for the case of vector. - eastl::vector ctorValues; - - for (int v = 0; v < 10; v++) - ctorValues.push_back(v); - - eastl::vector testStruct(ctorValues.begin(), ctorValues.end()); - eastl::vector testInt(ctorValues.begin(), ctorValues.end()); - } - { // Regression to verify that const vector works. const eastl::vector constIntVector1; EATEST_VERIFY(constIntVector1.empty()); diff --git a/test/source/TestVectorMap.cpp b/test/source/TestVectorMap.cpp index ca400ed0..57ce87d4 100644 --- a/test/source/TestVectorMap.cpp +++ b/test/source/TestVectorMap.cpp @@ -40,12 +40,18 @@ typedef eastl::vector_map, EASTLAllocatorType, eastl: typedef eastl::vector_map VM4; typedef eastl::vector_map, EASTLAllocatorType, eastl::deque > > VM5; +static_assert(sizeof(eastl::vector_map) == sizeof(eastl::vector), "if is_empty_v, sizeof(vector_map) == sizeof(RandomAccessContainer)"); +static_assert(sizeof(eastl::vector_map) == sizeof(eastl::vector), "if is_empty_v, sizeof(vector_map) == sizeof(RandomAccessContainer)"); + typedef eastl::vector_multimap VMM1; typedef eastl::vector_multimap, EASTLAllocatorType, eastl::deque > > VMM2; typedef eastl::vector_multimap VMM4; typedef eastl::vector_multimap, EASTLAllocatorType, eastl::deque > > VMM5; +static_assert(sizeof(eastl::vector_multimap) == sizeof(eastl::vector>), "if is_empty_v, sizeof(vector_multimap) == sizeof(RandomAccessContainer)"); +static_assert(sizeof(eastl::vector_multimap) == sizeof(eastl::vector>), "if is_empty_v, sizeof(vector_multimap) == sizeof(RandomAccessContainer)"); + #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY typedef std::map VM3; typedef std::map VM6; @@ -54,7 +60,25 @@ typedef eastl::vector_multimap, #endif /////////////////////////////////////////////////////////////////////////////// +template +int TestVectorMapAtKey() +{ + int nErrorCount = 0; + + typedef T1 TOMap; + typedef typename TOMap::key_type key_type; + typedef typename TOMap::mapped_type mapped_type; + TOMap map1; + map1[key_type(1)] = mapped_type(1); + map1[key_type(3)] = mapped_type(3); + map1[key_type(0)] = mapped_type(1); + EATEST_VERIFY(map1.at_key(key_type(0)) == mapped_type(1)); + EATEST_VERIFY(map1.at_key(key_type(1)) == mapped_type(1)); + EATEST_VERIFY(map1.at_key(key_type(3)) == mapped_type(3)); + + return nErrorCount; +} int TestVectorMap() { @@ -110,6 +134,21 @@ int TestVectorMap() nErrorCount += TestMultimapCpp11, EASTLAllocatorType, eastl::deque > > >(); } + { + // Tests for element access: operator[] and at() + + // todo: can't enable these tests until the current at() function is removed (which gets by index rather than by key) and we can replace with a semanticly correct one. + + //nErrorCount += TestMapAccess(); + //nErrorCount += TestMapAccess(); + //nErrorCount += TestMapAccess(); + //nErrorCount += TestMapAccess(); + + nErrorCount += TestVectorMapAtKey(); + nErrorCount += TestVectorMapAtKey(); + nErrorCount += TestVectorMapAtKey(); + nErrorCount += TestVectorMapAtKey(); + } { // insert at the upper bound of a range @@ -191,17 +230,23 @@ int TestVectorMap() tvm["AllowedDomain"] = NULL; } - { // find_as predicate + { // find / find_as / lower_bound / upper_bound { // vector_map eastl::vector_map vss = {{"abc", 11}, {"def", 22}, {"ghi", 33}, {"jklmnop", 44}, {"qrstu", 55}, {"vw", 66}, {"x", 77}, {"yz", 88}}; + VERIFY(vss.find("ghi") != vss.end()); VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end()); + VERIFY(vss.lower_bound("ghi") != vss.end()); + VERIFY(vss.upper_bound("ghi") != vss.end()); } { // const vector_map const eastl::vector_map vss = {{"abc", 11}, {"def", 22}, {"ghi", 33}, {"jklmnop", 44}, {"qrstu", 55}, {"vw", 66}, {"x", 77}, {"yz", 88}}; + VERIFY(vss.find("ghi") != vss.end()); VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end()); + VERIFY(vss.lower_bound("ghi") != vss.end()); + VERIFY(vss.upper_bound("ghi") != vss.end()); } // vector_multimap diff --git a/test/source/TestVectorSet.cpp b/test/source/TestVectorSet.cpp index 067630fa..fb371bb8 100644 --- a/test/source/TestVectorSet.cpp +++ b/test/source/TestVectorSet.cpp @@ -28,6 +28,11 @@ template class eastl::vector_multiset; template class eastl::vector_set; template class eastl::vector_multiset; +static_assert(sizeof(eastl::vector_set) == sizeof(eastl::vector), "if is_empty_v, sizeof(vector_set) == sizeof(RandomAccessContainer)"); +static_assert(sizeof(eastl::vector_set) == sizeof(eastl::vector), "if is_empty_v, sizeof(vector_set) == sizeof(RandomAccessContainer)"); +static_assert(sizeof(eastl::vector_multiset) == sizeof(eastl::vector), "if is_empty_v, sizeof(vector_multiset) == sizeof(RandomAccessContainer)"); +static_assert(sizeof(eastl::vector_multiset) == sizeof(eastl::vector), "if is_empty_v, sizeof(vector_multiset) == sizeof(RandomAccessContainer)"); + /////////////////////////////////////////////////////////////////////////////// // typedefs @@ -132,25 +137,41 @@ int TestVectorSet() } } - { // find_as predicate + { // find / find_as / lower_bound / upper_bound { // vector_set eastl::vector_set vss = {"abc", "def", "ghi", "jklmnop", "qrstu", "vw", "x", "yz"}; + VERIFY(vss.find("ghi") != vss.end()); + VERIFY(vss.find("GHI") == vss.end()); VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end()); + VERIFY(vss.lower_bound("ghi") != vss.end()); + VERIFY(vss.upper_bound("ghi") != vss.end()); } { // const vector_set const eastl::vector_set vss = {"abc", "def", "ghi", "jklmnop", "qrstu", "vw", "x", "yz"}; + VERIFY(vss.find("ghi") != vss.end()); + VERIFY(vss.find("GHI") == vss.end()); VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end()); + VERIFY(vss.lower_bound("ghi") != vss.end()); + VERIFY(vss.upper_bound("ghi") != vss.end()); } { // vector_multiset eastl::vector_multiset vss = {"abc", "def", "ghi", "jklmnop", "qrstu", "vw", "x", "yz"}; + VERIFY(vss.find("ghi") != vss.end()); + VERIFY(vss.find("GHI") == vss.end()); VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end()); + VERIFY(vss.lower_bound("ghi") != vss.end()); + VERIFY(vss.upper_bound("ghi") != vss.end()); } { // const vector_multiset const eastl::vector_multiset vss = {"abc", "def", "ghi", "jklmnop", "qrstu", "vw", "x", "yz"}; + VERIFY(vss.find("ghi") != vss.end()); + VERIFY(vss.find("GHI") == vss.end()); VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end()); + VERIFY(vss.lower_bound("ghi") != vss.end()); + VERIFY(vss.upper_bound("ghi") != vss.end()); } } diff --git a/test/source/main.cpp b/test/source/main.cpp index 132bab18..e67b14cb 100644 --- a/test/source/main.cpp +++ b/test/source/main.cpp @@ -148,6 +148,7 @@ int EAMain(int argc, char* argv[]) testSuite.AddTest("Bitcast", TestBitcast); + nErrorCount += testSuite.Run(); nErrorCount += EASTLTest_CheckMemory();