///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// #include "EASTLTest.h" #include #include #include #include #include #include #include #include #include #include "ConceptImpls.h" EA_DISABLE_ALL_VC_WARNINGS() #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY #include #include #endif EA_RESTORE_ALL_VC_WARNINGS() // Template instantations. // These tell the compiler to compile all the functions for the given class. template class eastl::vector; template class eastl::vector; template class eastl::vector; template class eastl::vector; // This tests "uninitialized_fill" usage in vector when T has a user provided // address-of operator overload. In these situations, EASTL containers must use // the standard utility "eastl::addressof(T)" which is designed to by-pass user // provided address-of operator overloads. // // Previously written as: // for(; first != last; ++first, ++currentDest) // ::new((void*)&*currentDest) value_type(*first); // & not guaranteed to be a pointer // // Bypasses user 'addressof' operators: // for(; n > 0; --n, ++currentDest) // ::new(eastl::addressof(*currentDest)) value_type(value); // guaranteed to be a pointer // struct AddressOfOperatorResult {}; struct HasAddressOfOperator { // problematic 'addressof' operator that doesn't return a pointer type AddressOfOperatorResult operator&() const { return {}; } bool operator==(const HasAddressOfOperator&) const { return false; } }; template class eastl::vector; // force compile all functions of vector // Test compiler issue that appeared in VS2012 relating to kAlignment struct StructWithContainerOfStructs { eastl::vector children; }; // This relatively complex test is to prevent a regression on VS2013. The data types have what may appear to be // strange names (for test code) because the code is based on a test case extracted from the Frostbite codebase. // This test is actually invalid and should be removed as const data memebers are problematic for STL container // implementations. (ie. they prevent constructors from being generated). namespace { EA_DISABLE_VC_WARNING(4512) // disable warning : "assignment operator could not be generated" #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) // VS2015-preview and later. EA_DISABLE_VC_WARNING(5025) // disable warning : "move assignment operator could not be generated" EA_DISABLE_VC_WARNING(4626) // disable warning : "assignment operator was implicitly defined as deleted" EA_DISABLE_VC_WARNING(5027) // disable warning : "move assignment operator was implicitly defined as deleted" #endif struct ScenarioRefEntry { ScenarioRefEntry(const eastl::string& contextDatabase) : ContextDatabase(contextDatabase) {} struct RowEntry { RowEntry(int levelId, int sceneId, int actorId, int partId, const eastl::string& controller) : LevelId(levelId), SceneId(sceneId), ActorId(actorId), PartId(partId), Controller(controller) { } int LevelId; int SceneId; int ActorId; int PartId; const eastl::string& Controller; }; const eastl::string& ContextDatabase; // note: const class members prohibits move semantics typedef eastl::vector RowData; RowData Rows; }; typedef eastl::vector ScenarRefData; struct AntMetaDataRecord { ScenarRefData ScenarioRefs; }; typedef eastl::vector MetadataRecords; struct StructWithConstInt { StructWithConstInt(const int& _i) : i(_i) {} const int i; }; struct StructWithConstRefToInt { StructWithConstRefToInt(const int& _i) : i(_i) {} const int& i; }; #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) // VS2015-preview and later. EA_RESTORE_VC_WARNING() // disable warning 5025: "move assignment operator could not be generated" EA_RESTORE_VC_WARNING() // disable warning 4626: "assignment operator was implicitly defined as deleted" EA_RESTORE_VC_WARNING() // disable warning 5027: "move assignment operator was implicitly defined as deleted" #endif EA_RESTORE_VC_WARNING() } struct ItemWithConst { ItemWithConst& operator=(const ItemWithConst&); public: ItemWithConst(int _i) : i(_i) {} ItemWithConst(const ItemWithConst& x) : i(x.i) {} const int i; }; struct testmovable { EA_NON_COPYABLE(testmovable) public: testmovable() EA_NOEXCEPT {} testmovable(testmovable&&) EA_NOEXCEPT {} testmovable& operator=(testmovable&&) EA_NOEXCEPT { return *this; } }; struct TestMoveAssignToSelf { TestMoveAssignToSelf() EA_NOEXCEPT : mMovedToSelf(false) {} TestMoveAssignToSelf(const TestMoveAssignToSelf& other) { mMovedToSelf = other.mMovedToSelf; } TestMoveAssignToSelf& operator=(TestMoveAssignToSelf&&) { mMovedToSelf = true; return *this; } TestMoveAssignToSelf& operator=(const TestMoveAssignToSelf&) = delete; bool mMovedToSelf; }; #if EASTL_VARIABLE_TEMPLATES_ENABLED /// custom type-trait which checks if a type is comparable via the > struct is_less_comparable : eastl::false_type { }; template struct is_less_comparable() < eastl::declval())>> : eastl::true_type { }; #else // bypass the test since the compiler doesn't support variable templates. template struct is_less_comparable : eastl::false_type { }; #endif int TestVector() { int nErrorCount = 0; eastl_size_t i; TestObject::Reset(); { MetadataRecords mMetadataRecords; AntMetaDataRecord r, s; mMetadataRecords.push_back(r); mMetadataRecords.push_back(s); } { using namespace eastl; // explicit vector(); vector intArray1; vector toArray1; vector > toListArray1; EATEST_VERIFY(intArray1.validate()); EATEST_VERIFY(intArray1.empty()); EATEST_VERIFY(toArray1.validate()); EATEST_VERIFY(toArray1.empty()); EATEST_VERIFY(toListArray1.validate()); EATEST_VERIFY(toListArray1.empty()); // explicit vector(const allocator_type& allocator); MallocAllocator::reset_all(); MallocAllocator ma; vector intArray6(ma); vector toArray6(ma); vector, MallocAllocator> toListArray6(ma); intArray6.resize(1); toArray6.resize(1); toListArray6.resize(1); EATEST_VERIFY(MallocAllocator::mAllocCountAll == 3); // explicit vector(size_type n, const allocator_type& allocator = EASTL_VECTOR_DEFAULT_ALLOCATOR) vector intArray2(10); vector toArray2(10); vector > toListArray2(10); EATEST_VERIFY(intArray2.validate()); EATEST_VERIFY(intArray2.size() == 10); EATEST_VERIFY(toArray2.validate()); EATEST_VERIFY(toArray2.size() == 10); EATEST_VERIFY(toListArray2.validate()); EATEST_VERIFY(toListArray2.size() == 10); // vector(size_type n, const value_type& value, const allocator_type& allocator = // EASTL_VECTOR_DEFAULT_ALLOCATOR) vector intArray3(10, 7); vector toArray3(10, TestObject(7)); vector > toListArray3(10, list(7)); EATEST_VERIFY(intArray3.validate()); EATEST_VERIFY(intArray3.size() == 10); EATEST_VERIFY(intArray3[5] == 7); EATEST_VERIFY(toArray3.validate()); EATEST_VERIFY(toArray3[5] == TestObject(7)); EATEST_VERIFY(toListArray3.validate()); EATEST_VERIFY(toListArray3[5] == list(7)); // vector(const vector& x) vector intArray4(intArray2); vector toArray4(toArray2); vector > toListArray4(toListArray2); EATEST_VERIFY(intArray4.validate()); EATEST_VERIFY(intArray4 == intArray2); EATEST_VERIFY(toArray4.validate()); EATEST_VERIFY(toArray4 == toArray2); EATEST_VERIFY(intArray4.validate()); EATEST_VERIFY(toListArray4 == toListArray2); // vector(const this_type& x, const allocator_type& allocator) MallocAllocator::reset_all(); vector intArray7(intArray6, ma); vector toArray7(toArray6, ma); vector, MallocAllocator> toListArray7(toListArray6, ma); EATEST_VERIFY(MallocAllocator::mAllocCountAll == 3); // vector(InputIterator first, InputIterator last) deque intDeque(3); deque toDeque(3); deque > toListDeque(3); vector intArray5(intDeque.begin(), intDeque.end()); vector toArray5(toDeque.begin(), toDeque.end()); vector > toListArray5(toListDeque.begin(), toListDeque.end()); // vector(std::initializer_list ilist, const Allocator& allocator = EASTL_VECTOR_DEFAULT_ALLOCATOR); { #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) eastl::vector floatVector{0, 1, 2, 3}; EATEST_VERIFY(floatVector.size() == 4); EATEST_VERIFY((floatVector[0] == 0) && (floatVector[3] == 3)); #endif } // vector& operator=(const vector& x); intArray3 = intArray4; toArray3 = toArray4; toListArray3 = toListArray4; EATEST_VERIFY(intArray3.validate()); EATEST_VERIFY(intArray3 == intArray4); EATEST_VERIFY(toArray3.validate()); EATEST_VERIFY(toArray3 == toArray4); EATEST_VERIFY(intArray3.validate()); EATEST_VERIFY(toListArray3 == toListArray4); // this_type& operator=(std::initializer_list ilist); #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) intArray3 = {0, 1, 2, 3}; EATEST_VERIFY((intArray3.size() == 4) && (intArray3[0] == 0) && (intArray3[3] == 3)); #endif } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { using namespace eastl; // vector(this_type&& x) // vector(this_type&& x, const Allocator& allocator) // this_type& operator=(this_type&& x) vector vector3TO33(3, TestObject(33)); vector toVectorA(eastl::move(vector3TO33)); EATEST_VERIFY((toVectorA.size() == 3) && (toVectorA.front().mX == 33) && (vector3TO33.size() == 0)); // The following is not as strong a test of this ctor as it could be. A stronger test would be to use // IntanceAllocator with different instances. vector vector4TO44(4, TestObject(44)); vector toVectorB(eastl::move(vector4TO44), MallocAllocator()); EATEST_VERIFY((toVectorB.size() == 4) && (toVectorB.front().mX == 44) && (vector4TO44.size() == 0)); vector vector5TO55(5, TestObject(55)); toVectorB = eastl::move(vector5TO55); EATEST_VERIFY((toVectorB.size() == 5) && (toVectorB.front().mX == 55) && (vector5TO55.size() == 0)); // Should be able to emplace_back an item with const members (non-copyable) eastl::vector myVec2; ItemWithConst& ref = myVec2.emplace_back(42); EATEST_VERIFY(myVec2.back().i == 42); EATEST_VERIFY(ref.i == 42); } { using namespace eastl; // pointer data(); // const_pointer data() const; // reference front(); // const_reference front() const; // reference back(); // const_reference back() const; vector intArray(10, 7); intArray[0] = 10; intArray[1] = 11; intArray[2] = 12; EATEST_VERIFY(intArray.data() == &intArray[0]); EATEST_VERIFY(*intArray.data() == 10); EATEST_VERIFY(intArray.front() == 10); EATEST_VERIFY(intArray.back() == 7); const vector toArrayC(10, TestObject(7)); EATEST_VERIFY(toArrayC.data() == &toArrayC[0]); EATEST_VERIFY(*toArrayC.data() == TestObject(7)); EATEST_VERIFY(toArrayC.front() == TestObject(7)); EATEST_VERIFY(toArrayC.back() == TestObject(7)); } { using namespace eastl; // iterator begin(); // const_iterator begin() const; // iterator end(); // const_iterator end() const; // reverse_iterator rbegin(); // const_reverse_iterator rbegin() const; // reverse_iterator rend(); // const_reverse_iterator rend() const; vector intArray(20); for (i = 0; i < 20; i++) intArray[i] = (int)i; i = 0; for (vector::iterator it = intArray.begin(); it != intArray.end(); ++it, ++i) EATEST_VERIFY(*it == (int)i); i = intArray.size() - 1; for (vector::reverse_iterator itr = intArray.rbegin(); itr != intArray.rend(); ++itr, --i) EATEST_VERIFY(*itr == (int)i); } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { using namespace eastl; // void swap(vector& x); // void assign(size_type n, const value_type& value); // void assign(InputIterator first, InputIterator last); const int A[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; const int B[] = {99, 99, 99, 99, 99}; const size_t N = sizeof(A) / sizeof(int); const size_t M = sizeof(B) / sizeof(int); // assign from pointer range vector v3; v3.assign(A, A + N); EATEST_VERIFY(equal(v3.begin(), v3.end(), A)); EATEST_VERIFY(v3.size() == N); // assign from iterator range vector v4; v4.assign(v3.begin(), v3.end()); EATEST_VERIFY(equal(v4.begin(), v4.end(), A)); EATEST_VERIFY(equal(A, A + N, v4.begin())); // assign from initializer range with resize v4.assign(M, 99); EATEST_VERIFY(equal(v4.begin(), v4.end(), B)); EATEST_VERIFY(equal(B, B + M, v4.begin())); EATEST_VERIFY((v4.size() == M) && (M != N)); #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) // void assign(std::initializer_list ilist); v4.assign({0, 1, 2, 3}); EATEST_VERIFY(v4.size() == 4); EATEST_VERIFY((v4[0] == 0) && (v4[3] == 3)); #endif } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { using namespace eastl; // reference operator[](size_type n); // const_reference operator[](size_type n) const; // reference at(size_type n); // const_reference at(size_type n) const; vector intArray(5); EATEST_VERIFY(intArray[3] == 0); EATEST_VERIFY(intArray.at(3) == 0); vector toArray(5); EATEST_VERIFY(toArray[3] == TestObject(0)); EATEST_VERIFY(toArray.at(3) == TestObject(0)); #if EASTL_EXCEPTIONS_ENABLED vector vec01(5); try { TestObject& r01 = vec01.at(6); EATEST_VERIFY(!(r01 == TestObject(0))); // Should not get here, as exception thrown. } catch (std::out_of_range&) { EATEST_VERIFY(true); } catch (...) { EATEST_VERIFY(false); } #endif } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { using namespace eastl; // void push_back(const value_type& value); // void push_back(); // void pop_back(); // void push_back(T&& value); vector intArray(6); for (i = 0; i < 6; i++) intArray[i] = (int)i; EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 6); EATEST_VERIFY(intArray[5] == 5); for (i = 0; i < 40; i++) { int& ref = intArray.push_back(); EATEST_VERIFY(&ref == &intArray.back()); ref = 98; } EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 46); EATEST_VERIFY(intArray[45] == 98); for (i = 0; i < 40; i++) intArray.push_back(99); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 86); EATEST_VERIFY(intArray[85] == 99); for (i = 0; i < 30; i++) intArray.pop_back(); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 56); EATEST_VERIFY(intArray[5] == 5); } { using namespace eastl; // void* push_back_uninitialized(); int64_t toCount0 = TestObject::sTOCount; vector vTO; EATEST_VERIFY(TestObject::sTOCount == toCount0); for (i = 0; i < 25; i++) { void* pTO = vTO.push_back_uninitialized(); EATEST_VERIFY(TestObject::sTOCount == (toCount0 + static_cast(i))); new (pTO) TestObject((int)i); EATEST_VERIFY(TestObject::sTOCount == (toCount0 + static_cast(i) + 1)); EATEST_VERIFY(vTO.back().mX == (int)i); EATEST_VERIFY(vTO.validate()); } } { using namespace eastl; // template // iterator emplace(const_iterator position, Args&&... args); // template // void emplace_back(Args&&... args); // iterator insert(const_iterator position, value_type&& value); // void push_back(value_type&& value); TestObject::Reset(); vector toVectorA; TestObject& ref = toVectorA.emplace_back(2, 3, 4); EATEST_VERIFY((toVectorA.size() == 1) && (toVectorA.back().mX == (2 + 3 + 4)) && (TestObject::sTOCtorCount == 1)); EATEST_VERIFY(ref.mX == (2 + 3 + 4)); toVectorA.emplace(toVectorA.begin(), 3, 4, 5); EATEST_VERIFY((toVectorA.size() == 2) && (toVectorA.front().mX == (3 + 4 + 5)) && (TestObject::sTOCtorCount == 3)); // 3 because the original count of 1, plus the existing vector // element will be moved, plus the one being emplaced. TestObject::Reset(); // void push_back(T&& x); // iterator insert(const_iterator position, T&& x); vector toVectorC; toVectorC.push_back(TestObject(2, 3, 4)); EATEST_VERIFY((toVectorC.size() == 1) && (toVectorC.back().mX == (2 + 3 + 4)) && (TestObject::sTOMoveCtorCount == 1)); toVectorC.insert(toVectorC.begin(), TestObject(3, 4, 5)); EATEST_VERIFY((toVectorC.size() == 2) && (toVectorC.front().mX == (3 + 4 + 5)) && (TestObject::sTOMoveCtorCount == 3)); // 3 because the original count of 1, plus the existing // vector element will be moved, plus the one being // emplaced. } // We don't check for TestObject::IsClear because we messed with state above and don't currently have a matching set // of ctors and dtors. TestObject::Reset(); { using namespace eastl; // iterator erase(iterator position); // iterator erase(iterator first, iterator last); // iterator erase_unsorted(iterator position); // iterator erase_first(const T& pos); // iterator erase_first_unsorted(const T& pos); // iterator erase_last(const T& pos); // iterator erase_last_unsorted(const T& pos); // void clear(); vector intArray(20); for (i = 0; i < 20; i++) intArray[i] = (int)i; // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 intArray.erase(intArray.begin() + 10); // Becomes: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19 EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 19); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[10] == 11); EATEST_VERIFY(intArray[18] == 19); intArray.erase(intArray.begin() + 10, intArray.begin() + 15); // Becomes: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19 EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 14); EATEST_VERIFY(intArray[9] == 9); EATEST_VERIFY(intArray[13] == 19); intArray.erase(intArray.begin() + 1, intArray.begin() + 5); // Becomes: 0, 5, 6, 7, 8, 9, 16, 17, 18, 19 EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 10); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 5); EATEST_VERIFY(intArray[9] == 19); intArray.erase(intArray.begin() + 7, intArray.begin() + 10); // Becomes: 0, 5, 6, 7, 8, 9, 16 EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 7); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 5); EATEST_VERIFY(intArray[6] == 16); intArray.clear(); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.empty()); EATEST_VERIFY(intArray.size() == 0); vector toArray(20); for (i = 0; i < 20; i++) toArray[i] = TestObject((int)i); toArray.erase(toArray.begin() + 10); EATEST_VERIFY(toArray.validate()); EATEST_VERIFY(toArray.size() == 19); EATEST_VERIFY(toArray[10] == TestObject(11)); toArray.erase(toArray.begin() + 10, toArray.begin() + 15); EATEST_VERIFY(toArray.validate()); EATEST_VERIFY(toArray.size() == 14); EATEST_VERIFY(toArray[10] == TestObject(16)); toArray.clear(); EATEST_VERIFY(toArray.validate()); EATEST_VERIFY(toArray.empty()); EATEST_VERIFY(toArray.size() == 0); // iterator erase_unsorted(iterator position); intArray.resize(20); for (i = 0; i < 20; i++) intArray[i] = (int)i; intArray.erase_unsorted(intArray.begin() + 0); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 19); EATEST_VERIFY(intArray[0] == 19); EATEST_VERIFY(intArray[1] == 1); EATEST_VERIFY(intArray[18] == 18); intArray.erase_unsorted(intArray.begin() + 10); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 18); EATEST_VERIFY(intArray[0] == 19); EATEST_VERIFY(intArray[10] == 18); EATEST_VERIFY(intArray[17] == 17); intArray.erase_unsorted(intArray.begin() + 17); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 17); EATEST_VERIFY(intArray[0] == 19); EATEST_VERIFY(intArray[10] == 18); EATEST_VERIFY(intArray[16] == 16); // iterator erase_first(iterator position); intArray.resize(20); for (i = 0; i < 20; i++) intArray[i] = (int)i % 3; // (i.e. 0,1,2,0,1,2...) intArray.erase_first(1); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 19); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 2); EATEST_VERIFY(intArray[2] == 0); EATEST_VERIFY(intArray[3] == 1); EATEST_VERIFY(intArray[18] == 1); intArray.erase_first(1); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 18); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 2); EATEST_VERIFY(intArray[2] == 0); EATEST_VERIFY(intArray[3] == 2); EATEST_VERIFY(intArray[17] == 1); intArray.erase_first(0); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 17); EATEST_VERIFY(intArray[0] == 2); EATEST_VERIFY(intArray[1] == 0); EATEST_VERIFY(intArray[2] == 2); EATEST_VERIFY(intArray[3] == 0); EATEST_VERIFY(intArray[16] == 1); // iterator erase_first_unsorted(const T& val); intArray.resize(20); for (i = 0; i < 20; i++) intArray[i] = (int) i/2; // every two values are the same (i.e. 0,0,1,1,2,2,3,3...) intArray.erase_first_unsorted(1); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 19); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 0); EATEST_VERIFY(intArray[2] == 9); EATEST_VERIFY(intArray[3] == 1); EATEST_VERIFY(intArray[18] == 9); intArray.erase_first_unsorted(1); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 18); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 0); EATEST_VERIFY(intArray[2] == 9); EATEST_VERIFY(intArray[3] == 9); EATEST_VERIFY(intArray[17] == 8); intArray.erase_first_unsorted(0); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 17); EATEST_VERIFY(intArray[0] == 8); EATEST_VERIFY(intArray[1] == 0); EATEST_VERIFY(intArray[2] == 9); EATEST_VERIFY(intArray[3] == 9); EATEST_VERIFY(intArray[16] == 8); // iterator erase_last(const T& val); intArray.resize(20); for (i = 0; i < 20; i++) intArray[i] = (int)i % 3; // (i.e. 0,1,2,0,1,2...) intArray.erase_last(1); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 19); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 1); EATEST_VERIFY(intArray[2] == 2); EATEST_VERIFY(intArray[3] == 0); EATEST_VERIFY(intArray[15] == 0); EATEST_VERIFY(intArray[16] == 1); EATEST_VERIFY(intArray[17] == 2); EATEST_VERIFY(intArray[18] == 0); intArray.erase_last(1); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 18); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 1); EATEST_VERIFY(intArray[2] == 2); EATEST_VERIFY(intArray[3] == 0); EATEST_VERIFY(intArray[14] == 2); EATEST_VERIFY(intArray[15] == 0); EATEST_VERIFY(intArray[16] == 2); EATEST_VERIFY(intArray[17] == 0); intArray.erase_last(0); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 17); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 1); EATEST_VERIFY(intArray[2] == 2); EATEST_VERIFY(intArray[3] == 0); EATEST_VERIFY(intArray[13] == 1); EATEST_VERIFY(intArray[14] == 2); EATEST_VERIFY(intArray[15] == 0); EATEST_VERIFY(intArray[16] == 2); // iterator erase_last_unsorted(const T& val); intArray.resize(20); for (i = 0; i < 20; i++) intArray[i] = (int)i / 2; // every two values are the same (i.e. 0,0,1,1,2,2,3,3...) intArray.erase_last_unsorted(1); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 19); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 0); EATEST_VERIFY(intArray[2] == 1); EATEST_VERIFY(intArray[3] == 9); EATEST_VERIFY(intArray[18] == 9); intArray.erase_last_unsorted(1); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 18); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 0); EATEST_VERIFY(intArray[2] == 9); EATEST_VERIFY(intArray[3] == 9); EATEST_VERIFY(intArray[17] == 8); intArray.erase_last_unsorted(0); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY(intArray.size() == 17); EATEST_VERIFY(intArray[0] == 0); EATEST_VERIFY(intArray[1] == 8); EATEST_VERIFY(intArray[2] == 9); EATEST_VERIFY(intArray[3] == 9); EATEST_VERIFY(intArray[16] == 8); } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { using namespace eastl; // iterator erase(reverse_iterator position); // iterator erase(reverse_iterator first, reverse_iterator last); // iterator erase_unsorted(reverse_iterator position); vector intVector; for (i = 0; i < 20; i++) intVector.push_back((int)i); EATEST_VERIFY((intVector.size() == 20) && (intVector[0] == 0) && (intVector[19] == 19)); vector::reverse_iterator r2A = intVector.rbegin(); vector::reverse_iterator r2B = r2A + 3; intVector.erase(r2A, r2B); EATEST_VERIFY((intVector.size() == 17)); EATEST_VERIFY((intVector[0] == 0)); EATEST_VERIFY((intVector[16] == 16)); r2B = intVector.rend(); r2A = r2B - 3; intVector.erase(r2A, r2B); EATEST_VERIFY((intVector.size() == 14)); EATEST_VERIFY((intVector[0] == 3)); EATEST_VERIFY((intVector[13] == 16)); r2B = intVector.rend() - 1; intVector.erase(r2B); EATEST_VERIFY((intVector.size() == 13)); EATEST_VERIFY((intVector[0] == 4)); EATEST_VERIFY((intVector[12] == 16)); r2B = intVector.rbegin(); intVector.erase(r2B); EATEST_VERIFY((intVector.size() == 12)); EATEST_VERIFY((intVector[0] == 4)); EATEST_VERIFY((intVector[11] == 15)); r2A = intVector.rbegin(); r2B = intVector.rend(); intVector.erase(r2A, r2B); EATEST_VERIFY(intVector.size() == 0); // iterator erase_unsorted(iterator position); intVector.resize(20); for (i = 0; i < 20; i++) intVector[i] = (int)i; intVector.erase_unsorted(intVector.rbegin() + 0); EATEST_VERIFY(intVector.validate()); EATEST_VERIFY(intVector.size() == 19); EATEST_VERIFY(intVector[0] == 0); EATEST_VERIFY(intVector[10] == 10); EATEST_VERIFY(intVector[18] == 18); intVector.erase_unsorted(intVector.rbegin() + 10); EATEST_VERIFY(intVector.validate()); EATEST_VERIFY(intVector.size() == 18); EATEST_VERIFY(intVector[0] == 0); EATEST_VERIFY(intVector[8] == 18); EATEST_VERIFY(intVector[17] == 17); intVector.erase_unsorted(intVector.rbegin() + 17); EATEST_VERIFY(intVector.validate()); EATEST_VERIFY(intVector.size() == 17); EATEST_VERIFY(intVector[0] == 17); EATEST_VERIFY(intVector[8] == 18); EATEST_VERIFY(intVector[16] == 16); } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { const int valueToRemove = 44; int testValues[] = {42, 43, 44, 45, 46, 47}; eastl::vector> v; for(auto& te : testValues) v.push_back(eastl::make_unique(te)); // remove 'valueToRemove' from the container auto iterToRemove = eastl::find_if(v.begin(), v.end(), [&](eastl::unique_ptr& e) { return *e == valueToRemove; }); v.erase_unsorted(iterToRemove); EATEST_VERIFY(v.size() == 5); // verify 'valueToRemove' is no longer in the container EATEST_VERIFY(eastl::find_if(v.begin(), v.end(), [&](eastl::unique_ptr& e) { return *e == valueToRemove; }) == v.end()); // verify all other expected values are in the container for (auto& te : testValues) { if (te == valueToRemove) continue; EATEST_VERIFY(eastl::find_if(v.begin(), v.end(), [&](eastl::unique_ptr& e) { return *e == te; }) != v.end()); } } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { using namespace eastl; // iterator insert(iterator position, const value_type& value); // iterator insert(iterator position, size_type n, const value_type& value); // iterator insert(iterator position, InputIterator first, InputIterator last); // iterator insert(const_iterator position, std::initializer_list ilist); vector v(7, 13); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector", 13, 13, 13, 13, 13, 13, 13, -1)); // insert at end of size and capacity. v.insert(v.end(), 99); EATEST_VERIFY(v.validate()); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 13, 13, 13, 13, 13, 13, 99, -1)); // insert at end of size. v.reserve(30); v.insert(v.end(), 999); EATEST_VERIFY(v.validate()); EATEST_VERIFY( VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 13, 13, 13, 13, 13, 13, 99, 999, -1)); // Insert in middle. vector::iterator it = v.begin() + 7; it = v.insert(it, 49); EATEST_VERIFY(v.validate()); EATEST_VERIFY( VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 13, 13, 13, 13, 13, 13, 49, 99, 999, -1)); // Insert multiple copies it = v.insert(v.begin() + 5, 3, 42); EATEST_VERIFY(it == v.begin() + 5); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 13, 13, 13, 13, 42, 42, 42, 13, 13, 49, 99, 999, -1)); // Insert multiple copies with count == 0 vector::iterator at = v.end(); it = v.insert(at, 0, 666); EATEST_VERIFY(it == at); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 13, 13, 13, 13, 42, 42, 42, 13, 13, 49, 99, 999, -1)); // Insert iterator range const int data[] = {2, 3, 4, 5}; it = v.insert(v.begin() + 1, data, data + 4); EATEST_VERIFY(it == v.begin() + 1); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 2, 3, 4, 5, 13, 13, 13, 13, 42, 42, 42, 13, 13, 49, 99, 999, -1)); // Insert empty iterator range at = v.begin() + 1; it = v.insert(at, data + 4, data + 4); EATEST_VERIFY(it == at); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 2, 3, 4, 5, 13, 13, 13, 13, 42, 42, 42, 13, 13, 49, 99, 999, -1)); // Insert with reallocation it = v.insert(v.end() - 3, 6, 17); EATEST_VERIFY(it == v.end() - (3 + 6)); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 2, 3, 4, 5, 13, 13, 13, 13, 42, 42, 42, 13, 13, 17, 17, 17, 17, 17, 17, 49, 99, 999, -1)); // Single insert with reallocation vector v2; v2.reserve(100); v2.insert(v2.begin(), 100, 17); EATEST_VERIFY(v2.size() == 100); EATEST_VERIFY(v2[0] == 17); v2.insert(v2.begin() + 50, 42); EATEST_VERIFY(v2.size() == 101); EATEST_VERIFY(v2[50] == 42); // Test insertion of values that come from within the vector. v.insert(v.end() - 3, v.end() - 5, v.end()); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 2, 3, 4, 5, 13, 13, 13, 13, 42, 42, 42, 13, 13, 17, 17, 17, 17, 17, 17, 17, 17, 49, 99, 999, 49, 99, 999, -1)); v.insert(v.end() - 3, v.back()); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 2, 3, 4, 5, 13, 13, 13, 13, 42, 42, 42, 13, 13, 17, 17, 17, 17, 17, 17, 17, 17, 49, 99, 999, 999, 49, 99, 999, -1)); v.insert(v.end() - 3, 2, v[v.size() - 3]); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.insert", 13, 2, 3, 4, 5, 13, 13, 13, 13, 42, 42, 42, 13, 13, 17, 17, 17, 17, 17, 17, 17, 17, 49, 99, 999, 999, 49, 49, 49, 99, 999, -1)); #if !defined(EASTL_STD_ITERATOR_CATEGORY_ENABLED) && !defined(EA_COMPILER_NO_STANDARD_CPP_LIBRARY) // std::vector / eastl::vector std::vector stdV(10); eastl::vector eastlV(10); eastlV.insert(eastlV.end(), stdV.begin(), stdV.end()); stdV.insert(stdV.end(), eastlV.begin(), eastlV.end()); EATEST_VERIFY(eastlV.size() == 20); EATEST_VERIFY(stdV.size() == 30); // std::string / eastl::vector std::string stdString("blah"); eastl::vector eastlVString; eastlVString.assign(stdString.begin(), stdString.end()); #endif // iterator insert(const_iterator position, std::initializer_list ilist); #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) // iterator insert(const_iterator position, std::initializer_list ilist); eastl::vector floatVector; floatVector.insert(floatVector.end(), {0, 1, 2, 3}); EATEST_VERIFY(floatVector.size() == 4); EATEST_VERIFY((floatVector[0] == 0) && (floatVector[3] == 3)); #endif } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { // Test insert move objects eastl::vector toVector1; toVector1.reserve(20); for(int idx = 0; idx < 2; ++idx) toVector1.push_back(TestObject(idx)); eastl::vector toVector2; for(int idx = 0; idx < 3; ++idx) toVector2.push_back(TestObject(10 + idx)); // Insert more objects than the existing number using insert with iterator TestObject::Reset(); eastl::vector::iterator it; it = toVector1.insert(toVector1.begin(), toVector2.begin(), toVector2.end()); EATEST_VERIFY(it == toVector1.begin()); EATEST_VERIFY(VerifySequence(toVector1.begin(), toVector1.end(), int(), "vector.insert", 10, 11, 12, 0, 1, -1)); EATEST_VERIFY(TestObject::sTOMoveCtorCount + TestObject::sTOMoveAssignCount == 2 && TestObject::sTOCopyCtorCount + TestObject::sTOCopyAssignCount == 3); // Move 2 existing elements and copy the 3 inserted eastl::vector toVector3; toVector3.push_back(TestObject(20)); // Insert less objects than the existing number using insert with iterator TestObject::Reset(); it = toVector1.insert(toVector1.begin(), toVector3.begin(), toVector3.end()); EATEST_VERIFY(VerifySequence(toVector1.begin(), toVector1.end(), int(), "vector.insert", 20, 10, 11, 12, 0, 1, -1)); EATEST_VERIFY(it == toVector1.begin()); EATEST_VERIFY(TestObject::sTOMoveCtorCount + TestObject::sTOMoveAssignCount == 5 && TestObject::sTOCopyCtorCount + TestObject::sTOCopyAssignCount == 1); // Move 5 existing elements and copy the 1 inserted // Insert more objects than the existing number using insert without iterator TestObject::Reset(); it = toVector1.insert(toVector1.begin(), 1, TestObject(17)); EATEST_VERIFY(it == toVector1.begin()); EATEST_VERIFY(VerifySequence(toVector1.begin(), toVector1.end(), int(), "vector.insert", 17, 20, 10, 11, 12, 0, 1, -1)); EATEST_VERIFY(TestObject::sTOMoveCtorCount + TestObject::sTOMoveAssignCount == 6 && TestObject::sTOCopyCtorCount + TestObject::sTOCopyAssignCount == 2); // Move 6 existing element and copy the 1 inserted + // the temporary one inside the function // Insert less objects than the existing number using insert without iterator TestObject::Reset(); it = toVector1.insert(toVector1.begin(), 10, TestObject(18)); EATEST_VERIFY(it == toVector1.begin()); EATEST_VERIFY(VerifySequence(toVector1.begin(), toVector1.end(), int(), "vector.insert", 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 17, 20, 10, 11, 12, 0, 1, -1)); EATEST_VERIFY(TestObject::sTOMoveCtorCount + TestObject::sTOMoveAssignCount == 7 && TestObject::sTOCopyCtorCount + TestObject::sTOCopyAssignCount == 11); // Move 7 existing element and copy the 10 inserted + // the temporary one inside the function } TestObject::Reset(); { using namespace eastl; // reserve / resize / capacity / clear vector v(10, 17); v.reserve(20); EATEST_VERIFY(v.validate()); EATEST_VERIFY(v.size() == 10); EATEST_VERIFY(v.capacity() == 20); v.resize(7); // Shrink EATEST_VERIFY(v.validate()); EATEST_VERIFY(v.capacity() == 20); v.resize(17); // Grow without reallocation EATEST_VERIFY(v.validate()); EATEST_VERIFY(v.capacity() == 20); v.resize(42); // Grow with reallocation vector::size_type c = v.capacity(); EATEST_VERIFY(v.validate()); EATEST_VERIFY(v[41] == 0); EATEST_VERIFY(c >= 42); v.resize(44, 19); // Grow with reallocation EATEST_VERIFY(v.validate()); EATEST_VERIFY(v[43] == 19); c = v.capacity(); v.clear(); EATEST_VERIFY(v.validate()); EATEST_VERIFY(v.empty()); EATEST_VERIFY(v.capacity() == c); // How to shrink a vector's capacity to be equal to its size. vector(v).swap(v); EATEST_VERIFY(v.validate()); EATEST_VERIFY(v.empty()); EATEST_VERIFY(v.capacity() == v.size()); // How to completely clear a vector (size = 0, capacity = 0, no allocation). vector().swap(v); EATEST_VERIFY(v.validate()); EATEST_VERIFY(v.empty()); EATEST_VERIFY(v.capacity() == 0); } { // set_capacity / reset using namespace eastl; const int intArray[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; const size_t kIntArraySize = sizeof(intArray) / sizeof(int); vector v(30); EATEST_VERIFY(v.capacity() >= 30); v.assign(intArray, intArray + kIntArraySize); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.assign", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, -1)); // set_capacity v.set_capacity(); EATEST_VERIFY(v.capacity() == v.size()); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.set_capacity", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, -1)); v.set_capacity(0); EATEST_VERIFY(v.size() == 0); EATEST_VERIFY(v.data() == NULL); EATEST_VERIFY(v.capacity() == v.size()); // Test set_capacity doing a realloc of non-scalar class types. eastl::vector toArray; toArray.resize(16); toArray.set_capacity(64); EATEST_VERIFY(v.validate()); // reset_lose_memory int* const pData = v.data(); vector::size_type n = v.size(); vector::allocator_type& allocator = v.get_allocator(); v.reset_lose_memory(); allocator.deallocate(pData, n); EATEST_VERIFY(v.capacity() == 0); EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "vector.reset", -1)); // Test set_capacity make a move when reducing size vector toArray2(10, TestObject(7)); TestObject::Reset(); toArray2.set_capacity(5); EATEST_VERIFY(TestObject::sTOMoveCtorCount == 5 && TestObject::sTOCopyCtorCount + TestObject::sTOCopyAssignCount == 0); // Move the 5 existing elements, no copy EATEST_VERIFY(VerifySequence(toArray2.begin(), toArray2.end(), int(), "vector.set_capacity", 7, 7, 7, 7, 7, -1)); } TestObject::Reset(); { using namespace eastl; // Regression for user-reported possible bug. { MallocAllocator::reset_all(); eastl::vector v; v.reserve(32); // does allocation v.push_back(37); // may reallocate if we do enough of these to exceed 32 v.erase(v.begin()); v.set_capacity(0); // Verify that all memory is freed by the set_capacity function. EATEST_VERIFY((MallocAllocator::mAllocCountAll > 0) && (MallocAllocator::mAllocCountAll == MallocAllocator::mFreeCountAll)); MallocAllocator::reset_all(); } { MallocAllocator::reset_all(); eastl::vector v; v.reserve(32); // does allocation for (int j = 0; j < 40; j++) v.push_back(37); // may reallocate if we do enough of these to exceed 32 for (int k = 0; k < 40; k++) v.erase(v.begin()); v.set_capacity(0); // Verify that all memory is freed by the set_capacity function. EATEST_VERIFY((MallocAllocator::mAllocCountAll > 0) && (MallocAllocator::mAllocCountAll == MallocAllocator::mFreeCountAll)); MallocAllocator::reset_all(); } } { using namespace eastl; // bool validate() const; // bool validate_iterator(const_iterator i) const; vector intArray(20); EATEST_VERIFY(intArray.validate()); EATEST_VERIFY((intArray.validate_iterator(intArray.begin()) & (isf_valid | isf_can_dereference)) != 0); EATEST_VERIFY(intArray.validate_iterator(NULL) == isf_none); } { using namespace eastl; // global operators (==, !=, <, etc.) vector intArray1(10); vector intArray2(10); for (i = 0; i < intArray1.size(); i++) { intArray1[i] = (int)i; // Make intArray1 equal to intArray2. intArray2[i] = (int)i; } EATEST_VERIFY((intArray1 == intArray2)); EATEST_VERIFY(!(intArray1 != intArray2)); EATEST_VERIFY((intArray1 <= intArray2)); EATEST_VERIFY((intArray1 >= intArray2)); EATEST_VERIFY(!(intArray1 < intArray2)); EATEST_VERIFY(!(intArray1 > intArray2)); intArray1.push_back(100); // Make intArray1 less than intArray2. intArray2.push_back(101); EATEST_VERIFY(!(intArray1 == intArray2)); EATEST_VERIFY((intArray1 != intArray2)); EATEST_VERIFY((intArray1 <= intArray2)); EATEST_VERIFY(!(intArray1 >= intArray2)); EATEST_VERIFY((intArray1 < intArray2)); EATEST_VERIFY(!(intArray1 > intArray2)); } { using namespace eastl; // Test vector // Aligned objects should be CustomAllocator instead of the default, because the // EASTL default might be unable to do aligned allocations, but CustomAllocator always can. vector vA64(10); vA64.resize(2); EATEST_VERIFY(vA64.size() == 2); vA64.push_back(Align64()); EATEST_VERIFY(vA64.size() == 3); vA64.resize(0); EATEST_VERIFY(vA64.size() == 0); vA64.insert(vA64.begin(), Align64()); EATEST_VERIFY(vA64.size() == 1); vA64.resize(20); EATEST_VERIFY(vA64.size() == 20); } { // Misc additional tests eastl::vector empty1; EATEST_VERIFY(empty1.data() == NULL); EATEST_VERIFY(empty1.size() == 0); EATEST_VERIFY(empty1.capacity() == 0); eastl::vector empty2 = empty1; EATEST_VERIFY(empty2.data() == NULL); EATEST_VERIFY(empty2.size() == 0); EATEST_VERIFY(empty2.capacity() == 0); } { // Test whose purpose is to see if calling vector::size() in a const loop results in the compiler optimizing the // size() call to outside the loop. eastl::vector toArray; toArray.resize(7); for (i = 0; i < toArray.size(); i++) { TestObject& to = toArray[i]; if (to.mX == 99999) to.mX++; } } { // Test assign from iterator type. TestObject to; eastl::vector toTest; // InputIterator demoted_iterator toInput(&to); toTest.assign(toInput, toInput); // ForwardIterator eastl::slist toSList; toTest.assign(toSList.begin(), toSList.end()); // BidirectionalIterator eastl::list toList; toTest.assign(toList.begin(), toList.end()); // RandomAccessIterator eastl::deque toDeque; toTest.assign(toDeque.begin(), toDeque.end()); // ContiguousIterator (note: as of this writing, vector doesn't actually use contiguous_iterator_tag) eastl::vector toArray; toTest.assign(toArray.begin(), toArray.end()); } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { // Test user report that they think they saw code like this leak memory. eastl::vector intTest; intTest.push_back(1); intTest = eastl::vector(); eastl::vector toTest; toTest.push_back(TestObject(1)); toTest = eastl::vector(); } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); { // Regression of user error report for the case of vector. eastl::vector ctorValues; for (int v = 0; v < 10; v++) ctorValues.push_back(v); eastl::vector testStruct(ctorValues.begin(), ctorValues.end()); eastl::vector testInt(ctorValues.begin(), ctorValues.end()); } { // Regression to verify that const vector works. const eastl::vector constIntVector1; EATEST_VERIFY(constIntVector1.empty()); int intArray[3] = {37, 38, 39}; const eastl::vector constIntVector2(intArray, intArray + 3); EATEST_VERIFY(constIntVector2.size() == 3); const eastl::vector constIntVector3(4, 37); EATEST_VERIFY(constIntVector3.size() == 4); const eastl::vector constIntVector4; const eastl::vector constIntVector5 = constIntVector4; } { // Regression to verify that a bug fix for a vector optimization works. eastl::vector intVector1; intVector1.reserve(128); intVector1.resize(128, 37); intVector1.push_back(intVector1.front()); EATEST_VERIFY(intVector1.back() == 37); eastl::vector intVector2; intVector2.reserve(1024); intVector2.resize(1024, 37); intVector2.resize(2048, intVector2.front()); EATEST_VERIFY(intVector2.back() == 37); } { // C++11 Range // EABase 2.00.34+ has EA_COMPILER_NO_RANGE_BASED_FOR_LOOP, which we can check instead. #if (defined(_MSC_VER) && (EA_COMPILER_VERSION >= 1700)) || \ (defined(__clang__) && (EA_COMPILER_VERSION >= 300) && (__cplusplus >= 201103L)) || \ (defined(__GNUC__) && (EA_COMPILER_VERSION >= 4006) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (__cplusplus >= 201103L) eastl::vector floatVector; floatVector.push_back(0.0); floatVector.push_back(1.0); for (auto& f : floatVector) f += 1.0; EATEST_VERIFY(floatVector.back() == 2.0); #endif } { // C++11 cbegin, cend, crbegin, crend #if !defined(EA_COMPILER_NO_AUTO) // float vector eastl::vector floatVector; auto cb = floatVector.cbegin(); auto ce = floatVector.cend(); auto crb = floatVector.crbegin(); auto cre = floatVector.crend(); EATEST_VERIFY(eastl::distance(cb, ce) == 0); EATEST_VERIFY(eastl::distance(crb, cre) == 0); // const float vector const eastl::vector cFloatVector; auto ccb = cFloatVector.cbegin(); auto cce = cFloatVector.cend(); auto ccrb = cFloatVector.crbegin(); auto ccre = cFloatVector.crend(); EATEST_VERIFY(eastl::distance(ccb, cce) == 0); EATEST_VERIFY(eastl::distance(ccrb, ccre) == 0); #endif } { // Regression for failure in DoRealloc's use of uninitialize_move. using namespace eastl; const eastl::string str0 = "TestString0"; vector v(1, str0); vector v_copy; // Test operator= v_copy = v; EATEST_VERIFY_MSG(v_copy.size() == 1, "vector string8 copy size"); EATEST_VERIFY_MSG(eastl::find(v_copy.begin(), v_copy.end(), str0) != v_copy.end(), "vector copy string8"); EATEST_VERIFY_MSG(v.size() == 1, "vector string8 copy size"); EATEST_VERIFY_MSG(eastl::find(v.begin(), v.end(), str0) != v.end(), "vector copy string8"); // Test assign. v.clear(); v.push_back(str0); v_copy.assign(v.begin(), v.end()); EATEST_VERIFY_MSG(v_copy.size() == 1, "vector string8 copy size"); EATEST_VERIFY_MSG(eastl::find(v_copy.begin(), v_copy.end(), str0) != v_copy.end(), "vector copy string8"); EATEST_VERIFY_MSG(v.size() == 1, "vector string8 copy size"); EATEST_VERIFY_MSG(eastl::find(v.begin(), v.end(), str0) != v.end(), "vector copy string8"); } { // Regression of vector::operator= for the case of EASTL_ALLOCATOR_COPY_ENABLED=1 // For this test we need to use InstanceAllocator to create two containers of the same // type but with different and unequal allocator instances. The bug was that when // EASTL_ALLOCATOR_COPY_ENABLED was enabled operator=(this_type& x) assigned x.mAllocator // to this and then proceeded to assign member elements from x to this. That's invalid // because the existing elements of this were allocated by a different allocator and // will be freed in the future with the allocator copied from x. // The test below should work for the case of EASTL_ALLOCATOR_COPY_ENABLED == 0 or 1. InstanceAllocator::reset_all(); InstanceAllocator ia0((uint8_t)0); InstanceAllocator ia1((uint8_t)1); eastl::vector v0((eastl_size_t)1, (int)0, ia0); eastl::vector v1((eastl_size_t)1, (int)1, ia1); EATEST_VERIFY((v0.front() == 0) && (v1.front() == 1)); #if EASTL_ALLOCATOR_COPY_ENABLED EATEST_VERIFY(v0.get_allocator() != v1.get_allocator()); #endif v0 = v1; EATEST_VERIFY((v0.front() == 1) && (v1.front() == 1)); EATEST_VERIFY(InstanceAllocator::mMismatchCount == 0); EATEST_VERIFY(v0.validate()); EATEST_VERIFY(v1.validate()); #if EASTL_ALLOCATOR_COPY_ENABLED EATEST_VERIFY(v0.get_allocator() == v1.get_allocator()); #endif } { // Test shrink_to_fit eastl::vector v; EATEST_VERIFY(v.capacity() == 0); v.resize(100); EATEST_VERIFY(v.capacity() == 100); v.clear(); EATEST_VERIFY(v.capacity() == 100); v.shrink_to_fit(); EATEST_VERIFY(v.capacity() == 0); } { // Regression for compilation errors found and fixed when integrating into Frostbite. int j = 7; eastl::vector v1; v1.push_back(StructWithConstInt(j)); eastl::vector v2; v2.push_back(StructWithConstRefToInt(j)); } { // Regression for issue with vector containing non-copyable values reported by user eastl::vector moveablevec; testmovable moveable; moveablevec.insert(moveablevec.end(), eastl::move(moveable)); } { // Calling erase of empty range should not call a move assignment to self eastl::vector v1; v1.push_back(TestMoveAssignToSelf()); EATEST_VERIFY(!v1[0].mMovedToSelf); v1.erase(v1.begin(), v1.begin()); EATEST_VERIFY(!v1[0].mMovedToSelf); } #if defined(EASTL_TEST_CONCEPT_IMPLS) { // vector default constructor should require no more than Destructible eastl::vector v1; EATEST_VERIFY(v1.empty()); // some basic vector operations (data(), capacity(), size(), empty(), clear(), erase()) should impose no // requirements beyond Destructible EATEST_VERIFY(v1.empty()); EATEST_VERIFY(v1.size() == 0); EATEST_VERIFY(v1.capacity() == 0); EATEST_VERIFY(eastl::distance(v1.data(), v1.data() + v1.size()) == 0); v1.clear(); } { // vector default constructor should work with DefaultConstructible T eastl::vector v1; EATEST_VERIFY(v1.empty()); } { // vector constructor that takes an initial size should only require DefaultConstructible T eastl::vector v2(2); EATEST_VERIFY(v2.size() == 2 && v2[0].value == v2[1].value && v2[0].value == DefaultConstructible::defaultValue); } { // vector constructor taking an initial size and a value should only require CopyConstructible eastl::vector v3(2, CopyConstructible::Create()); EATEST_VERIFY(v3.size() == 2 && v3[0].value == v3[1].value && v3[0].value == CopyConstructible::defaultValue); // vector constructor taking a pair of iterators should work for CopyConstructible eastl::vector v4(cbegin(v3), cend(v3)); EATEST_VERIFY(v4.size() == 2 && v4[0].value == v4[1].value && v4[0].value == CopyConstructible::defaultValue); } { // vector::reserve() should only require MoveInsertible eastl::vector v5; v5.reserve(2); v5.push_back(MoveConstructible::Create()); v5.push_back(MoveConstructible::Create()); EATEST_VERIFY(v5.size() == 2 && v5[0].value == v5[1].value && v5[0].value == MoveConstructible::defaultValue); v5.pop_back(); // vector::shrink_to_fit() should only require MoveInsertible v5.shrink_to_fit(); EATEST_VERIFY(v5.size() == 1 && v5.capacity() == 1 && v5[0].value == MoveConstructible::defaultValue); } { // vector constructor taking a pair of iterators should only require MoveConstructible MoveConstructible moveConstructibleArray[] = {MoveConstructible::Create()}; eastl::vector v7( eastl::move_iterator(eastl::begin(moveConstructibleArray)), eastl::move_iterator(eastl::end(moveConstructibleArray))); EATEST_VERIFY(v7.size() == 1 && v7[0].value == MoveConstructible::defaultValue); } { // vector::swap() should only require Destructible. We also test with DefaultConstructible as it gives us a // testable result. eastl::vector v4, v5; eastl::swap(v4, v5); EATEST_VERIFY(v4.empty() && v5.empty()); eastl::vector v6(1), v7(2); eastl::swap(v6, v7); EATEST_VERIFY(v6.size() == 2 && v7.size() == 1); } { // vector::resize() should only require MoveInsertable and DefaultInsertable eastl::vector v8; v8.resize(2); EATEST_VERIFY(v8.size() == 2 && v8[0].value == v8[1].value && v8[0].value == MoveAndDefaultConstructible::defaultValue); } { eastl::vector v1; // vector::insert(pos, rv) should only require MoveAssignable v1.insert(begin(v1), MoveAssignable::Create()); EATEST_VERIFY(v1.size() == 1 && v1.front().value == MoveAssignable::defaultValue); // vector::erase(pos) should only require MoveAssignable v1.erase(begin(v1)); EATEST_VERIFY(v1.empty()); } #endif // EASTL_TEST_CONCEPT_IMPLS { // validates our vector implementation does not use 'operator<' on input iterators during vector construction. // struct container_value_type { int data; }; struct container_with_custom_iterator { struct iterator { typedef eastl::input_iterator_tag iterator_category; typedef int value_type; typedef ptrdiff_t difference_type; typedef int* pointer; typedef int& reference; bool operator!=(const iterator&) const { return false; } iterator& operator++() { return *this; } iterator operator++(int) { return *this; } container_value_type operator*() { return {}; } }; container_with_custom_iterator() EA_NOEXCEPT {} iterator begin() const { return {}; } iterator end() const { return {}; } bool empty() const { return false; } private: eastl::vector m_vector; }; static_assert(!is_less_comparable::value, "type cannot support comparison by '<' for this test"); container_with_custom_iterator ci; eastl::vector v2(ci.begin(), ci.end()); } // If the legacy code path is enabled we cannot handle non-copyable types #ifndef EASTL_VECTOR_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR // unique_ptr tests { // Simple move-assignment test to prevent regressions where eastl::vector utilizes operations on T that are not necessary. { eastl::vector> v1; eastl::vector> v2; v2 = eastl::move(v1); } { // This test verifies that eastl::vector can handle the move-assignment case where its utilizes two // different allocator instances that do not compare equal. An example of an allocator that compares equal // but isn't the same object instance is an allocator that shares the same memory allocation mechanism (eg. // malloc). The memory allocated from one instance can be freed by another instance in the case where // allocators compare equal. This test is verifying functionality in the opposite case where allocators // instances do not compare equal and must clean up its own allocated memory. InstanceAllocator::reset_all(); { InstanceAllocator a1(uint8_t(0)), a2(uint8_t(1)); eastl::vector, InstanceAllocator> v1(a1); eastl::vector, InstanceAllocator> v2(a2); VERIFY(v1.get_allocator() != v2.get_allocator()); // add some data in the vector so we can move it to the other vector. v1.push_back(nullptr); v1.push_back(nullptr); v1.push_back(nullptr); v1.push_back(nullptr); VERIFY(!v1.empty() && v2.empty()); v2 = eastl::move(v1); VERIFY(v1.empty() && !v2.empty()); v1.swap(v2); VERIFY(!v1.empty() && v2.empty()); } VERIFY(InstanceAllocator::mMismatchCount == 0); } } #endif { // CustomAllocator has no data members which reduces the size of an eastl::vector via the empty base class optimization. typedef eastl::vector EboVector; static_assert(sizeof(EboVector) == 3 * sizeof(void*), ""); } // eastl::erase / eastl::erase_if tests { { eastl::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; eastl::erase(v, 5); VERIFY((v == eastl::vector {1, 2, 3, 4, 6, 7, 8, 9})); eastl::erase(v, 2); VERIFY((v == eastl::vector {1, 3, 4, 6, 7, 8, 9})); eastl::erase(v, 9); VERIFY((v == eastl::vector {1, 3, 4, 6, 7, 8})); } { eastl::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; eastl::erase_if(v, [](auto i) { return i % 2 == 0; }); VERIFY((v == eastl::vector{1, 3, 5, 7, 9})); } } return nErrorCount; }