Example #1
0
int TestFixedSList()
{
	int nErrorCount = 0;

	{
		fixed_slist<int, 64> list0101;
		VERIFY(list0101.empty());
		VERIFY(list0101.size() == 0);
		VERIFY(list0101.max_size() == 64);

		list0101.push_front(1);
		VERIFY(!list0101.empty());
		VERIFY(list0101.size() == 1);

		list0101.resize(3, 2);
		VERIFY(!list0101.empty());
		VERIFY(list0101.size() == 3);

		fixed_slist<int, 64>::iterator i = list0101.begin();
		VERIFY(*i == 1); ++i;
		VERIFY(*i == 2); ++i;
		VERIFY(*i == 2); ++i;
		VERIFY(i == list0101.end());

		list0101.resize(0);
		VERIFY(list0101.empty());
		VERIFY(list0101.size() == 0);
	}

	{
		fixed_slist<int, 64, true, MallocAllocator> list0101;
		VERIFY(list0101.empty());
		VERIFY(list0101.size() == 0);
		VERIFY(list0101.max_size() == 64);

		list0101.push_front(1);
		VERIFY(!list0101.empty());
		VERIFY(list0101.size() == 1);

		list0101.resize(3, 2);
		VERIFY(!list0101.empty());
		VERIFY(list0101.size() == 3);

		fixed_slist<int, 64>::iterator i = list0101.begin();
		VERIFY(*i == 1); ++i;
		VERIFY(*i == 2); ++i;
		VERIFY(*i == 2); ++i;
		VERIFY(i == list0101.end());

		while(list0101.size() < 64 + 16)
			list0101.push_front(0);

		list0101.resize(0);
		VERIFY(list0101.empty());
		VERIFY(list0101.size() == 0);
	}

	{
		// Test fixed slist with overflow and alignment requirements.
		typedef fixed_slist<Align64, 1, true, CustomAllocator> FixedSListWithAlignment;

		FixedSListWithAlignment fsl;

		Align64 a;

		fsl.push_front(a);
		fsl.push_front(a);
		fsl.push_front(a);
		fsl.push_front(a);
		fsl.push_front(a);
		for (FixedSListWithAlignment::const_iterator it = fsl.begin(); it != fsl.end(); ++it)
		{
			const Align64* ptr = &(*it);
			EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
		}
	}

	{
		// bool empty() const
		// bool has_overflowed() const
		// size_type size() const;
		// size_type max_size() const

		// Test a list that has overflow disabled.
		fixed_slist<int, 5, false> listInt5;

		VERIFY(listInt5.max_size() == 5);
		VERIFY(listInt5.size() == 0);
		VERIFY(listInt5.empty());
		VERIFY(!listInt5.has_overflowed());

		listInt5.push_front(37);
		listInt5.push_front(37);
		listInt5.push_front(37);

		VERIFY(listInt5.size() == 3);
		VERIFY(!listInt5.empty());
		VERIFY(!listInt5.has_overflowed());

		listInt5.push_front(37);
		listInt5.push_front(37);

		VERIFY(listInt5.size() == 5);
		VERIFY(!listInt5.empty());
		VERIFY(!listInt5.has_overflowed());

		listInt5.pop_front();

		VERIFY(listInt5.size() == 4);
		VERIFY(!listInt5.empty());
		VERIFY(!listInt5.has_overflowed());
	}


	{
		// bool empty() const
		// bool has_overflowed() const
		// size_type size() const;
		// size_type max_size() const

		// Test a list that has overflow enabled.
		fixed_slist<int, 5, true> listInt5;

		VERIFY(listInt5.max_size() == 5);
		VERIFY(listInt5.size() == 0);
		VERIFY(listInt5.empty());
		VERIFY(!listInt5.has_overflowed());

		listInt5.push_front(37);
		listInt5.push_front(37);
		listInt5.push_front(37);

		VERIFY(listInt5.size() == 3);
		VERIFY(!listInt5.empty());
		VERIFY(!listInt5.has_overflowed());

		listInt5.push_front(37);
		listInt5.push_front(37);

		VERIFY(listInt5.size() == 5);
		VERIFY(!listInt5.empty());
		VERIFY(!listInt5.has_overflowed());

		listInt5.push_front(37);

		VERIFY(listInt5.size() == 6);
		VERIFY(!listInt5.empty());
		VERIFY(listInt5.has_overflowed());

		listInt5.pop_front();

		VERIFY(listInt5.size() == 5);
		VERIFY(!listInt5.empty());
	  //VERIFY(listInt5.has_overflowed());  Disabled because currently has_overflowed can't detect this situation in non-debug builds.
	}


	{
		// fixed_slist(this_type&& x);
		// fixed_slist(this_type&&, const allocator_type&);
		// this_type& operator=(this_type&& x);

		#if EASTL_MOVE_SEMANTICS_ENABLED
			fixed_slist<TestObject, 16> slist3TO33(3, TestObject(33));
			fixed_slist<TestObject, 16> toListA(eastl::move(slist3TO33));
			EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == 33) /* && (slist3TO33.size() == 0) fixed_list usually can't honor the move request. */);

			// The following is not as strong a test of this ctor as it could be. A stronger test would be to use IntanceAllocator with different instances.
			fixed_slist<TestObject, 16, true, MallocAllocator> slist4TO44(4, TestObject(44));
			fixed_slist<TestObject, 16, true, MallocAllocator> toListB(eastl::move(slist4TO44), MallocAllocator());
			EATEST_VERIFY((toListB.size() == 4) && (toListB.front().mX == 44) /* && (slist4TO44.size() == 0) fixed_list usually can't honor the move request. */);

			fixed_slist<TestObject, 16, true, MallocAllocator> slist5TO55(5, TestObject(55));
			toListB = eastl::move(slist5TO55);
			EATEST_VERIFY((toListB.size() == 5) && (toListB.front().mX == 55) /* && (slist5TO55.size() == 0) fixed_list usually can't honor the move request. */);
		#endif
	}


	{
		#if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED
			// template <class... Args>
			// void emplace_front(Args&&... args);

			// template <class... Args>
			// iterator emplace_after(const_iterator position, Args&&... args);
		#else
			#if EASTL_MOVE_SEMANTICS_ENABLED
				// void emplace_front(value_type&& value);
				// iterator emplace_after(const_iterator position, value_type&& value);
			#endif
			// void emplace_front(const value_type& value);
			// iterator emplace_after(const_iterator position, const value_type& value);
		#endif

		#if EASTL_MOVE_SEMANTICS_ENABLED && EASTL_VARIADIC_TEMPLATES_ENABLED
			TestObject::Reset();

			fixed_slist<TestObject, 16> toListA;

			toListA.emplace_front(1, 2, 3); // This uses the TestObject(int x0, int x1, int x2, bool bThrowOnCopy) constructor.
			EATEST_VERIFY((toListA.size() == 1) && (toListA.front().mX == (1+2+3)) && (TestObject::sTOCtorCount == 1));

			toListA.emplace_after(toListA.before_begin(), 3, 4, 5);
			EATEST_VERIFY((toListA.size() == 2) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOCtorCount == 2));
		#else
			#if EASTL_MOVE_SEMANTICS_ENABLED
				TestObject::Reset();

				// We have a potential problem here in that the compiler is not required to use move construction below.
				// It is allowed to use standard copy construction if it wants. We could force it with eastl::move() usage.
				fixed_slist<TestObject, 16> toListA;

				toListA.emplace_front(TestObject(1, 2, 3));
				EATEST_VERIFY((toListA.size() == 1) && (toListA.front().mX == (1+2+3)) && (TestObject::sTOMoveCtorCount == 1));

				toListA.emplace_after(toListA.before_begin(), TestObject(3, 4, 5));
				EATEST_VERIFY((toListA.size() == 2) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 2));
			#endif
			
			TestObject::Reset();

			fixed_slist<TestObject, 16> toListB;
			TestObject to123(1, 2, 3);
			TestObject to345(3, 4, 5);

			toListB.emplace_front(to123);  // This should use the const value_type& version and not the value_type&& version of emplace_front.
			EATEST_VERIFY((toListB.size() == 1) && (toListB.front().mX == (1+2+3)) && (TestObject::sTOCopyCtorCount == 1));

			toListB.emplace_after(toListB.before_begin(), to345);
			EATEST_VERIFY((toListB.size() == 2) && (toListB.front().mX == (3+4+5)) && (TestObject::sTOCopyCtorCount == 2));

			EATEST_VERIFY(to123.mX == (1+2+3));  // Verify that the object was copied and not moved. If it was moved then mX would be 0 and not 1+2+3.
			EATEST_VERIFY(to345.mX == (3+4+5));
		#endif


		#if EASTL_MOVE_SEMANTICS_ENABLED
			// This test is similar to the emplace EASTL_MOVE_SEMANTICS_ENABLED pathway above. 
			TestObject::Reset();

			// void push_front(T&& x);
			// iterator insert(const_iterator position, T&& x);

			fixed_slist<TestObject, 16> toListC;

			toListC.push_front(TestObject(1, 2, 3));
			EATEST_VERIFY((toListC.size() == 1) && (toListC.front().mX == (1+2+3)) && (TestObject::sTOMoveCtorCount == 1));

			toListC.insert_after(toListC.before_begin(), TestObject(3, 4, 5));
			EATEST_VERIFY((toListC.size() == 2) && (toListC.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 2));
		#endif
	}


	{
		// slist(std::initializer_list<value_type> ilist, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR);
		// this_type& operator=(std::initializer_list<value_type>);
		// void assign(std::initializer_list<value_type> ilist);
		// iterator insert_after(iterator position, std::initializer_list<value_type> ilist);
		#if !defined(EA_COMPILER_NO_INITIALIZER_LISTS)
			fixed_slist<int, 8> intList = { 0, 1, 2 };
			EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "fixed_slist std::initializer_list", 0, 1, 2, -1));

			intList = { 13, 14, 15 };
			EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "fixed_slist std::initializer_list", 13, 14, 15, -1));

			intList.assign({ 16, 17, 18 });
			EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "fixed_slist std::initializer_list", 16, 17, 18, -1));

			fixed_slist<int, 8>::iterator it = intList.insert_after(intList.before_begin(), { 14, 15 });
			EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "fixed_slist std::initializer_list", 14, 15, 16, 17, 18, -1));
			EATEST_VERIFY(*it == 15); // Note that slist::insert_after returns the last inserted element, not the first as with list::insert.
		#endif
	}


	{
		// Test construction of a container with an overflow allocator constructor argument.
		//
		// GCC 4.4 has a hard time compiling this code correctly in optimized builds as it 
		// omits the increment of the mAllocCount field when calling overflowAllocator.allocate.
		#if defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION == 4004)
			MallocAllocator overflowAllocator;
			fixed_slist<int, 64, true, MallocAllocator> c(overflowAllocator);
			c.resize(65);
			VERIFY(c.get_overflow_allocator().mAllocCount == 1); // 1 for overflowing from 64 to 65.
		#else
			MallocAllocator overflowAllocator;
			void* p = overflowAllocator.allocate(1);
			fixed_slist<int, 64, true, MallocAllocator> c(overflowAllocator);
			c.resize(65);
			VERIFY(c.get_overflow_allocator().mAllocCount == 2); // 1 for above, and 1 for overflowing from 64 to 65.
			overflowAllocator.deallocate(p, 1);
		#endif
	}


	// We can't do this, due to how Reset is used above:
	//   EATEST_VERIFY(TestObject::IsClear());
	EATEST_VERIFY(TestObject::sMagicErrorCount == 0);
	TestObject::Reset();


	return nErrorCount;
}
Example #2
0
int TestFixedHash()
{
    EASTLTest_Printf("TestFixedHash\n");

    int nErrorCount = 0;

    {   // fixed_hash_map
        {
            // Test version *without* pool overflow.
            typedef eastl::fixed_hash_map<int, int, 100, 100, false> FixedHashMapFalse;
            FixedHashMapFalse fixedHashMap;

            fixedHashMap[0] = 0;
            fixedHashMap.insert(FixedHashMapFalse::value_type(0, 0));

            VERIFY(fixedHashMap.max_size() == 100);
            VERIFY(fixedHashMap.size() == 1);

            fixedHashMap.clear();
            VERIFY(fixedHashMap.size() == 0);

            for(int i = 0; i < 100; i++)
                fixedHashMap.insert(FixedHashMapFalse::value_type(i, i));
            VERIFY(fixedHashMap.size() == 100);

            // Verify that we allocated enough space for exactly N items.
            // It's possible that due to alignments, there might be room for N + 1.
            FixedHashMapFalse::allocator_type& allocator = fixedHashMap.get_allocator();
            void* pResult = allocator.allocate(sizeof(FixedHashMapFalse::node_type));
            if(pResult)
            {
                pResult = allocator.allocate(sizeof(FixedHashMapFalse::node_type));
                VERIFY(pResult == NULL);
            }

            fixedHashMap.clear(true);
            VERIFY(fixedHashMap.validate());
            VERIFY(fixedHashMap.size() == 0);
            VERIFY(fixedHashMap.bucket_count() == 1);
        }

        {
            // Test version *with* pool overflow.
            typedef eastl::fixed_hash_map<int, int, 100, 100, true> FixedHashMapTrue;
            FixedHashMapTrue fixedHashMap;

            fixedHashMap[0] = 0;
            fixedHashMap.insert(FixedHashMapTrue::value_type(0, 0));

            VERIFY(fixedHashMap.max_size() == 100);
            VERIFY(fixedHashMap.size() == 1);

            fixedHashMap.clear();
            VERIFY(fixedHashMap.size() == 0);

            for(int i = 0; i < 100; i++)
                fixedHashMap.insert(FixedHashMapTrue::value_type(i, i));
            VERIFY(fixedHashMap.size() == 100);

            FixedHashMapTrue::allocator_type& allocator = fixedHashMap.get_allocator();
            void* pResult = allocator.allocate(sizeof(FixedHashMapTrue::node_type));
            VERIFY(pResult != NULL);
            allocator.deallocate(pResult, sizeof(FixedHashMapTrue::node_type));

            fixedHashMap.clear(true);
            VERIFY(fixedHashMap.validate());
            VERIFY(fixedHashMap.size() == 0);
            VERIFY(fixedHashMap.bucket_count() == 1);

            // get_overflow_allocator / set_overflow_allocator
            // This is a weak test which should be improved.
            EASTLAllocatorType a = fixedHashMap.get_allocator().get_overflow_allocator();
            fixedHashMap.get_allocator().set_overflow_allocator(a);
        }

        {
            // Test fixed_hash_map *with* overflow and ensure the underlying hashtable rehashes.
            typedef eastl::fixed_hash_map<unsigned int, unsigned int, 512, 513, true,  eastl::hash<unsigned int>, eastl::equal_to<unsigned int>, false, MallocAllocator> FixedHashMap;

            FixedHashMap fixedHashMap;
            auto old_bucket_count = fixedHashMap.bucket_count();
            auto old_load_factor = fixedHashMap.load_factor();

            for (int i = 0; i < 1000; i++)
                fixedHashMap.insert(i);

            auto new_bucket_count = fixedHashMap.bucket_count();
            auto new_load_factor = fixedHashMap.load_factor();

            VERIFY(new_bucket_count != old_bucket_count);
            VERIFY(new_bucket_count > old_bucket_count);
            VERIFY(new_load_factor != old_load_factor);
            VERIFY(fixedHashMap.get_overflow_allocator().mAllocCountAll != 0);
        }

        {
            // Test version with overflow and alignment requirements.
            typedef fixed_hash_map<Align64, int, 1, 2, true> FixedHashMapWithAlignment;
            typedef fixed_hash_multimap<Align64, int, 1, 2, true> FixedHashMultiMapWithAlignment;
            typedef fixed_hash_set<Align64, 1, 2, true> FixedHashSetWithAlignment;
            typedef fixed_hash_multiset<Align64, 1, 2, true> FixedHashMultiSetWithAlignment;

            FixedHashMapWithAlignment fhm;
            FixedHashMultiMapWithAlignment fhmm;
            FixedHashSetWithAlignment fhs;
            FixedHashMultiSetWithAlignment fhms;

            Align64 a;
            a.mX = 1;
            Align64 b;
            b.mX = 2;
            Align64 c;
            c.mX = 3;
            Align64 d;
            d.mX = 4;
            Align64 e;
            e.mX = 5;

            fhm.insert(a);
            fhm.insert(b);
            fhm.insert(c);
            fhm.insert(d);
            fhm.insert(e);
            for (FixedHashMapWithAlignment::const_iterator it = fhm.begin(); it != fhm.end(); ++it)
            {
                const Align64* ptr = &((*it).first);
                EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
            }
            fhmm.insert(a);
            fhmm.insert(b);
            fhmm.insert(c);
            fhmm.insert(d);
            fhmm.insert(e);
            for (FixedHashMultiMapWithAlignment::const_iterator it = fhmm.begin(); it != fhmm.end(); ++it)
            {
                const Align64* ptr = &((*it).first);
                EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
            }
            fhs.insert(a);
            fhs.insert(b);
            fhs.insert(c);
            fhs.insert(d);
            fhs.insert(e);
            for (FixedHashSetWithAlignment::const_iterator it = fhs.begin(); it != fhs.end(); ++it)
            {
                const Align64* ptr = &(*it);
                EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
            }
            fhms.insert(a);
            fhms.insert(b);
            fhms.insert(c);
            fhms.insert(d);
            fhms.insert(e);
            for (FixedHashMultiSetWithAlignment::const_iterator it = fhms.begin(); it != fhms.end(); ++it)
            {
                const Align64* ptr = &(*it);
                EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
            }
        }

        {
            typedef eastl::fixed_hash_map<int, A, 100, 100> FixedHashMap;
            FixedHashMap fixedHashMap;

            fixedHashMap[0] = A();
            fixedHashMap.insert(FixedHashMap::value_type(0, A()));

            VERIFY(fixedHashMap.size() == 1);
        }

        {
            typedef eastl::fixed_hash_map<A, int, 100, 100> FixedHashMap;
            FixedHashMap fixedHashMap;

            fixedHashMap[A()] = 0;
            fixedHashMap.insert(FixedHashMap::value_type(A(), 0));

            VERIFY(fixedHashMap.size() == 1);
        }

        // explicitly instantiate some templated member functions
        {
            typedef eastl::fixed_hash_map<int, int, 100, 100, true> FixedHashMapTrue;
            FixedHashMapTrue::value_type testValues[] = { eastl::make_pair(0, 0), eastl::make_pair(1,1) };
            FixedHashMapTrue fixedHashMap(testValues, testValues + EAArrayCount(testValues));
            VERIFY(fixedHashMap.size() == 2);
        }
    }


    {   // fixed_hash_multimap
        {
            typedef eastl::fixed_hash_multimap<int, int, 100, 100> FixedHashMultiMap;
            FixedHashMultiMap fixedHashMultiMap;

            fixedHashMultiMap.insert(FixedHashMultiMap::value_type(0, 0));
            fixedHashMultiMap.insert(FixedHashMultiMap::value_type(0, 0));

            VERIFY(fixedHashMultiMap.max_size() == 100);
            VERIFY(fixedHashMultiMap.size() == 2);
        }

        // explicitly instantiate some templated member functions
        {
            typedef eastl::fixed_hash_multimap<int, int, 100, 100, true> FixedHashMultiMap;
            FixedHashMultiMap::value_type testValues[] = { eastl::make_pair(0, 0), eastl::make_pair(1,1) };
            FixedHashMultiMap fixedHashMultiMap(testValues, testValues + EAArrayCount(testValues));
            VERIFY(fixedHashMultiMap.size() == 2);
        }
    }


    {   // fixed_hash_set
        {
            typedef eastl::fixed_hash_set<int, 100, 100> FixedHashSet;
            FixedHashSet fixedHashSet;

            fixedHashSet.insert(0);
            fixedHashSet.insert(0);
            VERIFY(fixedHashSet.size() == 1);

            fixedHashSet.clear();
            VERIFY(fixedHashSet.size() == 0);

            for(int i = 0; i < 100; i++)
                fixedHashSet.insert(i);

            VERIFY(fixedHashSet.max_size() == 100);
            VERIFY(fixedHashSet.size() == 100);

            fixedHashSet.clear(true);
            VERIFY(fixedHashSet.validate());
            VERIFY(fixedHashSet.size() == 0);
            VERIFY(fixedHashSet.bucket_count() == 1);
        }

        {
            typedef eastl::fixed_hash_set<A, 100, 100> FixedHashSet;
            FixedHashSet fixedHashSet;

            fixedHashSet.insert(A());
            fixedHashSet.insert(A());

            VERIFY(fixedHashSet.max_size() == 100);
            VERIFY(fixedHashSet.size() == 1);
        }

        // explicitly instantiate some templated member functions
        {
            typedef eastl::fixed_hash_set<A, 100, 100> FixedHashSet;
            FixedHashSet::value_type testValues[] = { 0, 1 };
            FixedHashSet fixedHashSet(testValues, testValues + EAArrayCount(testValues));
            VERIFY(fixedHashSet.size() == 2);
        }
    }


    {   // fixed_hash_multiset
        {
            typedef eastl::fixed_hash_multiset<int, 100, 100> FixedHashMultiSet;
            FixedHashMultiSet fixedHashMultiSet;

            fixedHashMultiSet.insert(0);
            fixedHashMultiSet.insert(0);

            VERIFY(fixedHashMultiSet.size() == 2);
        }


        // explicitly instantiate some templated member functions
        {
            typedef eastl::fixed_hash_multiset<A, 100, 100> FixedHashMultiSet;
            FixedHashMultiSet::value_type testValues[] = { 0, 1 };
            FixedHashMultiSet fixedHashMultiSet(testValues, testValues + EAArrayCount(testValues));
            VERIFY(fixedHashMultiSet.size() == 2);
        }
    }


    {   // Tests of various bucketCount values.
        {
            typedef eastl::fixed_hash_set<int, 1, 2> FixedHashSet;
            FixedHashSet fixedHashSet;

            fixedHashSet.insert(0);

            VERIFY(fixedHashSet.size() == 1);
        }

        {
            typedef eastl::fixed_hash_set<int, 2, 2> FixedHashSet;
            FixedHashSet fixedHashSet;

            fixedHashSet.insert(0);
            fixedHashSet.insert(1);

            VERIFY(fixedHashSet.size() == 2);
        }

        {
            typedef eastl::fixed_hash_set<int, 11, 11> FixedHashSet; // 11 is one of the hashtable prime numbers.
            FixedHashSet fixedHashSet;

            for(int i = 0; i < 11; i++)
                fixedHashSet.insert(i);

            VERIFY(fixedHashSet.size() == 11);
        }


        {
            typedef eastl::fixed_hash_set<int, 11, 11> FixedHashSet; // 11 is one of the hashtable prime numbers.
            FixedHashSet fixedHashSet;

            VERIFY(fixedHashSet.validate());
            VERIFY(fixedHashSet.size() == 0);

            // Clear a newly constructed, already empty container.
            fixedHashSet.clear(true);
            VERIFY(fixedHashSet.validate());
            VERIFY(fixedHashSet.size() == 0);
            VERIFY(fixedHashSet.bucket_count() == 1);

            for(int i = 0; i < 11; i++)
                fixedHashSet.insert(i);
            VERIFY(fixedHashSet.size() == 11);
            VERIFY(fixedHashSet.bucket_count() > 1);

            fixedHashSet.clear(true);
            VERIFY(fixedHashSet.validate());
            VERIFY(fixedHashSet.size() == 0);
            VERIFY(fixedHashSet.bucket_count() == 1);

            for(int i = 0; i < 11; i++)
                fixedHashSet.insert(i);
            VERIFY(fixedHashSet.size() == 11);
        }
    }

    {   // Test of user-reported crash.

        // MemoryAddressToGroupMap is a container used by one team to associate debug
        // information with memory allocations. A crash due to corruption of the
        // fixed size node pool was reported on consoles (no crash on PC platform).
        const eastl_size_t kMemoryAddressMapNodeCount = 500000;

        typedef eastl::fixed_hash_map<
        const void*,                             // Key
              MemoryEntry,                             // Value
              kMemoryAddressMapNodeCount,              // Node Count
              kMemoryAddressMapNodeCount + 1,          // Bucket Count
              true,                                    // Enable Overflow
              eastl::hash<const void*>,                // Hash
              eastl::equal_to<const void*>,            // Predicate
              false,                                   // Cache Hash Code
              eastl::allocator                         // Allocator
              > MemoryAddressToGroupMap;

        MemoryAddressToGroupMap* pMap = new MemoryAddressToGroupMap;
        EA::UnitTest::Rand       rng(EA::UnitTest::GetRandSeed());

        // We simulate the usage of MemoryAddressToGroupMap via simulated alloc/free actions.
        for(eastl_size_t i = 0; i < kMemoryAddressMapNodeCount * 2; i++)
        {
            void* const p = (void*)(uintptr_t)rng.RandLimit(kMemoryAddressMapNodeCount);

            if(pMap->find(p) == pMap->end())
                (*pMap)[p] = MemoryEntry();
            else
                pMap->erase(p);
        }

        delete pMap;
    }


    {   // Test of bug reported by Dave Wall, May 14, 2008.
        const size_t kNumBuckets = 10;  // Bug only occurred with kNumBuckets == 10 or 11.

        typedef eastl::fixed_hash_map<const InstanceRenderData, uint32_t, kNumBuckets, kNumBuckets + 1, false> Map;

        Map map;
        InstanceRenderData renderData;

        uint32_t count = (uint32_t)kNumBuckets;

        while(count--)
        {
            renderData.mPad[0] = count;
            map.insert(Map::value_type(renderData, count));
        }

    }

    {
        // Test construction of a container with an overflow allocator constructor argument.
        MallocAllocator overflowAllocator;
        void* p = overflowAllocator.allocate(1);

        typedef eastl::fixed_hash_map<int, int, 64, 100, true, eastl::hash<int>, eastl::equal_to<int>, false, MallocAllocator> Container;
        Container c(overflowAllocator);

        for(int i = 0; i < 65; i++)
            c.insert(Container::value_type(i, i));

        VERIFY(c.get_overflow_allocator().mAllocCount == 2); // 1 for above, and 1 for overflowing from 64 to 65.
        overflowAllocator.deallocate(p, 1);
    }


    {
        // C++11 emplace and related functionality
        nErrorCount += TestMapCpp11<eastl::fixed_hash_map<int, TestObject,  2, 7, true> >();  // Exercize a low-capacity fixed-size container.
        nErrorCount += TestMapCpp11<eastl::fixed_hash_map<int, TestObject, 32, 7, true> >();

        nErrorCount += TestMapCpp11NonCopyable<eastl::fixed_hash_map<int, NonCopyable, 2, 7, true>>();

        nErrorCount += TestSetCpp11<eastl::fixed_hash_set<TestObject,  2, 7, true> >();
        nErrorCount += TestSetCpp11<eastl::fixed_hash_set<TestObject, 32, 7, true> >();

        nErrorCount += TestMultimapCpp11<eastl::fixed_hash_multimap<int, TestObject,  2, 7, true> >();
        nErrorCount += TestMultimapCpp11<eastl::fixed_hash_multimap<int, TestObject, 32, 7, true> >();

        nErrorCount += TestMultisetCpp11<eastl::fixed_hash_multiset<TestObject,  2, 7, true> >();
        nErrorCount += TestMultisetCpp11<eastl::fixed_hash_multiset<TestObject, 32, 7, true> >();
    }


    {
        // initializer_list support.
#if !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(_MSC_VER) //MSVC2013 cannot handle nested initializer lists properly. A bug report will be submitted for this.
        // fixed_hash_set(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR)
        // this_type& operator=(std::initializer_list<value_type> ilist);
        // void insert(std::initializer_list<value_type> ilist);
        fixed_hash_set<int, 11> intHashSet = { 12, 13, 14 };
        EATEST_VERIFY(intHashSet.size() == 3);
        EATEST_VERIFY(intHashSet.find(12) != intHashSet.end());
        EATEST_VERIFY(intHashSet.find(13) != intHashSet.end());
        EATEST_VERIFY(intHashSet.find(14) != intHashSet.end());

        intHashSet = { 22, 23, 24 };
        EATEST_VERIFY(intHashSet.size() == 3);
        EATEST_VERIFY(intHashSet.find(22) != intHashSet.end());
        EATEST_VERIFY(intHashSet.find(23) != intHashSet.end());
        EATEST_VERIFY(intHashSet.find(24) != intHashSet.end());

        intHashSet.insert({ 42, 43, 44 });
        EATEST_VERIFY(intHashSet.size() == 6);
        EATEST_VERIFY(intHashSet.find(42) != intHashSet.end());
        EATEST_VERIFY(intHashSet.find(43) != intHashSet.end());
        EATEST_VERIFY(intHashSet.find(44) != intHashSet.end());

        // hash_map(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR)
        // this_type& operator=(std::initializer_list<value_type> ilist);
        // void insert(std::initializer_list<value_type> ilist);
        fixed_hash_map<int, double, 11> intHashMap = { {12,12.0}, {13,13.0}, {14,14.0} };
        EATEST_VERIFY(intHashMap.size() == 3);
        EATEST_VERIFY(intHashMap.find(12) != intHashMap.end());
        EATEST_VERIFY(intHashMap.find(13) != intHashMap.end());
        EATEST_VERIFY(intHashMap.find(14) != intHashMap.end());

        intHashMap = { {22,22.0}, {23,23.0}, {24,24.0} };
        EATEST_VERIFY(intHashMap.size() == 3);
        EATEST_VERIFY(intHashMap.find(22) != intHashMap.end());
        EATEST_VERIFY(intHashMap.find(23) != intHashMap.end());
        EATEST_VERIFY(intHashMap.find(24) != intHashMap.end());

        intHashMap.insert({ {42,42.0}, {43,43.0}, {44,44.0} });
        EATEST_VERIFY(intHashMap.size() == 6);
        EATEST_VERIFY(intHashMap.find(42) != intHashMap.end());
        EATEST_VERIFY(intHashMap.find(43) != intHashMap.end());
        EATEST_VERIFY(intHashMap.find(44) != intHashMap.end());
#endif
    }

    return nErrorCount;
}
Example #3
0
int TestFixedVector()
{
	int nErrorCount = 0;

	TestObject::Reset();

	{ // Test the aligned_buffer template
		{
			eastl::aligned_buffer<sizeof(TestObject), EASTL_ALIGN_OF(TestObject)> toAlignedBuffer;
			TestObject* const pTO = new(toAlignedBuffer.buffer) TestObject;
			#if !defined(__GNUC__) // GCC complains about strict aliasing here.
				EATEST_VERIFY(pTO->mX == ((TestObject*)&toAlignedBuffer.buffer[0])->mX);
			#endif
			pTO->~TestObject();
		}

		{
			eastl::aligned_buffer<sizeof(Align64), EASTL_ALIGN_OF(Align64)> a64AlignedBuffer;
			Align64* const pAlign64 = new(a64AlignedBuffer.buffer) Align64;
			#if !defined(__GNUC__) // GCC complains about strict aliasing here.
				EATEST_VERIFY(pAlign64->mX == ((Align64*)&a64AlignedBuffer.buffer[0])->mX);
			#endif
			pAlign64->~Align64();
		}
	}

	{
		// fixed_vector();
		// size_type max_size() const;
		fixed_vector<int, 1, true> v;
		EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "fixed_vector", -1));
		EATEST_VERIFY(v.max_size() == 1);

		// fixed_vector();
		typedef fixed_vector<int, 8, false> FixedVectorInt8;
		FixedVectorInt8 fv1;
		EATEST_VERIFY(fv1.size() == 0);
		EATEST_VERIFY(fv1.capacity() == 8);

		// this_type& operator=(const base_type& x);
		FixedVectorInt8 fv2 = fv1;
		EATEST_VERIFY(fv2.size() == 0);
		EATEST_VERIFY(fv2.capacity() == 8);

		// fixed_vector(const base_type& x);
		FixedVectorInt8 fv3(fv1);
		EATEST_VERIFY(fv3.size() == 0);
		EATEST_VERIFY(fv3.capacity() == 8);

		// explicit fixed_vector(size_type n);
		FixedVectorInt8 fv4(5);
		EATEST_VERIFY(fv4.size() == 5);
		EATEST_VERIFY(fv4.capacity() == 8);
		EATEST_VERIFY((fv4[0] == 0) && (fv4[4] == 0));

		// fixed_vector(size_type n, const value_type& value);
		FixedVectorInt8 fv5((eastl_size_t)5, (int)3);
		EATEST_VERIFY(fv5.size() == 5);
		EATEST_VERIFY(fv5.capacity() == 8);
		EATEST_VERIFY((fv5[0] == 3) && (fv5[4] == 3));

		// fixed_vector(InputIterator first, InputIterator last);
		const int intArray[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
		FixedVectorInt8 fv6(intArray, intArray + 8);
		EATEST_VERIFY(fv6.size() == 8);
		EATEST_VERIFY(fv5.capacity() == 8);
		EATEST_VERIFY((fv6[0] == 0) && (fv6[7] == 7));

		// void reset_lose_memory();
		fv6.reset_lose_memory();
		EATEST_VERIFY(fv6.size() == 0);
		EATEST_VERIFY(fv6.capacity() == 8);

		// void set_capacity(size_type);
		fv6.set_capacity(100);  // overflow is disabled, so this should have no effect.
		EATEST_VERIFY(fv6.size() == 0);
		EATEST_VERIFY(fv6.capacity() == 8); // EATEST_VERIFY that the capacity is unchanged.

		fv6.resize(8);
		EATEST_VERIFY(fv6.size() == 8);
		fv6.set_capacity(1);
		EATEST_VERIFY(fv6.size() == 1);
		EATEST_VERIFY(fv6.capacity() == 8);

		// Exercise the freeing of memory in set_capacity.
		fixed_vector<int, 8, true> fv88;
		eastl_size_t capacity = fv88.capacity();
		fv88.resize(capacity);
		fv88.set_capacity(capacity * 2);
		EATEST_VERIFY(fv88.capacity() >= (capacity * 2));

		// void swap(this_type& x);
		FixedVectorInt8 fv7(5, 3);
		FixedVectorInt8 fv8(intArray, intArray + 8);

		swap(fv7, fv8);
		EATEST_VERIFY(fv7.size() == 8);
		EATEST_VERIFY((fv7[0] == 0) && (fv7[7] == 7));
		EATEST_VERIFY(fv8.size() == 5);
		EATEST_VERIFY((fv8[0] == 3) && (fv8[4] == 3));

		fv7.swap(fv8);
		EATEST_VERIFY(fv8.size() == 8);
		EATEST_VERIFY((fv8[0] == 0) && (fv8[7] == 7));
		EATEST_VERIFY(fv7.size() == 5);
		EATEST_VERIFY((fv7[0] == 3) && (fv7[4] == 3));

		// Test a recent optimization we added, which was to do a pointer swap of the fixed_vector pointers
		// for the case that both fixed_vectors were overflowed and using the heap instead of their fixed buffers.
		fixed_vector<int8_t, 4, true> fvo5;
		fixed_vector<int8_t, 4, true> fvo6;
		fvo5.resize(5, 5);
		EATEST_VERIFY(fvo5.has_overflowed());
		fvo6.resize(6, 6);
		EATEST_VERIFY(fvo6.has_overflowed());
		fvo5.swap(fvo6);
		EATEST_VERIFY(fvo5.size() == 6); // Verify that sizes are swapped.
		EATEST_VERIFY(fvo6.size() == 5);
		EATEST_VERIFY(EA::StdC::Memcheck8(fvo5.data(), 6, fvo5.size()) == NULL); // Verify that contents are swapped.
		EATEST_VERIFY(EA::StdC::Memcheck8(fvo6.data(), 5, fvo6.size()) == NULL);

		// global operators
		EATEST_VERIFY(  fv7 != fv8);
		EATEST_VERIFY(!(fv7 == fv8));
		fv7 = fv8;
		EATEST_VERIFY(  fv7 == fv8);
		EATEST_VERIFY(!(fv7 != fv8));
		EATEST_VERIFY(fv7.validate());
		EATEST_VERIFY(fv8.validate());
	}


	{
		// POD types
		typedef fixed_vector<int, 1, true> vInt;

		vInt    v;
		int     n = 5;
		int*    pN = &n;

		v.insert(v.begin(), pN, pN + 1);
		EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "fixed_vector", 5, -1));
		EATEST_VERIFY(v.validate());
	}


	{
		// non POD types
		typedef fixed_vector<TestObject, 1, true> VTO;

		VTO              v;
		TestObject       to(5);
		TestObject*      pTO = &to;

		v.insert(v.begin(), pTO, pTO + 1);
		EATEST_VERIFY(VerifySequence(v.begin(), v.end(), int(), "fixed_vector", 5, -1));
		EATEST_VERIFY(v.validate());
	}


	{
		// non POD types

		// The variables used here are declared above in the global space.
		vA64.insert(vA64.begin(), pA64, pA64 + 1);
		EATEST_VERIFY(VerifySequence(vA64.begin(), vA64.end(), int(), "fixed_vector", 5, -1));
		EATEST_VERIFY(((uintptr_t)&a64 % kEASTLTestAlign64) == 0);
		EATEST_VERIFY(((uintptr_t)vA64.data() % kEASTLTestAlign64) == 0);
		EATEST_VERIFY(((uintptr_t)&vA64[0] % kEASTLTestAlign64) == 0);
		EATEST_VERIFY(vA64.max_size() == 3);
		EATEST_VERIFY(vA64.validate());
	}


	{
		// Test for potential bug reported Sep. 19, 2006.
		typedef eastl::fixed_vector<void*, 160, false> FixedVector;
		FixedVector v;
		int* p = (int*)(uintptr_t)0;

		for(int i = 0; i < 100; i++, p++)
			v.push_back(p);

		EATEST_VERIFY(v.size() == 100);
		EATEST_VERIFY(eastl::unique(v.begin(), v.end()) == v.end());

		FixedVector::iterator it = eastl::lower_bound(v.begin(), v.end(), p - 30);
		EATEST_VERIFY(v.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference));
		EATEST_VERIFY((*it) == (p - 30));

		v.erase(it);

		EATEST_VERIFY(v.size() == 99);
		EATEST_VERIFY(eastl::unique(v.begin(), v.end()) == v.end());
	}

	{
		typedef fixed_vector<Align64, 4, true, CustomAllocator> FixedVectorWithAlignment;

		FixedVectorWithAlignment fv;

		Align64 a;

		fv.push_back(a);
		fv.push_back(a);
		fv.push_back(a);
		fv.push_back(a);
		fv.push_back(a);
		for (FixedVectorWithAlignment::const_iterator it = fv.begin(); it != fv.end(); ++it)
		{
			const Align64* ptr = &(*it);
			EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
		}
	}

	{   // Test overflow allocator specification
		typedef fixed_vector<char8_t, 64, true, MallocAllocator> FixedString64Malloc;

		FixedString64Malloc fs;

		fs.push_back('a');
		EATEST_VERIFY(fs.size() == 1);
		EATEST_VERIFY(fs[0] == 'a');

		fs.resize(95);
		fs[94] = 'b';
		EATEST_VERIFY(fs[0] == 'a');
		EATEST_VERIFY(fs[94] == 'b');
		EATEST_VERIFY(fs.size() == 95);
		EATEST_VERIFY(fs.validate());

		fs.clear();
		EATEST_VERIFY(fs.empty());

		fs.push_back('a');
		EATEST_VERIFY(fs.size() == 1);
		EATEST_VERIFY(fs[0] == 'a');
		EATEST_VERIFY(fs.validate());

		fs.resize(195);
		fs[194] = 'b';
		EATEST_VERIFY(fs[0] == 'a');
		EATEST_VERIFY(fs[194] == 'b');
		EATEST_VERIFY(fs.size() == 195);
		EATEST_VERIFY(fs.validate());

		// get_overflow_allocator / set_overflow_allocator
		fs.set_capacity(0); // This should free all memory allocated by the existing (overflow) allocator.
		EATEST_VERIFY(fs.validate());
		MallocAllocator a;
		fs.get_allocator().set_overflow_allocator(a);
		EATEST_VERIFY(fs.validate());
		fs.resize(400);
		EATEST_VERIFY(fs.validate());
	}


	{
		//Test clear(bool freeOverflow)
		const size_t nodeCount = 4;
		typedef fixed_vector<int, nodeCount, true> vInt4;
		vInt4 fv;
		for (int i = 0; (unsigned)i < nodeCount+1; i++)
		{
			fv.push_back(i);
		}
		vInt4::size_type capacity = fv.capacity();
		EATEST_VERIFY(capacity >= nodeCount+1);
		fv.clear(false);
		EATEST_VERIFY(fv.size() == 0);
		EATEST_VERIFY(fv.capacity() == capacity);
		fv.push_back(1);
		fv.clear(true);
		EATEST_VERIFY(fv.size() == 0);
		EATEST_VERIFY(fv.capacity() == nodeCount);
	}


	{
		// bool empty() const
		// bool has_overflowed() const
		// size_type size() const;
		// size_type max_size() const

		// Test a vector that has overflow disabled.
		fixed_vector<int, 5, false> vInt5;

		EATEST_VERIFY(vInt5.max_size() == 5);
		EATEST_VERIFY(vInt5.size() == 0);
		EATEST_VERIFY(vInt5.empty());
		EATEST_VERIFY(!vInt5.has_overflowed());

		vInt5.push_back(37);
		vInt5.push_back(37);
		vInt5.push_back(37);

		EATEST_VERIFY(vInt5.size() == 3);
		EATEST_VERIFY(!vInt5.empty());
		EATEST_VERIFY(!vInt5.has_overflowed());

		vInt5.push_back(37);
		vInt5.push_back(37);

		EATEST_VERIFY(vInt5.size() == 5);
		EATEST_VERIFY(!vInt5.empty());
		EATEST_VERIFY(!vInt5.has_overflowed());

		vInt5.pop_back();

		EATEST_VERIFY(vInt5.size() == 4);
		EATEST_VERIFY(!vInt5.empty());
		EATEST_VERIFY(!vInt5.has_overflowed());
		EATEST_VERIFY(vInt5.validate());
	}


	{
		// bool empty() const
		// bool has_overflowed() const
		// size_type size() const;
		// size_type max_size() const

		// Test a list that has overflow enabled.
		fixed_vector<int, 5, true> vInt5;

		EATEST_VERIFY(vInt5.max_size() == 5);
		EATEST_VERIFY(vInt5.size() == 0);
		EATEST_VERIFY(vInt5.empty());
		EATEST_VERIFY(!vInt5.has_overflowed());

		vInt5.push_back(37);
		vInt5.push_back(37);
		vInt5.push_back(37);

		EATEST_VERIFY(vInt5.size() == 3);
		EATEST_VERIFY(!vInt5.empty());
		EATEST_VERIFY(!vInt5.has_overflowed());

		vInt5.push_back(37);
		vInt5.push_back(37);

		EATEST_VERIFY(vInt5.size() == 5);
		EATEST_VERIFY(!vInt5.empty());
		EATEST_VERIFY(!vInt5.has_overflowed());

		vInt5.push_back(37);

		EATEST_VERIFY(vInt5.size() == 6);
		EATEST_VERIFY(!vInt5.empty());
		EATEST_VERIFY(vInt5.has_overflowed());

		vInt5.clear();

		EATEST_VERIFY(vInt5.size() == 0);
		EATEST_VERIFY(vInt5.empty());
		EATEST_VERIFY(vInt5.has_overflowed());           // Note that we declare the container full, as it is no longer using the fixed-capacity.
		EATEST_VERIFY(vInt5.validate());
	}

	{
		// void* push_back_uninitialized();

		int64_t toCount0 = TestObject::sTOCount;

		eastl::fixed_vector<TestObject, 32, false> vTO1;         // <-- bEnableOverflow = false
		EATEST_VERIFY(TestObject::sTOCount == toCount0);

		for(int i = 0; i < 25; i++) // 25 is simply a number that is <= 32.
		{
			void* pTO1 = vTO1.push_back_uninitialized();
			EATEST_VERIFY(TestObject::sTOCount == (toCount0 + i));

			new(pTO1) TestObject(i);
			EATEST_VERIFY(TestObject::sTOCount == (toCount0 + i + 1));
			EATEST_VERIFY(vTO1.back().mX == i);
			EATEST_VERIFY(vTO1.validate());
		}
	}

	{
		// void* push_back_uninitialized();

		int64_t toCount0 = TestObject::sTOCount;

		eastl::fixed_vector<TestObject, 15, true> vTO2;         // <-- bEnableOverflow = true
		EATEST_VERIFY(TestObject::sTOCount == toCount0);

		for(int i = 0; i < 25; i++) // 25 is simply a number that is > 15.
		{
			void* pTO2 = vTO2.push_back_uninitialized();
			EATEST_VERIFY(TestObject::sTOCount == (toCount0 + i));

			new(pTO2) TestObject(i);
			EATEST_VERIFY(TestObject::sTOCount == (toCount0 + i + 1));
			EATEST_VERIFY(vTO2.back().mX == i);
			EATEST_VERIFY(vTO2.validate());
		}
	}

	{ // Try to repro user report that fixed_vector on the stack crashes.
		eastl::fixed_vector<int,        10, false> fvif;
		eastl::fixed_vector<int,        10, true>  fvit;
		eastl::fixed_vector<TestObject, 10, false> fvof;
		eastl::fixed_vector<TestObject, 10, true>  fvot;
		eastl::fixed_vector<int,        10, false, MallocAllocator> fvimf;
		eastl::fixed_vector<int,        10, true,  MallocAllocator> fvimt;
		eastl::fixed_vector<TestObject, 10, false, MallocAllocator> fvomf;
		eastl::fixed_vector<TestObject, 10, true,  MallocAllocator> fvomt;

		fvif.push_back(1);
		fvit.push_back(1);
		fvimf.push_back(1);
		fvimt.push_back(1);

		fvif.clear();
		fvit.clear();
		fvimf.clear();
		fvimt.clear();
	}

	{
		// Test construction of a container with an overflow allocator constructor argument.
		MallocAllocator overflowAllocator;
		void* p = overflowAllocator.allocate(1);
		fixed_vector<int, 64, true, MallocAllocator> c(overflowAllocator);
		c.resize(65);
		EATEST_VERIFY(c.get_overflow_allocator().mAllocCount == 2); // 1 for above, and 1 for overflowing from 64 to 65.
		overflowAllocator.deallocate(p, 1);
	}

	EATEST_VERIFY(TestObject::IsClear());
	TestObject::Reset();


	{   // Test for crash bug reported by Arpit Baldeva.
		eastl::fixed_vector<void*, 1, true> test;

		test.push_back(NULL);
		test.push_back(NULL);
		test.erase(eastl::find(test.begin(), test.end(), (void*)NULL));
		test.erase(eastl::find(test.begin(), test.end(), (void*)NULL));
		EATEST_VERIFY(test.empty());
		EATEST_VERIFY(test.validate());

		test.set_capacity(0);    // "Does nothing currently."
		EATEST_VERIFY(test.capacity() == 0);
		EATEST_VERIFY(test.validate());

	}   // "Crash here."

	{
		const int FV_SIZE = 100;
		fixed_vector<unique_ptr<unsigned int>, FV_SIZE> fvmv1; // to move via move assignment operator
		fixed_vector<unique_ptr<unsigned int>, FV_SIZE> fvmv2; // to move via move copy constructor

		for (unsigned int i = 0; i < FV_SIZE; ++i) // populate fvmv1
			fvmv1.push_back(make_unique<unsigned int>(i));

		fvmv2 = eastl::move(fvmv1); // Test move assignment operator

		for (unsigned int i = 0; i < FV_SIZE; ++i)
		{
			EATEST_VERIFY(!fvmv1[i]);
			EATEST_VERIFY(*fvmv2[i] == i);
		}
		EATEST_VERIFY(fvmv2.validate());
		
		swap(fvmv1, fvmv2); // Test swap with move-only objects
		for (unsigned int i = 0; i < FV_SIZE; ++i)
		{
			EATEST_VERIFY(*fvmv1[i] == i);
			EATEST_VERIFY(!fvmv2[i]);
		}
		EATEST_VERIFY(fvmv1.validate());
		EATEST_VERIFY(fvmv2.validate());

		fixed_vector<unique_ptr<unsigned int>, FV_SIZE> fv = eastl::move(fvmv1); // Test move copy constructor
		for (unsigned int i = 0; i < FV_SIZE; ++i)
		{
			EATEST_VERIFY(!fvmv1[i]);
			EATEST_VERIFY(*fv[i] == i);
		}
		EATEST_VERIFY(fv.validate());
	}

	#if defined(EA_COMPILER_CPP17_ENABLED) 
	//Test pairing of std::variant with fixed_vector
	{
		eastl::fixed_vector<std::variant<int>, 4> v;
		eastl::fixed_vector<std::variant<int>, 4> b = eastl::move(v);
	}
	#endif
	return nErrorCount;     
}