///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Test forward delcarations ///////////////////////////////////////////////////////////////////////////// namespace eastl { class allocator; template class basic_string; typedef basic_string local_string8; // collides with eastl::string8 in bulkbuilds template struct local_less {}; static void UseForwardDeclaredString(local_string8*) { } template class vector; typedef vector vector8; static void UseForwardDeclaredVector(vector8*) { } template class hash_set; typedef hash_set, allocator, false> hash_set8; static void UseForwardDeclaredHashSet(hash_set8*) { } template class map; typedef map, allocator> map8; static void UseForwardDeclaredMap(map8*) { } } #include "EASTLTest.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(push, 0) #endif #include #include #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY #include #include #include #include #include #include #include #endif #if defined(_MSC_VER) #pragma warning(pop) #endif using namespace eastl; namespace { /// IntNode /// /// Test intrusive_list node. /// struct IntNode : public eastl::intrusive_list_node { int mX; IntNode(int x = 0) : mX(x) { } operator int() const { return mX; } }; bool operator<(const IntNode& a, const IntNode& b) { return a.mX < b.mX; } } struct TestClass { mutable int mX; TestClass() : mX(37) { } void Increment() { mX++; } void IncrementConst() const { mX++; } int MultiplyBy(int x) { return mX * x; } int MultiplyByConst(int x) const { return mX * x; } }; /////////////////////////////////////////////////////////////////////////////// // TestForwardDeclarations // static int TestForwardDeclarations() { int nErrorCount = 0; eastl::local_string8 s8; UseForwardDeclaredString(&s8); eastl::vector8 v8; UseForwardDeclaredVector(&v8); eastl::hash_set8 h8; UseForwardDeclaredHashSet(&h8); eastl::map8 m8; UseForwardDeclaredMap(&m8); return nErrorCount; } /////////////////////////////////////////////////////////////////////////////// // fixed_pool_reference // struct fixed_pool_reference { public: fixed_pool_reference(const char* = NULL) { mpFixedPool = NULL; } fixed_pool_reference(eastl::fixed_pool& fixedPool) { mpFixedPool = &fixedPool; } fixed_pool_reference(const fixed_pool_reference& x) { mpFixedPool = x.mpFixedPool; } fixed_pool_reference& operator=(const fixed_pool_reference& x) { mpFixedPool = x.mpFixedPool; return *this; } void* allocate(size_t /*n*/, int /*flags*/ = 0) { return mpFixedPool->allocate(); } void* allocate(size_t /*n*/, size_t /*alignment*/, size_t /*offset*/, int /*flags*/ = 0) { return mpFixedPool->allocate(); } void deallocate(void* p, size_t /*n*/) { return mpFixedPool->deallocate(p); } const char* get_name() const { return "fixed_pool_reference"; } void set_name(const char* /*pName*/) { } protected: friend bool operator==(const fixed_pool_reference& a, const fixed_pool_reference& b); friend bool operator!=(const fixed_pool_reference& a, const fixed_pool_reference& b); eastl::fixed_pool* mpFixedPool; }; inline bool operator==(const fixed_pool_reference& a, const fixed_pool_reference& b) { return (a.mpFixedPool == b.mpFixedPool); } inline bool operator!=(const fixed_pool_reference& a, const fixed_pool_reference& b) { return (a.mpFixedPool != b.mpFixedPool); } // Template instantations. // These tell the compiler to compile all the functions for the given class. template class eastl::queue >; template class eastl::queue >; template class eastl::queue >; //template class eastl::queue >;// This test has been disabled as of the addition of initializer_list support to eastl::queue. initializer_lists have const nodes, which is incompatible with intrusive_list. You can use eastl::queue > as long as you don't use initializer_list with it. The problem with this line of code is that it forces compilation of the entire class. /////////////////////////////////////////////////////////////////////////////// // TestQueue // static int TestQueue() { int nErrorCount = 0; { // Exercise IntNode. IntNode x, y; EATEST_VERIFY((x < y) || !(x < y) || ((int)x < (int)y)); } TestObject::Reset(); { // queue(const Sequence& x = Sequence()); queue> toListQueue; queue> toListQueue2; // global operators EATEST_VERIFY( (toListQueue == toListQueue2)); EATEST_VERIFY(!(toListQueue != toListQueue2)); EATEST_VERIFY( (toListQueue <= toListQueue2)); EATEST_VERIFY( (toListQueue >= toListQueue2)); EATEST_VERIFY(!(toListQueue < toListQueue2)); EATEST_VERIFY(!(toListQueue > toListQueue2)); // bool empty() const; // size_type size() const; EATEST_VERIFY(toListQueue.empty()); EATEST_VERIFY(toListQueue.size() == 0); // void push(const value_type& value); // reference front(); // const_reference front() const; // reference back(); // const_reference back() const; toListQueue.push(TestObject(0)); EATEST_VERIFY(toListQueue.front() == TestObject(0)); EATEST_VERIFY(toListQueue.back() == TestObject(0)); toListQueue.push(TestObject(1)); EATEST_VERIFY(toListQueue.front() == TestObject(0)); EATEST_VERIFY(toListQueue.back() == TestObject(1)); toListQueue.push(TestObject(2)); EATEST_VERIFY(toListQueue.front() == TestObject(0)); EATEST_VERIFY(toListQueue.back() == TestObject(2)); EATEST_VERIFY(!toListQueue.empty()); EATEST_VERIFY(toListQueue.size() == 3); // void pop(); toListQueue.pop(); EATEST_VERIFY(toListQueue.front() == TestObject(1)); EATEST_VERIFY(toListQueue.back() == TestObject(2)); toListQueue.pop(); EATEST_VERIFY(toListQueue.front() == TestObject(2)); EATEST_VERIFY(toListQueue.back() == TestObject(2)); toListQueue.pop(); EATEST_VERIFY(toListQueue.empty()); EATEST_VERIFY(toListQueue.size() == 0); // decltype(auto) emplace(Args&&... args); toListQueue.emplace(1); EATEST_VERIFY(!toListQueue.empty()); EATEST_VERIFY(toListQueue.front() == TestObject(1)); EATEST_VERIFY(toListQueue.size() == 1); // container_type& get_container(); // const container_type& get_container() const; list& ref = toListQueue.get_container(); EATEST_VERIFY(ref.size() == toListQueue.size()); // queue(std::initializer_list ilist); queue intQueue = { 3, 4, 5 }; EATEST_VERIFY(intQueue.size() == 3); EATEST_VERIFY(intQueue.front() == 3); intQueue.pop(); EATEST_VERIFY(intQueue.front() == 4); intQueue.pop(); EATEST_VERIFY(intQueue.front() == 5); } { vector toVector; for(int i = 0; i < 100; i++) toVector.push_back(TestObject(i)); // template // queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); // // explicit queue(container_type&& x); // // void push(value_type&& x); queue > toQ_0; queue > toQ_A(eastl::move(toQ_0), toQ_0.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. EATEST_VERIFY(toQ_A.size() == 0); toQ_A.push(TestObject(1000)); EATEST_VERIFY(toQ_A.size() == 1); queue > toQ_B(eastl::move(toQ_A), toQ_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. EATEST_VERIFY((toQ_B.size() == 1) && toQ_A.empty()); eastl::vector toVectorM(toVector); queue > toQ_C(eastl::move(toVectorM)); EATEST_VERIFY((toQ_C.size() == toVector.size()) && toVectorM.empty()); // template // void emplace_back(Args&&... args); queue > toQ_D; toQ_D.emplace(0, 1, 2); EATEST_VERIFY(toQ_D.size() == 1) && (toQ_D.back() == TestObject(0, 1, 2)); } { // Test std namespace elements contained in queue #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY eastl::queue< std::pair > stlQueue; stlQueue.push(std::make_pair(1, 1)); EATEST_VERIFY(stlQueue.size() == 1); #endif } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); return nErrorCount; } // Template instantations. // These tell the compiler to compile all the functions for the given class. template class eastl::priority_queue >; template class eastl::priority_queue >; template class eastl::priority_queue >; template class eastl::priority_queue, less >; /////////////////////////////////////////////////////////////////////////////// // TestPriorityQueue // static int TestPriorityQueue() { int nErrorCount = 0; EASTLTest_Rand rng(EA::UnitTest::GetRandSeed()); TestObject::Reset(); { less toLess; vector toVector; for(int i = 0; i < 100; i++) toVector.push_back(TestObject(i)); random_shuffle(toVector.begin(), toVector.end(), rng); list toList; for(eastl_size_t j = 0; j < 100; j++) toList.push_back(toVector[j]); // priority_queue(const Compare& compare = Compare(), const Sequence& x = Sequence()); // template // priority_queue(InputIterator first, InputIterator last, const Compare& compare = Compare(), const Sequence& x = Sequence()); priority_queue > toPQ; priority_queue > toPQV(toLess, toVector); priority_queue > toPQL(toList.begin(), toList.end()); EATEST_VERIFY(toPQ.empty()); EATEST_VERIFY(toPQ.size() == 0); EATEST_VERIFY(!toPQV.empty()); EATEST_VERIFY( toPQV.size() == toVector.size()); EATEST_VERIFY(!toPQL.empty()); EATEST_VERIFY( toPQL.size() == toList.size()); // global operators EATEST_VERIFY( (toPQ != toPQL)); EATEST_VERIFY( (toPQV == toPQL)); EATEST_VERIFY(!(toPQV != toPQL)); EATEST_VERIFY( (toPQV <= toPQL)); EATEST_VERIFY( (toPQV >= toPQL)); EATEST_VERIFY(!(toPQV < toPQL)); EATEST_VERIFY(!(toPQV > toPQL)); // container_type& get_container(); // const container_type& get_container() const; vector& ref = toPQL.get_container(); EATEST_VERIFY(ref.size() == toPQL.size()); EATEST_VERIFY(is_heap(ref.begin(), ref.end())); // bool validate() const; EATEST_VERIFY(toPQL.validate()); // To consider: Verify that validate detects an invalid heap. // Testing this might be an issue if the validation function actively complains in some way. // const_reference top() const; // void pop(); const TestObject& to1 = toPQL.top(); EATEST_VERIFY(to1 == TestObject(99)); toPQL.pop(); EATEST_VERIFY(!toPQL.empty()); EATEST_VERIFY( toPQL.size() == toList.size() - 1); EATEST_VERIFY(to1 == TestObject(98)); EATEST_VERIFY(is_heap(ref.begin(), ref.end())); // void push(const value_type& value); toPQL.push(TestObject(1000)); EATEST_VERIFY(toPQL.size() == toList.size()); const TestObject& to2 = toPQL.top(); EATEST_VERIFY(to2 == TestObject(1000)); toPQL.pop(); const TestObject& to3 = toPQL.top(); EATEST_VERIFY(to3 == TestObject(98)); EATEST_VERIFY(is_heap(ref.begin(), ref.end())); // void change(size_type n); TestObject& to4 = ref[50]; to4 = TestObject(2000); toPQL.change(50); const TestObject& to5 = toPQL.top(); EATEST_VERIFY(to5 == TestObject(2000)); EATEST_VERIFY(is_heap(ref.begin(), ref.end())); // void remove(size_type n); TestObject to6 = ref[20]; toPQL.remove(20); EATEST_VERIFY( toPQL.size() == toList.size() - 2); TestObject& to7 = ref[20]; EATEST_VERIFY(!(to6 == to7)); EATEST_VERIFY(is_heap(ref.begin(), ref.end())); // priority_queue(std::initializer_list ilist, const compare_type& compare = compare_type()); #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) priority_queue > intPQ = { 3, 4, 5 }; EATEST_VERIFY(intPQ.size() == 3); EATEST_VERIFY(intPQ.top() == 5); intPQ.pop(); EATEST_VERIFY(intPQ.top() == 4); intPQ.pop(); EATEST_VERIFY(intPQ.top() == 3); #endif } { vector toVector; for(int i = 0; i < 100; i++) toVector.push_back(TestObject(i)); // template // priority_queue(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); // // explicit priority_queue(const compare_type& compare, container_type&& x); // // template // priority_queue(InputIterator first, InputIterator last, const compare_type& compare, container_type&& x); // // void push(value_type&& x); priority_queue > toPQ_0; priority_queue > toPQ_A(toPQ_0.get_container().begin(), toPQ_0.get_container().begin(), eastl::less(), toPQ_0.get_container()); EATEST_VERIFY(toPQ_A.size() == 0); toPQ_A.push(TestObject(1000)); EATEST_VERIFY(toPQ_A.size() == 1); priority_queue > toPQ_B(eastl::move(toPQ_A), toPQ_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. EATEST_VERIFY((toPQ_B.size() == 1) && toPQ_A.empty()); eastl::vector toVectorM(toVector); priority_queue > toPQ_C(eastl::less(), eastl::move(toVectorM)); EATEST_VERIFY((toPQ_C.size() == toVector.size()) && toVectorM.empty()); // template // void emplace(Args&&... args); priority_queue > toPQ_D; toPQ_D.emplace(0, 1, 2); EATEST_VERIFY(toPQ_D.size() == 1) && (toPQ_D.top() == TestObject(0, 1, 2)); } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); return nErrorCount; } // Template instantations. // These tell the compiler to compile all the functions for the given class. template class eastl::stack >; template class eastl::stack >; template class eastl::stack >; //template class eastl::stack >; // This test has been disabled as of the addition of initializer_list support to eastl::stack. initializer_lists have const nodes, which is incompatible with intrusive_list. You can use eastl::stack > as long as you don't use initializer_list with it. The problem with this line of code is that it forces compilation of the entire class. /////////////////////////////////////////////////////////////////////////////// // TestStack // static int TestStack() { int nErrorCount = 0; TestObject::Reset(); { // stack(const Sequence& x = Sequence()); stack > toListStack; stack > toListStack2; // bool empty() const; // size_type size() const; EATEST_VERIFY(toListStack.empty()); EATEST_VERIFY(toListStack.size() == 0); // global operators EATEST_VERIFY( (toListStack == toListStack2)); EATEST_VERIFY(!(toListStack != toListStack2)); EATEST_VERIFY( (toListStack <= toListStack2)); EATEST_VERIFY( (toListStack >= toListStack2)); EATEST_VERIFY(!(toListStack < toListStack2)); EATEST_VERIFY(!(toListStack > toListStack2)); // void push(const value_type& value); // reference top(); // const_reference top() const; toListStack.push(TestObject(0)); EATEST_VERIFY(toListStack.top() == TestObject(0)); toListStack.push(TestObject(1)); EATEST_VERIFY(toListStack.top() == TestObject(1)); toListStack.push(TestObject(2)); EATEST_VERIFY( toListStack.top() == TestObject(2)); EATEST_VERIFY(!toListStack.empty()); EATEST_VERIFY( toListStack.size() == 3); // void pop(); toListStack.pop(); EATEST_VERIFY(toListStack.top() == TestObject(1)); toListStack.pop(); EATEST_VERIFY(toListStack.top() == TestObject(0)); toListStack.pop(); EATEST_VERIFY(toListStack.empty()); EATEST_VERIFY(toListStack.size() == 0); // container_type& get_container(); // const container_type& get_container() const; list& ref = toListStack.get_container(); EATEST_VERIFY(ref.size() == toListStack.size()); // stack(std::initializer_list ilist); #if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) stack intStack = { 3, 4, 5 }; EATEST_VERIFY(intStack.size() == 3); EATEST_VERIFY(intStack.top() == 5); intStack.pop(); EATEST_VERIFY(intStack.top() == 4); intStack.pop(); EATEST_VERIFY(intStack.top() == 3); #endif } { vector toVector; for(int i = 0; i < 100; i++) toVector.push_back(TestObject(i)); // template // stack(this_type&& x, const Allocator& allocator, typename eastl::enable_if::value>::type* = NULL); // // explicit stack(container_type&& x); // // void push(value_type&& x); stack > toS_0; stack > toS_A(eastl::move(toS_0), toS_0.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. EATEST_VERIFY(toS_A.size() == 0); toS_A.push(TestObject(1000)); EATEST_VERIFY(toS_A.size() == 1); stack > toS_B(eastl::move(toS_A), toS_A.get_container().get_allocator()); // It would be better if we also tested an alternative allocator. EATEST_VERIFY((toS_B.size() == 1) && toS_A.empty()); eastl::vector toVectorM(toVector); stack > toS_C(eastl::move(toVectorM)); EATEST_VERIFY((toS_C.size() == toVector.size()) && toVectorM.empty()); { // template // void emplace_back(Args&&... args); stack> toS_D; toS_D.emplace_back(0, 1, 2); EATEST_VERIFY(toS_D.size() == 1) && (toS_D.top() == TestObject(0, 1, 2)); } { // template // decltype(auto) emplace(Args&&... args); stack> toS_D; auto it = toS_D.emplace(0, 1, 2); EATEST_VERIFY(toS_D.size() == 1) && (toS_D.top() == TestObject(0, 1, 2)); EATEST_VERIFY(it == TestObject(0, 1, 2)); } } EATEST_VERIFY(TestObject::IsClear()); TestObject::Reset(); return nErrorCount; } struct Size0 { // Empty }; struct Size4 { uint32_t m32; }; /////////////////////////////////////////////////////////////////////////////// // TestCompressedPair // static int TestCompressedPair() { int nErrorCount = 0; compressed_pair cp00; compressed_pair cp04; compressed_pair cp40; compressed_pair cp44; EATEST_VERIFY(sizeof(cp00) <= 4); EATEST_VERIFY(sizeof(cp04) <= 4); EATEST_VERIFY(sizeof(cp40) <= 4); EATEST_VERIFY(sizeof(cp44) <= 8); return nErrorCount; } template struct CallTraitsContainer { typedef typename eastl::call_traits::param_type param_type; typedef typename eastl::call_traits::reference reference; typedef typename eastl::call_traits::const_reference const_reference; typedef typename eastl::call_traits::value_type result_type; typedef T value_type; public: value_type mValue; CallTraitsContainer() { } CallTraitsContainer(param_type p) : mValue(p) { } CallTraitsContainer& operator=(const CallTraitsContainer&) { } // Defined simply to prevent possible compiler warnings. result_type value() { return mValue; } reference get() { return mValue; } const_reference const_get() const { return mValue; } void call(param_type p){ } }; /////////////////////////////////////////////////////////////////////////////// // TestCallTraits // static int TestCallTraits() { int nErrorCount = 0; CallTraitsContainer ctcInt; CallTraitsContainer ctcIntPtr; CallTraitsContainer ctcVoid(nErrorCount); CallTraitsContainer ctcIntArray; char buffer[128]; sprintf(buffer, "%p %p %p %p", &ctcInt, &ctcIntPtr, &ctcVoid, &ctcIntArray); return nErrorCount; } static int AccumulateMultiply(int x, int y) { return (x * y); } static eastl::string AccumulateString(eastl::string s, int x) { s += '0' + static_cast(x); return s; } /////////////////////////////////////////////////////////////////////////////// // TestNumeric // static int TestNumeric() { int nErrorCount = 0; //template //T accumulate(InputIterator first, InputIterator last, T init); eastl::vector v(5, 0); eastl::generate(v.begin(), v.end(), GenerateIncrementalIntegers(1)); int sum = eastl::accumulate(v.begin(), v.end(), 100); EATEST_VERIFY(sum == (100 + 1 + 2 + 3 + 4 + 5)); // template //T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op); eastl::generate(v.begin(), v.end(), GenerateIncrementalIntegers(1)); int product = eastl::accumulate(v.begin(), v.end(), 100, AccumulateMultiply); EATEST_VERIFY(product == (100 * 1 * 2 * 3 * 4 * 5)); eastl::generate(v.begin(), v.end(), GenerateIncrementalIntegers(1)); eastl::string s = eastl::accumulate(v.begin(), v.end(), eastl::string("0"), AccumulateString); EATEST_VERIFY(s == "012345"); //template //T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init); // To do. //template //T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2) // To do. //template //OutputIterator partial_sum(InputIterator first, InputIterator last, OutputIterator result); // To do. //template //OutputIterator partial_sum(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op); // To do. return nErrorCount; } /////////////////////////////////////////////////////////////////////////////// // TestAdaptors // static int TestAdaptors() { int nErrorCount = 0; // reverse lvalue container { int int_data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; eastl::vector original(begin(int_data), end(int_data)); eastl::vector reversed; for(auto& e : eastl::reverse(original)) reversed.push_back(e); eastl::reverse(begin(original), end(original)); EATEST_VERIFY(reversed == original); } // reverse const lvalue container { int int_data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; const eastl::vector original(begin(int_data), end(int_data)); eastl::vector reversed; for(auto& e : eastl::reverse(original)) reversed.push_back(e); eastl::vector reversed_original(original); eastl::reverse(begin(reversed_original), end(reversed_original)); EATEST_VERIFY(reversed == reversed_original); } // reverse rvalue container { int int_data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; eastl::vector original(begin(int_data), end(int_data)); eastl::vector reversed; for (auto& e : eastl::reverse(eastl::vector(original))) reversed.push_back(e); eastl::reverse(begin(original), end(original)); EATEST_VERIFY(reversed == original); } return nErrorCount; } /////////////////////////////////////////////////////////////////////////////// // TestExtra // int TestExtra() { int nErrorCount = 0; nErrorCount += TestForwardDeclarations(); nErrorCount += TestQueue(); nErrorCount += TestPriorityQueue(); nErrorCount += TestStack(); nErrorCount += TestCompressedPair(); nErrorCount += TestCallTraits(); nErrorCount += TestNumeric(); nErrorCount += TestAdaptors(); return nErrorCount; }