///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// #include "EASTLTest.h" #include #include #include #include #include #include #include #include using namespace eastl; // Template instantations. // These tell the compiler to compile all the functions for the given class. template class eastl::ring_buffer< int, eastl::vector >; template class eastl::ring_buffer< Align64, eastl::vector >; template class eastl::ring_buffer< TestObject, eastl::vector >; template class eastl::ring_buffer< int, eastl::deque >; template class eastl::ring_buffer< Align64, eastl::deque >; template class eastl::ring_buffer< TestObject, eastl::deque >; template class eastl::ring_buffer< int, eastl::list >; template class eastl::ring_buffer< Align64, eastl::list >; template class eastl::ring_buffer< TestObject, eastl::list >; // TODO(rparolin): To consider adding support for eastl::array. // template class eastl::ring_buffer< int, eastl::array>; typedef eastl::fixed_string RBFixedString; typedef eastl::fixed_vector RBFixedStringVector; typedef RBFixedStringVector::overflow_allocator_type RBFixedStringVectorOverflowAllocator; template class eastl::ring_buffer; typedef eastl::fixed_vector RBFixedIntVector; template class eastl::ring_buffer; // template class eastl::ring_buffer; // currently fails to compile typedef eastl::fixed_vector RBFixedIntVectorWithOverFlow; template class eastl::ring_buffer; // template class eastl::ring_buffer; // currently fails to compile int TestRingBuffer() { int nErrorCount = 0; // GCC prior to 4.1 has a fatal code generation bug in string arrays, which we use below. #if !defined(EA_DEBUG) && defined(__GNUC__) && !defined(__EDG__) && (((__GNUC__ * 100) + __GNUC_MINOR__) < 401) return nErrorCount; #endif { // regression for bug in the capacity() function for the case of capacity == 0. vector emptyIntArray; ring_buffer > intRingBuffer(emptyIntArray); EATEST_VERIFY(intRingBuffer.validate()); EATEST_VERIFY(intRingBuffer.capacity() == 0); intRingBuffer.resize(0); EATEST_VERIFY(intRingBuffer.validate()); EATEST_VERIFY(intRingBuffer.size() == 0); intRingBuffer.resize(1); EATEST_VERIFY(intRingBuffer.validate()); EATEST_VERIFY(intRingBuffer.size() == 1); } { EA::UnitTest::Rand rng(EA::UnitTest::GetRandSeed()); typedef ring_buffer< string, vector > RBVectorString; int counter = 0; char counterBuffer[32]; // explicit ring_buffer(size_type size = 0); const int kOriginalCapacity = 50; RBVectorString rbVectorString(50); // bool empty() const; // size_type size() const; // bool validate() const; EATEST_VERIFY(rbVectorString.validate()); EATEST_VERIFY(rbVectorString.empty()); EATEST_VERIFY(rbVectorString.size() == 0); EATEST_VERIFY(rbVectorString.capacity() == 50); // void clear(); rbVectorString.clear(); EATEST_VERIFY(rbVectorString.validate()); EATEST_VERIFY(rbVectorString.empty()); EATEST_VERIFY(rbVectorString.size() == 0); EATEST_VERIFY(rbVectorString.capacity() == 50); // container_type& get_container(); RBVectorString::container_type& c = rbVectorString.get_container(); EATEST_VERIFY(c.size() == (kOriginalCapacity + 1)); // We need to add one because the ring_buffer mEnd is necessarily an unused element. // iterator begin(); // iterator end(); // int validate_iterator(const_iterator i) const; RBVectorString::iterator it = rbVectorString.begin(); EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current)); while(it != rbVectorString.end()) // This loop should do nothing. { EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current)); ++it; } // void push_back(const value_type& value); sprintf(counterBuffer, "%d", counter++); rbVectorString.push_back(string(counterBuffer)); EATEST_VERIFY(rbVectorString.validate()); EATEST_VERIFY(!rbVectorString.empty()); EATEST_VERIFY(rbVectorString.size() == 1); EATEST_VERIFY(rbVectorString.capacity() == 50); it = rbVectorString.begin(); EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); EATEST_VERIFY(*it == "0"); // reference front(); // reference back(); string& sFront = rbVectorString.front(); string& sBack = rbVectorString.back(); EATEST_VERIFY(&sFront == &sBack); // void push_back(); string& ref = rbVectorString.push_back(); EATEST_VERIFY(rbVectorString.validate()); EATEST_VERIFY(rbVectorString.size() == 2); EATEST_VERIFY(rbVectorString.capacity() == 50); EATEST_VERIFY(&ref == &rbVectorString.back()); it = rbVectorString.begin(); ++it; EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); EATEST_VERIFY(it->empty()); sprintf(counterBuffer, "%d", counter++); *it = counterBuffer; EATEST_VERIFY(*it == "1"); ++it; EATEST_VERIFY(it == rbVectorString.end()); it = rbVectorString.begin(); while(it != rbVectorString.end()) { EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); ++it; } // reference operator[](size_type n); string& s0 = rbVectorString[0]; EATEST_VERIFY(s0 == "0"); string& s1 = rbVectorString[1]; EATEST_VERIFY(s1 == "1"); // Now we start hammering the ring buffer with push_back. for(eastl_size_t i = 0, iEnd = rbVectorString.capacity() * 5; i != iEnd; i++) { sprintf(counterBuffer, "%d", counter++); rbVectorString.push_back(string(counterBuffer)); EATEST_VERIFY(rbVectorString.validate()); } int counterCheck = counter - 1; char counterCheckBuffer[32]; sprintf(counterCheckBuffer, "%d", counterCheck); EATEST_VERIFY(rbVectorString.back() == counterCheckBuffer); // reverse_iterator rbegin(); // reverse_iterator rend(); for(RBVectorString::reverse_iterator ri = rbVectorString.rbegin(); ri != rbVectorString.rend(); ++ri) { sprintf(counterCheckBuffer, "%d", counterCheck--); EATEST_VERIFY(*ri == counterCheckBuffer); } ++counterCheck; // iterator begin(); // iterator end(); for(RBVectorString::iterator i = rbVectorString.begin(); i != rbVectorString.end(); ++i) { EATEST_VERIFY(rbVectorString.validate_iterator(i) == (isf_valid | isf_current | isf_can_dereference)); EATEST_VERIFY(*i == counterCheckBuffer); sprintf(counterCheckBuffer, "%d", ++counterCheck); } // void clear(); rbVectorString.clear(); EATEST_VERIFY(rbVectorString.validate()); EATEST_VERIFY(rbVectorString.empty()); EATEST_VERIFY(rbVectorString.size() == 0); EATEST_VERIFY(rbVectorString.capacity() == 50); // Random operations // Not easy to test the expected values without some tedium. for(int j = 0; j < 10000 + (gEASTL_TestLevel * 10000); j++) { sprintf(counterBuffer, "%d", counter++); const eastl_size_t op = rng.RandLimit(12); const eastl_size_t s = rbVectorString.size(); if(op == 0) { // void push_back(const value_type& value); rbVectorString.push_back(string(counterBuffer)); EATEST_VERIFY(rbVectorString.size() == eastl::min(s + 1, rbVectorString.capacity())); } else if(op == 1) { // void push_back(); string& ref2 = rbVectorString.push_back(); rbVectorString.back() = string(counterBuffer); EATEST_VERIFY(rbVectorString.size() == eastl::min(s + 1, rbVectorString.capacity())); EATEST_VERIFY(&ref2 == &rbVectorString.back()); } else if(op == 2) { // void pop_back(); if(!rbVectorString.empty()) { rbVectorString.pop_back(); EATEST_VERIFY(rbVectorString.size() == (s - 1)); } } else if(op == 3) { // void push_front(const value_type& value); rbVectorString.push_front(string(counterBuffer)); EATEST_VERIFY(rbVectorString.size() == eastl::min(s + 1, rbVectorString.capacity())); } else if(op == 4) { // void push_front(); string& ref2 = rbVectorString.push_front(); rbVectorString.front() = string(counterBuffer); EATEST_VERIFY(rbVectorString.size() == eastl::min(s + 1, rbVectorString.capacity())); EATEST_VERIFY(&ref2 == &rbVectorString.front()); } else if(op == 5) { // void pop_front(); if(!rbVectorString.empty()) { rbVectorString.pop_front(); EATEST_VERIFY(rbVectorString.size() == (s - 1)); } } else if(op == 6) { // iterator insert(iterator position, const value_type& value); it = rbVectorString.begin(); const eastl_size_t dist = rng.RandLimit((uint32_t)s + 1); eastl::advance(it, dist); if(it == rbVectorString.end()) EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current)); else EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); rbVectorString.insert(it, string(counterBuffer)); EATEST_VERIFY(rbVectorString.size() == eastl::min(s + 1, rbVectorString.capacity())); } else if(op == 7) { // void insert(iterator position, size_type n, const value_type& value); it = rbVectorString.begin(); const eastl_size_t dist = rng.RandLimit((uint32_t)s + 1); eastl::advance(it, dist); if(it == rbVectorString.end()) EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current)); else EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); const eastl_size_t count = (eastl_size_t)rng.RandLimit(10); rbVectorString.insert(it, count, string(counterBuffer)); EATEST_VERIFY(rbVectorString.size() == eastl::min(s + count, rbVectorString.capacity())); } else if(op == 8) { // template // void insert(iterator position, InputIterator first, InputIterator last); string stringArray[10]; it = rbVectorString.begin(); const eastl_size_t dist = rng.RandLimit((uint32_t)s + 1); eastl::advance(it, dist); if(it == rbVectorString.end()) EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current)); else EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); const eastl_size_t count = (eastl_size_t)rng.RandLimit(10); rbVectorString.insert(it, stringArray, stringArray + count); EATEST_VERIFY(rbVectorString.size() == eastl::min(s + count, rbVectorString.capacity())); } else if(op == 9) { // iterator erase(iterator position); if(!rbVectorString.empty()) { it = rbVectorString.begin(); const eastl_size_t dist = rng.RandLimit((uint32_t)s); eastl::advance(it, dist); EATEST_VERIFY(rbVectorString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); rbVectorString.erase(it); EATEST_VERIFY(rbVectorString.size() == (s - 1)); } } else if(op == 10) { // iterator erase(iterator first, iterator last); if(!rbVectorString.empty()) { RBVectorString::iterator it1 = rbVectorString.begin(); const eastl_size_t pos = rng.RandLimit((uint32_t)s / 4); eastl::advance(it1, pos); EATEST_VERIFY(rbVectorString.validate_iterator(it1) == (isf_valid | isf_current | isf_can_dereference)); RBVectorString::iterator it2 = it1; const eastl_size_t dist = rng.RandLimit((uint32_t)s / 4); eastl::advance(it2, dist); EATEST_VERIFY(rbVectorString.validate_iterator(it2) == (isf_valid | isf_current | isf_can_dereference)); EATEST_VERIFY(s > (pos + dist)); rbVectorString.erase(it1, it2); EATEST_VERIFY(rbVectorString.size() == (s - dist)); } } else if(op == 11) { // void resize(size_type n); const eastl_size_t nSubOp = rng.RandLimit(100); if(nSubOp == 1) { rbVectorString.resize(kOriginalCapacity); EATEST_VERIFY(rbVectorString.size() == (RBVectorString::size_type)kOriginalCapacity); } else if(nSubOp == 2) { const eastl_size_t newSize = rng.RandLimit((uint32_t)s * 2) + 2; rbVectorString.resize(newSize); EATEST_VERIFY(rbVectorString.size() == newSize); } else if(nSubOp == 3) { rbVectorString.clear(); EATEST_VERIFY(rbVectorString.size() == 0); } } EATEST_VERIFY(rbVectorString.validate()); } // We make sure that after the above we still have some contents. if(rbVectorString.size() < 8) rbVectorString.resize(8); EATEST_VERIFY(rbVectorString.validate()); // Test const functions // const_iterator begin() const; // const_iterator end() const; // const_reverse_iterator rbegin() const; // const_reverse_iterator rend() const; // const_reference front() const; // const_reference back() const; // const_reference operator[](size_type n) const; // const container_type& get_container() const; const RBVectorString& rbVSConst = rbVectorString; for(RBVectorString::const_iterator ic = rbVSConst.begin(); ic != rbVSConst.end(); ++ic) { EATEST_VERIFY(rbVectorString.validate_iterator(ic) == (isf_valid | isf_current | isf_can_dereference)); } for(RBVectorString::const_reverse_iterator ric = rbVSConst.rbegin(); ric != rbVSConst.rend(); ++ric) { if(ric == rbVSConst.rbegin()) EATEST_VERIFY(rbVectorString.validate_iterator(ric.base()) == (isf_valid | isf_current)); else EATEST_VERIFY(rbVectorString.validate_iterator(ric.base()) == (isf_valid | isf_current | isf_can_dereference)); } EATEST_VERIFY(rbVSConst.front() == rbVectorString.front()); EATEST_VERIFY(rbVSConst.back() == rbVectorString.back()); EATEST_VERIFY(rbVSConst[0] == rbVectorString[0]); EATEST_VERIFY(&rbVSConst.get_container() == &rbVectorString.get_container()); // Test additional constructors. // ring_buffer(const this_type& x); // explicit ring_buffer(const Container& x); // this_type& operator=(const this_type& x); // void swap(this_type& x); RBVectorString rbVectorString2(rbVectorString); RBVectorString rbVectorString3(rbVectorString.get_container()); RBVectorString rbVectorString4(rbVectorString.capacity() / 2); RBVectorString rbVectorString5(rbVectorString.capacity() * 2); EATEST_VERIFY(rbVectorString.validate()); EATEST_VERIFY(rbVectorString2.validate()); EATEST_VERIFY(rbVectorString3.validate()); EATEST_VERIFY(rbVectorString4.validate()); EATEST_VERIFY(rbVectorString5.validate()); EATEST_VERIFY(rbVectorString == rbVectorString2); EATEST_VERIFY(rbVectorString3.get_container() == rbVectorString2.get_container()); rbVectorString3 = rbVectorString4; EATEST_VERIFY(rbVectorString3.validate()); eastl::swap(rbVectorString2, rbVectorString4); EATEST_VERIFY(rbVectorString2.validate()); EATEST_VERIFY(rbVectorString3.validate()); EATEST_VERIFY(rbVectorString4.validate()); EATEST_VERIFY(rbVectorString == rbVectorString4); EATEST_VERIFY(rbVectorString2 == rbVectorString3); // void ring_buffer::reserve(size_type n) eastl_size_t cap = rbVectorString2.capacity(); rbVectorString2.reserve(cap += 2); EATEST_VERIFY(rbVectorString2.validate()); EATEST_VERIFY(rbVectorString2.capacity() == cap); rbVectorString2.reserve(cap -= 4); // This should act as a no-op if we are following convention. EATEST_VERIFY(rbVectorString2.validate()); // void ring_buffer::set_capacity(size_type n) cap = rbVectorString2.capacity(); rbVectorString2.resize(cap); EATEST_VERIFY(rbVectorString2.size() == cap); rbVectorString2.set_capacity(cap += 2); EATEST_VERIFY(rbVectorString2.validate()); EATEST_VERIFY(rbVectorString2.capacity() == cap); rbVectorString2.set_capacity(cap -= 4); EATEST_VERIFY(rbVectorString2.capacity() == cap); EATEST_VERIFY(rbVectorString2.validate()); // template // void assign(InputIterator first, InputIterator last); string stringArray[10]; for(int q = 0; q < 10; q++) stringArray[q] = (char)('0' + (char)q); rbVectorString5.assign(stringArray, stringArray + 10); EATEST_VERIFY(rbVectorString5.validate()); EATEST_VERIFY(rbVectorString5.size() == 10); EATEST_VERIFY(rbVectorString5.front() == "0"); EATEST_VERIFY(rbVectorString5.back() == "9"); } { // Additional testing typedef ring_buffer< int, vector > RBVectorInt; RBVectorInt rbVectorInt(6); rbVectorInt.push_back(0); rbVectorInt.push_back(1); rbVectorInt.push_back(2); rbVectorInt.push_back(3); rbVectorInt.push_back(4); rbVectorInt.push_back(5); EATEST_VERIFY(rbVectorInt[0] == 0); EATEST_VERIFY(rbVectorInt[5] == 5); // iterator insert(iterator position, const value_type& value); rbVectorInt.insert(rbVectorInt.begin(), 999); EATEST_VERIFY(rbVectorInt[0] == 999); EATEST_VERIFY(rbVectorInt[1] == 0); EATEST_VERIFY(rbVectorInt[5] == 4); rbVectorInt.clear(); rbVectorInt.push_back(0); rbVectorInt.push_back(1); rbVectorInt.push_back(2); rbVectorInt.push_back(3); rbVectorInt.push_back(4); // iterator insert(iterator position, const value_type& value); rbVectorInt.insert(rbVectorInt.begin(), 999); EATEST_VERIFY(rbVectorInt[0] == 999); EATEST_VERIFY(rbVectorInt[1] == 0); EATEST_VERIFY(rbVectorInt[5] == 4); rbVectorInt.clear(); rbVectorInt.push_back(0); rbVectorInt.push_back(1); rbVectorInt.push_back(2); rbVectorInt.push_back(3); rbVectorInt.push_back(4); rbVectorInt.push_back(5); rbVectorInt.push_back(6); EATEST_VERIFY(rbVectorInt[0] == 1); EATEST_VERIFY(rbVectorInt[5] == 6); // iterator insert(iterator position, const value_type& value); rbVectorInt.insert(rbVectorInt.begin(), 999); EATEST_VERIFY(rbVectorInt[0] == 999); EATEST_VERIFY(rbVectorInt[1] == 1); EATEST_VERIFY(rbVectorInt[5] == 5); // iterator insert(iterator position, const value_type& value); RBVectorInt::iterator it = rbVectorInt.begin(); eastl::advance(it, 3); rbVectorInt.insert(it, 888); EATEST_VERIFY(rbVectorInt[0] == 999); EATEST_VERIFY(rbVectorInt[1] == 1); EATEST_VERIFY(rbVectorInt[2] == 2); EATEST_VERIFY(rbVectorInt[3] == 888); EATEST_VERIFY(rbVectorInt[4] == 3); EATEST_VERIFY(rbVectorInt[5] == 4); } { EA::UnitTest::Rand rng(EA::UnitTest::GetRandSeed()); typedef ring_buffer< string, list > RBListString; int counter = 0; char counterBuffer[32]; // explicit ring_buffer(size_type size = 0); const int kOriginalCapacity = 50; RBListString rbListString(50); // bool empty() const; // size_type size() const; // bool validate() const; EATEST_VERIFY(rbListString.validate()); EATEST_VERIFY(rbListString.empty()); EATEST_VERIFY(rbListString.size() == 0); EATEST_VERIFY(rbListString.capacity() == 50); // void clear(); rbListString.clear(); EATEST_VERIFY(rbListString.validate()); EATEST_VERIFY(rbListString.empty()); EATEST_VERIFY(rbListString.size() == 0); EATEST_VERIFY(rbListString.capacity() == 50); // container_type& get_container(); RBListString::container_type& c = rbListString.get_container(); EATEST_VERIFY(c.size() == (kOriginalCapacity + 1)); // We need to add one because the ring_buffer mEnd is necessarily an unused element. // iterator begin(); // iterator end(); // int validate_iterator(const_iterator i) const; RBListString::iterator it = rbListString.begin(); EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current)); while(it != rbListString.end()) // This loop should do nothing. { EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current)); ++it; } // void push_back(const value_type& value); sprintf(counterBuffer, "%d", counter++); rbListString.push_back(string(counterBuffer)); EATEST_VERIFY(rbListString.validate()); EATEST_VERIFY(!rbListString.empty()); EATEST_VERIFY(rbListString.size() == 1); EATEST_VERIFY(rbListString.capacity() == 50); it = rbListString.begin(); EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); EATEST_VERIFY(*it == "0"); // reference front(); // reference back(); string& sFront = rbListString.front(); string& sBack = rbListString.back(); EATEST_VERIFY(&sFront == &sBack); // void push_back(); string& ref = rbListString.push_back(); EATEST_VERIFY(rbListString.validate()); EATEST_VERIFY(rbListString.size() == 2); EATEST_VERIFY(rbListString.capacity() == 50); EATEST_VERIFY(&ref == &rbListString.back()); it = rbListString.begin(); ++it; EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); EATEST_VERIFY(it->empty()); sprintf(counterBuffer, "%d", counter++); *it = counterBuffer; EATEST_VERIFY(*it == "1"); ++it; EATEST_VERIFY(it == rbListString.end()); it = rbListString.begin(); while(it != rbListString.end()) { EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); ++it; } // reference operator[](size_type n); string& s0 = rbListString[0]; EATEST_VERIFY(s0 == "0"); string& s1 = rbListString[1]; EATEST_VERIFY(s1 == "1"); // Now we start hammering the ring buffer with push_back. for(eastl_size_t i = 0, iEnd = rbListString.capacity() * 5; i != iEnd; i++) { sprintf(counterBuffer, "%d", counter++); rbListString.push_back(string(counterBuffer)); EATEST_VERIFY(rbListString.validate()); } int counterCheck = counter - 1; char counterCheckBuffer[32]; sprintf(counterCheckBuffer, "%d", counterCheck); EATEST_VERIFY(rbListString.back() == counterCheckBuffer); // reverse_iterator rbegin(); // reverse_iterator rend(); for(RBListString::reverse_iterator ri = rbListString.rbegin(); ri != rbListString.rend(); ++ri) { sprintf(counterCheckBuffer, "%d", counterCheck--); EATEST_VERIFY(*ri == counterCheckBuffer); } ++counterCheck; // iterator begin(); // iterator end(); for(RBListString::iterator i = rbListString.begin(); i != rbListString.end(); ++i) { EATEST_VERIFY(rbListString.validate_iterator(i) == (isf_valid | isf_current | isf_can_dereference)); EATEST_VERIFY(*i == counterCheckBuffer); sprintf(counterCheckBuffer, "%d", ++counterCheck); } // void clear(); rbListString.clear(); EATEST_VERIFY(rbListString.validate()); EATEST_VERIFY(rbListString.empty()); EATEST_VERIFY(rbListString.size() == 0); EATEST_VERIFY(rbListString.capacity() == 50); // Random operations // Not easy to test the expected values without some tedium. for(int j = 0; j < 10000 + (gEASTL_TestLevel * 10000); j++) { sprintf(counterBuffer, "%d", counter++); const eastl_size_t op = rng.RandLimit(12); const eastl_size_t s = rbListString.size(); if(op == 0) { // void push_back(const value_type& value); rbListString.push_back(string(counterBuffer)); EATEST_VERIFY(rbListString.size() == eastl::min(s + 1, rbListString.capacity())); } else if(op == 1) { // void push_back(); string& ref2 = rbListString.push_back(); rbListString.back() = string(counterBuffer); EATEST_VERIFY(rbListString.size() == eastl::min(s + 1, rbListString.capacity())); EATEST_VERIFY(&ref2 == &rbListString.back()); } else if(op == 2) { // void pop_back(); if(!rbListString.empty()) { rbListString.pop_back(); EATEST_VERIFY(rbListString.size() == (s - 1)); } } else if(op == 3) { // void push_front(const value_type& value); rbListString.push_front(string(counterBuffer)); EATEST_VERIFY(rbListString.size() == eastl::min(s + 1, rbListString.capacity())); } else if(op == 4) { // void push_front(); string& ref2 = rbListString.push_front(); rbListString.front() = string(counterBuffer); EATEST_VERIFY(rbListString.size() == eastl::min(s + 1, rbListString.capacity())); EATEST_VERIFY(&ref2 == &rbListString.front()); } else if(op == 5) { // void pop_front(); if(!rbListString.empty()) { rbListString.pop_front(); EATEST_VERIFY(rbListString.size() == (s - 1)); } } else if(op == 6) { // iterator insert(iterator position, const value_type& value); it = rbListString.begin(); const eastl_size_t dist = rng.RandLimit((uint32_t)s + 1); eastl::advance(it, dist); if(it == rbListString.end()) EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current)); else EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); rbListString.insert(it, string(counterBuffer)); EATEST_VERIFY(rbListString.size() == eastl::min(s + 1, rbListString.capacity())); } else if(op == 7) { // void insert(iterator position, size_type n, const value_type& value); it = rbListString.begin(); const eastl_size_t dist = rng.RandLimit((uint32_t)s + 1); eastl::advance(it, dist); if(it == rbListString.end()) EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current)); else EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); const eastl_size_t count = (eastl_size_t)rng.RandLimit(10); rbListString.insert(it, count, string(counterBuffer)); EATEST_VERIFY(rbListString.size() == eastl::min(s + count, rbListString.capacity())); } else if(op == 8) { // template // void insert(iterator position, InputIterator first, InputIterator last); string stringArray[10]; it = rbListString.begin(); const eastl_size_t dist = rng.RandLimit((uint32_t)s + 1); eastl::advance(it, dist); if(it == rbListString.end()) EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current)); else EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); const eastl_size_t count = (eastl_size_t)rng.RandLimit(10); rbListString.insert(it, stringArray, stringArray + count); EATEST_VERIFY(rbListString.size() == eastl::min(s + count, rbListString.capacity())); } else if(op == 9) { // iterator erase(iterator position); if(!rbListString.empty()) { it = rbListString.begin(); const eastl_size_t dist = rng.RandLimit((uint32_t)s); eastl::advance(it, dist); EATEST_VERIFY(rbListString.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference)); rbListString.erase(it); EATEST_VERIFY(rbListString.size() == (s - 1)); } } else if(op == 10) { // iterator erase(iterator first, iterator last); if(!rbListString.empty()) { RBListString::iterator it1 = rbListString.begin(); const eastl_size_t pos = rng.RandLimit((uint32_t)s / 4); eastl::advance(it1, pos); EATEST_VERIFY(rbListString.validate_iterator(it1) == (isf_valid | isf_current | isf_can_dereference)); RBListString::iterator it2 = it1; const eastl_size_t dist = rng.RandLimit((uint32_t)s / 4); eastl::advance(it2, dist); EATEST_VERIFY(rbListString.validate_iterator(it2) == (isf_valid | isf_current | isf_can_dereference)); EATEST_VERIFY(s > (pos + dist)); rbListString.erase(it1, it2); EATEST_VERIFY(rbListString.size() == (s - dist)); } } else if(op == 11) { // void resize(size_type n); const eastl_size_t nSubOp = rng.RandLimit(100); if(nSubOp == 1) { rbListString.resize(kOriginalCapacity); EATEST_VERIFY(rbListString.size() == (RBListString::size_type)kOriginalCapacity); } else if(nSubOp == 2) { const eastl_size_t newSize = rng.RandLimit((uint32_t)s * 2) + 2; rbListString.resize(newSize); EATEST_VERIFY(rbListString.size() == newSize); } else if(nSubOp == 3) { rbListString.clear(); EATEST_VERIFY(rbListString.size() == 0); } } EATEST_VERIFY(rbListString.validate()); } // We make sure that after the above we still have some contents. if(rbListString.size() < 8) rbListString.resize(8); EATEST_VERIFY(rbListString.validate()); // Test const functions // const_iterator begin() const; // const_iterator end() const; // const_reverse_iterator rbegin() const; // const_reverse_iterator rend() const; // const_reference front() const; // const_reference back() const; // const_reference operator[](size_type n) const; // const container_type& get_container() const; const RBListString& rbVSConst = rbListString; for(RBListString::const_iterator ic = rbVSConst.begin(); ic != rbVSConst.end(); ++ic) { EATEST_VERIFY(rbListString.validate_iterator(ic) == (isf_valid | isf_current | isf_can_dereference)); } for(RBListString::const_reverse_iterator ric = rbVSConst.rbegin(); ric != rbVSConst.rend(); ++ric) { if(ric == rbVSConst.rbegin()) EATEST_VERIFY(rbListString.validate_iterator(ric.base()) == (isf_valid | isf_current)); else EATEST_VERIFY(rbListString.validate_iterator(ric.base()) == (isf_valid | isf_current | isf_can_dereference)); } EATEST_VERIFY(rbVSConst.front() == rbListString.front()); EATEST_VERIFY(rbVSConst.back() == rbListString.back()); EATEST_VERIFY(rbVSConst[0] == rbListString[0]); EATEST_VERIFY(&rbVSConst.get_container() == &rbListString.get_container()); // Test additional constructors. // ring_buffer(const this_type& x); // explicit ring_buffer(const Container& x); // this_type& operator=(const this_type& x); // void swap(this_type& x); RBListString rbListString2(rbListString); RBListString rbListString3(rbListString.get_container()); RBListString rbListString4(rbListString.capacity() / 2); RBListString rbListString5(rbListString.capacity() * 2); EATEST_VERIFY(rbListString.validate()); EATEST_VERIFY(rbListString2.validate()); EATEST_VERIFY(rbListString3.validate()); EATEST_VERIFY(rbListString4.validate()); EATEST_VERIFY(rbListString5.validate()); EATEST_VERIFY(rbListString == rbListString2); EATEST_VERIFY(rbListString3.get_container() == rbListString2.get_container()); rbListString3 = rbListString4; EATEST_VERIFY(rbListString3.validate()); eastl::swap(rbListString2, rbListString4); EATEST_VERIFY(rbListString2.validate()); EATEST_VERIFY(rbListString3.validate()); EATEST_VERIFY(rbListString4.validate()); EATEST_VERIFY(rbListString == rbListString4); EATEST_VERIFY(rbListString2 == rbListString3); // void ring_buffer::reserve(size_type n) eastl_size_t cap = rbListString2.capacity(); rbListString2.reserve(cap += 2); EATEST_VERIFY(rbListString2.validate()); EATEST_VERIFY(rbListString2.capacity() == cap); rbListString2.reserve(cap -= 4); // This should act as a no-op if we are following convention. EATEST_VERIFY(rbListString2.validate()); // template // void assign(InputIterator first, InputIterator last); string stringArray[10]; for(int q = 0; q < 10; q++) stringArray[q] = '0' + (char)q; rbListString5.assign(stringArray, stringArray + 10); EATEST_VERIFY(rbListString5.validate()); EATEST_VERIFY(rbListString5.size() == 10); EATEST_VERIFY(rbListString5.front() == "0"); EATEST_VERIFY(rbListString5.back() == "9"); // ring_buffer(this_type&& x); // ring_buffer(this_type&& x, const allocator_type& allocator); // this_type& operator=(this_type&& x); RBListString rbListStringM1(eastl::move(rbListString5)); EATEST_VERIFY(rbListStringM1.validate() && rbListString5.validate()); EATEST_VERIFY((rbListStringM1.size() == 10) && (rbListString5.size() == 0)); RBListString rbListStringM2(eastl::move(rbListStringM1), RBListString::allocator_type()); EATEST_VERIFY(rbListStringM2.validate() && rbListStringM1.validate()); EATEST_VERIFY((rbListStringM2.size() == 10) && (rbListStringM1.size() == 0)); rbListStringM1 = eastl::move(rbListStringM2); EATEST_VERIFY(rbListStringM1.validate() && rbListStringM2.validate()); EATEST_VERIFY((rbListStringM1.size() == 10) && (rbListStringM2.size() == 0)); } { // ring_buffer(std::initializer_list ilist, const allocator_type& allocator = allocator_type()); // this_type& operator=(std::initializer_list ilist); // void insert(iterator position, std::initializer_list ilist); #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) ring_buffer intBuffer = { 0, 1, 2 }; EATEST_VERIFY(VerifySequence(intBuffer.begin(), intBuffer.end(), int(), "ring_buffer std::initializer_list", 0, 1, 2, -1)); intBuffer = { 16, 17, 18 }; EATEST_VERIFY(VerifySequence(intBuffer.begin(), intBuffer.end(), int(), "ring_buffer std::initializer_list", 16, 17, 18, -1)); // We need to increase the capacity in order to insert new items because the ctor above set the capacity to be only enough to hold the initial list. intBuffer.reserve(intBuffer.capacity() + 2); intBuffer.insert(intBuffer.begin(), { 14, 15 }); EATEST_VERIFY(VerifySequence(intBuffer.begin(), intBuffer.end(), int(), "ring_buffer std::initializer_list", 14, 15, 16, 17, 18, -1)); #endif } { // Regression for user-reported problem. typedef eastl::fixed_vector GamepadData_t; typedef eastl::ring_buffer GamepadDataDelayBuffer_t; typedef eastl::fixed_vector GamepadDataDelayBufferTable_t; GamepadDataDelayBufferTable_t mDelayTable; mDelayTable.resize(32); for(eastl_size_t i = 0; i < mDelayTable.size(); i++) mDelayTable[i].reserve(16); GamepadData_t data(8, 1.f); mDelayTable[0].push_back(data); mDelayTable[0].push_back(data); mDelayTable[0].push_back(data); mDelayTable[0].push_back(data); EATEST_VERIFY(mDelayTable[0].size() == 4); GamepadData_t dataFront = mDelayTable[0].front(); EATEST_VERIFY((dataFront.size() == 8) && (dataFront[0] == 1.f)); mDelayTable[0].pop_front(); } { // Regression for bug with iterator subtraction typedef eastl::ring_buffer IntBuffer_t; IntBuffer_t intBuffer = { 0, 1, 2, 3, 4, 5, 6, 7 }; IntBuffer_t::iterator it = intBuffer.begin(); EATEST_VERIFY(*it == 0); it += 4; EATEST_VERIFY(*it == 4); it--; EATEST_VERIFY(*it == 3); it -= 2; EATEST_VERIFY(*it == 1); intBuffer.push_back(8); intBuffer.push_back(9); intBuffer.push_back(10); intBuffer.push_back(11); EATEST_VERIFY(*it == 10); it -= 3; EATEST_VERIFY(*it == 7); // Test looping around the end of the underlying container it -= 5; EATEST_VERIFY(*it == 11); // Test wrapping around begin to end of the ring_buffer it -= 2; EATEST_VERIFY(*it == 9); // It is important to test going back to the beginning of the underlying container. } // fixed_ring_buffer tests // ring_buffer> tests { { // (MAX_ELEMENTS - 1) accommodates the ring_buffer sentinel const int MAX_ELEMENTS = 8; eastl::ring_buffer> rb(MAX_ELEMENTS - 1); for (int i = 0; i < MAX_ELEMENTS - 1; i++) rb.push_back(i); auto it = rb.begin(); for (int i = 0; i < MAX_ELEMENTS - 1; i++) { EATEST_VERIFY(*it++ == i); } } #if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) { const int MAX_ELEMENTS = 25; eastl::fixed_ring_buffer rb(MAX_ELEMENTS); for(int i = 0; i < MAX_ELEMENTS; i++) rb.push_back(i); auto it = rb.begin(); for(int i = 0; i < MAX_ELEMENTS; i++) { EATEST_VERIFY(*it++ == i); } } #endif #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(EA_COMPILER_NO_TEMPLATE_ALIASES) { const int MAX_ELEMENTS = 8; eastl::fixed_ring_buffer rb = {0, 1, 2, 3, 4, 5, 6, 7}; auto it = rb.begin(); for(int i = 0; i < MAX_ELEMENTS; i++) { EATEST_VERIFY(*it++ == i); } } { struct LocalStruct {}; fixed_ring_buffer rb = {{{}, {}, {}}}; EATEST_VERIFY(rb.size() == 3); } #endif } { const auto MAX_ELEMENTS = EASTL_MAX_STACK_USAGE; // create a container simulating LARGE state that exceeds // our maximum stack size macro. This forces our ring_buffer implementation // to allocate the container in the heap instead of holding it on the stack. // This test ensures that allocation is NOT serviced by the default global heap. // Instead it is serviced by the allocator of the ring_buffers underlying container. struct PaddedVector : public eastl::vector { char mPadding[EASTL_MAX_STACK_USAGE]; }; MallocAllocator::reset_all(); CountingAllocator::resetCount(); { CountingAllocator countingAlloc; AutoDefaultAllocator _(&countingAlloc); eastl::ring_buffer intBuffer(1); for (int i = 0; i < MAX_ELEMENTS; i++) intBuffer.push_back(i); #if !EASTL_OPENSOURCE const auto cacheAllocationCount = gEASTLTest_TotalAllocationCount; #endif const auto cacheMallocatorCount = MallocAllocator::mAllocCountAll; const auto forceReAllocSize = intBuffer.size() * 2; intBuffer.resize(forceReAllocSize); #if !EASTL_OPENSOURCE VERIFY(cacheAllocationCount == gEASTLTest_TotalAllocationCount); #endif VERIFY(cacheMallocatorCount < MallocAllocator::mAllocCountAll); VERIFY(CountingAllocator::neverUsed()); } } return nErrorCount; }