///////////////////////////////////////////////////////////////////////////// // Copyright (c) Electronic Arts Inc. All rights reserved. ///////////////////////////////////////////////////////////////////////////// #include "EASTLTest.h" #include #include EA_DISABLE_ALL_VC_WARNINGS() #include #include #include #ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY #include #endif EA_RESTORE_ALL_VC_WARNINGS() 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; } }; /// ListInit /// /// Utility class for setting up a list. /// class ListInit { public: ListInit(intrusive_list& container, IntNode* pNodeArray) : mpContainer(&container), mpNodeArray(pNodeArray) { mpContainer->clear(); } ListInit& operator+=(int x) { mpNodeArray->mX = x; mpContainer->push_back(*mpNodeArray++); return *this; } ListInit& operator,(int x) { mpNodeArray->mX = x; mpContainer->push_back(*mpNodeArray++); return *this; } protected: intrusive_list* mpContainer; IntNode* mpNodeArray; }; } // namespace // Template instantations. // These tell the compiler to compile all the functions for the given class. template class eastl::intrusive_list; int TestIntrusiveList() { int nErrorCount = 0; int i; { // Verify that intrusive_list_node is a POD, at least when EASTL_VALIDATE_INTRUSIVE_LIST is disabled. #if !EASTL_VALIDATE_INTRUSIVE_LIST // is_pod doesn't currently detect structs as PODs, even though it should. // This is due to limitations in C++. // VERIFY(eastl::is_pod::value); const size_t offset = offsetof(intrusive_list_node, mpPrev); VERIFY(offset == sizeof(intrusive_list_node*)); #endif } { IntNode nodes[20]; intrusive_list ilist; // Enforce that the intrusive_list copy ctor is visible. If it is not, // then the class is not a POD type as it is supposed to be. delete new intrusive_list(ilist); #ifndef __GNUC__ // GCC warns on this, though strictly specaking it is allowed to. // Enforce that offsetof() can be used with an intrusive_list in a struct; // it requires a POD type. Some compilers will flag warnings or even errors // when this is violated. struct Test { intrusive_list m; }; (void)offsetof(Test, m); #endif // begin / end VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "ctor()", -1)); // push_back ListInit(ilist, nodes) += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9; VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "push_back()", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1)); // iterator / begin intrusive_list::iterator it = ilist.begin(); VERIFY(it->mX == 0); ++it; VERIFY(it->mX == 1); ++it; VERIFY(it->mX == 2); ++it; VERIFY(it->mX == 3); // const_iterator / begin const intrusive_list cilist; intrusive_list::const_iterator cit; for(cit = cilist.begin(); cit != cilist.end(); ++cit) VERIFY(cit == cilist.end()); // This is guaranteed to be false. // reverse_iterator / rbegin intrusive_list::reverse_iterator itr = ilist.rbegin(); VERIFY(itr->mX == 9); ++itr; VERIFY(itr->mX == 8); ++itr; VERIFY(itr->mX == 7); ++itr; VERIFY(itr->mX == 6); // iterator++/-- { intrusive_list::iterator it1(ilist.begin()); intrusive_list::iterator it2(ilist.begin()); ++it1; ++it2; if ((it1 != it2++) || (++it1 != it2)) VERIFY(!"[iterator::increment] fail\n"); if ((it1 != it2--) || (--it1 != it2)) VERIFY(!"[iterator::decrement] fail\n"); } // clear / empty VERIFY(!ilist.empty()); ilist.clear(); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "clear()", -1)); VERIFY(ilist.empty()); // splice ListInit(ilist, nodes) += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9; ilist.splice(++ilist.begin(), ilist, --ilist.end()); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "splice(single)", 0, 9, 1, 2, 3, 4, 5, 6, 7, 8, -1)); intrusive_list ilist2; ListInit(ilist2, nodes+10) += 10, 11, 12, 13, 14, 15, 16, 17, 18, 19; ilist.splice(++++ilist.begin(), ilist2); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "splice(whole)", -1)); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "splice(whole)", 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 2, 3, 4, 5, 6, 7, 8, -1)); ilist.splice(ilist.begin(), ilist, ++++ilist.begin(), ----ilist.end()); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "splice(range)", 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 2, 3, 4, 5, 6, 0, 9, 7, 8, -1)); ilist.clear(); ilist.swap(ilist2); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "swap(empty)", -1)); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "swap(empty)", -1)); ilist2.push_back(nodes[0]); ilist.splice(ilist.begin(), ilist2); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "splice(single)", 0, -1)); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "splice(single)", -1)); // splice(single) -- evil case (splice at or right after current position) ListInit(ilist, nodes) += 0, 1, 2, 3, 4; ilist.splice(++++ilist.begin(), *++++ilist.begin()); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "splice(single)", 0, 1, 2, 3, 4, -1)); ilist.splice(++++++ilist.begin(), *++++ilist.begin()); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "splice(single)", 0, 1, 2, 3, 4, -1)); // splice(range) -- evil case (splice right after current position) ListInit(ilist, nodes) += 0, 1, 2, 3, 4; ilist.splice(++++ilist.begin(), ilist, ++ilist.begin(), ++++ilist.begin()); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "splice(range)", 0, 1, 2, 3, 4, -1)); // push_front / push_back ilist.clear(); ilist2.clear(); for(i = 4; i >= 0; --i) ilist.push_front(nodes[i]); for(i = 5; i < 10; ++i) ilist2.push_back(nodes[i]); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "push_front()", 0, 1, 2, 3, 4, -1)); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "push_back()", 5, 6, 7, 8, 9, -1)); for(i = 4; i >= 0; --i) { ilist.pop_front(); ilist2.pop_back(); } VERIFY(ilist.empty() && ilist2.empty()); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "pop_front()", -1)); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "pop_back()", -1)); // contains / locate for(i = 0; i < 5; ++i) ilist.push_back(nodes[i]); VERIFY( ilist.contains(nodes[2])); VERIFY(!ilist.contains(nodes[7])); it = ilist.locate(nodes[3]); VERIFY(it->mX == 3); it = ilist.locate(nodes[8]); VERIFY(it == ilist.end()); // reverse ilist.reverse(); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "push_front()", 4, 3, 2, 1, 0, -1)); // validate / validate_iterator VERIFY(ilist.validate()); it = ilist.locate(nodes[3]); VERIFY((ilist.validate_iterator(it) & (isf_valid | isf_can_dereference)) != 0); VERIFY( ilist.validate_iterator(intrusive_list::iterator(NULL)) == isf_none); // swap() ilist.swap(ilist2); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "swap()", -1)); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "swap()", 4, 3, 2, 1, 0, -1)); // erase() ListInit(ilist2, nodes) += 0, 1, 2, 3, 4; ListInit(ilist, nodes+5) += 5, 6, 7, 8, 9; ilist.erase(++++ilist.begin()); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "erase(single)", 5, 6, 8, 9, -1)); ilist.erase(ilist.begin(), ilist.end()); VERIFY(VerifySequence(ilist.begin(), ilist.end(), int(), "erase(all)", -1)); ilist2.erase(++ilist2.begin(), ----ilist2.end()); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "erase(range)", 0, 3, 4, -1)); // size VERIFY(ilist2.size() == 3); // pop_front / pop_back ilist2.pop_front(); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "pop_front()", 3, 4, -1)); ilist2.pop_back(); VERIFY(VerifySequence(ilist2.begin(), ilist2.end(), int(), "pop_back()", 3, -1)); } { // Test copy construction and assignment. // The following *should* not compile. intrusive_list ilist1; intrusive_list ilist2(ilist1); ilist1 = ilist2; } { // void sort() // void sort(Compare compare) const int kSize = 10; IntNode nodes[kSize]; intrusive_list listEmpty; listEmpty.sort(); VERIFY(VerifySequence(listEmpty.begin(), listEmpty.end(), int(), "list::sort", -1)); intrusive_list list1; ListInit(list1, nodes) += 1; list1.sort(); VERIFY(VerifySequence(list1.begin(), list1.end(), int(), "list::sort", 1, -1)); list1.clear(); intrusive_list list4; ListInit(list4, nodes) += 1, 9, 2, 3; list4.sort(); VERIFY(VerifySequence(list4.begin(), list4.end(), int(), "list::sort", 1, 2, 3, 9, -1)); list4.clear(); intrusive_list listA; ListInit(listA, nodes) += 1, 9, 2, 3, 5, 7, 4, 6, 8, 0; listA.sort(); VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "list::sort", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1)); listA.clear(); intrusive_list listB; ListInit(listB, nodes) += 1, 9, 2, 3, 5, 7, 4, 6, 8, 0; listB.sort(eastl::less()); VERIFY(VerifySequence(listB.begin(), listB.end(), int(), "list::sort", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1)); listB.clear(); } { // void merge(this_type& x); // void merge(this_type& x, Compare compare); const int kSize = 8; IntNode nodesA[kSize]; IntNode nodesB[kSize]; intrusive_list listA; ListInit(listA, nodesA) += 1, 2, 3, 4, 4, 5, 9, 9; intrusive_list listB; ListInit(listB, nodesB) += 1, 2, 3, 4, 4, 5, 9, 9; listA.merge(listB); VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "list::merge", 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5, 9, 9, 9, 9, -1)); VERIFY(VerifySequence(listB.begin(), listB.end(), int(), "list::merge", -1)); } { // void unique(); // void unique(BinaryPredicate); const int kSize = 8; IntNode nodesA[kSize]; IntNode nodesB[kSize]; intrusive_list listA; ListInit(listA, nodesA) += 1, 2, 3, 4, 4, 5, 9, 9; listA.unique(); VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "list::unique", 1, 2, 3, 4, 5, 9, -1)); intrusive_list listB; ListInit(listB, nodesB) += 1, 2, 3, 4, 4, 5, 9, 9; listB.unique(eastl::equal_to()); VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "list::unique", 1, 2, 3, 4, 5, 9, -1)); } return nErrorCount; }