///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// #include "TestMap.h" #include "EASTLTest.h" #include #include #include EA_DISABLE_ALL_VC_WARNINGS() #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY #include #endif EA_RESTORE_ALL_VC_WARNINGS() using namespace eastl; // Template instantations. // These tell the compiler to compile all the functions for the given class. template class eastl::map; template class eastl::multimap; template class eastl::map; template class eastl::multimap; /////////////////////////////////////////////////////////////////////////////// // typedefs // typedef eastl::map VM1; typedef eastl::map VM4; typedef eastl::multimap VMM1; typedef eastl::multimap VMM4; #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY typedef std::map VM3; typedef std::map VM6; typedef std::multimap VMM3; typedef std::multimap VMM6; #endif /////////////////////////////////////////////////////////////////////////////// int TestMap() { int nErrorCount = 0; #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY { // Test construction nErrorCount += TestMapConstruction(); nErrorCount += TestMapConstruction(); nErrorCount += TestMapConstruction(); nErrorCount += TestMapConstruction(); } { // Test mutating functionality. nErrorCount += TestMapMutation(); nErrorCount += TestMapMutation(); nErrorCount += TestMapMutation(); nErrorCount += TestMapMutation(); } #endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY { // Test searching functionality. nErrorCount += TestMapSearch(); nErrorCount += TestMapSearch(); nErrorCount += TestMapSearch(); nErrorCount += TestMapSearch(); } { // C++11 emplace and related functionality nErrorCount += TestMapCpp11>(); nErrorCount += TestMultimapCpp11>(); nErrorCount += TestMapCpp11NonCopyable>(); } { // C++17 try_emplace and related functionality nErrorCount += TestMapCpp17>(); } { // Misc tests // const key_compare& key_comp() const; // key_compare& key_comp(); VM1 vm; const VM1 vmc; const VM1::key_compare& kc = vmc.key_comp(); vm.key_comp() = kc; } // Regressions against user bug reports. { // User reports that the following doesn't compile on GCC 4.1.1 due to unrecognized lower_bound. eastl::map m; m[1] = 1; EATEST_VERIFY(m.size() == 1); m.erase(1); EATEST_VERIFY(m.empty()); } { // User reports that EASTL_VALIDATE_COMPARE_ENABLED / EASTL_COMPARE_VALIDATE isn't compiling for this case. eastl::map m; m.find_as(EA_CHAR8("some string"), eastl::equal_to_2()); } { eastl::map m; int* ip = (int*)(uintptr_t)0xDEADC0DE; m[ip] = 0; auto it = m.find_as(ip, eastl::less_2{}); EATEST_VERIFY(it != m.end()); it = m.find_as((int*)(uintptr_t)0xDEADC0DE, eastl::less_2{}); EATEST_VERIFY(it != m.end()); } { // User reports that vector> is crashing after the recent changes to add rvalue move and emplace support to rbtree. typedef eastl::map IntIntMap; typedef eastl::vector IntIntMapArray; IntIntMapArray v; v.push_back(IntIntMap()); // This was calling the rbtree move constructor, which had a bug. v[0][16] = 0; // The rbtree was in a bad internal state and so this line resulted in a crash. EATEST_VERIFY(v[0].validate()); EATEST_VERIFY(v.validate()); } { typedef eastl::map IntIntMap; IntIntMap map1; map1[1] = 1; map1[3] = 3; #if EASTL_EXCEPTIONS_ENABLED EATEST_VERIFY_THROW(map1.at(0)); EATEST_VERIFY_THROW(map1.at(2)); EATEST_VERIFY_THROW(map1.at(4)); #endif map1[0] = 1; #if EASTL_EXCEPTIONS_ENABLED EATEST_VERIFY_NOTHROW(map1.at(0)); EATEST_VERIFY_NOTHROW(map1.at(1)); EATEST_VERIFY_NOTHROW(map1.at(3)); #endif EATEST_VERIFY(map1.at(0) == 1); EATEST_VERIFY(map1.at(1) == 1); EATEST_VERIFY(map1.at(3) == 3); const IntIntMap map2; const IntIntMap map3(map1); #if EASTL_EXCEPTIONS_ENABLED EATEST_VERIFY_THROW(map2.at(0)); EATEST_VERIFY_NOTHROW(map3.at(0)); #endif EATEST_VERIFY(map3.at(0) == 1); } // User regression test { #if !EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR typedef eastl::map IntMOMap; IntMOMap m1, m2; m2[0] = MoveOnlyTypeDefaultCtor(0); m2[1] = MoveOnlyTypeDefaultCtor(1); EATEST_VERIFY( m1.empty()); EATEST_VERIFY(!m2.empty()); m1.swap(m2); EATEST_VERIFY(!m1.empty()); EATEST_VERIFY( m2.empty()); #endif } // todo: create a test case for this. // { // // User reports that an incorrectly wrapped pair key used to insert into an eastl map compiles when it should fire a compiler error about unconvertible types. // typedef eastl::pair PairStringKey; // typedef eastl::map PairStringMap; // // PairStringMap p1, p2; // // p1.insert(PairStringMap::value_type(PairStringKey("key1", "key2"), "data")).first->second = "other_data"; // // PairStringKey key("key1", "key2"); // PairStringMap::value_type insert_me(key, "data"); // p2.insert(insert_me).first->second = "other_data"; // // for(auto& e : p1) // printf("%s,%s = %s\n", e.first.first.c_str(), e.first.second.c_str(), e.second.c_str()); // // for(auto& e : p2) // printf("%s,%s = %s\n", e.first.first.c_str(), e.first.second.c_str(), e.second.c_str()); // // EATEST_VERIFY(p1 == p2); // } { // Test empty base-class optimization struct UnemptyLess : eastl::less { int foo; }; typedef eastl::map> VM1; typedef eastl::map VM2; EATEST_VERIFY(sizeof(VM1) < sizeof(VM2)); } { // Test erase_if eastl::map m = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}}; auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); VERIFY((m == eastl::map{{1, 1},{3, 3}})); VERIFY(numErased == 3); } { // Test erase_if eastl::multimap m = {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {4, 4}}; auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; }); VERIFY((m == eastl::multimap{{1, 1}, {1, 1}, {3, 3}}));; VERIFY(numErased == 7); } #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) { // Test map <=> eastl::map m1 = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}}; eastl::map m2 = {{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; eastl::map m3 = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}}; eastl::map m4 = {{1, 0}, {3, 2}, {5, 4}, {7, 6}, {9, 8}}; eastl::map 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 m1 = {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {4, 4}, {4, 4}}; eastl::multimap m2 = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}}; eastl::multimap m3 = {{0, 1}, {2, 3}, {4, 5}, {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}}; eastl::multimap m4 = {{1, 0}, {3, 2}, {5, 4}, {1, 0}, {3, 2}, {5, 4}, {7, 6}, {9, 8}}; eastl::multimap 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; }