///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// #include "EASTLTest.h" #include #include struct BasicObject { int mX; BasicObject(int x) : mX(x) {} }; inline bool operator==(const BasicObject& t1, const BasicObject& t2) { return t1.mX == t2.mX; } inline bool operator<(const BasicObject& t1, const BasicObject& t2) { return t1.mX < t2.mX; } /////////////////////////////////////////////////////////////////////////////// // TestUtilityPair // static int TestUtilityPair() { using namespace eastl; int nErrorCount = 0; { int _0 = 0, _2 = 2, _3 = 3; float _1f = 1.f; // pair(); pair ifPair1; EATEST_VERIFY((ifPair1.first == 0) && (ifPair1.second == 0.f)); // pair(const T1& x, const T2& y); pair ifPair2(_0, _1f); EATEST_VERIFY((ifPair2.first == 0) && (ifPair2.second == 1.f)); // template // pair(U&& u, V&& v); pair ifPair3(int(0), float(1.f)); EATEST_VERIFY((ifPair3.first == 0) && (ifPair3.second == 1.f)); // template // pair(U&& x, const T2& y); const float fConst1 = 1.f; pair ifPair4(int(0), fConst1); EATEST_VERIFY((ifPair4.first == 0) && (ifPair4.second == 1.f)); // template // pair(const T1& x, V&& y); const int intConst0 = 0; pair ifPair5(intConst0, float(1.f)); EATEST_VERIFY((ifPair5.first == 0) && (ifPair5.second == 1.f)); pair constIntPair(_2, _3); EATEST_VERIFY((constIntPair.first == 2) && (constIntPair.second == 3)); // pair(const pair&) = default; pair ifPair2Copy(ifPair2); EATEST_VERIFY((ifPair2Copy.first == 0) && (ifPair2Copy.second == 1.f)); pair constIntPairCopy(constIntPair); EATEST_VERIFY((constIntPairCopy.first == 2) && (constIntPairCopy.second == 3)); // template // pair(const pair& p); pair idPair2(ifPair2); EATEST_VERIFY((idPair2.first == 0) && (idPair2.second == 1.0)); // pair(pair&& p); // template // pair(pair&& p); // pair& operator=(const pair& p); // template // pair& operator=(const pair& p); // pair& operator=(pair&& p); // template // pair& operator=(pair&& p); // void swap(pair& p); // use_self, use_first, use_second use_self > usIFPair; use_first > u1IFPair; use_second > u2IFPair; ifPair2 = usIFPair(ifPair2); EATEST_VERIFY((ifPair2.first == 0) && (ifPair2.second == 1)); int first = u1IFPair(ifPair2); EATEST_VERIFY(first == 0); float second = u2IFPair(ifPair2); EATEST_VERIFY(second == 1); // make_pair pair p1 = make_pair(int(0), float(1)); EATEST_VERIFY((p1.first == 0) && (p1.second == 1.f)); pair p2 = make_pair_ref(int(0), float(1)); EATEST_VERIFY((p2.first == 0) && (p2.second == 1.f)); pair p3 = eastl::make_pair("a", 1); EATEST_VERIFY((EA::StdC::Strcmp(p3.first, "a") == 0) && (p2.second == 1)); pair p4 = eastl::make_pair("a", 1); EATEST_VERIFY((EA::StdC::Strcmp(p4.first, "a") == 0) && (p4.second == 1)); pair p5 = eastl::make_pair(1, "b"); EATEST_VERIFY((p5.first == 1) && (EA::StdC::Strcmp(p5.second, "b") == 0)); #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)); auto p61 = eastl::make_pair("ab", "cd"); // Different strings of same length > 1. EATEST_VERIFY((EA::StdC::Strcmp(p61.first, "ab") == 0) && (EA::StdC::Strcmp(p61.second, "cd") == 0)); auto p62 = eastl::make_pair("abc", "bcdef"); // Different strings of different length. EATEST_VERIFY((EA::StdC::Strcmp(p62.first, "abc") == 0) && (EA::StdC::Strcmp(p62.second, "bcdef") == 0)); char strA[] = "a"; auto p70 = eastl::make_pair(strA, strA); EATEST_VERIFY((EA::StdC::Strcmp(p70.first, "a") == 0) && (EA::StdC::Strcmp(p70.second, "a") == 0)); char strBC[] = "bc"; auto p71 = eastl::make_pair(strA, strBC); EATEST_VERIFY((EA::StdC::Strcmp(p71.first, "a") == 0) && (EA::StdC::Strcmp(p71.second, "bc") == 0)); const char cstrA[] = "a"; auto p80 = eastl::make_pair(cstrA, cstrA); EATEST_VERIFY((EA::StdC::Strcmp(p80.first, "a") == 0) && (EA::StdC::Strcmp(p80.second, "a") == 0)); const char cstrBC[] = "bc"; auto p81 = eastl::make_pair(cstrA, cstrBC); EATEST_VERIFY((EA::StdC::Strcmp(p81.first, "a") == 0) && (EA::StdC::Strcmp(p81.second, "bc") == 0)); #endif } { // One-off tests and regressions #if EASTL_PAIR_CONFORMANCE // See http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#811 pair zeroLiteralPair(0, 0); EATEST_VERIFY((zeroLiteralPair.first == NULL) && (zeroLiteralPair.second == NULL)); #endif // template // pair(U&& x, const T2& y) typedef eastl::pair LCIDMapping; LCIDMapping lcidMappingArray[1] = {LCIDMapping(0x0036, EA_CHAR8("af"))}; // Note that 0x0036 is of type int. EATEST_VERIFY((lcidMappingArray[0].first == 0x0036)); // template // pair(const T1& x, V&& y) typedef eastl::pair LCIDMapping2; LCIDMapping2 lcidMapping2Array[1] = {LCIDMapping2(EA_CHAR8("af"), 0x0036)}; EATEST_VERIFY((lcidMapping2Array[0].second == 0x0036)); // The following code was giving an EDG compiler: // error 145: a value of type "int" cannot be used to initialize // an entity of type "void *" second(eastl::forward(v)) {} // template // pair(U&& u, V&& v); #if EASTL_PAIR_CONFORMANCE typedef eastl::pair TestPair1; float fOne = 1.f; TestPair1 testPair1(&fOne, NULL); EATEST_VERIFY(*testPair1.first == 1.f); #endif } #ifndef EA_COMPILER_NO_STRUCTURED_BINDING // pair structured bindings test { eastl::pair t = {1,2}; auto [x,y] = t; EATEST_VERIFY(x == 1); EATEST_VERIFY(y == 2); } { auto t = eastl::make_pair(1, 2); auto [x,y] = t; EATEST_VERIFY(x == 1); EATEST_VERIFY(y == 2); } { // reported user-regression structured binding unpacking for iterators eastl::vector v = {1,2,3,4,5,6}; auto t = eastl::make_pair(v.begin(), v.end() - 1); auto [x,y] = t; EATEST_VERIFY(*x == 1); EATEST_VERIFY(*y == 6); } { // reported user-regression structured binding unpacking for iterators eastl::vector v = {1,2,3,4,5,6}; auto t = eastl::make_pair(v.begin(), v.end()); auto [x,y] = t; EATEST_VERIFY(*x == 1); EA_UNUSED(y); } { // reported user-regression for const structured binding unpacking for iterators eastl::vector v = {1,2,3,4,5,6}; const auto [x,y] = eastl::make_pair(v.begin(), v.end());; EATEST_VERIFY(*x == 1); EA_UNUSED(y); } #endif return nErrorCount; } /////////////////////////////////////////////////////////////////////////////// // TestUtilityRelops // static int TestUtilityRelops() { int nErrorCount = 0; { using namespace eastl::rel_ops; // Defines default versions of operators !=, <, >, <=, >= based on == and <. BasicObject bo1(1), bo2(2); EATEST_VERIFY(!(bo1 == bo2)); EATEST_VERIFY((bo1 != bo2)); EATEST_VERIFY((bo1 < bo2)); EATEST_VERIFY(!(bo1 > bo2)); EATEST_VERIFY((bo1 <= bo2)); EATEST_VERIFY(!(bo1 >= bo2)); } return nErrorCount; } // ThrowSwappable struct ThrowSwappable { }; void swap(ThrowSwappable& x, ThrowSwappable& y) EA_NOEXCEPT_IF(false) { ThrowSwappable temp(x); x = y; y = temp; #if EASTL_EXCEPTIONS_ENABLED throw int(); #endif } #if EASTL_TYPE_TRAIT_is_nothrow_swappable_CONFORMANCE // NoThrowSwappable struct NoThrowSwappable { }; void swap(NoThrowSwappable& x, NoThrowSwappable& y) EA_NOEXCEPT_IF(true) { NoThrowSwappable temp(x); x = y; y = temp; } #endif struct Swappable1 {}; struct Swappable2 {}; struct Swappable3 {}; void swap(Swappable1&, Swappable2&) {} void swap(Swappable2&, Swappable1&) {} void swap(Swappable1&, Swappable3&) {} // intentionally missing 'swap(Swappable3, Swappable1)' static int TestUtilitySwap() { int nErrorCount = 0; // is_swappable // is_nothrow_swappable #if EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE static_assert((eastl::is_swappable::value == true), "is_swappable failure"); static_assert((eastl::is_swappable >::value == true), "is_swappable failure"); static_assert((eastl::is_swappable::value == true), "is_swappable failure"); #if EASTL_VARIABLE_TEMPLATES_ENABLED static_assert((eastl::is_swappable_v == true), "is_swappable failure"); static_assert((eastl::is_swappable_v > == true), "is_swappable failure"); static_assert((eastl::is_swappable_v == true), "is_swappable failure"); #endif // Need to come up with a class that's not swappable. How do we do that, given the universal swap template? // static_assert((eastl::is_swappable::value == false), "is_swappable failure"); #endif #if EASTL_TYPE_TRAIT_is_nothrow_swappable_CONFORMANCE static_assert((eastl::is_nothrow_swappable::value == true), "is_nothrow_swappable failure"); // There currently isn't any specialization for swap of scalar types that's nothrow. static_assert((eastl::is_nothrow_swappable >::value == false), "is_nothrow_swappable failure"); static_assert((eastl::is_nothrow_swappable::value == false), "is_nothrow_swappable failure"); static_assert((eastl::is_nothrow_swappable::value == true), "is_nothrow_swappable failure"); #if EASTL_VARIABLE_TEMPLATES_ENABLED static_assert((eastl::is_nothrow_swappable_v == true), "is_nothrow_swappable failure"); // There currently isn't any specialization for swap of scalar types that's nothrow. static_assert((eastl::is_nothrow_swappable_v> == false), "is_nothrow_swappable failure"); static_assert((eastl::is_nothrow_swappable_v == false), "is_nothrow_swappable failure"); static_assert((eastl::is_nothrow_swappable_v == true), "is_nothrow_swappable failure"); #endif #endif #if EASTL_VARIADIC_TEMPLATES_ENABLED // is_swappable_with // is_nothrow_swappable_with static_assert(eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with>::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(!eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(eastl::is_swappable_with::value, "is_swappable_with failure"); static_assert(eastl::is_swappable_with::value, "is_swappable_with failure"); #if EASTL_VARIABLE_TEMPLATES_ENABLED static_assert(eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v>, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(!eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(eastl::is_swappable_with_v, "is_swappable_with_v failure"); static_assert(eastl::is_swappable_with_v, "is_swappable_with_v failure"); #endif // EASTL_VARIABLE_TEMPLATES_ENABLED #if EASTL_TYPE_TRAIT_is_nothrow_swappable_with_CONFORMANCE static_assert(eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with>::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(!eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); static_assert(eastl::is_nothrow_swappable_with::value, "is_nothrow_swappable_with failure"); #if EASTL_VARIABLE_TEMPLATES_ENABLED static_assert(eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v>, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(!eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); static_assert(eastl::is_nothrow_swappable_with_v, "is_nothrow_swappable_with_v failure"); #endif // EASTL_VARIABLE_TEMPLATES_ENABLED #endif #endif // EASTL_VARIADIC_TEMPLATES_ENABLED return nErrorCount; } #if !defined(EA_COMPILER_NO_NOEXCEPT) /////////////////////////////////////////////////////////////////////////////////////////////////////////// // Warning C4626 warns against an implicitly deleted move assignment operator. // This warning was disabled by default in VS2013. It was enabled by default in // VS2015. Since the the tests below are explicitly testing move construction // of the various classes explicitly deleting the move assignment to remove the // warning is safe. // // https://msdn.microsoft.com/en-us/library/23k5d385.aspx struct noexcept_move_copy { bool mStatus; noexcept_move_copy() : mStatus(true) {} noexcept_move_copy(const noexcept_move_copy&) = default; noexcept_move_copy(noexcept_move_copy&& r) noexcept { r.mStatus = false; } noexcept_move_copy& operator=(const noexcept_move_copy&) = delete; // required as VS2015 enabled C4626 by default. }; struct noexcept_move_no_copy { bool mStatus; noexcept_move_no_copy() : mStatus(true) {} noexcept_move_no_copy(const noexcept_move_no_copy&) = delete; noexcept_move_no_copy(noexcept_move_no_copy&& r) noexcept { r.mStatus = false; }; noexcept_move_no_copy& operator=(const noexcept_move_no_copy&) = delete; // required as VS2015 enabled C4626 by default. }; struct except_move_copy { bool mStatus; except_move_copy() : mStatus(true) {} except_move_copy(const except_move_copy&) = default; except_move_copy(except_move_copy&& r) noexcept(false) { r.mStatus = false; }; except_move_copy& operator=(const except_move_copy&) = delete; // required as VS2015 enabled C4626 by default. }; struct except_move_no_copy { bool mStatus; except_move_no_copy() : mStatus(true) {} except_move_no_copy(const except_move_no_copy&) = delete; except_move_no_copy(except_move_no_copy&& r) noexcept(false) { r.mStatus = false; }; except_move_no_copy& operator=(const except_move_no_copy&) = delete; // required as VS2015 enabled C4626 by default. }; #endif static int TestUtilityMove() { int nErrorCount = 0; // move_if_noexcept #if !defined(EA_COMPILER_NO_NOEXCEPT) noexcept_move_copy nemcA; noexcept_move_copy nemcB = eastl::move_if_noexcept(nemcA); // nemcB should be constructed via noexcept_move_copy(noexcept_move_copy&&) EATEST_VERIFY(nemcA.mStatus == false); EA_UNUSED(nemcB); noexcept_move_no_copy nemncA; noexcept_move_no_copy nemncB = eastl::move_if_noexcept( nemncA); // nemncB should be constructed via noexcept_move_no_copy(noexcept_move_no_copy&&) EATEST_VERIFY(nemncA.mStatus == false); EA_UNUSED(nemncB); except_move_copy emcA; except_move_copy emcB = eastl::move_if_noexcept( emcA); // emcB should be constructed via except_move_copy(const except_move_copy&) if exceptions are enabled. #if EASTL_EXCEPTIONS_ENABLED EATEST_VERIFY(emcA.mStatus == true); #else EATEST_VERIFY(emcA.mStatus == false); #endif EA_UNUSED(emcB); except_move_no_copy emncA; except_move_no_copy emncB = eastl::move_if_noexcept(emncA); // emncB should be constructed via except_move_no_copy(except_move_no_copy&&) EATEST_VERIFY(emncA.mStatus == false); EA_UNUSED(emncB); #endif return nErrorCount; } 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::size() == 5)); EATEST_VERIFY((make_integer_sequence::size() == 5)); #endif EATEST_VERIFY((index_sequence<0, 1, 2, 3, 4>::size() == 5)); EATEST_VERIFY((make_index_sequence<5>::size() == 5)); #endif // EASTL_VARIADIC_TEMPLATES_ENABLED return nErrorCount; } static int TestUtilityExchange() { int nErrorCount = 0; { int a = 0; auto r = eastl::exchange(a, 1); EATEST_VERIFY(r == 0); EATEST_VERIFY(a == 1); } { int a = 0; auto r = eastl::exchange(a, 1.78); EATEST_VERIFY(r == 0); EATEST_VERIFY(a == 1); } { int a = 0; auto r = eastl::exchange(a, 1.78f); EATEST_VERIFY(r == 0); EATEST_VERIFY(a == 1); } { int a = 0, b = 1; auto r = eastl::exchange(a, b); EATEST_VERIFY(r == 0); EATEST_VERIFY(a == 1); EATEST_VERIFY(b == 1); } { bool b = true; auto r = eastl::exchange(b, true); EATEST_VERIFY(r); r = eastl::exchange(b, false); EATEST_VERIFY(r); EATEST_VERIFY(!b); r = eastl::exchange(b, true); EATEST_VERIFY(!r); EATEST_VERIFY(b); } { TestObject::Reset(); TestObject a(42); auto r = eastl::exchange(a, TestObject(24)); EATEST_VERIFY(r.mX == 42); EATEST_VERIFY(a.mX == 24); } { const char* const pElectronicArts = "Electronic Arts"; const char* const pEAVancouver = "EA Vancouver"; eastl::string a(pElectronicArts); auto r = eastl::exchange(a, pEAVancouver); EATEST_VERIFY(r == pElectronicArts); EATEST_VERIFY(a == pEAVancouver); r = eastl::exchange(a, "EA Standard Template Library"); EATEST_VERIFY(a == "EA Standard Template Library"); } // Construct pair using single move constructor { struct TestPairSingleMoveConstructor { void test(int&& val) { eastl::pair p(eastl::pair_first_construct, eastl::move(val)); } }; int i1 = 1; TestPairSingleMoveConstructor test; test.test(eastl::move(i1)); } // User reported regression where via reference collapsing, we see the same single element ctor defined twice. // // T = const U& // pair(const T&) -> pair(const const U& &) -> pair(const U&) // pair(T&&) -> pair(const U& &&) -> pair(const U&) { struct FooType {}; using VectorOfPairWithReference = eastl::vector>; VectorOfPairWithReference v; } return nErrorCount; } /////////////////////////////////////////////////////////////////////////////// // TestUtility // int TestUtility() { int nErrorCount = 0; nErrorCount += TestUtilityPair(); nErrorCount += TestUtilityRelops(); nErrorCount += TestUtilitySwap(); nErrorCount += TestUtilityMove(); nErrorCount += TestUtilityIntegerSequence(); nErrorCount += TestUtilityExchange(); return nErrorCount; }