diff options
Diffstat (limited to 'EASTL/test/source/TestRingBuffer.cpp')
-rw-r--r-- | EASTL/test/source/TestRingBuffer.cpp | 1139 |
1 files changed, 1139 insertions, 0 deletions
diff --git a/EASTL/test/source/TestRingBuffer.cpp b/EASTL/test/source/TestRingBuffer.cpp new file mode 100644 index 0000000..d640380 --- /dev/null +++ b/EASTL/test/source/TestRingBuffer.cpp @@ -0,0 +1,1139 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) Electronic Arts Inc. All rights reserved. +///////////////////////////////////////////////////////////////////////////// + + +#include "EASTLTest.h" +#include <EASTL/bonus/ring_buffer.h> +#include <EASTL/bonus/fixed_ring_buffer.h> +#include <EASTL/vector.h> +#include <EASTL/deque.h> +#include <EASTL/string.h> +#include <EASTL/list.h> +#include <EASTL/fixed_vector.h> +#include <EASTL/fixed_string.h> + + + +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<int> >; +template class eastl::ring_buffer< Align64, eastl::vector<Align64> >; +template class eastl::ring_buffer< TestObject, eastl::vector<TestObject> >; + +template class eastl::ring_buffer< int, eastl::deque<int> >; +template class eastl::ring_buffer< Align64, eastl::deque<Align64> >; +template class eastl::ring_buffer< TestObject, eastl::deque<TestObject> >; + +template class eastl::ring_buffer< int, eastl::list<int> >; +template class eastl::ring_buffer< Align64, eastl::list<Align64> >; +template class eastl::ring_buffer< TestObject, eastl::list<TestObject> >; + +// TODO(rparolin): To consider adding support for eastl::array. +// template class eastl::ring_buffer< int, eastl::array<int, 64>>; + +typedef eastl::fixed_string<char, 256, false> RBFixedString; +typedef eastl::fixed_vector<RBFixedString, 100, false> RBFixedStringVector; +typedef RBFixedStringVector::overflow_allocator_type RBFixedStringVectorOverflowAllocator; +template class eastl::ring_buffer<RBFixedString, RBFixedStringVector, RBFixedStringVectorOverflowAllocator>; + +typedef eastl::fixed_vector<int, 100, false> RBFixedIntVector; +template class eastl::ring_buffer<int, RBFixedIntVector, RBFixedIntVector::overflow_allocator_type>; +// template class eastl::ring_buffer<int, RBFixedIntVector>; // currently fails to compile + +typedef eastl::fixed_vector<int, 100> RBFixedIntVectorWithOverFlow; +template class eastl::ring_buffer<int, RBFixedIntVectorWithOverFlow, RBFixedIntVectorWithOverFlow::overflow_allocator_type>; +// template class eastl::ring_buffer<int, RBFixedIntVectorWithOverFlow>; // 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<int> emptyIntArray; + ring_buffer<int, vector<int> > 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<string> > 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 <typename InputIterator> + // 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<T, Container>::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<T, Container>::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 <typename InputIterator> + // 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<int> > 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<string> > 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 <typename InputIterator> + // 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<T, Container>::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 <typename InputIterator> + // 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<value_type> ilist, const allocator_type& allocator = allocator_type()); + // this_type& operator=(std::initializer_list<value_type> ilist); + // void insert(iterator position, std::initializer_list<value_type> ilist); + #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) + ring_buffer<int> 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<float, 8> GamepadData_t; + typedef eastl::ring_buffer<GamepadData_t> GamepadDataDelayBuffer_t; + typedef eastl::fixed_vector<GamepadDataDelayBuffer_t, 32> 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<int> 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<T,N> tests + // ring_buffer<T, fixed_vector<T,N>> tests + { + { + // (MAX_ELEMENTS - 1) accommodates the ring_buffer sentinel + const int MAX_ELEMENTS = 8; + eastl::ring_buffer<int, eastl::fixed_vector<int, MAX_ELEMENTS, false>> 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<int, MAX_ELEMENTS> 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<int, MAX_ELEMENTS> 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<LocalStruct, 8> 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<int, MallocAllocator> + { + char mPadding[EASTL_MAX_STACK_USAGE]; + }; + + MallocAllocator::reset_all(); + CountingAllocator::resetCount(); + + { + CountingAllocator countingAlloc; + AutoDefaultAllocator _(&countingAlloc); + + eastl::ring_buffer<int, PaddedVector> 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; +} + + + + + + + + + |