diff options
Diffstat (limited to 'test/source/TestVector.cpp')
-rw-r--r-- | test/source/TestVector.cpp | 1739 |
1 files changed, 1739 insertions, 0 deletions
diff --git a/test/source/TestVector.cpp b/test/source/TestVector.cpp new file mode 100644 index 0000000..0fe719d --- /dev/null +++ b/test/source/TestVector.cpp @@ -0,0 +1,1739 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + +#include "EASTLTest.h" +#include <EASTL/vector.h> +#include <EASTL/string.h> +#include <EASTL/deque.h> +#include <EASTL/list.h> +#include <EASTL/slist.h> +#include <EASTL/algorithm.h> +#include <EASTL/utility.h> +#include <EASTL/allocator_malloc.h> +#include <EASTL/unique_ptr.h> + +#include "ConceptImpls.h" + + +EA_DISABLE_ALL_VC_WARNINGS() +#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY + #include <vector> + #include <string> +#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<bool>; +template class eastl::vector<int>; +template class eastl::vector<Align64>; +template class eastl::vector<TestObject>; + + +// 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<HasAddressOfOperator>; // force compile all functions of vector + + + +// Test compiler issue that appeared in VS2012 relating to kAlignment +struct StructWithContainerOfStructs +{ + eastl::vector<StructWithContainerOfStructs> 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<RowEntry> RowData; + RowData Rows; +}; +typedef eastl::vector<ScenarioRefEntry> ScenarRefData; +struct AntMetaDataRecord +{ + ScenarRefData ScenarioRefs; +}; +typedef eastl::vector<AntMetaDataRecord> 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 <operator. + template <class, class = eastl::void_t<>> + struct is_less_comparable : eastl::false_type { }; + template <class T> + struct is_less_comparable<T, eastl::void_t<decltype(eastl::declval<T>() < eastl::declval<T>())>> : eastl::true_type { }; +#else + // bypass the test since the compiler doesn't support variable templates. + template <class> 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<int> intArray1; + vector<TestObject> toArray1; + vector<list<TestObject> > 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<int, MallocAllocator> intArray6(ma); + vector<TestObject, MallocAllocator> toArray6(ma); + vector<list<TestObject>, 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<int> intArray2(10); + vector<TestObject> toArray2(10); + vector<list<TestObject> > 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<int> intArray3(10, 7); + vector<TestObject> toArray3(10, TestObject(7)); + vector<list<TestObject> > toListArray3(10, list<TestObject>(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<TestObject>(7)); + + // vector(const vector& x) + vector<int> intArray4(intArray2); + vector<TestObject> toArray4(toArray2); + vector<list<TestObject> > 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<int, MallocAllocator> intArray7(intArray6, ma); + vector<TestObject, MallocAllocator> toArray7(toArray6, ma); + vector<list<TestObject>, MallocAllocator> toListArray7(toListArray6, ma); + EATEST_VERIFY(MallocAllocator::mAllocCountAll == 3); + + // vector(InputIterator first, InputIterator last) + deque<int> intDeque(3); + deque<TestObject> toDeque(3); + deque<list<TestObject> > toListDeque(3); + + vector<int> intArray5(intDeque.begin(), intDeque.end()); + vector<TestObject> toArray5(toDeque.begin(), toDeque.end()); + vector<list<TestObject> > toListArray5(toListDeque.begin(), toListDeque.end()); + + // vector(std::initializer_list<T> ilist, const Allocator& allocator = EASTL_VECTOR_DEFAULT_ALLOCATOR); + { +#if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) + eastl::vector<float> 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<T> 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<TestObject> vector3TO33(3, TestObject(33)); + vector<TestObject> 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<TestObject, MallocAllocator> vector4TO44(4, TestObject(44)); + vector<TestObject, MallocAllocator> toVectorB(eastl::move(vector4TO44), MallocAllocator()); + EATEST_VERIFY((toVectorB.size() == 4) && (toVectorB.front().mX == 44) && (vector4TO44.size() == 0)); + + vector<TestObject, MallocAllocator> 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<ItemWithConst> 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<int> 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<TestObject> 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<int> intArray(20); + for (i = 0; i < 20; i++) + intArray[i] = (int)i; + + i = 0; + for (vector<int>::iterator it = intArray.begin(); it != intArray.end(); ++it, ++i) + EATEST_VERIFY(*it == (int)i); + + i = intArray.size() - 1; + for (vector<int>::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<int> v3; + v3.assign(A, A + N); + EATEST_VERIFY(equal(v3.begin(), v3.end(), A)); + EATEST_VERIFY(v3.size() == N); + + // assign from iterator range + vector<int> 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<T> 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<int> intArray(5); + EATEST_VERIFY(intArray[3] == 0); + EATEST_VERIFY(intArray.at(3) == 0); + + vector<TestObject> toArray(5); + EATEST_VERIFY(toArray[3] == TestObject(0)); + EATEST_VERIFY(toArray.at(3) == TestObject(0)); + +#if EASTL_EXCEPTIONS_ENABLED + vector<TestObject> 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<int> 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<TestObject> 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<int64_t>(i))); + + new (pTO) TestObject((int)i); + EATEST_VERIFY(TestObject::sTOCount == (toCount0 + static_cast<int64_t>(i) + 1)); + EATEST_VERIFY(vTO.back().mX == (int)i); + EATEST_VERIFY(vTO.validate()); + } + } + + { + using namespace eastl; + + // template<class... Args> + // iterator emplace(const_iterator position, Args&&... args); + + // template<class... Args> + // void emplace_back(Args&&... args); + + // iterator insert(const_iterator position, value_type&& value); + // void push_back(value_type&& value); + + TestObject::Reset(); + + vector<TestObject> 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<TestObject> 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<int> 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<TestObject> 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<int> intVector; + + for (i = 0; i < 20; i++) + intVector.push_back((int)i); + EATEST_VERIFY((intVector.size() == 20) && (intVector[0] == 0) && (intVector[19] == 19)); + + vector<int>::reverse_iterator r2A = intVector.rbegin(); + vector<int>::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<eastl::unique_ptr<int>> v; + + for(auto& te : testValues) + v.push_back(eastl::make_unique<int>(te)); + + // remove 'valueToRemove' from the container + auto iterToRemove = eastl::find_if(v.begin(), v.end(), [&](eastl::unique_ptr<int>& 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<int>& 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<int>& 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<T> ilist); + + vector<int> 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<int>::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<int>::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<int> 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<TestObject> stdV(10); + eastl::vector<TestObject> 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<char8_t> eastlVString; + + eastlVString.assign(stdString.begin(), stdString.end()); +#endif + +// iterator insert(const_iterator position, std::initializer_list<T> ilist); +#if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) + // iterator insert(const_iterator position, std::initializer_list<T> ilist); + eastl::vector<float> 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<TestObject> toVector1; + toVector1.reserve(20); + for(int idx = 0; idx < 2; ++idx) + toVector1.push_back(TestObject(idx)); + + eastl::vector<TestObject> 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<TestObject>::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<TestObject> 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<int> 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<int>::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<int>(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<int>().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<int> 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<TestObject> toArray; + toArray.resize(16); + toArray.set_capacity(64); + EATEST_VERIFY(v.validate()); + + // reset_lose_memory + int* const pData = v.data(); + vector<int>::size_type n = v.size(); + vector<int>::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<TestObject> 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<int, MallocAllocator> 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<int, MallocAllocator> 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<int> 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<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; + } + + 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<Align64> + + // 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<Align64, CustomAllocator> 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<int> empty1; + EATEST_VERIFY(empty1.data() == NULL); + EATEST_VERIFY(empty1.size() == 0); + EATEST_VERIFY(empty1.capacity() == 0); + + eastl::vector<int> 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<TestObject> 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<TestObject> toTest; + + // InputIterator + demoted_iterator<TestObject*, eastl::forward_iterator_tag> toInput(&to); + toTest.assign(toInput, toInput); + + // ForwardIterator + eastl::slist<TestObject> toSList; + toTest.assign(toSList.begin(), toSList.end()); + + // BidirectionalIterator + eastl::list<TestObject> toList; + toTest.assign(toList.begin(), toList.end()); + + // RandomAccessIterator + eastl::deque<TestObject> toDeque; + toTest.assign(toDeque.begin(), toDeque.end()); + + // ContiguousIterator (note: as of this writing, vector doesn't actually use contiguous_iterator_tag) + eastl::vector<TestObject> 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<int> intTest; + + intTest.push_back(1); + intTest = eastl::vector<int>(); + + eastl::vector<TestObject> toTest; + + toTest.push_back(TestObject(1)); + toTest = eastl::vector<TestObject>(); + } + + EATEST_VERIFY(TestObject::IsClear()); + TestObject::Reset(); + + { // Regression of user error report for the case of vector<const type>. + eastl::vector<int> ctorValues; + + for (int v = 0; v < 10; v++) + ctorValues.push_back(v); + + eastl::vector<const ConstType> testStruct(ctorValues.begin(), ctorValues.end()); + eastl::vector<const int> testInt(ctorValues.begin(), ctorValues.end()); + } + + { // Regression to verify that const vector works. + const eastl::vector<int> constIntVector1; + EATEST_VERIFY(constIntVector1.empty()); + + int intArray[3] = {37, 38, 39}; + const eastl::vector<int> constIntVector2(intArray, intArray + 3); + EATEST_VERIFY(constIntVector2.size() == 3); + + const eastl::vector<int> constIntVector3(4, 37); + EATEST_VERIFY(constIntVector3.size() == 4); + + const eastl::vector<int> constIntVector4; + const eastl::vector<int> constIntVector5 = constIntVector4; + } + + { // Regression to verify that a bug fix for a vector optimization works. + eastl::vector<int> intVector1; + intVector1.reserve(128); + intVector1.resize(128, 37); + intVector1.push_back(intVector1.front()); + EATEST_VERIFY(intVector1.back() == 37); + + eastl::vector<int> 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<float> 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<float> 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<float> 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<eastl::string> v(1, str0); + vector<eastl::string> 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<int, InstanceAllocator> v0((eastl_size_t)1, (int)0, ia0); + eastl::vector<int, InstanceAllocator> 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<int> 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<StructWithConstInt> v1; + v1.push_back(StructWithConstInt(j)); + + eastl::vector<StructWithConstRefToInt> v2; + v2.push_back(StructWithConstRefToInt(j)); + } + + { + // Regression for issue with vector containing non-copyable values reported by user + eastl::vector<testmovable> 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<TestMoveAssignToSelf> 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<Destructible> 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<DefaultConstructible> v1; + EATEST_VERIFY(v1.empty()); + } + + { + // vector constructor that takes an initial size should only require DefaultConstructible T + eastl::vector<DefaultConstructible> 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<CopyConstructible> 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<CopyConstructible> 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<MoveConstructible> 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<MoveConstructible> v7( + eastl::move_iterator<MoveConstructible*>(eastl::begin(moveConstructibleArray)), + eastl::move_iterator<MoveConstructible*>(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<Destructible> v4, v5; + eastl::swap(v4, v5); + EATEST_VERIFY(v4.empty() && v5.empty()); + + eastl::vector<DefaultConstructible> 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<MoveAndDefaultConstructible> v8; + v8.resize(2); + EATEST_VERIFY(v8.size() == 2 && v8[0].value == v8[1].value && v8[0].value == + MoveAndDefaultConstructible::defaultValue); + } + + { + eastl::vector<MoveAssignable> 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<container_value_type> m_vector; + }; + + static_assert(!is_less_comparable<container_with_custom_iterator::iterator>::value, "type cannot support comparison by '<' for this test"); + container_with_custom_iterator ci; + eastl::vector<container_value_type> 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<eastl::unique_ptr<int>> v1; + eastl::vector<eastl::unique_ptr<int>> 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<eastl::unique_ptr<int>, InstanceAllocator> v1(a1); + eastl::vector<eastl::unique_ptr<int>, 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<int, CustomAllocator> EboVector; + static_assert(sizeof(EboVector) == 3 * sizeof(void*), ""); + } + + // eastl::erase / eastl::erase_if tests + { + { + eastl::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + + eastl::erase(v, 5); + VERIFY((v == eastl::vector<int> {1, 2, 3, 4, 6, 7, 8, 9})); + + eastl::erase(v, 2); + VERIFY((v == eastl::vector<int> {1, 3, 4, 6, 7, 8, 9})); + + eastl::erase(v, 9); + VERIFY((v == eastl::vector<int> {1, 3, 4, 6, 7, 8})); + } + + { + eastl::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + eastl::erase_if(v, [](auto i) { return i % 2 == 0; }); + VERIFY((v == eastl::vector<int>{1, 3, 5, 7, 9})); + } + } + + return nErrorCount; +} |