diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2025-06-25 12:39:04 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2025-06-25 12:39:04 +0200 |
commit | d9ed004d0928567ab822d2b96862c33454e2e1c7 (patch) | |
tree | 5c4a0afb789249947145e0d1fe3eceae0cea6091 /EASTL/test | |
parent | 2083c3d97ed2946fd8168b02a2ec3f8e585ecb48 (diff) | |
parent | da5ddb55fd888d6d5ef185acdb054deac335717b (diff) |
Diffstat (limited to 'EASTL/test')
31 files changed, 2567 insertions, 150 deletions
diff --git a/EASTL/test/CMakeLists.txt b/EASTL/test/CMakeLists.txt index 3fac51f..ff16189 100644 --- a/EASTL/test/CMakeLists.txt +++ b/EASTL/test/CMakeLists.txt @@ -17,6 +17,9 @@ add_definitions(-D_SCL_SECURE_NO_WARNINGS) add_definitions(-DEASTL_OPENSOURCE=1) add_definitions(-D_CHAR16T) add_definitions(-DEASTL_THREAD_SUPPORT_AVAILABLE=0) +if (EASTL_STD_ITERATOR_CATEGORY_ENABLED) + add_definitions(-DEASTL_STD_ITERATOR_CATEGORY_ENABLED=1) +endif() #------------------------------------------------------------------------------------------- # Compiler Flags diff --git a/EASTL/test/source/EASTLTest.h b/EASTL/test/source/EASTLTest.h index 1908f5f..fca6b2c 100644 --- a/EASTL/test/source/EASTLTest.h +++ b/EASTL/test/source/EASTLTest.h @@ -1261,6 +1261,8 @@ public: activeAllocatedMemory = 0; } + virtual ~CountingAllocator() = default; + static uint64_t activeAllocCount; static uint64_t totalAllocCount; static uint64_t totalDeallocCount; diff --git a/EASTL/test/source/TestAlgorithm.cpp b/EASTL/test/source/TestAlgorithm.cpp index 142d45e..a0f64da 100644 --- a/EASTL/test/source/TestAlgorithm.cpp +++ b/EASTL/test/source/TestAlgorithm.cpp @@ -1509,6 +1509,82 @@ int TestAlgorithm() EATEST_VERIFY( b); } +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + // <compairison_category> lexicographical_compare_three_way(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, Compare compare) + + int intArray1[6] = {0, 1, 2, 3, 4, 5}; + int intArray2[6] = {0, 1, 2, 3, 4, 6}; + int intArray3[5] = {0, 1, 2, 3, 4}; + int intArray4[5] = {4, 3, 2, 1, 0}; + + // strong ordering + auto compare_strong = [](int first, int second) + { + return (first < second) ? std::strong_ordering::less : + (first > second) ? std::strong_ordering::greater : + std::strong_ordering::equal; + }; + + auto b = lexicographical_compare_three_way(intArray1, intArray1 + 6, intArray2, intArray2 + 6, compare_strong); + EATEST_VERIFY(b == std::strong_ordering::less); + b = lexicographical_compare_three_way(intArray3, intArray3 + 5, intArray2, intArray2 + 6, compare_strong); + EATEST_VERIFY(b == std::strong_ordering::less); + b = lexicographical_compare_three_way(intArray3, intArray3 + 5, intArray2, intArray2 + 6, synth_three_way{}); + EATEST_VERIFY(b == std::strong_ordering::less); + + b = lexicographical_compare_three_way(intArray2, intArray2 + 6, intArray1, intArray1 + 6, compare_strong); + EATEST_VERIFY(b == std::strong_ordering::greater); + b = lexicographical_compare_three_way(intArray2, intArray2 + 6, intArray1, intArray1 + 6, synth_three_way{}); + EATEST_VERIFY(b == std::strong_ordering::greater); + + b = lexicographical_compare_three_way(intArray1, intArray1 + 6, intArray3, intArray3 + 5, compare_strong); + EATEST_VERIFY(b == std::strong_ordering::greater); + b = lexicographical_compare_three_way(intArray1, intArray1 + 6, intArray3, intArray3 + 5, synth_three_way{}); + EATEST_VERIFY(b == std::strong_ordering::greater); + + b = lexicographical_compare_three_way(intArray1, intArray1, intArray2, intArray2, compare_strong); // Test empty range. + EATEST_VERIFY(b == std::strong_ordering::equal); + b = lexicographical_compare_three_way(intArray1, intArray1, intArray2, intArray2, synth_three_way{}); // Test empty range. + EATEST_VERIFY(b == std::strong_ordering::equal); + + // weak ordering + auto compare_weak = [](int first, int second) + { + return (first < second) ? std::weak_ordering::less : + (first > second) ? std::weak_ordering::greater : + std::weak_ordering::equivalent; + }; + + auto c = lexicographical_compare_three_way(intArray3, intArray3 + 5, intArray4, intArray4 + 5, compare_weak); + EATEST_VERIFY(c == std::weak_ordering::less); + c = lexicographical_compare_three_way(intArray4, intArray4 + 5, intArray3, intArray3 + 5, compare_weak); + EATEST_VERIFY(c == std::weak_ordering::greater); + c = lexicographical_compare_three_way(intArray3, intArray3 + 5, intArray4, intArray4 + 5, synth_three_way{}); + EATEST_VERIFY(c == std::weak_ordering::less); + c = lexicographical_compare_three_way(intArray4, intArray4 + 5, intArray3, intArray3 + 5, synth_three_way{}); + EATEST_VERIFY(c == std::weak_ordering::greater); + } + + { + EATEST_VERIFY(synth_three_way{}(1, 1) == std::strong_ordering::equal); + EATEST_VERIFY(synth_three_way{}(2, 1) == std::strong_ordering::greater); + EATEST_VERIFY(synth_three_way{}(1, 2) == std::strong_ordering::less); + + struct weak_struct + { + int val; + inline std::weak_ordering operator<=>(const weak_struct& b) const + { + return val <=> b.val; + } + }; + + EATEST_VERIFY(synth_three_way{}(weak_struct{1}, weak_struct{2}) == std::weak_ordering::less); + EATEST_VERIFY(synth_three_way{}(weak_struct{2}, weak_struct{1}) == std::weak_ordering::greater); + EATEST_VERIFY(synth_three_way{}(weak_struct{1}, weak_struct{1}) == std::weak_ordering::equivalent); + } +#endif { // ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value) @@ -1815,7 +1891,164 @@ int TestAlgorithm() } - { + { + // ForwardIterator apply_and_remove(ForwardIterator first, ForwardIterator last, Function function, const T& + // value) ForwardIterator apply_and_remove_if(ForwardIterator first, ForwardIterator last, Function function, + // Predicate predicate) + + // Test for empty range and full container range + { + int intArray[12] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + int* pInt = apply_and_remove(intArray, intArray, func, 1); + EATEST_VERIFY(pInt == intArray); + EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove", 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", -1)); + pInt = apply_and_remove(intArray, intArray + 12, func, 1); + EATEST_VERIFY(pInt == intArray + 6); + EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "apply_and_remove", 0, 0, 0, 0, 0, 0, -1)); + EATEST_VERIFY( + VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", 1, 1, 1, 1, 1, 1, -1)); + } + + // Test for no match on empty range and full container range + { + int intArray[12] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + int* pInt = apply_and_remove(intArray, intArray, func, 1); + EATEST_VERIFY(pInt == intArray); + EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove", 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", -1)); + pInt = apply_and_remove(intArray, intArray + 12, func, 1); + EATEST_VERIFY(pInt == intArray + 12); + EATEST_VERIFY(VerifySequence(intArray, intArray + 12, int(), "apply_and_remove", 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", -1)); + } + + // Test for empty range and full container range + { + int intArray[12] = {0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + int* pInt = apply_and_remove_if(intArray, intArray, func, bind2nd(equal_to<int>(), (int)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>(), (int)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( + VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", 1, 1, 1, 1, 1, 1, -1)); + } + + // Test for no match on empty range and full container range + { + int intArray[12] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + int* pInt = apply_and_remove_if(intArray, intArray, func, bind2nd(equal_to<int>(), (int)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>(), (int)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)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", -1)); + } + + auto even = [](int a) { return (a % 2) == 0; }; + // Test to verify that the remaining element have stable ordering + { + int intArray[12] = {7, 8, 2, 3, 4, 5, 6, 0, 1, 9, 10, 11}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + int* pInt = apply_and_remove_if(intArray, intArray + 12, func, even); + EATEST_VERIFY(pInt == intArray + 6); + EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "apply_and_remove_if", 7, 3, 5, 1, 9, 11, -1)); + EATEST_VERIFY( + VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", 8, 2, 4, 6, 0, 10, -1)); + } + { + int intArray[12] = {7, 8, 0, 0, 4, 5, 6, 0, 1, 9, 0, 11}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + int* pInt = apply_and_remove(intArray, intArray + 12, func, 0); + EATEST_VERIFY(pInt == intArray + 8); + EATEST_VERIFY( + VerifySequence(intArray, intArray + 8, int(), "apply_and_remove", 7, 8, 4, 5, 6, 1, 9, 11, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", 0, 0, 0, 0, -1)); + } + + // Tests on a list (i.e. non-contiguous memory container) + { + list<int> intList = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + auto listIter = apply_and_remove_if(intList.begin(), intList.begin(), func, even); + EATEST_VERIFY(listIter == intList.begin()); + EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "apply_and_remove_if", 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", -1)); + listIter = apply_and_remove_if(intList.begin(), intList.end(), func, even); + EATEST_VERIFY(listIter == next(intList.begin(), 6)); + EATEST_VERIFY( + VerifySequence(intList.begin(), listIter, int(), "apply_and_remove_if", 1, 3, 5, 7, 9, 11, -1)); + EATEST_VERIFY( + VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", 0, 2, 4, 6, 8, 10, -1)); + } + { + list<int> intList = {0, 4, 2, 3, 4, 5, 6, 4, 4, 4, 10, 11}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + auto listIter = apply_and_remove(intList.begin(), intList.begin(), func, 4); + EATEST_VERIFY(listIter == intList.begin()); + EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "apply_and_remove", 0, 4, 2, 3, 4, 5, 6, + 4, 4, 4, 10, 11, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", -1)); + listIter = apply_and_remove(intList.begin(), intList.end(), func, 4); + EATEST_VERIFY(listIter == next(intList.begin(), 7)); + EATEST_VERIFY( + VerifySequence(intList.begin(), listIter, int(), "apply_and_remove", 0, 2, 3, 5, 6, 10, 11, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", 4, 4, 4, 4, 4, -1)); + } + + // Tests on a part of a container + { + vector<int> intVector = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + auto vectorIter = apply_and_remove_if(next(intVector.begin(), 3), prev(intVector.end(), 2), func, even); + EATEST_VERIFY(vectorIter == next(intVector.begin(), 7)); + EATEST_VERIFY( + VerifySequence(intVector.begin(), vectorIter, int(), "apply_and_remove_if", 0, 1, 2, 3, 5, 7, 9, -1)); + EATEST_VERIFY( + VerifySequence(prev(intVector.end(), 2), intVector.end(), int(), "apply_and_remove_if", 10, 11, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove_if", 4, 6, 8, -1)); + } + { + vector<int> intVector = {5, 1, 5, 3, 4, 5, 5, 7, 8, 5, 10, 5}; + vector<int> output; + auto func = [&output](int a) { output.push_back(a); }; + auto vectorIter = apply_and_remove(next(intVector.begin(), 2), prev(intVector.end(), 3), func, 5); + EATEST_VERIFY(vectorIter == next(intVector.begin(), 6)); + EATEST_VERIFY( + VerifySequence(intVector.begin(), vectorIter, int(), "apply_and_remove", 5, 1, 3, 4, 7, 8, -1)); + EATEST_VERIFY( + VerifySequence(prev(intVector.end(), 3), intVector.end(), int(), "apply_and_remove", 5, 10, 5, -1)); + EATEST_VERIFY(VerifySequence(output.begin(), output.end(), int(), "apply_and_remove", 5, 5, 5, -1)); + } + } + + + { // OutputIterator replace_copy(InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value) // OutputIterator replace_copy_if(InputIterator first, InputIterator last, OutputIterator result, Predicate predicate, const T& new_value) diff --git a/EASTL/test/source/TestAllocator.cpp b/EASTL/test/source/TestAllocator.cpp index 85f5adf..2a28c07 100644 --- a/EASTL/test/source/TestAllocator.cpp +++ b/EASTL/test/source/TestAllocator.cpp @@ -151,6 +151,8 @@ static int TestFixedAllocator() { EATEST_VERIFY(buffer1[i].mValue == TEST_VALUE); } + + intList1.clear(); } { // fixed_allocator_with_overflow diff --git a/EASTL/test/source/TestArray.cpp b/EASTL/test/source/TestArray.cpp index 3db95b9..ca05b67 100644 --- a/EASTL/test/source/TestArray.cpp +++ b/EASTL/test/source/TestArray.cpp @@ -125,6 +125,22 @@ int TestArray() VERIFY(!(a >= c)); VERIFY(!(a > c)); +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + VERIFY( (a <=> b) == 0); + VERIFY(!((a <=> b) != 0)); + VERIFY(!((a <=> b) < 0)); + VERIFY( (a <=> b) <= 0); + VERIFY( (a <=> b) >= 0); + VERIFY(!((a <=> b) > 0)); + + VERIFY(!((a <=> c) == 0)); + VERIFY( (a <=> c) != 0); + VERIFY( (a <=> c) < 0); + VERIFY( (a <=> c) <= 0); + VERIFY(!((a <=> c) >= 0)); + VERIFY(!((a <=> c) > 0)); +#endif + // deduction guides #ifdef __cpp_deduction_guides array deduced {1,2,3,4,5}; @@ -132,6 +148,37 @@ int TestArray() static_assert(eastl::is_same_v<decltype(deduced)::value_type, int>, "deduced array value_type mismatch"); VERIFY(deduced.size() == 5); #endif + + // structured binding + + { + eastl::array<int, 5> 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]); + VERIFY(a4 == aCopy[4]); + + a0 = 100; + VERIFY(aCopy[0] == 100); + + a4 = 0; + VERIFY(aCopy[4] == 0); + + // The deduced type may or may not be a reference type; it is an aliased type, + // as per https://en.cppreference.com/w/cpp/language/structured_binding: + // > Like a reference, a structured binding is an alias to an existing object. Unlike a reference, + // the type of a structured binding does not have to be a reference type. + // Any reference specifier is thus removed to check only the type & its const qualifier + static_assert(eastl::is_same_v<eastl::remove_reference_t<decltype(a0)>, int>); + + const eastl::array<int, 5> aConstCopy = a; + auto&& [aConst0, aConst1, aConst2, aConst3, aConst4] = aConstCopy; + + static_assert(eastl::is_same_v<eastl::remove_reference_t<decltype(aConst0)>, const int>); + } } // constexpr tests diff --git a/EASTL/test/source/TestChrono.cpp b/EASTL/test/source/TestChrono.cpp index 6a698e9..a56b934 100644 --- a/EASTL/test/source/TestChrono.cpp +++ b/EASTL/test/source/TestChrono.cpp @@ -89,12 +89,15 @@ int TestDuration() microseconds us = 2 * ms; // 6000 microseconds constructed from 3 milliseconds VERIFY(us.count() == 6000); + + microseconds us2 = ms * 2; // 6000 microseconds constructed from 3 milliseconds + VERIFY(us2.count() == 6000); - microseconds us2 = us / 2; - VERIFY(us2.count() == 3000); + microseconds us3 = us / 2; + VERIFY(us3.count() == 3000); - microseconds us3 = us % 2; - VERIFY(us3.count() == 0); + microseconds us4 = us % 2; + VERIFY(us4.count() == 0); } } diff --git a/EASTL/test/source/TestDeque.cpp b/EASTL/test/source/TestDeque.cpp index 99076ff..e3f4ab6 100644 --- a/EASTL/test/source/TestDeque.cpp +++ b/EASTL/test/source/TestDeque.cpp @@ -1063,29 +1063,61 @@ int TestDeque() { eastl::deque<int> d = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - eastl::erase(d, 2); + auto numErased = eastl::erase(d, 2); VERIFY((d == eastl::deque<int>{1, 3, 4, 5, 6, 7, 8, 9})); + VERIFY(numErased == 1); - eastl::erase(d, 7); + numErased = eastl::erase(d, 7); VERIFY((d == eastl::deque<int>{1, 3, 4, 5, 6, 8, 9})); + VERIFY(numErased == 1); - eastl::erase(d, 9); + numErased = eastl::erase(d, 9); VERIFY((d == eastl::deque<int>{1, 3, 4, 5, 6, 8})); + VERIFY(numErased == 1); - eastl::erase(d, 5); + numErased = eastl::erase(d, 5); VERIFY((d == eastl::deque<int>{1, 3, 4, 6, 8})); + VERIFY(numErased == 1); - eastl::erase(d, 3); + numErased = eastl::erase(d, 3); VERIFY((d == eastl::deque<int>{1, 4, 6, 8})); + VERIFY(numErased == 1); } { eastl::deque<int> d = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - eastl::erase_if(d, [](auto i) { return i % 2 == 0; }); + auto numErased = eastl::erase_if(d, [](auto i) { return i % 2 == 0; }); VERIFY((d == eastl::deque<int>{1, 3, 5, 7, 9})); + VERIFY(numErased == 4); } } +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + + { // Test <=> + eastl::deque<int> d1 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + eastl::deque<int> d2 = {9, 8, 7, 6, 5, 4, 3, 2, 1}; + eastl::deque<int> d3 = {1, 2, 3, 4, 5}; + eastl::deque<int> 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); + } +#endif + return nErrorCount; } diff --git a/EASTL/test/source/TestExtra.cpp b/EASTL/test/source/TestExtra.cpp index 03f7b41..52fbd62 100644 --- a/EASTL/test/source/TestExtra.cpp +++ b/EASTL/test/source/TestExtra.cpp @@ -66,6 +66,7 @@ namespace eastl #include <EASTL/string.h> #include <EASTL/hash_set.h> #include <EASTL/random.h> +#include <EASTL/bit.h> #include <EASTL/core_allocator_adapter.h> #include <EASTL/bonus/call_traits.h> #include <EASTL/bonus/compressed_pair.h> @@ -292,7 +293,6 @@ static int TestQueue() EATEST_VERIFY(!(toListQueue < toListQueue2)); EATEST_VERIFY(!(toListQueue > toListQueue2)); - // bool empty() const; // size_type size() const; EATEST_VERIFY(toListQueue.empty()); @@ -356,6 +356,103 @@ static int TestQueue() EATEST_VERIFY(intQueue.front() == 5); } +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + // queue(const Sequence& x = Sequence()); + queue<TestObject, list<TestObject>> toListQueue; + queue<TestObject, list<TestObject>> toListQueue2; + + + // global operators + EATEST_VERIFY( ((toListQueue <=> toListQueue2) == 0)); + EATEST_VERIFY(!((toListQueue <=> toListQueue2) != 0)); + EATEST_VERIFY( ((toListQueue <=> toListQueue2) <= 0)); + EATEST_VERIFY( ((toListQueue <=> toListQueue2) >= 0)); + EATEST_VERIFY(!((toListQueue <=> toListQueue2) < 0)); + EATEST_VERIFY(!((toListQueue <=> toListQueue2) > 0)); + + // bool empty() const; + // size_type size() const; + EATEST_VERIFY(toListQueue.empty()); + EATEST_VERIFY(toListQueue.size() == 0); + + // Verify toListQueue > toListQueue2 + toListQueue.push(TestObject(0)); + toListQueue.push(TestObject(1)); + toListQueue2.push(TestObject(0)); + + EATEST_VERIFY(!((toListQueue <=> toListQueue2) == 0)); + EATEST_VERIFY( ((toListQueue <=> toListQueue2) != 0)); + EATEST_VERIFY( ((toListQueue <=> toListQueue2) >= 0)); + EATEST_VERIFY(!((toListQueue <=> toListQueue2) <= 0)); + EATEST_VERIFY( ((toListQueue <=> toListQueue2) > 0)); + EATEST_VERIFY(!((toListQueue <=> toListQueue2) < 0)); + + // Verify toListQueue2 > toListQueue by element size + toListQueue2.push(TestObject(3)); + EATEST_VERIFY(!((toListQueue <=> toListQueue2) == 0)); + EATEST_VERIFY( ((toListQueue <=> toListQueue2) != 0)); + EATEST_VERIFY( ((toListQueue <=> toListQueue2) <= 0)); + EATEST_VERIFY(!((toListQueue <=> toListQueue2) >= 0)); + EATEST_VERIFY( ((toListQueue <=> toListQueue2) < 0)); + EATEST_VERIFY(!((toListQueue <=> toListQueue2) > 0)); + + queue<TestObject, list<TestObject>> toListQueue3; + queue<TestObject, list<TestObject>> toListQueue4; + + for (int i = 0; i < 10; i++) + { + toListQueue3.push(TestObject(i)); + if (i < 5) + toListQueue4.push(TestObject(i)); + } + + // Verify toListQueue4 is a strict subset of toListQueue3 + EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) == 0)); + EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) != 0)); + EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) >= 0)); + EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) <= 0)); + EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) > 0)); + EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) < 0)); + + // Verify that even thoughn toListQueue4 has a smaller size, it's lexicographically larger + toListQueue4.push(TestObject(11)); + EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) == 0)); + EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) != 0)); + EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) <= 0)); + EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) >= 0)); + EATEST_VERIFY( ((toListQueue3 <=> toListQueue4) < 0)); + EATEST_VERIFY(!((toListQueue3 <=> toListQueue4) > 0)); + + } + + { + queue<TestObject, list<TestObject>> toListQueue1; + queue<TestObject, list<TestObject>> toListQueue2; + queue<TestObject, list<TestObject>> toListQueue3; + + for (int i = 0; i < 10; i++) + { + toListQueue1.push(TestObject(i)); + toListQueue2.push(TestObject(9-i)); + if (i < 5) + toListQueue3.push(TestObject(i)); + } + + struct weak_ordering_queue + { + queue<TestObject, list<TestObject>> queue; + inline std::weak_ordering operator<=>(const weak_ordering_queue& b) const { return queue <=> b.queue; } + }; + + EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue1}, weak_ordering_queue{toListQueue2}) == std::weak_ordering::less); + EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue3}, weak_ordering_queue{toListQueue1}) == std::weak_ordering::less); + EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue2}, weak_ordering_queue{toListQueue1}) == std::weak_ordering::greater); + EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue2}, weak_ordering_queue{toListQueue3}) == std::weak_ordering::greater); + EATEST_VERIFY(synth_three_way{}(weak_ordering_queue{toListQueue1}, weak_ordering_queue{toListQueue1}) == std::weak_ordering::equivalent); + } + #endif + { vector<TestObject> toVector; for(int i = 0; i < 100; i++) @@ -620,7 +717,6 @@ static int TestStack() EATEST_VERIFY(!(toListStack < toListStack2)); EATEST_VERIFY(!(toListStack > toListStack2)); - // void push(const value_type& value); // reference top(); // const_reference top() const; @@ -665,6 +761,101 @@ static int TestStack() #endif } +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + // stack(const Sequence& x = Sequence()); + stack<TestObject, list<TestObject> > toListStack; + stack<TestObject, list<TestObject> > toListStack2; + + // bool empty() const; + // size_type size() const; + EATEST_VERIFY(toListStack.empty()); + EATEST_VERIFY(toListStack.size() == 0); + + + // global operators + EATEST_VERIFY( ((toListStack <=> toListStack2) == 0)); + EATEST_VERIFY(!((toListStack <=> toListStack2) != 0)); + EATEST_VERIFY( ((toListStack <=> toListStack2) <= 0)); + EATEST_VERIFY( ((toListStack <=> toListStack2) >= 0)); + EATEST_VERIFY(!((toListStack <=> toListStack2) < 0)); + EATEST_VERIFY(!((toListStack <=> toListStack2) > 0)); + + toListStack.push(TestObject(0)); + toListStack.push(TestObject(1)); + toListStack2.push(TestObject(0)); + + EATEST_VERIFY(!((toListStack <=> toListStack2) == 0)); + EATEST_VERIFY( ((toListStack <=> toListStack2) != 0)); + EATEST_VERIFY( ((toListStack <=> toListStack2) >= 0)); + EATEST_VERIFY(!((toListStack <=> toListStack2) <= 0)); + EATEST_VERIFY( ((toListStack <=> toListStack2) > 0)); + EATEST_VERIFY(!((toListStack <=> toListStack2) < 0)); + + // Verify toListStack2 > toListStack by element size + toListStack2.push(TestObject(3)); + EATEST_VERIFY(!((toListStack <=> toListStack2) == 0)); + EATEST_VERIFY( ((toListStack <=> toListStack2) != 0)); + EATEST_VERIFY( ((toListStack <=> toListStack2) <= 0)); + EATEST_VERIFY(!((toListStack <=> toListStack2) >= 0)); + EATEST_VERIFY( ((toListStack <=> toListStack2) < 0)); + EATEST_VERIFY(!((toListStack <=> toListStack2) > 0)); + + stack<TestObject, list<TestObject> > toListStack3; + stack<TestObject, list<TestObject> > toListStack4; + + for (int i = 0; i < 10; i++) + { + toListStack3.push(TestObject(i)); + if (i < 5) + toListStack4.push(TestObject(i)); + } + + // Verify toListStack4 is a strict subset of toListStack3 + EATEST_VERIFY(!((toListStack3 <=> toListStack4) == 0)); + EATEST_VERIFY( ((toListStack3 <=> toListStack4) != 0)); + EATEST_VERIFY( ((toListStack3 <=> toListStack4) >= 0)); + EATEST_VERIFY(!((toListStack3 <=> toListStack4) <= 0)); + EATEST_VERIFY( ((toListStack3 <=> toListStack4) > 0)); + EATEST_VERIFY(!((toListStack3 <=> toListStack4) < 0)); + + // Verify that even thoughn toListQueue4 has a smaller size, it's lexicographically larger + toListStack4.push(TestObject(11)); + EATEST_VERIFY(!((toListStack3 <=> toListStack4) == 0)); + EATEST_VERIFY( ((toListStack3 <=> toListStack4) != 0)); + EATEST_VERIFY( ((toListStack3 <=> toListStack4) <= 0)); + EATEST_VERIFY(!((toListStack3 <=> toListStack4) >= 0)); + EATEST_VERIFY( ((toListStack3 <=> toListStack4) < 0)); + EATEST_VERIFY(!((toListStack3 <=> toListStack4) > 0)); + } + + { + stack<TestObject, list<TestObject> > toListStack1; + stack<TestObject, list<TestObject> > toListStack2; + stack<TestObject, list<TestObject> > toListStack3; + + for (int i = 0; i < 10; i++) + { + toListStack1.push(TestObject(i)); + toListStack2.push(TestObject(9-i)); + if (i < 5) + toListStack3.push(TestObject(i)); + } + + struct weak_ordering_stack + { + stack<TestObject, list<TestObject> > stack; + inline std::weak_ordering operator<=>(const weak_ordering_stack& b) const { return stack <=> b.stack; } + }; + + EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack1}, weak_ordering_stack{toListStack2}) == std::weak_ordering::less); + EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack3}, weak_ordering_stack{toListStack1}) == std::weak_ordering::less); + EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack2}, weak_ordering_stack{toListStack1}) == std::weak_ordering::greater); + EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack2}, weak_ordering_stack{toListStack3}) == std::weak_ordering::greater); + EATEST_VERIFY(synth_three_way{}(weak_ordering_stack{toListStack1}, weak_ordering_stack{toListStack1}) == std::weak_ordering::equivalent); + } +#endif + { vector<TestObject> toVector; @@ -862,6 +1053,281 @@ static int TestNumeric() return nErrorCount; } +#if defined(EA_COMPILER_CPP20_ENABLED) +template <typename T> +static constexpr int SignedIntMidpoint() +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::midpoint(T(0), T(0)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(0), T(2)) == T(1)); + EATEST_VERIFY(eastl::midpoint(T(0), T(4)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(0), T(8)) == T(4)); + EATEST_VERIFY(eastl::midpoint(T(2), T(0)) == T(1)); + EATEST_VERIFY(eastl::midpoint(T(4), T(0)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(8), T(0)) == T(4)); + + EATEST_VERIFY(eastl::midpoint(T(1), T(1)) == T(1)); + EATEST_VERIFY(eastl::midpoint(T(1), T(3)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(3), T(1)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(2), T(6)) == T(4)); + EATEST_VERIFY(eastl::midpoint(T(6), T(2)) == T(4)); + + EATEST_VERIFY(eastl::midpoint(T(-1), T(-1)) == T(-1)); + EATEST_VERIFY(eastl::midpoint(T(-1), T(-3)) == T(-2)); + EATEST_VERIFY(eastl::midpoint(T(-3), T(-1)) == T(-2)); + EATEST_VERIFY(eastl::midpoint(T(-2), T(-6)) == T(-4)); + EATEST_VERIFY(eastl::midpoint(T(-6), T(-2)) == T(-4)); + + EATEST_VERIFY(eastl::midpoint(T(-0), T(0)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(0), T(-0)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(-0), T(-0)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(-1), T(1)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(-10), T(10)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(-3), T(7)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(-7), T(3)) == T(-2)); + EATEST_VERIFY(eastl::midpoint(T(-2), T(6)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(-6), T(2)) == T(-2)); + EATEST_VERIFY(eastl::midpoint(T(2), T(-6)) == T(-2)); + EATEST_VERIFY(eastl::midpoint(T(6), T(-2)) == T(2)); + + // If an odd sum, midpoint should round towards the LHS operand. + EATEST_VERIFY(eastl::midpoint(T(0), T(5)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(5), T(0)) == T(3)); + EATEST_VERIFY(eastl::midpoint(T(1), T(4)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(4), T(1)) == T(3)); + EATEST_VERIFY(eastl::midpoint(T(7), T(10)) == T(8)); + EATEST_VERIFY(eastl::midpoint(T(10), T(7)) == T(9)); + EATEST_VERIFY(eastl::midpoint(T(-1), T(2)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(2), T(-1)) == T(1)); + EATEST_VERIFY(eastl::midpoint(T(-5), T(4)) == T(-1)); + EATEST_VERIFY(eastl::midpoint(T(4), T(-5)) == T(0)); + + // Test absolute limits + constexpr T MIN = eastl::numeric_limits<T>::min(); + constexpr T MAX = eastl::numeric_limits<T>::max(); + + EATEST_VERIFY(eastl::midpoint(MIN, MIN) == MIN); + EATEST_VERIFY(eastl::midpoint(MAX, MAX) == MAX); + EATEST_VERIFY(eastl::midpoint(MIN, MAX) == T(-1)); + EATEST_VERIFY(eastl::midpoint(MAX, MIN) == T(0)); + EATEST_VERIFY(eastl::midpoint(MIN, T(0)) == MIN / 2); + EATEST_VERIFY(eastl::midpoint(T(0), MIN) == MIN / 2); + EATEST_VERIFY(eastl::midpoint(MAX, T(0)) == (MAX / 2) + 1); + EATEST_VERIFY(eastl::midpoint(T(0), MAX) == (MAX / 2)); + + EATEST_VERIFY(eastl::midpoint(MIN, T(10)) == (MIN / 2) + 5); + EATEST_VERIFY(eastl::midpoint(T(10), MIN) == (MIN / 2) + 5); + EATEST_VERIFY(eastl::midpoint(MAX, T(10)) == (MAX / 2) + 5 + 1); + EATEST_VERIFY(eastl::midpoint(T(10), MAX) == (MAX / 2) + 5); + EATEST_VERIFY(eastl::midpoint(MIN, T(-10)) == (MIN / 2) - 5); + EATEST_VERIFY(eastl::midpoint(T(-10), MIN) == (MIN / 2) - 5); + EATEST_VERIFY(eastl::midpoint(MAX, T(-10)) == (MAX / 2) - 5 + 1); + EATEST_VERIFY(eastl::midpoint(T(-10), MAX) == (MAX / 2) - 5); + + return nErrorCount; +} + +template <typename T> +static constexpr int UnsignedIntMidpoint() +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::midpoint(T(0), T(0)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(0), T(2)) == T(1)); + EATEST_VERIFY(eastl::midpoint(T(0), T(4)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(0), T(8)) == T(4)); + EATEST_VERIFY(eastl::midpoint(T(2), T(0)) == T(1)); + EATEST_VERIFY(eastl::midpoint(T(4), T(0)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(8), T(0)) == T(4)); + + EATEST_VERIFY(eastl::midpoint(T(1), T(1)) == T(1)); + EATEST_VERIFY(eastl::midpoint(T(1), T(3)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(3), T(1)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(2), T(6)) == T(4)); + EATEST_VERIFY(eastl::midpoint(T(6), T(2)) == T(4)); + + // If an odd sum, midpoint should round towards the LHS operand. + EATEST_VERIFY(eastl::midpoint(T(0), T(5)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(5), T(0)) == T(3)); + EATEST_VERIFY(eastl::midpoint(T(1), T(4)) == T(2)); + EATEST_VERIFY(eastl::midpoint(T(4), T(1)) == T(3)); + EATEST_VERIFY(eastl::midpoint(T(7), T(10)) == T(8)); + EATEST_VERIFY(eastl::midpoint(T(10), T(7)) == T(9)); + + // Test absolute limits + constexpr T MIN = eastl::numeric_limits<T>::min(); + constexpr T MAX = eastl::numeric_limits<T>::max(); + + EATEST_VERIFY(eastl::midpoint(MIN, MIN) == MIN); + EATEST_VERIFY(eastl::midpoint(MAX, MAX) == MAX); + EATEST_VERIFY(eastl::midpoint(MIN, MAX) == MAX / 2); + EATEST_VERIFY(eastl::midpoint(MAX, MIN) == (MAX / 2) + 1); + EATEST_VERIFY(eastl::midpoint(MIN, T(0)) == T(0)); + EATEST_VERIFY(eastl::midpoint(T(0), MIN) == T(0)); + + EATEST_VERIFY(eastl::midpoint(MIN, T(10)) == (MIN / 2) + 5); + EATEST_VERIFY(eastl::midpoint(T(10), MIN) == (MIN / 2) + 5); + EATEST_VERIFY(eastl::midpoint(MAX, T(10)) == (MAX / 2) + 5 + 1); + EATEST_VERIFY(eastl::midpoint(T(10), MAX) == (MAX / 2) + 5); + + return nErrorCount; +} + +template <typename T> +static constexpr int FloatMidpoint() +{ + // for use with floats, double, long doubles. + int nErrorCount = 0; + EATEST_VERIFY(eastl::midpoint(T(0.0), T(0.0)) == T(0.0)); + EATEST_VERIFY(eastl::midpoint(T(0.0), T(2.0)) == T(1.0)); + EATEST_VERIFY(eastl::midpoint(T(0.0), T(4.0)) == T(2.0)); + EATEST_VERIFY(eastl::midpoint(T(2.0), T(0.0)) == T(1.0)); + EATEST_VERIFY(eastl::midpoint(T(4.0), T(0.0)) == T(2.0)); + + EATEST_VERIFY(eastl::midpoint(T(0.5), T(0.5)) == T(0.5)); + EATEST_VERIFY(eastl::midpoint(T(0.0), T(0.5)) == T(0.25)); + EATEST_VERIFY(eastl::midpoint(T(0.5), T(0.0)) == T(0.25)); + EATEST_VERIFY(eastl::midpoint(T(0.5), T(1.0)) == T(0.75)); + EATEST_VERIFY(eastl::midpoint(T(1.0), T(0.5)) == T(0.75)); + + EATEST_VERIFY(eastl::midpoint(T(-0.0), T(0.0)) == T(0.0)); + EATEST_VERIFY(eastl::midpoint(T(0.0), T(-0.0)) == T(0.0)); + EATEST_VERIFY(eastl::midpoint(T(-0.0), T(-0.0)) == T(0.0)); + EATEST_VERIFY(eastl::midpoint(T(-1.0), T(2.0)) == T(0.5)); + EATEST_VERIFY(eastl::midpoint(T(-2.0), T(1)) == T(-0.5)); + EATEST_VERIFY(eastl::midpoint(T(-3.0), T(6.0)) == T(1.5)); + EATEST_VERIFY(eastl::midpoint(T(-6.0), T(3.0)) == T(-1.5)); + + // Test absolute limits + const T MIN = eastl::numeric_limits<T>::min(); + const T MAX = eastl::numeric_limits<T>::max(); + + EATEST_VERIFY(eastl::midpoint(MIN, MIN) == MIN); + EATEST_VERIFY(eastl::midpoint(MAX, MAX) == MAX); + EATEST_VERIFY(eastl::midpoint(MIN, MAX) == MAX / 2); + EATEST_VERIFY(eastl::midpoint(MAX, MIN) == MAX / 2); + EATEST_VERIFY(eastl::midpoint(-MAX, MIN) == -MAX / 2); + + EATEST_VERIFY(eastl::midpoint(MIN, T(9.0)) == T(4.5)); + EATEST_VERIFY(eastl::midpoint(MIN, T(-9.0)) == T(-4.5)); + EATEST_VERIFY(eastl::midpoint(T(9.0), MIN) == T(4.5)); + EATEST_VERIFY(eastl::midpoint(T(-9.0), MIN) == T(-4.5)); + EATEST_VERIFY(eastl::midpoint(MAX, T(9.0)) == MAX / 2 + T(4.5)); + EATEST_VERIFY(eastl::midpoint(MAX, T(-9.0)) == MAX / 2 - T(4.5)); + EATEST_VERIFY(eastl::midpoint(T(9.0), MAX) == MAX / 2 + T(4.5)); + EATEST_VERIFY(eastl::midpoint(T(-9.0), MAX) == MAX / 2 - T(4.5)); + + return nErrorCount; +} + +template <typename T> +static constexpr int PointerMidpoint() +{ + int nErrorCount = 0; + + const T ARR[100] = {}; + + EATEST_VERIFY(eastl::midpoint(ARR, ARR) == ARR); + EATEST_VERIFY(eastl::midpoint(ARR, ARR + 100) == ARR + 50); + EATEST_VERIFY(eastl::midpoint(ARR + 100, ARR) == ARR + 50); + EATEST_VERIFY(eastl::midpoint(ARR, ARR + 25) == ARR + 12); + EATEST_VERIFY(eastl::midpoint(ARR + 25, ARR) == ARR + 13); + EATEST_VERIFY(eastl::midpoint(ARR, ARR + 13) == ARR + 6); + EATEST_VERIFY(eastl::midpoint(ARR + 13, ARR) == ARR + 7); + EATEST_VERIFY(eastl::midpoint(ARR + 50, ARR + 100) == ARR + 75); + EATEST_VERIFY(eastl::midpoint(ARR + 100, ARR + 50) == ARR + 75); + + return nErrorCount; +} + + +/////////////////////////////////////////////////////////////////////////////// +// TestMidpoint +// +static int TestMidpoint() +{ + int nErrorCount = 0; + + // template <typename T> + // constexpr eastl::enable_if_t<eastl::is_arithmetic_v<T> && !eastl::is_same_v<eastl::remove_cv_t<T>, bool>, T> + // midpoint(const T lhs, const T rhs) EA_NOEXCEPT + nErrorCount += SignedIntMidpoint<int>(); + nErrorCount += SignedIntMidpoint<char>(); + nErrorCount += SignedIntMidpoint<short>(); + nErrorCount += SignedIntMidpoint<long>(); + nErrorCount += SignedIntMidpoint<long long>(); + + nErrorCount += UnsignedIntMidpoint<unsigned int>(); + nErrorCount += UnsignedIntMidpoint<unsigned char>(); + nErrorCount += UnsignedIntMidpoint<unsigned short>(); + nErrorCount += UnsignedIntMidpoint<unsigned long>(); + nErrorCount += UnsignedIntMidpoint<unsigned long long>(); + + nErrorCount += FloatMidpoint<float>(); + nErrorCount += FloatMidpoint<double>(); + nErrorCount += FloatMidpoint<long double>(); + + // template <typename T> + // constexpr eastl::enable_if_t<eastl::is_object_v<T>, const T*> midpoint(const T* lhs, const T* rhs) + nErrorCount += PointerMidpoint<int>(); + nErrorCount += PointerMidpoint<char>(); + nErrorCount += PointerMidpoint<short>(); + nErrorCount += PointerMidpoint<float>(); + nErrorCount += PointerMidpoint<double>(); + nErrorCount += PointerMidpoint<long double>(); + + return nErrorCount; +} + + +template <typename T> +static constexpr int FloatLerp() +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::lerp(T(0.0), T(0.0), T(0.0)) == T(0.0)); + EATEST_VERIFY(eastl::lerp(T(1.0), T(0.0), T(0.0)) == T(1.0)); + EATEST_VERIFY(eastl::lerp(T(-1.0), T(0.0), T(0.0)) == T(-1.0)); + EATEST_VERIFY(eastl::lerp(T(0.0), T(1.0), T(0.0)) == T(0.0)); + EATEST_VERIFY(eastl::lerp(T(0.0), T(-1.0), T(0.0)) == T(0.0)); + EATEST_VERIFY(eastl::lerp(T(-1.0), T(1.0), T(1.0)) == T(1.0)); + EATEST_VERIFY(eastl::lerp(T(1.0), T(-1.0), T(1.0)) == T(-1.0)); + EATEST_VERIFY(eastl::lerp(T(-1.0), T(1.0), T(0.5)) == T(0.0)); + EATEST_VERIFY(eastl::lerp(T(1.0), T(-1.0), T(0.5)) == T(0.0)); + EATEST_VERIFY(eastl::lerp(T(5.0), T(5.0), T(0.5)) == T(5.0)); + EATEST_VERIFY(eastl::lerp(T(-5.0), T(-5.0), T(0.5)) == T(-5.0)); + EATEST_VERIFY(eastl::lerp(T(1.0), T(2.0), T(1.0)) == T(2.0)); + EATEST_VERIFY(eastl::lerp(T(2.0), T(1.0), T(1.0)) == T(1.0)); + EATEST_VERIFY(eastl::lerp(T(1.0), T(2.0), T(1.0)) == T(2.0)); + EATEST_VERIFY(eastl::lerp(T(1.0), T(2.0), T(2.0)) == T(3.0)); + EATEST_VERIFY(eastl::lerp(T(2.0), T(1.0), T(2.0)) == T(0.0)); + EATEST_VERIFY(eastl::lerp(T(1.0), T(-2.0), T(2.0)) == T(-5.0)); + EATEST_VERIFY(eastl::lerp(T(-1.0), T(2.0), T(2.0)) == T(5.0)); + EATEST_VERIFY(eastl::lerp(T(-1.5), T(1.5), T(0.75)) == T(0.75)); + EATEST_VERIFY(eastl::lerp(T(0.125), T(1.75), T(0.25)) == T(0.53125)); + EATEST_VERIFY(eastl::lerp(T(-0.125), T(-1.75), T(0.5)) == T(-0.9375)); + EATEST_VERIFY(eastl::lerp(T(-0.125), T(1.5), T(2.5)) == T(3.9375)); + + return nErrorCount; +} + +/////////////////////////////////////////////////////////////////////////////// +// TestLerp +// +static int TestLerp() +{ + int nErrorCount = 0; + + // template <class T> + // constexpr T lerp(const T a, const T b, const T t) EA_NOEXCEPT + nErrorCount += FloatLerp<float>(); + nErrorCount += FloatLerp<double>(); + nErrorCount += FloatLerp<long double>(); + + return nErrorCount; +} +#endif /////////////////////////////////////////////////////////////////////////////// @@ -914,7 +1380,142 @@ static int TestAdaptors() return nErrorCount; } +#if defined(EA_COMPILER_CPP20_ENABLED) +template <typename T> +int TestHasSingleBit() +{ + int nErrorCount = 0; + + VERIFY(eastl::has_single_bit(T(0)) == false); + VERIFY(eastl::has_single_bit(T(1)) == true); + VERIFY(eastl::has_single_bit(T(2)) == true); + VERIFY(eastl::has_single_bit(T(3)) == false); + + VERIFY(eastl::has_single_bit(eastl::numeric_limits<T>::min()) == false); + VERIFY(eastl::has_single_bit(eastl::numeric_limits<T>::max()) == false); + for (int i = 4; i < eastl::numeric_limits<T>::digits; i++) + { + T power_of_two = static_cast<T>(T(1U) << i); + VERIFY(eastl::has_single_bit(power_of_two)); + VERIFY(eastl::has_single_bit(static_cast<T>(power_of_two - 1)) == false); + } + + return nErrorCount; +} + +template <typename T> +static int TestBitCeil() +{ + int nErrorCount = 0; + + VERIFY(eastl::bit_ceil(T(0)) == T(1)); + VERIFY(eastl::bit_ceil(T(1)) == T(1)); + VERIFY(eastl::bit_ceil(T(2)) == T(2)); + VERIFY(eastl::bit_ceil(T(3)) == T(4)); + + EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits; + EA_CONSTEXPR auto MIN = eastl::numeric_limits<T>::min(); + EA_CONSTEXPR auto MAX = static_cast<T>(T(1) << (DIGITS - 1)); + + VERIFY(eastl::bit_ceil(MAX) == MAX); + VERIFY(eastl::bit_ceil(static_cast<T>(MAX - 1)) == MAX); + VERIFY(eastl::bit_ceil(MIN) == T(1)); + + for (int i = 4; i < eastl::numeric_limits<T>::digits; i++) + { + T power_of_two = static_cast<T>(T(1U) << i); + VERIFY(eastl::bit_ceil(power_of_two) == power_of_two); + VERIFY(eastl::bit_ceil(static_cast<T>(power_of_two - 1)) == power_of_two); + } + + return nErrorCount; +} + +template <typename T> +static int TestBitFloor() +{ + int nErrorCount = 0; + VERIFY(eastl::bit_floor(T(0)) == T(0)); + VERIFY(eastl::bit_floor(T(1)) == T(1)); + VERIFY(eastl::bit_floor(T(2)) == T(2)); + VERIFY(eastl::bit_floor(T(3)) == T(2)); + + EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits; + EA_CONSTEXPR auto MIN = eastl::numeric_limits<T>::min(); + EA_CONSTEXPR auto MAX = eastl::numeric_limits<T>::max(); + + VERIFY(eastl::bit_floor(MAX) == T(1) << (DIGITS - 1)); + VERIFY(eastl::bit_floor(MIN) == T(0)); + + for (int i = 4; i < eastl::numeric_limits<T>::digits; i++) + { + T power_of_two = static_cast<T>(T(1U) << i); + VERIFY(eastl::bit_floor(power_of_two) == power_of_two); + VERIFY(eastl::bit_floor(static_cast<T>(power_of_two + 1)) == power_of_two); + } + return nErrorCount; +} + +template <typename T> +static int TestBitWidth() +{ + int nErrorCount = 0; + + VERIFY(eastl::bit_width(T(0)) == T(0)); + VERIFY(eastl::bit_width(T(1)) == T(1)); + VERIFY(eastl::bit_width(T(2)) == T(2)); + VERIFY(eastl::bit_width(T(3)) == T(2)); + + EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits; + EA_CONSTEXPR auto MIN = eastl::numeric_limits<T>::min(); + EA_CONSTEXPR auto MAX = eastl::numeric_limits<T>::max(); + + VERIFY(eastl::bit_width(MIN) == 0); + VERIFY(eastl::bit_width(MAX) == DIGITS); + + for (int i = 4; i < eastl::numeric_limits<T>::digits; i++) + { + T power_of_two = static_cast<T>(T(1U) << i); + VERIFY(eastl::bit_width(power_of_two) == static_cast<T>(i + 1)); + } + + return nErrorCount; +} + +/////////////////////////////////////////////////////////////////////////////// +// TestPowerofTwo +// +static int TestPowerOfTwo() +{ + int nErrorCount = 0; + nErrorCount += TestHasSingleBit<unsigned int>(); + nErrorCount += TestHasSingleBit<unsigned char>(); + nErrorCount += TestHasSingleBit<unsigned short>(); + nErrorCount += TestHasSingleBit<unsigned long>(); + nErrorCount += TestHasSingleBit<unsigned long long>(); + + nErrorCount += TestBitCeil<unsigned int>(); + nErrorCount += TestBitCeil<unsigned char>(); + nErrorCount += TestBitCeil<unsigned short>(); + nErrorCount += TestBitCeil<unsigned long>(); + nErrorCount += TestBitCeil<unsigned long long>(); + + nErrorCount += TestBitFloor<unsigned int>(); + nErrorCount += TestBitFloor<unsigned char>(); + nErrorCount += TestBitFloor<unsigned short>(); + nErrorCount += TestBitFloor<unsigned long>(); + nErrorCount += TestBitFloor<unsigned long long>(); + + nErrorCount += TestBitWidth<unsigned int>(); + nErrorCount += TestBitWidth<unsigned char>(); + nErrorCount += TestBitWidth<unsigned short>(); + nErrorCount += TestBitWidth<unsigned long>(); + nErrorCount += TestBitWidth<unsigned long long>(); + + return nErrorCount; +} +#endif /////////////////////////////////////////////////////////////////////////////// // TestExtra @@ -931,6 +1532,11 @@ int TestExtra() nErrorCount += TestCallTraits(); nErrorCount += TestNumeric(); nErrorCount += TestAdaptors(); +#if defined(EA_COMPILER_CPP20_ENABLED) + nErrorCount += TestMidpoint(); + nErrorCount += TestLerp(); + nErrorCount += TestPowerOfTwo(); +#endif return nErrorCount; } diff --git a/EASTL/test/source/TestFixedString.cpp b/EASTL/test/source/TestFixedString.cpp index a7f7bd9..8528dc7 100644 --- a/EASTL/test/source/TestFixedString.cpp +++ b/EASTL/test/source/TestFixedString.cpp @@ -131,6 +131,58 @@ int TestFixedSubstring() EATEST_VERIFY(str == ""); } + + { + // Check that copies/moves don't become independent strings. + // They should all point to the same sub-string. + string str = "hello world"; + fixed_substring<char> sub(str, 2, 5); + + EATEST_VERIFY(sub.size() == 5); + EATEST_VERIFY(sub[0] == 'l'); + EATEST_VERIFY(sub == "llo w"); + + vector<fixed_substring<char>> v; + for (eastl_size_t i = 0; i < 1000; ++i) { + v.push_back(sub); + } + + sub[0] = 'g'; + EATEST_VERIFY(str == "heglo world"); + EATEST_VERIFY(sub == "glo w"); + + for (const auto& s : v){ + EATEST_VERIFY(s == "glo w"); + } + + // copy construct + fixed_substring<char> sub2 = sub; + + // copy assign + fixed_substring<char> sub3; + sub3 = sub; + + // move construct + fixed_substring<char> sub4 = eastl::move(sub); + + // move assign + fixed_substring<char> sub_again(str, 2, 5); + fixed_substring<char> sub5; + sub5 = eastl::move(sub_again); + + EATEST_VERIFY(sub2 == "glo w"); + EATEST_VERIFY(sub3 == "glo w"); + EATEST_VERIFY(sub4 == "glo w"); + EATEST_VERIFY(sub5 == "glo w"); + + str[5] = 'g'; + EATEST_VERIFY(sub2 == "glogw"); + EATEST_VERIFY(sub3 == "glogw"); + EATEST_VERIFY(sub4 == "glogw"); + EATEST_VERIFY(sub5 == "glogw"); + + } + return nErrorCount; } diff --git a/EASTL/test/source/TestFunctional.cpp b/EASTL/test/source/TestFunctional.cpp index 63b3516..1e25200 100644 --- a/EASTL/test/source/TestFunctional.cpp +++ b/EASTL/test/source/TestFunctional.cpp @@ -1491,5 +1491,39 @@ struct TestInvokeResult }; template struct eastl::invoke_result<decltype(&TestInvokeResult::f), TestInvokeResult, void>; + static_assert(!eastl::is_invocable<decltype(&TestInvokeResult::f), TestInvokeResult, void>::value, "incorrect value for is_invocable"); +static_assert(!eastl::is_invocable<decltype(&TestInvokeResult::f), TestInvokeResult, int, int>::value, "incorrect value for is_invocable"); static_assert(eastl::is_invocable<decltype(&TestInvokeResult::f), TestInvokeResult, int>::value, "incorrect value for is_invocable"); + +static_assert(!eastl::is_invocable_r<int, decltype(&TestInvokeResult::f), TestInvokeResult, void>::value, "incorrect value for is_invocable_r"); +static_assert(!eastl::is_invocable_r<void, decltype(&TestInvokeResult::f), TestInvokeResult, int, int>::value, "incorrect value for is_invocable_r"); +static_assert(eastl::is_invocable_r<void, decltype(&TestInvokeResult::f), TestInvokeResult, int>::value, "incorrect value for is_invocable_r"); +static_assert(eastl::is_invocable_r<int, decltype(&TestInvokeResult::f), TestInvokeResult, int>::value, "incorrect value for is_invocable_r"); + +struct TestCallableInvokeResult +{ + int operator()(int i) {return i;} +}; + +template struct eastl::invoke_result<TestCallableInvokeResult, void>; + +static_assert(!eastl::is_invocable<TestCallableInvokeResult, void>::value, "incorrect value for is_invocable"); +static_assert(!eastl::is_invocable<TestCallableInvokeResult, int, int>::value, "incorrect value for is_invocable"); +static_assert(eastl::is_invocable<TestCallableInvokeResult, int>::value, "incorrect value for is_invocable"); + +static_assert(!eastl::is_invocable_r<int, TestCallableInvokeResult, void>::value, "incorrect value for is_invocable_r"); +static_assert(!eastl::is_invocable_r<void, TestCallableInvokeResult, int, int>::value, "incorrect value for is_invocable_r"); +static_assert(eastl::is_invocable_r<void, TestCallableInvokeResult, int>::value, "incorrect value for is_invocable_r"); +static_assert(eastl::is_invocable_r<int, TestCallableInvokeResult, int>::value, "incorrect value for is_invocable_r"); + +typedef decltype(eastl::ref(eastl::declval<TestCallableInvokeResult&>())) TestCallableRefInvokeResult; + +static_assert(!eastl::is_invocable<TestCallableRefInvokeResult, void>::value, "incorrect value for is_invocable"); +static_assert(!eastl::is_invocable<TestCallableRefInvokeResult, int, int>::value, "incorrect value for is_invocable"); +static_assert(eastl::is_invocable<TestCallableRefInvokeResult, int>::value, "incorrect value for is_invocable"); + +static_assert(!eastl::is_invocable_r<int, TestCallableRefInvokeResult, void>::value, "incorrect value for is_invocable_r"); +static_assert(!eastl::is_invocable_r<void, TestCallableRefInvokeResult, int, int>::value, "incorrect value for is_invocable_r"); +static_assert(eastl::is_invocable_r<void, TestCallableRefInvokeResult, int>::value, "incorrect value for is_invocable_r"); +static_assert(eastl::is_invocable_r<int, TestCallableRefInvokeResult, int>::value, "incorrect value for is_invocable_r"); diff --git a/EASTL/test/source/TestHash.cpp b/EASTL/test/source/TestHash.cpp index 9c9bf9d..1bcf996 100644 --- a/EASTL/test/source/TestHash.cpp +++ b/EASTL/test/source/TestHash.cpp @@ -746,14 +746,16 @@ int TestHash() { // hash_set erase_if hash_set<int> m = {0, 1, 2, 3, 4}; - eastl::erase_if(m, [](auto i) { return i % 2 == 0; }); + auto numErased = eastl::erase_if(m, [](auto i) { return i % 2 == 0; }); VERIFY((m == hash_set<int>{1, 3})); + VERIFY(numErased == 3); } { // hash_multiset erase_if hash_multiset<int> m = {0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4}; - eastl::erase_if(m, [](auto i) { return i % 2 == 0; }); + auto numErased = eastl::erase_if(m, [](auto i) { return i % 2 == 0; }); VERIFY((m == hash_multiset<int>{1, 1, 1, 3})); + VERIFY(numErased == 12); } @@ -943,15 +945,17 @@ int TestHash() { // hash_map erase_if hash_map<int, int> m = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}}; - eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); + auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); VERIFY((m == hash_map<int, int>{{1, 1}, {3, 3}})); + VERIFY(numErased == 3); } { // hash_multimap erase_if hash_multimap<int, int> m = {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {1, 1}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {4, 4}}; - eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); + auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); VERIFY((m == hash_multimap<int, int>{{1, 1}, {3, 3}, {3, 3}})); + VERIFY(numErased == 9); } diff --git a/EASTL/test/source/TestIterator.cpp b/EASTL/test/source/TestIterator.cpp index 02aa1d4..b6c6f76 100644 --- a/EASTL/test/source/TestIterator.cpp +++ b/EASTL/test/source/TestIterator.cpp @@ -4,6 +4,7 @@ #include "EASTLTest.h" +#include <EASTL/deque.h> #include <EASTL/iterator.h> #include <EASTL/vector.h> #include <EASTL/set.h> @@ -21,6 +22,8 @@ EA_DISABLE_ALL_VC_WARNINGS() #include <string.h> EA_RESTORE_ALL_VC_WARNINGS() +template <class T> +using detect_iterator_traits_reference = typename eastl::iterator_traits<T>::reference; // This is used below, though is currently disabled as documented below. struct IListNode : public eastl::intrusive_list_node{}; @@ -181,7 +184,7 @@ int TestIterator_moveIterator() // Check that we support iterators yielding plain value (typically a proxy-iterator). struct FakeProxyIterator { - using iterator_category = eastl::forward_iterator_tag; + using iterator_category = EASTL_ITC_NS::forward_iterator_tag; using difference_type = ptrdiff_t; using value_type = int; using pointer = int; // Note that we are yielding by value. @@ -250,6 +253,34 @@ int TestIterator() } { + // Regression bug with assign/insert combined with reverse iterator. + eastl::vector<int> a; + for (int i = 0; i < 10; ++i) { + a.push_back(i); + } + + eastl::deque<int> d; + d.assign(a.rbegin(), a.rend()); + for (int i = 0; i < 10; ++i) { + EATEST_VERIFY(a[i] == d[a.size() - i - 1]); + } + d.insert(d.end(), a.rbegin(), a.rend()); + for (int i = 0; i < 10; ++i) { + EATEST_VERIFY(a[i] == d[d.size() - i - 1]); + } + + eastl::vector<int> b; + b.assign(a.rbegin(), a.rend()); + for (int i = 0; i < 10; ++i) { + EATEST_VERIFY(a[i] == b[a.size() - i - 1]); + } + b.insert(b.end(), a.rbegin(), a.rend()); + for (int i = 0; i < 10; ++i) { + EATEST_VERIFY(a[i] == b[b.size() - i - 1]); + } + } + + { // move_iterator // move_iterator<Iterator> make_move_iterator(Iterator mi) typedef eastl::vector<eastl::string> StringArray; @@ -421,13 +452,17 @@ int TestIterator() { // is_iterator_wrapper - static_assert((eastl::is_iterator_wrapper<void>::value == false), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper<int>::value == false), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper<int*>::value == false), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper<eastl::array<char>*>::value == false), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper<eastl::vector<char> >::value == false), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper<eastl::generic_iterator<int*> >::value == true), "is_iterator_wrapper failure"); - static_assert((eastl::is_iterator_wrapper<eastl::move_iterator<eastl::array<int>::iterator> >::value == true), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<void>::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<int>::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<int*>::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<eastl::array<int>::iterator>::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<eastl::array<char>*>::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<eastl::vector<char> >::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<eastl::generic_iterator<int*> >::value == true), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<eastl::move_iterator<eastl::array<int>::iterator> >::value == true), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<eastl::array<int>::iterator> >::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<int*> >::value == false), "is_iterator_wrapper failure"); + static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<eastl::move_iterator<int*>> >::value == true), "is_iterator_wrapper failure"); } @@ -455,6 +490,61 @@ int TestIterator() intVector[0] = 20; EATEST_VERIFY(*itVector == 20); static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(miIntVector)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure"); + + eastl::reverse_iterator<eastl::vector<int>::iterator> riIntVector = intVector.rbegin(); + eastl::reverse_iterator<eastl::vector<int>::iterator> riUnwrapped = eastl::unwrap_iterator(riIntVector); + EATEST_VERIFY(*riUnwrapped == 19); + static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(riIntVector)), eastl::reverse_iterator<eastl::vector<int>::iterator>>::value == true), "unwrap_iterator failure"); + + eastl::reverse_iterator<eastl::move_iterator<eastl::vector<int>::iterator>> rimiIntVec(miIntVector); + static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(rimiIntVec)), eastl::reverse_iterator<eastl::vector<int>::iterator>>::value == true), "unwrap_iterator failure"); + + eastl::reverse_iterator<eastl::generic_iterator<int*>> rigiIntArray(giIntArray); + static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(rigiIntArray)), eastl::reverse_iterator<int*>>::value == true), "unwrap_iterator failure"); + + eastl::deque<int> intDeque(3); + eastl::deque<int>::iterator begin = intDeque.begin(); + eastl::generic_iterator<eastl::deque<int>::iterator> giWrappedBegin(begin); + static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(giWrappedBegin)), eastl::deque<int>::iterator>::value == true), "unwrap_iterator failure"); + + eastl::deque<int>::iterator unwrappedBegin = eastl::unwrap_iterator(giWrappedBegin); + EATEST_VERIFY(begin == unwrappedBegin); + } + + { + // unwrap_generic_iterator + int intArray[2] = {0, 1}; + eastl::generic_iterator<int*> giIntArray(intArray); + int* pInt = eastl::unwrap_generic_iterator(giIntArray); + EATEST_VERIFY(*pInt == 0); + static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(giIntArray)), int*>::value == true), "unwrap_iterator failure"); + + eastl::move_iterator<int*> miIntArray(intArray); + static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(miIntArray)), eastl::move_iterator<int*>>::value == true), "unwrap_iterator failure"); + + eastl::vector<int> intVector(1, 1); + eastl::generic_iterator<eastl::vector<int>::iterator> giVectorInt(intVector.begin()); + eastl::vector<int>::iterator it = unwrap_generic_iterator(giVectorInt); + EATEST_VERIFY(*it == 1); + static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(giVectorInt)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure"); + } + + { + // unwrap_move_iterator + int intArray[2] = {0, 1}; + eastl::move_iterator<int*> miIntArray(intArray); + int* pInt = eastl::unwrap_move_iterator(miIntArray); + EATEST_VERIFY(*pInt == 0); + static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(miIntArray)), int*>::value == true), "unwrap_iterator failure"); + + eastl::generic_iterator<int*> giIntArray(intArray); + static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(giIntArray)), eastl::generic_iterator<int*>>::value == true), "unwrap_iterator failure"); + + eastl::vector<int> intVector(1, 1); + eastl::move_iterator<eastl::vector<int>::iterator> miVectorInt(intVector.begin()); + eastl::vector<int>::iterator it = unwrap_move_iterator(miVectorInt); + EATEST_VERIFY(*it == 1); + static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(miVectorInt)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure"); } { @@ -468,6 +558,11 @@ int TestIterator() EATEST_VERIFY(dist == 3); } + { + // Regression test that ensure N3844 is working correctly. + static_assert(!eastl::is_detected<detect_iterator_traits_reference, int>::value, "detecting iterator_traits<int> should SFINAE gracefully."); + } + return nErrorCount; } diff --git a/EASTL/test/source/TestList.cpp b/EASTL/test/source/TestList.cpp index 8a5e057..001b79a 100644 --- a/EASTL/test/source/TestList.cpp +++ b/EASTL/test/source/TestList.cpp @@ -975,20 +975,115 @@ int TestList() { eastl::list<int> l = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - eastl::erase(l, 3); - eastl::erase(l, 5); - eastl::erase(l, 7); + auto numErased = eastl::erase(l, 3); + VERIFY(numErased == 1); + numErased = eastl::erase(l, 5); + VERIFY(numErased == 1); + numErased = eastl::erase(l, 7); + VERIFY(numErased == 1); VERIFY((l == eastl::list<int>{1, 2, 4, 6, 8, 9})); } { eastl::list<int> l = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - eastl::erase_if(l, [](auto i) { return i % 2 == 0; }); + auto numErased = eastl::erase_if(l, [](auto i) { return i % 2 == 0; }); VERIFY((l == eastl::list<int>{1, 3, 5, 7, 9})); + VERIFY(numErased == 4); } } + { // Test global operators + { + eastl::list<int> list1 = {0, 1, 2, 3, 4, 5}; + eastl::list<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + eastl::list<int> list3 = {5, 6, 7, 8}; + + VERIFY(list1 == list1); + VERIFY(!(list1 != list1)); + + VERIFY(list1 != list2); + VERIFY(list2 != list3); + VERIFY(list1 != list3); + + VERIFY(list1 < list2); + VERIFY(list1 <= list2); + + VERIFY(list2 > list1); + VERIFY(list2 >= list1); + + VERIFY(list3 > list1); + VERIFY(list3 > list2); + } + + // three way comparison operator +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + eastl::list<int> list1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + eastl::list<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + // Verify equality between list1 and list2 + VERIFY((list1 <=> list2) == 0); + VERIFY(!((list1 <=> list2) != 0)); + VERIFY((list1 <=> list2) <= 0); + VERIFY((list1 <=> list2) >= 0); + VERIFY(!((list1 <=> list2) < 0)); + VERIFY(!((list1 <=> list2) > 0)); + + list1.push_back(100); // Make list1 less than list2. + list2.push_back(101); + + // Verify list1 < list2 + VERIFY(!((list1 <=> list2) == 0)); + VERIFY((list1 <=> list2) != 0); + VERIFY((list1 <=> list2) <= 0); + VERIFY(!((list1 <=> list2) >= 0)); + VERIFY(((list1 <=> list2) < 0)); + VERIFY(!((list1 <=> list2) > 0)); + + for (int i = 0; i < 3; i++) // Make the length of list2 less than list1 + list2.pop_back(); + + // Verify list2.size() < list1.size() and list2 is a subset of list1 + VERIFY(!((list1 <=> list2) == 0)); + VERIFY((list1 <=> list2) != 0); + VERIFY((list1 <=> list2) >= 0); + VERIFY(!((list1 <=> list2) <= 0)); + VERIFY(((list1 <=> list2) > 0)); + VERIFY(!((list1 <=> list2) < 0)); + } + + { + eastl::list<int> list1 = {1, 2, 3, 4, 5, 6, 7}; + eastl::list<int> list2 = {7, 6, 5, 4, 3, 2, 1}; + eastl::list<int> list3 = {1, 2, 3, 4}; + + struct weak_ordering_list + { + eastl::list<int> list; + inline std::weak_ordering operator<=>(const weak_ordering_list& b) const { return list <=> b.list; } + }; + + VERIFY(synth_three_way{}(weak_ordering_list{list1}, weak_ordering_list{list2}) == std::weak_ordering::less); + VERIFY(synth_three_way{}(weak_ordering_list{list3}, weak_ordering_list{list1}) == std::weak_ordering::less); + VERIFY(synth_three_way{}(weak_ordering_list{list2}, weak_ordering_list{list1}) == std::weak_ordering::greater); + VERIFY(synth_three_way{}(weak_ordering_list{list2}, weak_ordering_list{list3}) == std::weak_ordering::greater); + VERIFY(synth_three_way{}(weak_ordering_list{list1}, weak_ordering_list{list1}) == std::weak_ordering::equivalent); + + struct strong_ordering_list + { + eastl::list<int> list; + inline std::strong_ordering operator<=>(const strong_ordering_list& b) const { return list <=> b.list; } + }; + + VERIFY(synth_three_way{}(strong_ordering_list{list1}, strong_ordering_list{list2}) == std::strong_ordering::less); + VERIFY(synth_three_way{}(strong_ordering_list{list3}, strong_ordering_list{list1}) == std::strong_ordering::less); + VERIFY(synth_three_way{}(strong_ordering_list{list2}, strong_ordering_list{list1}) == std::strong_ordering::greater); + VERIFY(synth_three_way{}(strong_ordering_list{list2}, strong_ordering_list{list3}) == std::strong_ordering::greater); + VERIFY(synth_three_way{}(strong_ordering_list{list1}, strong_ordering_list{list1}) == std::strong_ordering::equal); + } +#endif + } return nErrorCount; } diff --git a/EASTL/test/source/TestMap.cpp b/EASTL/test/source/TestMap.cpp index e2eef2f..0df8c88 100644 --- a/EASTL/test/source/TestMap.cpp +++ b/EASTL/test/source/TestMap.cpp @@ -147,15 +147,23 @@ int TestMap() { typedef eastl::map<int, int> 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; + 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); @@ -223,16 +231,65 @@ int TestMap() { // Test erase_if eastl::map<int, int> m = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}}; - eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); + auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); VERIFY((m == eastl::map<int, int>{{1, 1},{3, 3}})); + VERIFY(numErased == 3); } { // Test erase_if eastl::multimap<int, int> m = {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {4, 4}}; - eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); - VERIFY((m == eastl::multimap<int, int>{{1, 1}, {1, 1}, {3, 3}})); + auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); + VERIFY((m == eastl::multimap<int, int>{{1, 1}, {1, 1}, {3, 3}}));; + VERIFY(numErased == 7); } +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { // Test map <=> + eastl::map<int, int> m1 = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}}; + eastl::map<int, int> m2 = {{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; + eastl::map<int, int> m3 = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}}; + eastl::map<int, int> m4 = {{1, 0}, {3, 2}, {5, 4}, {7, 6}, {9, 8}}; + eastl::map<int, int> m5 = {{0, 1}, {2, 3}, {4, 5}}; + + VERIFY(m1 == m2); + VERIFY(m1 != m3); + VERIFY(m3 != m4); + VERIFY(m3 < m4); + VERIFY(m5 < m4); + VERIFY(m5 < m3); + + + VERIFY((m1 <=> m2) == 0); + VERIFY((m1 <=> m3) != 0); + VERIFY((m3 <=> m4) != 0); + VERIFY((m3 <=> m4) < 0); + VERIFY((m5 <=> m4) < 0); + VERIFY((m5 <=> m3) < 0); + } + + { // Test multimap <=> + eastl::multimap<int, int> m1 = {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {4, 4}, {4, 4}}; + eastl::multimap<int, int> m2 = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; + eastl::multimap<int, int> m3 = {{0, 1}, {2, 3}, {4, 5}, {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}}; + eastl::multimap<int, int> m4 = {{1, 0}, {3, 2}, {5, 4}, {1, 0}, {3, 2}, {5, 4}, {7, 6}, {9, 8}}; + eastl::multimap<int, int> m5 = {{10, 11}, {10, 11}}; + + VERIFY(m1 == m2); + VERIFY(m1 != m3); + VERIFY(m3 != m4); + VERIFY(m3 < m4); + VERIFY(m5 > m4); + VERIFY(m5 > m3); + + VERIFY((m1 <=> m2) == 0); + VERIFY((m1 <=> m3) != 0); + VERIFY((m3 <=> m4) != 0); + VERIFY((m3 <=> m4) < 0); + VERIFY((m5 <=> m4) > 0); + VERIFY((m5 <=> m3) > 0); + } +#endif + return nErrorCount; } diff --git a/EASTL/test/source/TestMap.h b/EASTL/test/source/TestMap.h index 09353cd..8d480cf 100644 --- a/EASTL/test/source/TestMap.h +++ b/EASTL/test/source/TestMap.h @@ -1248,11 +1248,18 @@ int TestMapCpp17() VERIFY(toMap.size() == 1); } + auto ctorCount = TestObject::sTOCtorCount; + { // verify duplicate not inserted auto result = toMap.try_emplace(7, mapped_type(7)); // test fwding to copy-ctor VERIFY(!result.second); VERIFY(result.first->second == mapped_type(7)); VERIFY(toMap.size() == 1); + + // we explicitly constructed an element for the parameter + // and one for the VERIFY check + ctorCount += 2; + VERIFY(ctorCount == TestObject::sTOCtorCount); } { // verify duplicate not inserted @@ -1261,6 +1268,9 @@ int TestMapCpp17() VERIFY(result->first == 7); VERIFY(result->second == mapped_type(7)); VERIFY(toMap.size() == 1); + // we explicitly constructed an element for the VERIFY check + ++ctorCount; + VERIFY(ctorCount == TestObject::sTOCtorCount); } { // verify duplicate not inserted @@ -1269,20 +1279,36 @@ int TestMapCpp17() VERIFY(result->first == 7); VERIFY(result->second == mapped_type(7)); VERIFY(toMap.size() == 1); + + // we explicitly constructed an element for the parameter + // and one for the VERIFY check + ctorCount += 2; + VERIFY(ctorCount == TestObject::sTOCtorCount); } { { - auto result = toMap.try_emplace(8, 8); + auto result = toMap.try_emplace(8, 8); + // emplacing a new value should call exactly one constructor, + // when the value is constructed in place inside the container. + ++ctorCount; VERIFY(result.second); VERIFY(result.first->second == mapped_type(8)); + // One more constructor for the temporary in the VERIFY + ++ctorCount; VERIFY(toMap.size() == 2); + VERIFY(ctorCount == TestObject::sTOCtorCount); } { - auto result = toMap.try_emplace(9, mapped_type(9)); + auto result = toMap.try_emplace(9, mapped_type(9)); VERIFY(result.second); VERIFY(result.first->second == mapped_type(9)); VERIFY(toMap.size() == 3); + // one more constructor for the temporary argument, + // one for moving it to the container, and one for the VERIFY + ctorCount += 3; + VERIFY(ctorCount == TestObject::sTOCtorCount); + } } } diff --git a/EASTL/test/source/TestMemory.cpp b/EASTL/test/source/TestMemory.cpp index 4e25738..77caf9f 100644 --- a/EASTL/test/source/TestMemory.cpp +++ b/EASTL/test/source/TestMemory.cpp @@ -133,6 +133,23 @@ eastl::late_constructed<LCTestObject, false, true> gLCTestObjectFalseTrue; eastl::late_constructed<LCTestObject, false, false> gLCTestObjectFalseFalse; eastl::late_constructed<LCTestObject, true, false> gLCTestObjectTrueFalse; +struct TypeWithPointerTraits {}; + +namespace eastl +{ + template <> + struct pointer_traits<TypeWithPointerTraits> + { + // Note: only parts of the traits we are interested to test are defined here. + static const int* to_address(TypeWithPointerTraits) + { + return &a; + } + + inline static constexpr int a = 42; + }; +} + /////////////////////////////////////////////////////////////////////////////// // TestMemory @@ -684,6 +701,33 @@ int TestMemory() } } + // to_address + { + // Normal pointers. + int a; + int* ptrA = &a; + EATEST_VERIFY(ptrA == to_address(ptrA)); + + // Smart pointer. + struct MockSmartPointer + { + const int* operator->() const + { + return &a; + } + + int a = 42; + }; + + MockSmartPointer sp; + EATEST_VERIFY(&sp.a == to_address(sp)); + + // Type with specialized pointer_traits. + TypeWithPointerTraits t; + const int* result = to_address(t); + EATEST_VERIFY(result != nullptr && *result == 42); + } + { // Test that align handles integral overflow correctly and returns NULL. void* ptr; diff --git a/EASTL/test/source/TestNumericLimits.cpp b/EASTL/test/source/TestNumericLimits.cpp index 440715b..1964442 100644 --- a/EASTL/test/source/TestNumericLimits.cpp +++ b/EASTL/test/source/TestNumericLimits.cpp @@ -64,6 +64,11 @@ int TestNumericLimits() EATEST_VERIFY(eastl::numeric_limits<wchar_t>::is_bounded); EATEST_VERIFY(eastl::numeric_limits<wchar_t>::max() != 0); + #if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE + EATEST_VERIFY(eastl::numeric_limits<char8_t>::is_bounded); + EATEST_VERIFY(eastl::numeric_limits<char8_t>::max() != 0); + #endif + EATEST_VERIFY(eastl::numeric_limits<char16_t>::is_bounded); EATEST_VERIFY(eastl::numeric_limits<char16_t>::max() != 0); diff --git a/EASTL/test/source/TestOptional.cpp b/EASTL/test/source/TestOptional.cpp index b4934a7..36307ad 100644 --- a/EASTL/test/source/TestOptional.cpp +++ b/EASTL/test/source/TestOptional.cpp @@ -18,12 +18,17 @@ struct IntStruct int data; }; +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) +auto operator<=>(const IntStruct& lhs, const IntStruct& rhs) { return lhs.data <=> rhs.data; } +#else bool operator<(const IntStruct& lhs, const IntStruct& rhs) { return lhs.data < rhs.data; } +#endif bool operator==(const IntStruct& lhs, const IntStruct& rhs) { return lhs.data == rhs.data; } + ///////////////////////////////////////////////////////////////////////////// struct destructor_test { @@ -476,6 +481,43 @@ int TestOptional() VERIFY(o >= nullopt); } + #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + optional<IntStruct> o(in_place, 10); + optional<IntStruct> e; + + VERIFY((o <=> IntStruct(42)) < 0); + VERIFY((o <=> IntStruct(2)) >= 0); + VERIFY((o <=> IntStruct(10)) >= 0); + VERIFY((e <=> o) < 0); + VERIFY((e <=> IntStruct(10)) < 0); + + VERIFY((o <=> IntStruct(4)) > 0); + VERIFY(o <=> IntStruct(42) <= 0); + + VERIFY((o <=> IntStruct(4)) >= 0); + VERIFY((o <=> IntStruct(10)) >= 0); + VERIFY((IntStruct(4) <=> o) <= 0); + VERIFY((IntStruct(10) <=> o) <= 0); + + VERIFY((o <=> IntStruct(10)) == 0); + VERIFY((o->data <=> IntStruct(10).data) == 0); + + VERIFY((o <=> IntStruct(11)) != 0); + VERIFY((o->data <=> IntStruct(11).data) != 0); + + VERIFY((e <=> nullopt) == 0); + VERIFY((nullopt <=> e) == 0); + + VERIFY((o <=> nullopt) != 0); + VERIFY((nullopt <=> o) != 0); + VERIFY((nullopt <=> o) < 0); + VERIFY((o <=> nullopt) > 0); + VERIFY((nullopt <=> o) <= 0); + VERIFY((o <=> nullopt) >= 0); + } + #endif + // hash { { diff --git a/EASTL/test/source/TestSList.cpp b/EASTL/test/source/TestSList.cpp index d73f2bc..94a4d3a 100644 --- a/EASTL/test/source/TestSList.cpp +++ b/EASTL/test/source/TestSList.cpp @@ -795,36 +795,134 @@ int TestSList() { slist<int> l = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - eastl::erase(l, 5); + auto numErased = eastl::erase(l, 5); VERIFY((l == slist<int>{0, 1, 2, 3, 4, 6, 7, 8, 9})); + VERIFY(numErased == 1); - eastl::erase(l, 7); + numErased = eastl::erase(l, 7); VERIFY((l == slist<int>{0, 1, 2, 3, 4, 6, 8, 9})); + VERIFY(numErased == 1); - eastl::erase(l, 2); + numErased = eastl::erase(l, 2); VERIFY((l == slist<int>{0, 1, 3, 4, 6, 8, 9})); + VERIFY(numErased == 1); - eastl::erase(l, 0); + numErased = eastl::erase(l, 0); VERIFY((l == slist<int>{1, 3, 4, 6, 8, 9})); + VERIFY(numErased == 1); - eastl::erase(l, 4); + numErased = eastl::erase(l, 4); VERIFY((l == slist<int>{1, 3, 6, 8, 9})); + VERIFY(numErased == 1); } { slist<int> l = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - eastl::erase_if(l, [](auto e) { return e % 2 == 0; }); + auto numErased = eastl::erase_if(l, [](auto e) { return e % 2 == 0; }); VERIFY((l == slist<int>{1, 3, 5, 7, 9})); + VERIFY(numErased == 5); - eastl::erase_if(l, [](auto e) { return e == 5; }); + numErased = eastl::erase_if(l, [](auto e) { return e == 5; }); VERIFY((l == slist<int>{1, 3, 7, 9})); + VERIFY(numErased == 1); - eastl::erase_if(l, [](auto e) { return e % 3 == 0; }); + numErased = eastl::erase_if(l, [](auto e) { return e % 3 == 0; }); VERIFY((l == slist<int>{1, 7})); + VERIFY(numErased == 2); } } + { // Test global operators + { + slist<int> list1 = {0, 1, 2, 3, 4, 5}; + slist<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + slist<int> list3 = {5, 6, 7, 8}; + + VERIFY(list1 == list1); + VERIFY(!(list1 != list1)); + + VERIFY(list1 != list2); + VERIFY(list2 != list3); + VERIFY(list1 != list3); + + VERIFY(list1 < list2); + VERIFY(list1 <= list2); + + VERIFY(list2 > list1); + VERIFY(list2 >= list1); + + VERIFY(list3 > list1); + VERIFY(list3 > list2); + } + +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + slist<int> list1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + slist<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + slist<int> list3 = {-1, 0, 1, 2, 3, 4, 5}; + + // Verify equality between list1 and list2 + VERIFY((list1 <=> list2) == 0); + VERIFY(!((list1 <=> list2) != 0)); + VERIFY((list1 <=> list2) <= 0); + VERIFY((list1 <=> list2) >= 0); + VERIFY(!((list1 <=> list2) < 0)); + VERIFY(!((list1 <=> list2) > 0)); + + list1.push_front(-2); // Make list1 less than list2. + list2.push_front(-1); + + // Verify list1 < list2 + VERIFY(!((list1 <=> list2) == 0)); + VERIFY((list1 <=> list2) != 0); + VERIFY((list1 <=> list2) <= 0); + VERIFY(!((list1 <=> list2) >= 0)); + VERIFY(((list1 <=> list2) < 0)); + VERIFY(!((list1 <=> list2) > 0)); + + + // Verify list3.size() < list2.size() and list3 is a subset of list2 + VERIFY(!((list3 <=> list2) == 0)); + VERIFY((list3 <=> list2) != 0); + VERIFY((list3 <=> list2) <= 0); + VERIFY(!((list3 <=> list2) >= 0)); + VERIFY(((list3 <=> list2) < 0)); + VERIFY(!((list3 <=> list2) > 0)); + } + + { + slist<int> list1 = {1, 2, 3, 4, 5, 6, 7}; + slist<int> list2 = {7, 6, 5, 4, 3, 2, 1}; + slist<int> list3 = {1, 2, 3, 4}; + + struct weak_ordering_slist + { + slist<int> slist; + inline std::weak_ordering operator<=>(const weak_ordering_slist& b) const { return slist <=> b.slist; } + }; + + VERIFY(synth_three_way{}(weak_ordering_slist{list1}, weak_ordering_slist{list2}) == std::weak_ordering::less); + VERIFY(synth_three_way{}(weak_ordering_slist{list3}, weak_ordering_slist{list1}) == std::weak_ordering::less); + VERIFY(synth_three_way{}(weak_ordering_slist{list2}, weak_ordering_slist{list1}) == std::weak_ordering::greater); + VERIFY(synth_three_way{}(weak_ordering_slist{list2}, weak_ordering_slist{list3}) == std::weak_ordering::greater); + VERIFY(synth_three_way{}(weak_ordering_slist{list1}, weak_ordering_slist{list1}) == std::weak_ordering::equivalent); + + struct strong_ordering_slist + { + slist<int> slist; + inline std::strong_ordering operator<=>(const strong_ordering_slist& b) const { return slist <=> b.slist; } + }; + + VERIFY(synth_three_way{}(strong_ordering_slist{list1}, strong_ordering_slist{list2}) == std::strong_ordering::less); + VERIFY(synth_three_way{}(strong_ordering_slist{list3}, strong_ordering_slist{list1}) == std::strong_ordering::less); + VERIFY(synth_three_way{}(strong_ordering_slist{list2}, strong_ordering_slist{list1}) == std::strong_ordering::greater); + VERIFY(synth_three_way{}(strong_ordering_slist{list2}, strong_ordering_slist{list3}) == std::strong_ordering::greater); + VERIFY(synth_three_way{}(strong_ordering_slist{list1}, strong_ordering_slist{list1}) == std::strong_ordering::equal); + } +#endif + } + return nErrorCount; } diff --git a/EASTL/test/source/TestSet.cpp b/EASTL/test/source/TestSet.cpp index 1adc12f..9a590c2 100644 --- a/EASTL/test/source/TestSet.cpp +++ b/EASTL/test/source/TestSet.cpp @@ -162,16 +162,60 @@ int TestSet() { // set erase_if tests set<int> s = {0, 1, 2, 3, 4}; - eastl::erase_if(s, [](auto i) { return i % 2 == 0;}); + auto numErased = eastl::erase_if(s, [](auto i) { return i % 2 == 0;}); VERIFY((s == set<int>{1,3})); + VERIFY(numErased == 3); } { // multiset erase_if tests multiset<int> s = {0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4}; - eastl::erase_if(s, [](auto i) { return i % 2 == 0;}); + auto numErased = eastl::erase_if(s, [](auto i) { return i % 2 == 0;}); VERIFY((s == multiset<int>{1, 1, 1, 3, 3, 3})); + VERIFY(numErased == 7); } +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { // Test set <=> + set<int> s1 = {0, 1, 2, 3, 4}; + set<int> s2 = {4, 3, 2, 1, 0}; + set<int> s3 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + set<int> s4 = {1, 2, 3, 4, 5, 6}; + set<int> s5 = {9}; + + VERIFY(s1 == s2); + VERIFY(s1 != s3); + VERIFY(s3 > s4); + VERIFY(s5 > s4); + VERIFY(s5 > s3); + + VERIFY((s1 <=> s2) == 0); + VERIFY((s1 <=> s3) != 0); + VERIFY((s3 <=> s4) > 0); + VERIFY((s5 <=> s4) > 0); + VERIFY((s5 <=> s3) > 0); + } + + { // Test multiset <=> + multiset<int> s1 = {0, 0, 0, 1, 1, 2, 3, 3, 4}; + multiset<int> s2 = {4, 3, 3, 2, 1, 1, 0, 0, 0}; + multiset<int> s3 = {1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9}; + multiset<int> s4 = {1, 1, 2, 2, 3, 4, 5, 5, 6}; + multiset<int> s5 = {9}; + + VERIFY(s1 == s2); + VERIFY(s1 != s3); + VERIFY(s3 > s4); + VERIFY(s5 > s4); + VERIFY(s5 > s3); + + VERIFY((s1 <=> s2) == 0); + VERIFY((s1 <=> s3) != 0); + VERIFY((s3 <=> s4) > 0); + VERIFY((s5 <=> s4) > 0); + VERIFY((s5 <=> s3) > 0); + } +#endif + { // user reported regression: ensure container elements are NOT // moved from during the eastl::set construction process. diff --git a/EASTL/test/source/TestSmartPtr.cpp b/EASTL/test/source/TestSmartPtr.cpp index dc94b96..8052392 100644 --- a/EASTL/test/source/TestSmartPtr.cpp +++ b/EASTL/test/source/TestSmartPtr.cpp @@ -8,6 +8,7 @@ #include "GetTypeName.h" #include <EAStdC/EAString.h> #include <EAStdC/EAStopwatch.h> +#include <EASTL/atomic.h> #include <EASTL/core_allocator_adapter.h> #include <EASTL/core_allocator.h> #include <EASTL/intrusive_ptr.h> @@ -800,6 +801,38 @@ static int Test_unique_ptr() } #endif + #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + unique_ptr<int> pT1(new int(5)); + unique_ptr<int> pT2(new int(10)); + unique_ptr<int> pT3(new int(0)); + + EATEST_VERIFY((pT1 <=> pT2) != 0); + EATEST_VERIFY((pT2 <=> pT1) != 0); + + EATEST_VERIFY((pT1 <=> pT2) < 0); + EATEST_VERIFY((pT1 <=> pT2) <= 0); + EATEST_VERIFY((pT2 <=> pT1) > 0); + EATEST_VERIFY((pT2 <=> pT1) >= 0); + + EATEST_VERIFY((pT3 <=> pT1) < 0); + EATEST_VERIFY((pT3 <=> pT2) < 0); + EATEST_VERIFY((pT1 <=> pT3) > 0); + EATEST_VERIFY((pT2 <=> pT3) > 0); + + unique_ptr<A> pT4(new A(5)); + unique_ptr<A> pT5(new A(10)); + + EATEST_VERIFY((pT4 <=> pT5) != 0); + EATEST_VERIFY((pT5 <=> pT4) != 0); + + EATEST_VERIFY((pT4 <=> pT5) < 0); + EATEST_VERIFY((pT4 <=> pT5) <= 0); + EATEST_VERIFY((pT5 <=> pT4) > 0); + EATEST_VERIFY((pT5 <=> pT4) >= 0); + } + #endif + // ToDo: Test move assignment between two convertible types with an is_assignable deleter_type //{ // struct Base {}; @@ -1351,7 +1384,7 @@ static int Test_shared_ptr() { EA::Thread::ThreadParameters mThreadParams; EA::Thread::Thread mThread; - volatile bool mbShouldContinue; + eastl::atomic<bool> mbShouldContinue; int mnErrorCount; eastl::shared_ptr<TestObject>* mpSPTO; eastl::weak_ptr<TestObject>* mpWPTO; @@ -1364,7 +1397,7 @@ static int Test_shared_ptr() { int& nErrorCount = mnErrorCount; // declare nErrorCount so that EATEST_VERIFY can work, as it depends on it being declared. - while(mbShouldContinue) + while(mbShouldContinue.load(eastl::memory_order_relaxed)) { EA::UnitTest::ThreadSleepRandom(1, 10); @@ -1419,7 +1452,7 @@ static int Test_shared_ptr_thread() EA::UnitTest::ThreadSleep(2000); for(size_t i = 0; i < EAArrayCount(thread); i++) - thread[i].mbShouldContinue = false; + thread[i].mbShouldContinue.store(false, eastl::memory_order_relaxed); for(size_t i = 0; i < EAArrayCount(thread); i++) { diff --git a/EASTL/test/source/TestSort.cpp b/EASTL/test/source/TestSort.cpp index 2d0116f..114a73b 100644 --- a/EASTL/test/source/TestSort.cpp +++ b/EASTL/test/source/TestSort.cpp @@ -177,8 +177,22 @@ namespace eastl return x; } }; + + struct TestNoLessOperator + { + int i {}; + }; } // namespace Internal + template <> + struct less<Internal::TestNoLessOperator> + { + bool operator()(const Internal::TestNoLessOperator& lhs, const Internal::TestNoLessOperator& rhs) const noexcept + { + return lhs.i < rhs.i; + } + }; + } // namespace eastl int TestSort() @@ -630,6 +644,13 @@ int TestSort() radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer); EATEST_VERIFY(is_sorted(begin(input), end(input))); } + { + // Test case for bug where the last histogram bucket was not being cleared to zero + uint32_t input[] = { 0xff00, 0xff }; + uint32_t buffer[EAArrayCount(input)]; + radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer); + EATEST_VERIFY(is_sorted(begin(input), end(input))); + } } { @@ -793,7 +814,7 @@ int TestSort() } { - // EATEST_VERIFY deque sorting can compile. + // Test checking that deque sorting can compile. deque<int> intDeque; vector<int> intVector; @@ -801,6 +822,25 @@ int TestSort() stable_sort(intVector.begin(), intVector.end()); } + { + // Test checking that sorting containers having elements of a type without an operator< compiles correctly + + vector<TestNoLessOperator> 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<TestNoLessOperator> 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/EASTL/test/source/TestString.inl b/EASTL/test/source/TestString.inl index 08fb924..3a59e68 100644 --- a/EASTL/test/source/TestString.inl +++ b/EASTL/test/source/TestString.inl @@ -2024,19 +2024,25 @@ int TEST_STRING_NAME() // test eastl::erase { StringType str(LITERAL("abcdefghijklmnopqrstuvwxyz")); - eastl::erase(str, LITERAL('a')); - eastl::erase(str, LITERAL('f')); - eastl::erase(str, LITERAL('l')); - eastl::erase(str, LITERAL('w')); - eastl::erase(str, LITERAL('y')); + auto numErased = eastl::erase(str, LITERAL('a')); + VERIFY(numErased == 1); + numErased = eastl::erase(str, LITERAL('f')); + VERIFY(numErased == 1); + numErased = eastl::erase(str, LITERAL('l')); + VERIFY(numErased == 1); + numErased = eastl::erase(str, LITERAL('w')); + VERIFY(numErased == 1); + numErased = eastl::erase(str, LITERAL('y')); + VERIFY(numErased == 1); VERIFY(str == LITERAL("bcdeghijkmnopqrstuvxz")); } // test eastl::erase_if { StringType str(LITERAL("abcdefghijklmnopqrstuvwxyz")); - eastl::erase_if(str, [](auto c) { return c == LITERAL('a') || c == LITERAL('v'); }); + auto numErased = eastl::erase_if(str, [](auto c) { return c == LITERAL('a') || c == LITERAL('v'); }); VERIFY(str == LITERAL("bcdefghijklmnopqrstuwxyz")); + VERIFY(numErased == 2); } // template<> struct hash<eastl::string>; @@ -2064,6 +2070,28 @@ int TEST_STRING_NAME() VERIFY(LocalHash(sw2) == LocalHash(sw3)); } + // test <=> operator + #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + StringType sw1(LITERAL("Test String ")); + StringType sw2(LITERAL("Test String 1")); + StringType sw3(LITERAL("Test String 2")); + StringType sw4(LITERAL("abcdef")); + + VERIFY((sw1 <=> sw2) != 0); + VERIFY((sw1 <=> sw3) != 0); + VERIFY((sw2 <=> sw3) != 0); + VERIFY((sw1 <=> sw2) < 0); + VERIFY((sw1 <=> sw3) < 0); + VERIFY((sw2 <=> sw2) == 0); + VERIFY((sw2 <=> sw3) < 0); + VERIFY((sw2 <=> sw4) < 0); + VERIFY((sw4 <=> sw2) > 0); + VERIFY((sw4 <=> sw3) > 0); + VERIFY((sw3 <=> sw2) > 0); + } + #endif + return nErrorCount; } diff --git a/EASTL/test/source/TestStringView.cpp b/EASTL/test/source/TestStringView.cpp index 835488c..23e6e51 100644 --- a/EASTL/test/source/TestStringView.cpp +++ b/EASTL/test/source/TestStringView.cpp @@ -5,6 +5,7 @@ #include "EASTLTest.h" #include <EABase/eabase.h> #include <EASTL/numeric_limits.h> +#include <EASTL/string.h> #include <EASTL/string_view.h> // Verify char8_t support is present if the test build requested it. @@ -78,12 +79,18 @@ int TestStringView() static_assert(eastl::is_same_v<decltype(U"abcdef"_sv), eastl::u32string_view>, "string_view literal type mismatch"); static_assert(eastl::is_same_v<decltype(L"abcdef"_sv), eastl::wstring_view>, "string_view literal type mismatch"); - // TODO: Need to resolve this. Not sure why on Clang the user literal 'operator ""sv' can't be found. - // VERIFY("cplusplus"sv.compare("cplusplus") == 0); - // VERIFY(L"cplusplus"sv.compare(L"cplusplus") == 0); - // VERIFY(u"cplusplus"sv.compare(u"cplusplus") == 0); - // VERIFY(U"cplusplus"sv.compare(U"cplusplus") == 0); - // VERIFY(u8"cplusplus"sv.compare(u8"cplusplus") == 0); + + VERIFY("cplusplus"sv.compare("cplusplus") == 0); + VERIFY(L"cplusplus"sv.compare(L"cplusplus") == 0); + VERIFY(u"cplusplus"sv.compare(u"cplusplus") == 0); + VERIFY(U"cplusplus"sv.compare(U"cplusplus") == 0); + VERIFY(u8"cplusplus"sv.compare(u8"cplusplus") == 0); + + static_assert(eastl::is_same_v<decltype("abcdef"sv), eastl::string_view>, "string_view literal type mismatch"); + static_assert(eastl::is_same_v<decltype(u8"abcdef"sv), eastl::u8string_view>, "string_view literal type mismatch"); + static_assert(eastl::is_same_v<decltype(u"abcdef"sv), eastl::u16string_view>, "string_view literal type mismatch"); + static_assert(eastl::is_same_v<decltype(U"abcdef"sv), eastl::u32string_view>, "string_view literal type mismatch"); + static_assert(eastl::is_same_v<decltype(L"abcdef"sv), eastl::wstring_view>, "string_view literal type mismatch"); } #endif diff --git a/EASTL/test/source/TestStringView.inl b/EASTL/test/source/TestStringView.inl index 14472fb..cd4214e 100644 --- a/EASTL/test/source/TestStringView.inl +++ b/EASTL/test/source/TestStringView.inl @@ -5,6 +5,8 @@ template<typename StringViewT> int TEST_STRING_NAME() { + using StringT = eastl::basic_string<typename StringViewT::value_type>; + int nErrorCount = 0; { // EA_CONSTEXPR basic_string_view() @@ -476,6 +478,84 @@ int TEST_STRING_NAME() VERIFY(sw1 <= sw2); VERIFY(sw2 > sw1); VERIFY(sw2 >= sw1); + +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + VERIFY((sw1 <=> StringViewT(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH"))) == 0); + VERIFY((sw1 <=> StringViewT(LITERAL("abcdefghijklmnopqrstuvwxyz"))) != 0); + VERIFY((sw1 <=> sw2) < 0); + VERIFY((sw1 <=> sw2) <= 0); + VERIFY((sw2 <=> sw1) > 0); + VERIFY((sw2 <=> sw1) >= 0); +#endif + } + + { + auto s = LITERAL("Hello, World"); + StringViewT sv(s); + + VERIFY(s == sv); + VERIFY(sv == s); + + VERIFY(s <= sv); + VERIFY(sv <= s); + VERIFY(s >= sv); + VERIFY(sv >= s); + VERIFY(!(s != sv)); + VERIFY(!(sv != s)); + VERIFY(!(s < sv)); + VERIFY(!(sv < s)); + VERIFY(!(s > sv)); + VERIFY(!(sv > s)); + +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + VERIFY((s <=> sv) == 0); + VERIFY((sv <=> s) == 0); + + VERIFY((s <=> sv) <= 0); + VERIFY((sv <=> s) <= 0); + VERIFY((s <=> sv) >= 0); + VERIFY((sv <=> s) >= 0); + VERIFY(!((s <=> sv) != 0)); + VERIFY(!((sv <=> s) != 0)); + VERIFY(!((s <=> sv) > 0)); + VERIFY(!((sv <=> s) < 0)); +#endif + } + + // Regression comparison operators should work between basic_string_view and basic_string. + // The idea is that type_identity_t on some overloads will force basic_string::operator basic_string_view() to kick in. + { + StringT s(LITERAL("Hello, Stockholm")); + StringViewT sv(s); + + VERIFY(s == sv); + VERIFY(sv == s); + + // All the operators bellow used to not work. + VERIFY(s <= sv); + VERIFY(sv <= s); + VERIFY(s >= sv); + VERIFY(sv >= s); + VERIFY(!(s != sv)); + VERIFY(!(sv != s)); + VERIFY(!(s < sv)); + VERIFY(!(sv < s)); + VERIFY(!(s > sv)); + VERIFY(!(sv > s)); + +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + VERIFY((s <=> sv) == 0); + VERIFY((sv <=> s) == 0); + + VERIFY((s <=> sv) <= 0); + VERIFY((sv <=> s) <= 0); + VERIFY((s <=> sv) >= 0); + VERIFY((sv <=> s) >= 0); + VERIFY(!((s <=> sv) != 0)); + VERIFY(!((sv <=> s) != 0)); + VERIFY(!((s <=> sv) > 0)); + VERIFY(!((sv <=> s) < 0)); +#endif } // template<> struct hash<std::string_view>; diff --git a/EASTL/test/source/TestTuple.cpp b/EASTL/test/source/TestTuple.cpp index 8c1b48a..6a7647e 100644 --- a/EASTL/test/source/TestTuple.cpp +++ b/EASTL/test/source/TestTuple.cpp @@ -227,11 +227,27 @@ int TestTuple() EATEST_VERIFY(aTuple != aDefaultInitTuple); EATEST_VERIFY(aDefaultInitTuple < aTuple); + #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + EATEST_VERIFY((aTuple <=> anotherTuple) == 0); + EATEST_VERIFY((aTuple <=> anotherTuple) >= 0); + EATEST_VERIFY((anotherTuple <=> aTuple) >= 0); + EATEST_VERIFY((aTuple <=> aDefaultInitTuple) != 0); + EATEST_VERIFY((aDefaultInitTuple <=> aTuple) < 0); + #endif + tuple<int, int, int> lesserTuple(1, 2, 3); tuple<int, int, int> greaterTuple(1, 2, 4); EATEST_VERIFY(lesserTuple < greaterTuple && !(greaterTuple < lesserTuple) && greaterTuple > lesserTuple && !(lesserTuple > greaterTuple)); + #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + EATEST_VERIFY((lesserTuple <=> greaterTuple) != 0); + EATEST_VERIFY((lesserTuple <=> greaterTuple) < 0); + EATEST_VERIFY((lesserTuple <=> greaterTuple) <= 0); + EATEST_VERIFY((greaterTuple <=> lesserTuple) > 0); + EATEST_VERIFY((greaterTuple <=> lesserTuple) >= 0); + #endif + tuple<int, float, TestObject> valTup(2, 2.0f, TestObject(2)); tuple<int&, float&, TestObject&> refTup(valTup); tuple<const int&, const float&, const TestObject&> constRefTup(valTup); @@ -272,6 +288,20 @@ int TestTuple() } { + // Test construction of tuple containing r-value references + int x = 42; + TestObject object{1337}; + + tuple<int&&, TestObject&&> aTupleWithRValueReference(eastl::move(x), eastl::move(object)); + static_assert(is_same<decltype(get<0>(aTupleWithRValueReference)), int&>::value, "wrong return type for get when using r-value reference."); + static_assert(is_same<decltype(get<1>(aTupleWithRValueReference)), TestObject&>::value, "wrong return type for get when using r-value reference."); + EATEST_VERIFY(get<0>(aTupleWithRValueReference) == 42); + EATEST_VERIFY(get<1>(aTupleWithRValueReference).mX == 1337); + + static_assert(!is_constructible<decltype(aTupleWithRValueReference), int&, TestObject&>::value, "it shouldn't be possible to assign r-value references with l-values."); + } + + { // Tuple helpers // make_tuple @@ -481,6 +511,27 @@ int TestTuple() #endif } + // Compilation test to make sure that we can handle reference to forward-declared types + { + struct ForwardDeclared; + + auto fill_tuple = [](ForwardDeclared& f) { + eastl::tuple<ForwardDeclared&, const ForwardDeclared&> t{f, f}; + return t; + }; + + struct ForwardDeclared + { + int x; + }; + + ForwardDeclared f{666}; + auto t = fill_tuple(f); + + EATEST_VERIFY(get<0>(t).x == 666); + EATEST_VERIFY(get<1>(t).x == 666); + } + #ifndef EA_COMPILER_NO_STRUCTURED_BINDING // tuple structured bindings test { diff --git a/EASTL/test/source/TestTypeTraits.cpp b/EASTL/test/source/TestTypeTraits.cpp index 0353be9..2670e24 100644 --- a/EASTL/test/source/TestTypeTraits.cpp +++ b/EASTL/test/source/TestTypeTraits.cpp @@ -173,15 +173,16 @@ struct NonPod2 virtual void Function(){} }; -#if EASTL_VARIABLE_TEMPLATES_ENABLED - struct HasIncrementOperator { HasIncrementOperator& operator++() { return *this; } }; +struct HasIncrementOperator { HasIncrementOperator& operator++() { return *this; } }; - template<typename, typename = eastl::void_t<>> - struct has_increment_operator : eastl::false_type {}; +template <class T> +using has_increment_operator_detection = decltype(++eastl::declval<T>()); - template <typename T> - struct has_increment_operator<T, eastl::void_t<decltype(++eastl::declval<T>())>> : eastl::true_type {}; -#endif +template<typename, typename = eastl::void_t<>> +struct has_increment_operator_using_void_t : eastl::false_type {}; + +template <typename T> +struct has_increment_operator_using_void_t<T, eastl::void_t<has_increment_operator_detection<T>>> : eastl::true_type {}; // We use this for the is_copy_constructible test in order to verify that @@ -359,13 +360,19 @@ struct NonPolymorphic1 void Function(){} }; +// Disable the following warning: +// warning: ‘struct Abstract’ has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor] +// We explicitly want this class not to have a virtual destructor to test our type traits. +EA_DISABLE_VC_WARNING(4265) +EA_DISABLE_CLANG_WARNING(-Wnon-virtual-dtor) +EA_DISABLE_GCC_WARNING(-Wnon-virtual-dtor) struct Abstract { - #if defined(EA_COMPILER_GNUC) // GCC warns about this, so we include it for this class, even though for this compiler it partly defeats the purpose of its usage. - virtual ~Abstract(){} - #endif virtual void Function() = 0; }; +EA_RESTORE_GCC_WARNING() +EA_RESTORE_CLANG_WARNING() +EA_RESTORE_VC_WARNING() struct AbstractWithDtor { @@ -542,6 +549,7 @@ int TestTypeTraits() EATEST_VERIFY(GetType(is_integral<float>()) == false); static_assert(is_integral<bool>::value, "is_integral failure"); + static_assert(is_integral<char8_t>::value, "is_integral failure"); static_assert(is_integral<char16_t>::value, "is_integral failure"); static_assert(is_integral<char32_t>::value, "is_integral failure"); static_assert(is_integral<char>::value, "is_integral failure"); @@ -616,6 +624,42 @@ int TestTypeTraits() EATEST_VERIFY(GetType(is_array<uint32_t*>()) == false); + //is_bounded_array + static_assert(is_bounded_array<Array>::value == true, "is_bounded_array failure"); + EATEST_VERIFY(GetType(is_bounded_array<Array>()) == true); + + static_assert(is_bounded_array<ArrayConst>::value == true, "is_bounded_array failure"); + EATEST_VERIFY(GetType(is_bounded_array<ArrayConst>()) == true); + + static_assert(is_bounded_array<int>::value == false, "is_bounded_array failure"); + static_assert(is_bounded_array<int[32]>::value == true, "is_bounded_array failure"); + static_assert(is_bounded_array<int[]>::value == false, "is_bounded_array failure"); + + static_assert(is_bounded_array<uint32_t>::value == false, "is_bounded_array failure"); + EATEST_VERIFY(GetType(is_bounded_array<uint32_t>()) == false); + + static_assert(is_bounded_array<uint32_t*>::value == false, "is_bounded_array failure"); + EATEST_VERIFY(GetType(is_bounded_array<uint32_t*>()) == false); + + + //is_unbounded_array + static_assert(is_unbounded_array<Array>::value == false, "is_unbounded_array failure"); + EATEST_VERIFY(GetType(is_unbounded_array<Array>()) == false); + + static_assert(is_unbounded_array<ArrayConst>::value == false, "is_unbounded_array failure"); + EATEST_VERIFY(GetType(is_unbounded_array<ArrayConst>()) == false); + + static_assert(is_unbounded_array<int>::value == false, "is_unbounded_array failure"); + static_assert(is_unbounded_array<int[32]>::value == false, "is_unbounded_array failure"); + static_assert(is_unbounded_array<int[]>::value == true, "is_unbounded_array failure"); + + static_assert(is_unbounded_array<uint32_t>::value == false, "is_unbounded_array failure"); + EATEST_VERIFY(GetType(is_unbounded_array<uint32_t>()) == false); + + static_assert(is_unbounded_array<uint32_t*>::value == false, "is_unbounded_array failure"); + EATEST_VERIFY(GetType(is_unbounded_array<uint32_t*>()) == false); + + // is_reference static_assert(is_reference<Class&>::value == true, "is_reference failure"); EATEST_VERIFY(GetType(is_reference<Class&>()) == true); @@ -640,6 +684,10 @@ int TestTypeTraits() static_assert(is_member_function_pointer<int>::value == false, "is_member_function_pointer failure"); static_assert(is_member_function_pointer<int(Class::*)>::value == false, "is_member_function_pointer failure"); static_assert(is_member_function_pointer<int(Class::*)()>::value == true, "is_member_function_pointer failure"); + static_assert(is_member_function_pointer<int(Class::*)(...)>::value == true, "is_member_function_pointer failure"); + static_assert(is_member_function_pointer<int(Class::*)() noexcept>::value == true, "is_member_function_pointer failure"); + static_assert(is_member_function_pointer<int(Class::*)() &>::value == true, "is_member_function_pointer failure"); + static_assert(is_member_function_pointer<int(Class::*)() &&>::value == true, "is_member_function_pointer failure"); // is_member_object_pointer @@ -652,6 +700,9 @@ int TestTypeTraits() static_assert(is_member_pointer<int>::value == false, "is_member_pointer failure"); static_assert(is_member_pointer<int(Class::*)>::value == true, "is_member_pointer failure"); static_assert(is_member_pointer<int(Class::*)()>::value == true, "is_member_pointer failure"); + static_assert(is_member_pointer<int(Class::* const)>::value == true, "is_member_pointer failure"); + static_assert(is_member_pointer<int(Class::* volatile)>::value == true, "is_member_pointer failure"); + static_assert(is_member_pointer<int(Class::* const volatile)>::value == true, "is_member_pointer failure"); // is_pointer @@ -719,7 +770,7 @@ int TestTypeTraits() // is_function static_assert(is_function<void>::value == false, "is_function failure"); static_assert(is_function<FunctionVoidVoid>::value == true, "is_function failure"); - static_assert(is_function<FunctionVoidVoid&>::value == false, "is_function failure"); + static_assert(is_function<FunctionVoidVoid&>::value == false, "is_function failure"); static_assert(is_function<FunctionIntVoid>::value == true, "is_function failure"); static_assert(is_function<FunctionIntFloat>::value == true, "is_function failure"); static_assert(is_function<FunctionVoidVoidPtr>::value == false, "is_function failure"); @@ -731,6 +782,16 @@ int TestTypeTraits() // typedef int PrintfConst(const char*, ...) const; static_assert(is_function<int (const char*, ...)>::value == true, "is_function failure"); // This is the signature of printf. #endif + + static_assert(is_function<int (float)>::value == true, "is_function failure"); + static_assert(is_function<int (float) const>::value == true, "is_function failure"); + static_assert(is_function<int(float) volatile>::value == true, "is_function failure"); + static_assert(is_function<int(float) const volatile>::value == true, "is_function failure"); + static_assert(is_function<int(float)&>::value == true, "is_function failure"); + static_assert(is_function<int(float)&&>::value == true, "is_function failure"); + static_assert(is_function<int(float) noexcept>::value == true, "is_function failure"); + static_assert(is_function<FunctionIntFloat &>::value == false, "is_function failure"); // reference to function, not a l-value reference qualified function + static_assert(is_function<FunctionIntFloat &&>::value == false, "is_function failure"); static_assert(is_function_v<void> == false, "is_function failure"); static_assert(is_function_v<FunctionVoidVoid> == true, "is_function failure"); @@ -820,6 +881,8 @@ int TestTypeTraits() static_assert(is_const<ConstVolatileIntReference>::value == false, "is_const failure"); // Note here that the int is const, not the reference to the int. EATEST_VERIFY(GetType(is_const<ConstVolatileIntReference>()) == false); + static_assert(is_const<void() const>::value == false, "is_const failure"); + EATEST_VERIFY(GetType(is_const<void() const>()) == false); // is_volatile static_assert(is_volatile<Int>::value == false, "is_volatile failure"); @@ -843,6 +906,9 @@ int TestTypeTraits() static_assert(is_volatile<ConstVolatileIntReference>::value == false, "is_volatile failure"); // Note here that the int is volatile, not the reference to the int. EATEST_VERIFY(GetType(is_volatile<ConstVolatileIntReference>()) == false); + static_assert(is_volatile<void() const>::value == false, "is_volatile failure"); + EATEST_VERIFY(GetType(is_volatile<void() const>()) == false); + // underlying_type and to_underlying #if EASTL_TYPE_TRAIT_underlying_type_CONFORMANCE && !defined(EA_COMPILER_NO_STRONGLY_TYPED_ENUMS) // If we can execute this test... @@ -1067,7 +1133,24 @@ int TestTypeTraits() static_assert(is_signed<double>::value == true, "is_signed failure "); static_assert(is_signed_v<double> == true, "is_signed failure "); EATEST_VERIFY(GetType(is_signed<double>()) == true); - + + static_assert(is_signed<char16_t>::value == false, "is_signed failure "); + static_assert(is_signed_v<char16_t> == false, "is_signed failure "); + EATEST_VERIFY(GetType(is_signed<char16_t>()) == false); + + static_assert(is_signed<char32_t>::value == false, "is_signed failure "); + static_assert(is_signed_v<char32_t> == false, "is_signed failure "); + EATEST_VERIFY(GetType(is_signed<char32_t>()) == false); + +#if EASTL_GCC_STYLE_INT128_SUPPORTED + static_assert(is_signed<__int128_t>::value == true, "is_signed failure "); + static_assert(is_signed_v<__int128_t> == true, "is_signed failure "); + EATEST_VERIFY(GetType(is_signed<__int128_t>()) == true); + + static_assert(is_signed<__uint128_t>::value == false, "is_signed failure "); + static_assert(is_signed_v<__uint128_t> == false, "is_signed failure "); + EATEST_VERIFY(GetType(is_signed<__uint128_t>()) == false); +#endif // is_unsigned static_assert(is_unsigned<unsigned int>::value == true, "is_unsigned failure "); @@ -1082,9 +1165,9 @@ int TestTypeTraits() static_assert(is_unsigned_v<int32_t> == false, "is_unsigned failure "); EATEST_VERIFY(GetType(is_unsigned<int32_t>()) == false); - static_assert(is_unsigned<bool>::value == false, "is_unsigned failure "); - static_assert(is_unsigned_v<bool> == false, "is_unsigned failure "); - EATEST_VERIFY(GetType(is_unsigned<bool>()) == false); + static_assert(is_unsigned<bool>::value == true, "is_unsigned failure "); + static_assert(is_unsigned_v<bool> == true, "is_unsigned failure "); + EATEST_VERIFY(GetType(is_unsigned<bool>()) == true); static_assert(is_unsigned<float>::value == false, "is_unsigned failure "); static_assert(is_unsigned_v<float> == false, "is_unsigned failure "); @@ -1093,6 +1176,24 @@ int TestTypeTraits() static_assert(is_unsigned<double>::value == false, "is_unsigned failure "); static_assert(is_unsigned_v<double> == false, "is_unsigned failure "); EATEST_VERIFY(GetType(is_unsigned<double>()) == false); + + static_assert(is_unsigned<char16_t>::value == true, "is_unsigned failure "); + static_assert(is_unsigned_v<char16_t> == true, "is_unsigned failure "); + EATEST_VERIFY(GetType(is_unsigned<char16_t>()) == true); + + static_assert(is_unsigned<char32_t>::value == true, "is_unsigned failure "); + static_assert(is_unsigned_v<char32_t> == true, "is_unsigned failure "); + EATEST_VERIFY(GetType(is_unsigned<char32_t>()) == true); + +#if EASTL_GCC_STYLE_INT128_SUPPORTED + static_assert(is_unsigned<__int128_t>::value == false, "is_unsigned failure "); + static_assert(is_unsigned_v<__int128_t> == false, "is_unsigned failure "); + EATEST_VERIFY(GetType(is_unsigned<__int128_t>()) == false); + + static_assert(is_unsigned<__uint128_t>::value == true, "is_unsigned failure "); + static_assert(is_unsigned_v<__uint128_t> == true, "is_unsigned failure "); + EATEST_VERIFY(GetType(is_unsigned<__uint128_t>()) == true); +#endif // is_lvalue_reference @@ -1252,6 +1353,7 @@ int TestTypeTraits() // is_trivially_copyable static_assert(is_trivially_copyable<void>::value == false, "is_trivially_copyable failure"); + EATEST_VERIFY(GetType(is_trivially_copyable<void>()) == false); static_assert(is_trivially_copyable<int>::value == true, "is_trivially_copyable failure"); static_assert(is_trivially_copyable<int*>::value == true, "is_trivially_copyable failure"); static_assert(is_trivially_copyable<int[]>::value == true, "is_trivially_copyable failure"); @@ -1395,14 +1497,16 @@ int TestTypeTraits() // is_destructible static_assert(is_destructible<int>::value == true, "is_destructible failure"); + static_assert(is_destructible<int&>::value == true, "is_destructible failure"); + static_assert(is_destructible<int&&>::value == true, "is_destructible failure"); static_assert(is_destructible<char>::value == true, "is_destructible failure"); static_assert(is_destructible<char*>::value == true, "is_destructible failure"); static_assert(is_destructible<PodA>::value == true, "is_destructible failure"); static_assert(is_destructible<void>::value == false, "is_destructible failure"); static_assert(is_destructible<int[3]>::value == true, "is_destructible failure"); static_assert(is_destructible<int[]>::value == false, "is_destructible failure"); // You can't call operator delete on this class. - static_assert(is_destructible<Abstract>::value == false, "is_destructible failure"); // You can't call operator delete on this class. - static_assert(is_destructible<AbstractWithDtor>::value == false, "is_destructible failure"); // You can't call operator delete on this class. + static_assert(is_destructible<Abstract>::value == true, "is_destructible failure"); + static_assert(is_destructible<AbstractWithDtor>::value == true, "is_destructible failure"); #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) static_assert(is_destructible<DeletedDtor>::value == false, "is_destructible failure"); // You can't call operator delete on this class. #endif @@ -1420,18 +1524,25 @@ int TestTypeTraits() static_assert(is_trivially_destructible<PodA>::value == true, "is_trivially_destructible failure"); static_assert(is_trivially_destructible<int[3]>::value == true, "is_trivially_destructible failure"); static_assert(is_trivially_destructible<int[]>::value == false, "is_trivially_destructible failure"); - static_assert(is_trivially_destructible<Abstract>::value == false, "is_trivially_destructible failure"); - static_assert(is_trivially_destructible<AbstractWithDtor>::value == false, "is_trivially_destructible failure"); + static_assert(is_trivially_destructible<Abstract>::value == true, "is_trivially_destructible failure"); + static_assert(is_trivially_destructible<AbstractWithDtor>::value == false, "is_trivially_destructible failure"); // Having a user-defined destructor make it non-trivial. + #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) static_assert(is_trivially_destructible<DeletedDtor>::value == false, "is_trivially_destructible failure"); + #endif static_assert(is_trivially_destructible<NonPod2>::value == false, "is_trivially_destructible failure"); // This case differs from is_destructible, because we have a declared destructor. #endif // is_nothrow_destructible static_assert(is_nothrow_destructible<int>::value == true, "is_nothrow_destructible failure"); - static_assert(is_nothrow_destructible<int&>::value == true, "is_nothrow_destructible failure"); - static_assert(is_nothrow_destructible<int&&>::value == true, "is_nothrow_destructible failure"); + static_assert(is_nothrow_destructible<int&>::value == true, "is_nothrow_destructible failure"); + static_assert(is_nothrow_destructible<int&&>::value == true, "is_nothrow_destructible failure"); static_assert(is_nothrow_destructible<void>::value == false, "is_nothrow_destructible failure"); + static_assert(is_nothrow_destructible<Abstract>::value == true, "is_nothrow_destructible failure"); + static_assert(is_nothrow_destructible<AbstractWithDtor>::value == true, "is_nothrow_destructible failure"); + #if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) + static_assert(is_nothrow_destructible<DeletedDtor>::value == false, "is_nothrow_destructible failure"); // You can't call operator delete on this class. + #endif #if EASTL_TYPE_TRAIT_is_nothrow_destructible_CONFORMANCE static_assert(is_nothrow_destructible<NonPod2>::value == true, "is_nothrow_destructible failure"); // NonPod2 is nothrow destructible because it has an empty destructor (makes no calls) which has no exception specification. Thus its exception specification defaults to noexcept(true) [C++11 Standard, 15.4 paragraph 14] static_assert(is_nothrow_destructible<NoThrowDestructible>::value == true, "is_nothrow_destructible failure"); @@ -1669,7 +1780,7 @@ int TestTypeTraits() static_assert(eastl::is_same_v<unsigned long, eastl::make_unsigned<unsigned long>::type>); static_assert(eastl::is_same_v<unsigned long long, eastl::make_unsigned<unsigned long long>::type>); - #if EASTL_INT128_SUPPORTED && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) + #if EASTL_GCC_STYLE_INT128_SUPPORTED static_assert(eastl::is_same_v<__uint128_t, eastl::make_unsigned<__int128_t>::type>); static_assert(eastl::is_same_v<__uint128_t, eastl::make_unsigned<__uint128_t>::type>); @@ -1680,13 +1791,18 @@ int TestTypeTraits() // Char tests static_assert(sizeof(char) == sizeof(eastl::make_signed<char>::type)); static_assert(sizeof(wchar_t) == sizeof(eastl::make_signed<wchar_t>::type)); + static_assert(sizeof(char8_t) == sizeof(eastl::make_signed<char8_t>::type)); static_assert(sizeof(char16_t) == sizeof(eastl::make_signed<char16_t>::type)); static_assert(sizeof(char32_t) == sizeof(eastl::make_signed<char32_t>::type)); static_assert(sizeof(char) == sizeof(eastl::make_unsigned<char>::type)); static_assert(sizeof(wchar_t) == sizeof(eastl::make_unsigned<wchar_t>::type)); + static_assert(sizeof(char8_t) == sizeof(eastl::make_unsigned<char8_t>::type)); static_assert(sizeof(char16_t) == sizeof(eastl::make_unsigned<char16_t>::type)); static_assert(sizeof(char32_t) == sizeof(eastl::make_unsigned<char32_t>::type)); + static_assert(eastl::is_same_v<signed char, eastl::make_signed<char8_t>::type>); + static_assert(eastl::is_same_v<unsigned char, eastl::make_unsigned<char8_t>::type>); + // Enum tests enum EnumUCharSize : unsigned char {}; enum EnumUShortSize : unsigned short {}; @@ -1833,6 +1949,28 @@ int TestTypeTraits() yValue = 3; EATEST_VERIFY(yValue == 3); + // ref to T + // -> T* + static_assert(is_same_v<add_pointer_t<int&>, int*>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<int(&)()>, int(*)()>, "add_pointer failure"); + + // object type (a (possibly cv-qualified) type other than function type, reference type or void), or + // a function type that is not cv- or ref-qualified, or a (possibly cv-qualified) void type + // -> T* + static_assert(is_same_v<add_pointer_t<int>, int*>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<int*>, int**>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<int()>, int(*)()>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<void>, void*>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<const void>, const void*>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<volatile void>, volatile void*>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<const volatile void>, const volatile void*>, "add_pointer failure"); + + // otherwise (cv- or ref-qualified function type) + // -> T + static_assert(is_same_v<add_pointer_t<int() const>, int() const>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<int() volatile>, int() volatile>, "add_pointer failure"); + static_assert(is_same_v<add_pointer_t<int() const volatile>, int() const volatile>, "add_pointer failure"); + // remove_extent // If T is an array of some type X, provides the member typedef type equal to X, otherwise // type is T. Note that if T is a multidimensional array, only the first dimension is removed. @@ -1846,6 +1984,55 @@ int TestTypeTraits() static_assert((eastl::is_same<Int2, int>::value == true), "remove_all_extents/is_same failure"); } + // add_lvalue_reference + { + // function type with no cv- or ref-qualifier + // -> T& + static_assert(is_same_v<add_lvalue_reference_t<void()>, void(&)()>, "add_lvalue_reference failure"); + + // object type (a (possibly cv-qualified) type other than function type, reference type or void) + // -> T& + static_assert(is_same_v<add_lvalue_reference_t<int>, int&>, "add_lvalue_reference failure"); + static_assert(is_same_v<add_lvalue_reference_t<const int>, const int&>, "add_lvalue_reference failure"); + + // if T is an rvalue reference (to some type U) + // -> U& + static_assert(is_same_v<add_lvalue_reference_t<int&&>, int&>, "add_lvalue_reference failure"); + + // otherwise (cv- or ref-qualified function type, or reference type, or (possibly cv-qualified) void) + // -> T + static_assert(is_same_v<add_lvalue_reference_t<void() const>, void() const>, "add_lvalue_reference failure"); + static_assert(is_same_v<add_lvalue_reference_t<void()&>, void()&>, "add_lvalue_reference failure"); + static_assert(is_same_v<add_lvalue_reference_t<void()&&>, void()&&>, "add_lvalue_reference failure"); + static_assert(is_same_v<add_lvalue_reference_t<int&>, int&>, "add_lvalue_reference failure"); + static_assert(is_same_v<add_lvalue_reference_t<const int&>, const int&>, "add_lvalue_reference failure"); + static_assert(is_same_v<add_lvalue_reference_t<void>, void>, "add_lvalue_reference failure"); + static_assert(is_same_v<add_lvalue_reference_t<const void>, const void>, "add_lvalue_reference failure"); + } + + // add_rvalue_reference + { + // function type with no cv- or ref-qualifier + // -> T&& + static_assert(is_same_v<add_rvalue_reference_t<void()>, void(&&)()>, "add_rvalue_reference failure"); + + // object type (a (possibly cv-qualified) type other than function type, reference type or void) + // -> T&& + static_assert(is_same_v<add_rvalue_reference_t<int>, int&&>, "add_rvalue_reference failure"); + static_assert(is_same_v<add_rvalue_reference_t<const int>, const int&&>, "add_rvalue_reference failure"); + + // otherwise (cv- or ref-qualified function type, or reference type, or (possibly cv-qualified) void) + // -> T + static_assert(is_same_v<add_rvalue_reference_t<void() const>, void() const>, "add_rvalue_reference failure"); + static_assert(is_same_v<add_rvalue_reference_t<void()&>, void()&>, "add_rvalue_reference failure"); + static_assert(is_same_v<add_rvalue_reference_t<void()&&>, void()&&>, "add_rvalue_reference failure"); + static_assert(is_same_v<add_rvalue_reference_t<int&>, int&>, "add_rvalue_reference failure"); + static_assert(is_same_v<add_rvalue_reference_t<int&&>, int&&>, "add_rvalue_reference failure"); + static_assert(is_same_v<add_rvalue_reference_t<const int&>, const int&>, "add_rvalue_reference failure"); + static_assert(is_same_v<add_rvalue_reference_t<void>, void>, "add_rvalue_reference failure"); + static_assert(is_same_v<add_rvalue_reference_t<const void>, const void>, "add_rvalue_reference failure"); + } + // decay { @@ -1979,26 +2166,71 @@ int TestTypeTraits() } // void_t - #if EASTL_VARIABLE_TEMPLATES_ENABLED { { - static_assert(is_same_v<void_t<void>, void>, "void_t failure"); - static_assert(is_same_v<void_t<int>, void>, "void_t failure"); - static_assert(is_same_v<void_t<short>, void>, "void_t failure"); - static_assert(is_same_v<void_t<long>, void>, "void_t failure"); - static_assert(is_same_v<void_t<long long>, void>, "void_t failure"); - static_assert(is_same_v<void_t<ClassEmpty>, void>, "void_t failure"); - static_assert(is_same_v<void_t<ClassNonEmpty>, void>, "void_t failure"); - static_assert(is_same_v<void_t<vector<int>>, void>, "void_t failure"); + static_assert(is_same<void_t<void>, void>::value, "void_t failure"); + static_assert(is_same<void_t<int>, void>::value, "void_t failure"); + static_assert(is_same<void_t<short>, void>::value, "void_t failure"); + static_assert(is_same<void_t<long>, void>::value, "void_t failure"); + static_assert(is_same<void_t<long long>, void>::value, "void_t failure"); + static_assert(is_same<void_t<ClassEmpty>, void>::value, "void_t failure"); + static_assert(is_same<void_t<ClassNonEmpty>, void>::value, "void_t failure"); + static_assert(is_same<void_t<vector<int>>, void>::value, "void_t failure"); } // new sfinae mechansim test { - static_assert(has_increment_operator<HasIncrementOperator>::value, "void_t sfinae failure"); - static_assert(!has_increment_operator<ClassEmpty>::value, "void_t sfinae failure"); + static_assert(has_increment_operator_using_void_t<HasIncrementOperator>::value, "void_t sfinae failure"); + static_assert(!has_increment_operator_using_void_t<ClassEmpty>::value, "void_t sfinae failure"); } } + + // detected idiom + { + static_assert(is_detected<has_increment_operator_detection, HasIncrementOperator>::value, "is_detected failure."); + static_assert(!is_detected<has_increment_operator_detection, ClassEmpty>::value, "is_detected failure."); + + static_assert(is_same<detected_t<has_increment_operator_detection, HasIncrementOperator>, HasIncrementOperator&>::value, "is_detected_t failure."); + static_assert(is_same<detected_t<has_increment_operator_detection, ClassEmpty>, nonesuch>::value, "is_detected_t failure."); + + using detected_or_positive_result = detected_or<float, has_increment_operator_detection, HasIncrementOperator>; + using detected_or_negative_result = detected_or<float, has_increment_operator_detection, ClassEmpty>; + static_assert(detected_or_positive_result::value_t::value, "detected_or failure."); + static_assert(!detected_or_negative_result::value_t::value, "detected_or failure."); + static_assert(is_same<detected_or_positive_result::type, HasIncrementOperator&>::value, "detected_or failure."); + static_assert(is_same<detected_or_negative_result::type, float>::value, "detected_or failure."); + + static_assert(is_same<detected_or_t<float, has_increment_operator_detection, HasIncrementOperator>, HasIncrementOperator&>::value, "detected_or_t failure."); + static_assert(is_same<detected_or_t<float, has_increment_operator_detection, ClassEmpty>, float>::value, "detected_or_t failure."); + + static_assert(is_detected_exact<HasIncrementOperator&, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_exact failure."); + static_assert(!is_detected_exact<float, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_exact failure."); + static_assert(is_detected_exact<nonesuch, has_increment_operator_detection, ClassEmpty>::value, "is_detected_exact failure."); + static_assert(!is_detected_exact<float, has_increment_operator_detection, ClassEmpty>::value, "is_detected_exact failure."); + + static_assert(is_detected_convertible<HasIncrementOperator&, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_convertible failure."); + static_assert(is_detected_convertible<HasIncrementOperator, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_convertible failure."); + static_assert(!is_detected_convertible<float, has_increment_operator_detection, HasIncrementOperator>::value, "is_detected_convertible failure."); + static_assert(!is_detected_convertible<nonesuch, has_increment_operator_detection, ClassEmpty>::value, "is_detected_convertible failure."); + static_assert(!is_detected_convertible<float, has_increment_operator_detection, ClassEmpty>::value, "is_detected_convertible failure."); + + + #if EASTL_VARIABLE_TEMPLATES_ENABLED + static_assert(is_detected_v<has_increment_operator_detection, HasIncrementOperator>, "is_detected_v failure."); + static_assert(!is_detected_v<has_increment_operator_detection, ClassEmpty>, "is_detected_v failure."); + + static_assert(is_detected_exact_v<HasIncrementOperator&, has_increment_operator_detection, HasIncrementOperator>, "is_detected_exact_v failure."); + static_assert(!is_detected_exact_v<float, has_increment_operator_detection, HasIncrementOperator>, "is_detected_exact_v failure."); + static_assert(is_detected_exact_v<nonesuch, has_increment_operator_detection, ClassEmpty>, "is_detected_exact_v failure."); + static_assert(!is_detected_exact_v<float, has_increment_operator_detection, ClassEmpty>, "is_detected_exact_v failure."); + + static_assert(is_detected_convertible_v<HasIncrementOperator&, has_increment_operator_detection, HasIncrementOperator>, "is_detected_convertible_v failure."); + static_assert(is_detected_convertible_v<HasIncrementOperator, has_increment_operator_detection, HasIncrementOperator>, "is_detected_convertible_v failure."); + static_assert(!is_detected_convertible_v<float, has_increment_operator_detection, HasIncrementOperator>, "is_detected_convertible_v failure."); + static_assert(!is_detected_convertible_v<nonesuch, has_increment_operator_detection, ClassEmpty>, "is_detected_convertible_v failure."); + static_assert(!is_detected_convertible_v<float, has_increment_operator_detection, ClassEmpty>, "is_detected_convertible_v failure."); #endif + } // conjunction { @@ -2160,8 +2392,10 @@ int TestTypeTraits() static_assert(!is_aggregate_v<NotAggregrate>, "is_aggregate failure"); } - #ifndef EA_COMPILER_MSVC - // NOTE(rparolin): MSVC is incorrectly categorizing the aggregate type in this test-case. + #if defined(EA_COMPILER_CPP11_ENABLED) && !defined(EA_COMPILER_CPP14_ENABLED) + // See https://en.cppreference.com/w/cpp/language/aggregate_initialization + // In C++11 the requirement was added to aggregate types that no default member initializers exist, + // however this requirement was removed in C++14. { struct NotAggregrate { int data = 42; }; // default member initializer static_assert(!is_aggregate_v<NotAggregrate>, "is_aggregate failure"); diff --git a/EASTL/test/source/TestUtility.cpp b/EASTL/test/source/TestUtility.cpp index 363f409..e9027e5 100644 --- a/EASTL/test/source/TestUtility.cpp +++ b/EASTL/test/source/TestUtility.cpp @@ -108,7 +108,7 @@ static int TestUtilityPair() EATEST_VERIFY((p2.first == 0) && (p2.second == 1.f)); pair<const char*, int> p3 = eastl::make_pair("a", 1); - EATEST_VERIFY((EA::StdC::Strcmp(p3.first, "a") == 0) && (p2.second == 1)); + EATEST_VERIFY((EA::StdC::Strcmp(p3.first, "a") == 0) && (p3.second == 1)); pair<const char*, int> p4 = eastl::make_pair<const char*, int>("a", 1); EATEST_VERIFY((EA::StdC::Strcmp(p4.first, "a") == 0) && (p4.second == 1)); @@ -116,6 +116,20 @@ static int TestUtilityPair() pair<int, const char*> p5 = eastl::make_pair<int, const char*>(1, "b"); EATEST_VERIFY((p5.first == 1) && (EA::StdC::Strcmp(p5.second, "b") == 0)); +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + pair<int, int> p6 = eastl::make_pair<int, int>(1, 2); + pair<int, int> p7 = eastl::make_pair<int, int>(2, 1); + pair<int, int> p8 = eastl::make_pair<int, int>(7, 8); + pair<int, int> p9 = eastl::make_pair<int, int>(10, 1); + + EATEST_VERIFY( (p6 <=> p7) != 0); + EATEST_VERIFY( (p6 <=> p6) == 0); + EATEST_VERIFY( (p7 <=> p8) < 0); + EATEST_VERIFY( (p7 <=> p8) <= 0); + EATEST_VERIFY( (p9 <=> p8) > 0); + EATEST_VERIFY( (p9 <=> p8) >= 0); +#endif + #if !defined(EA_COMPILER_NO_AUTO) auto p60 = eastl::make_pair("a", "b"); // Different strings of same length of 1. EATEST_VERIFY((EA::StdC::Strcmp(p60.first, "a") == 0) && (EA::StdC::Strcmp(p60.second, "b") == 0)); @@ -495,13 +509,15 @@ static int TestUtilityIntegerSequence() using namespace eastl; int nErrorCount = 0; #if EASTL_VARIADIC_TEMPLATES_ENABLED -// Android clang chokes with an internal compiler error on make_integer_sequence -#if !defined(EA_PLATFORM_ANDROID) + EATEST_VERIFY((integer_sequence<int, 0, 1, 2, 3, 4>::size() == 5)); EATEST_VERIFY((make_integer_sequence<int, 5>::size() == 5)); -#endif + static_assert(is_same<make_integer_sequence<int, 5>, integer_sequence<int, 0, 1, 2, 3, 4>>::value); + EATEST_VERIFY((index_sequence<0, 1, 2, 3, 4>::size() == 5)); EATEST_VERIFY((make_index_sequence<5>::size() == 5)); + static_assert(is_same<make_index_sequence<5>, index_sequence<0, 1, 2, 3, 4>>::value); + static_assert(is_same<make_index_sequence<5>, integer_sequence<size_t, 0, 1, 2, 3, 4>>::value); #endif // EASTL_VARIADIC_TEMPLATES_ENABLED return nErrorCount; @@ -614,6 +630,271 @@ static int TestUtilityExchange() return nErrorCount; } +#if defined(EA_COMPILER_CPP20_ENABLED) +template <typename T> +static int TestCmpCommon() +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::cmp_equal(T(0), T(0))); + EATEST_VERIFY(eastl::cmp_equal(T(1), T(1))); + EATEST_VERIFY(eastl::cmp_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min())); + EATEST_VERIFY(eastl::cmp_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max())); + EATEST_VERIFY(!eastl::cmp_equal(T(0), T(1))); + EATEST_VERIFY(!eastl::cmp_equal(T(1), T(0))); + if (eastl::is_signed_v<T>) + { + EATEST_VERIFY(eastl::cmp_equal(T(-1), T(-1))); + EATEST_VERIFY(!eastl::cmp_equal(T(-1), T(-2))); + EATEST_VERIFY(!eastl::cmp_equal(T(-2), T(-1))); + } + + EATEST_VERIFY(eastl::cmp_not_equal(T(1), T(0))); + EATEST_VERIFY(eastl::cmp_not_equal(T(0), T(1))); + EATEST_VERIFY(eastl::cmp_not_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max())); + EATEST_VERIFY(eastl::cmp_not_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min())); + if (eastl::is_signed_v<T>) + { + EATEST_VERIFY(!eastl::cmp_not_equal(T(-1), T(-1))); + EATEST_VERIFY(eastl::cmp_not_equal(T(-1), T(-2))); + EATEST_VERIFY(eastl::cmp_not_equal(T(-2), T(-1))); + } + + EATEST_VERIFY(eastl::cmp_less(T(0), T(1))); + EATEST_VERIFY(eastl::cmp_less(T(5), T(10))); + EATEST_VERIFY(!eastl::cmp_less(T(0), T(0))); + EATEST_VERIFY(!eastl::cmp_less(T(1), T(0))); + EATEST_VERIFY(eastl::cmp_less(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max())); + EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min())); + EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max())); + EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min())); + if (eastl::is_signed_v<T>) + { + EATEST_VERIFY(!eastl::cmp_less(T(-1), T(-1))); + EATEST_VERIFY(!eastl::cmp_less(T(-1), T(-2))); + EATEST_VERIFY(eastl::cmp_less(T(-2), T(-1))); + } + + EATEST_VERIFY(eastl::cmp_less_equal(T(0), T(1))); + EATEST_VERIFY(eastl::cmp_less_equal(T(5), T(10))); + EATEST_VERIFY(eastl::cmp_less_equal(T(0), T(0))); + EATEST_VERIFY(eastl::cmp_less_equal(T(1), T(1))); + EATEST_VERIFY(!eastl::cmp_less_equal(T(1), T(0))); + EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max())); + EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min())); + EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max())); + EATEST_VERIFY(!eastl::cmp_less_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min())); + if (eastl::is_signed_v<T>) + { + EATEST_VERIFY(eastl::cmp_less_equal(T(-1), T(-1))); + EATEST_VERIFY(!eastl::cmp_less_equal(T(-1), T(-2))); + EATEST_VERIFY(eastl::cmp_less_equal(T(-2), T(-1))); + } + + EATEST_VERIFY(eastl::cmp_greater(T(1), T(0))); + EATEST_VERIFY(eastl::cmp_greater(T(10), T(5))); + EATEST_VERIFY(!eastl::cmp_greater(T(0), T(0))); + EATEST_VERIFY(!eastl::cmp_greater(T(0), T(1))); + EATEST_VERIFY(eastl::cmp_greater(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min())); + EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min())); + EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max())); + EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max())); + if (eastl::is_signed_v<T>) + { + EATEST_VERIFY(!eastl::cmp_greater(T(-1), T(-1))); + EATEST_VERIFY(eastl::cmp_greater(T(-1), T(-2))); + EATEST_VERIFY(!eastl::cmp_greater(T(-2), T(-1))); + } + + EATEST_VERIFY(eastl::cmp_greater_equal(T(1), T(0))); + EATEST_VERIFY(eastl::cmp_greater_equal(T(10), T(5))); + EATEST_VERIFY(eastl::cmp_greater_equal(T(0), T(0))); + EATEST_VERIFY(!eastl::cmp_greater_equal(T(0), T(1))); + EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min())); + EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min())); + EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max())); + EATEST_VERIFY(!eastl::cmp_greater_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max())); + if (eastl::is_signed_v<T>) + { + EATEST_VERIFY(eastl::cmp_greater_equal(T(-1), T(-1))); + EATEST_VERIFY(eastl::cmp_greater_equal(T(-1), T(-2))); + EATEST_VERIFY(!eastl::cmp_greater_equal(T(-2), T(-1))); + } + + return nErrorCount; +} + +template <typename T, typename U> +static int TestUtilityCmpEql(const T x, const U y) +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::cmp_equal(T(x), U(y))); + EATEST_VERIFY(eastl::cmp_equal(U(y), T(x))); + EATEST_VERIFY(!eastl::cmp_not_equal(T(x), U(y))); + EATEST_VERIFY(!eastl::cmp_not_equal(U(y), T(x))); + + return nErrorCount; +} + +template <typename T, typename U> +static int TestUtilityCmpLess(const T x, const U y) +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::cmp_less(T(x), U(y))); + EATEST_VERIFY(!eastl::cmp_less(U(y), T(x))); + + EATEST_VERIFY(!eastl::cmp_greater_equal(T(x), U(y))); + EATEST_VERIFY(eastl::cmp_greater_equal(U(y), T(x))); + + return nErrorCount; +} + +template <typename T, typename U> +static int TestUtilityCmpGreater(const T x, const U y) +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::cmp_greater(T(x), U(y))); + EATEST_VERIFY(!eastl::cmp_greater(U(y), T(x))); + + EATEST_VERIFY(!eastl::cmp_less_equal(T(x), U(y))); + EATEST_VERIFY(eastl::cmp_less_equal(U(y), T(x))); + + return nErrorCount; +} + +template <typename T, typename U> +static int TestUtilityCmpLessEq(const T x, const U y) +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::cmp_less_equal(T(x), U(y))); + EATEST_VERIFY(eastl::cmp_less(T(x), U(y)) || eastl::cmp_equal(T(x), U(y))); + + EATEST_VERIFY(eastl::cmp_greater_equal(U(y), T(x))); + + return nErrorCount; +} + +template <typename T, typename U> +static int TestUtilityCmpGreaterEq(const T x, const U y) +{ + int nErrorCount = 0; + + EATEST_VERIFY(eastl::cmp_greater_equal(T(x), U(y))); + EATEST_VERIFY(eastl::cmp_greater(T(x), U(y)) || eastl::cmp_equal(T(x), U(y))); + + EATEST_VERIFY(eastl::cmp_less_equal(U(y), T(x))); + + return nErrorCount; +} + +static int TestUtilityIntegralComp() +{ + int nErrorCount = 0; + + // Test integral comparisons among same types + nErrorCount += TestCmpCommon<int>(); + nErrorCount += TestCmpCommon<short>(); + nErrorCount += TestCmpCommon<long>(); + nErrorCount += TestCmpCommon<long long>(); + + nErrorCount += TestCmpCommon<unsigned int>(); + nErrorCount += TestCmpCommon<unsigned short>(); + nErrorCount += TestCmpCommon<unsigned long>(); + nErrorCount += TestCmpCommon<unsigned long long>(); + + // Test integral comparison among different types + nErrorCount += TestUtilityCmpEql(int(0), short(0)); + nErrorCount += TestUtilityCmpEql(short(2), long(2)); + nErrorCount += TestUtilityCmpEql(short(3), unsigned long(3)); + nErrorCount += TestUtilityCmpEql(int(-5), long long(-5)); + nErrorCount += TestUtilityCmpEql(short(-100), long long(-100)); + nErrorCount += TestUtilityCmpEql(unsigned int(100), long(100)); + nErrorCount += TestUtilityCmpEql(unsigned long long(100), int(100)); + + nErrorCount += TestUtilityCmpLess(int(0), long long(1)); + nErrorCount += TestUtilityCmpLess(int(-1), unsigned long(1)); + nErrorCount += TestUtilityCmpLess(short(-100), long long(100)); + nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<long>::min(), short(0)); + nErrorCount += TestUtilityCmpLess(short(0), eastl::numeric_limits<int>::max()); + nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<unsigned short>::min(), eastl::numeric_limits<int>::max()); + nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<short>::max(), eastl::numeric_limits<long>::max()); + nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<int>::max(), eastl::numeric_limits<long long>::max()); + nErrorCount += TestUtilityCmpLess(int(-100), unsigned int(0)); + nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<int>::min(), eastl::numeric_limits<unsigned int>::min()); + + nErrorCount += TestUtilityCmpGreater(int(1), short(0)); + nErrorCount += TestUtilityCmpGreater(unsigned long(1), int(-1)); + nErrorCount += TestUtilityCmpGreater(unsigned long long(100), short(-100)); + nErrorCount += TestUtilityCmpGreater(short(0), eastl::numeric_limits<short>::min()); + nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long>::max(), unsigned short(5)); + nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long>::max(), eastl::numeric_limits<int>::min()); + nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::max()); + nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long long>::max(), eastl::numeric_limits<int>::max()); + nErrorCount += TestUtilityCmpGreater(unsigned int(0), int(-100)); + nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<unsigned int>::min(), eastl::numeric_limits<int>::min()); + + nErrorCount += TestUtilityCmpLessEq(int(0), short(1)); + nErrorCount += TestUtilityCmpLessEq(int(-1), long long(-1)); + nErrorCount += TestUtilityCmpLessEq(short(-100), unsigned long long(100)); + nErrorCount += TestUtilityCmpLessEq(short(-100), long long(-100)); + nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::min(), short(0)); + nErrorCount += TestUtilityCmpLessEq(short(0), eastl::numeric_limits<int>::max()); + nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<short>::min(), eastl::numeric_limits<short>::min()); + nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<int>::max()); + nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<long long>::max()); + nErrorCount += TestUtilityCmpLessEq(int(50), unsigned int(50)); + nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::min(), eastl::numeric_limits<unsigned int>::min()); + + nErrorCount += TestUtilityCmpGreaterEq(int(1), short(1)); + nErrorCount += TestUtilityCmpGreaterEq(long long(-1), int(-1)); + nErrorCount += TestUtilityCmpGreaterEq(long long(-100), short(-100)); + nErrorCount += TestUtilityCmpGreaterEq(short(0), long(0)); + nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<long>::max(), eastl::numeric_limits<long>::max()); + nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::min()); + nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::max()); + nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<long long>::max(), eastl::numeric_limits<int>::max()); + nErrorCount += TestUtilityCmpGreaterEq(unsigned int(0), int(0)); + nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<unsigned int>::min(), eastl::numeric_limits<int>::min()); + + // Test in_range + EATEST_VERIFY(eastl::in_range<int>(0)); + EATEST_VERIFY(eastl::in_range<int>(eastl::numeric_limits<int>::min())); + EATEST_VERIFY(eastl::in_range<int>(eastl::numeric_limits<int>::max())); + EATEST_VERIFY(eastl::in_range<unsigned int>(0)); + EATEST_VERIFY(eastl::in_range<unsigned int>(eastl::numeric_limits<unsigned int>::min())); + EATEST_VERIFY(eastl::in_range<unsigned int>(eastl::numeric_limits<unsigned int>::max())); + EATEST_VERIFY(!eastl::in_range<unsigned int>(-1)); + EATEST_VERIFY(!eastl::in_range<int>(eastl::numeric_limits<unsigned int>::max())); + EATEST_VERIFY(!eastl::in_range<unsigned int>(eastl::numeric_limits<int>::min())); + + EATEST_VERIFY(eastl::in_range<short>(100)); + EATEST_VERIFY(eastl::in_range<short>(eastl::numeric_limits<short>::min())); + EATEST_VERIFY(eastl::in_range<short>(eastl::numeric_limits<short>::max())); + EATEST_VERIFY(eastl::in_range<unsigned short>(100)); + EATEST_VERIFY(eastl::in_range<unsigned short>(eastl::numeric_limits<unsigned short>::min())); + EATEST_VERIFY(eastl::in_range<unsigned short>(eastl::numeric_limits<unsigned short>::max())); + EATEST_VERIFY(!eastl::in_range<unsigned short>(-1)); + EATEST_VERIFY(!eastl::in_range<short>(eastl::numeric_limits<unsigned int>::max())); + EATEST_VERIFY(!eastl::in_range<unsigned short>(eastl::numeric_limits<int>::min())); + + EATEST_VERIFY(eastl::in_range<long>(50)); + EATEST_VERIFY(eastl::in_range<long>(eastl::numeric_limits<long>::min())); + EATEST_VERIFY(eastl::in_range<long>(eastl::numeric_limits<long>::max())); + EATEST_VERIFY(eastl::in_range<unsigned long>(50)); + EATEST_VERIFY(eastl::in_range<unsigned long>(eastl::numeric_limits<unsigned long>::min())); + EATEST_VERIFY(eastl::in_range<unsigned long>(eastl::numeric_limits<unsigned long>::max())); + EATEST_VERIFY(!eastl::in_range<unsigned long>(-1)); + EATEST_VERIFY(!eastl::in_range<long>(eastl::numeric_limits<unsigned int>::max())); + EATEST_VERIFY(!eastl::in_range<unsigned long>(eastl::numeric_limits<int>::min())); + + return nErrorCount; +} +#endif + /////////////////////////////////////////////////////////////////////////////// // TestUtility // @@ -627,6 +908,8 @@ int TestUtility() nErrorCount += TestUtilityMove(); nErrorCount += TestUtilityIntegerSequence(); nErrorCount += TestUtilityExchange(); - +#if defined(EA_COMPILER_CPP20_ENABLED) + nErrorCount += TestUtilityIntegralComp(); +#endif return nErrorCount; } diff --git a/EASTL/test/source/TestVariant.cpp b/EASTL/test/source/TestVariant.cpp index a8197e5..2a78a89 100644 --- a/EASTL/test/source/TestVariant.cpp +++ b/EASTL/test/source/TestVariant.cpp @@ -7,6 +7,7 @@ #include <EASTL/string.h> #include <EASTL/algorithm.h> #include <EASTL/sort.h> +#include <EASTL/bonus/overloaded.h> #ifdef EA_COMPILER_CPP14_ENABLED #include "ConceptImpls.h" @@ -291,7 +292,7 @@ int TestVariantHoldsAlternative() VERIFY(!holds_alternative<long>(v)); // Verify that a query for a T not in the variant typelist returns false. VERIFY(!holds_alternative<string>(v)); // Verify that a query for a T not in the variant typelist returns false. - VERIFY(!holds_alternative<int>(v)); // variant does not hold an int + VERIFY(!holds_alternative<int>(v)); // variant does not hold an int VERIFY(!holds_alternative<short>(v)); // variant does not hold a short } @@ -377,7 +378,7 @@ int TestVariantValuelessByException() VERIFY(!v.valueless_by_exception()); } - // TODO(rparolin): review exception safety for variant types + // TODO(rparolin): review exception safety for variant types // // { // #if EASTL_EXCEPTIONS_ENABLED @@ -563,12 +564,12 @@ int TestVariantSwap() v1.swap(v2); - VERIFY(get<int>(v1) == 24); + VERIFY(get<int>(v1) == 24); VERIFY(get<int>(v2) == 42); v1.swap(v2); - VERIFY(get<int>(v1) == 42); + VERIFY(get<int>(v1) == 42); VERIFY(get<int>(v2) == 24); } @@ -576,13 +577,13 @@ int TestVariantSwap() variant<string> v1 = "Hello"; variant<string> v2 = "World"; - VERIFY(get<string>(v1) == "Hello"); + VERIFY(get<string>(v1) == "Hello"); VERIFY(get<string>(v2) == "World"); v1.swap(v2); VERIFY(get<string>(v1) == "World"); - VERIFY(get<string>(v2) == "Hello"); + VERIFY(get<string>(v2) == "Hello"); } return nErrorCount; @@ -657,7 +658,7 @@ EA_NO_INLINE int TestVariantVisitNoInline(const eastl::variant<int, bool, unsign struct MyVisitor { MyVisitor() = delete; - MyVisitor(bool& b) : mVisited(b) {} + MyVisitor(bool& visited) : mVisited(visited) {}; void operator()(int) { mVisited = true; } void operator()(bool) { mVisited = true; } @@ -666,7 +667,7 @@ EA_NO_INLINE int TestVariantVisitNoInline(const eastl::variant<int, bool, unsign bool& mVisited; }; - eastl::visit(MyVisitor{bVisited}, v); + eastl::visit(MyVisitor(bVisited), v); EATEST_VERIFY(bVisited); @@ -682,7 +683,7 @@ EA_NO_INLINE int TestVariantVisit2NoInline(const eastl::variant<int, bool>& v0, struct MyVisitor { MyVisitor() = delete; - MyVisitor(bool& b) : mVisited(b) {} + MyVisitor(bool& visited) : mVisited(visited) {}; void operator()(int, int) { mVisited = true; } void operator()(bool, int) { mVisited = true; } @@ -692,7 +693,7 @@ EA_NO_INLINE int TestVariantVisit2NoInline(const eastl::variant<int, bool>& v0, bool& mVisited; }; - eastl::visit(MyVisitor{bVisited}, v0, v1); + eastl::visit(MyVisitor(bVisited), v0, v1); EATEST_VERIFY(bVisited); @@ -708,7 +709,7 @@ EA_NO_INLINE int TestVariantVisit3tNoInline(const eastl::variant<int, bool>& v0, struct MyVisitor { MyVisitor() = delete; - MyVisitor(bool& b) : mVisited(b) {} + MyVisitor(bool& visited) : mVisited(visited) {}; void operator()(int, int, int) { mVisited = true; } void operator()(bool, int, int) { mVisited = true; } @@ -723,38 +724,101 @@ EA_NO_INLINE int TestVariantVisit3tNoInline(const eastl::variant<int, bool>& v0, bool& mVisited; }; - eastl::visit(MyVisitor{bVisited}, v0, v1, v2); + eastl::visit(MyVisitor(bVisited), v0, v1, v2); EATEST_VERIFY(bVisited); return nErrorCount; } -int TestVariantVisitor() +int TestVariantVisitorOverloaded() { using namespace eastl; int nErrorCount = 0; using v_t = variant<int, string, double, long>; + v_t arr[] = {42, "jean", 42.0, 42L}; + v_t v{42.0}; + + + #ifdef __cpp_deduction_guides + { + int count = 0; + + for (auto& e : arr) + { + eastl::visit( + overloaded{ + [&](int) { count++; }, + [&](string) { count++; }, + [&](double) { count++; }, + [&](long) { count++; }}, + e + ); + } + + VERIFY(count == EAArrayCount(arr)); + } + + { + double visitedValue = 0.0f; + + eastl::visit( + overloaded{ + [](int) { }, + [](string) { }, + [&](double d) { visitedValue = d; }, + [](long) { }}, + v + ); + + VERIFY(visitedValue == 42.0f); + } + + #endif + + { + int count = 0; + + for (auto& e : arr) + { + eastl::visit( + eastl::make_overloaded( + [&](int) { count++; }, + [&](string) { count++; }, + [&](double) { count++; }, + [&](long) { count++; }), + e + ); + } - // TODO(rparolin): When we have a C++17 compiler - // - // template deduction guides test - // template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; }; - // template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>; + VERIFY(count == EAArrayCount(arr)); + } + + { + double visitedValue = 0.0f; - // { - // v_t arr[] = {42, "rob", 42.0, 42L}; + eastl::visit( + eastl::make_overloaded( + [](int) { }, + [](string) { }, + [&](double d) { visitedValue = d; }, + [](long) { }), + v + ); - // int count = 0; - // for (auto& e : arr) - // { - // eastl::visit(overloaded{[&](int) { count++; }, - // [&](string) { count++; }, - // [&](double) { count++; }, - // [&](long) { count++; }}, e); - // } - // } + VERIFY(visitedValue == 42.0f); + } + + return nErrorCount; +} + +int TestVariantVisitor() +{ + using namespace eastl; + int nErrorCount = 0; + + using v_t = variant<int, string, double, long>; { v_t arr[] = {42, "hello", 42.0, 42L}; @@ -982,7 +1046,7 @@ int TestVariantVisitor() struct MultipleVisitor { MultipleVisitor() = delete; - MultipleVisitor(bool& b) : mVisited(b) {} + MultipleVisitor(bool& visited) : mVisited(visited) {}; void operator()(int, int) { mVisited = true; } void operator()(int, bool) {} @@ -992,11 +1056,11 @@ int TestVariantVisitor() bool& mVisited; }; - visit(MultipleVisitor{bVisited}, v0, v1); + visit(MultipleVisitor(bVisited), v0, v1); EATEST_VERIFY(bVisited); bVisited = false; - visit<void>(MultipleVisitor{bVisited}, v0, v1); + visit<void>(MultipleVisitor(bVisited), v0, v1); EATEST_VERIFY(bVisited); } @@ -1742,6 +1806,7 @@ int TestVariant() nErrorCount += TestVariantEmplace(); nErrorCount += TestVariantRelOps(); nErrorCount += TestVariantInplaceCtors(); + nErrorCount += TestVariantVisitorOverloaded(); nErrorCount += TestVariantVisitor(); nErrorCount += TestVariantAssignment(); nErrorCount += TestVariantMoveOnly(); @@ -1756,13 +1821,3 @@ int TestVariant() #else int TestVariant() { return 0; } #endif - - - - - - - - - - diff --git a/EASTL/test/source/TestVector.cpp b/EASTL/test/source/TestVector.cpp index 0fe719d..69cdb52 100644 --- a/EASTL/test/source/TestVector.cpp +++ b/EASTL/test/source/TestVector.cpp @@ -1258,6 +1258,84 @@ int TestVector() EATEST_VERIFY(!(intArray1 > intArray2)); } + // three way comparison operator +#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) + { + using namespace eastl; + + vector<int> intArray1(10); + vector<int> intArray2(10); + + for (i = 0; i < intArray1.size(); i++) + { + intArray1[i] = (int)i; // Make intArray1 equal to intArray2. + intArray2[i] = (int)i; + } + + // Verify equality between intArray1 and intArray2 + EATEST_VERIFY((intArray1 <=> intArray2) == 0); + EATEST_VERIFY(!((intArray1 <=> intArray2) != 0)); + EATEST_VERIFY((intArray1 <=> intArray2) <= 0); + EATEST_VERIFY((intArray1 <=> intArray2) >= 0); + EATEST_VERIFY(!((intArray1 <=> intArray2) < 0)); + EATEST_VERIFY(!((intArray1 <=> intArray2) > 0)); + + intArray1.push_back(100); // Make intArray1 less than intArray2. + intArray2.push_back(101); + + // Verify intArray1 < intArray2 + EATEST_VERIFY(!((intArray1 <=> intArray2) == 0)); + EATEST_VERIFY((intArray1 <=> intArray2) != 0); + EATEST_VERIFY((intArray1 <=> intArray2) <= 0); + EATEST_VERIFY(!((intArray1 <=> intArray2) >= 0)); + EATEST_VERIFY(((intArray1 <=> intArray2) < 0)); + EATEST_VERIFY(!((intArray1 <=> intArray2) > 0)); + + for (i = 0; i < 3; i++) // Make the length of intArray2 less than intArray1 + intArray2.pop_back(); + + // Verify intArray2.size() < intArray1.size() and intArray2 is a subset of intArray1 + EATEST_VERIFY(!((intArray1 <=> intArray2) == 0)); + EATEST_VERIFY((intArray1 <=> intArray2) != 0); + EATEST_VERIFY((intArray1 <=> intArray2) >= 0); + EATEST_VERIFY(!((intArray1 <=> intArray2) <= 0)); + EATEST_VERIFY(((intArray1 <=> intArray2) > 0)); + EATEST_VERIFY(!((intArray1 <=> intArray2) < 0)); + } + + { + using namespace eastl; + + vector<int> intArray1 = {1, 2, 3, 4, 5, 6, 7}; + vector<int> intArray2 = {7, 6, 5, 4, 3, 2, 1}; + vector<int> intArray3 = {1, 2, 3, 4}; + + struct weak_ordering_vector + { + vector<int> vec; + inline std::weak_ordering operator<=>(const weak_ordering_vector& b) const { return vec <=> b.vec; } + }; + + EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray1}, weak_ordering_vector{intArray2}) == std::weak_ordering::less); + EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray3}, weak_ordering_vector{intArray1}) == std::weak_ordering::less); + EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray2}, weak_ordering_vector{intArray1}) == std::weak_ordering::greater); + EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray2}, weak_ordering_vector{intArray3}) == std::weak_ordering::greater); + EATEST_VERIFY(synth_three_way{}(weak_ordering_vector{intArray1}, weak_ordering_vector{intArray1}) == std::weak_ordering::equivalent); + + struct strong_ordering_vector + { + vector<int> vec; + inline std::strong_ordering operator<=>(const strong_ordering_vector& b) const { return vec <=> b.vec; } + }; + + EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray1}, strong_ordering_vector{intArray2}) == std::strong_ordering::less); + EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray3}, strong_ordering_vector{intArray1}) == std::strong_ordering::less); + EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray2}, strong_ordering_vector{intArray1}) == std::strong_ordering::greater); + EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray2}, strong_ordering_vector{intArray3}) == std::strong_ordering::greater); + EATEST_VERIFY(synth_three_way{}(strong_ordering_vector{intArray1}, strong_ordering_vector{intArray1}) == std::strong_ordering::equal); + } +#endif + { using namespace eastl; @@ -1317,7 +1395,7 @@ int TestVector() eastl::vector<TestObject> toTest; // InputIterator - demoted_iterator<TestObject*, eastl::forward_iterator_tag> toInput(&to); + demoted_iterator<TestObject*, EASTL_ITC_NS::forward_iterator_tag> toInput(&to); toTest.assign(toInput, toInput); // ForwardIterator @@ -1637,7 +1715,7 @@ int TestVector() { struct iterator { - typedef eastl::input_iterator_tag iterator_category; + typedef EASTL_ITC_NS::input_iterator_tag iterator_category; typedef int value_type; typedef ptrdiff_t difference_type; typedef int* pointer; @@ -1718,20 +1796,24 @@ int TestVector() { eastl::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - eastl::erase(v, 5); + auto numErased = eastl::erase(v, 5); VERIFY((v == eastl::vector<int> {1, 2, 3, 4, 6, 7, 8, 9})); + VERIFY(numErased == 1); - eastl::erase(v, 2); + numErased = eastl::erase(v, 2); VERIFY((v == eastl::vector<int> {1, 3, 4, 6, 7, 8, 9})); + VERIFY(numErased == 1); - eastl::erase(v, 9); + numErased = eastl::erase(v, 9); VERIFY((v == eastl::vector<int> {1, 3, 4, 6, 7, 8})); + VERIFY(numErased == 1); } { eastl::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - eastl::erase_if(v, [](auto i) { return i % 2 == 0; }); + auto numErased = eastl::erase_if(v, [](auto i) { return i % 2 == 0; }); VERIFY((v == eastl::vector<int>{1, 3, 5, 7, 9})); + VERIFY(numErased == 4); } } diff --git a/EASTL/test/source/main.cpp b/EASTL/test/source/main.cpp index 8ce7c1b..132bab1 100644 --- a/EASTL/test/source/main.cpp +++ b/EASTL/test/source/main.cpp @@ -145,7 +145,7 @@ int EAMain(int argc, char* argv[]) testSuite.AddTest("VectorSet", TestVectorSet); testSuite.AddTest("AtomicBasic", TestAtomicBasic); testSuite.AddTest("AtomicAsm", TestAtomicAsm); - testSuite.AddTest("TestBitcast", TestBitcast); + testSuite.AddTest("Bitcast", TestBitcast); nErrorCount += testSuite.Run(); |