First
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef CONCEPTSIMPLS_H
|
||||
#define CONCEPTSIMPLS_H
|
||||
|
||||
#include <EASTL/type_traits.h>
|
||||
|
||||
#if !defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS) && !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
|
||||
|
||||
#define EASTL_TEST_CONCEPT_IMPLS
|
||||
|
||||
// This header provides a variety of helper classes that have interfaces corresponding to the concepts used to specify
|
||||
// requirements of many STL containers and algorithms. These helper classes are used in tests to verify that containers
|
||||
// and algorithms do not impose stricter requirements than specified by the standard on their arguments.
|
||||
|
||||
// Destructible - only valid operation on this class is to destroy it.
|
||||
|
||||
class Destructible
|
||||
{
|
||||
public:
|
||||
~Destructible() = default;
|
||||
|
||||
Destructible() = delete;
|
||||
Destructible(const Destructible&) = delete;
|
||||
Destructible(Destructible&&) = delete;
|
||||
Destructible& operator=(const Destructible&) = delete;
|
||||
Destructible& operator=(Destructible&&) = delete;
|
||||
};
|
||||
|
||||
// Unfortunately not all compilers handle type_traits reliably correctly currently so we can't straightforwardly
|
||||
// static_assert everything that should be true of this class
|
||||
static_assert(eastl::is_destructible<Destructible>::value, "eastl::is_destructible<Destructible>::value");
|
||||
// static_assert(!eastl::is_default_constructible<Destructible>::value,
|
||||
// "!eastl::is_default_constructible<Destructible>::value");
|
||||
// static_assert(!is_copy_constructible<Destructible>::value, "!eastl::is_copy_constructible<Destructible>::value");
|
||||
static_assert(!eastl::is_copy_assignable<Destructible>::value, "!eastl::is_copy_assignable<Destructible>::value");
|
||||
// static_assert(!eastl::is_move_constructible<Destructible>::value,
|
||||
// "!eastl::is_move_constructible<Destructible>::value");
|
||||
static_assert(!eastl::is_move_assignable<Destructible>::value, "!eastl::is_move_assignable<Destructible>::value");
|
||||
|
||||
class DefaultConstructible
|
||||
{
|
||||
public:
|
||||
static const int defaultValue = 42;
|
||||
|
||||
DefaultConstructible() : value(defaultValue) {}
|
||||
~DefaultConstructible() = default;
|
||||
|
||||
DefaultConstructible(const DefaultConstructible&) = delete;
|
||||
DefaultConstructible(DefaultConstructible&&) = delete;
|
||||
DefaultConstructible& operator=(const DefaultConstructible&) = delete;
|
||||
DefaultConstructible& operator=(DefaultConstructible&&) = delete;
|
||||
|
||||
const int value;
|
||||
};
|
||||
|
||||
|
||||
struct NotDefaultConstructible
|
||||
{
|
||||
NotDefaultConstructible() = delete;
|
||||
};
|
||||
static_assert(!eastl::is_default_constructible<NotDefaultConstructible>::value, "'NotDefaultConstructible' is default constructible.");
|
||||
|
||||
|
||||
class CopyConstructible
|
||||
{
|
||||
public:
|
||||
static const int defaultValue = 42;
|
||||
static CopyConstructible Create()
|
||||
{
|
||||
CopyConstructible x;
|
||||
return x;
|
||||
}
|
||||
|
||||
CopyConstructible(const CopyConstructible&) = default;
|
||||
~CopyConstructible() = default;
|
||||
|
||||
CopyConstructible& operator=(const CopyConstructible&) = delete;
|
||||
CopyConstructible& operator=(CopyConstructible&&) = delete;
|
||||
|
||||
const int value;
|
||||
|
||||
private:
|
||||
CopyConstructible() : value(defaultValue) {}
|
||||
};
|
||||
|
||||
// Unfortunately not all compilers handle type_traits reliably correctly currently so we can't straightforwardly
|
||||
// static_assert everything that should be true of this class
|
||||
static_assert(eastl::is_destructible<CopyConstructible>::value, "eastl::is_destructible<CopyConstructible>::value");
|
||||
// static_assert(!eastl::is_default_constructible<CopyConstructible>::value,
|
||||
// "!eastl::is_default_constructible<CopyConstructible>::value");
|
||||
// static_assert(is_copy_constructible<CopyConstructible>::value, "is_copy_constructible<CopyConstructible>::value");
|
||||
static_assert(eastl::is_copy_constructible<CopyConstructible>::value,
|
||||
"eastl::is_copy_constructible<CopyConstructible>::value");
|
||||
static_assert(!eastl::is_copy_assignable<CopyConstructible>::value,
|
||||
"!eastl::is_copy_assignable<CopyConstructible>::value");
|
||||
// static_assert(!eastl::is_move_constructible<CopyConstructible>::value,
|
||||
// "!eastl::is_move_constructible<CopyConstructible>::value");
|
||||
static_assert(!eastl::is_move_assignable<CopyConstructible>::value,
|
||||
"!eastl::is_move_assignable<CopyConstructible>::value");
|
||||
|
||||
class MoveConstructible
|
||||
{
|
||||
public:
|
||||
static const int defaultValue = 42;
|
||||
static MoveConstructible Create()
|
||||
{
|
||||
return MoveConstructible{};
|
||||
}
|
||||
|
||||
MoveConstructible(MoveConstructible&& x) : value(x.value) {}
|
||||
~MoveConstructible() = default;
|
||||
|
||||
MoveConstructible(const MoveConstructible&) = delete;
|
||||
MoveConstructible& operator=(const MoveConstructible&) = delete;
|
||||
MoveConstructible& operator=(MoveConstructible&&) = delete;
|
||||
|
||||
const int value;
|
||||
|
||||
private:
|
||||
MoveConstructible() : value(defaultValue) {}
|
||||
};
|
||||
|
||||
class MoveAssignable
|
||||
{
|
||||
public:
|
||||
static const int defaultValue = 42;
|
||||
static MoveAssignable Create()
|
||||
{
|
||||
return MoveAssignable{};
|
||||
}
|
||||
|
||||
MoveAssignable(MoveAssignable&& x) : value(x.value) {}
|
||||
MoveAssignable& operator=(MoveAssignable&& x)
|
||||
{
|
||||
value = x.value;
|
||||
return *this;
|
||||
}
|
||||
~MoveAssignable() = default;
|
||||
|
||||
MoveAssignable(const MoveAssignable&) = delete;
|
||||
MoveAssignable& operator=(const MoveAssignable&) = delete;
|
||||
|
||||
int value;
|
||||
|
||||
private:
|
||||
MoveAssignable() : value(defaultValue) {}
|
||||
};
|
||||
|
||||
struct MoveAndDefaultConstructible
|
||||
{
|
||||
static const int defaultValue = 42;
|
||||
|
||||
MoveAndDefaultConstructible() : value(defaultValue) {}
|
||||
MoveAndDefaultConstructible(MoveAndDefaultConstructible&& x) : value(x.value) {}
|
||||
~MoveAndDefaultConstructible() = default;
|
||||
|
||||
MoveAndDefaultConstructible(const MoveAndDefaultConstructible&) = delete;
|
||||
MoveAndDefaultConstructible& operator=(const MoveAndDefaultConstructible&) = delete;
|
||||
MoveAndDefaultConstructible& operator=(MoveAndDefaultConstructible&&) = delete;
|
||||
|
||||
const int value;
|
||||
};
|
||||
|
||||
struct MissingMoveConstructor
|
||||
{
|
||||
MissingMoveConstructor() {}
|
||||
MissingMoveConstructor(const MissingMoveConstructor&) {}
|
||||
MissingMoveConstructor& operator=(MissingMoveConstructor&&) { return *this; }
|
||||
MissingMoveConstructor& operator=(const MissingMoveConstructor&) { return *this; }
|
||||
bool operator<(const MissingMoveConstructor&) const { return true; }
|
||||
};
|
||||
|
||||
struct MissingMoveAssignable
|
||||
{
|
||||
MissingMoveAssignable() {}
|
||||
MissingMoveAssignable(const MissingMoveAssignable&) {}
|
||||
MissingMoveAssignable(MissingMoveAssignable&&) {}
|
||||
MissingMoveAssignable& operator=(const MissingMoveAssignable&) { return *this; }
|
||||
bool operator<(const MissingMoveAssignable&) const { return true; }
|
||||
};
|
||||
|
||||
struct MissingEquality
|
||||
{
|
||||
MissingEquality& operator==(const MissingEquality&) = delete;
|
||||
};
|
||||
|
||||
#endif // !defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS) && !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
|
||||
|
||||
#endif // CONCEPTSIMPLS_H
|
||||
@@ -0,0 +1,273 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/version.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <new>
|
||||
#if !defined(EA_COMPILER_NO_STANDARD_CPP_LIBRARY)
|
||||
#include <vector> // Used to detect the C++ Standard Library version.
|
||||
#endif
|
||||
|
||||
#ifndef EA_PLATFORM_PLAYSTSATION2
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
#if defined(EA_PLATFORM_WINDOWS)
|
||||
#include <Windows.h>
|
||||
#elif defined(EA_PLATFORM_ANDROID)
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
#if defined(_MSC_VER) && defined(EA_PLATFORM_MICROSOFT)
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
#include "EASTLTestAllocator.h"
|
||||
#include "EASTLTest.h" // Include this last, as it enables compiler warnings.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// init_seg
|
||||
//
|
||||
#ifdef _MSC_VER
|
||||
// Set initialization order between init_seg(compiler) (.CRT$XCC) and
|
||||
// init_seg(lib) (.CRT$XCL). The linker sorts the .CRT sections
|
||||
// alphabetically so we simply need to pick a name that is between
|
||||
// XCC and XCL.
|
||||
#pragma warning(disable: 4075) // warning C4075: initializers put in unrecognized initialization area
|
||||
#pragma init_seg(".CRT$XCF")
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EA_INIT_PRIORITY
|
||||
//
|
||||
// This is simply a wrapper for the GCC init_priority attribute that allows
|
||||
// multiplatform code to be easier to read.
|
||||
//
|
||||
// Example usage:
|
||||
// SomeClass gSomeClass EA_INIT_PRIORITY(2000);
|
||||
//
|
||||
#if !defined(EA_INIT_PRIORITY)
|
||||
#if defined(__GNUC__)
|
||||
#define EA_INIT_PRIORITY(x) __attribute__ ((init_priority (x)))
|
||||
#else
|
||||
#define EA_INIT_PRIORITY(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestObject
|
||||
//
|
||||
int64_t TestObject::sTOCount = 0;
|
||||
int64_t TestObject::sTOCtorCount = 0;
|
||||
int64_t TestObject::sTODtorCount = 0;
|
||||
int64_t TestObject::sTODefaultCtorCount = 0;
|
||||
int64_t TestObject::sTOArgCtorCount = 0;
|
||||
int64_t TestObject::sTOCopyCtorCount = 0;
|
||||
int64_t TestObject::sTOMoveCtorCount = 0;
|
||||
int64_t TestObject::sTOCopyAssignCount = 0;
|
||||
int64_t TestObject::sTOMoveAssignCount = 0;
|
||||
int TestObject::sMagicErrorCount = 0;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MallocAllocator
|
||||
//
|
||||
int MallocAllocator::mAllocCountAll = 0;
|
||||
int MallocAllocator::mFreeCountAll = 0;
|
||||
size_t MallocAllocator::mAllocVolumeAll = 0;
|
||||
void* MallocAllocator::mpLastAllocation = NULL;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// InstanceAllocator
|
||||
//
|
||||
int InstanceAllocator::mMismatchCount = 0;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CountingAllocator
|
||||
//
|
||||
uint64_t CountingAllocator::activeAllocCount = 0;
|
||||
uint64_t CountingAllocator::totalAllocCount = 0;
|
||||
uint64_t CountingAllocator::totalDeallocCount = 0;
|
||||
uint64_t CountingAllocator::totalCtorCount = 0;
|
||||
uint64_t CountingAllocator::defaultCtorCount = 0;
|
||||
uint64_t CountingAllocator::copyCtorCount = 0;
|
||||
uint64_t CountingAllocator::assignOpCount = 0;
|
||||
uint64_t CountingAllocator::totalAllocatedMemory = 0;
|
||||
uint64_t CountingAllocator::activeAllocatedMemory = 0;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// gEASTL_TestLevel
|
||||
//
|
||||
int gEASTL_TestLevel = 0;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EASTLTest_CheckMemory_Imp
|
||||
//
|
||||
int EASTLTest_CheckMemory_Imp(const char* pFile, int nLine)
|
||||
{
|
||||
int nErrorCount(0);
|
||||
bool bMemoryOK(true);
|
||||
|
||||
#if defined(_DEBUG) && (defined(EA_COMPILER_MSVC) && defined(EA_PLATFORM_MICROSOFT))
|
||||
if(!_CrtCheckMemory())
|
||||
bMemoryOK = false;
|
||||
#endif
|
||||
|
||||
#ifdef EA_DEBUG
|
||||
if(!EASTLTest_ValidateHeap())
|
||||
bMemoryOK = false;
|
||||
#endif
|
||||
|
||||
if(!bMemoryOK)
|
||||
{
|
||||
nErrorCount++;
|
||||
EASTLTest_Printf("Memory check failure:\n%s: line %d\n\n", pFile, nLine);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GetStdSTLType
|
||||
//
|
||||
StdSTLType GetStdSTLType()
|
||||
{
|
||||
#if defined(_STLPORT_VERSION)
|
||||
return kSTLPort; // Descendent of the old HP / SGI STL.
|
||||
#elif defined(_RWSTD_VER_STR)
|
||||
return kSTLApache; // a.k.a. Rogue Wave, which is a descendent of the old HP / SGI STL.
|
||||
#elif defined(_CPPLIB_VER)
|
||||
return kSTLDinkumware; // Indicated by the presence of the central yvals.h header.
|
||||
#elif defined(_LIBCPP_VECTOR)
|
||||
return kSTLClang;
|
||||
#elif defined(_GLIBCXX_VECTOR)
|
||||
return kSTLGCC; // a.k.a. libstdc++
|
||||
#elif defined(_MSC_VER)
|
||||
return kSTLMS; // This is a tweaked version of Dinkumware.
|
||||
#else
|
||||
return kSTLUnknown;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GetStdSTLName
|
||||
//
|
||||
const char* GetStdSTLName()
|
||||
{
|
||||
// We may need to tweak this function over time.
|
||||
// Theoretically it is possible to have multiple standard
|
||||
// STL versions active, as some of them have options to
|
||||
// put themselves in different namespaces.
|
||||
|
||||
// Tests for specific STL versions directly.
|
||||
#if defined(_STLPORT_VERSION)
|
||||
return "STLPort";
|
||||
#elif defined(__SGI_STL_VECTOR)
|
||||
return "SGI";
|
||||
#elif defined(_RWSTD_VER_STR)
|
||||
return "Apache";
|
||||
|
||||
// Tests for specific platforms that have specific STL versions.
|
||||
#elif defined(EA_PLATFORM_SONY)
|
||||
return "Sony Dinkumware";
|
||||
|
||||
// Special case for Dinkumware.
|
||||
#elif defined(_CPPLIB_VER)
|
||||
#if defined(_MSC_VER)
|
||||
return "VC++ Dinkumware";
|
||||
#else
|
||||
return "Dinkumware";
|
||||
#endif
|
||||
|
||||
// Tests for specific compilers as a fallback.
|
||||
#elif defined(_MSC_VER)
|
||||
return "VC++ ???";
|
||||
#elif defined(_LIBCPP_VECTOR)
|
||||
return "clang libc++";
|
||||
#elif defined(__GNUC__) || defined(_GLIBCXX_VECTOR)
|
||||
return "GCC (or emulated GCC) libstdc++";
|
||||
#else
|
||||
#error Need to be able to identify the standard STL version.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MallocAllocator
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The following function is defined here instead of in the header because GCC
|
||||
// generates a bogus warning about freeing a non-heap pointer when this function
|
||||
// is declared inline.
|
||||
|
||||
void MallocAllocator::deallocate(void *p, size_t n)
|
||||
{
|
||||
++mFreeCount;
|
||||
mAllocVolume -= n;
|
||||
++mFreeCountAll;
|
||||
mAllocVolumeAll -= n;
|
||||
|
||||
return free(p);
|
||||
}
|
||||
|
||||
void* MallocAllocator::allocate(size_t n, int)
|
||||
{
|
||||
++mAllocCount; mAllocVolume += n; ++mAllocCountAll; mAllocVolumeAll += n; mpLastAllocation = malloc(n); return mpLastAllocation;
|
||||
}
|
||||
|
||||
void* MallocAllocator::allocate(size_t n, size_t, size_t, int)
|
||||
{
|
||||
++mAllocCount; mAllocVolume += n; ++mAllocCountAll; mAllocVolumeAll += n; mpLastAllocation = malloc(n); return mpLastAllocation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CustomAllocator
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void* CustomAllocator::allocate(size_t n, int flags)
|
||||
{
|
||||
return ::operator new[](n, get_name(), flags, 0, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void* CustomAllocator::allocate(size_t n, size_t alignment, size_t offset, int flags)
|
||||
{
|
||||
return ::operator new[](n, alignment, offset, get_name(), flags, 0, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void CustomAllocator::deallocate(void* p, size_t /*n*/)
|
||||
{
|
||||
::operator delete((char*)p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,492 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef EASTLTEST_ALLOCATOR_H
|
||||
#define EASTLTEST_ALLOCATOR_H
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
#if !EASTL_OPENSOURCE
|
||||
|
||||
#include <PPMalloc/EAGeneralAllocator.h>
|
||||
#include <PPMalloc/EAGeneralAllocatorDebug.h>
|
||||
|
||||
#include <coreallocator/icoreallocator_interface.h>
|
||||
|
||||
#if defined(EA_COMPILER_MSVC)
|
||||
#include <math.h> // VS2008 has an acknowledged bug that requires math.h (and possibly also string.h) to be #included before intrin.h.
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_ReturnAddress)
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EASTLTest_GetGeneralAllocator()
|
||||
//
|
||||
namespace EA
|
||||
{
|
||||
namespace Allocator
|
||||
{
|
||||
#ifdef EA_DEBUG
|
||||
extern PPM_API GeneralAllocatorDebug* gpEAGeneralAllocatorDebug;
|
||||
#else
|
||||
extern PPM_API GeneralAllocator* gpEAGeneralAllocator;
|
||||
#endif
|
||||
|
||||
static inline auto& EASTLTest_GetGeneralAllocator()
|
||||
{
|
||||
#ifdef EA_DEBUG
|
||||
using GeneralAllocatorType = GeneralAllocatorDebug;
|
||||
#else
|
||||
using GeneralAllocatorType = GeneralAllocator;
|
||||
#endif
|
||||
|
||||
static GeneralAllocatorType sGeneralAllocator;
|
||||
return sGeneralAllocator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// allocator counts for debugging purposes
|
||||
//
|
||||
int gEASTLTest_AllocationCount = 0;
|
||||
int gEASTLTest_TotalAllocationCount = 0;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EASTLTest_ValidateHeap
|
||||
//
|
||||
bool EASTLTest_ValidateHeap()
|
||||
{
|
||||
#ifdef EA_DEBUG
|
||||
return EA::Allocator::EASTLTest_GetGeneralAllocator().ValidateHeap(EA::Allocator::GeneralAllocator::kHeapValidationLevelBasic);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Microsoft function parameter annotations
|
||||
// https://msdn.microsoft.com/en-CA/library/hh916382.aspx
|
||||
//
|
||||
#ifndef _Ret_maybenull_
|
||||
#define _Ret_maybenull_
|
||||
#endif
|
||||
|
||||
#ifndef _Post_writable_byte_size_
|
||||
#define _Post_writable_byte_size_(x)
|
||||
#endif
|
||||
|
||||
#ifndef _Ret_notnull_
|
||||
#define _Ret_notnull_
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// operator new extensions
|
||||
//
|
||||
namespace
|
||||
{
|
||||
#ifdef EA_DEBUG
|
||||
const char gUnattributedNewTag[] = "Anonymous new";
|
||||
#endif
|
||||
|
||||
#if defined(EA_COMPILER_MSVC)
|
||||
#define UNATTRIBUTED_NEW_FILE "raw_return_address"
|
||||
#define UNATTRIBUTED_NEW_LINE ((int)(uintptr_t)_ReturnAddress())
|
||||
#else
|
||||
#define UNATTRIBUTED_NEW_FILE NULL
|
||||
#define UNATTRIBUTED_NEW_LINE 0
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// system memory allocation helpers
|
||||
//
|
||||
namespace
|
||||
{
|
||||
void* PlatformMalloc(size_t size, size_t alignment = 16)
|
||||
{
|
||||
#ifdef EA_PLATFORM_MICROSOFT
|
||||
return _aligned_malloc(size, alignment);
|
||||
#else
|
||||
void *p = nullptr;
|
||||
alignment = alignment < sizeof( void *) ? sizeof( void *) : alignment;
|
||||
posix_memalign(&p, alignment, size);
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlatformFree(void* p)
|
||||
{
|
||||
#ifdef EA_PLATFORM_MICROSOFT
|
||||
_aligned_free(p);
|
||||
#else
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
void* InternalMalloc(size_t size)
|
||||
{
|
||||
void* mem = nullptr;
|
||||
|
||||
auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator();
|
||||
|
||||
#ifdef EA_DEBUG
|
||||
mem = allocator.MallocDebug(size, 0, 0, gUnattributedNewTag, UNATTRIBUTED_NEW_FILE, UNATTRIBUTED_NEW_LINE);
|
||||
#else
|
||||
mem = allocator.Malloc(size);
|
||||
#endif
|
||||
|
||||
if(mem == nullptr)
|
||||
mem = PlatformMalloc(size);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void* InternalMalloc(size_t size, const char* name, int flags, unsigned debugFlags, const char* file, int line)
|
||||
{
|
||||
void* mem = nullptr;
|
||||
|
||||
auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator();
|
||||
|
||||
#ifdef EA_DEBUG
|
||||
mem = allocator.MallocDebug(size, flags, debugFlags, name, file, line);
|
||||
#else
|
||||
mem = allocator.Malloc(size, flags);
|
||||
EA_UNUSED(debugFlags);
|
||||
EA_UNUSED(file);
|
||||
EA_UNUSED(line);
|
||||
EA_UNUSED(name);
|
||||
#endif
|
||||
|
||||
if(mem == nullptr)
|
||||
mem = PlatformMalloc(size);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void* InternalMalloc(size_t size, size_t alignment, const char* name, int flags, unsigned debugFlags, const char* file, int line)
|
||||
{
|
||||
void* mem = nullptr;
|
||||
|
||||
auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator();
|
||||
|
||||
#ifdef EA_DEBUG
|
||||
mem = allocator.MallocAlignedDebug(size, alignment, 0, flags, debugFlags, name, file, line);
|
||||
#else
|
||||
mem = allocator.MallocAligned(size, alignment, flags);
|
||||
EA_UNUSED(debugFlags);
|
||||
EA_UNUSED(file);
|
||||
EA_UNUSED(line);
|
||||
EA_UNUSED(name);
|
||||
#endif
|
||||
|
||||
if(mem == nullptr)
|
||||
mem = PlatformMalloc(size, alignment);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void* InternalMalloc(size_t size, size_t alignment)
|
||||
{
|
||||
void* mem = nullptr;
|
||||
|
||||
auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator();
|
||||
|
||||
#ifdef EA_DEBUG
|
||||
mem = allocator.MallocAlignedDebug(size, alignment, 0, 0, 0, gUnattributedNewTag, UNATTRIBUTED_NEW_FILE, UNATTRIBUTED_NEW_LINE);
|
||||
#else
|
||||
mem = allocator.MallocAligned(size, alignment);
|
||||
#endif
|
||||
|
||||
if(mem == nullptr)
|
||||
mem = PlatformMalloc(size, alignment);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void InternalFree(void* p)
|
||||
{
|
||||
auto& allocator = EA::Allocator::EASTLTest_GetGeneralAllocator();
|
||||
|
||||
if(allocator.ValidateAddress(p, EA::Allocator::GeneralAllocator::kAddressTypeOwned) == p)
|
||||
{
|
||||
allocator.Free(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlatformFree(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EASTLTestICA : public EA::Allocator::ICoreAllocator
|
||||
{
|
||||
public:
|
||||
EASTLTestICA()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~EASTLTestICA()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void* Alloc(size_t size, const char* name, unsigned int flags)
|
||||
{
|
||||
return ::InternalMalloc(size, name, (int)flags, 0, NULL, 0);
|
||||
}
|
||||
|
||||
virtual void* Alloc(size_t size, const char* name, unsigned int flags,
|
||||
unsigned int align, unsigned int)
|
||||
{
|
||||
return ::InternalMalloc(size, (size_t)align, name, (int)flags, 0, NULL, 0);
|
||||
}
|
||||
|
||||
virtual void Free(void* pData, size_t /*size*/)
|
||||
{
|
||||
return ::InternalFree(pData);
|
||||
}
|
||||
};
|
||||
|
||||
EA::Allocator::ICoreAllocator* EA::Allocator::ICoreAllocator::GetDefaultAllocator()
|
||||
{
|
||||
static EASTLTestICA sEASTLTestICA;
|
||||
|
||||
return &sEASTLTestICA;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// operator new/delete implementations
|
||||
//
|
||||
_Ret_maybenull_ _Post_writable_byte_size_(size) void* operator new(size_t size, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE()
|
||||
{
|
||||
return InternalMalloc(size);
|
||||
}
|
||||
|
||||
|
||||
void operator delete(void* p, const std::nothrow_t&) EA_THROW_SPEC_DELETE_NONE()
|
||||
{
|
||||
if(p) // The standard specifies that 'delete NULL' is a valid operation.
|
||||
{
|
||||
gEASTLTest_AllocationCount--;
|
||||
InternalFree(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_Ret_maybenull_ _Post_writable_byte_size_(size) void* operator new[](size_t size, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE()
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
void* p = InternalMalloc(size);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void operator delete[](void* p, const std::nothrow_t&) EA_THROW_SPEC_DELETE_NONE()
|
||||
{
|
||||
if(p)
|
||||
{
|
||||
gEASTLTest_AllocationCount--;
|
||||
InternalFree(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_Ret_notnull_ _Post_writable_byte_size_(size) void* operator new(size_t size)
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
void* mem = InternalMalloc(size);
|
||||
|
||||
#if !defined(EA_COMPILER_NO_EXCEPTIONS)
|
||||
if (mem == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
#endif
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
_Ret_notnull_ _Post_writable_byte_size_(size) void* operator new[](size_t size)
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
void* mem = InternalMalloc(size);
|
||||
|
||||
#if !defined(EA_COMPILER_NO_EXCEPTIONS)
|
||||
if (mem == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
#endif
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
void* operator new[](size_t size, const char* name, int flags, unsigned debugFlags, const char* file, int line)
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
return InternalMalloc(size, name, flags, debugFlags, file, line);
|
||||
}
|
||||
|
||||
|
||||
void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char* name, int flags, unsigned debugFlags, const char* file, int line)
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
return InternalMalloc(size, alignment, name, flags, debugFlags, file, line);
|
||||
}
|
||||
|
||||
// Used by GCC when you make new objects of classes with >= N bit alignment (with N depending on the compiler).
|
||||
void* operator new(size_t size, size_t alignment)
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
return InternalMalloc(size, alignment);
|
||||
}
|
||||
|
||||
// Used by GCC when you make new objects of classes with >= N bit alignment (with N depending on the compiler).
|
||||
void* operator new(size_t size, size_t alignment, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE()
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
return InternalMalloc(size, alignment);
|
||||
}
|
||||
|
||||
// Used by GCC when you make new objects of classes with >= N bit alignment (with N depending on the compiler).
|
||||
void* operator new[](size_t size, size_t alignment)
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
return InternalMalloc(size, alignment);
|
||||
}
|
||||
|
||||
// Used by GCC when you make new objects of classes with >= N bit alignment (with N depending on the compiler).
|
||||
void* operator new[](size_t size, size_t alignment, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE()
|
||||
{
|
||||
gEASTLTest_AllocationCount++;
|
||||
gEASTLTest_TotalAllocationCount++;
|
||||
|
||||
return InternalMalloc(size, alignment);
|
||||
}
|
||||
|
||||
void operator delete(void* p) EA_THROW_SPEC_DELETE_NONE()
|
||||
{
|
||||
if(p) // The standard specifies that 'delete NULL' is a valid operation.
|
||||
{
|
||||
gEASTLTest_AllocationCount--;
|
||||
InternalFree(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void operator delete[](void* p) EA_THROW_SPEC_DELETE_NONE()
|
||||
{
|
||||
if(p)
|
||||
{
|
||||
gEASTLTest_AllocationCount--;
|
||||
InternalFree(p);
|
||||
}
|
||||
}
|
||||
|
||||
void EASTLTest_SetGeneralAllocator()
|
||||
{
|
||||
EA::Allocator::SetGeneralAllocator(&EA::Allocator::EASTLTest_GetGeneralAllocator());
|
||||
#ifdef EA_DEBUG
|
||||
EA::Allocator::gpEAGeneralAllocatorDebug->SetDefaultDebugDataFlag(EA::Allocator::GeneralAllocatorDebug::kDebugDataIdGuard);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
#if !defined(EA_PLATFORM_MICROSOFT) || defined(EA_PLATFORM_MINGW)
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
void* EASTLAlignedAlloc(size_t size, size_t alignment)
|
||||
{
|
||||
#ifdef EA_PLATFORM_MICROSOFT
|
||||
return _aligned_malloc(size, alignment);
|
||||
#else
|
||||
void *p = nullptr;
|
||||
alignment = alignment < sizeof( void *) ? sizeof( void *) : alignment;
|
||||
posix_memalign(&p, alignment, size);
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
void EASTLAlignedFree(void* p)
|
||||
{
|
||||
#ifdef EA_PLATFORM_MICROSOFT
|
||||
_aligned_free(p);
|
||||
#else
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void* operator new(size_t size)
|
||||
{ return Internal::EASTLAlignedAlloc(size, 16); }
|
||||
|
||||
void* operator new[](size_t size)
|
||||
{ return Internal::EASTLAlignedAlloc(size, 16); }
|
||||
|
||||
void* operator new[](size_t size, const char* /*name*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{ return Internal::EASTLAlignedAlloc(size, 16); }
|
||||
|
||||
void* operator new[](size_t size, size_t alignment, size_t /*alignmentOffset*/, const char* /*name*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{ return Internal::EASTLAlignedAlloc(size, alignment); }
|
||||
|
||||
void* operator new(size_t size, size_t alignment)
|
||||
{ return Internal::EASTLAlignedAlloc(size, alignment); }
|
||||
|
||||
void* operator new(size_t size, size_t alignment, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE()
|
||||
{ return Internal::EASTLAlignedAlloc(size, alignment); }
|
||||
|
||||
void* operator new[](size_t size, size_t alignment)
|
||||
{ return Internal::EASTLAlignedAlloc(size, alignment); }
|
||||
|
||||
void* operator new[](size_t size, size_t alignment, const std::nothrow_t&)EA_THROW_SPEC_NEW_NONE()
|
||||
{ return Internal::EASTLAlignedAlloc(size, alignment); }
|
||||
|
||||
// C++14 deleter
|
||||
void operator delete(void* p, std::size_t sz ) EA_THROW_SPEC_DELETE_NONE()
|
||||
{ Internal::EASTLAlignedFree(p); EA_UNUSED(sz); }
|
||||
|
||||
void operator delete[](void* p, std::size_t sz ) EA_THROW_SPEC_DELETE_NONE()
|
||||
{ Internal::EASTLAlignedFree(p); EA_UNUSED(sz); }
|
||||
|
||||
void operator delete(void* p) EA_THROW_SPEC_DELETE_NONE()
|
||||
{ Internal::EASTLAlignedFree(p); }
|
||||
|
||||
void operator delete[](void* p) EA_THROW_SPEC_DELETE_NONE()
|
||||
{ Internal::EASTLAlignedFree(p); }
|
||||
|
||||
void EASTLTest_SetGeneralAllocator() { /* intentionally blank */ }
|
||||
bool EASTLTest_ValidateHeap() { return true; }
|
||||
|
||||
#endif // !EASTL_OPENSOURCE
|
||||
|
||||
#endif // Header include guard
|
||||
@@ -0,0 +1,26 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef EASTLTEST_ALLOCATOR_H
|
||||
#define EASTLTEST_ALLOCATOR_H
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <new>
|
||||
|
||||
void* operator new(size_t size);
|
||||
void* operator new[](size_t size);
|
||||
void* operator new[](size_t size, const char* /*name*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/);
|
||||
void* operator new[](size_t size, size_t alignment, size_t /*alignmentOffset*/, const char* /*name*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/);
|
||||
void* operator new(size_t size, size_t alignment);
|
||||
void* operator new(size_t size, size_t alignment, const std::nothrow_t&) EA_THROW_SPEC_NEW_NONE();
|
||||
void* operator new[](size_t size, size_t alignment);
|
||||
void* operator new[](size_t size, size_t alignment, const std::nothrow_t&)EA_THROW_SPEC_NEW_NONE();
|
||||
void operator delete(void* p) EA_THROW_SPEC_DELETE_NONE();
|
||||
void operator delete[](void* p) EA_THROW_SPEC_DELETE_NONE();
|
||||
void EASTLTest_SetGeneralAllocator();
|
||||
bool EASTLTest_ValidateHeap();
|
||||
|
||||
|
||||
#endif // Header include guard
|
||||
@@ -0,0 +1,119 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef GETTYPENAME_H
|
||||
#define GETTYPENAME_H
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/type_traits.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <stdlib.h>
|
||||
#include <typeinfo>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EASTL_LIBSTDCPP_DEMANGLE_AVAILABLE
|
||||
//
|
||||
// Defined as 0 or 1. The value depends on the compilation environment.
|
||||
// Indicates if we can use system-provided abi::__cxa_demangle() at runtime.
|
||||
//
|
||||
#if !defined(EASTL_LIBSTDCPP_DEMANGLE_AVAILABLE)
|
||||
#if (defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_APPLE)) && defined(EA_PLATFORM_DESKTOP)
|
||||
#define EASTL_LIBSTDCPP_DEMANGLE_AVAILABLE 1
|
||||
#else
|
||||
#define EASTL_LIBSTDCPP_DEMANGLE_AVAILABLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if EASTL_LIBSTDCPP_DEMANGLE_AVAILABLE
|
||||
#include <cxxabi.h>
|
||||
#elif EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
|
||||
EA_DISABLE_ALL_VC_WARNINGS();
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
EA_RESTORE_ALL_VC_WARNINGS();
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EASTLTEST_GETTYPENAME_AVAILABLE
|
||||
//
|
||||
// Defined as 0 or 1. The value depends on the compilation environment.
|
||||
// Indicates if we can use system-provided abi::__cxa_demangle() at runtime.
|
||||
//
|
||||
#if !defined(EASTLTEST_GETTYPENAME_AVAILABLE)
|
||||
#if (EASTL_LIBSTDCPP_DEMANGLE_AVAILABLE || EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)) && (!defined(EA_COMPILER_NO_RTTI) || defined(_MSC_VER)) // VC++ works without RTTI enabled.
|
||||
#define EASTLTEST_GETTYPENAME_AVAILABLE 1
|
||||
#else
|
||||
#define EASTLTEST_GETTYPENAME_AVAILABLE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/// GetTypeName
|
||||
///
|
||||
/// Returns the type name of a templated type.
|
||||
///
|
||||
template <typename T>
|
||||
eastl::string GetTypeName()
|
||||
{
|
||||
eastl::string result;
|
||||
|
||||
#if !defined(EA_COMPILER_NO_RTTI) || defined(_MSC_VER) // VC++ works without RTTI enabled.
|
||||
typedef typename eastl::remove_reference<T>::type TR;
|
||||
|
||||
const char* pName = typeid(TR).name();
|
||||
|
||||
#if EASTL_LIBSTDCPP_DEMANGLE_AVAILABLE
|
||||
const char* pDemangledName = abi::__cxa_demangle(pName, NULL, NULL, NULL);
|
||||
|
||||
#elif EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
|
||||
char pDemangledName[1024];
|
||||
DWORD count = UnDecorateSymbolName(pName, pDemangledName, (DWORD)EAArrayCount(pDemangledName), UNDNAME_NO_THISTYPE | UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_MEMBER_TYPE);
|
||||
if(count == 0)
|
||||
pDemangledName[0] = 0;
|
||||
#else
|
||||
const char* pDemangledName = NULL;
|
||||
#endif
|
||||
|
||||
if(pDemangledName && pDemangledName[0])
|
||||
result = pDemangledName;
|
||||
else
|
||||
result = pName;
|
||||
|
||||
if(eastl::is_const<TR>::value)
|
||||
result += " const";
|
||||
|
||||
if(eastl::is_volatile<TR>::value)
|
||||
result += " volatile";
|
||||
|
||||
if(eastl::is_lvalue_reference<T>::value)
|
||||
result += "&";
|
||||
else if(eastl::is_rvalue_reference<T>::value)
|
||||
result += "&&";
|
||||
|
||||
if(pDemangledName)
|
||||
{
|
||||
#if EASTL_LIBSTDCPP_DEMANGLE_AVAILABLE
|
||||
free((void*)(pDemangledName));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif // Header include guard
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,405 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/allocator.h>
|
||||
#include <EASTL/allocator_malloc.h>
|
||||
#include <EASTL/fixed_allocator.h>
|
||||
#include <EASTL/core_allocator_adapter.h>
|
||||
#include <EASTL/list.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
#include <EAStdC/EAAlignment.h>
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedAllocator
|
||||
//
|
||||
EA_DISABLE_VC_WARNING(6262)
|
||||
static int TestFixedAllocator()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{ // fixed_allocator
|
||||
typedef eastl::list<int, fixed_allocator> IntList;
|
||||
typedef IntList::node_type IntListNode;
|
||||
|
||||
const size_t kBufferCount = 200;
|
||||
IntListNode buffer1[kBufferCount];
|
||||
IntList intList1;
|
||||
const size_t kAlignOfIntListNode = EA_ALIGN_OF(IntListNode);
|
||||
|
||||
intList1.get_allocator().init(buffer1, sizeof(buffer1), sizeof(IntListNode), kAlignOfIntListNode);
|
||||
|
||||
for(size_t i = 0; i < kBufferCount; i++)
|
||||
intList1.push_back(0);
|
||||
|
||||
EATEST_VERIFY(intList1.size() == kBufferCount);
|
||||
|
||||
// Try making a copy.
|
||||
IntListNode buffer2[kBufferCount];
|
||||
IntList intList2;
|
||||
intList2.get_allocator().init(buffer2, sizeof(buffer2), sizeof(IntListNode), kAlignOfIntListNode);
|
||||
intList2 = intList1;
|
||||
EATEST_VERIFY(intList2.size() == kBufferCount);
|
||||
}
|
||||
|
||||
// fixed_allocator_with_overflow, ensure allocations are coming from fixed buffer. This is to
|
||||
// prevent a reported user regression where all allocations were being routed to the overflow
|
||||
// allocator.
|
||||
{
|
||||
const int DEFAULT_VALUE = 0xbaadf00d;
|
||||
const int TEST_VALUE = 0x12345689;
|
||||
const size_t kBufferCount = 10;
|
||||
|
||||
typedef eastl::list<int, fixed_allocator_with_overflow> IntList;
|
||||
typedef IntList::node_type IntListNode;
|
||||
|
||||
const size_t kAlignOfIntListNode = EA_ALIGN_OF(IntListNode);
|
||||
|
||||
// ensure the fixed buffer contains the default value that will be replaced
|
||||
IntListNode buffer1[kBufferCount];
|
||||
for (int i = 0; i < kBufferCount; i++)
|
||||
{
|
||||
buffer1[i].mValue = DEFAULT_VALUE;
|
||||
EATEST_VERIFY(buffer1[i].mValue == DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
IntList intList1;
|
||||
|
||||
// replace all the values in the local buffer with the test value
|
||||
intList1.get_allocator().init(buffer1, sizeof(buffer1), sizeof(IntListNode), kAlignOfIntListNode);
|
||||
for (size_t i = 0; i < kBufferCount; i++)
|
||||
intList1.push_back(TEST_VALUE);
|
||||
|
||||
// ensure the local buffer has been altered with the contents of the list::push_back
|
||||
for (int i = 0; i < kBufferCount; i++)
|
||||
{
|
||||
EATEST_VERIFY(buffer1[i].mValue == TEST_VALUE);
|
||||
}
|
||||
|
||||
intList1.clear();
|
||||
}
|
||||
|
||||
{ // fixed_allocator_with_overflow
|
||||
typedef eastl::list<int, fixed_allocator_with_overflow> IntList;
|
||||
typedef IntList::node_type IntListNode;
|
||||
|
||||
const size_t kBufferCount = 200;
|
||||
IntListNode buffer1[kBufferCount];
|
||||
IntList intList1;
|
||||
const size_t kAlignOfIntListNode = EA_ALIGN_OF(IntListNode);
|
||||
|
||||
intList1.get_allocator().init(buffer1, sizeof(buffer1), sizeof(IntListNode), kAlignOfIntListNode);
|
||||
|
||||
for(size_t i = 0; i < kBufferCount * 2; i++)
|
||||
intList1.push_back(0);
|
||||
|
||||
EATEST_VERIFY(intList1.size() == (kBufferCount * 2));
|
||||
|
||||
// Try making a copy.
|
||||
IntListNode buffer2[kBufferCount];
|
||||
IntList intList2;
|
||||
intList2.get_allocator().init(buffer2, sizeof(buffer2), sizeof(IntListNode), kAlignOfIntListNode);
|
||||
intList2 = intList1;
|
||||
EATEST_VERIFY(intList2.size() == (kBufferCount * 2));
|
||||
}
|
||||
|
||||
{
|
||||
// fixed_pool_reference
|
||||
typedef eastl::list<int, fixed_pool_reference> WidgetList;
|
||||
|
||||
WidgetList::node_type buffer[16];
|
||||
eastl::fixed_pool myPool(buffer, sizeof(buffer), sizeof(WidgetList::node_type), 16);
|
||||
|
||||
WidgetList myList1(myPool);
|
||||
WidgetList myList2(myPool);
|
||||
|
||||
myList1.push_back(1);
|
||||
myList2.push_back(1);
|
||||
EATEST_VERIFY(myList1 == myList2);
|
||||
|
||||
myList1.push_back(2);
|
||||
myList1.sort();
|
||||
myList2.push_front(2);
|
||||
myList2.sort();
|
||||
EATEST_VERIFY(myList1 == myList2);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestAllocatorMalloc
|
||||
//
|
||||
static int TestAllocatorMalloc()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
typedef eastl::list<int, eastl::allocator_malloc> WidgetList;
|
||||
|
||||
WidgetList myList1;
|
||||
WidgetList myList2;
|
||||
|
||||
myList1.push_back(1);
|
||||
myList2.push_back(1);
|
||||
EATEST_VERIFY(myList1 == myList2);
|
||||
|
||||
myList1.push_back(2);
|
||||
myList1.sort();
|
||||
myList2.push_front(2);
|
||||
myList2.sort();
|
||||
EATEST_VERIFY(myList1 == myList2);
|
||||
|
||||
#if EASTL_ALIGNED_MALLOC_AVAILABLE
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if EASTL_DLL
|
||||
void* operator new[](size_t size, const char* pName, int flags, unsigned debugFlags, const char* file, int line);
|
||||
void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char* pName, int flags, unsigned debugFlags, const char* file, int line);
|
||||
#endif
|
||||
|
||||
|
||||
struct EASTLTestCoreAllocator
|
||||
{
|
||||
public:
|
||||
void* Alloc(size_t size, const char* name, unsigned int flags)
|
||||
{
|
||||
return ::operator new[](size, name, flags, 0, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void* Alloc(size_t size, const char* name, unsigned int flags,
|
||||
unsigned int alignment, unsigned int alignOffset = 0)
|
||||
{
|
||||
return ::operator new[](size, alignment, alignOffset, name, flags, 0, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void Free(void* p, size_t /*size*/ = 0)
|
||||
{
|
||||
::operator delete((char*)p);
|
||||
}
|
||||
|
||||
static EASTLTestCoreAllocator* GetDefaultAllocator();
|
||||
};
|
||||
|
||||
EASTLTestCoreAllocator gEASTLTestCoreAllocator;
|
||||
|
||||
EASTLTestCoreAllocator* EASTLTestCoreAllocator::GetDefaultAllocator()
|
||||
{
|
||||
return &gEASTLTestCoreAllocator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestCoreAllocatorAdapter
|
||||
//
|
||||
static int TestCoreAllocatorAdapter()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
#if EASTL_CORE_ALLOCATOR_ENABLED
|
||||
typedef EA::Allocator::CoreAllocatorAdapter<EASTLTestCoreAllocator> Adapter;
|
||||
|
||||
eastl::list<TestClass, Adapter> widgetList(Adapter("UI/WidgetList", &gEASTLTestCoreAllocator));
|
||||
widgetList.push_back(TestClass());
|
||||
EATEST_VERIFY(widgetList.size() == 1);
|
||||
|
||||
eastl::vector<TestClass, Adapter> widgetVector(100, Adapter("UI/WidgetVector", &gEASTLTestCoreAllocator));
|
||||
widgetVector.push_back(TestClass());
|
||||
EATEST_VERIFY(widgetVector.size() == 101);
|
||||
|
||||
eastl::vector<TestClass, Adapter> widgetVector2(widgetVector);
|
||||
widgetVector2.resize(400);
|
||||
EATEST_VERIFY(widgetVector2.size() == 400);
|
||||
#endif
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestSwapAllocator
|
||||
//
|
||||
static int TestSwapAllocator()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
InstanceAllocator a(nullptr, (uint8_t)111), b(nullptr, (uint8_t)222);
|
||||
eastl::swap(a, b);
|
||||
|
||||
EATEST_VERIFY(a.mInstanceId == 222);
|
||||
EATEST_VERIFY(b.mInstanceId == 111);
|
||||
|
||||
EATEST_VERIFY(EA::StdC::Strcmp(a.get_name(), "InstanceAllocator 222") == 0);
|
||||
EATEST_VERIFY(EA::StdC::Strcmp(b.get_name(), "InstanceAllocator 111") == 0);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
static int TestAllocationOffsetAndAlignment()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
auto testAllocatorAlignment = [&nErrorCount](int requestedSize, int requestedAlignment, int requestedOffset)
|
||||
{
|
||||
CountingAllocator::resetCount();
|
||||
CountingAllocator a;
|
||||
|
||||
void* p = allocate_memory(a, requestedSize, requestedAlignment, requestedOffset);
|
||||
|
||||
EATEST_VERIFY(p != nullptr);
|
||||
EATEST_VERIFY(EA::StdC::IsAligned(p, requestedAlignment));
|
||||
|
||||
a.deallocate(p, requestedSize);
|
||||
EATEST_VERIFY(CountingAllocator::getActiveAllocationSize() == 0);
|
||||
};
|
||||
|
||||
testAllocatorAlignment(100, 1, 0);
|
||||
testAllocatorAlignment(100, 2, 0);
|
||||
testAllocatorAlignment(100, 4, 0);
|
||||
testAllocatorAlignment(100, 8, 0);
|
||||
testAllocatorAlignment(100, 16, 0);
|
||||
|
||||
testAllocatorAlignment(100, 1, 16);
|
||||
testAllocatorAlignment(100, 2, 16);
|
||||
testAllocatorAlignment(100, 4, 16);
|
||||
testAllocatorAlignment(100, 8, 16);
|
||||
testAllocatorAlignment(100, 16, 16);
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestAllocator
|
||||
//
|
||||
int TestAllocator()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
nErrorCount += TestAllocationOffsetAndAlignment();
|
||||
nErrorCount += TestFixedAllocator();
|
||||
nErrorCount += TestAllocatorMalloc();
|
||||
nErrorCount += TestCoreAllocatorAdapter();
|
||||
nErrorCount += TestSwapAllocator();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,472 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/any.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/numeric.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
|
||||
|
||||
// SmallTestObject
|
||||
//
|
||||
struct SmallTestObject
|
||||
{
|
||||
static int mCtorCount;
|
||||
|
||||
SmallTestObject() EA_NOEXCEPT { mCtorCount++; }
|
||||
SmallTestObject(const SmallTestObject&) EA_NOEXCEPT { mCtorCount++; }
|
||||
SmallTestObject(SmallTestObject&&) EA_NOEXCEPT { mCtorCount++; }
|
||||
SmallTestObject& operator=(const SmallTestObject&) EA_NOEXCEPT { mCtorCount++; return *this; }
|
||||
~SmallTestObject() EA_NOEXCEPT { mCtorCount--; }
|
||||
|
||||
static void Reset() { mCtorCount = 0; }
|
||||
static bool IsClear() { return mCtorCount == 0; }
|
||||
};
|
||||
|
||||
int SmallTestObject::mCtorCount = 0;
|
||||
|
||||
|
||||
// RequiresInitList
|
||||
//
|
||||
struct RequiresInitList
|
||||
{
|
||||
RequiresInitList(std::initializer_list<int> ilist)
|
||||
: sum(eastl::accumulate(begin(ilist), end(ilist), 0)) {}
|
||||
|
||||
int sum;
|
||||
};
|
||||
|
||||
|
||||
int TestAny()
|
||||
{
|
||||
using namespace eastl;
|
||||
int nErrorCount = 0;
|
||||
|
||||
// NOTE(rparolin): Ensure 'any' is at least the size of an eastl::string and an eastl::vector to prevent heap
|
||||
// allocation of handle objects (objects that point to a heap allocation). This will reduce memory pressure since
|
||||
// eastl::string will be a commonly used type. We could also test with a vector.
|
||||
{
|
||||
static_assert(sizeof(eastl::string) <= sizeof(eastl::any), "ensure that 'any' has enough local memory to store a string");
|
||||
static_assert(sizeof(eastl::vector<int>) <= sizeof(eastl::any), "ensure that 'any' has enough local memory to store a vector");
|
||||
}
|
||||
|
||||
{
|
||||
// default construct
|
||||
any a;
|
||||
VERIFY(a.has_value() == false);
|
||||
}
|
||||
|
||||
{
|
||||
// test object ctors & dtors are called for a large object
|
||||
TestObject::Reset();
|
||||
{ any a{TestObject()}; }
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
{
|
||||
// test object ctors & dtors are called for a small object
|
||||
SmallTestObject::Reset();
|
||||
{ any a{SmallTestObject()}; }
|
||||
VERIFY(SmallTestObject::IsClear());
|
||||
}
|
||||
|
||||
{
|
||||
any a(42);
|
||||
VERIFY(a.has_value() == true);
|
||||
|
||||
VERIFY(any_cast<int>(a) == 42);
|
||||
VERIFY(any_cast<int>(a) != 1337);
|
||||
any_cast<int&>(a) = 10;
|
||||
VERIFY(any_cast<int>(a) == 10);
|
||||
|
||||
a = 1.f;
|
||||
any_cast<float&>(a) = 1337.f;
|
||||
VERIFY(any_cast<float>(a) == 1337.f);
|
||||
|
||||
a = 4343;
|
||||
VERIFY(any_cast<int>(a) == 4343);
|
||||
|
||||
a = string("hello world");
|
||||
VERIFY(any_cast<string>(a) == "hello world");
|
||||
VERIFY(any_cast<string&>(a) == "hello world");
|
||||
}
|
||||
|
||||
{
|
||||
struct custom_type { int data; };
|
||||
|
||||
any a = custom_type{};
|
||||
any_cast<custom_type&>(a).data = 42;
|
||||
VERIFY(any_cast<custom_type>(a).data == 42);
|
||||
}
|
||||
|
||||
{
|
||||
any a = 42;
|
||||
VERIFY(any_cast<int>(a) == 42);
|
||||
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
int throwCount = 0;
|
||||
try { VERIFY(any_cast<short>(a) == 42); }
|
||||
catch (bad_any_cast) { throwCount++; }
|
||||
VERIFY(throwCount != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
vector<any> va = {42, 'a', 42.f, 3333u, 4444ul, 5555ull, 6666.0};
|
||||
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<char>(va[1]) == 'a');
|
||||
VERIFY(any_cast<float>(va[2]) == 42.f);
|
||||
VERIFY(any_cast<unsigned>(va[3]) == 3333u);
|
||||
VERIFY(any_cast<unsigned long>(va[4]) == 4444ul);
|
||||
VERIFY(any_cast<unsigned long long>(va[5]) == 5555ull);
|
||||
VERIFY(any_cast<double>(va[6]) == 6666.0);
|
||||
}
|
||||
|
||||
{
|
||||
any a(string("test string"));
|
||||
VERIFY(a.has_value());
|
||||
VERIFY(any_cast<string>(a) == "test string");
|
||||
}
|
||||
|
||||
{
|
||||
vector<any> va = {42, string("rob"), 'a', 42.f};
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<string>(va[1]) == "rob");
|
||||
VERIFY(any_cast<char>(va[2]) == 'a');
|
||||
VERIFY(any_cast<float>(va[3]) == 42.f);
|
||||
}
|
||||
|
||||
{
|
||||
vector<any> va;
|
||||
va.push_back(42);
|
||||
va.push_back(string("rob"));
|
||||
va.push_back('a');
|
||||
va.push_back(42.f);
|
||||
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<string>(va[1]) == "rob");
|
||||
VERIFY(any_cast<char>(va[2]) == 'a');
|
||||
VERIFY(any_cast<float>(va[3]) == 42.f);
|
||||
}
|
||||
|
||||
// NOTE(rparolin): Replaces a small 'any' object with a large one and make sure it doesn't corrupt
|
||||
// the surrounding memory in the vector.
|
||||
{
|
||||
TestObject::Reset();
|
||||
{
|
||||
vector<any> va = {42, 'a', 42.f, 3333u, 4444ul, 5555ull, 6666.0};
|
||||
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<char>(va[1]) == 'a');
|
||||
VERIFY(any_cast<float>(va[2]) == 42.f);
|
||||
VERIFY(any_cast<unsigned>(va[3]) == 3333u);
|
||||
VERIFY(any_cast<unsigned long>(va[4]) == 4444ul);
|
||||
VERIFY(any_cast<unsigned long long>(va[5]) == 5555ull);
|
||||
VERIFY(any_cast<double>(va[6]) == 6666.0);
|
||||
|
||||
va[3] = TestObject(3333); // replace a small integral with a large heap allocated object.
|
||||
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<char>(va[1]) == 'a');
|
||||
VERIFY(any_cast<float>(va[2]) == 42.f);
|
||||
VERIFY(any_cast<TestObject>(va[3]).mX == 3333); // not 3333u because TestObject ctor takes a signed type.
|
||||
VERIFY(any_cast<unsigned long>(va[4]) == 4444ul);
|
||||
VERIFY(any_cast<unsigned long long>(va[5]) == 5555ull);
|
||||
VERIFY(any_cast<double>(va[6]) == 6666.0);
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
{
|
||||
any a(string("test string"));
|
||||
VERIFY(a.has_value());
|
||||
a.reset();
|
||||
VERIFY(!a.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
any a1 = 42;
|
||||
any a2 = a1;
|
||||
|
||||
VERIFY(a1.has_value());
|
||||
VERIFY(a2.has_value());
|
||||
VERIFY(any_cast<int>(a1) == any_cast<int>(a2));
|
||||
}
|
||||
|
||||
{
|
||||
any a1;
|
||||
VERIFY(!a1.has_value());
|
||||
{
|
||||
any a2(string("test string"));
|
||||
a1 = any_cast<string>(a2);
|
||||
|
||||
VERIFY(a1.has_value());
|
||||
}
|
||||
VERIFY(any_cast<string>(a1) == "test string");
|
||||
VERIFY(a1.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
any a1;
|
||||
VERIFY(!a1.has_value());
|
||||
{
|
||||
any a2(string("test string"));
|
||||
a1 = a2;
|
||||
VERIFY(a1.has_value());
|
||||
}
|
||||
VERIFY(any_cast<string&>(a1) == "test string");
|
||||
VERIFY(a1.has_value());
|
||||
}
|
||||
|
||||
// swap tests
|
||||
{
|
||||
{
|
||||
any a1 = 42;
|
||||
any a2 = 24;
|
||||
VERIFY(any_cast<int>(a1) == 42);
|
||||
VERIFY(any_cast<int>(a2) == 24);
|
||||
|
||||
a1.swap(a2);
|
||||
VERIFY(any_cast<int>(a1) == 24);
|
||||
VERIFY(any_cast<int>(a2) == 42);
|
||||
|
||||
eastl::swap(a1, a2);
|
||||
VERIFY(any_cast<int>(a1) == 42);
|
||||
VERIFY(any_cast<int>(a2) == 24);
|
||||
}
|
||||
{
|
||||
any a1 = string("hello");
|
||||
any a2 = string("world");
|
||||
VERIFY(any_cast<string>(a1) == "hello");
|
||||
VERIFY(any_cast<string>(a2) == "world");
|
||||
|
||||
a1.swap(a2);
|
||||
VERIFY(any_cast<string>(a1) == "world");
|
||||
VERIFY(any_cast<string>(a2) == "hello");
|
||||
|
||||
eastl::swap(a1, a2);
|
||||
VERIFY(any_cast<string>(a1) == "hello");
|
||||
VERIFY(any_cast<string>(a2) == "world");
|
||||
}
|
||||
}
|
||||
|
||||
#if EASTL_RTTI_ENABLED
|
||||
{
|
||||
#if defined(EA_COMPILER_MSVC)
|
||||
VERIFY(EA::StdC::Strcmp(any(42).type().name(), "int") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42.f).type().name(), "float") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42u).type().name(), "unsigned int") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42ul).type().name(), "unsigned long") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42l).type().name(), "long") == 0);
|
||||
|
||||
#elif defined(EA_COMPILER_CLANG) || defined(EA_COMPILER_GNUC)
|
||||
VERIFY(EA::StdC::Strcmp(any(42).type().name(), "i") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42.f).type().name(), "f") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42u).type().name(), "j") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42ul).type().name(), "m") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42l).type().name(), "l") == 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// emplace, small object tests
|
||||
{
|
||||
any a;
|
||||
|
||||
a.emplace<int>(42);
|
||||
VERIFY(a.has_value());
|
||||
VERIFY(any_cast<int>(a) == 42);
|
||||
|
||||
a.emplace<short>((short)8); // no way to define a short literal we must cast here.
|
||||
VERIFY(any_cast<short>(a) == 8);
|
||||
VERIFY(a.has_value());
|
||||
|
||||
a.reset();
|
||||
VERIFY(!a.has_value());
|
||||
}
|
||||
|
||||
// emplace, large object tests
|
||||
{
|
||||
TestObject::Reset();
|
||||
{
|
||||
any a;
|
||||
a.emplace<TestObject>();
|
||||
VERIFY(a.has_value());
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
// emplace, initializer_list
|
||||
{
|
||||
{
|
||||
any a;
|
||||
a.emplace<RequiresInitList>(std::initializer_list<int>{1,2,3,4,5,6});
|
||||
|
||||
VERIFY(a.has_value());
|
||||
VERIFY(any_cast<RequiresInitList>(a).sum == 21);
|
||||
}
|
||||
}
|
||||
|
||||
// equivalence tests
|
||||
{
|
||||
any a, b;
|
||||
VERIFY(!a.has_value() == !b.has_value());
|
||||
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
int bad_any_cast_thrown = 0;
|
||||
try
|
||||
{
|
||||
VERIFY(any_cast<int>(a) == any_cast<int>(b));
|
||||
}
|
||||
catch (eastl::bad_any_cast)
|
||||
{
|
||||
bad_any_cast_thrown++;
|
||||
}
|
||||
VERIFY(bad_any_cast_thrown != 0);
|
||||
#endif
|
||||
|
||||
|
||||
a = 42; b = 24;
|
||||
VERIFY(any_cast<int>(a) != any_cast<int>(b));
|
||||
VERIFY(a.has_value() == b.has_value());
|
||||
|
||||
a = 42; b = 42;
|
||||
VERIFY(any_cast<int>(a) == any_cast<int>(b));
|
||||
VERIFY(a.has_value() == b.has_value());
|
||||
}
|
||||
|
||||
// move tests
|
||||
{
|
||||
any a = string("hello world");
|
||||
VERIFY(any_cast<string&>(a) == "hello world");
|
||||
|
||||
auto s = move(any_cast<string&>(a)); // move string out
|
||||
VERIFY(s == "hello world");
|
||||
VERIFY(any_cast<string&>(a).empty());
|
||||
|
||||
any_cast<string&>(a) = move(s); // move string in
|
||||
VERIFY(any_cast<string&>(a) == "hello world");
|
||||
}
|
||||
|
||||
// nullptr tests
|
||||
{
|
||||
any* a = nullptr;
|
||||
VERIFY(any_cast<int>(a) == nullptr);
|
||||
VERIFY(any_cast<short>(a) == nullptr);
|
||||
VERIFY(any_cast<long>(a) == nullptr);
|
||||
VERIFY(any_cast<string>(a) == nullptr);
|
||||
|
||||
any b;
|
||||
VERIFY(any_cast<short>(&b) == nullptr);
|
||||
VERIFY(any_cast<const short>(&b) == nullptr);
|
||||
VERIFY(any_cast<volatile short>(&b) == nullptr);
|
||||
VERIFY(any_cast<const volatile short>(&b) == nullptr);
|
||||
|
||||
VERIFY(any_cast<short*>(&b) == nullptr);
|
||||
VERIFY(any_cast<const short*>(&b) == nullptr);
|
||||
VERIFY(any_cast<volatile short*>(&b) == nullptr);
|
||||
VERIFY(any_cast<const volatile short*>(&b) == nullptr);
|
||||
}
|
||||
|
||||
// Aligned type tests
|
||||
{
|
||||
{
|
||||
any a = Align16(1337);
|
||||
VERIFY(any_cast<Align16>(a) == Align16(1337));
|
||||
}
|
||||
|
||||
{
|
||||
any a = Align32(1337);
|
||||
VERIFY(any_cast<Align32>(a) == Align32(1337));
|
||||
}
|
||||
|
||||
{
|
||||
any a = Align64(1337);
|
||||
VERIFY(any_cast<Align64>(a) == Align64(1337));
|
||||
}
|
||||
}
|
||||
|
||||
// make_any
|
||||
{
|
||||
{
|
||||
auto a = make_any<int>(42);
|
||||
VERIFY(any_cast<int>(a) == 42);
|
||||
}
|
||||
|
||||
{
|
||||
auto a = make_any<RequiresInitList>(std::initializer_list<int>{1,2,3,4,5,6,7,8});
|
||||
VERIFY(any_cast<RequiresInitList&>(a).sum == 36);
|
||||
}
|
||||
}
|
||||
|
||||
// user reported regression that eastl::any constructor was not decaying the deduced type correctly.
|
||||
{
|
||||
float f = 42.f;
|
||||
eastl::any a(f);
|
||||
VERIFY(any_cast<float>(a) == 42.f);
|
||||
}
|
||||
|
||||
//testing unsafe operations
|
||||
{
|
||||
eastl::any a = 1;
|
||||
int* i = eastl::any_cast<int>(&a);
|
||||
VERIFY((*i) == 1);
|
||||
|
||||
a = 2;
|
||||
int *j = (int*)eastl::unsafe_any_cast<void>(&a);
|
||||
VERIFY((*j) == 2);
|
||||
|
||||
const eastl::any b = 3;
|
||||
const void * p = eastl::unsafe_any_cast<void>(&b);
|
||||
void *q = const_cast<void *>(p);
|
||||
int *r = static_cast<int *>(q);
|
||||
VERIFY((*r) == 3);
|
||||
}
|
||||
|
||||
// user regression when calling the assignment operator
|
||||
{
|
||||
{
|
||||
eastl::any a1;
|
||||
eastl::any a2;
|
||||
VERIFY(a1.has_value() == false);
|
||||
VERIFY(a2.has_value() == false);
|
||||
|
||||
a1 = a2;
|
||||
VERIFY(a1.has_value() == false);
|
||||
VERIFY(a2.has_value() == false);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::any a1 = 42;
|
||||
eastl::any a2;
|
||||
VERIFY(a1.has_value() == true);
|
||||
VERIFY(a2.has_value() == false);
|
||||
|
||||
a1 = a2;
|
||||
VERIFY(a1.has_value() == false);
|
||||
VERIFY(a2.has_value() == false);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::any a1;
|
||||
eastl::any a2 = 42;
|
||||
VERIFY(a1.has_value() == false);
|
||||
VERIFY(a2.has_value() == true);
|
||||
|
||||
a1 = a2;
|
||||
VERIFY(a1.has_value() == true);
|
||||
VERIFY(a2.has_value() == true);
|
||||
VERIFY(any_cast<int>(a1) == 42);
|
||||
VERIFY(any_cast<int>(a2) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/array.h>
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template struct eastl::array<int>;
|
||||
template struct eastl::array<Align32>; // VC++ fails to compile due to error generated by the swap function. C2718: http://msdn.microsoft.com/en-us/library/vstudio/sxe76d9e.aspx
|
||||
|
||||
template<typename T> class TP;
|
||||
|
||||
|
||||
int TestArray()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
array<int, 5> a = { { 0, 1, 2, 3, 4 } };
|
||||
array<int, 5> b = { { 0, 1, 2, 3 } };
|
||||
array<int, 5> c = { { 4, 3, 2, 1, 0 } };
|
||||
array<int, 0> d = { { 0 } };
|
||||
|
||||
VERIFY(!a.empty());
|
||||
VERIFY(a.size() == 5);
|
||||
VERIFY(a[0] == 0);
|
||||
VERIFY(a[4] == 4);
|
||||
|
||||
VERIFY(!b.empty());
|
||||
VERIFY(b.size() == 5);
|
||||
VERIFY(b[0] == 0);
|
||||
VERIFY(b[3] == 3);
|
||||
|
||||
VERIFY(d.empty());
|
||||
VERIFY(d.size() == 0);
|
||||
|
||||
// swap
|
||||
a.swap(c);
|
||||
VERIFY(a[0] == 4);
|
||||
VERIFY(c[0] == 0);
|
||||
|
||||
// begin, end
|
||||
array<int, 5>::iterator it = a.begin();
|
||||
VERIFY((a.validate_iterator(it) & (isf_valid | isf_can_dereference)) != 0);
|
||||
VERIFY(*it == 4);
|
||||
|
||||
++it;
|
||||
VERIFY(*it == 3);
|
||||
|
||||
++it;
|
||||
VERIFY(*it == 2);
|
||||
|
||||
--it;
|
||||
VERIFY(*it == 3);
|
||||
|
||||
it += 3;
|
||||
VERIFY((a.validate_iterator(it) & (isf_valid | isf_can_dereference)) != 0);
|
||||
VERIFY(*it == 0);
|
||||
|
||||
++it;
|
||||
VERIFY(it == a.end());
|
||||
VERIFY((a.validate_iterator(it) & isf_valid) != 0);
|
||||
VERIFY(a.validate());
|
||||
|
||||
// rbegin, rend
|
||||
array<int, 5>::reverse_iterator itr = a.rbegin();
|
||||
VERIFY((a.validate_iterator(itr.base()) & (isf_valid | isf_can_dereference)) != 0);
|
||||
VERIFY(*itr == 0);
|
||||
|
||||
itr++;
|
||||
VERIFY(*itr == 1);
|
||||
|
||||
// data
|
||||
int* pArray = a.data();
|
||||
VERIFY(pArray == a.mValue);
|
||||
|
||||
// front
|
||||
int& nFront = a.front();
|
||||
VERIFY(nFront == 4);
|
||||
|
||||
// back
|
||||
int& nBack = a.back();
|
||||
VERIFY(nBack == 0);
|
||||
|
||||
// at
|
||||
VERIFY(a[0] == a.at(0));
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
bool bExceptionOccurred = false;
|
||||
try{
|
||||
int x = a.at(100);
|
||||
VERIFY(x != -1);
|
||||
}
|
||||
catch(...){
|
||||
bExceptionOccurred = true;
|
||||
}
|
||||
VERIFY(bExceptionOccurred);
|
||||
#endif
|
||||
|
||||
// global operators
|
||||
a[0] = 0; a[1] = 1; a[2] = 2; a[3] = 3; a[4] = 4; // 01234
|
||||
b[0] = 0; b[1] = 1; b[2] = 2; b[3] = 3; b[4] = 4; // 01234
|
||||
c[0] = 0; c[1] = 1; c[2] = 2; c[3] = 3; c[4] = 9; // 01239
|
||||
|
||||
VERIFY( (a == b));
|
||||
VERIFY(!(a != b));
|
||||
VERIFY(!(a < b));
|
||||
VERIFY( (a <= b));
|
||||
VERIFY( (a >= b));
|
||||
VERIFY(!(a > b));
|
||||
|
||||
VERIFY(!(a == c));
|
||||
VERIFY( (a != c));
|
||||
VERIFY( (a < c));
|
||||
VERIFY( (a <= c));
|
||||
VERIFY(!(a >= c));
|
||||
VERIFY(!(a > c));
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
VERIFY( (a <=> b) == 0);
|
||||
VERIFY(!((a <=> b) != 0));
|
||||
VERIFY(!((a <=> b) < 0));
|
||||
VERIFY( (a <=> b) <= 0);
|
||||
VERIFY( (a <=> b) >= 0);
|
||||
VERIFY(!((a <=> b) > 0));
|
||||
|
||||
VERIFY(!((a <=> c) == 0));
|
||||
VERIFY( (a <=> c) != 0);
|
||||
VERIFY( (a <=> c) < 0);
|
||||
VERIFY( (a <=> c) <= 0);
|
||||
VERIFY(!((a <=> c) >= 0));
|
||||
VERIFY(!((a <=> c) > 0));
|
||||
#endif
|
||||
|
||||
// deduction guides
|
||||
#ifdef __cpp_deduction_guides
|
||||
array deduced {1,2,3,4,5};
|
||||
|
||||
static_assert(eastl::is_same_v<decltype(deduced)::value_type, int>, "deduced array value_type mismatch");
|
||||
VERIFY(deduced.size() == 5);
|
||||
#endif
|
||||
|
||||
// structured binding
|
||||
|
||||
{
|
||||
eastl::array<int, 5> aCopy = a;
|
||||
auto&& [a0, a1, a2, a3, a4] = aCopy;
|
||||
|
||||
VERIFY(a0 == aCopy[0]);
|
||||
VERIFY(a1 == aCopy[1]);
|
||||
VERIFY(a2 == aCopy[2]);
|
||||
VERIFY(a3 == aCopy[3]);
|
||||
VERIFY(a4 == aCopy[4]);
|
||||
|
||||
a0 = 100;
|
||||
VERIFY(aCopy[0] == 100);
|
||||
|
||||
a4 = 0;
|
||||
VERIFY(aCopy[4] == 0);
|
||||
|
||||
// The deduced type may or may not be a reference type; it is an aliased type,
|
||||
// as per https://en.cppreference.com/w/cpp/language/structured_binding:
|
||||
// > Like a reference, a structured binding is an alias to an existing object. Unlike a reference,
|
||||
// the type of a structured binding does not have to be a reference type.
|
||||
// Any reference specifier is thus removed to check only the type & its const qualifier
|
||||
static_assert(eastl::is_same_v<eastl::remove_reference_t<decltype(a0)>, int>);
|
||||
|
||||
const eastl::array<int, 5> aConstCopy = a;
|
||||
auto&& [aConst0, aConst1, aConst2, aConst3, aConst4] = aConstCopy;
|
||||
|
||||
static_assert(eastl::is_same_v<eastl::remove_reference_t<decltype(aConst0)>, const int>);
|
||||
}
|
||||
}
|
||||
|
||||
// constexpr tests
|
||||
{
|
||||
#ifndef EA_NO_CPP14_CONSTEXPR
|
||||
EA_CPP14_CONSTEXPR eastl::array<int, 4> a = {{ 0, 1, 2, 3 }};
|
||||
|
||||
static_assert(a == eastl::array<int, 4>{{ 0, 1, 2, 3 }}, "array constexpr failure");
|
||||
|
||||
static_assert(a[0] == 0, "array constexpr failure");
|
||||
static_assert(a[1] == 1, "array constexpr failure");
|
||||
static_assert(a[2] == 2, "array constexpr failure");
|
||||
static_assert(a[3] == 3, "array constexpr failure");
|
||||
|
||||
static_assert(a.at(0) == 0, "array constexpr failure");
|
||||
static_assert(a.at(1) == 1, "array constexpr failure");
|
||||
static_assert(a.at(2) == 2, "array constexpr failure");
|
||||
static_assert(a.at(3) == 3, "array constexpr failure");
|
||||
|
||||
static_assert(a.data()[0] == 0, "array constexpr failure");
|
||||
static_assert(a.data()[1] == 1, "array constexpr failure");
|
||||
static_assert(a.data()[2] == 2, "array constexpr failure");
|
||||
static_assert(a.data()[3] == 3, "array constexpr failure");
|
||||
|
||||
static_assert(a.empty() == false, "array constexpr failure");
|
||||
static_assert(a.size() == 4, "array constexpr failure");
|
||||
static_assert(a.max_size() == 4, "array constexpr failure");
|
||||
|
||||
static_assert(a.front() == 0, "array constexpr failure");
|
||||
static_assert(a.back() == 3, "array constexpr failure");
|
||||
|
||||
static_assert(a.begin()[0] == 0, "array constexpr failure");
|
||||
static_assert(a.begin()[1] == 1, "array constexpr failure");
|
||||
static_assert(a.begin()[2] == 2, "array constexpr failure");
|
||||
static_assert(a.begin()[3] == 3, "array constexpr failure");
|
||||
|
||||
static_assert(a.cbegin()[0] == 0, "array constexpr failure");
|
||||
static_assert(a.cbegin()[1] == 1, "array constexpr failure");
|
||||
static_assert(a.cbegin()[2] == 2, "array constexpr failure");
|
||||
static_assert(a.cbegin()[3] == 3, "array constexpr failure");
|
||||
|
||||
static_assert(a.crbegin()[0] == 3, "array constexpr failure");
|
||||
static_assert(a.crbegin()[1] == 2, "array constexpr failure");
|
||||
static_assert(a.crbegin()[2] == 1, "array constexpr failure");
|
||||
static_assert(a.crbegin()[3] == 0, "array constexpr failure");
|
||||
|
||||
static_assert(a.end()[-1] == 3, "array constexpr failure");
|
||||
static_assert(a.end()[-2] == 2, "array constexpr failure");
|
||||
static_assert(a.end()[-3] == 1, "array constexpr failure");
|
||||
static_assert(a.end()[-4] == 0, "array constexpr failure");
|
||||
|
||||
static_assert(a.cend()[-1] == 3, "array constexpr failure");
|
||||
static_assert(a.cend()[-2] == 2, "array constexpr failure");
|
||||
static_assert(a.cend()[-3] == 1, "array constexpr failure");
|
||||
static_assert(a.cend()[-4] == 0, "array constexpr failure");
|
||||
|
||||
static_assert(a.crend()[-1] == 0, "array constexpr failure");
|
||||
static_assert(a.crend()[-2] == 1, "array constexpr failure");
|
||||
static_assert(a.crend()[-3] == 2, "array constexpr failure");
|
||||
static_assert(a.crend()[-4] == 3, "array constexpr failure");
|
||||
#endif
|
||||
}
|
||||
|
||||
// to_array
|
||||
{
|
||||
{
|
||||
constexpr int c_array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
constexpr auto arr = to_array(c_array);
|
||||
|
||||
static_assert(is_same_v<remove_cv_t<decltype(arr)>, eastl::array<int, 10>>, "unexpected return type");
|
||||
|
||||
static_assert(arr[0] == 0, "unexpected array value");
|
||||
static_assert(arr[1] == 1, "unexpected array value");
|
||||
static_assert(arr[2] == 2, "unexpected array value");
|
||||
static_assert(arr[3] == 3, "unexpected array value");
|
||||
static_assert(arr[4] == 4, "unexpected array value");
|
||||
static_assert(arr[5] == 5, "unexpected array value");
|
||||
static_assert(arr[6] == 6, "unexpected array value");
|
||||
static_assert(arr[7] == 7, "unexpected array value");
|
||||
static_assert(arr[8] == 8, "unexpected array value");
|
||||
static_assert(arr[9] == 9, "unexpected array value");
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto arr = to_array({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
|
||||
static_assert(is_same_v<remove_cv_t<decltype(arr)>, eastl::array<int, 10>>, "unexpected return type");
|
||||
|
||||
static_assert(arr[0] == 0, "unexpected array value");
|
||||
static_assert(arr[1] == 1, "unexpected array value");
|
||||
static_assert(arr[2] == 2, "unexpected array value");
|
||||
static_assert(arr[3] == 3, "unexpected array value");
|
||||
static_assert(arr[4] == 4, "unexpected array value");
|
||||
static_assert(arr[5] == 5, "unexpected array value");
|
||||
static_assert(arr[6] == 6, "unexpected array value");
|
||||
static_assert(arr[7] == 7, "unexpected array value");
|
||||
static_assert(arr[8] == 8, "unexpected array value");
|
||||
static_assert(arr[9] == 9, "unexpected array value");
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto arr = to_array<long>({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
|
||||
static_assert(is_same_v<remove_cv_t<decltype(arr)>, eastl::array<long, 10>>, "unexpected return type");
|
||||
|
||||
static_assert(arr[0] == 0l, "unexpected array value");
|
||||
static_assert(arr[1] == 1l, "unexpected array value");
|
||||
static_assert(arr[2] == 2l, "unexpected array value");
|
||||
static_assert(arr[3] == 3l, "unexpected array value");
|
||||
static_assert(arr[4] == 4l, "unexpected array value");
|
||||
static_assert(arr[5] == 5l, "unexpected array value");
|
||||
static_assert(arr[6] == 6l, "unexpected array value");
|
||||
static_assert(arr[7] == 7l, "unexpected array value");
|
||||
static_assert(arr[8] == 8l, "unexpected array value");
|
||||
static_assert(arr[9] == 9l, "unexpected array value");
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto arr = to_array<unsigned long>({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
|
||||
static_assert(is_same_v<remove_cv_t<decltype(arr)>, eastl::array<unsigned long, 10>>, "unexpected return type");
|
||||
|
||||
static_assert(arr[0] == 0ul, "unexpected array value");
|
||||
static_assert(arr[1] == 1ul, "unexpected array value");
|
||||
static_assert(arr[2] == 2ul, "unexpected array value");
|
||||
static_assert(arr[3] == 3ul, "unexpected array value");
|
||||
static_assert(arr[4] == 4ul, "unexpected array value");
|
||||
static_assert(arr[5] == 5ul, "unexpected array value");
|
||||
static_assert(arr[6] == 6ul, "unexpected array value");
|
||||
static_assert(arr[7] == 7ul, "unexpected array value");
|
||||
static_assert(arr[8] == 8ul, "unexpected array value");
|
||||
static_assert(arr[9] == 9ul, "unexpected array value");
|
||||
}
|
||||
|
||||
{
|
||||
constexpr auto arr = to_array("EASTL");
|
||||
|
||||
static_assert(is_same_v<remove_cv_t<decltype(arr)>, eastl::array<char, 6>>, "unexpected return type");
|
||||
|
||||
static_assert(arr[0] == 'E', "unexpected value in array");
|
||||
static_assert(arr[1] == 'A', "unexpected value in array");
|
||||
static_assert(arr[2] == 'S', "unexpected value in array");
|
||||
static_assert(arr[3] == 'T', "unexpected value in array");
|
||||
static_assert(arr[4] == 'L', "unexpected value in array");
|
||||
}
|
||||
|
||||
// Older Microsoft compilers don't implement guaranteed copy ellision which is problematic when dealing with
|
||||
// non-copyable types. We disable this test unless we are on a version of MSVC with those features.
|
||||
#if defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1920) // VS2019 16.0+
|
||||
{
|
||||
struct LocalNonCopyable
|
||||
{
|
||||
LocalNonCopyable() = default;
|
||||
~LocalNonCopyable() = default;
|
||||
|
||||
LocalNonCopyable(LocalNonCopyable&&) = default;
|
||||
LocalNonCopyable& operator=(LocalNonCopyable&&) = default;
|
||||
|
||||
LocalNonCopyable(const LocalNonCopyable&) = delete;
|
||||
LocalNonCopyable& operator=(const LocalNonCopyable&) = delete;
|
||||
};
|
||||
|
||||
constexpr auto arr = to_array({LocalNonCopyable{}});
|
||||
static_assert(arr.size() == 1, "unexpected error");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,469 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/bitvector.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/deque.h>
|
||||
#include <EASTL/string.h>
|
||||
|
||||
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::bitvector<>;
|
||||
template class eastl::bitvector<MallocAllocator>;
|
||||
template class eastl::bitvector<EASTLAllocatorType, uint8_t>;
|
||||
template class eastl::bitvector<EASTLAllocatorType, int16_t>;
|
||||
template class eastl::bitvector<EASTLAllocatorType, int32_t>;
|
||||
template class eastl::bitvector<EASTLAllocatorType, int64_t, eastl::vector<int64_t, EASTLAllocatorType> >;
|
||||
|
||||
// bitvector doesn't yet support deque.
|
||||
//template class eastl::bitvector<EASTLAllocatorType, uint8_t, eastl::deque<uint64_t, EASTLAllocatorType> >;
|
||||
//template class eastl::bitvector<EASTLAllocatorType, uint8_t, eastl::deque<int32_t, EASTLAllocatorType, 64> >;
|
||||
|
||||
|
||||
|
||||
int TestBitVector()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
// typedef bitvector<Allocator, Element> this_type;
|
||||
// typedef bool value_type;
|
||||
// typedef bitvector_reference<Element> reference;
|
||||
// typedef bool const_reference;
|
||||
// typedef bitvector_iterator<Element> iterator;
|
||||
// typedef bitvector_const_iterator<Element> const_iterator;
|
||||
// typedef eastl::reverse_iterator<iterator> reverse_iterator;
|
||||
// typedef eastl::reverse_iterator<const_iterator> const_reverse_iterator;
|
||||
// typedef Allocator allocator_type;
|
||||
// typedef Element element_type;
|
||||
// typedef Container container_type;
|
||||
// typedef eastl_size_t size_type;
|
||||
|
||||
bitvector<>::this_type this_typeVariable;
|
||||
bitvector<>::value_type value_typeVariable = 0;
|
||||
bitvector<>::const_reference const_referenceVariable(false);
|
||||
bitvector<>::iterator iteratorVariable(NULL, 0);
|
||||
bitvector<>::const_iterator const_iteratorVariable(NULL, 0);
|
||||
bitvector<>::reverse_iterator reverse_iteratorVariable(iteratorVariable);
|
||||
bitvector<>::const_reverse_iterator const_reverse_iteratorVariable(const_iteratorVariable);
|
||||
bitvector<>::allocator_type allocator_typeVariable;
|
||||
bitvector<>::element_type element_typeVariable = 0;
|
||||
bitvector<>::container_type container_typeVariable;
|
||||
bitvector<>::size_type size_typeVariable = 0;
|
||||
|
||||
string sAddresses(string::CtorSprintf(), "%p %p %p %p %p %p %p %p %p %p %p",
|
||||
&this_typeVariable, &value_typeVariable, &const_referenceVariable, &iteratorVariable,
|
||||
&const_iteratorVariable, &reverse_iteratorVariable,&const_reverse_iteratorVariable,
|
||||
&allocator_typeVariable, &element_typeVariable, &container_typeVariable, &size_typeVariable);
|
||||
EATEST_VERIFY(sAddresses.size() > 0);
|
||||
}
|
||||
|
||||
{
|
||||
// bitvector();
|
||||
// explicit bitvector(const allocator_type& allocator);
|
||||
// explicit bitvector(size_type n, const allocator_type& allocator = EASTL_BITVECTOR_DEFAULT_ALLOCATOR);
|
||||
// bitvector(size_type n, value_type value, const allocator_type& allocator = EASTL_BITVECTOR_DEFAULT_ALLOCATOR);
|
||||
// bitvector(const bitvector& copy);
|
||||
// template <typename InputIterator> bitvector(InputIterator first, InputIterator last);
|
||||
// bitvector& operator=(const bitvector& x);
|
||||
// reference operator[](size_type n); // behavior is undefined if n is invalid.
|
||||
// const_reference operator[](size_type n) const;
|
||||
MallocAllocator mallocAllocator;
|
||||
bitvector<> bv0;
|
||||
bitvector<MallocAllocator> bv1(mallocAllocator);
|
||||
bitvector<> bv2(200);
|
||||
bitvector<> bv3(300, true);
|
||||
bitvector<MallocAllocator> bv4(400, false, mallocAllocator);
|
||||
const bitvector<> bv5(bv2);
|
||||
bool boolArray[] = { true, false, true };
|
||||
bitvector<> bv6(boolArray, boolArray + EAArrayCount(boolArray));
|
||||
bitvector<> bv7(bv3.begin(), bv3.end());
|
||||
|
||||
{
|
||||
// Validate the above constructions
|
||||
EATEST_VERIFY(bv0.validate());
|
||||
EATEST_VERIFY(bv0.empty());
|
||||
|
||||
EATEST_VERIFY(bv1.validate());
|
||||
EATEST_VERIFY(bv1.empty());
|
||||
|
||||
EATEST_VERIFY(bv2.validate());
|
||||
EATEST_VERIFY(bv2.size() == 200);
|
||||
for(eastl_size_t i = 0; i < bv2.size(); i++)
|
||||
EATEST_VERIFY(bv2[i] == false);
|
||||
|
||||
EATEST_VERIFY(bv3.validate());
|
||||
EATEST_VERIFY(bv3.size() == 300);
|
||||
for(eastl_size_t i = 0; i < bv3.size(); i++)
|
||||
EATEST_VERIFY(bv3[i] == true);
|
||||
|
||||
EATEST_VERIFY(bv4.validate());
|
||||
EATEST_VERIFY(bv4.size() == 400);
|
||||
for(eastl_size_t i = 0; i < bv4.size(); i++)
|
||||
EATEST_VERIFY(bv4[i] == false);
|
||||
|
||||
EATEST_VERIFY(bv5.validate());
|
||||
EATEST_VERIFY(bv5 == bv2);
|
||||
for(eastl_size_t i = 0; i < bv5.size(); i++)
|
||||
EATEST_VERIFY(bv5[i] == false);
|
||||
|
||||
EATEST_VERIFY(bv6.validate());
|
||||
EATEST_VERIFY(bv6.size() == EAArrayCount(boolArray));
|
||||
for(eastl_size_t i = 0; i < bv6.size(); i++)
|
||||
EATEST_VERIFY(bv6[i] == boolArray[i]);
|
||||
|
||||
EATEST_VERIFY(bv7.validate());
|
||||
EATEST_VERIFY(bv7.size() == bv3.size()); // The == test theoretically includes this test, be we check anyway.
|
||||
for(eastl_size_t j = 0; j < bv7.size(); j++)
|
||||
EATEST_VERIFY(bv7[j] == bv3[j]);
|
||||
EATEST_VERIFY(bv7 == bv3);
|
||||
for(eastl_size_t i = 0; (i < bv3.size()) && (i < bv7.size()); i++)
|
||||
EATEST_VERIFY(bv3[i] == bv7[i]);
|
||||
}
|
||||
|
||||
{
|
||||
// void swap(this_type& x);
|
||||
|
||||
bv7.swap(bv7); // Test swapping against self.
|
||||
EATEST_VERIFY(bv7.validate());
|
||||
EATEST_VERIFY(bv7 == bv3);
|
||||
EATEST_VERIFY(bv7.size() == bv3.size()); // The == test theoretically includes this test, be we check anyway.
|
||||
for(eastl_size_t i = 0; (i < bv3.size()) && (i < bv7.size()); i++)
|
||||
EATEST_VERIFY(bv3[i] == bv7[i]);
|
||||
|
||||
bv3.swap(bv2); // Note that bv3 and bv4 use different allocators, so we are exercizing that.
|
||||
EATEST_VERIFY(bv3.validate());
|
||||
EATEST_VERIFY(bv3.size() == 200);
|
||||
for(eastl_size_t i = 0; i < bv3.size(); i++)
|
||||
EATEST_VERIFY(bv3[i] == false);
|
||||
|
||||
EATEST_VERIFY(bv2.validate());
|
||||
EATEST_VERIFY(bv2.size() == 300);
|
||||
for(eastl_size_t i = 0; i < bv2.size(); i++)
|
||||
EATEST_VERIFY(bv2[i] == true);
|
||||
|
||||
|
||||
// bitvector& operator=(const bitvector& x);
|
||||
|
||||
bv6 = bv7;
|
||||
EATEST_VERIFY(bv6.validate());
|
||||
EATEST_VERIFY(bv6 == bv7);
|
||||
|
||||
|
||||
// template <typename InputIterator> void assign(InputIterator first, InputIterator last);
|
||||
bv0.assign(bv3.begin(), bv3.end());
|
||||
EATEST_VERIFY(bv0 == bv3);
|
||||
|
||||
bv0.assign(boolArray, boolArray + EAArrayCount(boolArray));
|
||||
EATEST_VERIFY(bv0 == bitvector<>(boolArray, boolArray + EAArrayCount(boolArray)));
|
||||
|
||||
bv0.resize(0);
|
||||
EATEST_VERIFY(bv0.begin()==bv0.end());//should not crash
|
||||
bv3.resize(0);
|
||||
EATEST_VERIFY(bv0 == bv3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// iterator begin();
|
||||
// const_iterator begin() const;
|
||||
// iterator end();
|
||||
// const_iterator end() const;
|
||||
|
||||
bool boolArray[] = { true, false, true, true, false, true };
|
||||
const bitvector<> bv0(boolArray, boolArray + EAArrayCount(boolArray));
|
||||
bitvector<>::const_iterator it;
|
||||
eastl_size_t i;
|
||||
|
||||
for(it = bv0.begin(), i = 0; it != bv0.end(); ++it, ++i) // Iterate forward by 1.
|
||||
{
|
||||
const bool value = *it;
|
||||
EATEST_VERIFY(value == boolArray[i]);
|
||||
}
|
||||
|
||||
for(--it, --i; (eastl_ssize_t)i >= 0; --it, --i) // Iterate backward by 1. Problem: this test code does --it for it == begin(), which isn't strictly allowed.
|
||||
{
|
||||
const bool value = *it;
|
||||
EATEST_VERIFY(value == boolArray[i]);
|
||||
}
|
||||
|
||||
// The following code asssumes an even number of elements.
|
||||
EASTL_CT_ASSERT((EAArrayCount(boolArray) % 2) == 0);
|
||||
for(it = bv0.begin(), ++i; it != bv0.end(); it += 2, i += 2) // Iterate forward by 2.
|
||||
{
|
||||
const bool value = *it;
|
||||
EATEST_VERIFY(value == boolArray[i]);
|
||||
}
|
||||
|
||||
for(it -= 2, i -= 2; (eastl_ssize_t)i >= 0; it -= 2, i -= 2) // Iterate backward by 1. Problem: this test code does it -= 2 for it == begin(), which isn't strictly allowed.
|
||||
{
|
||||
const bool value = *it;
|
||||
EATEST_VERIFY(value == boolArray[i]);
|
||||
}
|
||||
|
||||
|
||||
// reverse_iterator rbegin();
|
||||
// const_reverse_iterator rbegin() const;
|
||||
// reverse_iterator rend();
|
||||
// const_reverse_iterator rend() const;
|
||||
|
||||
bitvector<>::const_reverse_iterator rit;
|
||||
i = (bv0.size() - 1);
|
||||
|
||||
for(rit = bv0.rbegin(); rit != bv0.rend(); ++rit, --i) // Reverse-iterate forward by 1.
|
||||
{
|
||||
//const bool value = *rit; // This is currently broken and will require a bit of work to fix.
|
||||
const bool value = *--rit.base();
|
||||
EATEST_VERIFY(value == boolArray[i]);
|
||||
}
|
||||
|
||||
for(--rit, ++i; i < bv0.size(); --rit, ++i) // Reverse-iterate backward by 1.
|
||||
{
|
||||
//const bool value = *rit; // This is currently broken and will require a bit of work to fix.
|
||||
const bool value = *--rit.base();
|
||||
EATEST_VERIFY(value == boolArray[i]);
|
||||
}
|
||||
|
||||
// The following code asssumes an even number of elements.
|
||||
EASTL_CT_ASSERT((EAArrayCount(boolArray) % 2) == 0);
|
||||
for(rit = bv0.rbegin(), --i; rit != bv0.rend(); rit += 2, i -= 2) // Reverse-iterate forward by 2.
|
||||
{
|
||||
//const bool value = *rit; // This is currently broken and will require a bit of work to fix.
|
||||
const bool value = *--rit.base();
|
||||
EATEST_VERIFY(value == boolArray[i]);
|
||||
}
|
||||
|
||||
for(rit -= 2, i += 2; i < bv0.size(); rit -= 2, i += 2) // Reverse-iterate backward by 2.
|
||||
{
|
||||
//const bool value = *rit; // This is currently broken and will require a bit of work to fix.
|
||||
const bool value = *--rit.base();
|
||||
EATEST_VERIFY(value == boolArray[i]);
|
||||
}
|
||||
|
||||
|
||||
// find_first, etc.
|
||||
/* This work is not complete.
|
||||
{
|
||||
bitvector<> bv(30, false);
|
||||
|
||||
bitvector<>::iterator it = bv.find_first();
|
||||
EATEST_VERIFY(it == bv.begin());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
{
|
||||
MallocAllocator mallocAllocator;
|
||||
bitvector<MallocAllocator> bv0(mallocAllocator);
|
||||
|
||||
// bool empty() const;
|
||||
// size_type size() const;
|
||||
// size_type capacity() const;
|
||||
|
||||
EATEST_VERIFY(bv0.empty());
|
||||
EATEST_VERIFY(bv0.size() == 0);
|
||||
EATEST_VERIFY(bv0.capacity() == 0); // EASTL requires that newly constructed containers have 0 capacity.
|
||||
|
||||
bool boolArray[] = { false, true, true };
|
||||
bv0.assign(boolArray, boolArray + EAArrayCount(boolArray));
|
||||
|
||||
EATEST_VERIFY(!bv0.empty());
|
||||
EATEST_VERIFY(bv0.size() == EAArrayCount(boolArray));
|
||||
EATEST_VERIFY((bv0.capacity() > 0) && (bv0.capacity() <= (8 * sizeof(bitvector<>::element_type))));
|
||||
|
||||
|
||||
// reference front();
|
||||
// const_reference front() const;
|
||||
// reference back();
|
||||
// const_reference back() const;
|
||||
|
||||
EATEST_VERIFY(bv0.front() == false);
|
||||
EATEST_VERIFY(bv0.back() == true);
|
||||
bv0.erase(bv0.begin());
|
||||
EATEST_VERIFY(bv0.front() == true);
|
||||
bv0.erase(bv0.rbegin());
|
||||
EATEST_VERIFY(bv0.back() == true);
|
||||
|
||||
// void set_capacity(size_type n = npos);
|
||||
|
||||
bv0.reserve(17);
|
||||
EATEST_VERIFY((bv0.capacity() >= 17) && (bv0.capacity() <= 100)); // It's hard to make a unit test to portably test an upper limit.
|
||||
|
||||
int allocCountBefore = MallocAllocator::mAllocCountAll;
|
||||
while(bv0.size() < 17)
|
||||
bv0.push_back(false);
|
||||
EATEST_VERIFY(allocCountBefore == MallocAllocator::mAllocCountAll); // Verify no new memory was allocated.
|
||||
|
||||
bv0.set_capacity();
|
||||
EATEST_VERIFY(bv0.capacity() >= bv0.size());
|
||||
|
||||
bv0.set_capacity(0);
|
||||
EATEST_VERIFY(bv0.capacity() == 0);
|
||||
EATEST_VERIFY(bv0.empty());
|
||||
|
||||
|
||||
// void resize(size_type n, value_type value);
|
||||
// void resize(size_type n);
|
||||
// void reserve(size_type n);
|
||||
|
||||
bv0.reserve(800);
|
||||
EATEST_VERIFY(bv0.capacity() >= 800);
|
||||
allocCountBefore = MallocAllocator::mAllocCountAll;
|
||||
bv0.resize(800, true);
|
||||
EATEST_VERIFY(allocCountBefore == MallocAllocator::mAllocCountAll); // Verify no new memory was allocated.
|
||||
|
||||
|
||||
// void push_back();
|
||||
// void push_back(value_type value);
|
||||
// void pop_back();
|
||||
// reference operator[](size_type n);
|
||||
// const_reference operator[](size_type n) const;
|
||||
|
||||
bv0.push_back();
|
||||
bv0.back() = true;
|
||||
bv0.push_back(false);
|
||||
bv0.push_back(true);
|
||||
|
||||
EATEST_VERIFY(bv0[bv0.size()-1] == true);
|
||||
EATEST_VERIFY(bv0[bv0.size()-2] == false);
|
||||
EATEST_VERIFY(bv0[bv0.size()-3] == true);
|
||||
|
||||
|
||||
// reference at(size_type n);
|
||||
// const_reference at(size_type n) const;
|
||||
|
||||
EATEST_VERIFY(bv0.at(bv0.size()-1) == true);
|
||||
EATEST_VERIFY(bv0.at(bv0.size()-2) == false);
|
||||
EATEST_VERIFY(bv0.at(bv0.size()-3) == true);
|
||||
|
||||
|
||||
// void clear();
|
||||
// bool test(size_type n, bool defaultValue) const;
|
||||
// void set(bool value, size_type n);
|
||||
|
||||
bv0.clear();
|
||||
bv0.resize(17, true);
|
||||
EATEST_VERIFY(bv0.test(0, false) == true);
|
||||
EATEST_VERIFY(bv0.test(17, false) == false); // Test past the end.
|
||||
EATEST_VERIFY(bv0.test(17, true) == true);
|
||||
|
||||
bv0.set(3, false);
|
||||
EATEST_VERIFY(bv0.test(3, true) == false);
|
||||
|
||||
bv0.set(100, true);
|
||||
EATEST_VERIFY(bv0.test(100, false) == true);
|
||||
|
||||
|
||||
// container_type& get_container();
|
||||
// const container_type& get_container() const;
|
||||
|
||||
EATEST_VERIFY(!bv0.get_container().empty());
|
||||
|
||||
|
||||
// bool validate() const;
|
||||
// int validate_iterator(const_iterator i) const;
|
||||
|
||||
EATEST_VERIFY(bv0.validate());
|
||||
bitvector<>::iterator it;
|
||||
EATEST_VERIFY(bv0.validate_iterator(it) == isf_none);
|
||||
for(it = bv0.begin(); it != bv0.end(); ++it)
|
||||
EATEST_VERIFY(bv0.validate_iterator(it) == (isf_valid | isf_current | isf_can_dereference));
|
||||
EATEST_VERIFY(bv0.validate_iterator(it) == (isf_valid | isf_current));
|
||||
|
||||
|
||||
|
||||
// iterator insert(iterator position, value_type value);
|
||||
// void insert(iterator position, size_type n, value_type value);
|
||||
|
||||
bv0.clear();
|
||||
bv0.resize(17, true);
|
||||
bv0.insert(bv0.begin() + 5, false);
|
||||
EATEST_VERIFY(bv0[5] == false);
|
||||
bv0[5] = true;
|
||||
EATEST_VERIFY(bv0[5] == true);
|
||||
|
||||
bv0.insert(bv0.begin() + 5, 7, false);
|
||||
EATEST_VERIFY((bv0[5] == false) && (bv0[11] == false));
|
||||
|
||||
EATEST_VERIFY(bv0.back() == true);
|
||||
bv0.insert(bv0.end(), false);
|
||||
EATEST_VERIFY(bv0.back() == false);
|
||||
|
||||
|
||||
// iterator erase(iterator position);
|
||||
// iterator erase(iterator first, iterator last);
|
||||
|
||||
EATEST_VERIFY((bv0[10] == false) && (bv0[11] == false));
|
||||
bv0.erase(bv0.begin() + 11);
|
||||
EATEST_VERIFY((bv0[10] == false) && (bv0[11] == true));
|
||||
|
||||
EATEST_VERIFY(bv0[5] == false);
|
||||
bool bv06 = bv0[6];
|
||||
bv0.erase(bv0.begin() + 5, bv0.begin() + 6);
|
||||
EATEST_VERIFY(bv0[5] == bv06);
|
||||
|
||||
|
||||
// reverse_iterator erase(reverse_iterator position);
|
||||
// reverse_iterator erase(reverse_iterator first, reverse_iterator last);
|
||||
|
||||
bv0.clear();
|
||||
bv0.resize(10, true);
|
||||
bv0.back() = false;
|
||||
bv0.erase(bv0.rbegin());
|
||||
EATEST_VERIFY((bv0.size() == 9) && (bv0.back() == true));
|
||||
|
||||
bv0.erase(bv0.rbegin(), bv0.rend());
|
||||
EATEST_VERIFY(bv0.empty());
|
||||
|
||||
|
||||
// template <typename InputIterator> Not yet implemented. See below for disabled definition.
|
||||
// void insert(iterator position, InputIterator first, InputIterator last);
|
||||
//
|
||||
// Disabled because insert isn't implemented yet.
|
||||
// const bool boolArray2[4] = { false, true, false, true };
|
||||
// bv0.insert(bv0.end(), boolArray2, boolArray2 + EAArrayCount(boolArray));
|
||||
// EATEST_VERIFY(bv0.size() == EAArrayCount(boolArray2));
|
||||
|
||||
|
||||
// element_type* data();
|
||||
// const element_type* data() const;
|
||||
|
||||
EATEST_VERIFY(bv0.data() != NULL);
|
||||
bv0.set_capacity(0);
|
||||
EATEST_VERIFY(bv0.data() == NULL);
|
||||
|
||||
|
||||
// void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
|
||||
|
||||
bv0.resize(100, true);
|
||||
void* pSaved = MallocAllocator::mpLastAllocation;
|
||||
bv0.reset_lose_memory();
|
||||
EATEST_VERIFY(bv0.validate());
|
||||
free(pSaved); // Call the C free function.
|
||||
MallocAllocator::mpLastAllocation = NULL;
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/bit.h>
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
int TestBitcast()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
uint32_t int32Value = 0x12345678;
|
||||
float floatValue = eastl::bit_cast<float>(int32Value);
|
||||
VERIFY(memcmp(&int32Value, &floatValue, sizeof(float)) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
struct IntFloatStruct
|
||||
{
|
||||
uint32_t i = 0x87654321;
|
||||
float f = 10.f;
|
||||
};
|
||||
struct CharIntStruct
|
||||
{
|
||||
char c1;
|
||||
char c2;
|
||||
char c3;
|
||||
char c4;
|
||||
uint32_t i;
|
||||
};
|
||||
|
||||
IntFloatStruct ifStruct;
|
||||
CharIntStruct ciStruct = eastl::bit_cast<CharIntStruct>(ifStruct);
|
||||
VERIFY(memcmp(&ifStruct, &ciStruct, sizeof(IntFloatStruct)) == 0);
|
||||
}
|
||||
|
||||
#if EASTL_CONSTEXPR_BIT_CAST_SUPPORTED
|
||||
{
|
||||
constexpr uint32_t int32Value = 40;
|
||||
constexpr float floatValue = eastl::bit_cast<float>(int32Value);
|
||||
VERIFY(memcmp(&int32Value, &floatValue, sizeof(float)) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/internal/char_traits.h>
|
||||
|
||||
|
||||
template<typename CharT>
|
||||
int TestCharTraits()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
int TestCharTraits()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
nErrorCount += TestCharTraits<char>();
|
||||
nErrorCount += TestCharTraits<wchar_t>();
|
||||
nErrorCount += TestCharTraits<char16_t>();
|
||||
nErrorCount += TestCharTraits<char32_t>();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/chrono.h>
|
||||
#include <EASTL/numeric.h>
|
||||
#include <EASTL/string.h>
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
using namespace eastl::chrono;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TestDuration
|
||||
//
|
||||
int TestDuration()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
hours h{1}; // 1 hour
|
||||
milliseconds ms{3}; // 3 milliseconds
|
||||
duration<int, kilo> ks{3}; // 3000 seconds
|
||||
|
||||
duration<double, ratio<1, 30>> hz30{3.5};
|
||||
microseconds us = ms;
|
||||
duration<double, milli> ms2 = us; // 3.0 milliseconds
|
||||
|
||||
EA_UNUSED(h);
|
||||
EA_UNUSED(ms2);
|
||||
EA_UNUSED(ks);
|
||||
EA_UNUSED(hz30);
|
||||
EA_UNUSED(us);
|
||||
}
|
||||
|
||||
{
|
||||
typedef duration<double, ratio<1, 30>> dur_t;
|
||||
VERIFY(dur_t::min() < dur_t::zero());
|
||||
VERIFY(dur_t::zero() < dur_t::max());
|
||||
VERIFY(dur_t::min() < dur_t::max());
|
||||
}
|
||||
|
||||
{
|
||||
seconds s1(10);
|
||||
seconds s2 = -s1;
|
||||
VERIFY(s1.count() == 10);
|
||||
VERIFY(s2.count() == -10);
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
hours h(1);
|
||||
minutes m = ++h;
|
||||
m--;
|
||||
VERIFY(m.count() == 119);
|
||||
}
|
||||
|
||||
{
|
||||
hours h(24);
|
||||
minutes m = h;
|
||||
seconds s = m;
|
||||
milliseconds ms = s;
|
||||
|
||||
VERIFY(h.count() == 24);
|
||||
VERIFY(m.count() == 1440);
|
||||
VERIFY(s.count() == 86400);
|
||||
VERIFY(ms.count() == 86400000);
|
||||
}
|
||||
|
||||
{
|
||||
minutes m(11);
|
||||
m *= 2;
|
||||
VERIFY(m.count() == 22);
|
||||
m += hours(10);
|
||||
VERIFY(m.count() == 622);
|
||||
VERIFY(duration_cast<hours>(m).count() == 10);
|
||||
m %= hours(1);
|
||||
VERIFY(duration_cast<hours>(m).count() == 0);
|
||||
VERIFY(m.count() == 22);
|
||||
}
|
||||
|
||||
{
|
||||
milliseconds ms(3); // 3 milliseconds
|
||||
VERIFY(ms.count() == 3);
|
||||
|
||||
microseconds us = 2 * ms; // 6000 microseconds constructed from 3 milliseconds
|
||||
VERIFY(us.count() == 6000);
|
||||
|
||||
microseconds us2 = ms * 2; // 6000 microseconds constructed from 3 milliseconds
|
||||
VERIFY(us2.count() == 6000);
|
||||
|
||||
microseconds us3 = us / 2;
|
||||
VERIFY(us3.count() == 3000);
|
||||
|
||||
microseconds us4 = us % 2;
|
||||
VERIFY(us4.count() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TestTimePoint
|
||||
//
|
||||
int TestTimePoint()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
{
|
||||
{
|
||||
system_clock::time_point t0 = system_clock::now();
|
||||
auto tomorrow = t0 + hours(24);
|
||||
auto today = tomorrow - system_clock::now();
|
||||
auto hours_count = duration_cast<hours>(today).count();
|
||||
|
||||
VERIFY(hours_count == 24 || hours_count == 23); // account for time flux
|
||||
}
|
||||
|
||||
{
|
||||
time_point<system_clock, hours> hour1(hours(1));
|
||||
|
||||
auto hour_to_min = time_point_cast<minutes>(hour1);
|
||||
auto hour_to_sec = time_point_cast<seconds>(hour1);
|
||||
auto hour_to_millisec = time_point_cast<milliseconds>(hour1);
|
||||
auto hour_to_microsec = time_point_cast<microseconds>(hour1);
|
||||
auto hour_to_nanosec = time_point_cast<nanoseconds>(hour1);
|
||||
|
||||
VERIFY(hour_to_min.time_since_epoch().count() == 60);
|
||||
VERIFY(hour_to_sec.time_since_epoch().count() == 3600);
|
||||
VERIFY(hour_to_millisec.time_since_epoch().count() == 3600000ll);
|
||||
VERIFY(hour_to_microsec.time_since_epoch().count() == 3600000000ll);
|
||||
VERIFY(hour_to_nanosec.time_since_epoch().count() == 3600000000000ll);
|
||||
}
|
||||
}
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TestClocks
|
||||
//
|
||||
int TestClocks()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
{
|
||||
{
|
||||
auto sys = system_clock::now();
|
||||
VERIFY(sys.time_since_epoch().count() > 0);
|
||||
|
||||
auto stdy = steady_clock::now();
|
||||
VERIFY(stdy.time_since_epoch().count() > 0);
|
||||
|
||||
auto hrc = high_resolution_clock::now();
|
||||
VERIFY(hrc.time_since_epoch().count() > 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto start = system_clock::now();
|
||||
auto end = system_clock::now();
|
||||
auto d = end - start;
|
||||
EA_UNUSED(d);
|
||||
VERIFY(d.count() >= 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto start = steady_clock::now();
|
||||
auto end = steady_clock::now();
|
||||
auto d = end - start;
|
||||
EA_UNUSED(d);
|
||||
VERIFY(d.count() >= 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto start = high_resolution_clock::now();
|
||||
auto end = high_resolution_clock::now();
|
||||
auto d = end - start;
|
||||
EA_UNUSED(d);
|
||||
VERIFY(d.count() >= 0);
|
||||
}
|
||||
|
||||
{
|
||||
typedef duration<int, ratio<1, 100000000>> shakes;
|
||||
typedef duration<int, centi> jiffies;
|
||||
typedef duration<float, ratio<12096, 10000>> microfortnights;
|
||||
typedef duration<float, ratio<3155, 1000>> nanocenturies;
|
||||
|
||||
seconds sec(1);
|
||||
|
||||
VERIFY(duration_cast<shakes>(sec).count() == 100000000);
|
||||
VERIFY(duration_cast<jiffies>(sec).count() == 100);
|
||||
VERIFY(microfortnights(sec).count() > 0.82f);
|
||||
VERIFY(nanocenturies(sec).count() > 0.31f);
|
||||
}
|
||||
}
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
int TestChrono()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
nErrorCount += TestDuration();
|
||||
nErrorCount += TestTimePoint();
|
||||
nErrorCount += TestClocks();
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/type_traits.h>
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
#if defined(__cplusplus_winrt)
|
||||
ref class Foo
|
||||
{
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
int TestCppCXTypeTraits()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// We can only build this code if C++/CX is enabled
|
||||
#if defined(__cplusplus_winrt)
|
||||
{
|
||||
Foo^ foo = ref new Foo();
|
||||
static_assert(eastl::is_pod<Foo^>::value == false, "Ref types are not POD");
|
||||
static_assert(eastl::is_trivially_destructible<Foo^>::value == false, "Ref types cannot be trivially destructible");
|
||||
static_assert(eastl::is_trivially_constructible<Foo^>::value == false, "Ref types cannot be trivially constructible");
|
||||
static_assert(eastl::is_trivially_copy_constructible<Foo^>::value == false, "Ref types cannot be trivially copyable");
|
||||
static_assert(eastl::is_trivially_copy_assignable<Foo^>::value == false, "Ref types cannot be trivially copyable");
|
||||
}
|
||||
#endif
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/finally.h>
|
||||
|
||||
|
||||
int TestFinally()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
#if defined(EA_COMPILER_CPP17_ENABLED)
|
||||
{
|
||||
// requires CTAD (class template argument deduction)
|
||||
int a = 0;
|
||||
{
|
||||
VERIFY(a == 0);
|
||||
eastl::finally _([&] { a = 42; });
|
||||
VERIFY(a == 0);
|
||||
}
|
||||
VERIFY(a == 42);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
int a = 0;
|
||||
{
|
||||
VERIFY(a == 0);
|
||||
auto _ = eastl::make_finally([&] { a = 42; });
|
||||
VERIFY(a == 0);
|
||||
}
|
||||
VERIFY(a == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 0;
|
||||
{
|
||||
VERIFY(a == 0);
|
||||
auto f = eastl::make_finally([&] { a = 42; });
|
||||
VERIFY(a == 0);
|
||||
f.dismiss();
|
||||
VERIFY(a == 0);
|
||||
}
|
||||
VERIFY(a == 0);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 0;
|
||||
{
|
||||
VERIFY(a == 0);
|
||||
auto f = eastl::make_finally([&] { a = 42; });
|
||||
VERIFY(a == 0);
|
||||
f.execute();
|
||||
VERIFY(a == 42);
|
||||
}
|
||||
VERIFY(a == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 0;
|
||||
{
|
||||
VERIFY(a == 0);
|
||||
auto f = eastl::make_finally([&] { a = 42; });
|
||||
VERIFY(a == 0);
|
||||
f.execute();
|
||||
VERIFY(a == 42);
|
||||
|
||||
// verify the finally object doesn't re-run the callback on scope-exit.
|
||||
a = -1;
|
||||
}
|
||||
VERIFY(a == -1);
|
||||
}
|
||||
|
||||
{
|
||||
struct local_flag { bool b = false; };
|
||||
|
||||
local_flag lf;
|
||||
VERIFY(lf.b == false);
|
||||
|
||||
{ auto _ = eastl::make_finally([&] { lf.b = true; }); }
|
||||
|
||||
VERIFY(lf.b);
|
||||
}
|
||||
|
||||
// This currently does not compile by design.
|
||||
//
|
||||
// {
|
||||
// int a = 0;
|
||||
// auto lbda = [&a] { a = 1234; };
|
||||
// {
|
||||
// VERIFY(a == 0);
|
||||
// auto _ = eastl::make_finally(lbda); // compiler error
|
||||
// VERIFY(a == 0);
|
||||
// }
|
||||
// VERIFY(a == 1234);
|
||||
// }
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,614 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAAssert/eaassert.h>
|
||||
|
||||
// Included prior to EASTLTest.h to guard against the following bug resurfacing:
|
||||
// https://github.com/electronicarts/EASTL/issues/275
|
||||
#include <EASTL/fixed_function.h>
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/numeric.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <functional>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionDtor
|
||||
//
|
||||
int TestFixedFunctionDtor()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
TestObject to;
|
||||
TestObject::Reset();
|
||||
{
|
||||
eastl::fixed_function<sizeof(TestObject), void(void)> ff = [to] {};
|
||||
ff();
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionStdBind
|
||||
//
|
||||
int TestFixedFunctionStdBind()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
int val = 0;
|
||||
|
||||
{
|
||||
TestObject to;
|
||||
auto lambda = [to, &val] { ++val; };
|
||||
TestObject::Reset();
|
||||
{
|
||||
eastl::fixed_function<64, void(void)> ff = std::bind(lambda);
|
||||
ff();
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
VERIFY(val == 1);
|
||||
}
|
||||
{
|
||||
TestObject to;
|
||||
auto lambda = [to, &val] { ++val; };
|
||||
TestObject::Reset();
|
||||
{
|
||||
eastl::fixed_function<64, void(void)> ff = nullptr;
|
||||
ff = std::bind(lambda);
|
||||
ff();
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
VERIFY(val == 2);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionReferenceWrapper
|
||||
//
|
||||
int TestFixedFunctionReferenceWrapper()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
int val = 0;
|
||||
|
||||
{
|
||||
TestObject to;
|
||||
auto lambda = [to, &val] { ++val; };
|
||||
TestObject::Reset();
|
||||
{
|
||||
eastl::fixed_function<sizeof(eastl::reference_wrapper<decltype(lambda)>), void(void)> ff = eastl::reference_wrapper<decltype(lambda)>(lambda);
|
||||
ff();
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
VERIFY(val == 1);
|
||||
}
|
||||
{
|
||||
TestObject to;
|
||||
auto lambda = [to, &val] { ++val; };
|
||||
TestObject::Reset();
|
||||
{
|
||||
eastl::fixed_function<sizeof(eastl::reference_wrapper<decltype(lambda)>), void(void)> ff = nullptr;
|
||||
ff = eastl::reference_wrapper<decltype(lambda)>(lambda);
|
||||
ff();
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
VERIFY(val == 2);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionFunctionPointer
|
||||
//
|
||||
|
||||
static void TestVoidRet(int* p)
|
||||
{
|
||||
*p += 1;
|
||||
}
|
||||
|
||||
static int TestIntRet(int* p)
|
||||
{
|
||||
int ret = *p;
|
||||
*p += 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TestFixedFunctionFunctionPointer()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
typedef int (*FuncPtrInt)(int*);
|
||||
typedef void (*FuncPtrVoid)(int*);
|
||||
|
||||
int nErrorCount = 0;
|
||||
int val = 0;
|
||||
|
||||
{
|
||||
eastl::fixed_function<sizeof(FuncPtrVoid), void(int*)> ff = &TestVoidRet;
|
||||
ff(&val);
|
||||
VERIFY(val == 1);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(FuncPtrVoid), void(int*)> ff;
|
||||
ff = &TestVoidRet;
|
||||
ff(&val);
|
||||
VERIFY(val == 2);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(FuncPtrInt), int(int*)> ff = &TestIntRet;
|
||||
int ret = ff(&val);
|
||||
VERIFY(ret == 2);
|
||||
VERIFY(val == 3);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(FuncPtrInt), int(int*)> ff;
|
||||
ff = &TestIntRet;
|
||||
int ret = ff(&val);
|
||||
VERIFY(ret == 3);
|
||||
VERIFY(val == 4);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionPointerToMemberFunction
|
||||
//
|
||||
|
||||
int TestFixedFunctionPointerToMemberFunction()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
struct TestVoidRet
|
||||
{
|
||||
TestVoidRet() : x(0) {}
|
||||
~TestVoidRet() = default;
|
||||
|
||||
void IncX() const
|
||||
{
|
||||
++x;
|
||||
}
|
||||
|
||||
void IncX()
|
||||
{
|
||||
++x;
|
||||
}
|
||||
|
||||
mutable int x = 0;
|
||||
};
|
||||
|
||||
struct TestIntRet
|
||||
{
|
||||
TestIntRet() : x(0) {}
|
||||
|
||||
int IncX() const
|
||||
{
|
||||
return x++;
|
||||
}
|
||||
|
||||
int IncX()
|
||||
{
|
||||
return x++;
|
||||
}
|
||||
|
||||
mutable int x = 0;
|
||||
};
|
||||
|
||||
int nErrorCount = 0;
|
||||
TestVoidRet voidRet;
|
||||
TestIntRet intRet;
|
||||
const TestVoidRet cvoidRet;
|
||||
const TestIntRet cintRet;
|
||||
|
||||
typedef void (TestVoidRet::*PTMFSize)(void);
|
||||
|
||||
{
|
||||
eastl::fixed_function<sizeof(PTMFSize), void(const TestVoidRet&)> ff = static_cast<void(TestVoidRet::*)() const>(&TestVoidRet::IncX);
|
||||
ff(cvoidRet);
|
||||
VERIFY(cvoidRet.x == 1);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(PTMFSize), void(const TestVoidRet&)> ff = static_cast<void(TestVoidRet::*)() const>(&TestVoidRet::IncX);
|
||||
ff(voidRet);
|
||||
VERIFY(voidRet.x == 1);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(PTMFSize), void(TestVoidRet&)> ff = static_cast<void(TestVoidRet::*)()>(&TestVoidRet::IncX);
|
||||
ff(voidRet);
|
||||
VERIFY(voidRet.x == 2);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<sizeof(PTMFSize), int(const TestIntRet&)> ff = static_cast<int(TestIntRet::*)() const>(&TestIntRet::IncX);
|
||||
int ret = ff(cintRet);
|
||||
VERIFY(ret == 0);
|
||||
VERIFY(cintRet.x == 1);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(PTMFSize), int(const TestIntRet&)> ff = static_cast<int(TestIntRet::*)() const>(&TestIntRet::IncX);
|
||||
int ret = ff(intRet);
|
||||
VERIFY(ret == 0);
|
||||
VERIFY(intRet.x == 1);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(PTMFSize), int(TestIntRet&)> ff = static_cast<int(TestIntRet::*)()>(&TestIntRet::IncX);
|
||||
int ret = ff(intRet);
|
||||
VERIFY(ret == 1);
|
||||
VERIFY(intRet.x == 2);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionPointerToMemberData
|
||||
//
|
||||
|
||||
int TestFixedFunctionPointerToMemberData()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
struct Test
|
||||
{
|
||||
Test() : x(1) {}
|
||||
int x = 1;
|
||||
};
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
Test t;
|
||||
const Test ct;
|
||||
|
||||
{
|
||||
eastl::fixed_function<sizeof(void*), int(const Test&)> ff = &Test::x;
|
||||
int ret = ff(t);
|
||||
VERIFY(ret == 1);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(void*), int(const Test&)> ff = &Test::x;
|
||||
int ret = ff(ct);
|
||||
VERIFY(ret == 1);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(void*), int(const Test&)> ff;
|
||||
ff = &Test::x;
|
||||
int ret = ff(t);
|
||||
VERIFY(ret == 1);
|
||||
}
|
||||
{
|
||||
eastl::fixed_function<sizeof(void*), int(const Test&)> ff;
|
||||
ff = &Test::x;
|
||||
int ret = ff(ct);
|
||||
VERIFY(ret == 1);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionExistingClosure
|
||||
//
|
||||
int TestFixedFunctionExistingClosure()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
TestObject to;
|
||||
{
|
||||
using ff_t = eastl::fixed_function<sizeof(TestObject), void(void)>;
|
||||
{
|
||||
ff_t ff1 = [to] {};
|
||||
ff_t ff3 = [to] {};
|
||||
TestObject::Reset();
|
||||
{
|
||||
ff_t ff2 = ff1;
|
||||
ff2 = ff3; // copy over function that holds existing closure state
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
{
|
||||
ff_t ff1 = [to] {};
|
||||
TestObject::Reset();
|
||||
ff_t ff3 = [to] {};
|
||||
{
|
||||
ff_t ff2 = ff1;
|
||||
ff2 = eastl::move(ff3); // copy over function that holds existing closure state
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
{
|
||||
ff_t ff1 = [to] {};
|
||||
TestObject::Reset();
|
||||
{
|
||||
ff_t ff2 = ff1;
|
||||
ff2 = nullptr;
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
{
|
||||
TestObject::Reset();
|
||||
ff_t ff1 = [to] {};
|
||||
{
|
||||
ff_t ff2 = eastl::move(ff1);
|
||||
ff2 = nullptr;
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionCaptureless
|
||||
//
|
||||
// Tests calling a captureless (eg. function pointer) callable with variable
|
||||
// eastl::fixed_function size types.
|
||||
//
|
||||
template<class FixedFunctionT>
|
||||
int TestFixedFunctionCaptureless()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
FixedFunctionT fn;
|
||||
|
||||
EATEST_VERIFY(!fn);
|
||||
|
||||
fn = [](int in) { return in; };
|
||||
|
||||
EATEST_VERIFY(!!fn);
|
||||
|
||||
EATEST_VERIFY(fn(42) == 42);
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFixedFunctionBasic
|
||||
//
|
||||
int TestFixedFunctionBasic()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
struct Functor { void operator()() { return; } };
|
||||
fixed_function<24, void(void)> fn;
|
||||
fixed_function<24, void(void)> fn2 = nullptr;
|
||||
EATEST_VERIFY(!fn);
|
||||
EATEST_VERIFY(!fn2);
|
||||
EATEST_VERIFY(fn == nullptr);
|
||||
EATEST_VERIFY(fn2 == nullptr);
|
||||
EATEST_VERIFY(nullptr == fn);
|
||||
EATEST_VERIFY(nullptr == fn2);
|
||||
fn = Functor();
|
||||
fn2 = Functor();
|
||||
EATEST_VERIFY(!!fn);
|
||||
EATEST_VERIFY(!!fn2);
|
||||
EATEST_VERIFY(fn != nullptr);
|
||||
EATEST_VERIFY(fn2 != nullptr);
|
||||
EATEST_VERIFY(nullptr != fn);
|
||||
EATEST_VERIFY(nullptr != fn2);
|
||||
fn = nullptr;
|
||||
fn2 = fn;
|
||||
EATEST_VERIFY(!fn);
|
||||
EATEST_VERIFY(!fn2);
|
||||
EATEST_VERIFY(fn == nullptr);
|
||||
EATEST_VERIFY(fn2 == nullptr);
|
||||
EATEST_VERIFY(nullptr == fn);
|
||||
EATEST_VERIFY(nullptr == fn2);
|
||||
}
|
||||
|
||||
{
|
||||
using eastl::swap;
|
||||
struct Functor { int operator()() { return 5; } };
|
||||
fixed_function<24, int(void)> fn = Functor();
|
||||
fixed_function<24, int(void)> fn2;
|
||||
EATEST_VERIFY(fn() == 5);
|
||||
EATEST_VERIFY(!fn2);
|
||||
fn.swap(fn2);
|
||||
EATEST_VERIFY(!fn);
|
||||
EATEST_VERIFY(fn2() == 5);
|
||||
swap(fn, fn2);
|
||||
EATEST_VERIFY(fn() == 5);
|
||||
EATEST_VERIFY(!fn2);
|
||||
}
|
||||
|
||||
{
|
||||
struct Functor { int operator()() { return 42; } };
|
||||
fixed_function<0, int(void)> fn = Functor();
|
||||
EATEST_VERIFY(fn() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
struct Functor { int operator()(int in) { return in; } };
|
||||
fixed_function<0, int(int)> fn = Functor();
|
||||
EATEST_VERIFY(fn(24) == 24);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<0, void(void)> fn;
|
||||
|
||||
EATEST_VERIFY(!fn);
|
||||
fn = [] {};
|
||||
EATEST_VERIFY(!!fn);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<0, int(int)> fn = [](int param) { return param; };
|
||||
EATEST_VERIFY(fn(42) == 42);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<0, int(int)> fn = ReturnVal;
|
||||
EATEST_VERIFY(fn(42) == 42);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<0, int()> fn0 = ReturnZero;
|
||||
eastl::fixed_function<0, int()> fn1 = ReturnOne;
|
||||
|
||||
EATEST_VERIFY(fn0() == 0 && fn1() == 1);
|
||||
swap(fn0, fn1);
|
||||
EATEST_VERIFY(fn0() == 1 && fn1() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<0, int()> fn0 = ReturnZero;
|
||||
eastl::fixed_function<0, int()> fn1 = ReturnOne;
|
||||
|
||||
EATEST_VERIFY(fn0() == 0 && fn1() == 1);
|
||||
fn0 = fn1;
|
||||
EATEST_VERIFY(fn0() == 1 && fn1() == 1);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<0, int()> fn0 = ReturnZero;
|
||||
eastl::fixed_function<0, int()> fn1 = ReturnOne;
|
||||
|
||||
EATEST_VERIFY(fn0() == 0 && fn1() == 1);
|
||||
fn0 = eastl::move(fn1);
|
||||
EATEST_VERIFY(fn0() == 1 && fn1 == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<0, int(int)> f1(nullptr);
|
||||
EATEST_VERIFY(!f1);
|
||||
|
||||
eastl::fixed_function<0, int(int)> f2 = nullptr;
|
||||
EATEST_VERIFY(!f2);
|
||||
}
|
||||
|
||||
{
|
||||
// test using a large lambda capture
|
||||
uint64_t a = 1, b = 2, c = 3, d = 4, e = 5, f = 6;
|
||||
auto large_add = [=] { return a + b + c + d + e + f; };
|
||||
|
||||
{
|
||||
eastl::fixed_function<48, uint64_t(void)> fn = large_add;
|
||||
auto result = fn();
|
||||
EATEST_VERIFY(result == 21);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<sizeof(large_add), uint64_t(void)> fn = large_add;
|
||||
auto result = fn();
|
||||
EATEST_VERIFY(result == 21);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
using ff_0 = eastl::fixed_function<0, int(int)>;
|
||||
using ff_1 = eastl::fixed_function<1, int(int)>;
|
||||
using ff_4 = eastl::fixed_function<4, int(int)>;
|
||||
using ff_8 = eastl::fixed_function<8, int(int)>;
|
||||
using ff_64 = eastl::fixed_function<64, int(int)>;
|
||||
using ff_128 = eastl::fixed_function<128, int(int)>;
|
||||
using ff_4096 = eastl::fixed_function<4096, int(int)>;
|
||||
|
||||
static_assert(sizeof(ff_0) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_1) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_4) >= sizeof(void*), "error");
|
||||
static_assert(sizeof(ff_8) >= 8, "error");
|
||||
static_assert(sizeof(ff_64) >= 64, "error");
|
||||
static_assert(sizeof(ff_128) >= 128, "error");
|
||||
static_assert(sizeof(ff_4096) >= 4096, "error");
|
||||
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_0>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_1>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_4>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_8>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_64>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_128>();
|
||||
nErrorCount += TestFixedFunctionCaptureless<ff_4096>();
|
||||
}
|
||||
|
||||
// Verify conversions to fixed_function<N> for sizes greater or equal to the source size.
|
||||
{
|
||||
uint32_t v0 = 130480, v1 = 936780302;
|
||||
const uint32_t result = v0 + v1;
|
||||
|
||||
eastl::fixed_function<8, uint32_t(void)> ff8 = [v0, v1]
|
||||
{ return v0 + v1; };
|
||||
|
||||
{
|
||||
eastl::fixed_function<16, uint32_t(void)> ff16(ff8);
|
||||
VERIFY(result == ff16());
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<16, uint32_t(void)> ff16 = ff8;
|
||||
VERIFY(result == ff16());
|
||||
}
|
||||
|
||||
{
|
||||
eastl::fixed_function<16, uint32_t(void)> ff16;
|
||||
ff16 = ff8;
|
||||
VERIFY(result == ff16());
|
||||
}
|
||||
|
||||
{
|
||||
auto ff8Copy = ff8;
|
||||
eastl::fixed_function<16, uint32_t(void)> ff16(eastl::move(ff8Copy));
|
||||
VERIFY(result == ff16());
|
||||
}
|
||||
|
||||
{
|
||||
auto ff8Copy = ff8;
|
||||
eastl::fixed_function<16, uint32_t(void)> ff16 = eastl::move(ff8Copy);
|
||||
VERIFY(result == ff16());
|
||||
}
|
||||
|
||||
{
|
||||
auto ff8Copy = ff8;
|
||||
eastl::fixed_function<16, uint32_t(void)> ff16;
|
||||
ff16 = eastl::move(ff8Copy);
|
||||
VERIFY(result == ff16());
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestFunctional
|
||||
//
|
||||
int TestFixedFunction()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
nErrorCount += TestFixedFunctionBasic();
|
||||
nErrorCount += TestFixedFunctionDtor();
|
||||
nErrorCount += TestFixedFunctionExistingClosure();
|
||||
nErrorCount += TestFixedFunctionReferenceWrapper();
|
||||
nErrorCount += TestFixedFunctionFunctionPointer();
|
||||
nErrorCount += TestFixedFunctionPointerToMemberFunction();
|
||||
nErrorCount += TestFixedFunctionPointerToMemberData();
|
||||
nErrorCount += TestFixedFunctionStdBind();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -0,0 +1,744 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include "EASTLTest.h"
|
||||
#include "TestMap.h"
|
||||
#include "TestSet.h"
|
||||
#include <EASTL/fixed_hash_set.h>
|
||||
#include <EASTL/fixed_hash_map.h>
|
||||
#include <EASTL/fixed_vector.h>
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
struct A
|
||||
{
|
||||
int mX;
|
||||
A(int x = 999) : mX(x) {}
|
||||
};
|
||||
|
||||
inline bool operator==(const A& a1, const A& a2)
|
||||
{ return a1.mX == a2.mX; }
|
||||
|
||||
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
template <>
|
||||
struct hash<A>
|
||||
{
|
||||
size_t operator()(const A& a) const
|
||||
{ return static_cast<size_t>(a.mX); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// For test of user-reported crash.
|
||||
//
|
||||
struct MemoryEntry
|
||||
{
|
||||
size_t mSize;
|
||||
void* mGroup;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// For test of bug reported by Dave Wall, May 14, 2008.
|
||||
//
|
||||
struct InstanceRenderData
|
||||
{
|
||||
static const uint32_t kDataCount = 10; // Bug only occurs with this value.
|
||||
|
||||
uint32_t mPad[kDataCount];
|
||||
|
||||
InstanceRenderData()
|
||||
{
|
||||
memset(mPad, 0, sizeof(mPad));
|
||||
}
|
||||
|
||||
bool operator==(const InstanceRenderData &rhs) const
|
||||
{
|
||||
for(uint32_t index = 0; index < kDataCount; index++)
|
||||
{
|
||||
if(mPad[index] != rhs.mPad[index])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
template <>
|
||||
struct hash<const InstanceRenderData>
|
||||
{
|
||||
size_t operator()(InstanceRenderData val) const
|
||||
{
|
||||
return val.mPad[0];
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<InstanceRenderData>
|
||||
{
|
||||
size_t operator()(InstanceRenderData val) const
|
||||
{
|
||||
return val.mPad[0];
|
||||
}
|
||||
};
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::fixed_hash_set<int, 1, 2>;
|
||||
template class eastl::fixed_hash_map<int, int, 1, 2>;
|
||||
template class eastl::fixed_hash_multiset<int, 1, 2>;
|
||||
template class eastl::fixed_hash_multimap<int, int, 1, 2>;
|
||||
|
||||
template class eastl::fixed_hash_set<A, 1, 2>;
|
||||
template class eastl::fixed_hash_map<A, A, 1, 2>;
|
||||
template class eastl::fixed_hash_multiset<A, 1, 2>;
|
||||
template class eastl::fixed_hash_multimap<A, A, 1, 2>;
|
||||
|
||||
template class eastl::fixed_hash_set<int, 1, 2, true, eastl::hash<int>, eastl::equal_to<int>, true>;
|
||||
template class eastl::fixed_hash_map<int, int, 1, 2, true, eastl::hash<int>, eastl::equal_to<int>, true>;
|
||||
template class eastl::fixed_hash_multiset<int, 1, 2, true, eastl::hash<int>, eastl::equal_to<int>, true>;
|
||||
template class eastl::fixed_hash_multimap<int, int, 1, 2, true, eastl::hash<int>, eastl::equal_to<int>, true>;
|
||||
|
||||
template class eastl::fixed_hash_set<A, 1, 2, true, eastl::hash<A>, eastl::equal_to<A>, true>;
|
||||
template class eastl::fixed_hash_map<A, A, 1, 2, true, eastl::hash<A>, eastl::equal_to<A>, true>;
|
||||
template class eastl::fixed_hash_multiset<A, 1, 2, true, eastl::hash<A>, eastl::equal_to<A>, true>;
|
||||
template class eastl::fixed_hash_multimap<A, A, 1, 2, true, eastl::hash<A>, eastl::equal_to<A>, true>;
|
||||
|
||||
// Custom allocator
|
||||
template class eastl::fixed_hash_set<int, 1, 2, true, eastl::hash<int>, eastl::equal_to<int>, false, MallocAllocator>;
|
||||
template class eastl::fixed_hash_map<int, int, 1, 2, true, eastl::hash<int>, eastl::equal_to<int>, false, MallocAllocator>;
|
||||
template class eastl::fixed_hash_multiset<int, 1, 2, true, eastl::hash<int>, eastl::equal_to<int>, false, MallocAllocator>;
|
||||
template class eastl::fixed_hash_multimap<int, int, 1, 2, true, eastl::hash<int>, eastl::equal_to<int>, false, MallocAllocator>;
|
||||
|
||||
template class eastl::fixed_hash_set<A, 1, 2, true, eastl::hash<A>, eastl::equal_to<A>, false, MallocAllocator>;
|
||||
template class eastl::fixed_hash_map<A, A, 1, 2, true, eastl::hash<A>, eastl::equal_to<A>, false, MallocAllocator>;
|
||||
template class eastl::fixed_hash_multiset<A, 1, 2, true, eastl::hash<A>, eastl::equal_to<A>, false, MallocAllocator>;
|
||||
template class eastl::fixed_hash_multimap<A, A, 1, 2, true, eastl::hash<A>, eastl::equal_to<A>, false, MallocAllocator>;
|
||||
|
||||
|
||||
|
||||
template<typename FixedHashMap, int ELEMENT_MAX, int ITERATION_MAX>
|
||||
int TestFixedHashMapClearBuckets()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
FixedHashMap fixedHashMap;
|
||||
const auto nPreClearBucketCount = fixedHashMap.bucket_count();
|
||||
|
||||
for (int j = 0; j < ITERATION_MAX; j++)
|
||||
{
|
||||
// add elements and ensure container is valid
|
||||
for (int i = 0; i < int(nPreClearBucketCount); i++)
|
||||
fixedHashMap.emplace(i, i);
|
||||
VERIFY(fixedHashMap.validate());
|
||||
|
||||
// ensure contents are expected values
|
||||
for (int i = 0; i < int(nPreClearBucketCount); i++)
|
||||
{
|
||||
auto iter = fixedHashMap.find(i);
|
||||
|
||||
VERIFY(iter != fixedHashMap.end());
|
||||
VERIFY(iter->second == i);
|
||||
}
|
||||
|
||||
// validate container after its cleared its nodes and buckets
|
||||
fixedHashMap.clear(true);
|
||||
VERIFY(fixedHashMap.validate());
|
||||
VERIFY(fixedHashMap.size() == 0);
|
||||
VERIFY(fixedHashMap.bucket_count() == nPreClearBucketCount);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
EA_DISABLE_VC_WARNING(6262)
|
||||
int TestFixedHash()
|
||||
{
|
||||
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() == fixedHashMap.rehash_policy().GetPrevBucketCount(100));
|
||||
}
|
||||
|
||||
{
|
||||
// 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() == fixedHashMap.rehash_policy().GetPrevBucketCount(100));
|
||||
|
||||
// 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 that fixed_hash_map (with and without overflow enabled) is usable after the node and bucket array has
|
||||
// been cleared.
|
||||
{
|
||||
constexpr const int ITERATION_MAX = 5;
|
||||
constexpr const int ELEMENT_MAX = 100;
|
||||
constexpr const int ELEMENT_OVERFLOW_MAX = ELEMENT_MAX * 2;
|
||||
|
||||
TestFixedHashMapClearBuckets<eastl::fixed_hash_map<int, int, ELEMENT_MAX, ELEMENT_MAX, false>, ELEMENT_MAX, ITERATION_MAX>();
|
||||
TestFixedHashMapClearBuckets<eastl::fixed_hash_map<int, int, ELEMENT_MAX, ELEMENT_MAX, true>, ELEMENT_OVERFLOW_MAX, ITERATION_MAX>();
|
||||
TestFixedHashMapClearBuckets<eastl::fixed_hash_multimap<int, int, ELEMENT_MAX, ELEMENT_MAX, false>, ELEMENT_MAX, ITERATION_MAX>();
|
||||
TestFixedHashMapClearBuckets<eastl::fixed_hash_multimap<int, int, ELEMENT_MAX, ELEMENT_MAX, true>, ELEMENT_OVERFLOW_MAX, ITERATION_MAX>();
|
||||
}
|
||||
|
||||
{
|
||||
// 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> >();
|
||||
}
|
||||
|
||||
{
|
||||
// C++17 try_emplace and related functionality
|
||||
nErrorCount += TestMapCpp17<eastl::fixed_hash_map<int, TestObject, 2, 7, true>>();
|
||||
nErrorCount += TestMapCpp17<eastl::fixed_hash_map<int, TestObject, 32, 7, true> >();
|
||||
}
|
||||
|
||||
{
|
||||
// void reserve(size_type nElementCount);
|
||||
|
||||
// test with overflow enabled.
|
||||
nErrorCount += HashContainerReserveTest<fixed_hash_set<int, 16>>()();
|
||||
nErrorCount += HashContainerReserveTest<fixed_hash_multiset<int, 16>>()();
|
||||
nErrorCount += HashContainerReserveTest<fixed_hash_map<int, int, 16>>()();
|
||||
nErrorCount += HashContainerReserveTest<fixed_hash_multimap<int, int, 16>>()();
|
||||
|
||||
// API prevents testing fixed size hash container reservation without overflow enabled.
|
||||
//
|
||||
// nErrorCount += HashContainerReserveTest<fixed_hash_set<int, 400, 401, false>>()();
|
||||
// nErrorCount += HashContainerReserveTest<fixed_hash_multiset<int, 400, 401, false>>()();
|
||||
// nErrorCount += HashContainerReserveTest<fixed_hash_map<int, int, 400, 401, false>>()();
|
||||
// nErrorCount += HashContainerReserveTest<fixed_hash_multimap<int, int, 9000, 9001, false>>()();
|
||||
}
|
||||
|
||||
{
|
||||
// initializer_list support.
|
||||
// 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());
|
||||
}
|
||||
|
||||
{
|
||||
constexpr int ELEM_MAX = 10;
|
||||
typedef eastl::fixed_hash_map<int, int, ELEM_MAX, ELEM_MAX, false> FixedHashMapFalse;
|
||||
FixedHashMapFalse fixedHashMap;
|
||||
VERIFY(fixedHashMap.size() == 0);
|
||||
|
||||
for (int i = 0; i < ELEM_MAX; i++)
|
||||
fixedHashMap.insert(FixedHashMapFalse::value_type(i, i));
|
||||
|
||||
VERIFY(fixedHashMap.validate());
|
||||
VERIFY(fixedHashMap.size() == ELEM_MAX);
|
||||
|
||||
// Verify insert requests of nodes already in the container don't attempt to allocate memory.
|
||||
// Because the fixed_hash_map is full any attempt to allocate memory will generate an OOM error.
|
||||
{
|
||||
auto result = fixedHashMap.insert(FixedHashMapFalse::value_type(0, 0));
|
||||
VERIFY(result.second == false);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = fixedHashMap.insert(fixedHashMap.begin(), FixedHashMapFalse::value_type(0, 0));
|
||||
VERIFY(result->first == 0);
|
||||
VERIFY(result->second == 0);
|
||||
}
|
||||
|
||||
{
|
||||
FixedHashMapFalse::value_type value(0, 0);
|
||||
auto result = fixedHashMap.insert(eastl::move(value));
|
||||
VERIFY(result.second == false);
|
||||
}
|
||||
{
|
||||
FixedHashMapFalse::value_type value(0, 0);
|
||||
auto result = fixedHashMap.insert(fixedHashMap.begin(), eastl::move(value));
|
||||
VERIFY(result->first == 0);
|
||||
VERIFY(result->second == 0);
|
||||
}
|
||||
|
||||
{
|
||||
FixedHashMapFalse::value_type value(0, 0);
|
||||
auto result = fixedHashMap.insert(value);
|
||||
VERIFY(result.second == false);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = fixedHashMap.insert(eastl::make_pair(0, 0));
|
||||
VERIFY(result.second == false);
|
||||
}
|
||||
|
||||
{
|
||||
// OOM, fixed allocator memory is exhausted so it can't create a node for insertation testing
|
||||
// auto result = fixedHashMap.emplace(0, 0);
|
||||
// VERIFY(result.second == false);
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,563 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/fixed_list.h>
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::fixed_list<int, 1, true, EASTLAllocatorType>;
|
||||
template class eastl::fixed_list<int, 1, false, EASTLAllocatorType>;
|
||||
|
||||
|
||||
/*
|
||||
// This does not compile, since the fixed_list allocator is templated on sizeof(T),
|
||||
// not just T. Thus, the full type is required at the time of instantiation, but it
|
||||
// is not available.
|
||||
// See EATech Core JIRA issue ETCR-1608 for more information.
|
||||
struct StructWithContainerOfStructs
|
||||
{
|
||||
eastl::fixed_list<StructWithContainerOfStructs,4> children;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
namespace FixedListTest
|
||||
{
|
||||
struct Item
|
||||
{
|
||||
char mName[5];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
EA_DISABLE_VC_WARNING(6262)
|
||||
int TestFixedList()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
// Test version *without* pool overflow.
|
||||
typedef fixed_list<int, 64, false> FixedListInt64False;
|
||||
|
||||
FixedListInt64False listInt64;
|
||||
VERIFY(listInt64.empty());
|
||||
VERIFY(listInt64.size() == 0);
|
||||
VERIFY(listInt64.max_size() == 64);
|
||||
|
||||
listInt64.push_back(1);
|
||||
VERIFY(!listInt64.empty());
|
||||
VERIFY(listInt64.size() == 1);
|
||||
|
||||
listInt64.resize(3, 2);
|
||||
VERIFY(!listInt64.empty());
|
||||
VERIFY(listInt64.size() == 3);
|
||||
|
||||
FixedListInt64False::iterator i = listInt64.begin();
|
||||
VERIFY(*i == 1); ++i;
|
||||
VERIFY(*i == 2); ++i;
|
||||
VERIFY(*i == 2); ++i;
|
||||
VERIFY(i == listInt64.end());
|
||||
|
||||
listInt64.resize(0);
|
||||
VERIFY(listInt64.empty());
|
||||
VERIFY(listInt64.size() == 0);
|
||||
|
||||
while(listInt64.size() < 64)
|
||||
listInt64.push_back(0);
|
||||
|
||||
// Verify that we allocated enough space for exactly N items.
|
||||
// It's possible that due to alignments, there might be room for N + 1.
|
||||
FixedListInt64False::allocator_type& allocator = listInt64.get_allocator();
|
||||
void* pResult = allocator.allocate(sizeof(FixedListInt64False::node_type));
|
||||
if(pResult)
|
||||
{
|
||||
pResult = allocator.allocate(sizeof(FixedListInt64False::node_type));
|
||||
VERIFY(pResult == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test version *with* pool overflow.
|
||||
typedef fixed_list<int, 64, true> FixedListInt64True;
|
||||
|
||||
FixedListInt64True listInt64;
|
||||
VERIFY(listInt64.empty());
|
||||
VERIFY(listInt64.size() == 0);
|
||||
|
||||
listInt64.push_back(1);
|
||||
VERIFY(!listInt64.empty());
|
||||
VERIFY(listInt64.size() == 1);
|
||||
|
||||
listInt64.resize(3, 2);
|
||||
VERIFY(!listInt64.empty());
|
||||
VERIFY(listInt64.size() == 3);
|
||||
|
||||
FixedListInt64True::iterator i = listInt64.begin();
|
||||
VERIFY(*i == 1); ++i;
|
||||
VERIFY(*i == 2); ++i;
|
||||
VERIFY(*i == 2); ++i;
|
||||
VERIFY(i == listInt64.end());
|
||||
|
||||
listInt64.resize(0);
|
||||
VERIFY(listInt64.empty());
|
||||
VERIFY(listInt64.size() == 0);
|
||||
|
||||
while(listInt64.size() < 64 + 16)
|
||||
listInt64.push_back(0);
|
||||
|
||||
FixedListInt64True::allocator_type& allocator = listInt64.get_allocator();
|
||||
void* pResult = allocator.allocate(sizeof(FixedListInt64True::node_type));
|
||||
VERIFY(pResult != NULL);
|
||||
allocator.deallocate(pResult, sizeof(FixedListInt64True::node_type));
|
||||
|
||||
// get_overflow_allocator / set_overflow_allocator
|
||||
// This is a weak test which should be improved.
|
||||
EASTLAllocatorType a = listInt64.get_allocator().get_overflow_allocator();
|
||||
listInt64.get_allocator().set_overflow_allocator(a);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test version *with* pool overflow with a custom overlow allocator specification.
|
||||
typedef fixed_list<int, 64, true, MallocAllocator> FixedListInt64TrueMalloc;
|
||||
|
||||
FixedListInt64TrueMalloc listInt64;
|
||||
VERIFY(listInt64.empty());
|
||||
VERIFY(listInt64.size() == 0);
|
||||
|
||||
listInt64.push_back(1);
|
||||
VERIFY(!listInt64.empty());
|
||||
VERIFY(listInt64.size() == 1);
|
||||
|
||||
listInt64.resize(3, 2);
|
||||
VERIFY(!listInt64.empty());
|
||||
VERIFY(listInt64.size() == 3);
|
||||
|
||||
FixedListInt64TrueMalloc::iterator i = listInt64.begin();
|
||||
VERIFY(*i == 1); ++i;
|
||||
VERIFY(*i == 2); ++i;
|
||||
VERIFY(*i == 2); ++i;
|
||||
VERIFY(i == listInt64.end());
|
||||
|
||||
listInt64.resize(0);
|
||||
VERIFY(listInt64.empty());
|
||||
VERIFY(listInt64.size() == 0);
|
||||
|
||||
while(listInt64.size() < 64 + 16)
|
||||
listInt64.push_back(0);
|
||||
|
||||
FixedListInt64TrueMalloc::allocator_type& allocator = listInt64.get_allocator();
|
||||
void* pResult = allocator.allocate(sizeof(FixedListInt64TrueMalloc::node_type));
|
||||
VERIFY(pResult != NULL);
|
||||
allocator.deallocate(pResult, sizeof(FixedListInt64TrueMalloc::node_type));
|
||||
}
|
||||
|
||||
{
|
||||
// Test fixed list with overflow and alignment requirements.
|
||||
typedef fixed_list<Align64, 1, true, CustomAllocator> FixedListWithAlignment;
|
||||
|
||||
FixedListWithAlignment fl;
|
||||
|
||||
Align64 a;
|
||||
|
||||
fl.push_back(a);
|
||||
fl.push_back(a);
|
||||
fl.push_back(a);
|
||||
fl.push_back(a);
|
||||
fl.push_back(a);
|
||||
for (FixedListWithAlignment::const_iterator it = fl.begin(); it != fl.end(); ++it)
|
||||
{
|
||||
const Align64* ptr = &(*it);
|
||||
EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// swap
|
||||
|
||||
fixed_list<int, 64>* pListInt64A = new fixed_list<int, 64>;
|
||||
fixed_list<int, 64>* pListInt64B = new fixed_list<int, 64>;
|
||||
|
||||
pListInt64A->push_back(0);
|
||||
pListInt64B->push_back(0);
|
||||
|
||||
swap(*pListInt64A, *pListInt64B);
|
||||
|
||||
delete pListInt64A;
|
||||
delete pListInt64B;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// operator=
|
||||
|
||||
fixed_list<int, 64>* pListInt64A = new fixed_list<int, 64>;
|
||||
fixed_list<int, 64>* pListInt64B = new fixed_list<int, 64>;
|
||||
|
||||
pListInt64A->push_back(0);
|
||||
pListInt64B->push_back(0);
|
||||
|
||||
*pListInt64A = *pListInt64B;
|
||||
|
||||
delete pListInt64A;
|
||||
delete pListInt64B;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// bool empty() const
|
||||
// bool has_overflowed() const
|
||||
// size_type size() const;
|
||||
// size_type max_size() const
|
||||
|
||||
// Test a list that has overflow disabled.
|
||||
fixed_list<int, 5, false> listInt5;
|
||||
|
||||
VERIFY(listInt5.max_size() == 5);
|
||||
VERIFY(listInt5.size() == 0);
|
||||
VERIFY(listInt5.empty());
|
||||
VERIFY(!listInt5.has_overflowed());
|
||||
|
||||
listInt5.push_back(37);
|
||||
listInt5.push_back(37);
|
||||
listInt5.push_back(37);
|
||||
|
||||
VERIFY(listInt5.size() == 3);
|
||||
VERIFY(!listInt5.empty());
|
||||
VERIFY(!listInt5.has_overflowed());
|
||||
|
||||
listInt5.push_back(37);
|
||||
listInt5.push_back(37);
|
||||
|
||||
VERIFY(listInt5.size() == 5);
|
||||
VERIFY(!listInt5.empty());
|
||||
VERIFY(!listInt5.has_overflowed());
|
||||
|
||||
listInt5.pop_back();
|
||||
|
||||
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_list<int, 5, true> listInt5;
|
||||
|
||||
VERIFY(listInt5.max_size() == 5);
|
||||
VERIFY(listInt5.size() == 0);
|
||||
VERIFY(listInt5.empty());
|
||||
VERIFY(!listInt5.has_overflowed());
|
||||
|
||||
listInt5.push_back(37);
|
||||
listInt5.push_back(37);
|
||||
listInt5.push_back(37);
|
||||
|
||||
VERIFY(listInt5.size() == 3);
|
||||
VERIFY(!listInt5.empty());
|
||||
VERIFY(!listInt5.has_overflowed());
|
||||
|
||||
listInt5.push_back(37);
|
||||
listInt5.push_back(37);
|
||||
|
||||
VERIFY(listInt5.size() == 5);
|
||||
VERIFY(!listInt5.empty());
|
||||
VERIFY(!listInt5.has_overflowed());
|
||||
|
||||
listInt5.push_back(37);
|
||||
|
||||
VERIFY(listInt5.size() == 6);
|
||||
VERIFY(!listInt5.empty());
|
||||
VERIFY(listInt5.has_overflowed());
|
||||
|
||||
listInt5.pop_back();
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
{
|
||||
//template <typename Compare>
|
||||
//void merge(this_type& x, Compare compare);
|
||||
//void unique();
|
||||
//template <typename BinaryPredicate>
|
||||
//void unique(BinaryPredicate);
|
||||
//void sort();
|
||||
//template<typename Compare>
|
||||
//void sort(Compare compare);
|
||||
|
||||
const int A[] = {1, 2, 3, 4, 5, 6};
|
||||
const int B[] = {12, 15, 13, 14, 11};
|
||||
const int C[] = {11, 12, 13, 14, 15};
|
||||
const int D[] = {1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6};
|
||||
const int N = sizeof(A) / sizeof(A[0]);
|
||||
const int M = sizeof(B) / sizeof(B[0]);
|
||||
const int Q = sizeof(D) / sizeof(D[0]);
|
||||
|
||||
fixed_list<int, 32, true> list0401(A, A + N);
|
||||
fixed_list<int, 32, true> list0402(B, B + M);
|
||||
fixed_list<int, 32, true> list0403(C, C + M);
|
||||
fixed_list<int, 32, true> list0404(D, D + Q);
|
||||
fixed_list<int, 32, true> list0405(A, A + N);
|
||||
|
||||
list0402.sort(eastl::less<int>());
|
||||
VERIFY(list0402 == list0403);
|
||||
|
||||
list0401.merge(list0402, eastl::less<int>());
|
||||
list0404.sort();
|
||||
|
||||
//merge and isn't yet working for fixed_list.
|
||||
//VERIFY(list0401 == list0404);
|
||||
|
||||
VERIFY(list0401.validate());
|
||||
VERIFY(list0402.validate());
|
||||
VERIFY(list0403.validate());
|
||||
VERIFY(list0404.validate());
|
||||
VERIFY(list0405.validate());
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void sort()
|
||||
// void sort(Compare compare)
|
||||
|
||||
const int kSize = 10;
|
||||
const int A[kSize] = { 1, 9, 2, 3, 5, 7, 4, 6, 8, 0 };
|
||||
|
||||
fixed_list<int, 32, true> listEmpty;
|
||||
VERIFY(VerifySequence(listEmpty.begin(), listEmpty.end(), int(), "fixed_list::sort", -1));
|
||||
listEmpty.sort();
|
||||
VERIFY(VerifySequence(listEmpty.begin(), listEmpty.end(), int(), "fixed_list::sort", -1));
|
||||
|
||||
fixed_list<int, 32, true> list1(A, A + 1);
|
||||
VERIFY(VerifySequence(list1.begin(), list1.end(), int(), "fixed_list::sort", 1, -1));
|
||||
list1.sort();
|
||||
VERIFY(VerifySequence(list1.begin(), list1.end(), int(), "fixed_list::sort", 1, -1));
|
||||
|
||||
fixed_list<int, 32, true> list4(A, A + 4);
|
||||
VERIFY(VerifySequence(list4.begin(), list4.end(), int(), "fixed_list::sort", 1, 9, 2, 3, -1));
|
||||
list4.sort();
|
||||
VERIFY(VerifySequence(list4.begin(), list4.end(), int(), "fixed_list::sort", 1, 2, 3, 9, -1));
|
||||
|
||||
fixed_list<int, 32, true> listA(A, A + kSize);
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::sort", 1, 9, 2, 3, 5, 7, 4, 6, 8, 0, -1));
|
||||
listA.sort();
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::sort", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1));
|
||||
|
||||
listA.assign(A, A + kSize);
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::sort", 1, 9, 2, 3, 5, 7, 4, 6, 8, 0, -1));
|
||||
listA.sort(eastl::less<int>());
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::sort", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void merge(this_type& x);
|
||||
// void merge(this_type& x, Compare compare);
|
||||
|
||||
const int kSize = 8;
|
||||
const int A[kSize] = { 1, 2, 3, 4, 4, 5, 9, 9 };
|
||||
const int B[kSize] = { 1, 2, 3, 4, 4, 5, 9, 9 };
|
||||
|
||||
fixed_list<int, 32, true> listA(A, A + kSize);
|
||||
fixed_list<int, 32, true> listB(B, B + kSize);
|
||||
|
||||
listA.merge(listB);
|
||||
|
||||
//merge and isn't yet working for fixed_list.
|
||||
//VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_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(), "fixed_list::merge", -1));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void splice(iterator position, this_type& x);
|
||||
// void splice(iterator position, this_type& x, iterator i);
|
||||
// void splice(iterator position, this_type& x, iterator first, iterator last);
|
||||
|
||||
const int kSize = 8;
|
||||
const int A[kSize] = { 1, 2, 3, 4, 4, 5, 9, 9 };
|
||||
const int B[kSize] = { 1, 2, 3, 4, 4, 5, 9, 9 };
|
||||
|
||||
fixed_list<int, 32, true> listA(A, A + kSize);
|
||||
fixed_list<int, 32, true> listB(B, B + kSize);
|
||||
fixed_list<int, 32, true>::iterator it;
|
||||
|
||||
// void splice(iterator position, this_type& x);
|
||||
it = listA.begin(); eastl::advance(it, 2);
|
||||
listA.splice(it, listB); // move listB into listA at position it.
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::splice", 1, 2, 1, 2, 3, 4, 4, 5, 9, 9, 3, 4, 4, 5, 9, 9, -1));
|
||||
VERIFY(VerifySequence(listB.begin(), listB.end(), int(), "fixed_list::splice", -1));
|
||||
|
||||
// void splice(iterator position, this_type& x, iterator i);
|
||||
it = listA.begin(); eastl::advance(it, 6);
|
||||
listB.splice(listB.begin(), listA, it); // move listA's it (6th element) into the front of listB.
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::splice", 1, 2, 1, 2, 3, 4, 5, 9, 9, 3, 4, 4, 5, 9, 9, -1));
|
||||
VERIFY(VerifySequence(listB.begin(), listB.end(), int(), "fixed_list::splice", 4, -1));
|
||||
|
||||
// void splice(iterator position, this_type& x, iterator first, iterator last);
|
||||
listA.splice(listA.end(), listB, listB.begin(), listB.end()); // move listB into listA at the end of listA.
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::splice", 1, 2, 1, 2, 3, 4, 5, 9, 9, 3, 4, 4, 5, 9, 9, 4, -1));
|
||||
VERIFY(VerifySequence(listB.begin(), listB.end(), int(), "fixed_list::splice", -1));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void unique();
|
||||
// void unique(BinaryPredicate);
|
||||
|
||||
const int kSize = 8;
|
||||
const int A[kSize] = { 1, 2, 3, 4, 4, 5, 9, 9 };
|
||||
const int B[kSize] = { 1, 2, 3, 4, 4, 5, 9, 9 };
|
||||
|
||||
fixed_list<int, 32, true> listA(A, A + kSize);
|
||||
listA.unique();
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::unique", 1, 2, 3, 4, 5, 9, -1));
|
||||
|
||||
fixed_list<int, 32, true> listB(B, B + kSize);
|
||||
listB.unique(eastl::equal_to<int>());
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "fixed_list::unique", 1, 2, 3, 4, 5, 9, -1));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// fixed_list(this_type&& x);
|
||||
// fixed_list(this_type&&, const allocator_type&);
|
||||
// this_type& operator=(this_type&& x);
|
||||
fixed_list<TestObject, 16> list3TO33(3, TestObject(33));
|
||||
fixed_list<TestObject, 16> toListA(eastl::move(list3TO33));
|
||||
EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == 33) /* && (list3TO33.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_list<TestObject, 16, true, MallocAllocator> list4TO44(4, TestObject(44));
|
||||
fixed_list<TestObject, 16, true, MallocAllocator> toListB(eastl::move(list4TO44), MallocAllocator());
|
||||
EATEST_VERIFY((toListB.size() == 4) && (toListB.front().mX == 44) /* && (list4TO44.size() == 0) fixed_list usually can't honor the move request. */);
|
||||
|
||||
fixed_list<TestObject, 16, true, MallocAllocator> list5TO55(5, TestObject(55));
|
||||
toListB = eastl::move(list5TO55);
|
||||
EATEST_VERIFY((toListB.size() == 5) && (toListB.front().mX == 55) /* && (list5TO55.size() == 0) fixed_list usually can't honor the move request. */);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// template <class... Args>
|
||||
// void emplace_front(Args&&... args);
|
||||
|
||||
// template <class... Args>
|
||||
// void emplace_back(Args&&... args);
|
||||
|
||||
// template <class... Args>
|
||||
// iterator emplace(const_iterator position, Args&&... args);
|
||||
|
||||
TestObject::Reset();
|
||||
|
||||
fixed_list<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_back(2, 3, 4);
|
||||
EATEST_VERIFY((toListA.size() == 2) && (toListA.back().mX == (2+3+4)) && (TestObject::sTOCtorCount == 2));
|
||||
|
||||
toListA.emplace(toListA.begin(), 3, 4, 5);
|
||||
EATEST_VERIFY((toListA.size() == 3) && (toListA.front().mX == (3+4+5)) && (TestObject::sTOCtorCount == 3));
|
||||
|
||||
|
||||
// This test is similar to the emplace pathway above.
|
||||
TestObject::Reset();
|
||||
|
||||
// void push_front(T&& x);
|
||||
// void push_back(T&& x);
|
||||
// iterator insert(const_iterator position, T&& x);
|
||||
|
||||
fixed_list<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.push_back(TestObject(2, 3, 4));
|
||||
EATEST_VERIFY((toListC.size() == 2) && (toListC.back().mX == (2+3+4)) && (TestObject::sTOMoveCtorCount == 2));
|
||||
|
||||
toListC.insert(toListC.begin(), TestObject(3, 4, 5));
|
||||
EATEST_VERIFY((toListC.size() == 3) && (toListC.front().mX == (3+4+5)) && (TestObject::sTOMoveCtorCount == 3));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// list(std::initializer_list<value_type> ilist, const allocator_type& allocator = EASTL_LIST_DEFAULT_ALLOCATOR);
|
||||
// this_type& operator=(std::initializer_list<value_type> ilist);
|
||||
// void assign(std::initializer_list<value_type> ilist);
|
||||
// iterator insert(iterator position, std::initializer_list<value_type> ilist);
|
||||
list<int> intList = { 0, 1, 2 };
|
||||
EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "list std::initializer_list", 0, 1, 2, -1));
|
||||
|
||||
intList = { 13, 14, 15 };
|
||||
EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "list std::initializer_list", 13, 14, 15, -1));
|
||||
|
||||
intList.assign({ 16, 17, 18 });
|
||||
EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "list std::initializer_list", 16, 17, 18, -1));
|
||||
|
||||
intList.insert(intList.begin(), { 14, 15 });
|
||||
EATEST_VERIFY(VerifySequence(intList.begin(), intList.end(), int(), "list std::initializer_list", 14, 15, 16, 17, 18, -1));
|
||||
}
|
||||
|
||||
|
||||
{ // Regression of user test
|
||||
struct Dummy
|
||||
{
|
||||
typedef eastl::fixed_list<FixedListTest::Item, 10, false> TCollection;
|
||||
|
||||
TCollection mCollection1;
|
||||
TCollection mCollection2;
|
||||
};
|
||||
|
||||
Dummy d;
|
||||
VERIFY(d.mCollection1.size() == d.mCollection2.size());
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test construction of a container with an overflow allocator constructor argument.
|
||||
MallocAllocator overflowAllocator;
|
||||
void* p = overflowAllocator.allocate(1);
|
||||
fixed_list<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);
|
||||
}
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include "TestMap.h"
|
||||
#include <EASTL/fixed_map.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <map>
|
||||
#endif
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::fixed_map <int, float, 1>;
|
||||
template class eastl::fixed_multimap<float, int, 1>;
|
||||
template class eastl::fixed_map <int, TestObject, 1>;
|
||||
template class eastl::fixed_multimap<TestObject, int, 1>;
|
||||
|
||||
template class eastl::fixed_map <int, float, 1, true, eastl::less<int>, MallocAllocator>;
|
||||
template class eastl::fixed_multimap<float, int, 1, true, eastl::less<float>, MallocAllocator>;
|
||||
template class eastl::fixed_map <int, TestObject, 1, true, eastl::less<int>, MallocAllocator>;
|
||||
template class eastl::fixed_multimap<TestObject, int, 1, true, eastl::less<TestObject>, MallocAllocator>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// typedefs
|
||||
//
|
||||
const eastl_size_t kContainerSize = 1000;
|
||||
|
||||
typedef eastl::fixed_map<int, int, kContainerSize> VM1;
|
||||
typedef eastl::fixed_map<TestObject, TestObject, kContainerSize> VM4;
|
||||
typedef eastl::fixed_multimap<int, int, kContainerSize> VMM1;
|
||||
typedef eastl::fixed_multimap<TestObject, TestObject, kContainerSize> VMM4;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
typedef std::map<int, int> VM3;
|
||||
typedef std::map<TestObject, TestObject> VM6;
|
||||
typedef std::multimap<int, int> VMM3;
|
||||
typedef std::multimap<TestObject, TestObject> VMM6;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
EA_DISABLE_VC_WARNING(6262)
|
||||
int TestFixedMap()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
{ // Test construction
|
||||
nErrorCount += TestMapConstruction<VM1, VM3, false>();
|
||||
nErrorCount += TestMapConstruction<VM4, VM6, false>();
|
||||
|
||||
nErrorCount += TestMapConstruction<VMM1, VMM3, true>();
|
||||
nErrorCount += TestMapConstruction<VMM4, VMM6, true>();
|
||||
}
|
||||
|
||||
|
||||
{ // Test mutating functionality.
|
||||
nErrorCount += TestMapMutation<VM1, VM3, false>();
|
||||
nErrorCount += TestMapMutation<VM4, VM6, false>();
|
||||
|
||||
nErrorCount += TestMapMutation<VMM1, VMM3, true>();
|
||||
nErrorCount += TestMapMutation<VMM4, VMM6, true>();
|
||||
}
|
||||
#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
|
||||
{ // Test searching functionality.
|
||||
nErrorCount += TestMapSearch<VM1, false>();
|
||||
nErrorCount += TestMapSearch<VM4, false>();
|
||||
|
||||
nErrorCount += TestMapSearch<VMM1, true>();
|
||||
nErrorCount += TestMapSearch<VMM4, true>();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// C++11 emplace and related functionality
|
||||
nErrorCount += TestMapCpp11<eastl::fixed_map<int, TestObject, 32> >();
|
||||
|
||||
nErrorCount += TestMultimapCpp11<eastl::fixed_multimap<int, TestObject, 32> >();
|
||||
|
||||
nErrorCount += TestMapCpp11NonCopyable<eastl::fixed_map<int, NonCopyable, 32>>();
|
||||
}
|
||||
|
||||
{
|
||||
// C++17 try_emplace and related functionality
|
||||
nErrorCount += TestMapCpp17<eastl::fixed_map<int, TestObject, 32>>();
|
||||
}
|
||||
|
||||
|
||||
{ // Test functionality specific to fixed size containers.
|
||||
|
||||
VM1 vm1;
|
||||
VMM1 vmm1;
|
||||
|
||||
VERIFY(vm1.max_size() == kContainerSize);
|
||||
VERIFY(vmm1.max_size() == kContainerSize);
|
||||
}
|
||||
|
||||
|
||||
{ // Regression of bug report by Eric Turmel, May 20, 2008
|
||||
typedef eastl::fixed_map<int, TestObject, 37, false> FixedMap;
|
||||
VERIFY(FixedMap::kMaxSize == 37);
|
||||
|
||||
FixedMap fixedMap;
|
||||
FixedMap::fixed_allocator_type& a = fixedMap.get_allocator();
|
||||
|
||||
for(int i = 0; i < FixedMap::kMaxSize; i++)
|
||||
{
|
||||
VERIFY(a.can_allocate());
|
||||
|
||||
fixedMap.insert(FixedMap::value_type(i, TestObject(i)));
|
||||
|
||||
#if EASTL_FIXED_SIZE_TRACKING_ENABLED
|
||||
// Disabled because mPool is (mistakenly) inaccessible.
|
||||
// VERIFY((a.mPool.mnCurrentSize == a.mPool.mnPeakSize) && (a.mPool.mnCurrentSize == i));
|
||||
#endif
|
||||
}
|
||||
|
||||
VERIFY(!a.can_allocate());
|
||||
}
|
||||
|
||||
{
|
||||
// Test fixed set with overflow and alignment requirements.
|
||||
typedef fixed_map<Align64, int, 1, true> FixedMapWithAlignment;
|
||||
typedef fixed_multimap<Align64, int, 1, true> FixedMultiMapWithAlignment;
|
||||
|
||||
FixedMapWithAlignment fm;
|
||||
FixedMultiMapWithAlignment fmm;
|
||||
|
||||
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;
|
||||
|
||||
fm.insert(a);
|
||||
fm.insert(b);
|
||||
fm.insert(c);
|
||||
fm.insert(d);
|
||||
fm.insert(e);
|
||||
for (FixedMapWithAlignment::const_iterator it = fm.begin(); it != fm.end(); ++it)
|
||||
{
|
||||
const Align64* ptr = &((*it).first);
|
||||
EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
|
||||
}
|
||||
|
||||
fmm.insert(a);
|
||||
fmm.insert(b);
|
||||
fmm.insert(c);
|
||||
fmm.insert(d);
|
||||
fmm.insert(e);
|
||||
for (FixedMultiMapWithAlignment::const_iterator it = fmm.begin(); it != fmm.end(); ++it)
|
||||
{
|
||||
const Align64* ptr = &((*it).first);
|
||||
EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/fixed_slist.h>
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::fixed_slist<int, 1, true, EASTLAllocatorType>;
|
||||
template class eastl::fixed_slist<int, 1, false, EASTLAllocatorType>;
|
||||
|
||||
|
||||
/*
|
||||
// This does not compile, since the fixed_slist allocator is templated on sizeof(T),
|
||||
// not just T. Thus, the full type is required at the time of instantiation, but it
|
||||
// is not available.
|
||||
// See EATech Core JIRA issue ETCR-1608 for more information.
|
||||
struct StructWithContainerOfStructs
|
||||
{
|
||||
eastl::fixed_slist<StructWithContainerOfStructs,4> children;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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. */);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// template <class... Args>
|
||||
// void emplace_front(Args&&... args);
|
||||
|
||||
// template <class... Args>
|
||||
// iterator emplace_after(const_iterator position, Args&&... args);
|
||||
|
||||
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));
|
||||
|
||||
|
||||
// This test is similar to the emplace 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));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include "TestSet.h"
|
||||
#include <EASTL/fixed_set.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <set>
|
||||
#endif
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::fixed_set <int, 1>;
|
||||
template class eastl::fixed_multiset<float, 1>;
|
||||
template class eastl::fixed_set <Align64, 1>;
|
||||
template class eastl::fixed_multiset<TestObject, 1>;
|
||||
|
||||
|
||||
template class eastl::fixed_set <int, 1, true, eastl::less<int>, MallocAllocator>;
|
||||
template class eastl::fixed_multiset<float, 1, true, eastl::less<float>, MallocAllocator>;
|
||||
template class eastl::fixed_set <Align64, 1, true, eastl::less<Align64>, MallocAllocator>;
|
||||
template class eastl::fixed_multiset<TestObject, 1, true, eastl::less<TestObject>, MallocAllocator>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// typedefs
|
||||
//
|
||||
const eastl_size_t kContainerSize = 1000;
|
||||
|
||||
typedef eastl::fixed_set<int, kContainerSize> VS1;
|
||||
typedef eastl::fixed_set<TestObject, kContainerSize> VS4;
|
||||
typedef eastl::fixed_multiset<int, kContainerSize> VMS1;
|
||||
typedef eastl::fixed_multiset<TestObject, kContainerSize> VMS4;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
typedef std::set<int> VS3;
|
||||
typedef std::set<TestObject> VS6;
|
||||
typedef std::multiset<int> VMS3;
|
||||
typedef std::multiset<TestObject> VMS6;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
EA_DISABLE_VC_WARNING(6262)
|
||||
int TestFixedSet()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
{ // Test construction
|
||||
nErrorCount += TestSetConstruction<VS1, VS3, false>();
|
||||
nErrorCount += TestSetConstruction<VS4, VS6, false>();
|
||||
|
||||
nErrorCount += TestSetConstruction<VMS1, VMS3, true>();
|
||||
nErrorCount += TestSetConstruction<VMS4, VMS6, true>();
|
||||
}
|
||||
|
||||
|
||||
{ // Test mutating functionality.
|
||||
nErrorCount += TestSetMutation<VS1, VS3, false>();
|
||||
nErrorCount += TestSetMutation<VS4, VS6, false>();
|
||||
|
||||
nErrorCount += TestSetMutation<VMS1, VMS3, true>();
|
||||
nErrorCount += TestSetMutation<VMS4, VMS6, true>();
|
||||
}
|
||||
#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
|
||||
{ // Test searching functionality.
|
||||
nErrorCount += TestSetSearch<VS1, false>();
|
||||
nErrorCount += TestSetSearch<VS4, false>();
|
||||
|
||||
nErrorCount += TestSetSearch<VMS1, true>();
|
||||
nErrorCount += TestSetSearch<VMS4, true>();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// C++11 emplace and related functionality
|
||||
nErrorCount += TestSetCpp11<eastl::fixed_set<TestObject, 32> >();
|
||||
|
||||
nErrorCount += TestMultisetCpp11<eastl::fixed_multiset<TestObject, 32> >();
|
||||
}
|
||||
|
||||
|
||||
{ // Test functionality specific to fixed size containers.
|
||||
|
||||
VS1 vs1;
|
||||
VMS1 vms1;
|
||||
|
||||
VERIFY(vs1.max_size() == kContainerSize);
|
||||
VERIFY(vms1.max_size() == kContainerSize);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test version *without* pool overflow.
|
||||
typedef eastl::fixed_set<int, 100, false> FixedSetFalse;
|
||||
FixedSetFalse fixedSet;
|
||||
|
||||
fixedSet.insert(FixedSetFalse::value_type(0));
|
||||
VERIFY(fixedSet.size() == 1);
|
||||
|
||||
fixedSet.clear();
|
||||
VERIFY(fixedSet.size() == 0);
|
||||
|
||||
for(int i = 0; fixedSet.size() < 100; i++)
|
||||
fixedSet.insert(FixedSetFalse::value_type(i));
|
||||
VERIFY(fixedSet.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.
|
||||
FixedSetFalse::allocator_type& allocator = fixedSet.get_allocator();
|
||||
void* pResult = allocator.allocate(sizeof(FixedSetFalse::node_type));
|
||||
if(pResult)
|
||||
{
|
||||
pResult = allocator.allocate(sizeof(FixedSetFalse::node_type));
|
||||
VERIFY(pResult == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test version *with* pool overflow.
|
||||
typedef eastl::fixed_set<int, 100, true> FixedSetTrue;
|
||||
FixedSetTrue fixedSet;
|
||||
|
||||
fixedSet.insert(FixedSetTrue::value_type(0));
|
||||
VERIFY(fixedSet.size() == 1);
|
||||
|
||||
fixedSet.clear();
|
||||
VERIFY(fixedSet.size() == 0);
|
||||
|
||||
for(int i = 0; fixedSet.size() < 100; i++)
|
||||
fixedSet.insert(FixedSetTrue::value_type(i));
|
||||
VERIFY(fixedSet.size() == 100);
|
||||
|
||||
FixedSetTrue::allocator_type& allocator = fixedSet.get_allocator();
|
||||
void* pResult = allocator.allocate(sizeof(FixedSetTrue::node_type));
|
||||
VERIFY(pResult != NULL);
|
||||
allocator.deallocate(pResult, sizeof(FixedSetTrue::node_type));
|
||||
|
||||
// get_overflow_allocator / set_overflow_allocator
|
||||
// This is a weak test which should be improved.
|
||||
EASTLAllocatorType a = fixedSet.get_allocator().get_overflow_allocator();
|
||||
fixedSet.get_allocator().set_overflow_allocator(a);
|
||||
}
|
||||
|
||||
{
|
||||
// Test fixed set with overflow and alignment requirements.
|
||||
typedef fixed_set<Align64, 1, true> FixedSetWithAlignment;
|
||||
typedef fixed_multiset<Align64, 1, true> FixedMultiSetWithAlignment;
|
||||
|
||||
FixedSetWithAlignment fs;
|
||||
FixedMultiSetWithAlignment fms;
|
||||
|
||||
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;
|
||||
|
||||
fs.insert(a);
|
||||
fs.insert(b);
|
||||
fs.insert(c);
|
||||
fs.insert(d);
|
||||
fs.insert(e);
|
||||
for (FixedSetWithAlignment::const_iterator it = fs.begin(); it != fs.end(); ++it)
|
||||
{
|
||||
const Align64* ptr = &(*it);
|
||||
EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
|
||||
}
|
||||
fms.insert(a);
|
||||
fms.insert(b);
|
||||
fms.insert(c);
|
||||
fms.insert(d);
|
||||
fms.insert(e);
|
||||
for (FixedMultiSetWithAlignment::const_iterator it = fms.begin(); it != fms.end(); ++it)
|
||||
{
|
||||
const Align64* ptr = &(*it);
|
||||
EATEST_VERIFY((uint64_t)ptr % EASTL_ALIGN_OF(Align64) == 0);
|
||||
}
|
||||
}
|
||||
return nErrorCount;
|
||||
}
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,500 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
EA_DISABLE_GCC_WARNING(-Warray-bounds)
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/fixed_string.h>
|
||||
#include <EASTL/fixed_substring.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::fixed_string<char8_t, 1, true>;
|
||||
template class eastl::fixed_string<char16_t, 1, true>;
|
||||
template class eastl::fixed_string<char32_t, 1, true>;
|
||||
|
||||
template class eastl::fixed_string<char8_t, 128, false>;
|
||||
template class eastl::fixed_string<char16_t, 128, false>;
|
||||
template class eastl::fixed_string<char32_t, 128, false>;
|
||||
|
||||
template class eastl::fixed_string<char8_t, 128, true, MallocAllocator>;
|
||||
template class eastl::fixed_string<char16_t, 128, true, MallocAllocator>;
|
||||
template class eastl::fixed_string<char32_t, 128, true, MallocAllocator>;
|
||||
|
||||
template class eastl::fixed_string<char8_t, 128, false, MallocAllocator>;
|
||||
template class eastl::fixed_string<char16_t, 128, false, MallocAllocator>;
|
||||
template class eastl::fixed_string<char32_t, 128, false, MallocAllocator>;
|
||||
|
||||
template class eastl::fixed_substring<char8_t>;
|
||||
template class eastl::fixed_substring<char16_t>;
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// This does not compile, since the fixed_string allocator (among other things) is
|
||||
// templated on sizeof(T), not just T. Thus, the full type is required at the time
|
||||
// of instantiation, but it is not available.
|
||||
// See EATech Core JIRA issue ETCR-1608 for more information.
|
||||
struct StructWithContainerOfStructs
|
||||
{
|
||||
eastl::fixed_string<StructWithContainerOfStructs,4> children;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
int TestFixedSubstring()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
const char* pSource1 = "hello world";
|
||||
const char* pSource2 = "hola mundo";
|
||||
|
||||
basic_string<char> str(pSource1);
|
||||
fixed_substring<char> sub(str, 2, 5);
|
||||
|
||||
EATEST_VERIFY(sub.size() == 5);
|
||||
EATEST_VERIFY(sub[0] == 'l');
|
||||
EATEST_VERIFY(sub == "llo w");
|
||||
|
||||
sub.assign(pSource2);
|
||||
EATEST_VERIFY(sub.size() == 10);
|
||||
EATEST_VERIFY(sub[0] == pSource2[0]);
|
||||
EATEST_VERIFY(sub == pSource2);
|
||||
|
||||
fixed_substring<char> sub2(sub);
|
||||
EATEST_VERIFY(sub2.size() == 10);
|
||||
EATEST_VERIFY(sub2[0] == pSource2[0]);
|
||||
EATEST_VERIFY(sub2 == pSource2);
|
||||
|
||||
sub.assign(sub2, 1, 3);
|
||||
EATEST_VERIFY(sub.size() == 3);
|
||||
EATEST_VERIFY(sub == "ola");
|
||||
|
||||
sub.assign(pSource2, 3);
|
||||
EATEST_VERIFY(sub.size() == 3);
|
||||
EATEST_VERIFY(sub == "hol");
|
||||
|
||||
sub.assign(pSource2, pSource2 + 4);
|
||||
EATEST_VERIFY(sub.size() == 4);
|
||||
EATEST_VERIFY(sub == "hola");
|
||||
|
||||
sub = pSource1;
|
||||
EATEST_VERIFY(sub.size() == strlen(pSource1));
|
||||
EATEST_VERIFY(sub == pSource1);
|
||||
}
|
||||
|
||||
|
||||
{ // Test fixed_substring with a C character array
|
||||
char pArray[256];
|
||||
fixed_substring<char> str(pArray, 255);
|
||||
|
||||
str.resize(5);
|
||||
EATEST_VERIFY(str.size() == 5);
|
||||
|
||||
str[0] = 'a';
|
||||
EATEST_VERIFY(str[0] == 'a');
|
||||
|
||||
str.sprintf("Hello %s", "world");
|
||||
EATEST_VERIFY(str == "Hello world");
|
||||
|
||||
str += " Hola mundo";
|
||||
EATEST_VERIFY(str == "Hello world Hola mundo");
|
||||
|
||||
str.pop_back();
|
||||
EATEST_VERIFY(str == "Hello world Hola mund");
|
||||
|
||||
str.replace(6, 5, "abcdefghijlk");
|
||||
EATEST_VERIFY(str == "Hello abcdefghijlk Hola mund");
|
||||
|
||||
str.clear();
|
||||
EATEST_VERIFY(str.empty());
|
||||
EATEST_VERIFY(str == "");
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Check that copies/moves don't become independent strings.
|
||||
// They should all point to the same sub-string.
|
||||
string str = "hello world";
|
||||
fixed_substring<char> sub(str, 2, 5);
|
||||
|
||||
EATEST_VERIFY(sub.size() == 5);
|
||||
EATEST_VERIFY(sub[0] == 'l');
|
||||
EATEST_VERIFY(sub == "llo w");
|
||||
|
||||
vector<fixed_substring<char>> v;
|
||||
for (eastl_size_t i = 0; i < 1000; ++i) {
|
||||
v.push_back(sub);
|
||||
}
|
||||
|
||||
sub[0] = 'g';
|
||||
EATEST_VERIFY(str == "heglo world");
|
||||
EATEST_VERIFY(sub == "glo w");
|
||||
|
||||
for (const auto& s : v){
|
||||
EATEST_VERIFY(s == "glo w");
|
||||
}
|
||||
|
||||
// copy construct
|
||||
fixed_substring<char> sub2 = sub;
|
||||
|
||||
// copy assign
|
||||
fixed_substring<char> sub3;
|
||||
sub3 = sub;
|
||||
|
||||
// move construct
|
||||
fixed_substring<char> sub4 = eastl::move(sub);
|
||||
|
||||
// move assign
|
||||
fixed_substring<char> sub_again(str, 2, 5);
|
||||
fixed_substring<char> sub5;
|
||||
sub5 = eastl::move(sub_again);
|
||||
|
||||
EATEST_VERIFY(sub2 == "glo w");
|
||||
EATEST_VERIFY(sub3 == "glo w");
|
||||
EATEST_VERIFY(sub4 == "glo w");
|
||||
EATEST_VERIFY(sub5 == "glo w");
|
||||
|
||||
str[5] = 'g';
|
||||
EATEST_VERIFY(sub2 == "glogw");
|
||||
EATEST_VERIFY(sub3 == "glogw");
|
||||
EATEST_VERIFY(sub4 == "glogw");
|
||||
EATEST_VERIFY(sub5 == "glogw");
|
||||
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
int TestFixedString()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
fixed_string<char, 64>::CtorSprintf cs;
|
||||
|
||||
fixed_string<char, 64> s8(cs, "hello world %d.", 1);
|
||||
EATEST_VERIFY(s8 == "hello world 1.");
|
||||
EATEST_VERIFY(s8.capacity() == 63); // 63 because the 64 includes the terminating 0, but capacity() subtracts the terminating 0 usage.
|
||||
EATEST_VERIFY(s8.max_size() == 63);
|
||||
|
||||
s8.append_sprintf(" More hello %d.", 2);
|
||||
EATEST_VERIFY(s8 == "hello world 1. More hello 2.");
|
||||
EATEST_VERIFY(s8.capacity() == 63);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
fixed_string<wchar_t, 64>::CtorSprintf cs;
|
||||
|
||||
fixed_string<wchar_t, 64> sW(cs, L"hello world %d.", 1);
|
||||
EATEST_VERIFY(sW == L"hello world 1.");
|
||||
EATEST_VERIFY(sW.capacity() == 63); // 63 because the 64 includes the terminating 0, but capacity() subtracts the terminating 0 usage.
|
||||
|
||||
sW.append_sprintf(L" More hello %d.", 2);
|
||||
EATEST_VERIFY(sW == L"hello world 1. More hello 2.");
|
||||
EATEST_VERIFY(sW.capacity() == 63); // 63 because the 64 includes the terminating 0, but capacity() subtracts the terminating 0 usage.
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
typedef fixed_string<char8_t, 64, true> FixedString64;
|
||||
typedef fixed_string<char8_t, 64, false> FixedString64NoOverflow;
|
||||
FixedString64::CtorSprintf cs;
|
||||
FixedString64::CtorDoNotInitialize cdni;
|
||||
|
||||
// fixed_string();
|
||||
FixedString64 fs1;
|
||||
EATEST_VERIFY(fs1.size() == 0);
|
||||
EATEST_VERIFY(fs1.capacity() == 63);
|
||||
|
||||
FixedString64NoOverflow fsNo;
|
||||
EATEST_VERIFY(fs1.can_overflow() == true);
|
||||
EATEST_VERIFY(fsNo.can_overflow() == false);
|
||||
EATEST_VERIFY(fs1.full() == false);
|
||||
EATEST_VERIFY(fs1.has_overflowed() == false);
|
||||
|
||||
const char8_t* pCStr = fs1.c_str();
|
||||
EATEST_VERIFY(*pCStr == 0);
|
||||
|
||||
// fixed_string(const this_type& x);
|
||||
FixedString64 fs2(fs1);
|
||||
EATEST_VERIFY(fs2.size() == 0);
|
||||
EATEST_VERIFY(fs2.capacity() == 63);
|
||||
|
||||
fs1 = EA_CHAR8("abc");
|
||||
FixedString64 fs3(fs1);
|
||||
EATEST_VERIFY(fs3.size() == 3);
|
||||
EATEST_VERIFY(fs3.capacity() == 63);
|
||||
EATEST_VERIFY(fs3 == EA_CHAR8("abc"));
|
||||
|
||||
// fixed_string(const this_type& x, size_type position, size_type n = npos);
|
||||
FixedString64 fs4(fs1, 1, 2);
|
||||
EATEST_VERIFY(fs4.size() == 2);
|
||||
EATEST_VERIFY(fs4.capacity() == 63);
|
||||
EATEST_VERIFY(fs4 == EA_CHAR8("bc"));
|
||||
|
||||
// fixed_string(const value_type* p, size_type n);
|
||||
FixedString64 fs5(EA_CHAR8("abcdef"), 6);
|
||||
EATEST_VERIFY(fs5.size() == 6);
|
||||
EATEST_VERIFY(fs5.capacity() == 63);
|
||||
EATEST_VERIFY(fs5 == EA_CHAR8("abcdef"));
|
||||
|
||||
// fixed_string(const value_type* p);
|
||||
FixedString64 fs6(EA_CHAR8("abcdef"));
|
||||
EATEST_VERIFY(fs6.size() == 6);
|
||||
EATEST_VERIFY(fs6.capacity() == 63);
|
||||
EATEST_VERIFY(fs6 == EA_CHAR8("abcdef"));
|
||||
|
||||
// fixed_string(size_type n, const value_type& value);
|
||||
FixedString64 fs7(8, 'a');
|
||||
EATEST_VERIFY(fs7.size() == 8);
|
||||
EATEST_VERIFY(fs7.capacity() == 63);
|
||||
EATEST_VERIFY(fs7 == EA_CHAR8("aaaaaaaa"));
|
||||
|
||||
// fixed_string(const value_type* pBegin, const value_type* pEnd);
|
||||
FixedString64 fs8(&fs6[0], &fs6[5]);
|
||||
EATEST_VERIFY(fs8.size() == 5);
|
||||
EATEST_VERIFY(fs8.capacity() == 63);
|
||||
EATEST_VERIFY(fs8 == EA_CHAR8("abcde"));
|
||||
|
||||
// fixed_string(CtorDoNotInitialize, size_type n);
|
||||
FixedString64 fs9(cdni, 7);
|
||||
EATEST_VERIFY(fs9.size() == 7);
|
||||
EATEST_VERIFY(fs9.capacity() == 63);
|
||||
|
||||
// fixed_string(CtorSprintf, const value_type* pFormat, ...);
|
||||
FixedString64 fs10(cs, EA_CHAR8("%d"), 37);
|
||||
EATEST_VERIFY(fs10.size() == 2);
|
||||
EATEST_VERIFY(fs10.capacity() == 63);
|
||||
EATEST_VERIFY(fs10 == EA_CHAR8("37"));
|
||||
|
||||
// this_type& operator=(const const value_type* p);
|
||||
// this_type& operator=(const this_type& x);
|
||||
fs9 = EA_CHAR8("hello");
|
||||
EATEST_VERIFY(fs9 == EA_CHAR8("hello"));
|
||||
|
||||
fs9 = fs10;
|
||||
EATEST_VERIFY(fs9 == fs10);
|
||||
EATEST_VERIFY(fs9 == EA_CHAR8("37"));
|
||||
|
||||
// void swap(this_type& x);
|
||||
swap(fs7, fs9);
|
||||
EATEST_VERIFY(fs7 == EA_CHAR8("37"));
|
||||
EATEST_VERIFY(fs9 == EA_CHAR8("aaaaaaaa"));
|
||||
|
||||
// void set_capacity(size_type n);
|
||||
fs9.set_capacity(100);
|
||||
EATEST_VERIFY(fs9.size() == 8);
|
||||
EATEST_VERIFY(fs9.capacity() == 100);
|
||||
EATEST_VERIFY(fs9.full() == true);
|
||||
EATEST_VERIFY(fs9.has_overflowed() == true);
|
||||
|
||||
fs9.set_capacity(100); // EATEST_VERIFY that this has no effect.
|
||||
EATEST_VERIFY(fs9.size() == 8);
|
||||
EATEST_VERIFY(fs9.capacity() == 100);
|
||||
EATEST_VERIFY(fs9.full() == true);
|
||||
EATEST_VERIFY(fs9.has_overflowed() == true);
|
||||
|
||||
fs9.resize(100);
|
||||
fs9.set_capacity(100);
|
||||
EATEST_VERIFY(fs9.size() == 100);
|
||||
EATEST_VERIFY(fs9.capacity() == 100);
|
||||
EATEST_VERIFY(fs9.full() == true);
|
||||
EATEST_VERIFY(fs9.has_overflowed() == true);
|
||||
|
||||
fs9.set_capacity(1);
|
||||
EATEST_VERIFY(fs9.size() == 1);
|
||||
EATEST_VERIFY(fs9.capacity() < fs9.max_size()); // We don't test for capacity == 1, because with fixed_strings, the fixed-size capacity is the lowest it ever gets.
|
||||
EATEST_VERIFY(fs9.full() == false);
|
||||
EATEST_VERIFY(fs9.has_overflowed() == false);
|
||||
|
||||
fs9.set_capacity(0);
|
||||
EATEST_VERIFY(fs9.size() == 0);
|
||||
EATEST_VERIFY(fs9.capacity() < fs9.max_size()); // We don't test for capacity == 1, because with fixed_strings, the fixed-size capacity is the lowest it ever gets.
|
||||
EATEST_VERIFY(fs9.full() == false);
|
||||
EATEST_VERIFY(fs9.has_overflowed() == false);
|
||||
|
||||
// Exercise the freeing of memory in set_capacity.
|
||||
fixed_string<char8_t, 64, true> fs88;
|
||||
eastl_size_t capacity = fs88.capacity();
|
||||
fs88.resize(capacity);
|
||||
fs88.set_capacity(capacity * 2);
|
||||
EATEST_VERIFY(fs88.capacity() >= (capacity * 2));
|
||||
|
||||
// void reset_lose_memory();
|
||||
fs6.reset_lose_memory();
|
||||
EATEST_VERIFY(fs6.size() == 0);
|
||||
EATEST_VERIFY(fs5.capacity() == 63);
|
||||
|
||||
// size_type max_size() const;
|
||||
EATEST_VERIFY(fs7.max_size() == 63);
|
||||
|
||||
|
||||
// global operator +
|
||||
{
|
||||
// fixed_string operator+(const fixed_string& a, const fixed_string& b);
|
||||
// fixed_string operator+(value_type* p, const fixed_string& b);
|
||||
// fixed_string operator+(value_type c, const fixed_string& b);
|
||||
// fixed_string operator+(const fixed_string& a, const value_type* p);
|
||||
// fixed_string operator+(const fixed_string& a, value_type c);
|
||||
|
||||
typedef fixed_string<char, 8, true> FSTest; // Make it a small size so it's easily overflowed when we want.
|
||||
|
||||
FSTest a("abc");
|
||||
FSTest b("def");
|
||||
FSTest c(a + b);
|
||||
EATEST_VERIFY(c == "abcdef");
|
||||
c = a + "ghi";
|
||||
EATEST_VERIFY(c == "abcghi");
|
||||
c = "ghi" + a;
|
||||
EATEST_VERIFY(c == "ghiabc");
|
||||
c = a + 'g';
|
||||
EATEST_VERIFY(c == "abcg");
|
||||
c = 'g' + a;
|
||||
EATEST_VERIFY(c == "gabc");
|
||||
|
||||
// fixed_string operator+(fixed_string&& a, fixed_string&& b);
|
||||
// fixed_string operator+(fixed_string&& a, const fixed_string& b);
|
||||
// fixed_string operator+(const value_type* p, fixed_string&& b);
|
||||
// fixed_string operator+(fixed_string&& a, const value_type* p);
|
||||
// fixed_string operator+(fixed_string&& a, value_type b);
|
||||
|
||||
c = eastl::move(a) + eastl::move(b);
|
||||
EATEST_VERIFY(c == "abcdef");
|
||||
c.clear();
|
||||
|
||||
FSTest a1("abc");
|
||||
FSTest b1("def");
|
||||
c = eastl::move(a1) + b1;
|
||||
EATEST_VERIFY(c == "abcdef");
|
||||
c.clear();
|
||||
|
||||
FSTest b2("def");
|
||||
c = "abc" + eastl::move(b2);
|
||||
EATEST_VERIFY(c == "abcdef");
|
||||
c.clear();
|
||||
|
||||
FSTest a3("abc");
|
||||
c = eastl::move(a3) + "def";
|
||||
EATEST_VERIFY(c == "abcdef");
|
||||
c.clear();
|
||||
|
||||
FSTest a4("abc");
|
||||
c = eastl::move(a4) + 'd';
|
||||
EATEST_VERIFY(c == "abcd");
|
||||
c.clear();
|
||||
}
|
||||
|
||||
|
||||
// bool operator==(const fixed_string<& a, const fixed_string& b)
|
||||
// bool operator!=(const fixed_string<& a, const fixed_string& b)
|
||||
EATEST_VERIFY( fs7 != fs8);
|
||||
EATEST_VERIFY(!(fs7 == fs8));
|
||||
fs7 = fs8;
|
||||
EATEST_VERIFY( fs7 == fs8);
|
||||
EATEST_VERIFY(!(fs7 != fs8));
|
||||
}
|
||||
|
||||
|
||||
{ // Test overflow allocator specification
|
||||
|
||||
typedef fixed_string<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);
|
||||
|
||||
fs.clear();
|
||||
EATEST_VERIFY(fs.empty());
|
||||
|
||||
fs.push_back('a');
|
||||
EATEST_VERIFY(fs.size() == 1);
|
||||
EATEST_VERIFY(fs[0] == 'a');
|
||||
|
||||
fs.resize(195);
|
||||
fs[194] = 'b';
|
||||
EATEST_VERIFY(fs[0] == 'a');
|
||||
EATEST_VERIFY(fs[194] == 'b');
|
||||
EATEST_VERIFY(fs.size() == 195);
|
||||
}
|
||||
|
||||
{
|
||||
// Test construction of a container with an overflow allocator constructor argument.
|
||||
MallocAllocator overflowAllocator;
|
||||
void* p = overflowAllocator.allocate(1);
|
||||
fixed_string<char8_t, 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);
|
||||
}
|
||||
|
||||
{
|
||||
// Regression for compile failure when EASTL_NO_RVALUE_REFERENCES is 0.
|
||||
typedef eastl::fixed_string<char, 32, true, MallocAllocator> TestString;
|
||||
|
||||
TestString ts1;
|
||||
TestString ts2(ts1 + "Test");
|
||||
|
||||
EATEST_VERIFY(ts1.empty() && ts2.size() == 4);
|
||||
}
|
||||
|
||||
{
|
||||
// Test equality tests of differently-sized fixed_strings.
|
||||
|
||||
/* Disabled because this isn't currently supported by fixed_string.
|
||||
typedef fixed_string<char8_t, 64, true, MallocAllocator> FixedString64Malloc;
|
||||
typedef fixed_string<char8_t, 32> FixedString32;
|
||||
|
||||
FixedString64Malloc s64M;
|
||||
FixedString32 s32;
|
||||
|
||||
EATEST_VERIFY(s64M == s32);
|
||||
*/
|
||||
}
|
||||
|
||||
nErrorCount += TestFixedSubstring();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,581 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/fixed_vector.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
#include <EAStdC/EAMemory.h>
|
||||
#include <new>
|
||||
|
||||
#if defined(EA_COMPILER_CPP17_ENABLED) && __has_include(<variant>)
|
||||
#include <variant> //Variant not present in older standards
|
||||
#endif
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::fixed_vector<int, 1, true>;
|
||||
template class eastl::fixed_vector<Align64, 1, true>;
|
||||
template class eastl::fixed_vector<TestObject, 1, true>;
|
||||
|
||||
template class eastl::fixed_vector<int, 1, false>;
|
||||
template class eastl::fixed_vector<Align64, 1, false>;
|
||||
template class eastl::fixed_vector<TestObject, 1, false>;
|
||||
|
||||
/*
|
||||
// This does not compile, since the fixed_vector allocator is templated on sizeof(T),
|
||||
// not just T. Thus, the full type is required at the time of instantiation, but it
|
||||
// is not available.
|
||||
// See EATech Core JIRA issue ETCR-1608 for more information.
|
||||
struct StructWithContainerOfStructs
|
||||
{
|
||||
eastl::fixed_vector<StructWithContainerOfStructs,4> children;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// Aligned objects should be CustomAllocator instead of the default, because the
|
||||
// EASTL default might be unable to do aligned allocations, but CustomAllocator always can.
|
||||
typedef fixed_vector<Align64, 3, true, CustomAllocator> VA64;
|
||||
|
||||
VA64 vA64;
|
||||
Align64 a64(5);
|
||||
Align64* pA64 = &a64;
|
||||
}
|
||||
|
||||
|
||||
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); // MSVC-ARM64 generated an internal compiler error on this line.
|
||||
FixedVectorInt8 fv7 = {3, 3, 3, 3, 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());
|
||||
}
|
||||
|
||||
{ // Test that ensures that move ctor that triggers realloc (e.g. > capacity) does so via move code path
|
||||
eastl::fixed_vector<TestObject, 1, true> fv1;
|
||||
fv1.push_back(TestObject(0));
|
||||
fv1.push_back(TestObject(0));
|
||||
int64_t copyCtorCount0 = TestObject::sTOCopyCtorCount, moveCtorCount0 = TestObject::sTOMoveCtorCount;
|
||||
decltype(fv1) fv2 = eastl::move(fv1);
|
||||
EATEST_VERIFY(TestObject::sTOCopyCtorCount == copyCtorCount0 && TestObject::sTOMoveCtorCount == (moveCtorCount0 + 2));
|
||||
}
|
||||
{ // Same as above but with custom statefull allocator
|
||||
struct MyAlloc : public eastl::allocator
|
||||
{
|
||||
MyAlloc()=default;
|
||||
MyAlloc(int i) : dummy(i) {}
|
||||
int dummy;
|
||||
};
|
||||
eastl::fixed_vector<TestObject, 1, true, MyAlloc> fv1;
|
||||
fv1.push_back(TestObject(0));
|
||||
fv1.push_back(TestObject(0));
|
||||
int64_t copyCtorCount0 = TestObject::sTOCopyCtorCount, moveCtorCount0 = TestObject::sTOMoveCtorCount;
|
||||
decltype(fv1) fv2(eastl::move(fv1), MyAlloc(123));
|
||||
EATEST_VERIFY(TestObject::sTOCopyCtorCount == copyCtorCount0 && TestObject::sTOMoveCtorCount == (moveCtorCount0 + 2));
|
||||
}
|
||||
|
||||
#if defined(EA_COMPILER_CPP17_ENABLED) && __has_include(<variant>)
|
||||
//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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,295 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/heap.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/algorithm.h>
|
||||
#include <EASTL/sort.h>
|
||||
#include <EABase/eabase.h>
|
||||
#include <algorithm> //std::pop_heap
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
|
||||
|
||||
int VerifyHeaps(uint32_t* pArray2, uint32_t* pArray3, uint32_t nArraySize)
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
bool bResult;
|
||||
|
||||
bResult = is_heap(pArray2, pArray2 + nArraySize);
|
||||
EATEST_VERIFY(bResult);
|
||||
|
||||
bResult = is_heap(pArray3, pArray3 + nArraySize);
|
||||
EATEST_VERIFY(bResult);
|
||||
|
||||
// bResult = (memcmp(pArray2, pArray3, nArraySize * sizeof(uint32_t)) == 0);
|
||||
// EATEST_VERIFY(bResult);
|
||||
//
|
||||
// The above does not work on iOS since CM added -stdlib=libc++ to the linker switch
|
||||
// even though it was already used in our compile switches.
|
||||
// It would appear that on clang or iOS the heap is actually structured in a unique way,
|
||||
// possibly for optimization. Iterating over the array and using pop_heap verifies
|
||||
// that the heaps have the same elements and are retrieved in the same manner.
|
||||
// The underlying storage may be different.
|
||||
uint32_t* pArray2_copy = new uint32_t[nArraySize];
|
||||
uint32_t* pArray3_copy = new uint32_t[nArraySize];
|
||||
|
||||
memcpy(pArray2_copy, pArray2, sizeof(uint32_t) * nArraySize);
|
||||
memcpy(pArray3_copy, pArray3, sizeof(uint32_t) * nArraySize);
|
||||
|
||||
for(uint32_t i = 0; i < nArraySize; i++)
|
||||
{
|
||||
EATEST_VERIFY(pArray2_copy[0] == pArray3_copy[0]);
|
||||
std::pop_heap(pArray2_copy, pArray2_copy + nArraySize - i);
|
||||
pop_heap(pArray3_copy, pArray3_copy + nArraySize - i);
|
||||
}
|
||||
delete[] pArray2_copy;
|
||||
delete[] pArray3_copy;
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int TestHeap()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// We do a bit of our heap testing by simply doing rng operations and comparing
|
||||
// to a standard STL implementation of the heap functions.
|
||||
|
||||
{
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
EA::UnitTest::Rand rng(EA::UnitTest::GetRandSeed());
|
||||
|
||||
const int32_t kMinArraySize = 2;
|
||||
const int32_t kMaxArraySize = 1000;
|
||||
const int32_t kMinValue = 0;
|
||||
const int32_t kMaxValue = 500;
|
||||
|
||||
// To consider, instead of using 25, try conditioning on EA::UnitTest::GetSystemSpeed().
|
||||
// I tried this, but even though Caps and PC are the same system speed, Caps was quite slower
|
||||
// than PC doing 75 loops
|
||||
for(int i = 0; (i < 25) && (nErrorCount == 0); i++)
|
||||
{
|
||||
//
|
||||
// Set up an array of data to work with as a heap.
|
||||
uint32_t nArraySizeInitial = (uint32_t)rng.RandRange(kMinArraySize, kMaxArraySize);
|
||||
uint32_t nArraySize = nArraySizeInitial;
|
||||
uint32_t* pArray1 = new uint32_t[nArraySize + 1]; // Array1 is the original data. // +1 because we append an additional element in the is_heap_until test below.
|
||||
uint32_t* pArray2 = new uint32_t[nArraySize + 1]; // Array2 is the data in std::make_heap
|
||||
uint32_t* pArray3 = new uint32_t[nArraySize + 1]; // Array3 is the data in eastl::make_heap.
|
||||
|
||||
for(uint32_t j = 0; j < nArraySize; j++)
|
||||
pArray1[j] = pArray2[j] = pArray3[j] = (uint32_t)rng.RandRange(kMinValue, kMaxValue);
|
||||
|
||||
|
||||
// make_heap
|
||||
std::make_heap(pArray2, pArray2 + nArraySize);
|
||||
make_heap(pArray3, pArray3 + nArraySize);
|
||||
VerifyHeaps(pArray2, pArray3, nArraySize);
|
||||
|
||||
|
||||
// is_heap_until
|
||||
{
|
||||
pArray3[nArraySize] = kMaxValue + 1; // Append a value which is guaranteed to break the heap.
|
||||
uint32_t* pUntil = is_heap_until(pArray3, pArray3 + (nArraySize + 1));
|
||||
EATEST_VERIFY_F(pUntil == (pArray3 + nArraySize), "is_heap_until failure in iteration %d for array size %I32u.", nArraySize);
|
||||
}
|
||||
|
||||
|
||||
// pop_heap
|
||||
const int popCount = min<uint32_t>(200, nArraySize);
|
||||
for(int k = 0; (k < popCount) && (nErrorCount == 0); k++, nArraySize--)
|
||||
{
|
||||
std::pop_heap(pArray2, pArray2 + nArraySize);
|
||||
pArray2[nArraySize - 1] = 0xffffffff; // Set it to some value so we can recognize it in a debugger.
|
||||
|
||||
pop_heap(pArray3, pArray3 + nArraySize);
|
||||
pArray3[nArraySize - 1] = 0xffffffff;
|
||||
|
||||
VerifyHeaps(pArray2, pArray3, nArraySize - 1);
|
||||
}
|
||||
|
||||
|
||||
// push_heap
|
||||
const int pushCount = popCount;
|
||||
for(int m = 0; (m < pushCount) && (nErrorCount == 0); m++, nArraySize++)
|
||||
{
|
||||
const uint32_t n = (uint32_t)rng.RandRange(kMinValue, kMaxValue);
|
||||
|
||||
pArray2[nArraySize] = n;
|
||||
std::push_heap(pArray2, pArray2 + nArraySize + 1);
|
||||
|
||||
pArray3[nArraySize] = n;
|
||||
push_heap(pArray3, pArray3 + nArraySize + 1);
|
||||
|
||||
VerifyHeaps(pArray2, pArray3, nArraySize + 1);
|
||||
}
|
||||
|
||||
uint32_t originalSize = nArraySize;
|
||||
// remove_heap
|
||||
// Because the heap that stdlib on iOS and other platforms differs, different elements
|
||||
// will be removed. After calling remove heap, we cannot call VerifyHeaps anymore, but
|
||||
// can still check that heap format is retained.
|
||||
const int eraseCount = popCount;
|
||||
for(int e = 0; (e < eraseCount) && (nErrorCount == 0); e++, nArraySize--)
|
||||
{
|
||||
const uint32_t position = (uint32_t)rng.RandRange(0, nArraySize);
|
||||
|
||||
remove_heap(pArray2, nArraySize, position);
|
||||
pArray2[nArraySize - 1] = 0xffffffff;
|
||||
|
||||
remove_heap(pArray3, nArraySize, position);
|
||||
pArray3[nArraySize - 1] = 0xffffffff;
|
||||
|
||||
//use is_heap_until to verify remove_heap is working.
|
||||
if(nArraySize > 1) //If we just popped last element, don't use is_heap_until
|
||||
{
|
||||
uint32_t* pUntil = is_heap_until(pArray2, pArray2 + (nArraySize));
|
||||
EATEST_VERIFY_F(pUntil == (pArray2 + nArraySize - 1), "pUntil failure for pArray2 with array size %I32u.", nArraySize);
|
||||
|
||||
pUntil = is_heap_until(pArray3, pArray3 + (nArraySize));
|
||||
EATEST_VERIFY_F(pUntil == (pArray3 + nArraySize - 1), "failure for pArray3 with array size %I32u.", nArraySize);
|
||||
}
|
||||
}
|
||||
|
||||
// push_heap -- increase the heap size back to the original size.
|
||||
for(int m = 0; (m < pushCount) && (nErrorCount == 0); m++, nArraySize++)
|
||||
{
|
||||
const uint32_t n = (uint32_t)rng.RandRange(kMinValue, kMaxValue);
|
||||
|
||||
pArray2[nArraySize] = n;
|
||||
std::push_heap(pArray2, pArray2 + nArraySize + 1);
|
||||
|
||||
pArray3[nArraySize] = n;
|
||||
push_heap(pArray3, pArray3 + nArraySize + 1);
|
||||
}
|
||||
|
||||
EATEST_VERIFY_F(nArraySize == originalSize, "Array size is %d not original size %d", nArraySize , originalSize);
|
||||
|
||||
uint32_t* pUntil = is_heap_until(pArray2, pArray2 + (nArraySize));
|
||||
EATEST_VERIFY_F(pUntil == (pArray2 + nArraySize), "failure for pArray2 with array size %I32u.", nArraySize);
|
||||
pUntil = is_heap_until(pArray3, pArray3 + (nArraySize));
|
||||
EATEST_VERIFY_F(pUntil == (pArray3 + nArraySize), "failure for pArray3 with array size %I32u.", nArraySize);
|
||||
|
||||
|
||||
// change_heap
|
||||
const int changeCount = popCount;
|
||||
for(int r = 0; (r < changeCount) && (nErrorCount == 0); r++, nArraySize--)
|
||||
{
|
||||
uint32_t position = (uint32_t)rng.RandRange(0, nArraySize);
|
||||
uint32_t newValue = (uint32_t)rng.RandRange(kMinValue, kMaxValue);
|
||||
|
||||
if(rng.RandLimit(5) == 0) // One in five chance that we use the heap top position.
|
||||
position = 0;
|
||||
if(rng.RandLimit(5) != 0) // One in five chance that we do no change.
|
||||
pArray2[position] = pArray3[position] = newValue;
|
||||
|
||||
// There is no std::change_heap, so we just use ours for this test.
|
||||
change_heap(pArray2, nArraySize, position);
|
||||
pArray2[nArraySize - 1] = 0xffffffff;
|
||||
|
||||
change_heap(pArray3, nArraySize, position);
|
||||
pArray3[nArraySize - 1] = 0xffffffff;
|
||||
|
||||
if(nArraySize > 1) //If we just removed last element, don't use is_heap_until
|
||||
{
|
||||
uint32_t* pUntilChanged = is_heap_until(pArray2, pArray2 + (nArraySize));
|
||||
EATEST_VERIFY_F(pUntilChanged == (pArray2 + nArraySize - 1), "failure for pArray2 with array size %I32u.", nArraySize);
|
||||
pUntilChanged = is_heap_until(pArray3, pArray3 + (nArraySize));
|
||||
EATEST_VERIFY_F(pUntilChanged == (pArray3 + nArraySize - 1), "failure for pArray3 with array size %I32u.", nArraySize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sort_heap
|
||||
std::sort_heap(pArray2, pArray2 + nArraySize);
|
||||
sort_heap(pArray3, pArray3 + nArraySize);
|
||||
|
||||
for(uint32_t q = 1; (q < nArraySize) && (nErrorCount == 0); q++)
|
||||
{
|
||||
EATEST_VERIFY(pArray2[q-1] <= pArray2[q]);
|
||||
EATEST_VERIFY(pArray3[q-1] <= pArray3[q]);
|
||||
}
|
||||
// Free our heap data.
|
||||
delete[] pArray1;
|
||||
delete[] pArray2;
|
||||
delete[] pArray3;
|
||||
}
|
||||
|
||||
#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
}
|
||||
|
||||
{
|
||||
// Test aligned types.
|
||||
|
||||
// Aligned objects should be CustomAllocator instead of the default, because the
|
||||
// EASTL default might be unable to do aligned allocations, but CustomAllocator always can.
|
||||
eastl::vector<Align64, CustomAllocator> heap;
|
||||
|
||||
for(int i = 0; i < 16; i++)
|
||||
heap.push_back(Align64(i));
|
||||
|
||||
eastl::make_heap(heap.begin(), heap.end());
|
||||
EATEST_VERIFY(is_heap(heap.begin(), heap.end()));
|
||||
|
||||
heap.push_back(Align64(7));
|
||||
eastl::push_heap(heap.begin(), heap.end());
|
||||
EATEST_VERIFY(is_heap(heap.begin(), heap.end()));
|
||||
|
||||
heap.push_back(Align64(7));
|
||||
eastl::push_heap(heap.begin(), heap.end());
|
||||
heap.pop_back();
|
||||
EATEST_VERIFY(is_heap(heap.begin(), heap.end()));
|
||||
|
||||
eastl::remove_heap(heap.begin(), heap.size(), (eastl_size_t)4);
|
||||
heap.pop_back();
|
||||
EATEST_VERIFY(is_heap(heap.begin(), heap.end()));
|
||||
|
||||
eastl::sort_heap(heap.begin(), heap.end());
|
||||
EATEST_VERIFY(is_sorted(heap.begin(), heap.end()));
|
||||
}
|
||||
|
||||
{
|
||||
Align16 heap[5];
|
||||
|
||||
eastl::make_heap(heap, heap + 5);
|
||||
EATEST_VERIFY(is_heap(heap, heap + 5));
|
||||
|
||||
eastl::partial_sort(heap, heap + 3, heap + 5);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,773 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/internal/intrusive_hashtable.h>
|
||||
#include <EASTL/intrusive_hash_set.h>
|
||||
#include <EASTL/intrusive_hash_map.h>
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
struct SetWidget : public intrusive_hash_node
|
||||
{
|
||||
SetWidget(int x = 0)
|
||||
: mX(x) { }
|
||||
int mX;
|
||||
};
|
||||
|
||||
inline bool operator==(const SetWidget& a, const SetWidget& b)
|
||||
{ return a.mX == b.mX; }
|
||||
|
||||
struct SWHash
|
||||
{
|
||||
size_t operator()(const SetWidget& sw) const
|
||||
{
|
||||
return (size_t)sw.mX;
|
||||
}
|
||||
};
|
||||
|
||||
struct SetWidgetComparable // Exists for the sole purpose of testing the find_as function.
|
||||
{
|
||||
SetWidgetComparable(int x = 0)
|
||||
: mX(x) { }
|
||||
int mX;
|
||||
};
|
||||
|
||||
struct SWCHash
|
||||
{
|
||||
size_t operator()(const SetWidgetComparable& swc) const
|
||||
{
|
||||
return (size_t)swc.mX;
|
||||
}
|
||||
};
|
||||
|
||||
bool operator==(const SetWidget& a, const SetWidgetComparable& b)
|
||||
{ return a.mX == b.mX; }
|
||||
|
||||
|
||||
|
||||
struct MapWidget : public intrusive_hash_node_key<int>
|
||||
{
|
||||
MapWidget(int x = 0)
|
||||
: mX(x) { }
|
||||
int mX;
|
||||
};
|
||||
|
||||
inline bool operator==(const MapWidget& a, const MapWidget& b)
|
||||
{ return a.mX == b.mX; }
|
||||
|
||||
//struct MapWidgetComparable // Exists for the sole purpose of testing the find_as function.
|
||||
//{
|
||||
// MapWidgetComparable(int x = 0)
|
||||
// : mX(x) { }
|
||||
// int mX;
|
||||
//};
|
||||
//
|
||||
//bool operator==(const SetWidget& a, const MapWidgetComparable& b)
|
||||
// { return a.mX == b.mX; }
|
||||
|
||||
|
||||
|
||||
|
||||
// IHWidget
|
||||
//
|
||||
// Implements the intrusive node data directly instead of inheriting from intrusive_hash_node.
|
||||
//
|
||||
struct IHWidget
|
||||
{
|
||||
IHWidget(int x = 0)
|
||||
: mX(x) { }
|
||||
|
||||
int mX;
|
||||
IHWidget* mpNext;
|
||||
typedef int key_type;
|
||||
int mKey;
|
||||
|
||||
};
|
||||
|
||||
inline bool operator==(const IHWidget& a, const IHWidget& b)
|
||||
{ return a.mX == b.mX; }
|
||||
|
||||
struct IHWHash
|
||||
{
|
||||
size_t operator()(const IHWidget& ihw) const
|
||||
{
|
||||
return (size_t)ihw.mX;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
//template class intrusive_hash_set<SetWidget>;
|
||||
//template class intrusive_hash_map<MapWidget>;
|
||||
|
||||
|
||||
template class eastl::intrusive_hashtable<SetWidget, SetWidget, SWHash, eastl::equal_to<SetWidget>, 37, true, true>;
|
||||
template class eastl::intrusive_hashtable<int, MapWidget, eastl::hash<int>, eastl::equal_to<int>, 37, false, true>;
|
||||
|
||||
template class eastl::intrusive_hash_set<SetWidget, 37, SWHash>;
|
||||
template class eastl::intrusive_hash_multiset<SetWidget, 37, SWHash>;
|
||||
|
||||
template class eastl::intrusive_hash_map<int, MapWidget, 37>;
|
||||
template class eastl::intrusive_hash_multimap<int, MapWidget, 37>;
|
||||
|
||||
template class eastl::intrusive_hash_set<IHWidget, 37, IHWHash>;
|
||||
template class eastl::intrusive_hash_multiset<IHWidget, 37, IHWHash>;
|
||||
|
||||
template class eastl::intrusive_hash_map<int, IHWidget, 37, IHWHash>;
|
||||
template class eastl::intrusive_hash_multimap<int, IHWidget, 37, IHWHash>;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int TestIntrusiveHash()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
SetWidget sw1, sw2;
|
||||
VERIFY(sw1 == sw2);
|
||||
|
||||
MapWidget mw1, mw2;
|
||||
VERIFY(mw1 == mw2);
|
||||
|
||||
IHWidget iw1, iw2;
|
||||
VERIFY(iw1 == iw2);
|
||||
|
||||
IHWHash ih1;
|
||||
VERIFY(ih1.operator()(iw1) == ih1.operator()(iw2));
|
||||
}
|
||||
|
||||
{
|
||||
// Test intrusive_hash_set
|
||||
|
||||
const size_t kBucketCount = 37;
|
||||
typedef intrusive_hash_set<SetWidget, kBucketCount, SWHash> IHM_SW;
|
||||
|
||||
const size_t kArraySize = 100;
|
||||
SetWidget swArray[kArraySize];
|
||||
|
||||
int nExpectedKeySum = 0; // We use this as a checksum in order to do validity checks below.
|
||||
|
||||
for(size_t i = 0; i < kArraySize; i++)
|
||||
{
|
||||
swArray[i].mX = (int)i;
|
||||
nExpectedKeySum += (int)i;
|
||||
}
|
||||
|
||||
|
||||
// const key_equal& key_eq() const;
|
||||
// key_equal& key_eq();
|
||||
IHM_SW ih;
|
||||
const IHM_SW ihc;
|
||||
|
||||
const IHM_SW::key_equal& ke = ihc.key_eq();
|
||||
ih.key_eq() = ke;
|
||||
|
||||
|
||||
// intrusive_hashtable(const Hash&, const Equal&);
|
||||
// void swap(this_type& x);
|
||||
// size_type size() const;
|
||||
// bool empty() const;
|
||||
// size_type bucket_count() const;
|
||||
// size_type bucket_size(size_type n) const;
|
||||
// float load_factor() const;
|
||||
// void clear();
|
||||
// bool validate() const;
|
||||
|
||||
IHM_SW ihmSW1;
|
||||
IHM_SW ihmSW2;
|
||||
|
||||
VERIFY(ihmSW1.size() == 0);
|
||||
VERIFY(ihmSW1.empty());
|
||||
VERIFY(ihmSW1.validate());
|
||||
VERIFY(ihmSW2.validate());
|
||||
|
||||
ihmSW1.swap(ihmSW2);
|
||||
|
||||
VERIFY(ihmSW1.validate());
|
||||
VERIFY(ihmSW2.validate());
|
||||
VERIFY(ihmSW2.bucket_count() == kBucketCount);
|
||||
VERIFY(ihmSW2.bucket_size(0) == 0);
|
||||
VERIFY(ihmSW2.bucket_size(kBucketCount - 1) == 0);
|
||||
VERIFY(ihmSW1.load_factor() == 0.f);
|
||||
VERIFY(ihmSW2.load_factor() == 0.f);
|
||||
|
||||
ihmSW1.clear();
|
||||
VERIFY(ihmSW1.validate());
|
||||
VERIFY(ihmSW1.begin() == ihmSW1.end());
|
||||
|
||||
|
||||
// void insert(InputIterator first, InputIterator last);
|
||||
// insert_return_type insert(value_type& value);
|
||||
// void swap(this_type& x);
|
||||
// void clear();
|
||||
|
||||
ihmSW1.clear();
|
||||
ihmSW1.insert(swArray, swArray + (kArraySize - 10));
|
||||
for(int i = 0; i < 10; i++) // insert the remaining elements via the other insert function.
|
||||
{
|
||||
pair<IHM_SW::iterator, bool> result = ihmSW1.insert(swArray[(kArraySize - 10) + i]);
|
||||
VERIFY(result.second == true);
|
||||
}
|
||||
|
||||
VERIFY(ihmSW1.size() == kArraySize);
|
||||
VERIFY(ihmSW1.validate());
|
||||
|
||||
for(size_t i = 0; i < kArraySize; i++)
|
||||
{
|
||||
// Try to re-insert the elements. All insertions should fail.
|
||||
pair<IHM_SW::iterator, bool> result = ihmSW1.insert(swArray[i]);
|
||||
VERIFY(result.second == false);
|
||||
}
|
||||
|
||||
VERIFY(ihmSW1.size() == kArraySize);
|
||||
VERIFY(!ihmSW1.empty());
|
||||
VERIFY(ihmSW1.validate());
|
||||
|
||||
ihmSW2.clear();
|
||||
ihmSW1.swap(ihmSW2);
|
||||
|
||||
|
||||
// size_type size() const;
|
||||
// bool empty() const;
|
||||
// size_type count(const key_type& k) const;
|
||||
// size_type bucket_size(size_type n) const;
|
||||
// float load_factor() const;
|
||||
// size_type bucket(const key_type& k) const
|
||||
|
||||
VERIFY(ihmSW1.validate());
|
||||
VERIFY(ihmSW2.validate());
|
||||
VERIFY(ihmSW1.size() == 0);
|
||||
VERIFY(ihmSW1.empty());
|
||||
VERIFY(ihmSW2.size() == kArraySize);
|
||||
VERIFY(!ihmSW2.empty());
|
||||
VERIFY(ihmSW1.load_factor() == 0.f);
|
||||
VERIFY(ihmSW2.load_factor() > 2.f);
|
||||
VERIFY(ihmSW1.count(0) == 0);
|
||||
VERIFY(ihmSW1.count(999999) == 0);
|
||||
VERIFY(ihmSW2.count(0) == 1);
|
||||
VERIFY(ihmSW2.count(999999) == 0);
|
||||
VERIFY(ihmSW2.bucket_size(0) == 3); // We just happen to know this should be so based on the distribution.
|
||||
VERIFY(ihmSW2.bucket(13) == (13 % kBucketCount)); // We know this is so because our hash function simply returns n.
|
||||
VERIFY(ihmSW2.bucket(10000) == (10000 % kBucketCount)); // We know this is so because our hash function simply returns n.
|
||||
|
||||
|
||||
// iterator begin();
|
||||
// const_iterator begin() const;
|
||||
|
||||
ihmSW1.swap(ihmSW2);
|
||||
int nSum = 0;
|
||||
|
||||
for(IHM_SW::iterator it = ihmSW1.begin(); it != ihmSW1.end(); ++it)
|
||||
{
|
||||
const SetWidget& sw = *it; // Recall that set iterators are const_iterators.
|
||||
|
||||
nSum += sw.mX;
|
||||
|
||||
const int iresult = ihmSW1.validate_iterator(it);
|
||||
VERIFY(iresult == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
IHM_SW::iterator itf = ihmSW1.find(sw.mX);
|
||||
VERIFY(itf == it);
|
||||
}
|
||||
|
||||
VERIFY(nSum == nExpectedKeySum);
|
||||
|
||||
|
||||
// iterator end();
|
||||
// const_iterator end() const;
|
||||
|
||||
const IHM_SW& ihmSW1Const = ihmSW1;
|
||||
|
||||
for(IHM_SW::const_iterator itc = ihmSW1Const.begin(); itc != ihmSW1Const.end(); ++itc)
|
||||
{
|
||||
const SetWidget& sw = *itc;
|
||||
|
||||
IHM_SW::const_iterator itf = ihmSW1.find(sw.mX);
|
||||
VERIFY(itf == itc);
|
||||
}
|
||||
|
||||
|
||||
// local_iterator begin(size_type n)
|
||||
// local_iterator end(size_type)
|
||||
|
||||
for(IHM_SW::local_iterator itl = ihmSW1.begin(5); itl != ihmSW1.end(5); ++itl)
|
||||
{
|
||||
const SetWidget& sw = *itl; // Recall that set iterators are const_iterators.
|
||||
|
||||
VERIFY((sw.mX % kBucketCount) == 5);
|
||||
}
|
||||
|
||||
|
||||
// const_local_iterator begin(size_type n) const
|
||||
// const_local_iterator end(size_type) const
|
||||
|
||||
for(IHM_SW::const_local_iterator itlc = ihmSW1Const.begin(5); itlc != ihmSW1Const.end(5); ++itlc)
|
||||
{
|
||||
const SetWidget& sw = *itlc;
|
||||
|
||||
VERIFY((sw.mX % kBucketCount) == 5);
|
||||
}
|
||||
|
||||
|
||||
// iterator find(const key_type& k);
|
||||
// const_iterator find(const key_type& k) const;
|
||||
|
||||
IHM_SW::iterator itf = ihmSW1.find(SetWidget(99999));
|
||||
VERIFY(itf == ihmSW1.end());
|
||||
|
||||
IHM_SW::const_iterator itfc = ihmSW1Const.find(SetWidget(99999));
|
||||
VERIFY(itfc == ihmSW1Const.end());
|
||||
|
||||
|
||||
// iterator find_as(const U& u);
|
||||
// const_iterator find_as(const U& u) const;
|
||||
|
||||
//itf = ihmSW1.find_as(SetWidget(7)); // Can't work unless there was a default eastl::hash function for SetWidget.
|
||||
//VERIFY(itf->mX == 7);
|
||||
|
||||
//itfc = ihmSW1Const.find_as(SetWidget(7));
|
||||
//VERIFY(itfc->mX == 7);
|
||||
|
||||
|
||||
// iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate);
|
||||
// const_iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate) const;
|
||||
|
||||
itf = ihmSW1.find_as(SetWidgetComparable(7), SWCHash(), eastl::equal_to_2<SetWidget, SetWidgetComparable>());
|
||||
VERIFY(itf->mX == 7);
|
||||
|
||||
itfc = ihmSW1Const.find_as(SetWidgetComparable(7), SWCHash(), eastl::equal_to_2<SetWidget, SetWidgetComparable>());
|
||||
VERIFY(itfc->mX == 7);
|
||||
|
||||
|
||||
// iterator erase(iterator);
|
||||
// iterator erase(iterator, iterator);
|
||||
// size_type erase(const key_type&);
|
||||
|
||||
eastl_size_t n = ihmSW1.erase(SetWidget(99999));
|
||||
VERIFY(n == 0);
|
||||
|
||||
n = ihmSW1.erase(SetWidget(17));
|
||||
VERIFY(n == 1);
|
||||
|
||||
itf = ihmSW1.find(SetWidget(18));
|
||||
VERIFY(itf != ihmSW1.end());
|
||||
VERIFY(ihmSW1.validate_iterator(itf) == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itf = ihmSW1.erase(itf);
|
||||
VERIFY(itf != ihmSW1.end());
|
||||
VERIFY(ihmSW1.validate_iterator(itf) == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itf = ihmSW1.find(SetWidget(18));
|
||||
VERIFY(itf == ihmSW1.end());
|
||||
|
||||
itf = ihmSW1.find(SetWidget(19));
|
||||
VERIFY(itf != ihmSW1.end());
|
||||
|
||||
IHM_SW::iterator itf2(itf);
|
||||
eastl::advance(itf2, 7);
|
||||
VERIFY(itf2 != ihmSW1.end());
|
||||
VERIFY(ihmSW1.validate_iterator(itf2) == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itf = ihmSW1.erase(itf, itf2);
|
||||
VERIFY(itf != ihmSW1.end());
|
||||
VERIFY(ihmSW1.validate_iterator(itf) == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itf = ihmSW1.find(SetWidget(19));
|
||||
VERIFY(itf == ihmSW1.end());
|
||||
|
||||
|
||||
// eastl::pair<iterator, iterator> equal_range(const key_type& k);
|
||||
// eastl::pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
|
||||
|
||||
eastl::pair<IHM_SW::iterator, IHM_SW::iterator> p = ihmSW1.equal_range(SetWidget(1));
|
||||
VERIFY(p.first != ihmSW1.end());
|
||||
VERIFY(p.second != ihmSW1.end());
|
||||
|
||||
eastl::pair<IHM_SW::const_iterator, IHM_SW::const_iterator> pc = ihmSW1Const.equal_range(SetWidget(1));
|
||||
VERIFY(pc.first != ihmSW1Const.end());
|
||||
VERIFY(pc.second != ihmSW1Const.end());
|
||||
|
||||
|
||||
// void clear();
|
||||
// bool validate() const;
|
||||
// int validate_iterator(const_iterator i) const;
|
||||
|
||||
IHM_SW::iterator itTest;
|
||||
int iresult = ihmSW1.validate_iterator(itTest);
|
||||
VERIFY(iresult == isf_none);
|
||||
|
||||
itTest = ihmSW1.begin();
|
||||
iresult = ihmSW1.validate_iterator(itTest);
|
||||
VERIFY(iresult == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itTest = ihmSW1.end();
|
||||
iresult = ihmSW1.validate_iterator(itTest);
|
||||
VERIFY(iresult == (isf_valid | isf_current));
|
||||
|
||||
ihmSW1.clear();
|
||||
ihmSW2.clear();
|
||||
VERIFY(ihmSW1.validate());
|
||||
VERIFY(ihmSW2.validate());
|
||||
|
||||
itTest = ihmSW1.begin();
|
||||
iresult = ihmSW1.validate_iterator(itTest);
|
||||
VERIFY(iresult == (isf_valid | isf_current));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test intrusive_hash_map
|
||||
|
||||
const size_t kBucketCount = 37;
|
||||
typedef intrusive_hash_map<int, MapWidget, kBucketCount> IHM_MW;
|
||||
|
||||
const size_t kArraySize = 100;
|
||||
MapWidget mwArray[kArraySize];
|
||||
|
||||
int nExpectedKeySum = 0; // We use this as a checksum in order to do validity checks below.
|
||||
|
||||
for(size_t i = 0; i < kArraySize; i++)
|
||||
{
|
||||
mwArray[i].mKey = (int)i;
|
||||
mwArray[i].mX = (int)i;
|
||||
nExpectedKeySum += (int)i;
|
||||
}
|
||||
|
||||
|
||||
// intrusive_hashtable(const Hash&, const Equal&);
|
||||
// void swap(this_type& x);
|
||||
// size_type size() const;
|
||||
// bool empty() const;
|
||||
// size_type bucket_count() const;
|
||||
// size_type bucket_size(size_type n) const;
|
||||
// float load_factor() const;
|
||||
// void clear();
|
||||
// bool validate() const;
|
||||
|
||||
IHM_MW ihmMW1;
|
||||
IHM_MW ihmMW2;
|
||||
|
||||
VERIFY(ihmMW1.size() == 0);
|
||||
VERIFY(ihmMW1.empty());
|
||||
VERIFY(ihmMW1.validate());
|
||||
VERIFY(ihmMW2.validate());
|
||||
|
||||
ihmMW1.swap(ihmMW2);
|
||||
|
||||
VERIFY(ihmMW1.validate());
|
||||
VERIFY(ihmMW2.validate());
|
||||
VERIFY(ihmMW2.bucket_count() == kBucketCount);
|
||||
VERIFY(ihmMW2.bucket_size(0) == 0);
|
||||
VERIFY(ihmMW2.bucket_size(kBucketCount - 1) == 0);
|
||||
VERIFY(ihmMW1.load_factor() == 0.f);
|
||||
VERIFY(ihmMW2.load_factor() == 0.f);
|
||||
|
||||
ihmMW1.clear();
|
||||
VERIFY(ihmMW1.validate());
|
||||
VERIFY(ihmMW1.begin() == ihmMW1.end());
|
||||
|
||||
|
||||
// void insert(InputIterator first, InputIterator last);
|
||||
// insert_return_type insert(value_type& value);
|
||||
// void swap(this_type& x);
|
||||
// void clear();
|
||||
|
||||
ihmMW1.clear();
|
||||
ihmMW1.insert(mwArray, mwArray + (kArraySize - 10));
|
||||
for(int i = 0; i < 10; i++) // insert the remaining elements via the other insert function.
|
||||
{
|
||||
pair<IHM_MW::iterator, bool> result = ihmMW1.insert(mwArray[(kArraySize - 10) + i]);
|
||||
VERIFY(result.second == true);
|
||||
}
|
||||
|
||||
VERIFY(ihmMW1.size() == kArraySize);
|
||||
VERIFY(ihmMW1.validate());
|
||||
|
||||
for(size_t i = 0; i < kArraySize; i++)
|
||||
{
|
||||
// Try to re-insert the elements. All insertions should fail.
|
||||
pair<IHM_MW::iterator, bool> result = ihmMW1.insert(mwArray[i]);
|
||||
VERIFY(result.second == false);
|
||||
}
|
||||
|
||||
VERIFY(ihmMW1.size() == kArraySize);
|
||||
VERIFY(!ihmMW1.empty());
|
||||
VERIFY(ihmMW1.validate());
|
||||
|
||||
ihmMW2.clear();
|
||||
ihmMW1.swap(ihmMW2);
|
||||
|
||||
|
||||
// size_type size() const;
|
||||
// bool empty() const;
|
||||
// size_type count(const key_type& k) const;
|
||||
// size_type bucket_size(size_type n) const;
|
||||
// float load_factor() const;
|
||||
// size_type bucket(const key_type& k) const
|
||||
|
||||
VERIFY(ihmMW1.validate());
|
||||
VERIFY(ihmMW2.validate());
|
||||
VERIFY(ihmMW1.size() == 0);
|
||||
VERIFY(ihmMW1.empty());
|
||||
VERIFY(ihmMW2.size() == kArraySize);
|
||||
VERIFY(!ihmMW2.empty());
|
||||
VERIFY(ihmMW1.load_factor() == 0.f);
|
||||
VERIFY(ihmMW2.load_factor() > 2.f);
|
||||
VERIFY(ihmMW1.count(0) == 0);
|
||||
VERIFY(ihmMW1.count(999999) == 0);
|
||||
VERIFY(ihmMW2.count(0) == 1);
|
||||
VERIFY(ihmMW2.count(999999) == 0);
|
||||
VERIFY(ihmMW2.bucket_size(0) == 3); // We just happen to know this should be so based on the distribution.
|
||||
VERIFY(ihmMW2.bucket(13) == (13 % kBucketCount)); // We know this is so because our hash function simply returns n.
|
||||
VERIFY(ihmMW2.bucket(10000) == (10000 % kBucketCount)); // We know this is so because our hash function simply returns n.
|
||||
|
||||
|
||||
// iterator begin();
|
||||
// const_iterator begin() const;
|
||||
|
||||
ihmMW1.swap(ihmMW2);
|
||||
int nSum = 0;
|
||||
|
||||
for(IHM_MW::iterator it = ihmMW1.begin(); it != ihmMW1.end(); ++it)
|
||||
{
|
||||
IHM_MW::value_type& v = *it;
|
||||
|
||||
VERIFY(v.mKey == v.mX); // We intentionally made this so above.
|
||||
nSum += v.mKey;
|
||||
|
||||
const int iresult = ihmMW1.validate_iterator(it);
|
||||
VERIFY(iresult == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
IHM_MW::iterator itf = ihmMW1.find(v.mKey);
|
||||
VERIFY(itf == it);
|
||||
}
|
||||
|
||||
VERIFY(nSum == nExpectedKeySum);
|
||||
|
||||
|
||||
// iterator end();
|
||||
// const_iterator end() const;
|
||||
|
||||
const IHM_MW& ihmMW1Const = ihmMW1;
|
||||
|
||||
for(IHM_MW::const_iterator itc = ihmMW1Const.begin(); itc != ihmMW1Const.end(); ++itc)
|
||||
{
|
||||
const IHM_MW::value_type& v = *itc;
|
||||
|
||||
VERIFY(v.mKey == v.mX); // We intentionally made this so above.
|
||||
|
||||
IHM_MW::const_iterator itf = ihmMW1Const.find(v.mKey);
|
||||
VERIFY(itf == itc);
|
||||
}
|
||||
|
||||
|
||||
// local_iterator begin(size_type n)
|
||||
// local_iterator end(size_type)
|
||||
|
||||
for(IHM_MW::local_iterator itl = ihmMW1.begin(5); itl != ihmMW1.end(5); ++itl)
|
||||
{
|
||||
IHM_MW::value_type& v = *itl;
|
||||
|
||||
VERIFY(v.mKey == v.mX); // We intentionally made this so above.
|
||||
}
|
||||
|
||||
|
||||
// const_local_iterator begin(size_type n) const
|
||||
// const_local_iterator end(size_type) const
|
||||
|
||||
for(IHM_MW::const_local_iterator itlc = ihmMW1Const.begin(5); itlc != ihmMW1Const.end(5); ++itlc)
|
||||
{
|
||||
const IHM_MW::value_type& v = *itlc;
|
||||
|
||||
VERIFY(v.mKey == v.mX); // We intentionally made this so above.
|
||||
}
|
||||
|
||||
|
||||
// iterator find(const key_type& k);
|
||||
// const_iterator find(const key_type& k) const;
|
||||
|
||||
IHM_MW::iterator itf = ihmMW1.find(99999);
|
||||
VERIFY(itf == ihmMW1.end());
|
||||
|
||||
IHM_MW::const_iterator itfc = ihmMW1Const.find(99999);
|
||||
VERIFY(itfc == ihmMW1Const.end());
|
||||
|
||||
|
||||
// iterator find_as(const U& u);
|
||||
// const_iterator find_as(const U& u) const;
|
||||
|
||||
itf = ihmMW1.find_as(7.f);
|
||||
VERIFY(itf->mKey == 7);
|
||||
|
||||
itfc = ihmMW1Const.find_as(7.f);
|
||||
VERIFY(itfc->mKey == 7);
|
||||
|
||||
itf = ihmMW1.find_as(8);
|
||||
VERIFY(itf->mKey == 8);
|
||||
|
||||
itfc = ihmMW1Const.find_as(8);
|
||||
VERIFY(itfc->mKey == 8);
|
||||
|
||||
|
||||
// iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate);
|
||||
// const_iterator find_as(const U& u, UHash uhash, BinaryPredicate predicate) const;
|
||||
|
||||
itf = ihmMW1.find_as(7.f, eastl::hash<float>(), eastl::equal_to_2<int, float>());
|
||||
VERIFY(itf->mKey == 7);
|
||||
|
||||
itfc = ihmMW1Const.find_as(7.f, eastl::hash<float>(), eastl::equal_to_2<int, float>());
|
||||
VERIFY(itfc->mKey == 7);
|
||||
|
||||
|
||||
// iterator erase(iterator);
|
||||
// iterator erase(iterator, iterator);
|
||||
// size_type erase(const key_type&);
|
||||
|
||||
eastl_size_t n = ihmMW1.erase(99999);
|
||||
VERIFY(n == 0);
|
||||
|
||||
n = ihmMW1.erase(17);
|
||||
VERIFY(n == 1);
|
||||
|
||||
itf = ihmMW1.find(18);
|
||||
VERIFY(itf != ihmMW1.end());
|
||||
VERIFY(ihmMW1.validate_iterator(itf) == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itf = ihmMW1.erase(itf);
|
||||
VERIFY(itf != ihmMW1.end());
|
||||
VERIFY(ihmMW1.validate_iterator(itf) == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itf = ihmMW1.find(18);
|
||||
VERIFY(itf == ihmMW1.end());
|
||||
|
||||
itf = ihmMW1.find(19);
|
||||
VERIFY(itf != ihmMW1.end());
|
||||
|
||||
IHM_MW::iterator itf2(itf);
|
||||
eastl::advance(itf2, 7);
|
||||
VERIFY(itf2 != ihmMW1.end());
|
||||
VERIFY(ihmMW1.validate_iterator(itf2) == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itf = ihmMW1.erase(itf, itf2);
|
||||
VERIFY(itf != ihmMW1.end());
|
||||
VERIFY(ihmMW1.validate_iterator(itf) == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itf = ihmMW1.find(19);
|
||||
VERIFY(itf == ihmMW1.end());
|
||||
|
||||
|
||||
// eastl::pair<iterator, iterator> equal_range(const key_type& k);
|
||||
// eastl::pair<const_iterator, const_iterator> equal_range(const key_type& k) const;
|
||||
|
||||
eastl::pair<IHM_MW::iterator, IHM_MW::iterator> p = ihmMW1.equal_range(1);
|
||||
VERIFY(p.first != ihmMW1.end());
|
||||
VERIFY(p.second != ihmMW1.end());
|
||||
|
||||
eastl::pair<IHM_MW::const_iterator, IHM_MW::const_iterator> pc = ihmMW1Const.equal_range(1);
|
||||
VERIFY(pc.first != ihmMW1Const.end());
|
||||
VERIFY(pc.second != ihmMW1Const.end());
|
||||
|
||||
|
||||
// void clear();
|
||||
// bool validate() const;
|
||||
// int validate_iterator(const_iterator i) const;
|
||||
|
||||
IHM_MW::iterator itTest;
|
||||
int iresult = ihmMW1.validate_iterator(itTest);
|
||||
VERIFY(iresult == isf_none);
|
||||
|
||||
itTest = ihmMW1.begin();
|
||||
iresult = ihmMW1.validate_iterator(itTest);
|
||||
VERIFY(iresult == (isf_valid | isf_current | isf_can_dereference));
|
||||
|
||||
itTest = ihmMW1.end();
|
||||
iresult = ihmMW1.validate_iterator(itTest);
|
||||
VERIFY(iresult == (isf_valid | isf_current));
|
||||
|
||||
ihmMW1.clear();
|
||||
ihmMW2.clear();
|
||||
VERIFY(ihmMW1.validate());
|
||||
VERIFY(ihmMW2.validate());
|
||||
|
||||
itTest = ihmMW1.begin();
|
||||
iresult = ihmMW1.validate_iterator(itTest);
|
||||
VERIFY(iresult == (isf_valid | isf_current));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test case of single bucket.
|
||||
eastl::intrusive_hash_set<SetWidget, 1, SWHash> hs;
|
||||
SetWidget node1, node2, node3;
|
||||
|
||||
node1.mX = 1;
|
||||
node2.mX = 2;
|
||||
node3.mX = 3;
|
||||
|
||||
hs.insert(node1);
|
||||
hs.insert(node2);
|
||||
hs.insert(node3);
|
||||
|
||||
const eastl_size_t removeCount = hs.erase(node3);
|
||||
VERIFY(removeCount == 1);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test intrusive_hashtable_iterator(value_type* pNode, value_type** pBucket = NULL)
|
||||
eastl::intrusive_hash_set<SetWidget, 37, SWHash> hs;
|
||||
SetWidget node1, node2, node3;
|
||||
|
||||
node1.mX = 1;
|
||||
node2.mX = 2;
|
||||
node3.mX = 3;
|
||||
|
||||
hs.insert(node1);
|
||||
hs.insert(node2);
|
||||
hs.insert(node3);
|
||||
|
||||
VERIFY(hs.validate());
|
||||
|
||||
hs.remove(node1);
|
||||
hs.remove(node2);
|
||||
hs.remove(node3);
|
||||
|
||||
VERIFY(hs.validate());
|
||||
|
||||
hs.insert(node1);
|
||||
hs.insert(node2);
|
||||
hs.insert(node3);
|
||||
|
||||
VERIFY(hs.validate());
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,403 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/intrusive_list.h>
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <string>
|
||||
#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<IntNode>& 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<IntNode>* mpContainer;
|
||||
IntNode* mpNodeArray;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::intrusive_list<IntNode>;
|
||||
|
||||
|
||||
|
||||
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<eastl::intrusive_list_node>::value);
|
||||
|
||||
const size_t offset = offsetof(intrusive_list_node, mpPrev);
|
||||
VERIFY(offset == sizeof(intrusive_list_node*));
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
IntNode nodes[20];
|
||||
|
||||
intrusive_list<IntNode> 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<IntNode>(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<IntNode> 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<IntNode>::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<IntNode> cilist;
|
||||
intrusive_list<IntNode>::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<IntNode>::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<IntNode>::iterator it1(ilist.begin());
|
||||
intrusive_list<IntNode>::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<IntNode> 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<IntNode>::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<IntNode> ilist1;
|
||||
intrusive_list<IntNode> ilist2(ilist1);
|
||||
ilist1 = ilist2;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void sort()
|
||||
// void sort(Compare compare)
|
||||
|
||||
const int kSize = 10;
|
||||
IntNode nodes[kSize];
|
||||
|
||||
intrusive_list<IntNode> listEmpty;
|
||||
listEmpty.sort();
|
||||
VERIFY(VerifySequence(listEmpty.begin(), listEmpty.end(), int(), "list::sort", -1));
|
||||
|
||||
intrusive_list<IntNode> list1;
|
||||
ListInit(list1, nodes) += 1;
|
||||
list1.sort();
|
||||
VERIFY(VerifySequence(list1.begin(), list1.end(), int(), "list::sort", 1, -1));
|
||||
list1.clear();
|
||||
|
||||
intrusive_list<IntNode> 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<IntNode> 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<IntNode> listB;
|
||||
ListInit(listB, nodes) += 1, 9, 2, 3, 5, 7, 4, 6, 8, 0;
|
||||
listB.sort(eastl::less<int>());
|
||||
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<IntNode> listA;
|
||||
ListInit(listA, nodesA) += 1, 2, 3, 4, 4, 5, 9, 9;
|
||||
|
||||
intrusive_list<IntNode> 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<IntNode> 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<IntNode> listB;
|
||||
ListInit(listB, nodesB) += 1, 2, 3, 4, 4, 5, 9, 9;
|
||||
listB.unique(eastl::equal_to<int>());
|
||||
VERIFY(VerifySequence(listA.begin(), listA.end(), int(), "list::unique", 1, 2, 3, 4, 5, 9, -1));
|
||||
}
|
||||
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/bonus/intrusive_sdlist.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
namespace TestSDListLocal
|
||||
{
|
||||
|
||||
struct IntNode : public intrusive_sdlist_node
|
||||
{
|
||||
IntNode() {}
|
||||
IntNode(int x) : mX(x) {}
|
||||
operator int() const { return mX; }
|
||||
|
||||
int mX;
|
||||
};
|
||||
|
||||
typedef intrusive_sdlist<IntNode> IntrusiveSDList;
|
||||
|
||||
template <class T>
|
||||
eastl::string IntListToString8(const T& cont)
|
||||
{
|
||||
eastl::string s("<");
|
||||
char buf[64];
|
||||
|
||||
for(typename T::const_iterator it(cont.begin()), itEnd(cont.end()); it != itEnd; ++it)
|
||||
{
|
||||
const int& v = *it;
|
||||
sprintf(buf, " %d", v);
|
||||
s += buf;
|
||||
}
|
||||
|
||||
s += " >";
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
bool VerifyContainer(const T& cont, const char *testname, ...)
|
||||
{
|
||||
//if (!cont.validate()) {
|
||||
// EASTLTest_Printf("intrusive_list[%s] container damaged!\n", testname);
|
||||
// return false;
|
||||
//}
|
||||
|
||||
typename T::const_iterator it(cont.begin()), itEnd(cont.end());
|
||||
va_list val;
|
||||
int index = 0;
|
||||
|
||||
va_start(val, testname);
|
||||
while(it != itEnd)
|
||||
{
|
||||
int next = va_arg(val, int);
|
||||
|
||||
if (next == -1 || next != *it)
|
||||
{
|
||||
const int value = *it;
|
||||
const char* const pString = IntListToString8(cont).c_str();
|
||||
EASTLTest_Printf("intrusive_list[%s] Mismatch at index %d: expected %d, found %d; contents: %s\n", testname, index, next, value, pString);
|
||||
va_end(val);
|
||||
return false;
|
||||
}
|
||||
|
||||
++it;
|
||||
++index;
|
||||
}
|
||||
|
||||
if (va_arg(val, int) != -1)
|
||||
{
|
||||
do {
|
||||
++index;
|
||||
} while(va_arg(val, int) != -1);
|
||||
|
||||
const int countainerSize = (int)cont.size();
|
||||
const char* const pString = IntListToString8(cont).c_str();
|
||||
EASTLTest_Printf("intrusive_list[%s] Too many elements: expected %d, found %d; contents: %s\n", testname, index, countainerSize, pString);
|
||||
va_end(val);
|
||||
return false;
|
||||
}
|
||||
|
||||
va_end(val);
|
||||
|
||||
// We silence this by default for a quieter test run.
|
||||
// EASTLTest_Printf("intrusive_list[%s] pass\n", testname);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class ListInit
|
||||
{
|
||||
public:
|
||||
ListInit(intrusive_sdlist<IntNode>& 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_sdlist<IntNode>* mpContainer;
|
||||
IntNode* mpNodeArray;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::intrusive_sdlist<TestSDListLocal::IntNode>;
|
||||
|
||||
|
||||
|
||||
int TestIntrusiveSDList()
|
||||
{
|
||||
using namespace TestSDListLocal;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
IntNode nodes[20];
|
||||
|
||||
IntrusiveSDList l;
|
||||
|
||||
// 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.
|
||||
delete new IntrusiveSDList(l);
|
||||
|
||||
// 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 { IntrusiveSDList m; };
|
||||
|
||||
#ifndef __GNUC__ // GCC warns on this, though strictly specaking it is allowed to.
|
||||
(void)offsetof(Test, m);
|
||||
#endif
|
||||
|
||||
VERIFY(VerifyContainer(l, "ctor()", -1));
|
||||
|
||||
// push_back
|
||||
ListInit(l, nodes) += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
|
||||
VERIFY(VerifyContainer(l, "push_back()", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1));
|
||||
|
||||
// iterator++
|
||||
{
|
||||
IntrusiveSDList::iterator it1(l.begin());
|
||||
IntrusiveSDList::iterator it2(l.begin());
|
||||
|
||||
++it1;
|
||||
++it2;
|
||||
|
||||
if (it1 != it2++ || ++it1 != it2) {
|
||||
VERIFY(!"[iterator::increment] fail\n");
|
||||
}
|
||||
}
|
||||
|
||||
// clear()/empty()
|
||||
VERIFY(!l.empty());
|
||||
|
||||
l.clear();
|
||||
VERIFY(VerifyContainer(l, "clear()", -1));
|
||||
VERIFY(l.empty());
|
||||
|
||||
l.erase(l.begin(), l.end()); // Erase an already empty container.
|
||||
VERIFY(l.empty());
|
||||
|
||||
IntrusiveSDList l2;
|
||||
|
||||
// splice
|
||||
//ListInit(l, nodes) += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
|
||||
//
|
||||
//l.splice(++l.begin(), l, --l.end());
|
||||
//VERIFY(VerifyContainer(l, "splice(single)", 0, 9, 1, 2, 3, 4, 5, 6, 7, 8, -1));
|
||||
//
|
||||
//ListInit(l2, nodes+10) += 10, 11, 12, 13, 14, 15, 16, 17, 18, 19;
|
||||
//
|
||||
//l.splice(++++l.begin(), l2);
|
||||
//VERIFY(VerifyContainer(l2, "splice(whole)", -1));
|
||||
//VERIFY(VerifyContainer(l, "splice(whole)", 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 2, 3, 4, 5, 6, 7, 8, -1));
|
||||
|
||||
//l.splice(l.begin(), l, ++++l.begin(), ----l.end());
|
||||
//VERIFY(VerifyContainer(l, "splice(range)", 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1, 2, 3, 4, 5, 6, 0, 9, 7, 8, -1));
|
||||
|
||||
//l.clear();
|
||||
//l.swap(l2);
|
||||
//VERIFY(VerifyContainer(l, "swap(empty)", -1));
|
||||
//VERIFY(VerifyContainer(l2, "swap(empty)", -1));
|
||||
|
||||
//l2.push_back(nodes[0]);
|
||||
//l.splice(l.begin(), l2);
|
||||
//VERIFY(VerifyContainer(l, "splice(single)", 0, -1));
|
||||
//VERIFY(VerifyContainer(l2, "splice(single)", -1));
|
||||
|
||||
// splice(single) -- evil case (splice at or right after current position)
|
||||
//ListInit(l, nodes) += 0, 1, 2, 3, 4;
|
||||
//l.splice(++++l.begin(), *++++l.begin());
|
||||
//VERIFY(VerifyContainer(l, "splice(single)", 0, 1, 2, 3, 4, -1));
|
||||
//l.splice(++++++l.begin(), *++++l.begin());
|
||||
//VERIFY(VerifyContainer(l, "splice(single)", 0, 1, 2, 3, 4, -1));
|
||||
|
||||
// splice(range) -- evil case (splice right after current position)
|
||||
//ListInit(l, nodes) += 0, 1, 2, 3, 4;
|
||||
//l.splice(++++l.begin(), l, ++l.begin(), ++++l.begin());
|
||||
//VERIFY(VerifyContainer(l, "splice(range)", 0, 1, 2, 3, 4, -1));
|
||||
|
||||
// push_front()
|
||||
l.clear();
|
||||
l2.clear();
|
||||
for(int i=4; i>=0; --i) {
|
||||
l.push_front(nodes[i]);
|
||||
l2.push_front(nodes[i+5]);
|
||||
}
|
||||
|
||||
VERIFY(VerifyContainer(l, "push_front()", 0, 1, 2, 3, 4, -1));
|
||||
VERIFY(VerifyContainer(l2, "push_front()", 5, 6, 7, 8, 9, -1));
|
||||
|
||||
// swap()
|
||||
l.swap(l2);
|
||||
VERIFY(VerifyContainer(l, "swap()", 5, 6, 7, 8, 9, -1));
|
||||
VERIFY(VerifyContainer(l2, "swap()", 0, 1, 2, 3, 4, -1));
|
||||
|
||||
// erase()
|
||||
ListInit(l2, nodes) += 0, 1, 2, 3, 4;
|
||||
ListInit(l, nodes+5) += 5, 6, 7, 8, 9;
|
||||
l.erase(++++l.begin());
|
||||
VERIFY(VerifyContainer(l, "erase(single)", 5, 6, 8, 9, -1));
|
||||
|
||||
l.erase(l.begin(), l.end());
|
||||
VERIFY(VerifyContainer(l, "erase(all)", -1));
|
||||
|
||||
ListInit(l, nodes) += 0, 1, 2;
|
||||
VERIFY(l2.size() == 3);
|
||||
|
||||
l2.pop_front();
|
||||
VERIFY(VerifyContainer(l2, "pop_front()", 1, 2, -1));
|
||||
|
||||
l2.pop_back();
|
||||
VERIFY(VerifyContainer(l2, "pop_back()", 1, -1));
|
||||
|
||||
// remove
|
||||
IntNode i1(1), i2(2), i3(3);
|
||||
l.clear();
|
||||
|
||||
l.push_front(i1);
|
||||
IntrusiveSDList::remove(i1);
|
||||
VERIFY(VerifyContainer(l, "remove()", -1));
|
||||
|
||||
l.push_front(i1);
|
||||
l.push_front(i2);
|
||||
IntrusiveSDList::remove(i1);
|
||||
VERIFY(VerifyContainer(l, "remove()", 2, -1));
|
||||
|
||||
l.push_front(i1);
|
||||
IntrusiveSDList::remove(i2);
|
||||
VERIFY(VerifyContainer(l, "remove()", 1, -1));
|
||||
|
||||
l.push_back(i2);
|
||||
l.push_back(i3);
|
||||
IntrusiveSDList::remove(i2);
|
||||
VERIFY(VerifyContainer(l, "remove()", 1, 3, -1));
|
||||
|
||||
|
||||
// const_iterator / begin
|
||||
const intrusive_sdlist<IntNode> cilist;
|
||||
intrusive_sdlist<IntNode>::const_iterator cit;
|
||||
for(cit = cilist.begin(); cit != cilist.end(); ++cit)
|
||||
VERIFY(cit == cilist.end()); // This is guaranteed to be false.
|
||||
|
||||
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/bonus/intrusive_slist.h>
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
//template class intrusive_slist<int>;
|
||||
|
||||
|
||||
|
||||
int TestIntrusiveSList()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// As of this writing, we don't yet have a completed intrusive_slist implementation.
|
||||
// The interface is in place but the implementation hasn't been done yet.
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,579 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/deque.h>
|
||||
#include <EASTL/iterator.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/set.h>
|
||||
#include <EASTL/array.h>
|
||||
#include <EASTL/numeric.h>
|
||||
#include <EASTL/list.h>
|
||||
#include <EASTL/slist.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/intrusive_list.h>
|
||||
#include <EASTL/memory.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
template <class T>
|
||||
using detect_iterator_traits_reference = typename eastl::iterator_traits<T>::reference;
|
||||
|
||||
// This is used below, though is currently disabled as documented below.
|
||||
struct IListNode : public eastl::intrusive_list_node{};
|
||||
|
||||
int TestIterator_advance()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
// void advance(InputIterator& i, Distance n)
|
||||
const int num_elements = 10;
|
||||
int i;
|
||||
|
||||
eastl::vector<int> v;
|
||||
for(i = 0; i < num_elements; i++)
|
||||
v.push_back(i);
|
||||
|
||||
// test forward advancement
|
||||
eastl::vector<int>::iterator it = v.begin();
|
||||
for(i = 0; i < num_elements; i++)
|
||||
{
|
||||
EATEST_VERIFY(*it == v[i]);
|
||||
eastl::advance(it, 1);
|
||||
}
|
||||
|
||||
// test backwards advancement
|
||||
eastl::vector<int>::iterator it2 = v.end();
|
||||
i = num_elements - 1;
|
||||
do
|
||||
{
|
||||
eastl::advance(it2, -1);
|
||||
EATEST_VERIFY(*it2 == v[i]);
|
||||
}
|
||||
while(i-- != 0);
|
||||
}
|
||||
|
||||
{
|
||||
// void advance(InputIterator& i, Distance n)
|
||||
eastl::list<int> intList;
|
||||
intList.push_back(0);
|
||||
intList.push_back(1);
|
||||
intList.push_back(42);
|
||||
intList.push_back(2);
|
||||
|
||||
eastl::list<int>::iterator it = intList.begin();
|
||||
eastl::advance(it, intList.size());
|
||||
EATEST_VERIFY(it == intList.end());
|
||||
|
||||
// Exercise advance with an signed Distance type.
|
||||
it = intList.begin();
|
||||
eastl::advance(it, (ssize_t)intList.size());
|
||||
EATEST_VERIFY(it == intList.end());
|
||||
|
||||
|
||||
eastl::slist<int> intSlist;
|
||||
intSlist.push_front(0);
|
||||
intSlist.push_front(1);
|
||||
intSlist.push_front(42);
|
||||
intSlist.push_front(2);
|
||||
|
||||
eastl::slist<int>::iterator its = intSlist.begin();
|
||||
eastl::advance(its, intSlist.size());
|
||||
EATEST_VERIFY(its == intSlist.end());
|
||||
|
||||
// Exercise advance with an signed Distance type.
|
||||
its = intSlist.begin();
|
||||
eastl::advance(its, (ssize_t)intSlist.size());
|
||||
EATEST_VERIFY(its == intSlist.end());
|
||||
}
|
||||
|
||||
{
|
||||
// void next(InputIterator& i, Distance n)
|
||||
eastl::vector<int> v;
|
||||
v.push_back(0);
|
||||
v.push_back(1);
|
||||
v.push_back(42);
|
||||
v.push_back(2);
|
||||
|
||||
eastl::vector<int>::iterator it = v.begin();
|
||||
EATEST_VERIFY(*eastl::next(it, 0) == 0);
|
||||
EATEST_VERIFY(*eastl::next(it /*testing the iterator distance default value*/) == 1);
|
||||
EATEST_VERIFY(*eastl::next(it, 2) == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// void prev(InputIterator& i, Distance n)
|
||||
eastl::vector<int> v;
|
||||
v.push_back(0);
|
||||
v.push_back(1);
|
||||
v.push_back(42);
|
||||
v.push_back(2);
|
||||
|
||||
eastl::vector<int>::iterator it = v.end();
|
||||
EATEST_VERIFY(*eastl::prev(it, 2) == 42);
|
||||
EATEST_VERIFY(*eastl::prev(it /*testing the iterator distance default value*/) == 2);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
int TestIterator_moveIterator()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
eastl::vector<int> v = {0, 1, 42, 2};
|
||||
const auto constBeginMoveIter = eastl::make_move_iterator(v.begin());
|
||||
|
||||
// operator++(int)
|
||||
auto moveIter = constBeginMoveIter;
|
||||
moveIter++; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator.
|
||||
EATEST_VERIFY(*moveIter != *constBeginMoveIter);
|
||||
|
||||
// operator--(int)
|
||||
moveIter = constBeginMoveIter + 2; // points to '42'
|
||||
moveIter--; // the result of the expression is the incremented value, we need this test to read the existing state of the iterator.
|
||||
EATEST_VERIFY(*moveIter != *(constBeginMoveIter + 2));
|
||||
}
|
||||
|
||||
{
|
||||
// Ensure that move_iterator indeed move yielded value whenever possible.
|
||||
auto x = eastl::make_unique<int>(42);
|
||||
auto* pX = &x;
|
||||
auto moveIter = eastl::make_move_iterator(pX);
|
||||
|
||||
constexpr bool isCorrectReferenceType = eastl::is_same_v<decltype(moveIter)::reference, eastl::unique_ptr<int>&&>;
|
||||
constexpr bool isCorrectReturnType = eastl::is_same_v<decltype(*moveIter), eastl::unique_ptr<int>&&>;
|
||||
|
||||
static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type.");
|
||||
static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type.");
|
||||
EATEST_VERIFY(isCorrectReferenceType);
|
||||
EATEST_VERIFY(isCorrectReturnType);
|
||||
|
||||
auto pMoveX = *moveIter;
|
||||
EATEST_VERIFY(*pMoveX == 42);
|
||||
}
|
||||
|
||||
// Bellow are regression tests that ensure we are covering the defect LWG 2106: http://cplusplus.github.io/LWG/lwg-defects.html#2106
|
||||
{
|
||||
// Check that we support iterators yielding const references.
|
||||
const int x = 42;
|
||||
const int* pX = &x;
|
||||
auto moveIter = eastl::make_move_iterator(pX);
|
||||
|
||||
constexpr bool isCorrectReferenceType = eastl::is_same_v<decltype(moveIter)::reference, const int&&>;
|
||||
constexpr bool isCorrectReturnType = eastl::is_same_v<decltype(*moveIter), const int&&>;
|
||||
|
||||
static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type.");
|
||||
static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type.");
|
||||
EATEST_VERIFY(isCorrectReferenceType);
|
||||
EATEST_VERIFY(isCorrectReturnType);
|
||||
|
||||
auto pCopiedX = *moveIter;
|
||||
EATEST_VERIFY(pCopiedX == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// Check that we support iterators yielding plain value (typically a proxy-iterator).
|
||||
struct FakeProxyIterator
|
||||
{
|
||||
using iterator_category = EASTL_ITC_NS::forward_iterator_tag;
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = int;
|
||||
using pointer = int; // Note that we are yielding by value.
|
||||
using reference = int; // Note that we are yielding by value.
|
||||
|
||||
reference operator*() const { return 42; }
|
||||
pointer operator->() { return 42; }
|
||||
FakeProxyIterator& operator++() { return *this; }
|
||||
FakeProxyIterator operator++(int) { return {}; }
|
||||
|
||||
bool operator==(const FakeProxyIterator& rhs) { return true; };
|
||||
bool operator!=(const FakeProxyIterator& rhs) { return false; };
|
||||
};
|
||||
|
||||
FakeProxyIterator it = {};
|
||||
auto moveIter = eastl::make_move_iterator(it);
|
||||
|
||||
constexpr bool isCorrectReferenceType = eastl::is_same_v<decltype(moveIter)::reference, int>;
|
||||
constexpr bool isCorrectReturnType = eastl::is_same_v<decltype(*moveIter), int>;
|
||||
|
||||
static_assert(isCorrectReferenceType, "move_iterator::reference has wrong type.");
|
||||
static_assert(isCorrectReturnType, "move_iterator::operator*() has wrong return type.");
|
||||
EATEST_VERIFY(isCorrectReferenceType);
|
||||
EATEST_VERIFY(isCorrectReturnType);
|
||||
|
||||
auto pCopiedX = *moveIter;
|
||||
EATEST_VERIFY(pCopiedX == 42);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestIterator
|
||||
//
|
||||
int TestIterator()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
nErrorCount += TestIterator_advance();
|
||||
nErrorCount += TestIterator_moveIterator();
|
||||
|
||||
{
|
||||
// reverse_iterator
|
||||
// reverse_iterator<Iterator> make_reverse_iterator(Iterator mi)
|
||||
{
|
||||
eastl::vector<int> src;
|
||||
for(int i = 0; i < 10; i++)
|
||||
src.push_back(i); // src should become {0,1,2,3,4,5,6,7,8,9}
|
||||
|
||||
auto itr = eastl::make_reverse_iterator(src.end());
|
||||
EATEST_VERIFY(*itr == 9); ++itr;
|
||||
EATEST_VERIFY(*itr == 8); ++itr;
|
||||
EATEST_VERIFY(*itr == 7); ++itr;
|
||||
EATEST_VERIFY(*itr == 6); ++itr;
|
||||
EATEST_VERIFY(*itr == 5); ++itr;
|
||||
EATEST_VERIFY(*itr == 4); ++itr;
|
||||
EATEST_VERIFY(*itr == 3); ++itr;
|
||||
EATEST_VERIFY(*itr == 2); ++itr;
|
||||
EATEST_VERIFY(*itr == 1); ++itr;
|
||||
EATEST_VERIFY(*itr == 0); ++itr;
|
||||
EATEST_VERIFY( itr == src.rend());
|
||||
EATEST_VERIFY( itr == eastl::make_reverse_iterator(src.begin()));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Regression bug with assign/insert combined with reverse iterator.
|
||||
eastl::vector<int> a;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
a.push_back(i);
|
||||
}
|
||||
|
||||
eastl::deque<int> d;
|
||||
d.assign(a.rbegin(), a.rend());
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
EATEST_VERIFY(a[i] == d[a.size() - i - 1]);
|
||||
}
|
||||
d.insert(d.end(), a.rbegin(), a.rend());
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
EATEST_VERIFY(a[i] == d[d.size() - i - 1]);
|
||||
}
|
||||
|
||||
eastl::vector<int> b;
|
||||
b.assign(a.rbegin(), a.rend());
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
EATEST_VERIFY(a[i] == b[a.size() - i - 1]);
|
||||
}
|
||||
b.insert(b.end(), a.rbegin(), a.rend());
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
EATEST_VERIFY(a[i] == b[b.size() - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// move_iterator
|
||||
// move_iterator<Iterator> make_move_iterator(Iterator mi)
|
||||
typedef eastl::vector<eastl::string> StringArray;
|
||||
|
||||
StringArray src;
|
||||
for(eastl_size_t i = 0; i < 4; i++)
|
||||
src.push_back(eastl::string(1, (char8_t)('0' + i))); // v should become {"0", "1", "2", "3"};
|
||||
|
||||
// Moves the values out of the string array and into the result.
|
||||
StringArray dst(eastl::make_move_iterator(src.begin()), eastl::make_move_iterator(src.end()));
|
||||
|
||||
EATEST_VERIFY((src.size() == 4) && (src[0] == "") && (src[3] == ""));
|
||||
EATEST_VERIFY((dst.size() == 4) && (dst[0] == "0") && (dst[3] == "3"));
|
||||
}
|
||||
|
||||
{
|
||||
// back_insert_iterator
|
||||
// back_inserter
|
||||
EA_CPP14_CONSTEXPR int n = 3;
|
||||
eastl::vector<TestObject> v1, v2, v3;
|
||||
v1.resize(n); v2.reserve(n); v3.reserve(n);
|
||||
{
|
||||
int64_t copyCtorCount0 = TestObject::sTOCopyCtorCount, moveCtorCount0 = TestObject::sTOMoveCtorCount;
|
||||
eastl::copy(v1.begin(), v1.end(), eastl::back_inserter(v2));
|
||||
EATEST_VERIFY(v1.size() == v2.size() && TestObject::sTOCopyCtorCount == (copyCtorCount0 + n) &&
|
||||
TestObject::sTOMoveCtorCount == moveCtorCount0);
|
||||
}
|
||||
{
|
||||
int64_t copyCtorCount0 = TestObject::sTOCopyCtorCount, moveCtorCount0 = TestObject::sTOMoveCtorCount;
|
||||
eastl::move(v1.begin(), v1.end(), eastl::back_inserter(v3));
|
||||
EATEST_VERIFY(v1.size() == v3.size() && TestObject::sTOCopyCtorCount == copyCtorCount0 &&
|
||||
TestObject::sTOMoveCtorCount == (moveCtorCount0 + n));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// front_insert_iterator
|
||||
// front_inserter
|
||||
// To do.
|
||||
}
|
||||
|
||||
{
|
||||
// insert_iterator
|
||||
// inserter
|
||||
// To do.
|
||||
}
|
||||
|
||||
{
|
||||
// difference_type distance(InputIterator first, InputIterator last)
|
||||
eastl::vector<int> intVector = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
EATEST_VERIFY(eastl::distance(intVector.begin(), intVector.end()) == 8);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
#if EASTL_BEGIN_END_ENABLED
|
||||
// begin / end
|
||||
// auto inline begin(Container& container) -> decltype(container.begin())
|
||||
// auto inline end(Container& container) -> decltype(container.end())
|
||||
|
||||
eastl::vector<int> intVector;
|
||||
eastl::vector<int>::iterator intVectorIterator = eastl::begin(intVector);
|
||||
EATEST_VERIFY(intVectorIterator == eastl::end(intVector));
|
||||
|
||||
eastl::list<int> intList;
|
||||
eastl::list<int>::iterator intListIterator = eastl::begin(intList);
|
||||
EATEST_VERIFY(intListIterator == eastl::end(intList));
|
||||
|
||||
eastl::set<int> intSet;
|
||||
eastl::set<int>::iterator intSetIterator = eastl::begin(intSet);
|
||||
EATEST_VERIFY(intSetIterator == eastl::end(intSet));
|
||||
|
||||
eastl::array<int, 0> intArray;
|
||||
eastl::array<int>::iterator intArrayIterator = eastl::begin(intArray);
|
||||
EATEST_VERIFY(intArrayIterator == eastl::end(intArray));
|
||||
|
||||
eastl::intrusive_list<IListNode> intIList;
|
||||
eastl::intrusive_list<IListNode>::iterator intIListIterator = eastl::begin(intIList);
|
||||
EATEST_VERIFY(intIListIterator == eastl::end(intIList));
|
||||
|
||||
eastl::string8 str8;
|
||||
eastl::string8::iterator string8Iterator = eastl::begin(str8);
|
||||
EATEST_VERIFY(string8Iterator == eastl::end(str8));
|
||||
#endif
|
||||
}
|
||||
|
||||
// eastl::data
|
||||
{
|
||||
eastl::array<int, 0> intArray;
|
||||
int* pIntArrayData = eastl::data(intArray);
|
||||
EATEST_VERIFY(pIntArrayData == intArray.data());
|
||||
|
||||
eastl::vector<int> intVector;
|
||||
int* pIntVectorData = eastl::data(intVector);
|
||||
EATEST_VERIFY(pIntVectorData == intVector.data());
|
||||
|
||||
int intCArray[34];
|
||||
int* pIntCArray = eastl::data(intCArray);
|
||||
EATEST_VERIFY(pIntCArray == intCArray);
|
||||
|
||||
std::initializer_list<int> intInitList;
|
||||
const int* pIntInitList = eastl::data(intInitList);
|
||||
EATEST_VERIFY(pIntInitList == intInitList.begin());
|
||||
}
|
||||
|
||||
// eastl::size
|
||||
{
|
||||
eastl::vector<int> intVector;
|
||||
intVector.push_back();
|
||||
intVector.push_back();
|
||||
intVector.push_back();
|
||||
EATEST_VERIFY(eastl::size(intVector) == 3);
|
||||
|
||||
int intCArray[34];
|
||||
EATEST_VERIFY(eastl::size(intCArray) == 34);
|
||||
static_assert(eastl::size(intCArray) == 34, "eastl::size failure");
|
||||
}
|
||||
|
||||
// eastl::ssize
|
||||
{
|
||||
eastl::vector<int> intVector;
|
||||
intVector.push_back();
|
||||
intVector.push_back();
|
||||
intVector.push_back();
|
||||
EATEST_VERIFY(eastl::ssize(intVector) == (signed)3);
|
||||
|
||||
int intCArray[34];
|
||||
EATEST_VERIFY(eastl::ssize(intCArray) == (signed)34);
|
||||
static_assert(eastl::ssize(intCArray) == 34, "eastl::ssize failure");
|
||||
}
|
||||
|
||||
// eastl::empty
|
||||
{
|
||||
eastl::vector<int> intVector;
|
||||
EATEST_VERIFY(eastl::empty(intVector));
|
||||
intVector.push_back();
|
||||
EATEST_VERIFY(!eastl::empty(intVector));
|
||||
|
||||
std::initializer_list<int> intInitListEmpty;
|
||||
EATEST_VERIFY(eastl::empty(intInitListEmpty));
|
||||
EATEST_VERIFY(!eastl::empty({1, 2, 3, 4, 5, 6}));
|
||||
}
|
||||
|
||||
// Range-based for loops
|
||||
{
|
||||
{
|
||||
eastl::vector<int> v;
|
||||
int I = 0;
|
||||
|
||||
v.push_back(0);
|
||||
v.push_back(1);
|
||||
|
||||
for(int i : v)
|
||||
EATEST_VERIFY(i == I++);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::string s8;
|
||||
char C = 'a';
|
||||
|
||||
s8.push_back('a');
|
||||
s8.push_back('b');
|
||||
|
||||
for(char c : s8)
|
||||
EATEST_VERIFY(c == C++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// is_iterator_wrapper
|
||||
static_assert((eastl::is_iterator_wrapper<void>::value == false), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<int>::value == false), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<int*>::value == false), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<eastl::array<int>::iterator>::value == false), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<eastl::array<char>*>::value == false), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<eastl::vector<char> >::value == false), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<eastl::generic_iterator<int*> >::value == true), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<eastl::move_iterator<eastl::array<int>::iterator> >::value == true), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<eastl::array<int>::iterator> >::value == false), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<int*> >::value == false), "is_iterator_wrapper failure");
|
||||
static_assert((eastl::is_iterator_wrapper<eastl::reverse_iterator<eastl::move_iterator<int*>> >::value == true), "is_iterator_wrapper failure");
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// unwrap_iterator
|
||||
int intArray[2];
|
||||
int* pInt = eastl::unwrap_iterator(&intArray[0]);
|
||||
intArray[0] = 17;
|
||||
EATEST_VERIFY(*pInt == 17);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(&intArray[0])), int*>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::generic_iterator<int*> giIntArray(intArray);
|
||||
pInt = eastl::unwrap_iterator(giIntArray);
|
||||
intArray[0] = 18;
|
||||
EATEST_VERIFY(*pInt == 18);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(giIntArray)), int*>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::vector<int> intVector(4, 19);
|
||||
eastl::vector<int>::iterator itVector = eastl::unwrap_iterator(intVector.begin());
|
||||
EATEST_VERIFY(*itVector == 19);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(intVector.begin())), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::move_iterator<eastl::vector<int>::iterator> miIntVector(intVector.begin());
|
||||
itVector = eastl::unwrap_iterator(miIntVector);
|
||||
intVector[0] = 20;
|
||||
EATEST_VERIFY(*itVector == 20);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(miIntVector)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::reverse_iterator<eastl::vector<int>::iterator> riIntVector = intVector.rbegin();
|
||||
eastl::reverse_iterator<eastl::vector<int>::iterator> riUnwrapped = eastl::unwrap_iterator(riIntVector);
|
||||
EATEST_VERIFY(*riUnwrapped == 19);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(riIntVector)), eastl::reverse_iterator<eastl::vector<int>::iterator>>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::reverse_iterator<eastl::move_iterator<eastl::vector<int>::iterator>> rimiIntVec(miIntVector);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(rimiIntVec)), eastl::reverse_iterator<eastl::vector<int>::iterator>>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::reverse_iterator<eastl::generic_iterator<int*>> rigiIntArray(giIntArray);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(rigiIntArray)), eastl::reverse_iterator<int*>>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::deque<int> intDeque(3);
|
||||
eastl::deque<int>::iterator begin = intDeque.begin();
|
||||
eastl::generic_iterator<eastl::deque<int>::iterator> giWrappedBegin(begin);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_iterator(giWrappedBegin)), eastl::deque<int>::iterator>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::deque<int>::iterator unwrappedBegin = eastl::unwrap_iterator(giWrappedBegin);
|
||||
EATEST_VERIFY(begin == unwrappedBegin);
|
||||
}
|
||||
|
||||
{
|
||||
// unwrap_generic_iterator
|
||||
int intArray[2] = {0, 1};
|
||||
eastl::generic_iterator<int*> giIntArray(intArray);
|
||||
int* pInt = eastl::unwrap_generic_iterator(giIntArray);
|
||||
EATEST_VERIFY(*pInt == 0);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(giIntArray)), int*>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::move_iterator<int*> miIntArray(intArray);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(miIntArray)), eastl::move_iterator<int*>>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::vector<int> intVector(1, 1);
|
||||
eastl::generic_iterator<eastl::vector<int>::iterator> giVectorInt(intVector.begin());
|
||||
eastl::vector<int>::iterator it = unwrap_generic_iterator(giVectorInt);
|
||||
EATEST_VERIFY(*it == 1);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_generic_iterator(giVectorInt)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure");
|
||||
}
|
||||
|
||||
{
|
||||
// unwrap_move_iterator
|
||||
int intArray[2] = {0, 1};
|
||||
eastl::move_iterator<int*> miIntArray(intArray);
|
||||
int* pInt = eastl::unwrap_move_iterator(miIntArray);
|
||||
EATEST_VERIFY(*pInt == 0);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(miIntArray)), int*>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::generic_iterator<int*> giIntArray(intArray);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(giIntArray)), eastl::generic_iterator<int*>>::value == true), "unwrap_iterator failure");
|
||||
|
||||
eastl::vector<int> intVector(1, 1);
|
||||
eastl::move_iterator<eastl::vector<int>::iterator> miVectorInt(intVector.begin());
|
||||
eastl::vector<int>::iterator it = unwrap_move_iterator(miVectorInt);
|
||||
EATEST_VERIFY(*it == 1);
|
||||
static_assert((eastl::is_same<decltype(eastl::unwrap_move_iterator(miVectorInt)), eastl::vector<int>::iterator>::value == true), "unwrap_iterator failure");
|
||||
}
|
||||
|
||||
{
|
||||
// array cbegin - cend
|
||||
int arr[3]{ 1, 2, 3 };
|
||||
auto b = eastl::cbegin(arr);
|
||||
auto e = eastl::cend(arr);
|
||||
EATEST_VERIFY(*b == 1);
|
||||
|
||||
auto dist = eastl::distance(b,e);
|
||||
EATEST_VERIFY(dist == 3);
|
||||
}
|
||||
|
||||
{
|
||||
// Regression test that ensure N3844 is working correctly.
|
||||
static_assert(!eastl::is_detected<detect_iterator_traits_reference, int>::value, "detecting iterator_traits<int> should SFINAE gracefully.");
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,222 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/utility.h>
|
||||
#include <EASTL/bonus/list_map.h>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// We would like to use the generic EASTLTest VerifySequence function, but it's not currently ready to deal
|
||||
// with non-POD types. That can probably be solved, but in the meantime we implement a custom function here.
|
||||
template <typename T1, typename T2>
|
||||
bool VerifyListMapSequence(const char* pName,
|
||||
eastl::list_map<T1, T2>& listMap,
|
||||
T1 t1End, T2,
|
||||
T1 t10 = 0, T2 t20 = 0,
|
||||
T1 t11 = 0, T2 t21 = 0,
|
||||
T1 t12 = 0, T2 t22 = 0,
|
||||
T1 t13 = 0, T2 t23 = 0,
|
||||
T1 t14 = 0, T2 t24 = 0,
|
||||
T1 t15 = 0, T2 t25 = 0)
|
||||
{
|
||||
typename eastl::list_map<T1, T2>::iterator it = listMap.begin();
|
||||
|
||||
if(t10 == t1End)
|
||||
return (it == listMap.end());
|
||||
if(it->first != t10 || it->second != t20)
|
||||
{ EASTLTest_Printf("[%s] Mismatch at index %d\n", pName, 0); return false; }
|
||||
++it;
|
||||
|
||||
if(t11 == t1End)
|
||||
return (it == listMap.end());
|
||||
if(it->first != t11 || it->second != t21)
|
||||
{ EASTLTest_Printf("[%s] Mismatch at index %d\n", pName, 1); return false; }
|
||||
++it;
|
||||
|
||||
if(t12 == t1End)
|
||||
return (it == listMap.end());
|
||||
if(it->first != t12 || it->second != t22)
|
||||
{ EASTLTest_Printf("[%s] Mismatch at index %d\n", pName, 2); return false; }
|
||||
++it;
|
||||
|
||||
if(t13 == t1End)
|
||||
return (it == listMap.end());
|
||||
if(it->first != t13 || it->second != t23)
|
||||
{ EASTLTest_Printf("[%s] Mismatch at index %d\n", pName, 3); return false; }
|
||||
++it;
|
||||
|
||||
if(t14 == t1End)
|
||||
return (it == listMap.end());
|
||||
if(it->first != t14 || it->second != t24)
|
||||
{ EASTLTest_Printf("[%s] Mismatch at index %d\n", pName, 4); return false; }
|
||||
++it;
|
||||
|
||||
if(t15 == t1End)
|
||||
return (it == listMap.end());
|
||||
if(it->first != t15 || it->second != t25)
|
||||
{ EASTLTest_Printf("[%s] Mismatch at index %d\n", pName, 5); return false; }
|
||||
++it;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int TestListMap()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
typedef eastl::list_map<uint32_t, uint64_t> TestMapType;
|
||||
typedef eastl::pair<uint32_t, uint64_t> ValueType; // We currently can't use TestMapType::value_type because its 'first' is const.
|
||||
|
||||
TestMapType testMap;
|
||||
TestMapType::iterator iter;
|
||||
TestMapType::const_iterator c_iter;
|
||||
TestMapType::reverse_iterator rIter;
|
||||
TestMapType::const_reverse_iterator c_rIter;
|
||||
TestMapType::iterator tempIter;
|
||||
|
||||
EATEST_VERIFY(testMap.empty());
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.push_front(ValueType(3, 1003));
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.push_back(ValueType(4, 1004));
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.push_back(ValueType(2, 1002));
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.push_front(ValueType(6, 1006));
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
EATEST_VERIFY(!testMap.empty());
|
||||
EATEST_VERIFY(testMap.size() == 4);
|
||||
|
||||
EATEST_VERIFY(testMap.find(3) != testMap.end());
|
||||
EATEST_VERIFY(testMap.find(5) == testMap.end());
|
||||
EATEST_VERIFY((VerifyListMapSequence<uint32_t, uint64_t>("list_map::push_back", testMap, UINT32_MAX, 0, 6, 1006, 3, 1003, 4, 1004, 2, 1002, UINT32_MAX, 0)));
|
||||
|
||||
iter = testMap.find(3);
|
||||
EATEST_VERIFY((iter->first == 3) && ((++iter)->first == 4) && ((++iter)->first == 2));
|
||||
|
||||
rIter = testMap.rbegin();
|
||||
EATEST_VERIFY((rIter->first == 2) && ((++rIter)->first == 4) && ((++rIter)->first == 3) && ((++rIter)->first == 6));
|
||||
|
||||
TestMapType::const_reference rFront = testMap.front();
|
||||
EATEST_VERIFY(rFront.first == 6);
|
||||
|
||||
TestMapType::reference rBack = testMap.back();
|
||||
EATEST_VERIFY(rBack.first == 2);
|
||||
|
||||
testMap.clear();
|
||||
EATEST_VERIFY(testMap.empty());
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
iter = testMap.begin();
|
||||
EATEST_VERIFY(iter == testMap.end());
|
||||
|
||||
testMap.push_back(ValueType(10, 1010));
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.push_front(ValueType(8, 1008));
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.push_back(7, 1007);
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.push_front(9, 1009);
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.push_back(11, 1011LL);
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
EATEST_VERIFY((VerifyListMapSequence<uint32_t, uint64_t>("list_map::push_back", testMap, UINT32_MAX, 0, 9, 1009, 8, 1008, 10, 1010, 7, 1007, 11, 1011, UINT32_MAX, 0)));
|
||||
|
||||
testMap.pop_front();
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
EATEST_VERIFY((VerifyListMapSequence<uint32_t, uint64_t>("list_map::push_back", testMap, UINT32_MAX, 0, 8, 1008, 10, 1010, 7, 1007, 11, 1011, UINT32_MAX, 0)));
|
||||
|
||||
rIter = testMap.rbegin();
|
||||
EATEST_VERIFY((rIter->first == 11 && ((++rIter)->first == 7) && ((++rIter)->first == 10) && ((++rIter)->first == 8)));
|
||||
|
||||
testMap.pop_back();
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
EATEST_VERIFY((VerifyListMapSequence<uint32_t, uint64_t>("list_map::push_back", testMap, UINT32_MAX, 0, 8, 1008, 10, 1010, 7, 1007, UINT32_MAX, 0)));
|
||||
|
||||
rIter = testMap.rbegin();
|
||||
EATEST_VERIFY(((rIter)->first == 7) && ((++rIter)->first == 10) && ((++rIter)->first == 8));
|
||||
|
||||
tempIter = testMap.find(10);
|
||||
EATEST_VERIFY(tempIter != testMap.end());
|
||||
|
||||
testMap.erase(10);
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
EATEST_VERIFY((VerifyListMapSequence<uint32_t, uint64_t>("list_map::push_back", testMap, UINT32_MAX, 0, 8, 1008, 7, 1007, UINT32_MAX, 0)));
|
||||
|
||||
EATEST_VERIFY(testMap.validate_iterator(testMap.find(8)) == (eastl::isf_valid | eastl::isf_current | eastl::isf_can_dereference));
|
||||
EATEST_VERIFY(testMap.validate_iterator(testMap.find(30)) == (eastl::isf_valid | eastl::isf_current));
|
||||
EATEST_VERIFY(testMap.validate_iterator(tempIter) == eastl::isf_none);
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.erase(20); // erasing an index not in use should still be safe
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
EATEST_VERIFY((VerifyListMapSequence<uint32_t, uint64_t>("list_map::push_back", testMap, UINT32_MAX, 0, 8, 1008, 7, 1007, UINT32_MAX, 0)));
|
||||
|
||||
EATEST_VERIFY(testMap.count(7) == 1);
|
||||
EATEST_VERIFY(testMap.count(10) == 0);
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
|
||||
testMap.erase(testMap.find(8));
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
EATEST_VERIFY((VerifyListMapSequence<uint32_t, uint64_t>("list_map::push_back", testMap, UINT32_MAX, 0, 7, 1007, UINT32_MAX, 0)));
|
||||
|
||||
testMap.erase(testMap.rbegin());
|
||||
EATEST_VERIFY(testMap.empty());
|
||||
EATEST_VERIFY(testMap.validate());
|
||||
}
|
||||
|
||||
{
|
||||
typedef eastl::list_map<eastl::string, uint32_t> TestStringMapType;
|
||||
TestStringMapType testStringMap;
|
||||
TestStringMapType::iterator strIter;
|
||||
|
||||
testStringMap.push_back(eastl::string("hello"), 750);
|
||||
EATEST_VERIFY(testStringMap.size() == 1);
|
||||
|
||||
strIter = testStringMap.find_as("hello", eastl::less_2<eastl::string, const char*>());
|
||||
EATEST_VERIFY(strIter != testStringMap.end());
|
||||
EATEST_VERIFY(strIter->first == "hello");
|
||||
EATEST_VERIFY(strIter->second == 750);
|
||||
|
||||
strIter = testStringMap.find_as("fake_string", eastl::less_2<eastl::string, const char*>());
|
||||
EATEST_VERIFY(strIter == testStringMap.end());
|
||||
EATEST_VERIFY(testStringMap.validate());
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/bonus/lru_cache.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
|
||||
namespace TestLruCacheInternal
|
||||
{
|
||||
struct Foo
|
||||
{
|
||||
static int count;
|
||||
|
||||
Foo()
|
||||
: a(count++)
|
||||
, b(count++)
|
||||
{ }
|
||||
|
||||
Foo(int x, int y) : a(x), b(y) {}
|
||||
|
||||
int a;
|
||||
int b;
|
||||
|
||||
bool operator==(const Foo &other) const
|
||||
{
|
||||
return this->a == other.a && this->b == other.b;
|
||||
}
|
||||
};
|
||||
|
||||
int Foo::count = 0;
|
||||
|
||||
class FooCreator
|
||||
{
|
||||
public:
|
||||
FooCreator() : mFooCreatedCount(0) {}
|
||||
|
||||
Foo *Create()
|
||||
{
|
||||
mFooCreatedCount++;
|
||||
return new Foo();
|
||||
}
|
||||
|
||||
void Destroy(Foo *f)
|
||||
{
|
||||
delete f;
|
||||
mFooCreatedCount--;
|
||||
}
|
||||
|
||||
int mFooCreatedCount;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
int TestLruCache()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// Test simple situation
|
||||
{
|
||||
using namespace TestLruCacheInternal;
|
||||
|
||||
eastl::lru_cache<int, Foo> lruCache(3);
|
||||
|
||||
// Empty state
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.size() == 0);
|
||||
EATEST_VERIFY(lruCache.empty() == true);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
EATEST_VERIFY(lruCache.at(1).has_value() == false);
|
||||
|
||||
// Auto create with get call
|
||||
EATEST_VERIFY(lruCache[0].a == 0);
|
||||
EATEST_VERIFY(lruCache[0].b == 1);
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.contains(0) == true);
|
||||
EATEST_VERIFY(lruCache.size() == 1);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
|
||||
// Fill structure up to 2 more entries to fill out, also test at()
|
||||
lruCache.insert(1, Foo(2, 3));
|
||||
EATEST_VERIFY(lruCache.at(1).value().a == 2);
|
||||
EATEST_VERIFY(lruCache.at(1).value().b == 3);
|
||||
EATEST_VERIFY(lruCache.contains(0) == true);
|
||||
EATEST_VERIFY(lruCache.contains(1) == true);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
EATEST_VERIFY(lruCache.contains(3) == false);
|
||||
EATEST_VERIFY(lruCache.size() == 2);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
|
||||
lruCache.insert(2, Foo(4, 5));
|
||||
EATEST_VERIFY(lruCache[2].a == 4);
|
||||
EATEST_VERIFY(lruCache[2].b == 5);
|
||||
EATEST_VERIFY(lruCache.contains(0) == true);
|
||||
EATEST_VERIFY(lruCache.contains(1) == true);
|
||||
EATEST_VERIFY(lruCache.contains(2) == true);
|
||||
EATEST_VERIFY(lruCache.contains(3) == false);
|
||||
EATEST_VERIFY(lruCache.size() == 3);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
|
||||
// Add another entry, at this point 0 is the oldest, so it should be pulled
|
||||
lruCache.insert(3, Foo(6, 7));
|
||||
EATEST_VERIFY(lruCache[3].a == 6);
|
||||
EATEST_VERIFY(lruCache[3].b == 7);
|
||||
EATEST_VERIFY(lruCache.contains(0) == false);
|
||||
EATEST_VERIFY(lruCache.contains(1) == true);
|
||||
EATEST_VERIFY(lruCache.contains(2) == true);
|
||||
EATEST_VERIFY(lruCache.contains(3) == true);
|
||||
EATEST_VERIFY(lruCache.size() == 3);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
|
||||
// Touch the now oldest 1 key
|
||||
EATEST_VERIFY(lruCache.touch(1) == true);
|
||||
|
||||
// Add another entry, this will be #4 but since 1 was touched, 2 is now the oldest
|
||||
lruCache.insert(4, Foo(8, 9));
|
||||
EATEST_VERIFY(lruCache[4].a == 8);
|
||||
EATEST_VERIFY(lruCache[4].b == 9);
|
||||
EATEST_VERIFY(lruCache.contains(0) == false);
|
||||
EATEST_VERIFY(lruCache.contains(1) == true);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
EATEST_VERIFY(lruCache.contains(3) == true);
|
||||
EATEST_VERIFY(lruCache.contains(4) == true);
|
||||
EATEST_VERIFY(lruCache.size() == 3);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
|
||||
// Test resize down
|
||||
EATEST_VERIFY(lruCache.touch(3) == true); // Let's make some key in the middle the most recent
|
||||
lruCache.resize(1); // Resize down to 1 entry in the cache
|
||||
EATEST_VERIFY(lruCache.contains(0) == false);
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
EATEST_VERIFY(lruCache.contains(3) == true);
|
||||
EATEST_VERIFY(lruCache.contains(4) == false);
|
||||
EATEST_VERIFY(lruCache.size() == 1);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 1);
|
||||
|
||||
// Let's resize up to a size of 5 now
|
||||
lruCache.resize(5);
|
||||
EATEST_VERIFY(lruCache.contains(0) == false);
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
EATEST_VERIFY(lruCache.contains(3) == true);
|
||||
EATEST_VERIFY(lruCache.contains(4) == false);
|
||||
EATEST_VERIFY(lruCache.size() == 1);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 5);
|
||||
|
||||
// Let's try updating
|
||||
lruCache.assign(3, Foo(0, 0));
|
||||
EATEST_VERIFY(lruCache[3] == Foo(0, 0));
|
||||
EATEST_VERIFY(lruCache.contains(0) == false);
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
EATEST_VERIFY(lruCache.contains(3) == true);
|
||||
EATEST_VERIFY(lruCache.contains(4) == false);
|
||||
EATEST_VERIFY(lruCache.size() == 1);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 5);
|
||||
|
||||
// add or update existing
|
||||
lruCache.insert_or_assign(3, Foo(1, 1));
|
||||
EATEST_VERIFY(lruCache[3] == Foo(1, 1));
|
||||
EATEST_VERIFY(lruCache.contains(0) == false);
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
EATEST_VERIFY(lruCache.contains(3) == true);
|
||||
EATEST_VERIFY(lruCache.contains(4) == false);
|
||||
EATEST_VERIFY(lruCache.size() == 1);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 5);
|
||||
|
||||
// Add or update a new entry
|
||||
lruCache.insert_or_assign(25, Foo(2, 2));
|
||||
EATEST_VERIFY(lruCache[3] == Foo(1, 1));
|
||||
EATEST_VERIFY(lruCache[25] == Foo(2, 2));
|
||||
EATEST_VERIFY(lruCache.contains(0) == false);
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
EATEST_VERIFY(lruCache.contains(3) == true);
|
||||
EATEST_VERIFY(lruCache.contains(4) == false);
|
||||
EATEST_VERIFY(lruCache.contains(25) == true);
|
||||
EATEST_VERIFY(lruCache.size() == 2);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 5);
|
||||
|
||||
// clear everything
|
||||
lruCache.clear();
|
||||
EATEST_VERIFY(lruCache.size() == 0);
|
||||
EATEST_VERIFY(lruCache.empty() == true);
|
||||
EATEST_VERIFY(lruCache.capacity() == 5);
|
||||
EATEST_VERIFY(lruCache.contains(3) == false);
|
||||
|
||||
// test unilateral reset
|
||||
lruCache[1] = Foo(1, 2);
|
||||
lruCache.reset_lose_memory();
|
||||
EATEST_VERIFY(lruCache.size() == 0);
|
||||
}
|
||||
|
||||
// Test more advanced creation / deletion via callbacks
|
||||
{
|
||||
using namespace TestLruCacheInternal;
|
||||
|
||||
FooCreator fooCreator;
|
||||
|
||||
auto createCallback = [&fooCreator](int) { return fooCreator.Create(); };
|
||||
auto deleteCallback = [&fooCreator](Foo *f) { fooCreator.Destroy(f); };
|
||||
|
||||
eastl::lru_cache<int, Foo*> lruCache(3, EASTLAllocatorType("eastl lru_cache"), createCallback, deleteCallback);
|
||||
|
||||
lruCache[1];
|
||||
EATEST_VERIFY(fooCreator.mFooCreatedCount == 1);
|
||||
EATEST_VERIFY(lruCache.size() == 1);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
EATEST_VERIFY(lruCache.contains(1) == true);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
|
||||
lruCache[2];
|
||||
EATEST_VERIFY(fooCreator.mFooCreatedCount == 2);
|
||||
EATEST_VERIFY(lruCache.size() == 2);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
EATEST_VERIFY(lruCache.contains(1) == true);
|
||||
EATEST_VERIFY(lruCache.contains(2) == true);
|
||||
|
||||
// Update 2, which should delete the existing entry
|
||||
{
|
||||
auto f = fooCreator.Create();
|
||||
EATEST_VERIFY(fooCreator.mFooCreatedCount == 3);
|
||||
f->a = 20;
|
||||
f->b = 21;
|
||||
lruCache.assign(2, f);
|
||||
EATEST_VERIFY(fooCreator.mFooCreatedCount == 2);
|
||||
EATEST_VERIFY(lruCache.size() == 2);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
EATEST_VERIFY(lruCache.contains(1) == true);
|
||||
EATEST_VERIFY(lruCache.contains(2) == true);
|
||||
EATEST_VERIFY(lruCache[2]->a == 20);
|
||||
EATEST_VERIFY(lruCache[2]->b == 21);
|
||||
}
|
||||
|
||||
lruCache.erase(2);
|
||||
EATEST_VERIFY(fooCreator.mFooCreatedCount == 1);
|
||||
EATEST_VERIFY(lruCache.size() == 1);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
EATEST_VERIFY(lruCache.contains(1) == true);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
|
||||
lruCache.erase(1);
|
||||
EATEST_VERIFY(fooCreator.mFooCreatedCount == 0);
|
||||
EATEST_VERIFY(lruCache.size() == 0);
|
||||
EATEST_VERIFY(lruCache.empty() == true);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
|
||||
// Test insert_or_assign
|
||||
{
|
||||
auto f = fooCreator.Create();
|
||||
f->a = 22;
|
||||
f->b = 30;
|
||||
EATEST_VERIFY(fooCreator.mFooCreatedCount == 1);
|
||||
|
||||
lruCache.insert_or_assign(7, f);
|
||||
EATEST_VERIFY(lruCache.size() == 1);
|
||||
EATEST_VERIFY(lruCache.empty() == false);
|
||||
EATEST_VERIFY(lruCache.capacity() == 3);
|
||||
EATEST_VERIFY(lruCache.contains(1) == false);
|
||||
EATEST_VERIFY(lruCache.contains(2) == false);
|
||||
EATEST_VERIFY(lruCache.contains(7) == true);
|
||||
EATEST_VERIFY(lruCache.erase(7) == true);
|
||||
EATEST_VERIFY(fooCreator.mFooCreatedCount == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Test iteration
|
||||
{
|
||||
eastl::lru_cache<int, int> lc(5);
|
||||
lc.insert_or_assign(0,10);
|
||||
lc.insert_or_assign(1,11);
|
||||
lc.insert_or_assign(2,12);
|
||||
lc.insert_or_assign(3,13);
|
||||
lc.insert_or_assign(4,14);
|
||||
|
||||
{ // test manual for-loop
|
||||
int i = 0;
|
||||
for (auto b = lc.begin(), e = lc.end(); b != e; b++)
|
||||
{
|
||||
auto &p = *b;
|
||||
VERIFY(i == p.first);
|
||||
VERIFY(i + 10 == p.second.first);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
{ // test pairs
|
||||
int i = 0;
|
||||
for(auto& p : lc)
|
||||
{
|
||||
VERIFY(i == p.first);
|
||||
VERIFY(i + 10 == p.second.first);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
{ // test structured bindings
|
||||
int i = 0;
|
||||
for(auto& [key, value] : lc)
|
||||
{
|
||||
VERIFY(i == key);
|
||||
VERIFY(i + 10 == value.first);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test initializer_list
|
||||
{
|
||||
eastl::lru_cache<int, int> lc = {{0, 10}, {1, 11}, {2, 12}, {3, 13}, {4, 14}, {5, 15}};
|
||||
|
||||
int i = 0;
|
||||
for(auto& p : lc)
|
||||
{
|
||||
VERIFY(i == p.first);
|
||||
VERIFY(i + 10 == p.second.first);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "TestMap.h"
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/map.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/vector.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <map>
|
||||
#endif
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::map<int, int>;
|
||||
template class eastl::multimap<int, int>;
|
||||
template class eastl::map<TestObject, TestObject>;
|
||||
template class eastl::multimap<TestObject, TestObject>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// typedefs
|
||||
//
|
||||
typedef eastl::map<int, int> VM1;
|
||||
typedef eastl::map<TestObject, TestObject> VM4;
|
||||
typedef eastl::multimap<int, int> VMM1;
|
||||
typedef eastl::multimap<TestObject, TestObject> VMM4;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
typedef std::map<int, int> VM3;
|
||||
typedef std::map<TestObject, TestObject> VM6;
|
||||
typedef std::multimap<int, int> VMM3;
|
||||
typedef std::multimap<TestObject, TestObject> VMM6;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
int TestMap()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
{ // Test construction
|
||||
nErrorCount += TestMapConstruction<VM1, VM3, false>();
|
||||
nErrorCount += TestMapConstruction<VM4, VM6, false>();
|
||||
|
||||
nErrorCount += TestMapConstruction<VMM1, VMM3, true>();
|
||||
nErrorCount += TestMapConstruction<VMM4, VMM6, true>();
|
||||
}
|
||||
|
||||
|
||||
{ // Test mutating functionality.
|
||||
nErrorCount += TestMapMutation<VM1, VM3, false>();
|
||||
nErrorCount += TestMapMutation<VM4, VM6, false>();
|
||||
|
||||
nErrorCount += TestMapMutation<VMM1, VMM3, true>();
|
||||
nErrorCount += TestMapMutation<VMM4, VMM6, true>();
|
||||
}
|
||||
#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
|
||||
{ // Test searching functionality.
|
||||
nErrorCount += TestMapSearch<VM1, false>();
|
||||
nErrorCount += TestMapSearch<VM4, false>();
|
||||
|
||||
nErrorCount += TestMapSearch<VMM1, true>();
|
||||
nErrorCount += TestMapSearch<VMM4, true>();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// C++11 emplace and related functionality
|
||||
nErrorCount += TestMapCpp11<eastl::map<int, TestObject>>();
|
||||
nErrorCount += TestMultimapCpp11<eastl::multimap<int, TestObject>>();
|
||||
nErrorCount += TestMapCpp11NonCopyable<eastl::map<int, NonCopyable>>();
|
||||
}
|
||||
|
||||
{
|
||||
// C++17 try_emplace and related functionality
|
||||
nErrorCount += TestMapCpp17<eastl::map<int, TestObject>>();
|
||||
}
|
||||
|
||||
|
||||
{ // Misc tests
|
||||
|
||||
// const key_compare& key_comp() const;
|
||||
// key_compare& key_comp();
|
||||
VM1 vm;
|
||||
const VM1 vmc;
|
||||
|
||||
const VM1::key_compare& kc = vmc.key_comp();
|
||||
vm.key_comp() = kc;
|
||||
}
|
||||
|
||||
|
||||
// Regressions against user bug reports.
|
||||
{
|
||||
// User reports that the following doesn't compile on GCC 4.1.1 due to unrecognized lower_bound.
|
||||
eastl::map<int, int> m;
|
||||
m[1] = 1;
|
||||
EATEST_VERIFY(m.size() == 1);
|
||||
m.erase(1);
|
||||
EATEST_VERIFY(m.empty());
|
||||
}
|
||||
|
||||
{
|
||||
// User reports that EASTL_VALIDATE_COMPARE_ENABLED / EASTL_COMPARE_VALIDATE isn't compiling for this case.
|
||||
eastl::map<eastl::u8string, int> m;
|
||||
m.find_as(EA_CHAR8("some string"), eastl::equal_to_2<eastl::u8string, const char8_t*>());
|
||||
}
|
||||
|
||||
{
|
||||
eastl::map<int*, int> m;
|
||||
int* ip = (int*)(uintptr_t)0xDEADC0DE;
|
||||
|
||||
m[ip] = 0;
|
||||
|
||||
auto it = m.find_as(ip, eastl::less_2<int*, int*>{});
|
||||
EATEST_VERIFY(it != m.end());
|
||||
|
||||
it = m.find_as((int*)(uintptr_t)0xDEADC0DE, eastl::less_2<int*, int*>{});
|
||||
EATEST_VERIFY(it != m.end());
|
||||
}
|
||||
|
||||
{
|
||||
// User reports that vector<map<enum,enum>> is crashing after the recent changes to add rvalue move and emplace support to rbtree.
|
||||
typedef eastl::map<int, int> IntIntMap;
|
||||
typedef eastl::vector<IntIntMap> IntIntMapArray;
|
||||
|
||||
IntIntMapArray v;
|
||||
v.push_back(IntIntMap()); // This was calling the rbtree move constructor, which had a bug.
|
||||
v[0][16] = 0; // The rbtree was in a bad internal state and so this line resulted in a crash.
|
||||
EATEST_VERIFY(v[0].validate());
|
||||
EATEST_VERIFY(v.validate());
|
||||
}
|
||||
|
||||
{
|
||||
typedef eastl::map<int, int> IntIntMap;
|
||||
IntIntMap map1;
|
||||
map1[1] = 1;
|
||||
map1[3] = 3;
|
||||
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
EATEST_VERIFY_THROW(map1.at(0));
|
||||
EATEST_VERIFY_THROW(map1.at(2));
|
||||
EATEST_VERIFY_THROW(map1.at(4));
|
||||
#endif
|
||||
map1[0] = 1;
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
EATEST_VERIFY_NOTHROW(map1.at(0));
|
||||
EATEST_VERIFY_NOTHROW(map1.at(1));
|
||||
EATEST_VERIFY_NOTHROW(map1.at(3));
|
||||
#endif
|
||||
EATEST_VERIFY(map1.at(0) == 1);
|
||||
EATEST_VERIFY(map1.at(1) == 1);
|
||||
EATEST_VERIFY(map1.at(3) == 3);
|
||||
|
||||
const IntIntMap map2;
|
||||
const IntIntMap map3(map1);
|
||||
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
EATEST_VERIFY_THROW(map2.at(0));
|
||||
EATEST_VERIFY_NOTHROW(map3.at(0));
|
||||
#endif
|
||||
EATEST_VERIFY(map3.at(0) == 1);
|
||||
}
|
||||
|
||||
// User regression test
|
||||
{
|
||||
#if !EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR
|
||||
typedef eastl::map<int, MoveOnlyTypeDefaultCtor> IntMOMap;
|
||||
|
||||
IntMOMap m1, m2;
|
||||
m2[0] = MoveOnlyTypeDefaultCtor(0);
|
||||
m2[1] = MoveOnlyTypeDefaultCtor(1);
|
||||
|
||||
EATEST_VERIFY( m1.empty());
|
||||
EATEST_VERIFY(!m2.empty());
|
||||
|
||||
m1.swap(m2);
|
||||
|
||||
EATEST_VERIFY(!m1.empty());
|
||||
EATEST_VERIFY( m2.empty());
|
||||
#endif
|
||||
}
|
||||
|
||||
// todo: create a test case for this.
|
||||
// {
|
||||
// // User reports that an incorrectly wrapped pair key used to insert into an eastl map compiles when it should fire a compiler error about unconvertible types.
|
||||
// typedef eastl::pair<eastl::string, eastl::string> PairStringKey;
|
||||
// typedef eastl::map<PairStringKey, eastl::string> PairStringMap;
|
||||
//
|
||||
// PairStringMap p1, p2;
|
||||
//
|
||||
// p1.insert(PairStringMap::value_type(PairStringKey("key1", "key2"), "data")).first->second = "other_data";
|
||||
//
|
||||
// PairStringKey key("key1", "key2");
|
||||
// PairStringMap::value_type insert_me(key, "data");
|
||||
// p2.insert(insert_me).first->second = "other_data";
|
||||
//
|
||||
// for(auto& e : p1)
|
||||
// printf("%s,%s = %s\n", e.first.first.c_str(), e.first.second.c_str(), e.second.c_str());
|
||||
//
|
||||
// for(auto& e : p2)
|
||||
// printf("%s,%s = %s\n", e.first.first.c_str(), e.first.second.c_str(), e.second.c_str());
|
||||
//
|
||||
// EATEST_VERIFY(p1 == p2);
|
||||
// }
|
||||
|
||||
{ // Test empty base-class optimization
|
||||
struct UnemptyLess : eastl::less<int>
|
||||
{
|
||||
int foo;
|
||||
};
|
||||
|
||||
typedef eastl::map<int, int, eastl::less<int>> VM1;
|
||||
typedef eastl::map<int, int, UnemptyLess> VM2;
|
||||
|
||||
EATEST_VERIFY(sizeof(VM1) < sizeof(VM2));
|
||||
}
|
||||
|
||||
{ // Test erase_if
|
||||
eastl::map<int, int> m = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}};
|
||||
auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
|
||||
VERIFY((m == eastl::map<int, int>{{1, 1},{3, 3}}));
|
||||
VERIFY(numErased == 3);
|
||||
}
|
||||
|
||||
{ // Test erase_if
|
||||
eastl::multimap<int, int> m = {{0, 0}, {0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {4, 4}};
|
||||
auto numErased = eastl::erase_if(m, [](auto p) { return p.first % 2 == 0; });
|
||||
VERIFY((m == eastl::multimap<int, int>{{1, 1}, {1, 1}, {3, 3}}));;
|
||||
VERIFY(numErased == 7);
|
||||
}
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
{ // Test map <=>
|
||||
eastl::map<int, int> m1 = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}};
|
||||
eastl::map<int, int> m2 = {{4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}};
|
||||
eastl::map<int, int> m3 = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
|
||||
eastl::map<int, int> m4 = {{1, 0}, {3, 2}, {5, 4}, {7, 6}, {9, 8}};
|
||||
eastl::map<int, int> m5 = {{0, 1}, {2, 3}, {4, 5}};
|
||||
|
||||
VERIFY(m1 == m2);
|
||||
VERIFY(m1 != m3);
|
||||
VERIFY(m3 != m4);
|
||||
VERIFY(m3 < m4);
|
||||
VERIFY(m5 < m4);
|
||||
VERIFY(m5 < m3);
|
||||
|
||||
|
||||
VERIFY((m1 <=> m2) == 0);
|
||||
VERIFY((m1 <=> m3) != 0);
|
||||
VERIFY((m3 <=> m4) != 0);
|
||||
VERIFY((m3 <=> m4) < 0);
|
||||
VERIFY((m5 <=> m4) < 0);
|
||||
VERIFY((m5 <=> m3) < 0);
|
||||
}
|
||||
|
||||
{ // Test multimap <=>
|
||||
eastl::multimap<int, int> m1 = {{0, 0}, {0, 0}, {1, 1}, {1, 1}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {4, 4}, {4, 4}};
|
||||
eastl::multimap<int, int> m2 = {{0, 0}, {1, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {3, 3}, {2, 2}, {1, 1}, {0, 0}};
|
||||
eastl::multimap<int, int> m3 = {{0, 1}, {2, 3}, {4, 5}, {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 9}};
|
||||
eastl::multimap<int, int> m4 = {{1, 0}, {3, 2}, {5, 4}, {1, 0}, {3, 2}, {5, 4}, {7, 6}, {9, 8}};
|
||||
eastl::multimap<int, int> m5 = {{10, 11}, {10, 11}};
|
||||
|
||||
VERIFY(m1 == m2);
|
||||
VERIFY(m1 != m3);
|
||||
VERIFY(m3 != m4);
|
||||
VERIFY(m3 < m4);
|
||||
VERIFY(m5 > m4);
|
||||
VERIFY(m5 > m3);
|
||||
|
||||
VERIFY((m1 <=> m2) == 0);
|
||||
VERIFY((m1 <=> m3) != 0);
|
||||
VERIFY((m3 <=> m4) != 0);
|
||||
VERIFY((m3 <=> m4) < 0);
|
||||
VERIFY((m5 <=> m4) > 0);
|
||||
VERIFY((m5 <=> m3) > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,775 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/memory.h>
|
||||
#include <EASTL/utility.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EAStdC/EAMemory.h>
|
||||
#include <EAStdC/EAAlignment.h>
|
||||
|
||||
|
||||
// Regression for user reported operator new problem (12/8/2009):
|
||||
class AssetHandler
|
||||
{
|
||||
public:
|
||||
inline static void* operator new(size_t size, const char* /*text*/, unsigned int /*flags*/)
|
||||
{
|
||||
return ::operator new(size);
|
||||
}
|
||||
inline static void operator delete(void* p)
|
||||
{
|
||||
return ::operator delete(p);
|
||||
}
|
||||
};
|
||||
typedef eastl::vector<AssetHandler> AssetHandlerArray;
|
||||
|
||||
// Regression test for a default memory fill optimization that defers to memset instead of explicitly
|
||||
// value-initialization each element in a vector individually. This test ensures that the value of the memset is
|
||||
// consistent with an explicitly value-initialized element (namely when the container holds a scalar value that is
|
||||
// memset to zero).
|
||||
template <typename T>
|
||||
int TestValueInitOptimization()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
const int ELEM_COUNT = 100;
|
||||
|
||||
{
|
||||
eastl::vector<T> v1;
|
||||
eastl::vector<ValueInitOf<T>> v2;
|
||||
|
||||
v1.resize(ELEM_COUNT);
|
||||
v2.resize(ELEM_COUNT);
|
||||
|
||||
for (int i = 0; i < ELEM_COUNT; i++)
|
||||
{ EATEST_VERIFY(v1[i] == v2[i].get()); }
|
||||
}
|
||||
|
||||
{
|
||||
eastl::vector<T> v1(ELEM_COUNT);
|
||||
eastl::vector<ValueInitOf<T>> v2(ELEM_COUNT);
|
||||
|
||||
for (int i = 0; i < ELEM_COUNT; i++)
|
||||
{ EATEST_VERIFY(v1[i] == v2[i].get()); }
|
||||
}
|
||||
|
||||
EATEST_VERIFY(nErrorCount == 0);
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
// LCTestObject
|
||||
//
|
||||
// Helps test the late_constructed utility.
|
||||
// Has an unusual alignment so we can test that aspect of late_constructed.
|
||||
//
|
||||
struct EA_ALIGN(64) LCTestObject
|
||||
{
|
||||
int mX; //
|
||||
static int64_t sTOCount; // Count of all current existing objects.
|
||||
static int64_t sTOCtorCount; // Count of times any ctor was called.
|
||||
static int64_t sTODtorCount; // Count of times dtor was called.
|
||||
|
||||
explicit LCTestObject(int x = 0)
|
||||
: mX(x)
|
||||
{
|
||||
++sTOCount;
|
||||
++sTOCtorCount;
|
||||
}
|
||||
|
||||
LCTestObject(int x0, int x1, int x2)
|
||||
: mX(x0 + x1 + x2)
|
||||
{
|
||||
++sTOCount;
|
||||
++sTOCtorCount;
|
||||
}
|
||||
|
||||
LCTestObject(const LCTestObject& testObject)
|
||||
: mX(testObject.mX)
|
||||
{
|
||||
++sTOCount;
|
||||
++sTOCtorCount;
|
||||
}
|
||||
|
||||
#if !defined(EA_COMPILER_NO_RVALUE_REFERENCES)
|
||||
LCTestObject(TestObject&& testObject)
|
||||
: mX(testObject.mX)
|
||||
{
|
||||
++sTOCount;
|
||||
++sTOCtorCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
LCTestObject& operator=(const LCTestObject& testObject)
|
||||
{
|
||||
mX = testObject.mX;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if !defined(EA_COMPILER_NO_RVALUE_REFERENCES)
|
||||
LCTestObject& operator=(LCTestObject&& testObject)
|
||||
{
|
||||
eastl::swap(mX, testObject.mX);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
~LCTestObject()
|
||||
{
|
||||
--sTOCount;
|
||||
++sTODtorCount;
|
||||
}
|
||||
};
|
||||
|
||||
int64_t LCTestObject::sTOCount = 0;
|
||||
int64_t LCTestObject::sTOCtorCount = 0;
|
||||
int64_t LCTestObject::sTODtorCount = 0;
|
||||
|
||||
|
||||
eastl::late_constructed<LCTestObject, true, true> gLCTestObjectTrueTrue;
|
||||
eastl::late_constructed<LCTestObject, false, true> gLCTestObjectFalseTrue;
|
||||
eastl::late_constructed<LCTestObject, false, false> gLCTestObjectFalseFalse;
|
||||
eastl::late_constructed<LCTestObject, true, false> gLCTestObjectTrueFalse;
|
||||
|
||||
struct TypeWithPointerTraits {};
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
template <>
|
||||
struct pointer_traits<TypeWithPointerTraits>
|
||||
{
|
||||
// Note: only parts of the traits we are interested to test are defined here.
|
||||
static const int* to_address(TypeWithPointerTraits)
|
||||
{
|
||||
return &a;
|
||||
}
|
||||
|
||||
inline static constexpr int a = 42;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestMemory
|
||||
//
|
||||
int TestMemory()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
TestObject::Reset();
|
||||
|
||||
{
|
||||
// get_temporary_buffer(ptrdiff_t n, size_t alignment, size_t alignmentOffset, char* pName);
|
||||
|
||||
pair<int*, ptrdiff_t> pr1 = get_temporary_buffer<int>(100, 1, 0, EASTL_NAME_VAL("Temp int array"));
|
||||
memset(pr1.first, 0, 100 * sizeof(int));
|
||||
return_temporary_buffer(pr1.first);
|
||||
|
||||
// Note that
|
||||
pair<TestObject*, ptrdiff_t> pr2 = get_temporary_buffer<TestObject>(300);
|
||||
memset(pr2.first, 0, 300 * sizeof(TestObject));
|
||||
return_temporary_buffer(pr2.first, pr2.second);
|
||||
}
|
||||
|
||||
EATEST_VERIFY(TestObject::IsClear());
|
||||
TestObject::Reset();
|
||||
|
||||
|
||||
{
|
||||
LCTestObject* pLCTO;
|
||||
|
||||
LCTestObject::sTOCount = 0;
|
||||
LCTestObject::sTOCtorCount = 0;
|
||||
LCTestObject::sTODtorCount = 0;
|
||||
|
||||
// Verify alignment requirements.
|
||||
// We don't verify that gLCTestObjectTrueTrue.get() is aligned for all platforms because some platforms can't do that with global memory.
|
||||
static_assert(eastl::alignment_of<typename late_constructed<LCTestObject>::value_type>::value == 64, "late_constructed alignment failure.");
|
||||
static_assert(eastl::alignment_of<typename late_constructed<LCTestObject>::storage_type>::value == 64, "late_constructed alignment failure.");
|
||||
static_assert(eastl::alignment_of<late_constructed<LCTestObject> >::value >= 64, "late_constructed alignment failure.");
|
||||
|
||||
|
||||
// late_constructed / gLCTestObjectTrueTrue
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 0) && (LCTestObject::sTODtorCount == 0));
|
||||
EATEST_VERIFY(!gLCTestObjectTrueTrue.is_constructed());
|
||||
|
||||
pLCTO = gLCTestObjectTrueTrue.get(); // This will auto-construct LCTestObject.
|
||||
EATEST_VERIFY(pLCTO != NULL);
|
||||
EATEST_VERIFY(gLCTestObjectTrueTrue.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectTrueTrue->mX = 17;
|
||||
EATEST_VERIFY(gLCTestObjectTrueTrue->mX == 17);
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectTrueTrue.destruct();
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 1));
|
||||
EATEST_VERIFY(!gLCTestObjectTrueTrue.is_constructed());
|
||||
|
||||
gLCTestObjectTrueTrue->mX = 18;
|
||||
EATEST_VERIFY(gLCTestObjectTrueTrue->mX == 18);
|
||||
EATEST_VERIFY(gLCTestObjectTrueTrue.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 2) && (LCTestObject::sTODtorCount == 1));
|
||||
|
||||
gLCTestObjectTrueTrue.destruct();
|
||||
(*gLCTestObjectTrueTrue).mX = 19;
|
||||
EATEST_VERIFY(gLCTestObjectTrueTrue->mX == 19);
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 3) && (LCTestObject::sTODtorCount == 2));
|
||||
|
||||
gLCTestObjectTrueTrue.destruct();
|
||||
LCTestObject::sTOCount = 0;
|
||||
LCTestObject::sTOCtorCount = 0;
|
||||
LCTestObject::sTODtorCount = 0;
|
||||
|
||||
// late_constructed / gLCTestObjectFalseTrue
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 0) && (LCTestObject::sTODtorCount == 0));
|
||||
EATEST_VERIFY(!gLCTestObjectFalseTrue.is_constructed());
|
||||
|
||||
pLCTO = gLCTestObjectFalseTrue.get(); // This will not auto-construct LCTestObject.
|
||||
EATEST_VERIFY(pLCTO == NULL);
|
||||
EATEST_VERIFY(!gLCTestObjectFalseTrue.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 0) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectFalseTrue.construct();
|
||||
pLCTO = gLCTestObjectFalseTrue.get();
|
||||
EATEST_VERIFY(pLCTO != NULL);
|
||||
EATEST_VERIFY(gLCTestObjectFalseTrue.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectFalseTrue->mX = 17;
|
||||
EATEST_VERIFY(gLCTestObjectFalseTrue->mX == 17);
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectFalseTrue.destruct();
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 1));
|
||||
EATEST_VERIFY(!gLCTestObjectFalseTrue.is_constructed());
|
||||
|
||||
gLCTestObjectFalseTrue.construct(14);
|
||||
EATEST_VERIFY(gLCTestObjectFalseTrue->mX == 14);
|
||||
gLCTestObjectFalseTrue->mX = 18;
|
||||
EATEST_VERIFY(gLCTestObjectFalseTrue->mX == 18);
|
||||
EATEST_VERIFY(gLCTestObjectFalseTrue.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 2) && (LCTestObject::sTODtorCount == 1));
|
||||
|
||||
gLCTestObjectFalseTrue.destruct();
|
||||
gLCTestObjectFalseTrue.construct(10, 20, 30);
|
||||
EATEST_VERIFY(gLCTestObjectFalseTrue->mX == 10+20+30);
|
||||
(*gLCTestObjectFalseTrue).mX = 19;
|
||||
EATEST_VERIFY(gLCTestObjectFalseTrue->mX == 19);
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 3) && (LCTestObject::sTODtorCount == 2));
|
||||
|
||||
gLCTestObjectFalseTrue.destruct();
|
||||
}
|
||||
|
||||
{
|
||||
LCTestObject* pLCTO;
|
||||
|
||||
LCTestObject::sTOCount = 0;
|
||||
LCTestObject::sTOCtorCount = 0;
|
||||
LCTestObject::sTODtorCount = 0;
|
||||
|
||||
// Verify alignment requirements.
|
||||
// We don't verify that gLCTestObjectTrueTrue.get() is aligned for all platforms because some platforms can't do that with global memory.
|
||||
static_assert(eastl::alignment_of<typename late_constructed<LCTestObject>::value_type>::value == 64, "late_constructed alignment failure.");
|
||||
static_assert(eastl::alignment_of<typename late_constructed<LCTestObject>::storage_type>::value == 64, "late_constructed alignment failure.");
|
||||
static_assert(eastl::alignment_of<late_constructed<LCTestObject> >::value >= 64, "late_constructed alignment failure.");
|
||||
|
||||
|
||||
// late_constructed / gLCTestObjectTrueFalse
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 0) && (LCTestObject::sTODtorCount == 0));
|
||||
EATEST_VERIFY(!gLCTestObjectTrueFalse.is_constructed());
|
||||
|
||||
pLCTO = gLCTestObjectTrueFalse.get(); // This will auto-construct LCTestObject.
|
||||
EATEST_VERIFY(pLCTO != NULL);
|
||||
EATEST_VERIFY(gLCTestObjectTrueFalse.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectTrueFalse->mX = 17;
|
||||
EATEST_VERIFY(gLCTestObjectTrueFalse->mX == 17);
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectTrueFalse.destruct();
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 1));
|
||||
EATEST_VERIFY(!gLCTestObjectTrueFalse.is_constructed());
|
||||
|
||||
gLCTestObjectTrueFalse->mX = 18;
|
||||
EATEST_VERIFY(gLCTestObjectTrueFalse->mX == 18);
|
||||
EATEST_VERIFY(gLCTestObjectTrueFalse.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 2) && (LCTestObject::sTODtorCount == 1));
|
||||
|
||||
gLCTestObjectTrueFalse.destruct();
|
||||
(*gLCTestObjectTrueFalse).mX = 19;
|
||||
EATEST_VERIFY(gLCTestObjectTrueFalse->mX == 19);
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 3) && (LCTestObject::sTODtorCount == 2));
|
||||
|
||||
gLCTestObjectTrueFalse.destruct();
|
||||
LCTestObject::sTOCount = 0;
|
||||
LCTestObject::sTOCtorCount = 0;
|
||||
LCTestObject::sTODtorCount = 0;
|
||||
|
||||
// late_constructed / gLCTestObjectFalseFalse
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 0) && (LCTestObject::sTODtorCount == 0));
|
||||
EATEST_VERIFY(!gLCTestObjectFalseFalse.is_constructed());
|
||||
|
||||
pLCTO = gLCTestObjectFalseFalse.get(); // This will not auto-construct LCTestObject.
|
||||
EATEST_VERIFY(pLCTO == NULL);
|
||||
EATEST_VERIFY(!gLCTestObjectFalseFalse.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 0) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectFalseFalse.construct();
|
||||
pLCTO = gLCTestObjectFalseFalse.get();
|
||||
EATEST_VERIFY(pLCTO != NULL);
|
||||
EATEST_VERIFY(gLCTestObjectFalseFalse.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectFalseFalse->mX = 17;
|
||||
EATEST_VERIFY(gLCTestObjectFalseFalse->mX == 17);
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
gLCTestObjectFalseFalse.destruct();
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 0) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 1));
|
||||
EATEST_VERIFY(!gLCTestObjectFalseFalse.is_constructed());
|
||||
|
||||
gLCTestObjectFalseFalse.construct(14);
|
||||
EATEST_VERIFY(gLCTestObjectFalseFalse->mX == 14);
|
||||
gLCTestObjectFalseFalse->mX = 18;
|
||||
EATEST_VERIFY(gLCTestObjectFalseFalse->mX == 18);
|
||||
EATEST_VERIFY(gLCTestObjectFalseFalse.is_constructed());
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 2) && (LCTestObject::sTODtorCount == 1));
|
||||
|
||||
gLCTestObjectFalseFalse.destruct();
|
||||
gLCTestObjectFalseFalse.construct(10, 20, 30);
|
||||
EATEST_VERIFY(gLCTestObjectFalseFalse->mX == 10+20+30);
|
||||
(*gLCTestObjectFalseFalse).mX = 19;
|
||||
EATEST_VERIFY(gLCTestObjectFalseFalse->mX == 19);
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 3) && (LCTestObject::sTODtorCount == 2));
|
||||
|
||||
gLCTestObjectFalseFalse.destruct();
|
||||
}
|
||||
|
||||
LCTestObject::sTOCount = 0;
|
||||
LCTestObject::sTOCtorCount = 0;
|
||||
LCTestObject::sTODtorCount = 0;
|
||||
{
|
||||
eastl::late_constructed<LCTestObject, true, false> lc;
|
||||
lc.construct();
|
||||
}
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
LCTestObject::sTOCount = 0;
|
||||
LCTestObject::sTOCtorCount = 0;
|
||||
LCTestObject::sTODtorCount = 0;
|
||||
{
|
||||
eastl::late_constructed<LCTestObject, false, false> lc;
|
||||
lc.construct();
|
||||
}
|
||||
EATEST_VERIFY((LCTestObject::sTOCount == 1) && (LCTestObject::sTOCtorCount == 1) && (LCTestObject::sTODtorCount == 0));
|
||||
|
||||
|
||||
// We use the vector container to supply a RandomAccessIterator.
|
||||
// We use the list container to supply a BidirectionalIterator.
|
||||
// We use the slist container to supply a ForwardIterator.
|
||||
// We use our generic_input_iterator adapter to supply an InputIterator.
|
||||
|
||||
// eastl::vector<int> intVector;
|
||||
// eastl::list<int> intList;
|
||||
// eastl::slist<int> intSlist;
|
||||
|
||||
// template <typename ForwardIterator, typename ForwardIteratorDest>
|
||||
// inline ForwardIteratorDest uninitialized_relocate_start(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
|
||||
|
||||
// template <typename ForwardIterator, typename ForwardIteratorDest>
|
||||
// inline ForwardIteratorDest uninitialized_relocate_commit(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
|
||||
|
||||
// template <typename ForwardIterator, typename ForwardIteratorDest>
|
||||
// inline ForwardIteratorDest uninitialized_relocate_abort(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
|
||||
|
||||
// template <typename ForwardIterator, typename ForwardIteratorDest>
|
||||
// inline ForwardIteratorDest uninitialized_relocate(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
|
||||
|
||||
// This test does little more than verify that the code compiles.
|
||||
int* pEnd = eastl::uninitialized_relocate_start<int*, int*>((int*)NULL, (int*)NULL, (int*)NULL);
|
||||
EATEST_VERIFY(pEnd == NULL);
|
||||
|
||||
pEnd = eastl::uninitialized_relocate_commit<int*, int*>((int*)NULL, (int*)NULL, (int*)NULL);
|
||||
EATEST_VERIFY(pEnd == NULL);
|
||||
|
||||
pEnd = eastl::uninitialized_relocate_abort<int*, int*>((int*)NULL, (int*)NULL, (int*)NULL);
|
||||
EATEST_VERIFY(pEnd == NULL);
|
||||
|
||||
pEnd = eastl::uninitialized_relocate<int*, int*>((int*)NULL, (int*)NULL, (int*)NULL);
|
||||
EATEST_VERIFY(pEnd == NULL);
|
||||
|
||||
|
||||
|
||||
// template <typename InputIterator, typename ForwardIterator>
|
||||
// ForwardIterator uninitialized_copy(InputIterator sourceFirst, InputIterator sourceLast, ForwardIterator destination);
|
||||
|
||||
pEnd = eastl::uninitialized_copy<int*, int*>((int*)NULL, (int*)NULL, (int*)NULL);
|
||||
EATEST_VERIFY(pEnd == NULL);
|
||||
|
||||
|
||||
|
||||
// template <typename First, typename Last, typename Result>
|
||||
// Result uninitialized_copy_ptr(First first, Last last, Result result)
|
||||
|
||||
pEnd = eastl::uninitialized_copy_ptr<int*, int*, int*>((int*)NULL, (int*)NULL, (int*)NULL);
|
||||
EATEST_VERIFY(pEnd == NULL);
|
||||
|
||||
|
||||
|
||||
// template <typename ForwardIterator, typename T>
|
||||
// void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& value)
|
||||
|
||||
eastl::uninitialized_fill<int*, int>((int*)NULL, (int*)NULL, (int)0);
|
||||
|
||||
|
||||
|
||||
// template <typename T>
|
||||
// void uninitialized_fill_ptr(T* first, T* last, const T& value)
|
||||
|
||||
eastl::uninitialized_fill_ptr<int>((int*)NULL, (int*)NULL, (int)0);
|
||||
|
||||
|
||||
|
||||
// template <typename ForwardIterator, typename Count, typename T>
|
||||
// void uninitialized_fill_n(ForwardIterator first, Count n, const T& value)
|
||||
|
||||
eastl::uninitialized_fill_n<int*, int, int>((int*)NULL, (int)0, (int)0);
|
||||
|
||||
|
||||
|
||||
// template <typename T, typename Count>
|
||||
// void uninitialized_fill_n_ptr(T* first, Count n, const T& value)
|
||||
|
||||
eastl::uninitialized_fill_n_ptr<int, int>((int*)NULL, (int)0, (int)0);
|
||||
|
||||
|
||||
|
||||
|
||||
// template <typename InputIterator, typename ForwardIterator, typename T>
|
||||
// void uninitialized_copy_fill(InputIterator first1, InputIterator last1,
|
||||
// ForwardIterator first2, ForwardIterator last2, const T& value)
|
||||
|
||||
eastl::uninitialized_copy_fill<int*, int*, int>((int*)NULL, (int*)NULL, (int*)NULL, (int*)NULL, (int)0);
|
||||
|
||||
|
||||
|
||||
// template <typename ForwardIterator, typename T, typename InputIterator>
|
||||
// ForwardIterator uninitialized_fill_copy(ForwardIterator result, ForwardIterator mid, const T& value, InputIterator first, InputIterator last)
|
||||
|
||||
eastl::uninitialized_fill_copy<int*, int, int*>((int*)NULL, (int*)NULL, (int)0, (int*)NULL, (int*)NULL);
|
||||
|
||||
|
||||
|
||||
// template <typename InputIterator1, typename InputIterator2, typename ForwardIterator>
|
||||
// ForwardIterator uninitialized_copy_copy(InputIterator1 first1, InputIterator1 last1,
|
||||
// InputIterator2 first2, InputIterator2 last2,
|
||||
// ForwardIterator result)
|
||||
|
||||
eastl::uninitialized_copy_copy<int*, int*, int*>((int*)NULL, (int*)NULL, (int*)NULL, (int*)NULL, (int*)NULL);
|
||||
|
||||
// uninitialized_default_construct
|
||||
{
|
||||
TestObject::Reset();
|
||||
char testCharArray[sizeof(TestObject) * 10];
|
||||
TestObject* pTestMemory = (TestObject*)(testCharArray);
|
||||
|
||||
eastl::uninitialized_default_construct(pTestMemory, pTestMemory + 10);
|
||||
EATEST_VERIFY(TestObject::sTODefaultCtorCount == 10);
|
||||
}
|
||||
|
||||
// uninitialized_default_construct_n
|
||||
{
|
||||
TestObject::Reset();
|
||||
char testCharArray[sizeof(TestObject) * 10];
|
||||
TestObject* pTestMemory = (TestObject*)(testCharArray);
|
||||
|
||||
auto endIter = eastl::uninitialized_default_construct_n(pTestMemory, 5);
|
||||
EATEST_VERIFY(TestObject::sTODefaultCtorCount == 5);
|
||||
EATEST_VERIFY(endIter == (pTestMemory + 5));
|
||||
}
|
||||
|
||||
// uninitialized_value_construct
|
||||
{
|
||||
TestObject::Reset();
|
||||
char testCharArray[sizeof(TestObject) * 10];
|
||||
TestObject* pTestMemory = (TestObject*)(testCharArray);
|
||||
|
||||
eastl::uninitialized_value_construct(pTestMemory, pTestMemory + 10);
|
||||
EATEST_VERIFY(TestObject::sTODefaultCtorCount == 10);
|
||||
}
|
||||
|
||||
// uninitialized_value_construct_n
|
||||
{
|
||||
TestObject::Reset();
|
||||
char testCharArray[sizeof(TestObject) * 10];
|
||||
TestObject* pTestMemory = (TestObject*)(testCharArray);
|
||||
|
||||
auto endIter = eastl::uninitialized_value_construct_n(pTestMemory, 5);
|
||||
EATEST_VERIFY(TestObject::sTODefaultCtorCount == 5);
|
||||
EATEST_VERIFY(endIter == (pTestMemory + 5));
|
||||
}
|
||||
|
||||
// Verify that uninitialized_value_construct does not do any additional initialization besides zero-initialization.
|
||||
//
|
||||
/// Value-Initialization:
|
||||
// If T is a class, the object is default-initialized (after being zero-initialized if T's default
|
||||
// constructor is not user-provided/deleted); otherwise, the object is zero-initialized.
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
// foo() = default; // intentionally removed to force zero-initialization behavior
|
||||
char mV;
|
||||
};
|
||||
|
||||
static const int ARRAY_SIZE_IN_BYTES = sizeof(foo) * 10;
|
||||
|
||||
char testCharArray[ARRAY_SIZE_IN_BYTES];
|
||||
EA::StdC::Memfill8(testCharArray, 42, ARRAY_SIZE_IN_BYTES);
|
||||
foo* pTestMemory = (foo*)testCharArray;
|
||||
|
||||
eastl::uninitialized_value_construct(pTestMemory, pTestMemory + 10);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
EATEST_VERIFY(pTestMemory[i].mV == 0); // verify that memory is zero-initialized
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that uninitialized_default_construct does not do any additional initialization besides the calling of a empty
|
||||
// constructor.
|
||||
//
|
||||
// Default-initialization:
|
||||
// If T is a class, the default constructor is called; otherwise, no initialization is done, resulting in
|
||||
// indeterminate values.
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
foo() {} // default ctor intentionally a no-op
|
||||
char mV;
|
||||
};
|
||||
|
||||
static const int ARRAY_SIZE_IN_BYTES = sizeof(foo) * 10;
|
||||
|
||||
char testCharArray[ARRAY_SIZE_IN_BYTES];
|
||||
EA::StdC::Memfill8(testCharArray, 42, ARRAY_SIZE_IN_BYTES);
|
||||
foo* pTestMemory = (foo*)testCharArray;
|
||||
|
||||
eastl::uninitialized_default_construct(pTestMemory, pTestMemory + 10);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
EATEST_VERIFY(pTestMemory[i].mV == 42); // verify original memset value is intact
|
||||
}
|
||||
}
|
||||
|
||||
// template <typename T>
|
||||
// void destruct(T* p)
|
||||
{
|
||||
TestObject::Reset();
|
||||
uint64_t testObjectMemory[((sizeof(TestObject) / sizeof(uint64_t)) + 1) * 2];
|
||||
|
||||
TestObject* pTestObject = new(testObjectMemory) TestObject;
|
||||
destruct(pTestObject);
|
||||
EATEST_VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
// template <typename T>
|
||||
// void destroy_at(T* p)
|
||||
{
|
||||
TestObject::Reset();
|
||||
uint64_t testObjectMemory[((sizeof(TestObject) / sizeof(uint64_t)) + 1) * 2];
|
||||
TestObject* pTestObject = new(testObjectMemory) TestObject;
|
||||
destroy_at(pTestObject);
|
||||
|
||||
EATEST_VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
|
||||
// template <typename ForwardIterator>
|
||||
// void destruct(ForwardIterator first, ForwardIterator last)
|
||||
{
|
||||
TestObject::Reset();
|
||||
char testObjectMemory[sizeof(TestObject) * 3];
|
||||
TestObject* pTestObject = new(testObjectMemory) TestObject[2];
|
||||
destruct(pTestObject, pTestObject + 2);
|
||||
|
||||
EATEST_VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
// template <typename ForwardIterator>
|
||||
// void destroy(ForwardIterator first, ForwardIterator last)
|
||||
{
|
||||
TestObject::Reset();
|
||||
char testObjectMemory[sizeof(TestObject) * 3];
|
||||
TestObject* pTestObject = new(testObjectMemory) TestObject[2];
|
||||
destroy(pTestObject, pTestObject + 2);
|
||||
|
||||
EATEST_VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
// template <typename ForwardIterator, typename Size>
|
||||
// void destroy_n(ForwardIterator first, Size n)
|
||||
{
|
||||
TestObject::Reset();
|
||||
char testObjectMemory[sizeof(TestObject) * 3];
|
||||
TestObject* pTestObject = new (testObjectMemory) TestObject[2];
|
||||
|
||||
destroy_n(pTestObject, 1); // destroy TestObject[0]
|
||||
destroy_n(pTestObject + 1, 1); // destroy TestObject[1]
|
||||
|
||||
EATEST_VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Regression for user reported operator new problem (12/8/2009):
|
||||
eastl::vector<AssetHandler> ahArray;
|
||||
ahArray.push_back(AssetHandler());
|
||||
}
|
||||
|
||||
|
||||
// void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
|
||||
// void* align_advance(size_t alignment, size_t size, void*& ptr, size_t& space);
|
||||
{
|
||||
const size_t kBufferSize = 256;
|
||||
char buffer[kBufferSize * 2];
|
||||
size_t space = sizeof(buffer);
|
||||
void* ptr = buffer;
|
||||
void* ptrSaved;
|
||||
void* ptrAligned;
|
||||
size_t i;
|
||||
|
||||
// First get 256 bytes of space aligned to 256.
|
||||
// It's a coincidence that we are using eastl::align to set up a buffer for testing eastl::align below.
|
||||
ptrSaved = eastl::align(256, 256, ptr, space);
|
||||
|
||||
// At this point we have 256 bytes of memory aligned on 256 bytes, within buffer.
|
||||
// We test allocating multiple blocks from this space at various alignments values.
|
||||
// We also test that the function sets ptr to the next available location after the
|
||||
// returned allocated block.
|
||||
EA::StdC::Memset8(buffer, 0x00, sizeof(buffer));
|
||||
EATEST_VERIFY(EA::StdC::IsAligned(ptr, 256));
|
||||
|
||||
// align test
|
||||
// Try a number of allocation sizes.
|
||||
for(size_t a = 1; a < 64; a *= 2)
|
||||
{
|
||||
// Do multiple sequental allocations from the storage.
|
||||
for(i = 0, space = 256, ptr = ptrSaved; i < kBufferSize; i += a)
|
||||
{
|
||||
ptrAligned = eastl::align(a, a, ptr, space);
|
||||
|
||||
EATEST_VERIFY((uintptr_t)ptrAligned == ((uintptr_t)ptrSaved + i));
|
||||
EATEST_VERIFY(ptr == ptrAligned);
|
||||
EATEST_VERIFY(space == (kBufferSize - i));
|
||||
EATEST_VERIFY(EA::StdC::IsAligned(ptrAligned, a));
|
||||
EATEST_VERIFY(EA::StdC::Memcheck8(ptrAligned, 0x00, a) == NULL);
|
||||
|
||||
ptr = (char*)ptr + a;
|
||||
space -= a;
|
||||
memset(ptrAligned, 0xff, a); // Do this so that next time around we can verify this memory isn't returned.
|
||||
}
|
||||
|
||||
EA::StdC::Memset8(buffer, 0x00, sizeof(buffer));
|
||||
}
|
||||
|
||||
// align_advance test (similar to but not identical to the align test)
|
||||
// Try a number of allocation sizes.
|
||||
for(size_t a = 1; a < 64; a *= 2)
|
||||
{
|
||||
// Do multiple sequental allocations from the storage.
|
||||
for(i = 0, space = 256, ptr = ptrSaved; i < kBufferSize; i += a)
|
||||
{
|
||||
ptrAligned = eastl::align_advance(a, a, ptr, space, &ptr, &space);
|
||||
|
||||
EATEST_VERIFY((uintptr_t)ptrAligned == ((uintptr_t)ptrSaved + i));
|
||||
EATEST_VERIFY((uintptr_t)ptr == (uintptr_t)ptrAligned + a);
|
||||
EATEST_VERIFY(space == (kBufferSize - i) - a);
|
||||
EATEST_VERIFY(EA::StdC::IsAligned(ptrAligned, a));
|
||||
EATEST_VERIFY(EA::StdC::Memcheck8(ptrAligned, 0x00, a) == NULL);
|
||||
|
||||
memset(ptrAligned, 0xff, a); // Do this so that next time around we can verify this memory isn't returned.
|
||||
}
|
||||
|
||||
EA::StdC::Memset8(buffer, 0x00, sizeof(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
// to_address
|
||||
{
|
||||
// Normal pointers.
|
||||
int a;
|
||||
int* ptrA = &a;
|
||||
EATEST_VERIFY(ptrA == to_address(ptrA));
|
||||
|
||||
// Smart pointer.
|
||||
struct MockSmartPointer
|
||||
{
|
||||
const int* operator->() const
|
||||
{
|
||||
return &a;
|
||||
}
|
||||
|
||||
int a = 42;
|
||||
};
|
||||
|
||||
MockSmartPointer sp;
|
||||
EATEST_VERIFY(&sp.a == to_address(sp));
|
||||
|
||||
// Type with specialized pointer_traits.
|
||||
TypeWithPointerTraits t;
|
||||
const int* result = to_address(t);
|
||||
EATEST_VERIFY(result != nullptr && *result == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// Test that align handles integral overflow correctly and returns NULL.
|
||||
void* ptr;
|
||||
void* ptrSaved;
|
||||
size_t space;
|
||||
void* pResult;
|
||||
|
||||
space = 64;
|
||||
ptr = 0;
|
||||
ptr = (char*)ptr - space;
|
||||
ptrSaved = ptr;
|
||||
pResult = eastl::align(1, space + 1, ptr, space); // Possible alignment, impossible size due to wraparound.
|
||||
EATEST_VERIFY((pResult == NULL) && (ptr == ptrSaved));
|
||||
|
||||
space = 64;
|
||||
ptr = 0;
|
||||
ptr = (char*)ptr - space;
|
||||
ptrSaved = ptr;
|
||||
pResult = eastl::align(space * 2, 32, ptr, space); // Impossible alignment due to wraparound, possible size.
|
||||
EATEST_VERIFY((pResult == NULL) && (ptr == ptrSaved));
|
||||
}
|
||||
|
||||
{
|
||||
nErrorCount += TestValueInitOptimization<int>();
|
||||
nErrorCount += TestValueInitOptimization<char>();
|
||||
nErrorCount += TestValueInitOptimization<short>();
|
||||
nErrorCount += TestValueInitOptimization<float>();
|
||||
nErrorCount += TestValueInitOptimization<double>();
|
||||
nErrorCount += TestValueInitOptimization<void*>();
|
||||
}
|
||||
|
||||
EATEST_VERIFY(nErrorCount == 0);
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
|
||||
#ifdef EA_COMPILER_CPP14_ENABLED
|
||||
#include "ConceptImpls.h"
|
||||
#include <EASTL/meta.h>
|
||||
|
||||
|
||||
int TestGetTypeIndex()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
static_assert(meta::get_type_index_v<short, short, char, int> == 0, "error");
|
||||
static_assert(meta::get_type_index_v<char, short, char, int> == 1, "error");
|
||||
static_assert(meta::get_type_index_v<int, short, char, int> == 2, "error");
|
||||
static_assert(meta::get_type_index_v<int, int, int, int> == 0, "error");
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
int TestGetType()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
static_assert(is_same_v<meta::get_type_at_t<2, short, short, char, int>, char>, "error");
|
||||
static_assert(is_same_v<meta::get_type_at_t<3, char, short, char, int>, int>, "error");
|
||||
// static_assert(is_same_v<meta::get_type_at_t<4, int, short, char, int>, int>, "error");
|
||||
static_assert(is_same_v<meta::get_type_at_t<1, int, int, int, int>, int>, "error");
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
int TestTypeCount()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
static_assert(meta::type_count_v<short, short, char, int> == 1, "error");
|
||||
static_assert(meta::type_count_v<char, short, char, int> == 1, "error");
|
||||
static_assert(meta::type_count_v<int, short, char, int> == 1, "error");
|
||||
static_assert(meta::type_count_v<int, int, int, int> == 3, "error");
|
||||
static_assert(meta::type_count_v<int, int, int, int, int, int, int, int, int> == 8, "error");
|
||||
static_assert(meta::type_count_v<int, int, int, int, char, int, int, int, int> == 7, "error");
|
||||
static_assert(meta::type_count_v<int, int, char, int, char, int, int, int, int> == 6, "error");
|
||||
static_assert(meta::type_count_v<int, int, char, int, char, int, int, int, char> == 5, "error");
|
||||
static_assert(meta::type_count_v<int, int, char, int, char, int, const int, int, char> == 4, "error");
|
||||
static_assert(meta::type_count_v<int, volatile int, char, int, char, int, const int, const volatile int, char> == 2, "error");
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
int TestDuplicateTypeCheck()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
static_assert( meta::duplicate_type_check_v<short, short, char, int>, "error");
|
||||
static_assert( meta::duplicate_type_check_v<short, short, char, int, long, unsigned, long long>, "error");
|
||||
static_assert( meta::duplicate_type_check_v<int, const int, volatile int, const volatile int, int>, "error");
|
||||
static_assert(!meta::duplicate_type_check_v<short, short, char, int, long, unsigned, short, long long>, "error");
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
int TestOverloadResolution()
|
||||
{
|
||||
using namespace eastl;
|
||||
using namespace eastl::meta;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<int>>, int>, "error");
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<short>>, short>, "error");
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<long>>, long>, "error");
|
||||
static_assert(is_same_v<overload_resolution_t<short, overload_set<int>>, int>, "error");
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<int, short, long>>, int>, "error");
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<short, int, long, float>>, int>, "error");
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<short, long, int, float, char>>, int>, "error");
|
||||
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<int>>, int>, "error");
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<int, short>>, int>, "error");
|
||||
static_assert(is_same_v<overload_resolution_t<int, overload_set<int, short, long>>, int>, "error");
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
int TestMeta()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
nErrorCount += TestGetTypeIndex();
|
||||
nErrorCount += TestGetType();
|
||||
nErrorCount += TestTypeCount();
|
||||
nErrorCount += TestDuplicateTypeCheck();
|
||||
nErrorCount += TestOverloadResolution();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
#endif // EA_COMPILER_CPP14_ENABLED
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/numeric_limits.h>
|
||||
|
||||
|
||||
struct NonNumericType
|
||||
{
|
||||
NonNumericType(int value) : mValue(value){}
|
||||
bool operator==(int value) const { return mValue == value; }
|
||||
int mValue; // This exists for the purpose of allowing the type to act like a number and allow the test logic below to work.
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestNumericLimits
|
||||
//
|
||||
int TestNumericLimits()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// To consider: Some day when we get more time, make a big table-driven set of
|
||||
// expected results to all member variables and function calls.
|
||||
|
||||
// Test a type that is not numeric,.
|
||||
EATEST_VERIFY(!eastl::numeric_limits<NonNumericType>::is_bounded);
|
||||
EATEST_VERIFY( eastl::numeric_limits<NonNumericType>::max() == 0);
|
||||
|
||||
EATEST_VERIFY(!eastl::numeric_limits<const NonNumericType>::is_bounded);
|
||||
EATEST_VERIFY( eastl::numeric_limits<const NonNumericType>::max() == 0);
|
||||
|
||||
EATEST_VERIFY(!eastl::numeric_limits<volatile NonNumericType>::is_bounded);
|
||||
EATEST_VERIFY( eastl::numeric_limits<volatile NonNumericType>::max() == 0);
|
||||
|
||||
EATEST_VERIFY(!eastl::numeric_limits<const volatile NonNumericType>::is_bounded);
|
||||
EATEST_VERIFY( eastl::numeric_limits<const volatile NonNumericType>::max() == 0);
|
||||
|
||||
// Test bool in all const-volatile variants.
|
||||
EATEST_VERIFY(eastl::numeric_limits<bool>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<bool>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<const bool>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<const bool>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<volatile bool>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<volatile bool>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<const volatile bool>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<const volatile bool>::max() != 0);
|
||||
|
||||
// Do basic tests of the remaining types.
|
||||
EATEST_VERIFY(eastl::numeric_limits<char>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<char>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned char>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned char>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed char>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed char>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<wchar_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<wchar_t>::max() != 0);
|
||||
|
||||
#if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
|
||||
EATEST_VERIFY(eastl::numeric_limits<char8_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<char8_t>::max() != 0);
|
||||
#endif
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<char16_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<char16_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<char32_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<char32_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned short>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned short>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed short>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed short>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned int>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned int>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed int>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed int>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned long>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned long>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed long>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed long>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned long long>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<unsigned long long>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed long long>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<signed long long>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<float>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<float>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<double>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<double>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<long double>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<long double>::max() != 0);
|
||||
|
||||
// We don't yet have a generic global way to identify what the name of the supported 128 bit type is.
|
||||
// We just happen to know that for gcc/clang it is __int128.
|
||||
#if (EA_COMPILER_INTMAX_SIZE >= 16) && (defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG)) // If __int128_t/__uint128_t is supported...
|
||||
EATEST_VERIFY(eastl::numeric_limits<__uint128_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<__uint128_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<__int128_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<__int128_t>::max() != 0);
|
||||
#endif
|
||||
|
||||
// Test sized types.
|
||||
EATEST_VERIFY(eastl::numeric_limits<uint8_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<uint8_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<int8_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<int8_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<uint16_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<uint16_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<int16_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<int16_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<uint32_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<uint32_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<int32_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<int32_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<uint64_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<uint64_t>::max() != 0);
|
||||
|
||||
EATEST_VERIFY(eastl::numeric_limits<int64_t>::is_bounded);
|
||||
EATEST_VERIFY(eastl::numeric_limits<int64_t>::max() != 0);
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,695 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/type_traits.h>
|
||||
#include <EASTL/sort.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/optional.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
struct IntStruct
|
||||
{
|
||||
IntStruct(int in) : data(in) {}
|
||||
int data;
|
||||
};
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
auto operator<=>(const IntStruct& lhs, const IntStruct& rhs) { return lhs.data <=> rhs.data; }
|
||||
#else
|
||||
bool operator<(const IntStruct& lhs, const IntStruct& rhs)
|
||||
{ return lhs.data < rhs.data; }
|
||||
#endif
|
||||
bool operator==(const IntStruct& lhs, const IntStruct& rhs)
|
||||
{ return lhs.data == rhs.data; }
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
struct destructor_test
|
||||
{
|
||||
~destructor_test() { destructor_ran = true; }
|
||||
static bool destructor_ran;
|
||||
static void reset() { destructor_ran = false; }
|
||||
};
|
||||
bool destructor_test::destructor_ran = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
struct move_test
|
||||
{
|
||||
move_test() = default;
|
||||
move_test(move_test&&) { was_moved = true; }
|
||||
move_test& operator=(move_test&&) { was_moved = true; return *this;}
|
||||
|
||||
// issue a compiler error is container tries to copy
|
||||
move_test(move_test const&) = delete;
|
||||
move_test& operator=(const move_test&) = delete;
|
||||
|
||||
static bool was_moved;
|
||||
};
|
||||
|
||||
bool move_test::was_moved = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
class forwarding_test
|
||||
{
|
||||
eastl::optional<T> m_optional;
|
||||
|
||||
public:
|
||||
forwarding_test() : m_optional() {}
|
||||
forwarding_test(T&& t) : m_optional(t) {}
|
||||
~forwarding_test() { m_optional.reset(); }
|
||||
|
||||
template <typename U>
|
||||
T GetValueOrDefault(U&& def) const
|
||||
{
|
||||
return m_optional.value_or(eastl::forward<U>(def));
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
struct assignment_test
|
||||
{
|
||||
assignment_test() { ++num_objects_inited; }
|
||||
assignment_test(assignment_test&&) { ++num_objects_inited; }
|
||||
assignment_test(const assignment_test&) { ++num_objects_inited; }
|
||||
assignment_test& operator=(assignment_test&&) { return *this; }
|
||||
assignment_test& operator=(const assignment_test&) { return *this; }
|
||||
~assignment_test() { --num_objects_inited; }
|
||||
|
||||
static int num_objects_inited;
|
||||
};
|
||||
|
||||
int assignment_test::num_objects_inited = 0;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// TestOptional
|
||||
//
|
||||
int TestOptional()
|
||||
{
|
||||
using namespace eastl;
|
||||
int nErrorCount = 0;
|
||||
#if defined(EASTL_OPTIONAL_ENABLED) && EASTL_OPTIONAL_ENABLED
|
||||
{
|
||||
{
|
||||
VERIFY( (is_same<optional<int>::value_type, int>::value));
|
||||
VERIFY( (is_same<optional<short>::value_type, short>::value));
|
||||
VERIFY(!(is_same<optional<short>::value_type, long>::value));
|
||||
VERIFY( (is_same<optional<const short>::value_type, const short>::value));
|
||||
VERIFY( (is_same<optional<volatile short>::value_type, volatile short>::value));
|
||||
VERIFY( (is_same<optional<const volatile short>::value_type, const volatile short>::value));
|
||||
|
||||
VERIFY(is_empty<nullopt_t>::value);
|
||||
#if EASTL_TYPE_TRAIT_is_literal_type_CONFORMANCE
|
||||
VERIFY(is_literal_type<nullopt_t>::value);
|
||||
#endif
|
||||
|
||||
#if EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE
|
||||
VERIFY(is_trivially_destructible<int>::value);
|
||||
VERIFY(is_trivially_destructible<Internal::optional_storage<int>>::value);
|
||||
VERIFY(is_trivially_destructible<optional<int>>::value);
|
||||
VERIFY(is_trivially_destructible<optional<int>>::value == is_trivially_destructible<int>::value);
|
||||
#endif
|
||||
|
||||
{
|
||||
struct NotTrivialDestructible { ~NotTrivialDestructible() {} };
|
||||
VERIFY(!is_trivially_destructible<NotTrivialDestructible>::value);
|
||||
VERIFY(!is_trivially_destructible<optional<NotTrivialDestructible>>::value);
|
||||
VERIFY(!is_trivially_destructible<Internal::optional_storage<NotTrivialDestructible>>::value);
|
||||
VERIFY(is_trivially_destructible<optional<NotTrivialDestructible>>::value == is_trivially_destructible<NotTrivialDestructible>::value);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o;
|
||||
VERIFY(!o);
|
||||
VERIFY(o.value_or(0x8BADF00D) == (int)0x8BADF00D);
|
||||
o = 1024;
|
||||
VERIFY(static_cast<bool>(o));
|
||||
VERIFY(o.value_or(0x8BADF00D) == 1024);
|
||||
VERIFY(o.value() == 1024);
|
||||
|
||||
// Test reset
|
||||
o.reset();
|
||||
VERIFY(!o);
|
||||
VERIFY(o.value_or(0x8BADF00D) == (int)0x8BADF00D);
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o(nullopt);
|
||||
VERIFY(!o);
|
||||
VERIFY(o.value_or(0x8BADF00D) == (int)0x8BADF00D);
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o = {};
|
||||
VERIFY(!o);
|
||||
VERIFY(o.value_or(0x8BADF00D) == (int)0x8BADF00D);
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o(42);
|
||||
VERIFY(bool(o));
|
||||
VERIFY(o.value_or(0x8BADF00D) == 42);
|
||||
o = nullopt;
|
||||
VERIFY(!o);
|
||||
VERIFY(o.value_or(0x8BADF00D) == (int)0x8BADF00D);
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o(42);
|
||||
VERIFY(static_cast<bool>(o));
|
||||
VERIFY(o.value_or(0x8BADF00D) == 42);
|
||||
VERIFY(o.value() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
auto o = make_optional(42);
|
||||
VERIFY((is_same<decltype(o), optional<int>>::value));
|
||||
VERIFY(static_cast<bool>(o));
|
||||
VERIFY(o.value_or(0x8BADF00D) == 42);
|
||||
VERIFY(o.value() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 42;
|
||||
auto o = make_optional(a);
|
||||
VERIFY((is_same<decltype(o)::value_type, int>::value));
|
||||
VERIFY(o.value() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// test make_optional stripping refs/cv-qualifers
|
||||
int a = 42;
|
||||
const volatile int& intRef = a;
|
||||
auto o = make_optional(intRef);
|
||||
VERIFY((is_same<decltype(o)::value_type, int>::value));
|
||||
VERIFY(o.value() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 10;
|
||||
const volatile int& aRef = a;
|
||||
auto o = eastl::make_optional(aRef);
|
||||
VERIFY(o.value() == 10);
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
struct local { int payload1; };
|
||||
auto o = eastl::make_optional<local>(42);
|
||||
VERIFY(o.value().payload1 == 42);
|
||||
}
|
||||
{
|
||||
struct local { int payload1; int payload2; };
|
||||
auto o = eastl::make_optional<local>(42, 43);
|
||||
VERIFY(o.value().payload1 == 42);
|
||||
VERIFY(o.value().payload2 == 43);
|
||||
}
|
||||
|
||||
{
|
||||
struct local
|
||||
{
|
||||
local(std::initializer_list<int> ilist)
|
||||
{
|
||||
payload1 = ilist.begin()[0];
|
||||
payload2 = ilist.begin()[1];
|
||||
}
|
||||
|
||||
int payload1;
|
||||
int payload2;
|
||||
};
|
||||
|
||||
auto o = eastl::make_optional<local>({42, 43});
|
||||
VERIFY(o.value().payload1 == 42);
|
||||
VERIFY(o.value().payload2 == 43);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o1(42), o2(24);
|
||||
VERIFY(o1.value() == 42);
|
||||
VERIFY(o2.value() == 24);
|
||||
VERIFY(*o1 == 42);
|
||||
VERIFY(*o2 == 24);
|
||||
o1 = eastl::move(o2);
|
||||
VERIFY(*o2 == 24);
|
||||
VERIFY(*o1 == 24);
|
||||
VERIFY(o2.value() == 24);
|
||||
VERIFY(o1.value() == 24);
|
||||
VERIFY(bool(o1));
|
||||
VERIFY(bool(o2));
|
||||
}
|
||||
|
||||
{
|
||||
struct local { int payload; };
|
||||
optional<local> o = local{ 42 };
|
||||
VERIFY(o->payload == 42);
|
||||
}
|
||||
|
||||
{
|
||||
struct local
|
||||
{
|
||||
int test() const { return 42; }
|
||||
};
|
||||
|
||||
{
|
||||
const optional<local> o = local{};
|
||||
VERIFY(o->test() == 42);
|
||||
VERIFY((*o).test() == 42);
|
||||
VERIFY(o.value().test() == 42);
|
||||
VERIFY(bool(o));
|
||||
}
|
||||
|
||||
{
|
||||
optional<local> o = local{};
|
||||
VERIFY(bool(o));
|
||||
o = nullopt;
|
||||
VERIFY(!bool(o));
|
||||
|
||||
VERIFY(o.value_or(local{}).test() == 42);
|
||||
VERIFY(!bool(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
move_test t;
|
||||
optional<move_test> o(eastl::move(t));
|
||||
VERIFY(move_test::was_moved);
|
||||
}
|
||||
|
||||
{
|
||||
forwarding_test<float>ft(1.f);
|
||||
float val = ft.GetValueOrDefault(0.f);
|
||||
VERIFY(val == 1.f);
|
||||
}
|
||||
|
||||
{
|
||||
assignment_test::num_objects_inited = 0;
|
||||
{
|
||||
optional<assignment_test> o1;
|
||||
optional<assignment_test> o2 = assignment_test();
|
||||
optional<assignment_test> o3(o2);
|
||||
VERIFY(assignment_test::num_objects_inited == 2);
|
||||
o1 = nullopt;
|
||||
VERIFY(assignment_test::num_objects_inited == 2);
|
||||
o1 = o2;
|
||||
VERIFY(assignment_test::num_objects_inited == 3);
|
||||
o1 = o2;
|
||||
VERIFY(assignment_test::num_objects_inited == 3);
|
||||
o1 = nullopt;
|
||||
VERIFY(assignment_test::num_objects_inited == 2);
|
||||
o2 = o1;
|
||||
VERIFY(assignment_test::num_objects_inited == 1);
|
||||
o1 = o2;
|
||||
VERIFY(assignment_test::num_objects_inited == 1);
|
||||
}
|
||||
VERIFY(assignment_test::num_objects_inited == 0);
|
||||
|
||||
{
|
||||
optional<assignment_test> o1;
|
||||
VERIFY(assignment_test::num_objects_inited == 0);
|
||||
o1 = nullopt;
|
||||
VERIFY(assignment_test::num_objects_inited == 0);
|
||||
o1 = optional<assignment_test>(assignment_test());
|
||||
VERIFY(assignment_test::num_objects_inited == 1);
|
||||
o1 = optional<assignment_test>(assignment_test());
|
||||
VERIFY(assignment_test::num_objects_inited == 1);
|
||||
optional<assignment_test> o2(eastl::move(o1));
|
||||
VERIFY(assignment_test::num_objects_inited == 2);
|
||||
o1 = nullopt;
|
||||
VERIFY(assignment_test::num_objects_inited == 1);
|
||||
}
|
||||
VERIFY(assignment_test::num_objects_inited == 0);
|
||||
}
|
||||
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
{
|
||||
struct vec3
|
||||
{
|
||||
vec3(std::initializer_list<float> ilist) { auto* p = ilist.begin(); x = *p++; y = *p++; z = *p++; }
|
||||
vec3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {} // testing variadic template constructor overload
|
||||
float x = 0, y = 0, z = 0;
|
||||
};
|
||||
|
||||
{
|
||||
optional<vec3> o{ in_place, 4.f, 5.f, 6.f };
|
||||
VERIFY(o->x == 4 && o->y == 5 && o->z == 6);
|
||||
}
|
||||
|
||||
{
|
||||
optional<vec3> o{ in_place, {4.f, 5.f, 6.f} };
|
||||
VERIFY(o->x == 4 && o->y == 5 && o->z == 6);
|
||||
}
|
||||
|
||||
{
|
||||
optional<string> o(in_place, {'a', 'b', 'c'});
|
||||
VERIFY(o == string("abc"));
|
||||
}
|
||||
|
||||
// http://en.cppreference.com/w/cpp/utility/optional/emplace
|
||||
{
|
||||
optional<vec3> o;
|
||||
o.emplace(42.f, 42.f, 42.f);
|
||||
VERIFY(o->x == 42.f && o->y == 42.f && o->z == 42.f);
|
||||
}
|
||||
|
||||
{
|
||||
optional<vec3> o;
|
||||
o.emplace({42.f, 42.f, 42.f});
|
||||
VERIFY(o->x == 42.f && o->y == 42.f && o->z == 42.f);
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o;
|
||||
o.emplace(42);
|
||||
VERIFY(*o == 42);
|
||||
}
|
||||
|
||||
struct nonCopyableNonMovable
|
||||
{
|
||||
nonCopyableNonMovable(int v) : val(v) {}
|
||||
|
||||
nonCopyableNonMovable(const nonCopyableNonMovable&) = delete;
|
||||
nonCopyableNonMovable(nonCopyableNonMovable&&) = delete;
|
||||
nonCopyableNonMovable& operator=(const nonCopyableNonMovable&) = delete;
|
||||
|
||||
int val = 0;
|
||||
};
|
||||
|
||||
{
|
||||
optional<nonCopyableNonMovable> o;
|
||||
o.emplace(42);
|
||||
VERIFY(o->val == 42);
|
||||
}
|
||||
|
||||
{
|
||||
// Verify emplace will destruct object if it has been engaged.
|
||||
destructor_test::reset();
|
||||
optional<destructor_test> o;
|
||||
o.emplace();
|
||||
VERIFY(!destructor_test::destructor_ran);
|
||||
|
||||
destructor_test::reset();
|
||||
o.emplace();
|
||||
VERIFY(destructor_test::destructor_ran);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// swap
|
||||
{
|
||||
{
|
||||
optional<int> o1 = 42, o2 = 24;
|
||||
VERIFY(*o1 == 42);
|
||||
VERIFY(*o2 == 24);
|
||||
o1.swap(o2);
|
||||
VERIFY(*o1 == 24);
|
||||
VERIFY(*o2 == 42);
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o1 = 42, o2 = 24;
|
||||
VERIFY(*o1 == 42);
|
||||
VERIFY(*o2 == 24);
|
||||
swap(o1, o2);
|
||||
VERIFY(*o1 == 24);
|
||||
VERIFY(*o2 == 42);
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o1 = 42, o2;
|
||||
VERIFY(*o1 == 42);
|
||||
VERIFY(o2.has_value() == false);
|
||||
swap(o1, o2);
|
||||
VERIFY(o1.has_value() == false);
|
||||
VERIFY(*o2 == 42);
|
||||
}
|
||||
|
||||
{
|
||||
optional<int> o1 = nullopt, o2 = 42;
|
||||
VERIFY(o1.has_value() == false);
|
||||
VERIFY(*o2 == 42);
|
||||
swap(o1, o2);
|
||||
VERIFY(*o1 == 42);
|
||||
VERIFY(o2.has_value() == false);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
optional<IntStruct> o(in_place, 10);
|
||||
optional<IntStruct> e;
|
||||
|
||||
VERIFY(o < IntStruct(42));
|
||||
VERIFY(!(o < IntStruct(2)));
|
||||
VERIFY(!(o < IntStruct(10)));
|
||||
VERIFY(e < o);
|
||||
VERIFY(e < IntStruct(10));
|
||||
|
||||
VERIFY(o > IntStruct(4));
|
||||
VERIFY(!(o > IntStruct(42)));
|
||||
|
||||
VERIFY(o >= IntStruct(4));
|
||||
VERIFY(o >= IntStruct(10));
|
||||
VERIFY(IntStruct(4) <= o);
|
||||
VERIFY(IntStruct(10) <= o);
|
||||
|
||||
VERIFY(o == IntStruct(10));
|
||||
VERIFY(o->data == IntStruct(10).data);
|
||||
|
||||
VERIFY(o != IntStruct(11));
|
||||
VERIFY(o->data != IntStruct(11).data);
|
||||
|
||||
VERIFY(e == nullopt);
|
||||
VERIFY(nullopt == e);
|
||||
|
||||
VERIFY(o != nullopt);
|
||||
VERIFY(nullopt != o);
|
||||
VERIFY(nullopt < o);
|
||||
VERIFY(o > nullopt);
|
||||
VERIFY(!(nullopt > o));
|
||||
VERIFY(!(o < nullopt));
|
||||
VERIFY(nullopt <= o);
|
||||
VERIFY(o >= nullopt);
|
||||
}
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
{
|
||||
optional<IntStruct> o(in_place, 10);
|
||||
optional<IntStruct> e;
|
||||
|
||||
VERIFY((o <=> IntStruct(42)) < 0);
|
||||
VERIFY((o <=> IntStruct(2)) >= 0);
|
||||
VERIFY((o <=> IntStruct(10)) >= 0);
|
||||
VERIFY((e <=> o) < 0);
|
||||
VERIFY((e <=> IntStruct(10)) < 0);
|
||||
|
||||
VERIFY((o <=> IntStruct(4)) > 0);
|
||||
VERIFY(o <=> IntStruct(42) <= 0);
|
||||
|
||||
VERIFY((o <=> IntStruct(4)) >= 0);
|
||||
VERIFY((o <=> IntStruct(10)) >= 0);
|
||||
VERIFY((IntStruct(4) <=> o) <= 0);
|
||||
VERIFY((IntStruct(10) <=> o) <= 0);
|
||||
|
||||
VERIFY((o <=> IntStruct(10)) == 0);
|
||||
VERIFY((o->data <=> IntStruct(10).data) == 0);
|
||||
|
||||
VERIFY((o <=> IntStruct(11)) != 0);
|
||||
VERIFY((o->data <=> IntStruct(11).data) != 0);
|
||||
|
||||
VERIFY((e <=> nullopt) == 0);
|
||||
VERIFY((nullopt <=> e) == 0);
|
||||
|
||||
VERIFY((o <=> nullopt) != 0);
|
||||
VERIFY((nullopt <=> o) != 0);
|
||||
VERIFY((nullopt <=> o) < 0);
|
||||
VERIFY((o <=> nullopt) > 0);
|
||||
VERIFY((nullopt <=> o) <= 0);
|
||||
VERIFY((o <=> nullopt) >= 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// hash
|
||||
{
|
||||
{
|
||||
// verify that the hash an empty eastl::optional object is zero.
|
||||
typedef hash<optional<int>> hash_optional_t;
|
||||
optional<int> e;
|
||||
VERIFY(hash_optional_t{}(e) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
// verify that the hash is the same as the hash of the underlying type
|
||||
const char* const pMessage = "Electronic Arts Canada";
|
||||
typedef hash<optional<string>> hash_optional_t;
|
||||
optional<string> o = string(pMessage);
|
||||
VERIFY(hash_optional_t{}(o) == hash<string>{}(pMessage));
|
||||
}
|
||||
}
|
||||
|
||||
// sorting
|
||||
{
|
||||
vector<optional<int>> v = {{122}, {115}, nullopt, {223}};
|
||||
sort(begin(v), end(v));
|
||||
vector<optional<int>> sorted = {nullopt, 115, 122, 223};
|
||||
|
||||
VERIFY(v == sorted);
|
||||
}
|
||||
|
||||
// test destructors being called.
|
||||
{
|
||||
destructor_test::reset();
|
||||
{
|
||||
optional<destructor_test> o = destructor_test{};
|
||||
}
|
||||
VERIFY(destructor_test::destructor_ran);
|
||||
|
||||
destructor_test::reset();
|
||||
{
|
||||
optional<destructor_test> o;
|
||||
}
|
||||
// destructor shouldn't be called as object wasn't constructed.
|
||||
VERIFY(!destructor_test::destructor_ran);
|
||||
|
||||
|
||||
destructor_test::reset();
|
||||
{
|
||||
optional<destructor_test> o = {};
|
||||
}
|
||||
// destructor shouldn't be called as object wasn't constructed.
|
||||
VERIFY(!destructor_test::destructor_ran);
|
||||
|
||||
destructor_test::reset();
|
||||
{
|
||||
optional<destructor_test> o = nullopt;
|
||||
}
|
||||
// destructor shouldn't be called as object wasn't constructed.
|
||||
VERIFY(!destructor_test::destructor_ran);
|
||||
}
|
||||
|
||||
// optional rvalue tests
|
||||
{
|
||||
VERIFY(*optional<uint32_t>(1u) == 1u);
|
||||
VERIFY(optional<uint32_t>(1u).value() == 1u);
|
||||
VERIFY(optional<uint32_t>(1u).value_or(0xdeadf00d) == 1u);
|
||||
VERIFY(optional<uint32_t>().value_or(0xdeadf00d) == 0xdeadf00d);
|
||||
VERIFY(optional<uint32_t>(1u).has_value() == true);
|
||||
VERIFY(optional<uint32_t>().has_value() == false);
|
||||
VERIFY( optional<IntStruct>(in_place, 10)->data == 10);
|
||||
|
||||
}
|
||||
|
||||
// alignment type tests
|
||||
{
|
||||
static_assert(alignof(optional<Align16>) == alignof(Align16), "optional alignment failure");
|
||||
static_assert(alignof(optional<Align32>) == alignof(Align32), "optional alignment failure");
|
||||
static_assert(alignof(optional<Align64>) == alignof(Align64), "optional alignment failure");
|
||||
}
|
||||
|
||||
{
|
||||
// user reported regression that failed to compile
|
||||
struct local_struct
|
||||
{
|
||||
local_struct() {}
|
||||
~local_struct() {}
|
||||
};
|
||||
static_assert(!eastl::is_trivially_destructible_v<local_struct>, "");
|
||||
|
||||
{
|
||||
local_struct ls;
|
||||
eastl::optional<local_struct> o{ls};
|
||||
}
|
||||
{
|
||||
const local_struct ls;
|
||||
eastl::optional<local_struct> o{ls};
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
// user regression
|
||||
eastl::optional<eastl::string> o = eastl::string("Hello World");
|
||||
eastl::optional<eastl::string> co;
|
||||
|
||||
co = o; // force copy-assignment
|
||||
|
||||
VERIFY( o.value().data() != co.value().data());
|
||||
VERIFY( o.value().data() == eastl::string("Hello World"));
|
||||
VERIFY(co.value().data() == eastl::string("Hello World"));
|
||||
}
|
||||
{
|
||||
// user regression
|
||||
EA_DISABLE_VC_WARNING(4625 4626) // copy/assignment operator constructor was implicitly defined as deleted
|
||||
struct local
|
||||
{
|
||||
eastl::unique_ptr<int> ptr;
|
||||
};
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
eastl::optional<local> o1 = local{eastl::make_unique<int>(42)};
|
||||
eastl::optional<local> o2;
|
||||
|
||||
o2 = eastl::move(o1);
|
||||
|
||||
VERIFY(!!o1 == true);
|
||||
VERIFY(!!o2 == true);
|
||||
VERIFY(!!o1->ptr == false);
|
||||
VERIFY(!!o2->ptr == true);
|
||||
VERIFY(o2->ptr.get() != nullptr);
|
||||
}
|
||||
{
|
||||
// user regression
|
||||
static bool copyCtorCalledWithUninitializedValue;
|
||||
static bool moveCtorCalledWithUninitializedValue;
|
||||
copyCtorCalledWithUninitializedValue = moveCtorCalledWithUninitializedValue = false;
|
||||
struct local
|
||||
{
|
||||
uint32_t val;
|
||||
local()
|
||||
: val(0xabcdabcd)
|
||||
{}
|
||||
local(const local& other)
|
||||
: val(other.val)
|
||||
{
|
||||
if (other.val != 0xabcdabcd)
|
||||
copyCtorCalledWithUninitializedValue = true;
|
||||
}
|
||||
local(local&& other)
|
||||
: val(eastl::move(other.val))
|
||||
{
|
||||
if (other.val != 0xabcdabcd)
|
||||
moveCtorCalledWithUninitializedValue = true;
|
||||
}
|
||||
local& operator=(const local&) = delete;
|
||||
};
|
||||
eastl::optional<local> n;
|
||||
eastl::optional<local> o1(n);
|
||||
VERIFY(!copyCtorCalledWithUninitializedValue);
|
||||
eastl::optional<local> o2(eastl::move(n));
|
||||
VERIFY(!moveCtorCalledWithUninitializedValue);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto testFn = []() -> optional<int>
|
||||
{
|
||||
return eastl::nullopt;
|
||||
};
|
||||
|
||||
auto o = testFn();
|
||||
VERIFY(!!o == false);
|
||||
}
|
||||
|
||||
#endif // EASTL_OPTIONAL_ENABLED
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
//#pragma warning(disable: 4267) // 'argument' : conversion from 'size_t' to 'uint32_t', possible loss of data.
|
||||
#endif
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/numeric_limits.h>
|
||||
#include <EASTL/set.h>
|
||||
#include <EASTL/random.h>
|
||||
|
||||
|
||||
struct GeneratorUint8
|
||||
{
|
||||
uint8_t mValue;
|
||||
GeneratorUint8() : mValue(0) {}
|
||||
uint8_t operator()(){ return mValue++; } // This is a pretty bad random number generator, but works for our tests.
|
||||
};
|
||||
|
||||
struct GeneratorUint16
|
||||
{
|
||||
uint16_t mValue;
|
||||
GeneratorUint16() : mValue(0) {}
|
||||
uint16_t operator()(){ return mValue++; }
|
||||
};
|
||||
|
||||
struct GeneratorUint32
|
||||
{
|
||||
uint32_t mValue;
|
||||
GeneratorUint32() : mValue(0) {}
|
||||
uint32_t operator()(){ return mValue++; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestRandom
|
||||
//
|
||||
int TestRandom()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
// template<class IntType = int>
|
||||
// class uniform_int_distribution
|
||||
|
||||
// The C++11 Standard defines a number of formal Generators, such as std::mersenne_twister_engine,
|
||||
// linear_congruential_engine, discard_block_engine, etc.
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
eastl::uniform_int_distribution<uint8_t> uid(1, 6);
|
||||
GeneratorUint8 g;
|
||||
|
||||
for(uint32_t i = 0; i < UINT8_MAX; i += 1)
|
||||
{
|
||||
uint8_t value = uid(g);
|
||||
EATEST_VERIFY((value >= 1) && (value <= 6));
|
||||
// To do: Validate the randomness of the value.
|
||||
}
|
||||
|
||||
eastl::uniform_int_distribution<uint8_t> uid2(1, 6);
|
||||
EATEST_VERIFY(uid == uid2);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::uniform_int_distribution<uint16_t> uid(1, 6);
|
||||
GeneratorUint16 g;
|
||||
|
||||
for(uint32_t i = 0; i < (UINT16_MAX - (UINT16_MAX / 50)); i += (UINT16_MAX / 50))
|
||||
{
|
||||
uint16_t value = uid(g);
|
||||
EATEST_VERIFY((value >= 1) && (value <= 6));
|
||||
// To do: Validate the randomness of the value.
|
||||
}
|
||||
|
||||
eastl::uniform_int_distribution<uint16_t> uid2(1, 6);
|
||||
EATEST_VERIFY(uid == uid2);
|
||||
}
|
||||
|
||||
{
|
||||
eastl::uniform_int_distribution<uint32_t> uid(1, 6);
|
||||
GeneratorUint32 g;
|
||||
|
||||
for(uint32_t i = 0; i < (UINT32_MAX - (UINT32_MAX / 500)); i += (UINT32_MAX / 500))
|
||||
{
|
||||
uint32_t value = uid(g);
|
||||
EATEST_VERIFY((value >= 1) && (value <= 6));
|
||||
// To do: Validate the randomness of the value.
|
||||
}
|
||||
|
||||
eastl::uniform_int_distribution<uint32_t> uid2(1, 6);
|
||||
EATEST_VERIFY(uid == uid2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Example usage:
|
||||
/// eastl_size_t Rand(eastl_size_t n) { return (eastl_size_t)(rand() % n); } // Note: The C rand function is poor and slow.
|
||||
/// pointer_to_unary_function<eastl_size_t, eastl_size_t> randInstance(Rand);
|
||||
/// random_shuffle(pArrayBegin, pArrayEnd, randInstance);
|
||||
///
|
||||
/// Example usage:
|
||||
/// struct Rand{ eastl_size_t operator()(eastl_size_t n) { return (eastl_size_t)(rand() % n); } }; // Note: The C rand function is poor and slow.
|
||||
/// Rand randInstance;
|
||||
/// random_shuffle(pArrayBegin, pArrayEnd, randInstance);
|
||||
|
||||
|
||||
{
|
||||
// void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator& rng)
|
||||
using namespace eastl;
|
||||
|
||||
EASTLTest_Rand rng(EA::UnitTest::GetRandSeed());
|
||||
int intArray[] = { 3, 2, 6, 5, 4, 1 };
|
||||
|
||||
random_shuffle(intArray, intArray + 0, rng);
|
||||
EATEST_VERIFY(VerifySequence(intArray, intArray + 6, int(), "random_shuffle", 3, 2, 6, 5, 4, 1, -1));
|
||||
|
||||
random_shuffle(intArray, intArray + (sizeof(intArray) / sizeof(intArray[0])), rng);
|
||||
bool changed = false;
|
||||
for(int i = 0; (i < 5) && !changed; i++)
|
||||
{
|
||||
changed = (intArray[0] != 3) || (intArray[1] != 2) || (intArray[2] != 6) ||
|
||||
(intArray[3] != 5) || (intArray[4] != 4) || (intArray[5] != 1);
|
||||
}
|
||||
EATEST_VERIFY(changed);
|
||||
|
||||
// Test of possible bug report by user John Chin.
|
||||
// The report is that shuffling an ordered array 0, 1, 2, 3, 4 ... results in duplicates, such as 5, 2, 2, 4 ...
|
||||
eastl::vector<eastl_size_t> rngArray;
|
||||
|
||||
for(eastl_size_t i = 0; i < 200; ++i)
|
||||
rngArray.push_back(i);
|
||||
|
||||
random_shuffle(rngArray.begin(), rngArray.end(), rng);
|
||||
EATEST_VERIFY(rngArray.validate());
|
||||
|
||||
eastl::set<eastl_size_t> intSet;
|
||||
|
||||
for(eastl_size_t s = 0, sEnd = rngArray.size(); s < sEnd; ++s)
|
||||
intSet.insert(rngArray[s]);
|
||||
|
||||
// If the shuffled array is unique, then a set of its values should be the same size as the array.
|
||||
EATEST_VERIFY(intSet.size() == rngArray.size());
|
||||
}
|
||||
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/ratio.h>
|
||||
|
||||
|
||||
int TestRatio()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
{
|
||||
using namespace eastl::Internal;
|
||||
|
||||
// lcm (least common multiple)
|
||||
static_assert(lcm<0,0>::value == 0, "lcm failure");
|
||||
static_assert(lcm<10,6>::value == 30, "lcm failure");
|
||||
static_assert(lcm<21,6>::value == 42, "lcm failure");
|
||||
static_assert(lcm<21,6>::value == lcm<6,21>::value, "lcm failure");
|
||||
|
||||
// gcd (greatest common divisor)
|
||||
static_assert(gcd<6, 4>::value == 2, "gcd failure");
|
||||
static_assert(gcd<54, 24>::value == 6, "gcd failure");
|
||||
static_assert(gcd<42, 56>::value == 14, "gcd failure");
|
||||
static_assert(gcd<48, 18>::value == 6, "gcd failure");
|
||||
static_assert(gcd<50, 40>::value == 10, "gcd failure");
|
||||
static_assert(gcd<6, 4>::value != 9, "gcd failure");
|
||||
static_assert(gcd<0, 0>::value == 1, "gcd failure");
|
||||
static_assert(gcd<1, 0>::value == 1, "gcd failure");
|
||||
static_assert(gcd<0, 1>::value == 1, "gcd failure");
|
||||
static_assert(gcd<34,7>::value == gcd<7, 34>::value, "gcd failure");
|
||||
static_assert(gcd<9223372036854775807, 9223372036854775807>::value == 9223372036854775807, "gcd failure");
|
||||
|
||||
// simplify
|
||||
typedef ct_simplify<ratio<50, 40>>::ratio_type smp_rt;
|
||||
typedef ct_simplify<ratio<50, 40>>::this_type smp_tt;
|
||||
static_assert(smp_rt::num == 5 && smp_rt::den == 4, "simplify failure");
|
||||
static_assert(smp_tt::divisor == 10, "simplify failure0");
|
||||
static_assert(smp_rt::num == 5, "simplify failure1");
|
||||
static_assert(smp_rt::den == 4, "simplify failure2");
|
||||
}
|
||||
|
||||
{
|
||||
// ratio_add
|
||||
typedef ratio_add<ratio<2, 3>, ratio<1, 6>> sum;
|
||||
static_assert(sum::num == 5 && sum::den == 6, "ratio_add failure");
|
||||
typedef ratio_add<ratio<3,4>, ratio<5,10>> sum2;
|
||||
static_assert(sum2::num == 5 && sum2::den == 4, "ratio_add failure");
|
||||
|
||||
// ratio_subtract
|
||||
typedef ratio_subtract<ratio<10,10>, ratio<1,2>> sum3;
|
||||
static_assert(sum3::num == 1 && sum3::den == 2, "ratio_subtract failure");
|
||||
|
||||
// ratio_multiply
|
||||
typedef ratio_multiply<ratio<10,10>, ratio<1,2>> sum4;
|
||||
static_assert(sum4::num == 1 && sum4::den == 2, "ratio_multiply failure");
|
||||
typedef ratio_multiply<ratio<2,5>, ratio<1,2>> sum5;
|
||||
static_assert(sum5::num == 1 && sum5::den == 5, "ratio_multiply failure");
|
||||
typedef ratio_multiply<ratio<1,3>, ratio<9,16>> sum6;
|
||||
static_assert(sum6::num == 3 && sum6::den == 16, "ratio_multiply failure");
|
||||
|
||||
// ratio_divide
|
||||
typedef ratio_divide<ratio<1,8>, ratio<1,4>> sum8;
|
||||
static_assert(sum8::num == 1 && sum8::den == 2, "ratio_divide failure");
|
||||
typedef ratio_divide<ratio<2,3>, ratio<5>> sum9;
|
||||
static_assert(sum9::num == 2 && sum9::den == 15, "ratio_divide failure");
|
||||
|
||||
// ratio_equal
|
||||
static_assert(ratio_equal<ratio<1>, ratio<1>>::value, "ratio_equal failure");
|
||||
static_assert(ratio_equal<ratio<1,1>, ratio<4,4>>::value, "ratio_equal failure");
|
||||
static_assert(ratio_equal<ratio<5,10>, ratio<1,2>>::value, "ratio_equal failure");
|
||||
static_assert(ratio_equal<ratio<2,3>, ratio<4,6>>::value, "ratio_equal failure");
|
||||
|
||||
// ratio_not_equal
|
||||
static_assert(!ratio_not_equal<ratio<5,10>, ratio<1,2>>::value, "ratio_not_equal failure");
|
||||
|
||||
// ratio_less
|
||||
static_assert(ratio_less<ratio<2,10>, ratio<1,2>>::value, "ratio_less failure");
|
||||
static_assert(ratio_less<ratio<23,37>, ratio<57,90>>::value, "ratio_less failure");
|
||||
|
||||
// ratio_less_equal
|
||||
static_assert(ratio_less_equal<ratio<2,10>, ratio<1,2>>::value, "ratio_less_equal failure");
|
||||
static_assert(ratio_less_equal<ratio<2,10>, ratio<1,5>>::value, "ratio_less_equal failure");
|
||||
static_assert(ratio_less_equal<ratio<1,100>, ratio<1,5>>::value, "ratio_less_equal failure");
|
||||
|
||||
// ratio_greater
|
||||
static_assert(ratio_greater<ratio<1,2>, ratio<1,4>>::value, "ratio_greater failure");
|
||||
|
||||
// ratio_greater_equal
|
||||
static_assert(ratio_greater_equal<ratio<3,4>, ratio<1,2>>::value, "ratio_greater_equal failure");
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,928 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/slist.h>
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/fixed_allocator.h>
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct TestObj
|
||||
{
|
||||
TestObj() : mI(0), mMoveCtor(0), mCopyCtor(0) {}
|
||||
explicit TestObj(int i) : mI(i), mMoveCtor(0), mCopyCtor(0) {}
|
||||
explicit TestObj(int a, int b, int c, int d) : mI(a+b+c+d), mMoveCtor(0), mCopyCtor(0) {}
|
||||
|
||||
TestObj(TestObj&& other)
|
||||
{
|
||||
mI = other.mI;
|
||||
mMoveCtor = other.mMoveCtor;
|
||||
mCopyCtor = other.mCopyCtor;
|
||||
mMoveCtor++;
|
||||
}
|
||||
|
||||
TestObj(const TestObj& other)
|
||||
{
|
||||
mI = other.mI;
|
||||
mMoveCtor = other.mMoveCtor;
|
||||
mCopyCtor = other.mCopyCtor;
|
||||
mCopyCtor++;
|
||||
}
|
||||
|
||||
TestObj& operator=(const TestObj& other)
|
||||
{
|
||||
mI = other.mI;
|
||||
mMoveCtor = other.mMoveCtor;
|
||||
mCopyCtor = other.mCopyCtor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int mI;
|
||||
int mMoveCtor;
|
||||
int mCopyCtor;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TestSList
|
||||
int TestSList()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// slist();
|
||||
{
|
||||
slist<int> list;
|
||||
VERIFY(list.empty());
|
||||
VERIFY(list.size() == 0);
|
||||
}
|
||||
|
||||
// slist(const allocator_type& allocator);
|
||||
{
|
||||
MallocAllocator::reset_all();
|
||||
|
||||
VERIFY(MallocAllocator::mAllocCountAll == 0);
|
||||
slist<int, MallocAllocator> list;
|
||||
list.resize(100, 42);
|
||||
VERIFY(MallocAllocator::mAllocCountAll == 100);
|
||||
}
|
||||
|
||||
// explicit slist(size_type n, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR);
|
||||
{
|
||||
slist<int> list(100);
|
||||
VERIFY(list.size() == 100);
|
||||
VERIFY(!list.empty());
|
||||
}
|
||||
|
||||
// slist(size_type n, const value_type& value, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR);
|
||||
{
|
||||
slist<int> list(32, 42);
|
||||
VERIFY(list.size() == 32);
|
||||
VERIFY(list.front() == 42);
|
||||
VERIFY(!list.empty());
|
||||
}
|
||||
|
||||
// slist(const this_type& x);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 42);
|
||||
|
||||
VERIFY(!list1.empty());
|
||||
slist<int> list2(list1);
|
||||
VERIFY(!list2.empty());
|
||||
VERIFY(list1 == list2);
|
||||
}
|
||||
|
||||
// slist(std::initializer_list<value_type> ilist, const allocator_type& allocator = EASTL_SLIST_DEFAULT_ALLOCATOR);
|
||||
{
|
||||
#if !defined(EA_COMPILER_NO_INITIALIZER_LISTS)
|
||||
slist<int> list1({1,2,3,4,5,6,7,8});
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
// slist(this_type&& x);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100,42);
|
||||
|
||||
slist<int> list2(eastl::move(list1));
|
||||
|
||||
VERIFY(list1.empty());
|
||||
VERIFY(!list2.empty());
|
||||
VERIFY(list1 != list2);
|
||||
}
|
||||
|
||||
// slist(this_type&& x, const allocator_type& allocator);
|
||||
{ }
|
||||
|
||||
// slist(InputIterator first, InputIterator last);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 42);
|
||||
VERIFY(!list1.empty());
|
||||
|
||||
slist<int> list2(list1.begin(), list1.end());
|
||||
VERIFY(!list2.empty());
|
||||
VERIFY(list1 == list2);
|
||||
}
|
||||
|
||||
// this_type& operator=(const this_type& x);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 42);
|
||||
VERIFY(!list1.empty());
|
||||
|
||||
slist<int> list2 = list1;
|
||||
VERIFY(!list2.empty());
|
||||
VERIFY(list1 == list2);
|
||||
}
|
||||
|
||||
// this_type& operator=(std::initializer_list<value_type>);
|
||||
{
|
||||
slist<int> list1 = {1,2,3,4,5,6,7,8};
|
||||
VERIFY(!list1.empty());
|
||||
}
|
||||
|
||||
// this_type& operator=(this_type&& x);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 42);
|
||||
slist<int> list2 = eastl::move(list1);
|
||||
|
||||
VERIFY(list1.empty());
|
||||
VERIFY(!list2.empty());
|
||||
VERIFY(list1 != list2);
|
||||
}
|
||||
|
||||
// void swap(this_type& x);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(8, 37);
|
||||
|
||||
slist<int> list2;
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 8);
|
||||
VERIFY(list2.empty());
|
||||
|
||||
list2.swap(list1);
|
||||
|
||||
VERIFY(list1.empty());
|
||||
VERIFY(!list2.empty());
|
||||
}
|
||||
|
||||
// void assign(size_type n, const value_type& value);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.assign(100, 42);
|
||||
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 100);
|
||||
|
||||
for(auto& e : list1)
|
||||
VERIFY(e == 42);
|
||||
}
|
||||
|
||||
// void assign(std::initializer_list<value_type> ilist);
|
||||
{
|
||||
#if !defined(EA_COMPILER_NO_INITIALIZER_LISTS)
|
||||
slist<int> list1;
|
||||
list1.assign({1,2,3,4,5,6,7,8});
|
||||
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 8);
|
||||
|
||||
auto i = eastl::begin(list1);
|
||||
VERIFY(*i == 1); i++;
|
||||
VERIFY(*i == 2); i++;
|
||||
VERIFY(*i == 3); i++;
|
||||
VERIFY(*i == 4); i++;
|
||||
VERIFY(*i == 5); i++;
|
||||
VERIFY(*i == 6); i++;
|
||||
VERIFY(*i == 7); i++;
|
||||
VERIFY(*i == 8); i++;
|
||||
VERIFY(i == eastl::end(list1));
|
||||
#endif
|
||||
}
|
||||
|
||||
// void assign(InputIterator first, InputIterator last);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 42);
|
||||
VERIFY(!list1.empty());
|
||||
|
||||
slist<int> list2;
|
||||
list2.assign(list1.begin(), list1.end());
|
||||
VERIFY(!list2.empty());
|
||||
VERIFY(list1 == list2);
|
||||
}
|
||||
|
||||
// iterator begin() EA_NOEXCEPT;
|
||||
// const_iterator begin() const EA_NOEXCEPT;
|
||||
// const_iterator cbegin() const EA_NOEXCEPT;
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 1);
|
||||
VERIFY(!list1.empty());
|
||||
|
||||
const auto ci = list1.begin();
|
||||
auto i = list1.begin();
|
||||
auto ci2 = list1.cbegin();
|
||||
|
||||
VERIFY(*i == 1);
|
||||
VERIFY(*ci == 1);
|
||||
VERIFY(*ci2 == 1);
|
||||
}
|
||||
|
||||
// iterator end() EA_NOEXCEPT;
|
||||
// const_iterator end() const EA_NOEXCEPT;
|
||||
// const_iterator cend() const EA_NOEXCEPT;
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 42);
|
||||
VERIFY(!list1.empty());
|
||||
|
||||
const auto ci = list1.end();
|
||||
auto i = list1.end();
|
||||
auto ci2 = list1.cend();
|
||||
|
||||
VERIFY(i == eastl::end(list1));
|
||||
VERIFY(ci == eastl::end(list1));
|
||||
VERIFY(ci2 == eastl::end(list1));
|
||||
}
|
||||
|
||||
// iterator before_begin() EA_NOEXCEPT;
|
||||
// const_iterator before_begin() const EA_NOEXCEPT;
|
||||
// const_iterator cbefore_begin() const EA_NOEXCEPT;
|
||||
// iterator previous(const_iterator position);
|
||||
// const_iterator previous(const_iterator position) const;
|
||||
{
|
||||
slist<int> list1;
|
||||
|
||||
auto b = list1.begin();
|
||||
auto prev = list1.previous(b);
|
||||
|
||||
VERIFY(prev == list1.before_begin());
|
||||
}
|
||||
|
||||
// reference front();
|
||||
// const_reference front() const;
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 1);
|
||||
|
||||
VERIFY(list1.begin() == eastl::begin(list1));
|
||||
VERIFY(list1.front() == 1);
|
||||
|
||||
const slist<int> clist1(list1);
|
||||
VERIFY(clist1.front() == 1);
|
||||
VERIFY(list1.validate());
|
||||
VERIFY(clist1.validate());
|
||||
}
|
||||
|
||||
|
||||
// void emplace_front(Args&&... args);
|
||||
// void emplace_front(value_type&& value);
|
||||
// void emplace_front(const value_type& value);
|
||||
{
|
||||
slist<TestObj> list1;
|
||||
list1.emplace_front(42);
|
||||
VERIFY(list1.front().mI == 42);
|
||||
VERIFY(list1.front().mCopyCtor == 0);
|
||||
VERIFY(list1.front().mMoveCtor == 0);
|
||||
VERIFY(list1.size() == 1);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.emplace_front(1,2,3,4);
|
||||
VERIFY(list1.front().mCopyCtor == 0);
|
||||
VERIFY(list1.front().mMoveCtor == 0);
|
||||
VERIFY(list1.front().mI == (1+2+3+4));
|
||||
VERIFY(list1.size() == 2);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// void push_front(const value_type& value);
|
||||
// reference push_front();
|
||||
// void push_front(value_type&& value);
|
||||
{
|
||||
slist<TestObj> list1;
|
||||
list1.push_front(TestObj(42));
|
||||
VERIFY(list1.front().mI == 42);
|
||||
VERIFY(list1.front().mCopyCtor == 0);
|
||||
VERIFY(list1.front().mMoveCtor == 1);
|
||||
VERIFY(list1.size() == 1);
|
||||
|
||||
list1.push_front();
|
||||
VERIFY(list1.front().mCopyCtor == 0);
|
||||
VERIFY(list1.front().mMoveCtor == 0);
|
||||
VERIFY(list1.front().mI == 0);
|
||||
VERIFY(list1.size() == 2);
|
||||
|
||||
list1.push_front().mI = 1492;
|
||||
VERIFY(list1.front().mI == 1492);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// void pop_front();
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.push_front(4);
|
||||
list1.push_front(3);
|
||||
list1.push_front(2);
|
||||
list1.push_front(1);
|
||||
|
||||
list1.pop_front();
|
||||
VERIFY(list1.front() == 2);
|
||||
VERIFY(list1.size() == 3);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.pop_front();
|
||||
VERIFY(list1.front() == 3);
|
||||
VERIFY(list1.size() == 2);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.pop_front();
|
||||
VERIFY(list1.front() == 4);
|
||||
VERIFY(list1.size() == 1);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// bool empty() const EA_NOEXCEPT;
|
||||
// size_type size() const EA_NOEXCEPT;
|
||||
{
|
||||
slist<int> list1;
|
||||
VERIFY(list1.empty());
|
||||
VERIFY(list1.size() == 0);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.push_front(42);
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 1);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.pop_front();
|
||||
VERIFY(list1.empty());
|
||||
VERIFY(list1.size() == 0);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
|
||||
// void resize(size_type n, const value_type& value);
|
||||
// void resize(size_type n);
|
||||
{
|
||||
slist<int> list1;
|
||||
VERIFY(list1.empty());
|
||||
list1.resize(100, 42);
|
||||
VERIFY(list1.front() == 42);
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 100);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
slist<int> list2;
|
||||
VERIFY(list2.empty());
|
||||
list2.resize(100);
|
||||
VERIFY(!list2.empty());
|
||||
VERIFY(list2.size() == 100);
|
||||
VERIFY(list2.validate());
|
||||
}
|
||||
|
||||
// iterator insert(const_iterator position);
|
||||
// iterator insert(const_iterator position, const value_type& value);
|
||||
// void insert(const_iterator position, size_type n, const value_type& value);
|
||||
{
|
||||
static const int MAGIC_VALUE = 4242;
|
||||
struct TestVal
|
||||
{
|
||||
TestVal() : mV(MAGIC_VALUE) {}
|
||||
TestVal(int v) : mV(v) {}
|
||||
operator int() { return mV; }
|
||||
int mV;
|
||||
};
|
||||
|
||||
slist<TestVal> list1;
|
||||
VERIFY(list1.empty());
|
||||
|
||||
auto insert_iter = eastl::begin(list1);
|
||||
list1.insert(insert_iter);
|
||||
VERIFY(list1.size() == 1);
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.insert(insert_iter, 42);
|
||||
VERIFY(list1.size() == 2);
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.front() == MAGIC_VALUE);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
|
||||
list1.insert(insert_iter, 43);
|
||||
VERIFY(list1.size() == 3);
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.front() == MAGIC_VALUE);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// template <typename InputIterator>
|
||||
// void insert(const_iterator position, InputIterator first, InputIterator last);
|
||||
{
|
||||
slist<int> list1;
|
||||
VERIFY(list1.empty());
|
||||
list1.resize(100, 42);
|
||||
VERIFY(list1.size() == 100);
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.validate());
|
||||
|
||||
slist<int> list2;
|
||||
list2.resize(400, 24);
|
||||
VERIFY(list2.size() == 400);
|
||||
VERIFY(!list2.empty());
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.insert(eastl::end(list1), eastl::begin(list2), eastl::end(list2)); // [42,42,42,...,42, | 24,24,24,24...]
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 500);
|
||||
VERIFY(list1.front() == 42);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
auto boundary_iter = list1.begin();
|
||||
eastl::advance(boundary_iter, 100); // move to insertation point
|
||||
VERIFY(*boundary_iter == 24);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
|
||||
// Returns an iterator pointing to the last inserted element, or position if insertion count is zero.
|
||||
// iterator insert_after(const_iterator position);
|
||||
// iterator insert_after(const_iterator position, const value_type& value);
|
||||
// iterator insert_after(const_iterator position, size_type n, const value_type& value);
|
||||
// iterator insert_after(const_iterator position, std::initializer_list<value_type> ilist);
|
||||
{
|
||||
slist<int> list1;
|
||||
VERIFY(list1.empty());
|
||||
list1.push_front();
|
||||
|
||||
list1.insert_after(list1.begin());
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 2);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.insert_after(list1.begin(), 43);
|
||||
VERIFY(list1.size() == 3);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.insert_after(list1.begin(), 10, 42);
|
||||
VERIFY(list1.size() == 13);
|
||||
VERIFY(eastl::count_if(list1.begin(), list1.end(), [](int i) { return i == 42; }) == 10);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.insert_after(list1.begin(), {1,2,3,4,5,6,7,8,9,0});
|
||||
VERIFY(list1.size() == 23);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// iterator insert_after(const_iterator position, value_type&& value);
|
||||
{
|
||||
slist<TestObj> list1;
|
||||
VERIFY(list1.empty());
|
||||
list1.push_front();
|
||||
|
||||
auto inserted = list1.insert_after(list1.begin(), TestObj(42));
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY((*inserted).mCopyCtor == 0);
|
||||
VERIFY((*inserted).mMoveCtor == 1);
|
||||
}
|
||||
|
||||
// iterator insert_after(const_iterator position, InputIterator first, InputIterator last);
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3,4};
|
||||
slist<int> list2 = {9,8,7,6,5};
|
||||
list1.insert_after(list1.begin(), list2.begin(), list2.end());
|
||||
VERIFY(list1 == slist<int>({0,9,8,7,6,5,1,2,3,4}));
|
||||
}
|
||||
|
||||
// iterator emplace_after(const_iterator position, Args&&... args);
|
||||
// iterator emplace_after(const_iterator position, value_type&& value);
|
||||
// iterator emplace_after(const_iterator position, const value_type& value);
|
||||
{
|
||||
slist<TestObj> list1;
|
||||
list1.emplace_after(list1.before_begin(), 42);
|
||||
VERIFY(list1.front().mI == 42);
|
||||
VERIFY(list1.front().mCopyCtor == 0);
|
||||
VERIFY(list1.front().mMoveCtor == 0);
|
||||
VERIFY(list1.size() == 1);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.emplace_after(list1.before_begin(),1,2,3,4);
|
||||
VERIFY(list1.front().mCopyCtor == 0);
|
||||
VERIFY(list1.front().mMoveCtor == 0);
|
||||
VERIFY(list1.front().mI == (1+2+3+4));
|
||||
VERIFY(list1.size() == 2);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// iterator erase(const_iterator position);
|
||||
// iterator erase(const_iterator first, const_iterator last);
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3,4,5,6,7};
|
||||
|
||||
auto p = list1.begin();
|
||||
p++; p++; p++;
|
||||
|
||||
list1.erase(p);
|
||||
VERIFY(list1 == slist<int>({0,1,2,4,5,6,7}));
|
||||
|
||||
list1.erase(list1.begin(), list1.end());
|
||||
VERIFY(list1 == slist<int>({}));
|
||||
VERIFY(list1.size() == 0);
|
||||
VERIFY(list1.empty());
|
||||
}
|
||||
|
||||
// iterator erase_after(const_iterator position);
|
||||
// iterator erase_after(const_iterator before_first, const_iterator last);
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3,4,5,6,7};
|
||||
auto p = list1.begin();
|
||||
|
||||
list1.erase_after(p);
|
||||
VERIFY(list1 == slist<int>({0,2,3,4,5,6,7}));
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.erase_after(p);
|
||||
VERIFY(list1 == slist<int>({0,3,4,5,6,7}));
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.erase_after(p);
|
||||
VERIFY(list1 == slist<int>({0,4,5,6,7}));
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.erase_after(p, list1.end());
|
||||
VERIFY(list1 == slist<int>({0}));
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// void clear();
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 42);
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == 100);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.clear();
|
||||
VERIFY(list1.empty());
|
||||
VERIFY(list1.size() == 0);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// void reset_lose_memory();
|
||||
{
|
||||
typedef eastl::slist<int, fixed_allocator> SIntList;
|
||||
typedef SIntList::node_type SIntListNode;
|
||||
const size_t kBufferCount = 100;
|
||||
SIntListNode buffer1[kBufferCount];
|
||||
SIntList list1;
|
||||
const size_t kAlignOfSIntListNode = EA_ALIGN_OF(SIntListNode);
|
||||
list1.get_allocator().init(buffer1, sizeof(buffer1), sizeof(SIntListNode), kAlignOfSIntListNode);
|
||||
|
||||
VERIFY(list1.empty());
|
||||
VERIFY(list1.size() == 0);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.resize(kBufferCount, 42);
|
||||
VERIFY(!list1.empty());
|
||||
VERIFY(list1.size() == kBufferCount);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.reset_lose_memory();
|
||||
VERIFY(list1.empty());
|
||||
VERIFY(list1.size() == 0);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// void remove(const value_type& value);
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3,4};
|
||||
slist<int> list2 = {0,1,3,4};
|
||||
|
||||
list1.remove(2);
|
||||
|
||||
VERIFY(list1 == list2);
|
||||
VERIFY(list1.validate());
|
||||
VERIFY(list2.validate());
|
||||
}
|
||||
|
||||
// void remove_if(Predicate predicate);
|
||||
{
|
||||
slist<int> list1;
|
||||
list1.resize(100, 42);
|
||||
VERIFY(list1.size() == 100);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.remove_if([](int i) { return i == 1234; }); // intentionally remove nothing.
|
||||
VERIFY(list1.size() == 100);
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.remove_if([](int i) { return i == 42; });
|
||||
VERIFY(list1.size() == 0);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// void reverse() EA_NOEXCEPT;
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3,4};
|
||||
slist<int> list2 = {4,3,2,1,0};
|
||||
VERIFY(list1 != list2);
|
||||
|
||||
list1.reverse();
|
||||
VERIFY(list1 == list2);
|
||||
}
|
||||
|
||||
// void splice(const_iterator position, this_type& x);
|
||||
// void splice(const_iterator position, this_type& x, const_iterator i);
|
||||
// void splice(const_iterator position, this_type& x, const_iterator first, const_iterator last);
|
||||
{
|
||||
slist<int> valid = {0,1,2,3,4,5,6,7};
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
list1.splice(list1.end(), list2);
|
||||
|
||||
VERIFY(list1 == valid);
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
|
||||
list1.splice(list1.begin(), list2, list2.begin());
|
||||
VERIFY(list1 == slist<int>({4,0,1,2,3}));
|
||||
VERIFY(list2 == slist<int>({5,6,7}));
|
||||
|
||||
list1.splice(list1.begin(), list2, list2.begin());
|
||||
VERIFY(list1 == slist<int>({5,4,0,1,2,3}));
|
||||
VERIFY(list2 == slist<int>({6,7}));
|
||||
|
||||
list1.splice(list1.begin(), list2, list2.begin());
|
||||
VERIFY(list1 == slist<int>({6,5,4,0,1,2,3}));
|
||||
VERIFY(list2 == slist<int>({7}));
|
||||
|
||||
list1.splice(list1.begin(), list2, list2.begin());
|
||||
VERIFY(list1 == slist<int>({7,6,5,4,0,1,2,3}));
|
||||
VERIFY(list2 == slist<int>({}));
|
||||
|
||||
VERIFY(list1.validate());
|
||||
VERIFY(list2.validate());
|
||||
}
|
||||
}
|
||||
|
||||
// void splice(const_iterator position, this_type&& x);
|
||||
// void splice(const_iterator position, this_type&& x, const_iterator i);
|
||||
// void splice(const_iterator position, this_type&& x, const_iterator first, const_iterator last);
|
||||
{
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
|
||||
list1.splice(list1.begin(), eastl::move(list2));
|
||||
VERIFY(list1 == slist<int>({4,5,6,7,0,1,2,3}));
|
||||
}
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
|
||||
list1.splice(list1.begin(), eastl::move(list2), list2.begin());
|
||||
VERIFY(list1 == slist<int>({4,0,1,2,3}));
|
||||
}
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
|
||||
auto b = list2.begin();
|
||||
auto e = list2.end();
|
||||
e = list2.previous(e);
|
||||
e = list2.previous(e);
|
||||
|
||||
list1.splice(list1.begin(), eastl::move(list2), b, e);
|
||||
VERIFY(list1 == slist<int>({4,5,0,1,2,3}));
|
||||
}
|
||||
}
|
||||
|
||||
// void splice_after(const_iterator position, this_type& x);
|
||||
// void splice_after(const_iterator position, this_type& x, const_iterator i);
|
||||
// void splice_after(const_iterator position, this_type& x, const_iterator first, const_iterator last);
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
|
||||
list1.splice_after(list1.begin(), list2);
|
||||
VERIFY(list1 == slist<int>({0,4,5,6,7,1,2,3}));
|
||||
VERIFY(list1.validate());
|
||||
VERIFY(list2.validate());
|
||||
}
|
||||
|
||||
// void splice_after(const_iterator position, this_type&& x);
|
||||
// void splice_after(const_iterator position, this_type&& x, const_iterator i);
|
||||
// void splice_after(const_iterator position, this_type&& x, const_iterator first, const_iterator last);
|
||||
{
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
|
||||
list1.splice_after(list1.begin(), eastl::move(list2));
|
||||
VERIFY(list1 == slist<int>({0,4,5,6,7,1,2,3}));
|
||||
}
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
|
||||
list1.splice_after(list1.begin(), eastl::move(list2), list2.begin());
|
||||
VERIFY(list1 == slist<int>({0,5,6,7,1,2,3}));
|
||||
}
|
||||
{
|
||||
slist<int> list1 = {0,1,2,3};
|
||||
slist<int> list2 = {4,5,6,7};
|
||||
|
||||
auto b = list2.begin();
|
||||
auto e = list2.end();
|
||||
e = list2.previous(e);
|
||||
e = list2.previous(e);
|
||||
|
||||
list1.splice_after(list1.begin(), eastl::move(list2), b, e);
|
||||
VERIFY(list1 == slist<int>({0,5,6,1,2,3}));
|
||||
}
|
||||
}
|
||||
|
||||
// void sort();
|
||||
{
|
||||
slist<int> list1 = {0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 2, 2, 1, 0};
|
||||
VERIFY(!eastl::is_sorted(eastl::begin(list1), eastl::end(list1)));
|
||||
VERIFY(list1.validate());
|
||||
|
||||
list1.sort();
|
||||
|
||||
VERIFY(eastl::is_sorted(eastl::begin(list1), eastl::end(list1)));
|
||||
VERIFY(list1.validate());
|
||||
}
|
||||
|
||||
// template <class Compare>
|
||||
// void sort(Compare compare);
|
||||
{
|
||||
auto compare = [](int a, int b) { return a > b;};
|
||||
|
||||
slist<int> list1 = {0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 2, 2, 1, 0};
|
||||
VERIFY(!eastl::is_sorted(eastl::begin(list1), eastl::end(list1), compare));
|
||||
list1.sort(compare);
|
||||
VERIFY(eastl::is_sorted(eastl::begin(list1), eastl::end(list1), compare));
|
||||
}
|
||||
|
||||
{ // Test empty base-class optimization
|
||||
struct UnemptyDummyAllocator : eastl::dummy_allocator
|
||||
{
|
||||
int foo;
|
||||
};
|
||||
|
||||
typedef eastl::slist<int, eastl::dummy_allocator> list1;
|
||||
typedef eastl::slist<int, UnemptyDummyAllocator> list2;
|
||||
|
||||
EATEST_VERIFY(sizeof(list1) < sizeof(list2));
|
||||
}
|
||||
|
||||
{ // Test erase / erase_if
|
||||
{
|
||||
slist<int> l = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
auto numErased = eastl::erase(l, 5);
|
||||
VERIFY((l == slist<int>{0, 1, 2, 3, 4, 6, 7, 8, 9}));
|
||||
VERIFY(numErased == 1);
|
||||
|
||||
numErased = eastl::erase(l, 7);
|
||||
VERIFY((l == slist<int>{0, 1, 2, 3, 4, 6, 8, 9}));
|
||||
VERIFY(numErased == 1);
|
||||
|
||||
numErased = eastl::erase(l, 2);
|
||||
VERIFY((l == slist<int>{0, 1, 3, 4, 6, 8, 9}));
|
||||
VERIFY(numErased == 1);
|
||||
|
||||
numErased = eastl::erase(l, 0);
|
||||
VERIFY((l == slist<int>{1, 3, 4, 6, 8, 9}));
|
||||
VERIFY(numErased == 1);
|
||||
|
||||
numErased = eastl::erase(l, 4);
|
||||
VERIFY((l == slist<int>{1, 3, 6, 8, 9}));
|
||||
VERIFY(numErased == 1);
|
||||
}
|
||||
|
||||
{
|
||||
slist<int> l = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
auto numErased = eastl::erase_if(l, [](auto e) { return e % 2 == 0; });
|
||||
VERIFY((l == slist<int>{1, 3, 5, 7, 9}));
|
||||
VERIFY(numErased == 5);
|
||||
|
||||
numErased = eastl::erase_if(l, [](auto e) { return e == 5; });
|
||||
VERIFY((l == slist<int>{1, 3, 7, 9}));
|
||||
VERIFY(numErased == 1);
|
||||
|
||||
numErased = eastl::erase_if(l, [](auto e) { return e % 3 == 0; });
|
||||
VERIFY((l == slist<int>{1, 7}));
|
||||
VERIFY(numErased == 2);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Test global operators
|
||||
{
|
||||
slist<int> list1 = {0, 1, 2, 3, 4, 5};
|
||||
slist<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
slist<int> list3 = {5, 6, 7, 8};
|
||||
|
||||
VERIFY(list1 == list1);
|
||||
VERIFY(!(list1 != list1));
|
||||
|
||||
VERIFY(list1 != list2);
|
||||
VERIFY(list2 != list3);
|
||||
VERIFY(list1 != list3);
|
||||
|
||||
VERIFY(list1 < list2);
|
||||
VERIFY(list1 <= list2);
|
||||
|
||||
VERIFY(list2 > list1);
|
||||
VERIFY(list2 >= list1);
|
||||
|
||||
VERIFY(list3 > list1);
|
||||
VERIFY(list3 > list2);
|
||||
}
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
{
|
||||
slist<int> list1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
slist<int> list2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
slist<int> list3 = {-1, 0, 1, 2, 3, 4, 5};
|
||||
|
||||
// Verify equality between list1 and list2
|
||||
VERIFY((list1 <=> list2) == 0);
|
||||
VERIFY(!((list1 <=> list2) != 0));
|
||||
VERIFY((list1 <=> list2) <= 0);
|
||||
VERIFY((list1 <=> list2) >= 0);
|
||||
VERIFY(!((list1 <=> list2) < 0));
|
||||
VERIFY(!((list1 <=> list2) > 0));
|
||||
|
||||
list1.push_front(-2); // Make list1 less than list2.
|
||||
list2.push_front(-1);
|
||||
|
||||
// Verify list1 < list2
|
||||
VERIFY(!((list1 <=> list2) == 0));
|
||||
VERIFY((list1 <=> list2) != 0);
|
||||
VERIFY((list1 <=> list2) <= 0);
|
||||
VERIFY(!((list1 <=> list2) >= 0));
|
||||
VERIFY(((list1 <=> list2) < 0));
|
||||
VERIFY(!((list1 <=> list2) > 0));
|
||||
|
||||
|
||||
// Verify list3.size() < list2.size() and list3 is a subset of list2
|
||||
VERIFY(!((list3 <=> list2) == 0));
|
||||
VERIFY((list3 <=> list2) != 0);
|
||||
VERIFY((list3 <=> list2) <= 0);
|
||||
VERIFY(!((list3 <=> list2) >= 0));
|
||||
VERIFY(((list3 <=> list2) < 0));
|
||||
VERIFY(!((list3 <=> list2) > 0));
|
||||
}
|
||||
|
||||
{
|
||||
slist<int> list1 = {1, 2, 3, 4, 5, 6, 7};
|
||||
slist<int> list2 = {7, 6, 5, 4, 3, 2, 1};
|
||||
slist<int> list3 = {1, 2, 3, 4};
|
||||
|
||||
struct weak_ordering_slist
|
||||
{
|
||||
slist<int> slist;
|
||||
inline std::weak_ordering operator<=>(const weak_ordering_slist& b) const { return slist <=> b.slist; }
|
||||
};
|
||||
|
||||
VERIFY(synth_three_way{}(weak_ordering_slist{list1}, weak_ordering_slist{list2}) == std::weak_ordering::less);
|
||||
VERIFY(synth_three_way{}(weak_ordering_slist{list3}, weak_ordering_slist{list1}) == std::weak_ordering::less);
|
||||
VERIFY(synth_three_way{}(weak_ordering_slist{list2}, weak_ordering_slist{list1}) == std::weak_ordering::greater);
|
||||
VERIFY(synth_three_way{}(weak_ordering_slist{list2}, weak_ordering_slist{list3}) == std::weak_ordering::greater);
|
||||
VERIFY(synth_three_way{}(weak_ordering_slist{list1}, weak_ordering_slist{list1}) == std::weak_ordering::equivalent);
|
||||
|
||||
struct strong_ordering_slist
|
||||
{
|
||||
slist<int> slist;
|
||||
inline std::strong_ordering operator<=>(const strong_ordering_slist& b) const { return slist <=> b.slist; }
|
||||
};
|
||||
|
||||
VERIFY(synth_three_way{}(strong_ordering_slist{list1}, strong_ordering_slist{list2}) == std::strong_ordering::less);
|
||||
VERIFY(synth_three_way{}(strong_ordering_slist{list3}, strong_ordering_slist{list1}) == std::strong_ordering::less);
|
||||
VERIFY(synth_three_way{}(strong_ordering_slist{list2}, strong_ordering_slist{list1}) == std::strong_ordering::greater);
|
||||
VERIFY(synth_three_way{}(strong_ordering_slist{list2}, strong_ordering_slist{list3}) == std::strong_ordering::greater);
|
||||
VERIFY(synth_three_way{}(strong_ordering_slist{list1}, strong_ordering_slist{list1}) == std::strong_ordering::equal);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/segmented_vector.h>
|
||||
#include <EASTL/list.h>
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::segmented_vector<bool, 16>;
|
||||
template class eastl::segmented_vector<int, 16>;
|
||||
template class eastl::segmented_vector<Align64, 16>;
|
||||
template class eastl::segmented_vector<TestObject, 16>;
|
||||
|
||||
|
||||
int TestSegmentedVector()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
TestObject::Reset();
|
||||
|
||||
{
|
||||
eastl::segmented_vector<int, 8> sv;
|
||||
sv.push_back(0);
|
||||
sv.push_back(1);
|
||||
sv.push_back(2);
|
||||
sv.push_back(3);
|
||||
|
||||
{
|
||||
auto i = sv.begin();
|
||||
EATEST_VERIFY(*i == 0);
|
||||
EATEST_VERIFY(*i++ == 0);
|
||||
EATEST_VERIFY(*i++ == 1);
|
||||
EATEST_VERIFY(*i++ == 2);
|
||||
EATEST_VERIFY(*i++ == 3);
|
||||
}
|
||||
|
||||
{
|
||||
auto i = sv.begin();
|
||||
EATEST_VERIFY(*i == 0);
|
||||
EATEST_VERIFY(*(++i) == 1);
|
||||
EATEST_VERIFY(*(++i) == 2);
|
||||
EATEST_VERIFY(*(++i) == 3);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Construct segmented_vectors of different types.
|
||||
eastl::segmented_vector<int, 8> vectorOfInt;
|
||||
eastl::segmented_vector<TestObject, 8> vectorOfTO;
|
||||
eastl::segmented_vector<eastl::list<TestObject>, 8> vectorOfListOfTO;
|
||||
|
||||
EATEST_VERIFY(vectorOfInt.empty());
|
||||
EATEST_VERIFY(vectorOfTO.empty());
|
||||
EATEST_VERIFY(vectorOfListOfTO.empty());
|
||||
}
|
||||
|
||||
{
|
||||
// Test basic segmented_vector operations.
|
||||
eastl::segmented_vector<int, 4> vectorOfInt;
|
||||
|
||||
vectorOfInt.push_back(42);
|
||||
EATEST_VERIFY(vectorOfInt.size() == 1);
|
||||
EATEST_VERIFY(vectorOfInt.segment_count() == 1);
|
||||
EATEST_VERIFY(vectorOfInt.empty() == false);
|
||||
|
||||
vectorOfInt.push_back(43);
|
||||
vectorOfInt.push_back(44);
|
||||
vectorOfInt.push_back(45);
|
||||
vectorOfInt.push_back(46);
|
||||
EATEST_VERIFY(vectorOfInt.size() == 5);
|
||||
EATEST_VERIFY(vectorOfInt.segment_count() == 2);
|
||||
|
||||
EATEST_VERIFY(vectorOfInt.front() == 42);
|
||||
EATEST_VERIFY(vectorOfInt.back() == 46);
|
||||
|
||||
vectorOfInt.pop_back();
|
||||
EATEST_VERIFY(vectorOfInt.size() == 4);
|
||||
EATEST_VERIFY(vectorOfInt.segment_count() == 1);
|
||||
|
||||
vectorOfInt.clear();
|
||||
EATEST_VERIFY(vectorOfInt.empty());
|
||||
EATEST_VERIFY(vectorOfInt.size() == 0);
|
||||
EATEST_VERIFY(vectorOfInt.segment_count() == 0);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "TestSet.h"
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/map.h>
|
||||
#include <EASTL/set.h>
|
||||
#include <EASTL/functional.h>
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#endif
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::set<int>;
|
||||
template class eastl::multiset<float>;
|
||||
template class eastl::set<TestObject>;
|
||||
template class eastl::multiset<TestObject>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// typedefs
|
||||
//
|
||||
typedef eastl::set<int> VS1;
|
||||
typedef eastl::set<TestObject> VS4;
|
||||
typedef eastl::multiset<int> VMS1;
|
||||
typedef eastl::multiset<TestObject> VMS4;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
typedef std::set<int> VS3;
|
||||
typedef std::set<TestObject> VS6;
|
||||
typedef std::multiset<int> VMS3;
|
||||
typedef std::multiset<TestObject> VMS6;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// xvalue_test
|
||||
//
|
||||
// Test utility type that sets the class data to known value when its data has
|
||||
// has been moved out. This enables us to write tests that verify that the
|
||||
// destruction action taken on container elements occured during move operations.
|
||||
//
|
||||
struct xvalue_test
|
||||
{
|
||||
static const int MOVED_FROM = -1;
|
||||
|
||||
int data = 42;
|
||||
|
||||
xvalue_test(int in) : data(in) {}
|
||||
~xvalue_test() = default;
|
||||
|
||||
xvalue_test(const xvalue_test& other)
|
||||
: data(other.data) {}
|
||||
|
||||
xvalue_test& operator=(const xvalue_test& other)
|
||||
{
|
||||
data = other.data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
xvalue_test(xvalue_test&& other)
|
||||
{
|
||||
data = other.data;
|
||||
other.data = MOVED_FROM;
|
||||
}
|
||||
|
||||
xvalue_test& operator=(xvalue_test&& other)
|
||||
{
|
||||
data = other.data;
|
||||
other.data = MOVED_FROM;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator<(const xvalue_test& rhs, const xvalue_test& lhs)
|
||||
{ return rhs.data < lhs.data; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
int TestSet()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
{ // Test construction
|
||||
nErrorCount += TestSetConstruction<VS1, VS3, false>();
|
||||
nErrorCount += TestSetConstruction<VS4, VS6, false>();
|
||||
|
||||
nErrorCount += TestSetConstruction<VMS1, VMS3, true>();
|
||||
nErrorCount += TestSetConstruction<VMS4, VMS6, true>();
|
||||
}
|
||||
|
||||
|
||||
{ // Test mutating functionality.
|
||||
nErrorCount += TestSetMutation<VS1, VS3, false>();
|
||||
nErrorCount += TestSetMutation<VS4, VS6, false>();
|
||||
|
||||
nErrorCount += TestSetMutation<VMS1, VMS3, true>();
|
||||
nErrorCount += TestSetMutation<VMS4, VMS6, true>();
|
||||
}
|
||||
#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
|
||||
{ // Test searching functionality.
|
||||
nErrorCount += TestSetSearch<VS1, false>();
|
||||
nErrorCount += TestSetSearch<VS4, false>();
|
||||
|
||||
nErrorCount += TestSetSearch<VMS1, true>();
|
||||
nErrorCount += TestSetSearch<VMS4, true>();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// C++11 emplace and related functionality
|
||||
nErrorCount += TestSetCpp11<eastl::set<TestObject> >();
|
||||
|
||||
nErrorCount += TestMultisetCpp11<eastl::multiset<TestObject> >();
|
||||
}
|
||||
|
||||
|
||||
{ // Misc tests
|
||||
|
||||
// const key_compare& key_comp() const;
|
||||
// key_compare& key_comp();
|
||||
VS1 vs;
|
||||
const VS1 vsc;
|
||||
|
||||
const VS1::key_compare& kc = vsc.key_comp();
|
||||
vs.key_comp() = kc;
|
||||
}
|
||||
|
||||
{ // non-const comparator test
|
||||
struct my_less
|
||||
{
|
||||
bool operator()(int a, int b) { return a < b; }
|
||||
};
|
||||
|
||||
{
|
||||
set<int, my_less> a = {0, 1, 2, 3, 4};
|
||||
auto i = a.find(42);
|
||||
VERIFY(i == a.end());
|
||||
}
|
||||
}
|
||||
|
||||
{ // set erase_if tests
|
||||
set<int> s = {0, 1, 2, 3, 4};
|
||||
auto numErased = eastl::erase_if(s, [](auto i) { return i % 2 == 0;});
|
||||
VERIFY((s == set<int>{1,3}));
|
||||
VERIFY(numErased == 3);
|
||||
}
|
||||
|
||||
{ // multiset erase_if tests
|
||||
multiset<int> s = {0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3, 3, 4};
|
||||
auto numErased = eastl::erase_if(s, [](auto i) { return i % 2 == 0;});
|
||||
VERIFY((s == multiset<int>{1, 1, 1, 3, 3, 3}));
|
||||
VERIFY(numErased == 7);
|
||||
}
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
{ // Test set <=>
|
||||
set<int> s1 = {0, 1, 2, 3, 4};
|
||||
set<int> s2 = {4, 3, 2, 1, 0};
|
||||
set<int> s3 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
set<int> s4 = {1, 2, 3, 4, 5, 6};
|
||||
set<int> s5 = {9};
|
||||
|
||||
VERIFY(s1 == s2);
|
||||
VERIFY(s1 != s3);
|
||||
VERIFY(s3 > s4);
|
||||
VERIFY(s5 > s4);
|
||||
VERIFY(s5 > s3);
|
||||
|
||||
VERIFY((s1 <=> s2) == 0);
|
||||
VERIFY((s1 <=> s3) != 0);
|
||||
VERIFY((s3 <=> s4) > 0);
|
||||
VERIFY((s5 <=> s4) > 0);
|
||||
VERIFY((s5 <=> s3) > 0);
|
||||
}
|
||||
|
||||
{ // Test multiset <=>
|
||||
multiset<int> s1 = {0, 0, 0, 1, 1, 2, 3, 3, 4};
|
||||
multiset<int> s2 = {4, 3, 3, 2, 1, 1, 0, 0, 0};
|
||||
multiset<int> s3 = {1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 9};
|
||||
multiset<int> s4 = {1, 1, 2, 2, 3, 4, 5, 5, 6};
|
||||
multiset<int> s5 = {9};
|
||||
|
||||
VERIFY(s1 == s2);
|
||||
VERIFY(s1 != s3);
|
||||
VERIFY(s3 > s4);
|
||||
VERIFY(s5 > s4);
|
||||
VERIFY(s5 > s3);
|
||||
|
||||
VERIFY((s1 <=> s2) == 0);
|
||||
VERIFY((s1 <=> s3) != 0);
|
||||
VERIFY((s3 <=> s4) > 0);
|
||||
VERIFY((s5 <=> s4) > 0);
|
||||
VERIFY((s5 <=> s3) > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// user reported regression: ensure container elements are NOT
|
||||
// moved from during the eastl::set construction process.
|
||||
eastl::vector<xvalue_test> m1 = {{0}, {1}, {2}, {3}, {4}, {5}};
|
||||
eastl::set<xvalue_test> m2{m1.begin(), m1.end()};
|
||||
|
||||
bool result = eastl::all_of(m1.begin(), m1.end(),
|
||||
[&](auto& e) { return e.data != xvalue_test::MOVED_FROM; });
|
||||
|
||||
VERIFY(result);
|
||||
}
|
||||
|
||||
{
|
||||
// user reported regression: ensure container elements are moved from during the
|
||||
// eastl::set construction process when using an eastl::move_iterator.
|
||||
eastl::vector<xvalue_test> m1 = {{0}, {1}, {2}, {3}, {4}, {5}};
|
||||
eastl::set<xvalue_test> m2{eastl::make_move_iterator(m1.begin()), eastl::make_move_iterator(m1.end())};
|
||||
|
||||
bool result = eastl::all_of(m1.begin(), m1.end(),
|
||||
[&](auto& e) { return e.data == xvalue_test::MOVED_FROM; });
|
||||
|
||||
VERIFY(result);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,906 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/algorithm.h>
|
||||
#include <EASTL/type_traits.h>
|
||||
#include <EASTL/scoped_ptr.h>
|
||||
#include <EASTL/random.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <algorithm>
|
||||
#endif
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestSetConstruction
|
||||
//
|
||||
// This test compares eastl::set/multiset to std::set/multiset. It could possibly
|
||||
// work for comparing eastl::hash_set to C++11 std::unordered_set, but we would
|
||||
// rather move towards making this test be independent of any std comparisons.
|
||||
//
|
||||
// Requires a container that can hold at least 1000 items.
|
||||
//
|
||||
template <typename T1, typename T2, bool bMultiset>
|
||||
int TestSetConstruction()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
TestObject::Reset();
|
||||
|
||||
{
|
||||
eastl::scoped_ptr<T1> pt1A(new T1); // We use a pointers instead of concrete object because it's size may be huge.
|
||||
eastl::scoped_ptr<T2> pt2A(new T2);
|
||||
T1& t1A = *pt1A;
|
||||
T2& t2A = *pt2A;
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set ctor", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
VERIFY(t1A.validate());
|
||||
|
||||
|
||||
eastl::scoped_ptr<T1> pt1B(new T1);
|
||||
eastl::scoped_ptr<T2> pt2B(new T2);
|
||||
T1& t1B = *pt1B;
|
||||
T2& t2B = *pt2B;
|
||||
nErrorCount += CompareContainers(t1B, t2B, "Set ctor", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
eastl::scoped_ptr<T1> pt1C(new T1);
|
||||
eastl::scoped_ptr<T2> pt2C(new T2);
|
||||
T1& t1C = *pt1C;
|
||||
T2& t2C = *pt2C;
|
||||
for(int i = 0; i < 1000; i++)
|
||||
{
|
||||
t1C.insert(typename T1::value_type(typename T1::value_type(i)));
|
||||
t2C.insert(typename T2::value_type(typename T2::value_type(i)));
|
||||
VERIFY(t1C.validate());
|
||||
nErrorCount += CompareContainers(t1C, t2C, "Set insert", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
}
|
||||
|
||||
|
||||
eastl::scoped_ptr<T1> pt1D(new T1);
|
||||
eastl::scoped_ptr<T2> pt2D(new T2);
|
||||
T1& t1D = *pt1D;
|
||||
T2& t2D = *pt2D;
|
||||
nErrorCount += CompareContainers(t1D, t2D, "Set ctor", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
eastl::scoped_ptr<T1> pt1E(new T1(t1C));
|
||||
eastl::scoped_ptr<T2> pt2E(new T2(t2C));
|
||||
T1& t1E = *pt1E;
|
||||
T2& t2E = *pt2E;
|
||||
VERIFY(t1E.validate());
|
||||
nErrorCount += CompareContainers(t1E, t2E, "Set ctor", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
eastl::scoped_ptr<T1> pt1F(new T1(t1C.begin(), t1C.end()));
|
||||
eastl::scoped_ptr<T2> pt2F(new T2(t2C.begin(), t2C.end()));
|
||||
T1& t1F = *pt1F;
|
||||
T2& t2F = *pt2F;
|
||||
VERIFY(t1F.validate());
|
||||
nErrorCount += CompareContainers(t1F, t2F, "Set ctor", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
// operator=
|
||||
t1E = t1D;
|
||||
t2E = t2D;
|
||||
nErrorCount += CompareContainers(t1D, t2D, "Set operator=", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
nErrorCount += CompareContainers(t1E, t2E, "Set operator=", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
// operator=(set&&)
|
||||
// We test just the EASTL container here.
|
||||
eastl::scoped_ptr<T1> pT1P(new T1); // We use a pointers instead of concrete object because it's size may be huge.
|
||||
eastl::scoped_ptr<T1> pT1Q(new T1);
|
||||
T1& t1P = *pT1P;
|
||||
T1& t1Q = *pT1Q;
|
||||
|
||||
typename T1::value_type v10(0);
|
||||
typename T1::value_type v11(1);
|
||||
typename T1::value_type v12(2);
|
||||
typename T1::value_type v13(3);
|
||||
typename T1::value_type v14(4);
|
||||
typename T1::value_type v15(5);
|
||||
|
||||
t1P.insert(v10);
|
||||
t1P.insert(v11);
|
||||
t1P.insert(v12);
|
||||
|
||||
t1Q.insert(v13);
|
||||
t1Q.insert(v14);
|
||||
t1Q.insert(v15);
|
||||
|
||||
t1Q = eastl::move(t1P); // We are effectively requesting to swap t1A with t1B.
|
||||
//EATEST_VERIFY((t1P.size() == 3) && (t1P.find(v13) != t1P.end()) && (t1P.find(v14) != t1P.end()) && (t1P.find(v15) != t1P.end())); // Currently operator=(this_type&& x) clears x instead of swapping with it.
|
||||
|
||||
|
||||
// swap
|
||||
t1E.swap(t1D);
|
||||
t2E.swap(t2D);
|
||||
VERIFY(t1D.validate());
|
||||
VERIFY(t1E.validate());
|
||||
nErrorCount += CompareContainers(t1D, t2D, "Set swap", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
nErrorCount += CompareContainers(t1E, t2E, "Set swap", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
// eastl::swap
|
||||
eastl::swap(t1E, t1D);
|
||||
std::swap(t2E, t2D);
|
||||
VERIFY(t1D.validate());
|
||||
VERIFY(t1E.validate());
|
||||
nErrorCount += CompareContainers(t1D, t2D, "Global swap", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
nErrorCount += CompareContainers(t1E, t2E, "Global swap", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
// clear
|
||||
t1A.clear();
|
||||
t2A.clear();
|
||||
VERIFY(t1A.validate());
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set clear", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
t1B.clear();
|
||||
t2B.clear();
|
||||
VERIFY(t1B.validate());
|
||||
nErrorCount += CompareContainers(t1B, t2B, "Set clear", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
// global operators (==, !=, <, etc.)
|
||||
t1A.clear();
|
||||
t1B.clear();
|
||||
// Make t1A equal to t1B
|
||||
t1A.insert(typename T1::value_type(0));
|
||||
t1A.insert(typename T1::value_type(1));
|
||||
t1A.insert(typename T1::value_type(2));
|
||||
|
||||
t1B.insert(typename T1::value_type(0));
|
||||
t1B.insert(typename T1::value_type(1));
|
||||
t1B.insert(typename T1::value_type(2));
|
||||
|
||||
VERIFY( (t1A == t1B));
|
||||
VERIFY(!(t1A != t1B));
|
||||
VERIFY( (t1A <= t1B));
|
||||
VERIFY( (t1A >= t1B));
|
||||
VERIFY(!(t1A < t1B));
|
||||
VERIFY(!(t1A > t1B));
|
||||
// Make t1A less than t1B
|
||||
t1A.insert(typename T1::value_type(3));
|
||||
t1B.insert(typename T1::value_type(4));
|
||||
|
||||
VERIFY(!(t1A == t1B));
|
||||
VERIFY( (t1A != t1B));
|
||||
VERIFY( (t1A <= t1B));
|
||||
VERIFY(!(t1A >= t1B));
|
||||
VERIFY( (t1A < t1B));
|
||||
VERIFY(!(t1A > t1B));
|
||||
}
|
||||
|
||||
VERIFY(TestObject::IsClear());
|
||||
TestObject::Reset();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestSetMutation
|
||||
//
|
||||
// Requires a container that can hold at least 1000 items.
|
||||
//
|
||||
EA_DISABLE_VC_WARNING(6262)
|
||||
template <typename T1, typename T2, bool bMultiset>
|
||||
int TestSetMutation()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
TestObject::Reset();
|
||||
|
||||
{
|
||||
eastl::scoped_ptr<T1> pt1A(new T1); // We use a pointers instead of concrete object because it's size may be huge.
|
||||
eastl::scoped_ptr<T2> pt2A(new T2);
|
||||
T1& t1A = *pt1A;
|
||||
T2& t2A = *pt2A;
|
||||
int i, iEnd, p;
|
||||
|
||||
// Set up an array of values to randomize / permute.
|
||||
eastl::vector<typename T1::value_type> valueArrayInsert;
|
||||
|
||||
if(gEASTL_TestLevel >= kEASTL_TestLevelLow)
|
||||
{
|
||||
EASTLTest_Rand rng(EA::UnitTest::GetRandSeed());
|
||||
|
||||
valueArrayInsert.clear();
|
||||
|
||||
for(i = 0; i < 1000; i++)
|
||||
{
|
||||
valueArrayInsert.push_back(typename T1::value_type(i));
|
||||
|
||||
// Occasionally attempt to duplicate an element, both for set and multiset.
|
||||
if(((i + 1) < 1000) && (rng.RandLimit(4) == 0))
|
||||
{
|
||||
valueArrayInsert.push_back(typename T1::value_type(i));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
for(p = 0; p < gEASTL_TestLevel * 100; p++) // For each permutation...
|
||||
{
|
||||
eastl::random_shuffle(valueArrayInsert.begin(), valueArrayInsert.end(), rng);
|
||||
|
||||
// insert
|
||||
for(i = 0, iEnd = (int)valueArrayInsert.size(); i < iEnd; i++)
|
||||
{
|
||||
typename T1::value_type& k = valueArrayInsert[i];
|
||||
|
||||
t1A.insert(typename T1::value_type(k)); // We expect that both arguments are the same.
|
||||
t2A.insert(typename T2::value_type(k));
|
||||
|
||||
VERIFY(t1A.validate());
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set insert", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
}
|
||||
|
||||
|
||||
// reverse iteration
|
||||
typename T1::reverse_iterator r1 = t1A.rbegin();
|
||||
typename T2::reverse_iterator r2 = t2A.rbegin();
|
||||
|
||||
while(r1 != t1A.rend())
|
||||
{
|
||||
typename T1::value_type k1 = *r1;
|
||||
typename T2::value_type k2 = *r2;
|
||||
VERIFY(k1 == k2);
|
||||
}
|
||||
|
||||
|
||||
// erase
|
||||
for(i = 0, iEnd = (int)valueArrayInsert.size(); i < iEnd; i++)
|
||||
{
|
||||
typename T1::value_type& k = valueArrayInsert[i];
|
||||
|
||||
typename T1::size_type n1 = t1A.erase(k);
|
||||
typename T2::size_type n2 = t2A.erase(k);
|
||||
|
||||
VERIFY(n1 == n2);
|
||||
VERIFY(t1A.validate());
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set erase", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
}
|
||||
|
||||
VERIFY((TestObject::sTOCount == 0) || (TestObject::sTOCount == (int64_t)valueArrayInsert.size())); // This test will only have meaning when T1 contains TestObject.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VERIFY(TestObject::IsClear());
|
||||
TestObject::Reset();
|
||||
|
||||
|
||||
// Possibly do extended testing.
|
||||
if(gEASTL_TestLevel > 6)
|
||||
{
|
||||
valueArrayInsert.clear();
|
||||
|
||||
for(i = 0; i < 9; i++) // Much more than this count would take too long to test all permutations.
|
||||
valueArrayInsert.push_back(typename T1::value_type(i));
|
||||
|
||||
// Insert these values into the set in every existing permutation.
|
||||
for(p = 0; std::next_permutation(valueArrayInsert.begin(), valueArrayInsert.end()); p++) // For each permutation...
|
||||
{
|
||||
for(i = 0, iEnd = (int)valueArrayInsert.size(); i < iEnd; i++)
|
||||
{
|
||||
typename T1::value_type& k = valueArrayInsert[i];
|
||||
|
||||
t1A.insert(typename T1::value_type(k)); // We expect that both arguments are the same.
|
||||
t2A.insert(typename T2::value_type(k));
|
||||
|
||||
VERIFY(t1A.validate());
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set insert", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
}
|
||||
|
||||
for(i = 0, iEnd = (int)valueArrayInsert.size(); i < iEnd; i++)
|
||||
{
|
||||
typename T1::value_type& k = valueArrayInsert[i];
|
||||
|
||||
t1A.erase(k);
|
||||
t2A.erase(k);
|
||||
|
||||
VERIFY(t1A.validate());
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set erase", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
}
|
||||
|
||||
VERIFY((TestObject::sTOCount == 0) || (TestObject::sTOCount == (int64_t)valueArrayInsert.size())); // This test will only have meaning when T1 contains TestObject.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VERIFY(TestObject::IsClear());
|
||||
TestObject::Reset();
|
||||
|
||||
|
||||
{ // Other insert and erase operations
|
||||
|
||||
eastl::scoped_ptr<T1> pt1A(new T1); // We use a pointers instead of concrete object because it's size may be huge.
|
||||
eastl::scoped_ptr<T2> pt2A(new T2);
|
||||
T1& t1A = *pt1A;
|
||||
T2& t2A = *pt2A;
|
||||
int i;
|
||||
|
||||
// Set up an array of values to randomize / permute.
|
||||
eastl::vector<typename T1::value_type> valueArrayInsert1;
|
||||
eastl::vector<typename T2::value_type> valueArrayInsert2;
|
||||
|
||||
EASTLTest_Rand rng(EA::UnitTest::GetRandSeed());
|
||||
|
||||
for(i = 0; i < 100; i++)
|
||||
{
|
||||
valueArrayInsert1.push_back(typename T1::value_type(i));
|
||||
valueArrayInsert2.push_back(typename T2::value_type(i));
|
||||
|
||||
if(rng.RandLimit(3) == 0)
|
||||
{
|
||||
valueArrayInsert1.push_back(typename T1::value_type(i));
|
||||
valueArrayInsert2.push_back(typename T2::value_type(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// insert(InputIterator first, InputIterator last)
|
||||
t1A.insert(valueArrayInsert1.begin(), valueArrayInsert1.end());
|
||||
t2A.insert(valueArrayInsert2.begin(), valueArrayInsert2.end());
|
||||
VERIFY(t1A.validate());
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set insert", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
// iterator insert(iterator position, const value_type& value);
|
||||
//
|
||||
// If bMultiset == true, then the insertions below should fail due to the
|
||||
// item being present. But they should return the correct iterator value.
|
||||
typename T1::iterator it1 = t1A.insert(t1A.find(typename T1::value_type(2)), typename T1::value_type(1));
|
||||
typename T2::iterator it2 = t2A.insert(t2A.find(typename T2::value_type(2)), typename T2::value_type(1));
|
||||
VERIFY(t1A.validate());
|
||||
VERIFY(*it1 == typename T1::value_type(1));
|
||||
VERIFY(*it2 == typename T2::value_type(1));
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set insert", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
it1 = t1A.insert(t1A.end(), typename T1::value_type(5));
|
||||
it2 = t2A.insert(t2A.end(), typename T2::value_type(5));
|
||||
VERIFY(t1A.validate());
|
||||
VERIFY(*it1 == typename T1::value_type(5));
|
||||
VERIFY(*it2 == typename T2::value_type(5));
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set insert", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
// Now we remove these items so that the insertions above can succeed.
|
||||
t1A.erase(t1A.find(typename T1::value_type(1)));
|
||||
t2A.erase(t2A.find(typename T2::value_type(1)));
|
||||
it1 = t1A.insert(t1A.find(typename T1::value_type(2)), typename T1::value_type(1));
|
||||
it2 = t2A.insert(t2A.find(typename T2::value_type(2)), typename T2::value_type(1));
|
||||
VERIFY(t1A.validate());
|
||||
VERIFY(*it1 == typename T1::value_type(1));
|
||||
VERIFY(*it2 == typename T2::value_type(1));
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set insert", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
t1A.erase(t1A.find(typename T1::value_type(5)));
|
||||
t2A.erase(t2A.find(typename T2::value_type(5)));
|
||||
it1 = t1A.insert(t1A.end(), typename T1::value_type(5));
|
||||
it2 = t2A.insert(t2A.end(), typename T2::value_type(5));
|
||||
VERIFY(t1A.validate());
|
||||
VERIFY(*it1 == typename T1::value_type(5));
|
||||
VERIFY(*it2 == typename T2::value_type(5));
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set insert", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
// iterator erase(iterator first, iterator last);
|
||||
typename T1::iterator it11 = t1A.find(typename T1::value_type(17));
|
||||
typename T1::iterator it12 = t1A.find(typename T2::value_type(37));
|
||||
t1A.erase(it11, it12);
|
||||
|
||||
typename T2::iterator it21 = t2A.find(typename T1::value_type(17));
|
||||
typename T2::iterator it22 = t2A.find(typename T2::value_type(37));
|
||||
t2A.erase(it21, it22);
|
||||
|
||||
VERIFY(t1A.validate());
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set erase(first, last)", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
// iterator erase(iterator position);
|
||||
t1A.erase(t1A.find(typename T1::value_type(60)));
|
||||
t2A.erase(t2A.find(typename T1::value_type(60)));
|
||||
VERIFY(t1A.validate());
|
||||
nErrorCount += CompareContainers(t1A, t2A, "Set erase(first, last)", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
|
||||
|
||||
// Disabled because this function isn't exposed outside the rbtree yet.
|
||||
// void erase(const value_type* first, const value_type* last);
|
||||
//typename T1::value_type keyArray1[3] = { typename T1::value_type(70), typename T1::value_type(71), typename T1::value_type(72) };
|
||||
//typename T2::value_type keyArray2[3] = { typename T2::value_type(70), typename T2::value_type(71), typename T2::value_type(72) };
|
||||
//t1A.erase(keyArray1 + 0, keyArray1 + 3);
|
||||
//t2A.erase(keyArray2 + 0, keyArray2 + 3);
|
||||
//VERIFY(t1A.validate());
|
||||
//nErrorCount += CompareContainers(t1A, t2A, "Set erase(first, last)", eastl::use_self<typename T1::value_type>(), eastl::use_self<typename T2::value_type>());
|
||||
}
|
||||
|
||||
{
|
||||
// set(std::initializer_list<value_type> ilist, const Compare& compare = Compare(), const allocator_type& allocator = EASTL_MAP_DEFAULT_ALLOCATOR);
|
||||
// this_type& operator=(std::initializer_list<T> ilist);
|
||||
// void insert(std::initializer_list<value_type> ilist);
|
||||
#if !defined(EA_COMPILER_NO_INITIALIZER_LISTS)
|
||||
T1 mySet = { typename T1::value_type(10), typename T1::value_type(11) };
|
||||
EATEST_VERIFY(mySet.size() == 2);
|
||||
typename T1::iterator it = mySet.begin();
|
||||
EATEST_VERIFY(*it == typename T1::value_type(10));
|
||||
it = mySet.rbegin().base();
|
||||
EATEST_VERIFY(*--it == typename T1::value_type(11));
|
||||
|
||||
mySet = {typename T1::value_type(20), typename T1::value_type(21) };
|
||||
EATEST_VERIFY(mySet.size() == 2);
|
||||
EATEST_VERIFY(*mySet.begin() == typename T1::value_type(20));
|
||||
it = mySet.rbegin().base();
|
||||
EATEST_VERIFY(*--it == typename T1::value_type(21));
|
||||
|
||||
mySet.insert({ typename T1::value_type(40), typename T1::value_type(41) });
|
||||
EATEST_VERIFY(mySet.size() == 4);
|
||||
it = mySet.rbegin().base();
|
||||
EATEST_VERIFY(*--it == typename T1::value_type(41));
|
||||
#endif
|
||||
}
|
||||
|
||||
VERIFY(TestObject::IsClear());
|
||||
TestObject::Reset();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
|
||||
#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename T1>
|
||||
int TestSetSpecific(T1& /*t1A*/, eastl::false_type) // false_type means this is a map and not a multimap.
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template <typename T1>
|
||||
int TestSetSpecific(T1& t1A, eastl::true_type) // true_type means this is a multimap and not a map.
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// equal_range_small (multiset only)
|
||||
eastl::pair<typename T1::iterator, typename T1::iterator> er = t1A.equal_range_small(typename T1::value_type(499));
|
||||
VERIFY(*er.first == typename T1::value_type(499));
|
||||
VERIFY(*er.second == typename T1::value_type(501));
|
||||
|
||||
er = t1A.equal_range_small(typename T1::value_type(-1));
|
||||
VERIFY(er.first == er.second);
|
||||
VERIFY(er.first == t1A.begin());
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
// Just for the purposes of the map::find_as test below, we declare the following.
|
||||
// The map::find_as function searches a container of X for a type Y, where the user
|
||||
// defines the equality of X to Y. The purpose of TSetComparable is to be a generic type Y
|
||||
// that can be used for any X. We need to make this generic because the whole TestMapSearch
|
||||
// function below is templated on type T1 and so we don't know what T1 is ahead of time.
|
||||
|
||||
template <typename T>
|
||||
struct TSetComparable
|
||||
{
|
||||
T b;
|
||||
|
||||
TSetComparable() : b() { }
|
||||
TSetComparable(const T& a) : b(a){ }
|
||||
const TSetComparable& operator=(const T& a) { b = a; return *this; }
|
||||
const TSetComparable& operator=(const TSetComparable& x) { b = x.b; return *this; }
|
||||
operator const T&() const { return b; }
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestSetSearch
|
||||
//
|
||||
// This function is designed to work with set, fixed_set (and not hash containers).
|
||||
// Requires a container that can hold at least 1000 items.
|
||||
//
|
||||
template <typename T1, bool bMultimap>
|
||||
int TestSetSearch()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
TestObject::Reset();
|
||||
|
||||
{ // Test find, lower_bound, upper_bound, etc..
|
||||
eastl::scoped_ptr<T1> pt1A(new T1); // We use a pointers instead of concrete object because it's size may be huge.
|
||||
T1& t1A = *pt1A;
|
||||
int i, iEnd;
|
||||
typename T1::iterator it;
|
||||
|
||||
// Set up an array of values to randomize / permute.
|
||||
eastl::vector<typename T1::value_type> valueArrayInsert;
|
||||
|
||||
for(i = 0; i < 1000; i++)
|
||||
valueArrayInsert.push_back(typename T1::value_type(i));
|
||||
|
||||
EASTLTest_Rand rng(EA::UnitTest::GetRandSeed());
|
||||
eastl::random_shuffle(valueArrayInsert.begin(), valueArrayInsert.end(), rng);
|
||||
|
||||
|
||||
// insert
|
||||
for(i = 0, iEnd = (int)valueArrayInsert.size(); i < iEnd; i++)
|
||||
{
|
||||
typename T1::value_type k(i);
|
||||
t1A.insert(typename T1::value_type(k));
|
||||
|
||||
it = t1A.find(k);
|
||||
VERIFY(it != t1A.end());
|
||||
}
|
||||
|
||||
|
||||
// find
|
||||
for(i = 0; i < 1000; i++)
|
||||
{
|
||||
typename T1::value_type k(i);
|
||||
it = t1A.find(k);
|
||||
|
||||
VERIFY(it != t1A.end());
|
||||
VERIFY(*it == k);
|
||||
}
|
||||
|
||||
it = t1A.find(typename T1::value_type(-1));
|
||||
VERIFY(it == t1A.end());
|
||||
|
||||
it = t1A.find(typename T1::value_type(1001));
|
||||
VERIFY(it == t1A.end());
|
||||
|
||||
|
||||
// find_as
|
||||
typedef TSetComparable<typename T1::key_type> TC;
|
||||
|
||||
// Normally we use find_as to find via a different type, but we can test it here like this.
|
||||
for(i = 0; i < 1000; i++)
|
||||
{
|
||||
TC k = typename T1::key_type(i);
|
||||
it = t1A.find_as(k, eastl::less_2<typename T1::key_type, TC>());
|
||||
|
||||
VERIFY(it != t1A.end());
|
||||
VERIFY(*it == k);
|
||||
}
|
||||
|
||||
it = t1A.find_as(TC(typename T1::key_type(-1)), eastl::less_2<typename T1::key_type, TC>());
|
||||
VERIFY(it == t1A.end());
|
||||
|
||||
it = t1A.find_as(TC(typename T1::key_type(1001)), eastl::less_2<typename T1::key_type, TC>());
|
||||
VERIFY(it == t1A.end());
|
||||
|
||||
|
||||
// lower_bound
|
||||
it = t1A.lower_bound(typename T1::value_type(0));
|
||||
VERIFY(it == t1A.begin());
|
||||
|
||||
it = t1A.lower_bound(typename T1::value_type(-1));
|
||||
VERIFY(it == t1A.begin());
|
||||
|
||||
it = t1A.lower_bound(typename T1::value_type(1001));
|
||||
VERIFY(it == t1A.end());
|
||||
|
||||
t1A.erase(typename T1::value_type(500));
|
||||
it = t1A.lower_bound(typename T1::value_type(500));
|
||||
VERIFY(*it == typename T1::value_type(501));
|
||||
|
||||
|
||||
// upper_bound
|
||||
it = t1A.upper_bound(typename T1::value_type(-1));
|
||||
VERIFY(it == t1A.begin());
|
||||
|
||||
it = t1A.upper_bound(typename T1::value_type(499));
|
||||
VERIFY(*it == typename T1::value_type(501));
|
||||
|
||||
it = t1A.upper_bound(typename T1::value_type(-1));
|
||||
VERIFY(*it == typename T1::value_type(0));
|
||||
|
||||
it = t1A.upper_bound(typename T1::value_type(1000));
|
||||
VERIFY(it == t1A.end());
|
||||
|
||||
|
||||
// count
|
||||
typename T1::size_type n = t1A.count(typename T1::value_type(-1));
|
||||
VERIFY(n == 0);
|
||||
|
||||
n = t1A.count(typename T1::value_type(0));
|
||||
VERIFY(n == 1);
|
||||
|
||||
n = t1A.count(typename T1::value_type(500)); // We removed 500 above.
|
||||
VERIFY(n == 0);
|
||||
|
||||
n = t1A.count(typename T1::value_type(1001));
|
||||
VERIFY(n == 0);
|
||||
|
||||
|
||||
// equal_range
|
||||
eastl::pair<typename T1::iterator, typename T1::iterator> er = t1A.equal_range(typename T1::value_type(200));
|
||||
VERIFY(*er.first == typename T1::value_type(200));
|
||||
|
||||
er = t1A.equal_range(typename T1::value_type(499));
|
||||
VERIFY(*er.first == typename T1::value_type(499));
|
||||
VERIFY(*er.second == typename T1::value_type(501));
|
||||
|
||||
er = t1A.equal_range(typename T1::value_type(-1));
|
||||
VERIFY(er.first == er.second);
|
||||
VERIFY(er.first == t1A.begin());
|
||||
|
||||
|
||||
// Some tests need to be differently between map and multimap.
|
||||
nErrorCount += TestSetSpecific(t1A, eastl::integral_constant<bool, bMultimap>());
|
||||
}
|
||||
|
||||
VERIFY(TestObject::IsClear());
|
||||
TestObject::Reset();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestSetCpp11
|
||||
//
|
||||
// This function is designed to work with set, fixed_set, hash_set, fixed_hash_set
|
||||
//
|
||||
template <typename T1>
|
||||
int TestSetCpp11()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// template <class... Args>
|
||||
// insert_return_type emplace(Args&&... args);
|
||||
//
|
||||
// template <class... Args>
|
||||
// iterator emplace_hint(const_iterator position, Args&&... args);
|
||||
//
|
||||
// insert_return_type insert(value_type&& value);
|
||||
// iterator insert(const_iterator position, value_type&& value);
|
||||
TestObject::Reset();
|
||||
|
||||
typedef T1 TOSet;
|
||||
typename TOSet::insert_return_type toSetInsertResult;
|
||||
typename TOSet::iterator toSetIterator;
|
||||
|
||||
TOSet toSet;
|
||||
TestObject to0(0);
|
||||
TestObject to1(1);
|
||||
|
||||
toSetInsertResult = toSet.emplace(to0);
|
||||
EATEST_VERIFY(toSetInsertResult.second == true);
|
||||
//EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support.
|
||||
|
||||
toSetInsertResult = toSet.emplace(eastl::move(to1));
|
||||
EATEST_VERIFY(toSetInsertResult.second == true);
|
||||
|
||||
// insert_return_type t1A.emplace(value_type&& value);
|
||||
TestObject to40(4);
|
||||
EATEST_VERIFY(toSet.find(to40) == toSet.end());
|
||||
EATEST_VERIFY(to40.mX == 4); // It should change to 0 below during the move swap.
|
||||
toSetInsertResult = toSet.emplace(eastl::move(to40));
|
||||
EATEST_VERIFY(toSetInsertResult.second == true);
|
||||
EATEST_VERIFY(toSet.find(to40) != toSet.end());
|
||||
EATEST_VERIFY(to40.mX == 0);
|
||||
|
||||
TestObject to41(4);
|
||||
toSetInsertResult = toSet.emplace(eastl::move(to41));
|
||||
EATEST_VERIFY(toSetInsertResult.second == false);
|
||||
EATEST_VERIFY(toSet.find(to41) != toSet.end());
|
||||
|
||||
// iterator t1A.emplace_hint(const_iterator position, value_type&& value);
|
||||
TestObject to50(5);
|
||||
toSetInsertResult = toSet.emplace(eastl::move(to50));
|
||||
EATEST_VERIFY(toSetInsertResult.second == true);
|
||||
EATEST_VERIFY(toSet.find(to50) != toSet.end());
|
||||
|
||||
TestObject to51(5);
|
||||
toSetIterator = toSet.emplace_hint(toSetInsertResult.first, eastl::move(to51));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(5));
|
||||
EATEST_VERIFY(toSet.find(to51) != toSet.end());
|
||||
|
||||
TestObject to6(6);
|
||||
toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to6)); // specify a bad hint. Insertion should still work.
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(6));
|
||||
EATEST_VERIFY(toSet.find(to6) != toSet.end());
|
||||
|
||||
TestObject to2(2);
|
||||
EATEST_VERIFY(toSet.find(to2) == toSet.end());
|
||||
toSetInsertResult = toSet.emplace(to2);
|
||||
EATEST_VERIFY(toSetInsertResult.second == true);
|
||||
EATEST_VERIFY(toSet.find(to2) != toSet.end());
|
||||
toSetInsertResult = toSet.emplace(to2);
|
||||
EATEST_VERIFY(toSetInsertResult.second == false);
|
||||
EATEST_VERIFY(toSet.find(to2) != toSet.end());
|
||||
|
||||
// iterator t1A.emplace_hint(const_iterator position, const value_type& value);
|
||||
TestObject to70(7);
|
||||
toSetInsertResult = toSet.emplace(to70);
|
||||
EATEST_VERIFY(toSetInsertResult.second == true);
|
||||
EATEST_VERIFY(toSet.find(to70) != toSet.end());
|
||||
|
||||
TestObject to71(7);
|
||||
toSetIterator = toSet.emplace_hint(toSetInsertResult.first, to71);
|
||||
EATEST_VERIFY(*toSetIterator == to71);
|
||||
EATEST_VERIFY(toSet.find(to71) != toSet.end());
|
||||
|
||||
TestObject to8(8);
|
||||
toSetIterator = toSet.emplace_hint(toSet.begin(), to8); // specify a bad hint. Insertion should still work.
|
||||
EATEST_VERIFY(*toSetIterator == to8);
|
||||
EATEST_VERIFY(toSet.find(to8) != toSet.end());
|
||||
|
||||
//pair<iterator,bool> t1A.insert(value_type&& value);
|
||||
TestObject to3(3);
|
||||
EATEST_VERIFY(toSet.find(to3) == toSet.end());
|
||||
toSetInsertResult = toSet.insert(TestObject(to3));
|
||||
EATEST_VERIFY(toSetInsertResult.second == true);
|
||||
EATEST_VERIFY(toSet.find(to3) != toSet.end());
|
||||
toSetInsertResult = toSet.insert(TestObject(to3));
|
||||
EATEST_VERIFY(toSetInsertResult.second == false);
|
||||
EATEST_VERIFY(toSet.find(to3) != toSet.end());
|
||||
|
||||
|
||||
// iterator t1A.insert(const_iterator position, value_type&& value);
|
||||
TestObject to90(9);
|
||||
toSetInsertResult = toSet.emplace(eastl::move(to90));
|
||||
EATEST_VERIFY(toSetInsertResult.second == true);
|
||||
EATEST_VERIFY(toSet.find(to90) != toSet.end());
|
||||
|
||||
TestObject to91(9);
|
||||
toSetIterator = toSet.emplace_hint(toSetInsertResult.first, eastl::move(to91));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(9));
|
||||
EATEST_VERIFY(toSet.find(to91) != toSet.end());
|
||||
|
||||
TestObject to10(10);
|
||||
toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to10)); // specify a bad hint. Insertion should still work.
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(10));
|
||||
EATEST_VERIFY(toSet.find(to10) != toSet.end());
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestMultisetCpp11
|
||||
//
|
||||
// This function is designed to work with multiset, fixed_multiset, hash_multiset, fixed_hash_multiset
|
||||
//
|
||||
// This is similar to the TestSetCpp11 function, with some differences related
|
||||
// to handling of duplicate entries.
|
||||
//
|
||||
template <typename T1>
|
||||
int TestMultisetCpp11()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// template <class... Args>
|
||||
// insert_return_type emplace(Args&&... args);
|
||||
//
|
||||
// template <class... Args>
|
||||
// iterator emplace_hint(const_iterator position, Args&&... args);
|
||||
//
|
||||
// insert_return_type insert(value_type&& value);
|
||||
// iterator insert(const_iterator position, value_type&& value);
|
||||
TestObject::Reset();
|
||||
|
||||
typedef T1 TOSet;
|
||||
typename TOSet::iterator toSetIterator;
|
||||
|
||||
TOSet toSet;
|
||||
TestObject to0(0);
|
||||
TestObject to1(1);
|
||||
|
||||
toSetIterator = toSet.emplace(to0);
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(0));
|
||||
//EATEST_VERIFY((TestObject::sTOCopyCtorCount == 2) && (TestObject::sTOMoveCtorCount == 1)); // Disabled until we can guarantee its behavior and deal with how it's different between compilers of differing C++11 support.
|
||||
|
||||
toSetIterator = toSet.emplace(eastl::move(to1));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(1));
|
||||
|
||||
// insert_return_type t1A.emplace(value_type&& value);
|
||||
TestObject to40(4);
|
||||
EATEST_VERIFY(toSet.find(to40) == toSet.end());
|
||||
EATEST_VERIFY(to40.mX == 4); // It should change to 0 below during the move swap.
|
||||
toSetIterator = toSet.emplace(eastl::move(to40));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(4));
|
||||
EATEST_VERIFY(toSet.find(to40) != toSet.end());
|
||||
EATEST_VERIFY(to40.mX == 0);
|
||||
|
||||
TestObject to41(4);
|
||||
toSetIterator = toSet.emplace(eastl::move(to41)); // multiset can insert another of these.
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(4));
|
||||
EATEST_VERIFY(toSet.find(to41) != toSet.end());
|
||||
|
||||
// iterator t1A.emplace_hint(const_iterator position, value_type&& value);
|
||||
TestObject to50(5);
|
||||
toSetIterator = toSet.emplace(eastl::move(to50));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(5));
|
||||
EATEST_VERIFY(toSet.find(to50) != toSet.end());
|
||||
|
||||
TestObject to51(5);
|
||||
toSetIterator = toSet.emplace_hint(toSetIterator, eastl::move(to51));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(5));
|
||||
EATEST_VERIFY(toSet.find(to51) != toSet.end());
|
||||
|
||||
TestObject to6(6);
|
||||
toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to6)); // specify a bad hint. Insertion should still work.
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(6));
|
||||
EATEST_VERIFY(toSet.find(to6) != toSet.end());
|
||||
|
||||
TestObject to2(2);
|
||||
EATEST_VERIFY(toSet.find(to2) == toSet.end());
|
||||
toSetIterator = toSet.emplace(to2);
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(2));
|
||||
EATEST_VERIFY(toSet.find(to2) != toSet.end());
|
||||
toSetIterator = toSet.emplace(to2);
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(2));
|
||||
EATEST_VERIFY(toSet.find(to2) != toSet.end());
|
||||
|
||||
// iterator t1A.emplace_hint(const_iterator position, const value_type& value);
|
||||
TestObject to70(7);
|
||||
toSetIterator = toSet.emplace(to70);
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(7));
|
||||
EATEST_VERIFY(toSet.find(to70) != toSet.end());
|
||||
|
||||
TestObject to71(7);
|
||||
toSetIterator = toSet.emplace_hint(toSetIterator, to71);
|
||||
EATEST_VERIFY(*toSetIterator == to71);
|
||||
EATEST_VERIFY(toSet.find(to71) != toSet.end());
|
||||
|
||||
TestObject to8(8);
|
||||
toSetIterator = toSet.emplace_hint(toSet.begin(), to8); // specify a bad hint. Insertion should still work.
|
||||
EATEST_VERIFY(*toSetIterator == to8);
|
||||
EATEST_VERIFY(toSet.find(to8) != toSet.end());
|
||||
|
||||
// insert_return_type t1A.insert(value_type&& value);
|
||||
TestObject to3(3);
|
||||
EATEST_VERIFY(toSet.find(to3) == toSet.end());
|
||||
toSetIterator = toSet.insert(TestObject(to3));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(3));
|
||||
EATEST_VERIFY(toSet.find(to3) != toSet.end());
|
||||
toSetIterator = toSet.insert(TestObject(to3));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(3));
|
||||
EATEST_VERIFY(toSet.find(to3) != toSet.end());
|
||||
|
||||
// iterator t1A.insert(const_iterator position, value_type&& value);
|
||||
TestObject to90(9);
|
||||
toSetIterator = toSet.emplace(eastl::move(to90));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(9));
|
||||
EATEST_VERIFY(toSet.find(to90) != toSet.end());
|
||||
|
||||
TestObject to91(9);
|
||||
toSetIterator = toSet.emplace_hint(toSetIterator, eastl::move(to91));
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(9));
|
||||
EATEST_VERIFY(toSet.find(to91) != toSet.end());
|
||||
|
||||
TestObject to10(10);
|
||||
toSetIterator = toSet.emplace_hint(toSet.begin(), eastl::move(to10)); // specify a bad hint. Insertion should still work.
|
||||
EATEST_VERIFY(*toSetIterator == TestObject(10));
|
||||
EATEST_VERIFY(toSet.find(to10) != toSet.end());
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,961 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
// Some versions of GCC generate an array bounds warning in opt builds which
|
||||
// doesn't say what line below it comes from and doesn't appear to be a valid
|
||||
// warning. In researching this on the Internet it appears that this is a
|
||||
// known problem with GCC.
|
||||
#if defined(EA_DISABLE_GCC_WARNING)
|
||||
EA_DISABLE_GCC_WARNING(-Warray-bounds)
|
||||
#endif
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/sort.h>
|
||||
#include <EASTL/bonus/sort_extra.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/list.h>
|
||||
#include <EASTL/deque.h>
|
||||
#include <EASTL/algorithm.h>
|
||||
#include <EASTL/allocator.h>
|
||||
#include <EASTL/numeric.h>
|
||||
#include <EASTL/random.h>
|
||||
#include <EABase/eahave.h>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
typedef eastl::vector<int> IntArray;
|
||||
typedef eastl::vector<IntArray> IntArrayArray;
|
||||
|
||||
|
||||
// IntArrayCompare
|
||||
// Used to compare IntArray objects.
|
||||
struct IntArrayCompare
|
||||
{
|
||||
bool operator()(const IntArray& a, const IntArray& b)
|
||||
{ return a.front() < b.front(); }
|
||||
};
|
||||
|
||||
|
||||
// SafeFloatCompare
|
||||
//
|
||||
// Float comparison has a problem for the case that either of the floats are a NaN.
|
||||
// If you use a NaN in a sort function that uses default floating point comparison then
|
||||
// you will get undefined behavior, as all NaNs compare false. This compare function
|
||||
// class sorts floats such that all negative NaNs sort lower than all integers, and all
|
||||
// positive NaNs sort higher than all integers.
|
||||
//
|
||||
// Example usage:
|
||||
// eastl::sort(floatArray.begin(), floatArray.end(), SafeFloatCompare());
|
||||
//
|
||||
struct SafeFloatCompare
|
||||
{
|
||||
union FloatInt32{ float f; int32_t i; };
|
||||
|
||||
bool operator()(float a, float b) const
|
||||
{
|
||||
#if defined(EA_HAVE_ISNAN)
|
||||
bool aNan = (EA_HAVE_ISNAN(a) != 0);
|
||||
bool bNan = (EA_HAVE_ISNAN(b) != 0);
|
||||
#else
|
||||
bool aNan = (a != a); // This works as long as the compiler doesn't do any tricks to optimize it away.
|
||||
bool bNan = (b != b);
|
||||
#endif
|
||||
|
||||
if(!aNan && !bNan)
|
||||
return (a < b);
|
||||
|
||||
FloatInt32 fia = { a };
|
||||
FloatInt32 fib = { b };
|
||||
|
||||
if(aNan)
|
||||
{
|
||||
if(bNan)
|
||||
return (fia.i < fib.i); // Both are NaNs, so do a binary compare.
|
||||
else
|
||||
return (fia.i < 0); // All negative NaNs are assumed to be less than all non-NaNs.
|
||||
}
|
||||
else
|
||||
return (0 < fib.i); // All negative NaNs are assumed to be less than all non-NaNs.
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// StatefulCompare
|
||||
// Used to verify that sort<int, StatefulCompare&>() respects the
|
||||
// fact that StatefulCompare is passed by reference instead of by value.
|
||||
// All existing commercial STL implementations fail to do what the user
|
||||
// wants and instead pass around the compare object by value, even if
|
||||
// the user specifically asks to use it by reference. EASTL doesn't
|
||||
// have this problem.
|
||||
struct StatefulCompare
|
||||
{
|
||||
static int nCtorCount;
|
||||
static int nDtorCount;
|
||||
static int nCopyCount;
|
||||
|
||||
StatefulCompare()
|
||||
{ nCtorCount++; }
|
||||
|
||||
StatefulCompare(StatefulCompare&)
|
||||
{ nCopyCount++; }
|
||||
|
||||
~StatefulCompare()
|
||||
{ nDtorCount++; }
|
||||
|
||||
StatefulCompare& operator=(const StatefulCompare&)
|
||||
{ nCopyCount++; return *this; }
|
||||
|
||||
bool operator()(int a, int b)
|
||||
{ return a < b; }
|
||||
|
||||
static void Reset()
|
||||
{ nCtorCount = 0; nDtorCount = 0; nCopyCount = 0; }
|
||||
};
|
||||
|
||||
int StatefulCompare::nCtorCount = 0;
|
||||
int StatefulCompare::nDtorCount = 0;
|
||||
int StatefulCompare::nCopyCount = 0;
|
||||
|
||||
|
||||
// TestObjectPtrCompare
|
||||
// Used to compare sorted objects by pointer instead of value.
|
||||
struct TestObjectPtrCompare
|
||||
{
|
||||
bool operator()(TestObject* a, TestObject* b)
|
||||
{ return a->mX < b->mX; }
|
||||
};
|
||||
|
||||
|
||||
// TestObjectIndexCompare
|
||||
// Used to compare sorted objects by array index instead of value.
|
||||
struct TestObjectIndexCompare
|
||||
{
|
||||
vector<TestObject>* mpArray;
|
||||
|
||||
TestObjectIndexCompare(vector<TestObject>* pArray) : mpArray(pArray) { }
|
||||
TestObjectIndexCompare(const TestObjectIndexCompare& x) : mpArray(x.mpArray){ }
|
||||
TestObjectIndexCompare& operator=(const TestObjectIndexCompare& x) { mpArray = x.mpArray; return *this; }
|
||||
|
||||
bool operator()(eastl_size_t a, eastl_size_t b)
|
||||
{ return (*mpArray)[a] < (*mpArray)[b]; }
|
||||
};
|
||||
|
||||
// Radix sort elements
|
||||
template <typename Key>
|
||||
struct RadixSortElement
|
||||
{
|
||||
typedef Key radix_type;
|
||||
Key mKey;
|
||||
uint16_t mData;
|
||||
|
||||
bool operator<(const RadixSortElement<Key> &other) const
|
||||
{
|
||||
return mKey < other.mKey;
|
||||
}
|
||||
};
|
||||
|
||||
typedef RadixSortElement<uint8_t> RadixSortElement8;
|
||||
typedef RadixSortElement<uint16_t> RadixSortElement16;
|
||||
typedef RadixSortElement<uint32_t> RadixSortElement32;
|
||||
|
||||
template <typename integer_type>
|
||||
struct identity_extract_radix_key
|
||||
{
|
||||
typedef integer_type radix_type;
|
||||
|
||||
const radix_type operator()(const integer_type& x) const
|
||||
{
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
struct TestNoLessOperator
|
||||
{
|
||||
int i {};
|
||||
};
|
||||
} // namespace Internal
|
||||
|
||||
template <>
|
||||
struct less<Internal::TestNoLessOperator>
|
||||
{
|
||||
bool operator()(const Internal::TestNoLessOperator& lhs, const Internal::TestNoLessOperator& rhs) const noexcept
|
||||
{
|
||||
return lhs.i < rhs.i;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
int TestSort()
|
||||
{
|
||||
using namespace eastl;
|
||||
using namespace Internal;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
EASTLTest_Rand rng(EA::UnitTest::GetRandSeed());
|
||||
|
||||
{
|
||||
// is_sorted
|
||||
int array[] = { 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 9, 8, 7, 6, 5, 4, 3, 2, 2, 2, 1, 0 };
|
||||
|
||||
EATEST_VERIFY( is_sorted(array + 0, array + 0));
|
||||
EATEST_VERIFY( is_sorted(array + 2, array + 4));
|
||||
EATEST_VERIFY( is_sorted(array + 0, array + 10));
|
||||
EATEST_VERIFY(!is_sorted(array + 0, array + 14));
|
||||
EATEST_VERIFY( is_sorted(array + 11, array + 23, eastl::greater<int>()));
|
||||
}
|
||||
|
||||
{
|
||||
// is_sorted_until
|
||||
int sorted[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
int notsorted[] = { 0, 1, 2, 3, 4, 42, 6, 7, 8, 9 };
|
||||
|
||||
EATEST_VERIFY( is_sorted_until(sorted + EAArrayCount(sorted), sorted + EAArrayCount(sorted)) == sorted + EAArrayCount(sorted) );
|
||||
EATEST_VERIFY( is_sorted_until(sorted , sorted + EAArrayCount(sorted)) == sorted + EAArrayCount(sorted) );
|
||||
|
||||
EATEST_VERIFY( is_sorted_until(sorted + 0, sorted + 0) == sorted );
|
||||
EATEST_VERIFY( is_sorted_until(sorted + 2, sorted + 8) == sorted + 8 );
|
||||
|
||||
EATEST_VERIFY( is_sorted_until(notsorted + 2, notsorted + 8) == notsorted + 6 );
|
||||
|
||||
// is_sorted_until (with compare function)
|
||||
EATEST_VERIFY( is_sorted_until(sorted + EAArrayCount(sorted), sorted + EAArrayCount(sorted), eastl::less<int>()) == sorted + EAArrayCount(sorted) );
|
||||
EATEST_VERIFY( is_sorted_until(notsorted + 2, notsorted + 8, eastl::less<int>()) == notsorted + 6 );
|
||||
}
|
||||
|
||||
// Sort arrays of size 0 - N. Sort M random permutations of each.
|
||||
{
|
||||
vector<int64_t> intArray, intArraySaved;
|
||||
|
||||
for(int i = 0; i < (150 + (gEASTL_TestLevel * 200)); i += (i < 5) ? 1 : 37) // array sizes of 0 to 300 - 2100, depending on test level.
|
||||
{
|
||||
// intArraySaved.clear(); // Do we want to do this?
|
||||
|
||||
for(int n = 0; n < i; n++)
|
||||
{
|
||||
intArraySaved.push_back(n);
|
||||
|
||||
if(rng.RandLimit(10) == 0)
|
||||
{
|
||||
intArraySaved.push_back(n);
|
||||
|
||||
if(rng.RandLimit(5) == 0)
|
||||
intArraySaved.push_back(n);
|
||||
}
|
||||
}
|
||||
const int64_t expectedSum = eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0));
|
||||
|
||||
for(int j = 0; j < 300 + (gEASTL_TestLevel * 50); j++)
|
||||
{
|
||||
eastl::random_shuffle(intArraySaved.begin(), intArraySaved.end(), rng);
|
||||
|
||||
intArray = intArraySaved;
|
||||
bubble_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
shaker_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
insertion_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
selection_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
shell_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
comb_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
heap_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
merge_sort(intArray.begin(), intArray.end(), *get_default_allocator((EASTLAllocatorType*)NULL));
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
vector<int64_t> buffer(intArray.size());
|
||||
merge_sort_buffer(intArray.begin(), intArray.end(), buffer.data());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
quick_sort(intArray.begin(), intArray.end());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
|
||||
intArray = intArraySaved;
|
||||
buffer.resize(intArray.size()/2);
|
||||
tim_sort_buffer(intArray.begin(), intArray.end(), buffer.data());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
EATEST_VERIFY(eastl::accumulate(begin(intArraySaved), end(intArraySaved), int64_t(0)) == expectedSum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test tim sort with a specific array size and seed that caused a crash
|
||||
{
|
||||
vector<int64_t> intArray;
|
||||
int i = 1000000;
|
||||
{
|
||||
EASTLTest_Rand testRng(232526);
|
||||
|
||||
for (int n = 0; n < i; n++)
|
||||
{
|
||||
intArray.push_back(testRng.Rand());
|
||||
}
|
||||
vector<int64_t> buffer(intArray.size() / 2);
|
||||
tim_sort_buffer(intArray.begin(), intArray.end(), buffer.data());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
}
|
||||
}
|
||||
|
||||
// Test insertion_sort() does not invalidate a BidirectionalIterator by doing --BidirectionalIterator.begin()
|
||||
{
|
||||
// Test Passes if the Test doesn't crash
|
||||
eastl::deque<int> deque;
|
||||
deque.push_back(1);
|
||||
|
||||
insertion_sort(deque.begin(), deque.end());
|
||||
|
||||
insertion_sort(deque.begin(), deque.end(), eastl::less<int>{});
|
||||
}
|
||||
|
||||
|
||||
// TestObject sorting
|
||||
TestObject::Reset();
|
||||
{
|
||||
vector<TestObject> toArray, toArraySaved;
|
||||
|
||||
for(int i = 0; i < (150 + (gEASTL_TestLevel * 200)); i += (i < 5) ? 1 : 37) // array sizes of 0 to 300 - 2100, depending on test level.
|
||||
{
|
||||
for(int n = 0; n < i; n++)
|
||||
{
|
||||
toArraySaved.push_back(TestObject(n));
|
||||
|
||||
if(rng.RandLimit(10) == 0)
|
||||
{
|
||||
toArraySaved.push_back(TestObject(n));
|
||||
|
||||
if(rng.RandLimit(5) == 0)
|
||||
toArraySaved.push_back(TestObject(n));
|
||||
}
|
||||
}
|
||||
|
||||
for(int j = 0; j < 300 + (gEASTL_TestLevel * 50); j++)
|
||||
{
|
||||
eastl::random_shuffle(toArraySaved.begin(), toArraySaved.end(), rng);
|
||||
|
||||
toArray = toArraySaved;
|
||||
bubble_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
shaker_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
insertion_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
selection_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
shell_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
comb_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
heap_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
// Not ready yet:
|
||||
toArray = toArraySaved;
|
||||
merge_sort(toArray.begin(), toArray.end(), *get_default_allocator((EASTLAllocatorType*)NULL));
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
quick_sort(toArray.begin(), toArray.end());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
|
||||
toArray = toArraySaved;
|
||||
vector<TestObject> buffer(toArray.size()/2);
|
||||
tim_sort_buffer(toArray.begin(), toArray.end(), buffer.data());
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that stable sorting algorithms are actually stable
|
||||
{
|
||||
struct StableSortTestObj
|
||||
{
|
||||
StableSortTestObj()
|
||||
{
|
||||
}
|
||||
|
||||
StableSortTestObj(int value)
|
||||
:value(value)
|
||||
,initialPositionIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
int value;
|
||||
size_t initialPositionIndex;
|
||||
};
|
||||
|
||||
// During the test this comparison is used to sort elements based on value.
|
||||
struct StableSortCompare
|
||||
{
|
||||
bool operator()(const StableSortTestObj& a, const StableSortTestObj& b)
|
||||
{
|
||||
return a.value < b.value;
|
||||
}
|
||||
};
|
||||
|
||||
// During the test this comparison is used to verify the sort was a stable sort. i.e. if values are the same then
|
||||
// their relative position should be maintained.
|
||||
struct StableSortCompareForStability
|
||||
{
|
||||
bool operator()(const StableSortTestObj& a, const StableSortTestObj& b)
|
||||
{
|
||||
if (a.value != b.value)
|
||||
{
|
||||
return a.value < b.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return a.initialPositionIndex < b.initialPositionIndex;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
vector<StableSortTestObj> toArray, toArraySaved;
|
||||
StableSortCompare compare;
|
||||
StableSortCompareForStability compareForStability;
|
||||
|
||||
for (int i = 0; i < (150 + (gEASTL_TestLevel * 200)); i += (i < 5) ? 1 : 37) // array sizes of 0 to 300 - 2100, depending on test level.
|
||||
{
|
||||
for (int n = 0; n < i; n++)
|
||||
{
|
||||
toArraySaved.push_back(StableSortTestObj(n));
|
||||
|
||||
if (rng.RandLimit(10) == 0)
|
||||
{
|
||||
toArraySaved.push_back(StableSortTestObj(n));
|
||||
|
||||
if (rng.RandLimit(5) == 0)
|
||||
toArraySaved.push_back(StableSortTestObj(n));
|
||||
}
|
||||
}
|
||||
vector<StableSortTestObj> tempBuffer;
|
||||
tempBuffer.resize(toArraySaved.size());
|
||||
|
||||
for (int j = 0; j < 300 + (gEASTL_TestLevel * 50); j++)
|
||||
{
|
||||
eastl::random_shuffle(toArraySaved.begin(), toArraySaved.end(), rng);
|
||||
// Store the intial position of each element in the array before sorting. This position can then be used to verify that the sorting operation is stable.
|
||||
for (vector<StableSortTestObj>::size_type k = 0; k < toArraySaved.size(); k++)
|
||||
{
|
||||
toArraySaved[k].initialPositionIndex = k;
|
||||
}
|
||||
|
||||
toArray = toArraySaved;
|
||||
bubble_sort(toArray.begin(), toArray.end(), compare);
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability));
|
||||
|
||||
toArray = toArraySaved;
|
||||
shaker_sort(toArray.begin(), toArray.end(), compare);
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability));
|
||||
|
||||
toArray = toArraySaved;
|
||||
insertion_sort(toArray.begin(), toArray.end(), compare);
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability));
|
||||
|
||||
toArray = toArraySaved;
|
||||
tim_sort_buffer(toArray.begin(), toArray.end(), tempBuffer.data(), compare);
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability));
|
||||
|
||||
toArray = toArraySaved;
|
||||
merge_sort(toArray.begin(), toArray.end(), *get_default_allocator((EASTLAllocatorType*)NULL), compare);
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability));
|
||||
|
||||
toArray = toArraySaved;
|
||||
merge_sort_buffer(toArray.begin(), toArray.end(), tempBuffer.data(), compare);
|
||||
EATEST_VERIFY(is_sorted(toArray.begin(), toArray.end(), compareForStability));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// OutputIterator merge(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result)
|
||||
// This is tested by merge_sort.
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void partial_sort(RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last)
|
||||
// This is tested by quick_sort.
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void nth_element(RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last)
|
||||
// void nth_element(RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last, Compare compare)
|
||||
const int intArrayInit[16] = { 4, 2, 8, 6, 9, 1, 1, 4, 0, 5, 5, 7, 8, 9, 3, 3 };
|
||||
int intArraySorted[16]; // Same as intArrayInit but sorted
|
||||
int intArray[16];
|
||||
size_t i, j;
|
||||
|
||||
// We test many combinations of nth_element on the int array.
|
||||
for(i = 1; i < 16; i++)
|
||||
{
|
||||
for(j = 0; j < i; j++)
|
||||
{
|
||||
eastl::copy(intArrayInit, intArrayInit + i, intArraySorted);
|
||||
eastl::sort(intArraySorted, intArraySorted + i);
|
||||
|
||||
eastl::copy(intArrayInit, intArrayInit + i, intArray);
|
||||
nth_element(intArray, intArray + j, intArray + i);
|
||||
EATEST_VERIFY(intArray[j] == intArraySorted[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 1; i < 16; i++)
|
||||
{
|
||||
for(j = 0; j < i; j++)
|
||||
{
|
||||
eastl::copy(intArrayInit, intArrayInit + i, intArraySorted);
|
||||
eastl::sort(intArraySorted, intArraySorted + i);
|
||||
|
||||
eastl::copy(intArrayInit, intArrayInit + 16, intArray);
|
||||
nth_element(intArray, intArray + j, intArray + i, eastl::less<int>());
|
||||
EATEST_VERIFY(intArray[j] == intArraySorted[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void radix_sort(RandomAccessIterator first, RandomAccessIterator last, RandomAccessIterator buffer);
|
||||
const uint32_t kCount = 100;
|
||||
|
||||
{
|
||||
RadixSortElement32* pRadixSortElementArray32 = new RadixSortElement32[kCount];
|
||||
RadixSortElement32* pRadixSortElementArrayTemp32 = new RadixSortElement32[kCount];
|
||||
for(uint32_t i = 0; i < kCount; i++)
|
||||
{
|
||||
pRadixSortElementArray32[i].mKey = (uint16_t)(kCount - i);
|
||||
pRadixSortElementArray32[i].mData = (uint16_t)i;
|
||||
}
|
||||
radix_sort<RadixSortElement32*, extract_radix_key<RadixSortElement32> >(pRadixSortElementArray32, pRadixSortElementArray32 + kCount, pRadixSortElementArrayTemp32);
|
||||
EATEST_VERIFY(is_sorted(pRadixSortElementArray32, pRadixSortElementArray32 + kCount));
|
||||
delete[] pRadixSortElementArray32;
|
||||
delete[] pRadixSortElementArrayTemp32;
|
||||
}
|
||||
|
||||
{
|
||||
RadixSortElement16* pRadixSortElementArray16 = new RadixSortElement16[kCount];
|
||||
RadixSortElement16* pRadixSortElementArrayTemp16 = new RadixSortElement16[kCount];
|
||||
for(uint32_t i = 0; i < kCount; i++)
|
||||
{
|
||||
pRadixSortElementArray16[i].mKey = (uint16_t)(kCount - i);
|
||||
pRadixSortElementArray16[i].mData = (uint16_t)i;
|
||||
}
|
||||
radix_sort<RadixSortElement16*, extract_radix_key<RadixSortElement16> >(pRadixSortElementArray16, pRadixSortElementArray16 + kCount, pRadixSortElementArrayTemp16);
|
||||
EATEST_VERIFY(is_sorted(pRadixSortElementArray16, pRadixSortElementArray16 + kCount));
|
||||
delete[] pRadixSortElementArray16;
|
||||
delete[] pRadixSortElementArrayTemp16;
|
||||
}
|
||||
|
||||
{
|
||||
RadixSortElement8* pRadixSortElementArray8 = new RadixSortElement8[kCount];
|
||||
RadixSortElement8* pRadixSortElementArrayTemp8 = new RadixSortElement8[kCount];
|
||||
for(uint32_t i = 0; i < kCount; i++)
|
||||
{
|
||||
pRadixSortElementArray8[i].mKey = (uint8_t)(kCount - i);
|
||||
pRadixSortElementArray8[i].mData = (uint8_t)i;
|
||||
}
|
||||
radix_sort<RadixSortElement8*, extract_radix_key<RadixSortElement8> >(pRadixSortElementArray8, pRadixSortElementArray8 + kCount, pRadixSortElementArrayTemp8);
|
||||
EATEST_VERIFY(is_sorted(pRadixSortElementArray8, pRadixSortElementArray8 + kCount));
|
||||
delete[] pRadixSortElementArray8;
|
||||
delete[] pRadixSortElementArrayTemp8;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Do some white-box testing of radix sort to verify internal optimizations work properly for some edge cases.
|
||||
|
||||
{
|
||||
uint32_t input[] = { 123, 15, 76, 2, 74, 12, 62, 91 };
|
||||
uint32_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
{
|
||||
// Test values where some digit positions have identical values
|
||||
uint32_t input[] = { 0x75000017, 0x74000003, 0x73000045, 0x76000024, 0x78000033, 0x76000099, 0x78000043, 0x75000010 };
|
||||
uint32_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
{
|
||||
// Test values where some digit positions have identical values
|
||||
uint32_t input[] = { 0x00750017, 0x00740003, 0x00730045, 0x00760024, 0x00780033, 0x00760099, 0x00780043, 0x00750010 };
|
||||
uint32_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
{
|
||||
// Test values where an odd number of scatter operations will be done during sorting (which forces a copy operation to move values back to the input buffer).
|
||||
uint32_t input[] = { 0x00000017, 0x00000003, 0x00000045, 0x00000024, 0x00000033, 0x00000099, 0x00000043, 0x00000010 };
|
||||
uint32_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
{
|
||||
// Test case for bug where the last histogram bucket was not being cleared to zero
|
||||
uint32_t input[] = { 0xff00, 0xff };
|
||||
uint32_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Test different values for DigitBits
|
||||
|
||||
{
|
||||
uint32_t input[] = {2514513, 6278225, 2726217, 963245656, 35667326, 2625624562, 3562562562, 1556256252};
|
||||
uint32_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>, 1>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
{
|
||||
uint32_t input[] = { 2514513, 6278225, 2726217, 963245656, 35667326, 2625624562, 3562562562, 1556256252 };
|
||||
uint32_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>, 3>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
{
|
||||
uint32_t input[] = { 2514513, 6278225, 2726217, 963245656, 35667326, 2625624562, 3562562562, 1556256252 };
|
||||
uint32_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint32_t*, identity_extract_radix_key<uint32_t>, 6>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
{
|
||||
// Test a value for DigitBits that is more than half the size of the type.
|
||||
uint16_t input[] = { 14513, 58225, 26217, 34656, 63326, 24562, 35562, 15652 };
|
||||
uint16_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint16_t*, identity_extract_radix_key<uint16_t>, 11>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
{
|
||||
// Test a value for DigitBits that is the size of the type itself.
|
||||
uint8_t input[] = { 113, 225, 217, 56, 26, 162, 62, 152 };
|
||||
uint8_t buffer[EAArrayCount(input)];
|
||||
radix_sort<uint8_t*, identity_extract_radix_key<uint8_t>, 8>(begin(input), end(input), buffer);
|
||||
EATEST_VERIFY(is_sorted(begin(input), end(input)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
// void bucket_sort(ForwardIterator first, ForwardIterator last, ContainerArray& bucketArray, HashFunction hash)
|
||||
|
||||
const size_t kElementRange = 32;
|
||||
vector<int> intArray(1000);
|
||||
|
||||
for(int i = 0; i < 1000; i++)
|
||||
intArray[i] = rng() % kElementRange;
|
||||
|
||||
vector< vector<int> > bucketArray(kElementRange);
|
||||
bucket_sort(intArray.begin(), intArray.end(), bucketArray, eastl::hash_use_self<int>());
|
||||
EATEST_VERIFY(is_sorted(intArray.begin(), intArray.end()));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// stable_sort general test
|
||||
typedef eastl::less<int> IntCompare;
|
||||
|
||||
int intArray[2] = { 0, 1 };
|
||||
|
||||
stable_sort(intArray, intArray + 2);
|
||||
stable_sort(intArray, intArray + 2, IntCompare());
|
||||
stable_sort<int*>(intArray, intArray + 2);
|
||||
stable_sort<int*, IntCompare>(intArray, intArray + 2, IntCompare());
|
||||
|
||||
MallocAllocator mallocAllocator;
|
||||
|
||||
//stable_sort(intArray, intArray + 2, mallocAllocator);
|
||||
stable_sort(intArray, intArray + 2, mallocAllocator, IntCompare());
|
||||
//stable_sort<int*, MallocAllocator>(intArray, intArray + 2, mallocAllocator);
|
||||
stable_sort<int*, MallocAllocator, IntCompare>(intArray, intArray + 2, mallocAllocator, IntCompare());
|
||||
}
|
||||
|
||||
{
|
||||
// stable_sort special test
|
||||
IntArrayArray intArrayArray(2);
|
||||
IntArrayCompare compare;
|
||||
|
||||
intArrayArray[0].push_back(0);
|
||||
intArrayArray[1].push_back(1);
|
||||
|
||||
stable_sort(intArrayArray.begin(), intArrayArray.end(), compare);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test to verify that Compare object references are preserved.
|
||||
typedef deque<int> IntDeque;
|
||||
typedef IntDeque::iterator IntDequeIterator;
|
||||
|
||||
IntDeque intDeque, intDequeSaved;
|
||||
StatefulCompare compare;
|
||||
|
||||
// Set up intDequeSaved with random data.
|
||||
for(int n = 0; n < 500; n++)
|
||||
{
|
||||
intDequeSaved.push_back(n);
|
||||
|
||||
if(rng.RandLimit(10) == 0)
|
||||
{
|
||||
intDequeSaved.push_back(n);
|
||||
|
||||
if(rng.RandLimit(5) == 0)
|
||||
intDequeSaved.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
eastl::random_shuffle(intDequeSaved.begin(), intDequeSaved.end(), rng);
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
bubble_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
shaker_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
insertion_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
selection_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
shell_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
comb_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
heap_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
merge_sort<IntDequeIterator, EASTLAllocatorType, StatefulCompare&>(intDeque.begin(), intDeque.end(), *get_default_allocator((EASTLAllocatorType*)NULL), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
intDeque = intDequeSaved;
|
||||
quick_sort<IntDequeIterator, StatefulCompare&>(intDeque.begin(), intDeque.end(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
|
||||
StatefulCompare::Reset();
|
||||
vector<int> buffer(intDeque.size()/2);
|
||||
intDeque = intDequeSaved;
|
||||
tim_sort_buffer<IntDequeIterator, int, StatefulCompare&>(intDeque.begin(), intDeque.end(), buffer.data(), compare);
|
||||
EATEST_VERIFY((StatefulCompare::nCtorCount == 0) && (StatefulCompare::nDtorCount == 0) && (StatefulCompare::nCopyCount == 0));
|
||||
}
|
||||
|
||||
{
|
||||
// Test checking that deque sorting can compile.
|
||||
deque<int> intDeque;
|
||||
vector<int> intVector;
|
||||
|
||||
stable_sort(intDeque.begin(), intDeque.end());
|
||||
stable_sort(intVector.begin(), intVector.end());
|
||||
}
|
||||
|
||||
{
|
||||
// Test checking that sorting containers having elements of a type without an operator< compiles correctly
|
||||
|
||||
vector<TestNoLessOperator> noLessVector;
|
||||
|
||||
stable_sort(noLessVector.begin(), noLessVector.end());
|
||||
bubble_sort(noLessVector.begin(), noLessVector.end());
|
||||
shaker_sort(noLessVector.begin(), noLessVector.end());
|
||||
insertion_sort(noLessVector.begin(), noLessVector.end());
|
||||
selection_sort(noLessVector.begin(), noLessVector.end());
|
||||
shell_sort(noLessVector.begin(), noLessVector.end());
|
||||
comb_sort(noLessVector.begin(), noLessVector.end());
|
||||
heap_sort(noLessVector.begin(), noLessVector.end());
|
||||
merge_sort(noLessVector.begin(), noLessVector.end(), *get_default_allocator(nullptr));
|
||||
quick_sort(noLessVector.begin(), noLessVector.end());
|
||||
|
||||
vector<TestNoLessOperator> buffer;
|
||||
tim_sort_buffer(noLessVector.begin(), noLessVector.end(), buffer.data());
|
||||
}
|
||||
|
||||
{
|
||||
// Test sorting of a container of pointers to objects as opposed to a container of objects themselves.
|
||||
vector<TestObject> toArray;
|
||||
vector<TestObject*> topArray;
|
||||
|
||||
for(eastl_size_t i = 0; i < 32; i++)
|
||||
toArray.push_back(TestObject((int)rng.RandLimit(20)));
|
||||
for(eastl_size_t i = 0; i < 32; i++) // This needs to be a second loop because the addresses might change in the first loop due to container resizing.
|
||||
topArray.push_back(&toArray[i]);
|
||||
|
||||
quick_sort(topArray.begin(), topArray.end(), TestObjectPtrCompare());
|
||||
EATEST_VERIFY(is_sorted(topArray.begin(), topArray.end(), TestObjectPtrCompare()));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test sorting of a container of array indexes to objects as opposed to a container of objects themselves.
|
||||
|
||||
vector<TestObject> toArray;
|
||||
vector<eastl_size_t> toiArray;
|
||||
|
||||
for(eastl_size_t i = 0; i < 32; i++)
|
||||
{
|
||||
toArray.push_back(TestObject((int)rng.RandLimit(20)));
|
||||
toiArray.push_back(i);
|
||||
}
|
||||
|
||||
quick_sort(toiArray.begin(), toiArray.end(), TestObjectIndexCompare(&toArray));
|
||||
EATEST_VERIFY(is_sorted(toiArray.begin(), toiArray.end(), TestObjectIndexCompare(&toArray)));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// Test of special floating point sort in the presence of NaNs.
|
||||
vector<float> floatArray;
|
||||
union FloatInt32{ float f; int32_t i; } fi;
|
||||
|
||||
for(int i = 0; i < 1000; i++)
|
||||
{
|
||||
fi.i = (int32_t)rng.Rand();
|
||||
floatArray.push_back(fi.f);
|
||||
}
|
||||
|
||||
// Without SafeFloatCompare, the following quick_sort will crash, hang, or generate inconsistent results.
|
||||
quick_sort(floatArray.begin(), floatArray.end(), SafeFloatCompare());
|
||||
EATEST_VERIFY(is_sorted(floatArray.begin(), floatArray.end(), SafeFloatCompare()));
|
||||
}
|
||||
|
||||
{
|
||||
auto test_stable_sort = [&](auto testArray, size_t count)
|
||||
{
|
||||
auto isEven = [](auto val) { return (val % 2) == 0; };
|
||||
auto isOdd = [](auto val) { return (val % 2) != 0; };
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
testArray.push_back((uint16_t)rng.Rand());
|
||||
|
||||
vector<uint16_t> evenArray;
|
||||
vector<uint16_t> oddArray;
|
||||
|
||||
eastl::copy_if(testArray.begin(), testArray.end(), eastl::back_inserter(evenArray), isEven);
|
||||
eastl::copy_if(testArray.begin(), testArray.end(), eastl::back_inserter(oddArray), isOdd);
|
||||
|
||||
const auto boundary = eastl::stable_partition(testArray.begin(), testArray.end(), isEven);
|
||||
|
||||
const auto evenCount = eastl::distance(testArray.begin(), boundary);
|
||||
const auto oddCount = eastl::distance(boundary, testArray.end());
|
||||
|
||||
const auto evenExpectedCount = (ptrdiff_t)evenArray.size();
|
||||
const auto oddExpectedCount = (ptrdiff_t)oddArray.size();
|
||||
|
||||
EATEST_VERIFY(evenCount == evenExpectedCount);
|
||||
EATEST_VERIFY(oddCount == oddExpectedCount);
|
||||
EATEST_VERIFY(eastl::equal(testArray.begin(), boundary, evenArray.begin()));
|
||||
EATEST_VERIFY(eastl::equal(boundary, testArray.end(), oddArray.begin()));
|
||||
};
|
||||
|
||||
test_stable_sort(vector<uint16_t>(), 1000); // Test stable_partition
|
||||
test_stable_sort(vector<uint16_t>(), 0); // Test stable_partition on empty container
|
||||
test_stable_sort(vector<uint16_t>(), 1); // Test stable_partition on container of one element
|
||||
test_stable_sort(vector<uint16_t>(), 2); // Test stable_partition on container of two element
|
||||
test_stable_sort(list<uint16_t>(), 0); // Test stable_partition on bidirectional iterator (not random access)
|
||||
}
|
||||
|
||||
#if 0 // Disabled because it takes a long time and thus far seems to show no bug in quick_sort.
|
||||
{
|
||||
// Regression of Coverity report for Madden 2014 that quick_sort is reading beyond an array bounds within insertion_sort_simple.
|
||||
// The Madden code was sorting the 11 players on the field for a team by some criteria. We write
|
||||
vector<int> intArray(11);
|
||||
for(eastl_size_t i = 0; i < intArray.size(); i++)
|
||||
intArray[i] = i;
|
||||
|
||||
do {
|
||||
vector<int> intArrayCopy(intArray);
|
||||
|
||||
// We need to verify that intArray[12] is never accessed. We could do that with a stomp allocator,
|
||||
// which we don't currently have set up for the EASTL unit tests, or we could put a breakpoint in
|
||||
// the debugger. Until we get a stomp allocator installed, do the breakpoint solution.
|
||||
quick_sort(intArrayCopy.begin(), intArrayCopy.end());
|
||||
} while(next_permutation(intArray.begin(), intArray.end()));
|
||||
}
|
||||
#endif
|
||||
|
||||
EATEST_VERIFY(TestObject::IsClear());
|
||||
TestObject::Reset();
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,481 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/array.h>
|
||||
#include <EASTL/span.h>
|
||||
#include <EASTL/vector.h>
|
||||
|
||||
void TestSpanCtor(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
span<int> s;
|
||||
VERIFY(s.empty());
|
||||
VERIFY(s.size() == 0);
|
||||
VERIFY(s.data() == nullptr);
|
||||
}
|
||||
{
|
||||
span<float> s;
|
||||
VERIFY(s.empty());
|
||||
VERIFY(s.size() == 0);
|
||||
VERIFY(s.data() == nullptr);
|
||||
}
|
||||
{
|
||||
span<TestObject> s;
|
||||
VERIFY(s.empty());
|
||||
VERIFY(s.size() == 0);
|
||||
VERIFY(s.data() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(eastl::begin(arr), 5);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(eastl::begin(arr), eastl::end(arr));
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(arr);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(s.data()[2] == arr[2]);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
eastl::array<int, 5> arr = {{0, 1, 2, 3, 4}};
|
||||
span<int> s(arr);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(s.data()[2] == arr.data()[2]);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
const eastl::array<int, 5> arr = {{0, 1, 2, 3, 4}};
|
||||
span<const int> s(arr);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(s.data()[2] == arr.data()[2]);
|
||||
VERIFY(!s.empty());
|
||||
}
|
||||
|
||||
{
|
||||
const eastl::array<int, 5> arr = {{0, 1, 2, 3, 4}};
|
||||
const span<const int> s(arr);
|
||||
VERIFY(s.data() == eastl::begin(arr));
|
||||
VERIFY(s.size() == 5);
|
||||
VERIFY(s.data()[2] == arr.data()[2]);
|
||||
}
|
||||
|
||||
{
|
||||
class foo {};
|
||||
|
||||
foo* pFoo = nullptr;
|
||||
|
||||
auto f = [](eastl::span<const foo*>) {};
|
||||
|
||||
eastl::array<const foo*, 1> foos = {{pFoo}};
|
||||
|
||||
f(foos);
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanSizeBytes(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(arr);
|
||||
VERIFY(s.size_bytes() == sizeof(arr));
|
||||
VERIFY(s.size_bytes() == (5 * sizeof(int)));
|
||||
}
|
||||
|
||||
{
|
||||
float arr[8] = {0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f};
|
||||
span<float> s(arr);
|
||||
VERIFY(s.size_bytes() == sizeof(arr));
|
||||
VERIFY(s.size_bytes() == (8 * sizeof(float)));
|
||||
}
|
||||
|
||||
{
|
||||
int64_t arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int64_t> s(arr);
|
||||
VERIFY(s.size_bytes() == sizeof(arr));
|
||||
VERIFY(s.size_bytes() == (5 * sizeof(int64_t)));
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanElementAccess(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(arr);
|
||||
|
||||
VERIFY(s.front() == 0);
|
||||
VERIFY(s.back() == 4);
|
||||
|
||||
VERIFY(s[0] == 0);
|
||||
VERIFY(s[1] == 1);
|
||||
VERIFY(s[2] == 2);
|
||||
VERIFY(s[3] == 3);
|
||||
VERIFY(s[4] == 4);
|
||||
|
||||
VERIFY(s(0) == 0);
|
||||
VERIFY(s(1) == 1);
|
||||
VERIFY(s(2) == 2);
|
||||
VERIFY(s(3) == 3);
|
||||
VERIFY(s(4) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanIterators(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
span<int> s(arr);
|
||||
|
||||
// ranged-for test
|
||||
{
|
||||
int* pBegin = arr;
|
||||
for(auto& e : arr)
|
||||
{
|
||||
VERIFY(e == *pBegin++);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto testIteratorBegin = [&](auto p)
|
||||
{
|
||||
VERIFY(*p++ == 0);
|
||||
VERIFY(*p++ == 1);
|
||||
VERIFY(*p++ == 2);
|
||||
VERIFY(*p++ == 3);
|
||||
VERIFY(*p++ == 4);
|
||||
VERIFY(*p++ == 5);
|
||||
VERIFY(*p++ == 6);
|
||||
VERIFY(*p++ == 7);
|
||||
VERIFY(*p++ == 8);
|
||||
VERIFY(*p++ == 9);
|
||||
};
|
||||
|
||||
auto testIteratorEnd = [&](auto p)
|
||||
{
|
||||
p--; // move pointer to a valid element
|
||||
|
||||
VERIFY(*p-- == 9);
|
||||
VERIFY(*p-- == 8);
|
||||
VERIFY(*p-- == 7);
|
||||
VERIFY(*p-- == 6);
|
||||
VERIFY(*p-- == 5);
|
||||
VERIFY(*p-- == 4);
|
||||
VERIFY(*p-- == 3);
|
||||
VERIFY(*p-- == 2);
|
||||
VERIFY(*p-- == 1);
|
||||
VERIFY(*p-- == 0);
|
||||
};
|
||||
|
||||
testIteratorBegin(s.begin());
|
||||
testIteratorBegin(s.cbegin());
|
||||
testIteratorEnd(s.end());
|
||||
testIteratorEnd(s.cend());
|
||||
}
|
||||
|
||||
{
|
||||
auto testReverseIteratorBegin = [&](auto p)
|
||||
{
|
||||
VERIFY(*p++ == 9);
|
||||
VERIFY(*p++ == 8);
|
||||
VERIFY(*p++ == 7);
|
||||
VERIFY(*p++ == 6);
|
||||
VERIFY(*p++ == 5);
|
||||
VERIFY(*p++ == 4);
|
||||
VERIFY(*p++ == 3);
|
||||
VERIFY(*p++ == 2);
|
||||
VERIFY(*p++ == 1);
|
||||
VERIFY(*p++ == 0);
|
||||
};
|
||||
|
||||
auto testReverseIteratorEnd = [&](auto p)
|
||||
{
|
||||
p--; // move pointer to a valid element
|
||||
|
||||
VERIFY(*p-- == 0);
|
||||
VERIFY(*p-- == 1);
|
||||
VERIFY(*p-- == 2);
|
||||
VERIFY(*p-- == 3);
|
||||
VERIFY(*p-- == 4);
|
||||
VERIFY(*p-- == 5);
|
||||
VERIFY(*p-- == 6);
|
||||
VERIFY(*p-- == 7);
|
||||
VERIFY(*p-- == 8);
|
||||
VERIFY(*p-- == 9);
|
||||
};
|
||||
|
||||
testReverseIteratorBegin(s.rbegin());
|
||||
testReverseIteratorBegin(s.crbegin());
|
||||
testReverseIteratorEnd(s.rend());
|
||||
testReverseIteratorEnd(s.crend());
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanCopyAssignment(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
int arr[5] = {0, 1, 2, 3, 4};
|
||||
span<int> s(arr);
|
||||
span<int> sc = s;
|
||||
|
||||
VERIFY(s[0] == sc[0]);
|
||||
VERIFY(s[1] == sc[1]);
|
||||
VERIFY(s[2] == sc[2]);
|
||||
VERIFY(s[3] == sc[3]);
|
||||
VERIFY(s[4] == sc[4]);
|
||||
|
||||
VERIFY(s(0) == sc(0));
|
||||
VERIFY(s(1) == sc(1));
|
||||
VERIFY(s(2) == sc(2));
|
||||
VERIFY(s(3) == sc(3));
|
||||
VERIFY(s(4) == sc(4));
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanContainerConversion(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
{
|
||||
vector<int> v = {0, 1, 2, 3, 4, 5};
|
||||
span<const int> s(v);
|
||||
|
||||
VERIFY(s.size() == static_cast<span<int>::index_type>(eastl::size(v)));
|
||||
VERIFY(s.data() == eastl::data(v));
|
||||
|
||||
VERIFY(s[0] == v[0]);
|
||||
VERIFY(s[1] == v[1]);
|
||||
VERIFY(s[2] == v[2]);
|
||||
VERIFY(s[3] == v[3]);
|
||||
VERIFY(s[4] == v[4]);
|
||||
VERIFY(s[5] == v[5]);
|
||||
}
|
||||
|
||||
{
|
||||
const vector<int> v = {0, 1, 2, 3, 4, 5};
|
||||
span<const int> s(v);
|
||||
|
||||
VERIFY(s.size() == static_cast<span<int>::index_type>(eastl::size(v)));
|
||||
VERIFY(s.data() == eastl::data(v));
|
||||
|
||||
VERIFY(s[0] == v[0]);
|
||||
VERIFY(s[1] == v[1]);
|
||||
VERIFY(s[2] == v[2]);
|
||||
VERIFY(s[3] == v[3]);
|
||||
VERIFY(s[4] == v[4]);
|
||||
VERIFY(s[5] == v[5]);
|
||||
}
|
||||
|
||||
{
|
||||
vector<int> v = {0, 1, 2, 3, 4, 5};
|
||||
span<const int, 6> s1(v);
|
||||
span<const int> s2(s1);
|
||||
|
||||
VERIFY(s2.size() == (span<const int>::index_type)v.size());
|
||||
VERIFY(s2[0] == v[0]);
|
||||
VERIFY(s2[1] == v[1]);
|
||||
|
||||
VERIFY(s1.data() == v.data());
|
||||
VERIFY(s1.data() == s2.data());
|
||||
}
|
||||
|
||||
{ // user reported regression for calling non-const span overload with a vector.
|
||||
auto f1 = [](span<int> s) { return s.size(); };
|
||||
auto f2 = [](span<const int> s) { return s.size(); };
|
||||
|
||||
{
|
||||
vector<int> v = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
VERIFY(f1(v) == v.size());
|
||||
VERIFY(f2(v) == v.size());
|
||||
}
|
||||
|
||||
{
|
||||
int a[] = {0, 1, 2, 3, 4, 5};
|
||||
|
||||
VERIFY(f1(a) == EAArrayCount(a));
|
||||
VERIFY(f2(a) == EAArrayCount(a));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanComparison(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int arr1[5] = {0, 1, 2, 3, 4};
|
||||
int arr2[8] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
{
|
||||
span<int> s1 = arr1;
|
||||
span<int> s2 = arr2;
|
||||
span<int> s3 = arr2;
|
||||
VERIFY(s2 == s3);
|
||||
VERIFY(s1 != s2);
|
||||
VERIFY(s1 < s2);
|
||||
VERIFY(s1 <= s2);
|
||||
VERIFY(s2 > s1);
|
||||
VERIFY(s2 >= s1);
|
||||
}
|
||||
}
|
||||
|
||||
void TestSpanSubViews(int& nErrorCount)
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int arr1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
{
|
||||
span<int> s = arr1;
|
||||
auto first_span = s.first<4>();
|
||||
VERIFY(first_span.size() == 4);
|
||||
VERIFY(first_span[0] == 0);
|
||||
VERIFY(first_span[1] == 1);
|
||||
VERIFY(first_span[2] == 2);
|
||||
VERIFY(first_span[3] == 3);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s = arr1;
|
||||
auto first_span = s.first(4);
|
||||
VERIFY(first_span.size() == 4);
|
||||
VERIFY(first_span[0] == 0);
|
||||
VERIFY(first_span[1] == 1);
|
||||
VERIFY(first_span[2] == 2);
|
||||
VERIFY(first_span[3] == 3);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s = arr1;
|
||||
auto first_span = s.last<4>();
|
||||
VERIFY(first_span.size() == 4);
|
||||
VERIFY(first_span[0] == 6);
|
||||
VERIFY(first_span[1] == 7);
|
||||
VERIFY(first_span[2] == 8);
|
||||
VERIFY(first_span[3] == 9);
|
||||
}
|
||||
|
||||
{
|
||||
span<int> s = arr1;
|
||||
auto first_span = s.last(4);
|
||||
VERIFY(first_span.size() == 4);
|
||||
VERIFY(first_span[0] == 6);
|
||||
VERIFY(first_span[1] == 7);
|
||||
VERIFY(first_span[2] == 8);
|
||||
VERIFY(first_span[3] == 9);
|
||||
}
|
||||
|
||||
{ // empty range
|
||||
span<int, 0> s{};
|
||||
|
||||
auto fixed_span = s.subspan<0, 0>();
|
||||
VERIFY(fixed_span.empty());
|
||||
fixed_span = s.first<0>();
|
||||
VERIFY(fixed_span.empty());
|
||||
fixed_span = s.last<0>();
|
||||
VERIFY(fixed_span.empty());
|
||||
|
||||
span<int> dynamic_span;
|
||||
VERIFY(dynamic_span.empty());
|
||||
dynamic_span = s.first(0);
|
||||
VERIFY(dynamic_span.empty());
|
||||
dynamic_span = s.last(0);
|
||||
VERIFY(dynamic_span.empty());
|
||||
}
|
||||
|
||||
{ // subspan: full range
|
||||
span<int, 10> s = arr1;
|
||||
|
||||
auto fixed_span = s.subspan<0, 10>();
|
||||
VERIFY(fixed_span.size() == 10);
|
||||
VERIFY(fixed_span[0] == 0);
|
||||
VERIFY(fixed_span[1] == 1);
|
||||
VERIFY(fixed_span[8] == 8);
|
||||
VERIFY(fixed_span[9] == 9);
|
||||
|
||||
auto dynamic_span = s.subspan(0, s.size());
|
||||
VERIFY(dynamic_span.size() == 10);
|
||||
VERIFY(dynamic_span[0] == 0);
|
||||
VERIFY(dynamic_span[1] == 1);
|
||||
VERIFY(dynamic_span[8] == 8);
|
||||
VERIFY(dynamic_span[9] == 9);
|
||||
}
|
||||
|
||||
{ // subspan: subrange
|
||||
span<int, 10> s = arr1;
|
||||
|
||||
auto fixed_span = s.subspan<3, 4>();
|
||||
VERIFY(fixed_span.size() == 4);
|
||||
VERIFY(fixed_span[0] == 3);
|
||||
VERIFY(fixed_span[1] == 4);
|
||||
VERIFY(fixed_span[2] == 5);
|
||||
VERIFY(fixed_span[3] == 6);
|
||||
|
||||
auto dynamic_span = s.subspan(3, 4);
|
||||
VERIFY(dynamic_span.size() == 4);
|
||||
VERIFY(dynamic_span[0] == 3);
|
||||
VERIFY(dynamic_span[1] == 4);
|
||||
VERIFY(dynamic_span[2] == 5);
|
||||
VERIFY(dynamic_span[3] == 6);
|
||||
}
|
||||
|
||||
{ // subspan: default count
|
||||
span<int, 10> s = arr1;
|
||||
|
||||
auto fixed_span = s.subspan<3>();
|
||||
VERIFY(fixed_span.size() == 7);
|
||||
VERIFY(fixed_span[0] == 3);
|
||||
VERIFY(fixed_span[1] == 4);
|
||||
VERIFY(fixed_span[5] == 8);
|
||||
VERIFY(fixed_span[6] == 9);
|
||||
|
||||
auto dynamic_span = s.subspan(3);
|
||||
VERIFY(dynamic_span.size() == 7);
|
||||
VERIFY(dynamic_span[0] == 3);
|
||||
VERIFY(dynamic_span[1] == 4);
|
||||
VERIFY(dynamic_span[5] == 8);
|
||||
VERIFY(dynamic_span[6] == 9);
|
||||
}
|
||||
}
|
||||
|
||||
int TestSpan()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
TestSpanCtor(nErrorCount);
|
||||
TestSpanSizeBytes(nErrorCount);
|
||||
TestSpanElementAccess(nErrorCount);
|
||||
TestSpanIterators(nErrorCount);
|
||||
TestSpanCopyAssignment(nErrorCount);
|
||||
TestSpanContainerConversion(nErrorCount);
|
||||
TestSpanComparison(nErrorCount);
|
||||
TestSpanSubViews(nErrorCount);
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAStdC/EAMemory.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/algorithm.h>
|
||||
#include <EASTL/allocator_malloc.h>
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
// Verify char8_t support is present if the test build requested it.
|
||||
#if defined(EASTL_EXPECT_CHAR8T_SUPPORT) && !EA_CHAR8_UNIQUE
|
||||
static_assert(false, "Building with char8_t tests enabled, but EA_CHAR8_UNIQUE evaluates to false.");
|
||||
#endif
|
||||
|
||||
|
||||
// inject string literal string conversion macros into the unit tests
|
||||
#define TEST_STRING_NAME TestBasicString
|
||||
#define LITERAL(x) x
|
||||
#include "TestString.inl"
|
||||
|
||||
#define TEST_STRING_NAME TestBasicStringW
|
||||
#define LITERAL(x) EA_WCHAR(x)
|
||||
#include "TestString.inl"
|
||||
|
||||
#define TEST_STRING_NAME TestBasicString8
|
||||
#define LITERAL(x) EA_CHAR8(x)
|
||||
#include "TestString.inl"
|
||||
|
||||
#define TEST_STRING_NAME TestBasicString16
|
||||
#define LITERAL(x) EA_CHAR16(x)
|
||||
#include "TestString.inl"
|
||||
|
||||
#define TEST_STRING_NAME TestBasicString32
|
||||
#define LITERAL(x) EA_CHAR32(x)
|
||||
#include "TestString.inl"
|
||||
|
||||
int TestString()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
nErrorCount += TestBasicString<eastl::basic_string<char, StompDetectAllocator>>();
|
||||
nErrorCount += TestBasicString<eastl::string>();
|
||||
|
||||
nErrorCount += TestBasicStringW<eastl::basic_string<wchar_t, StompDetectAllocator>>();
|
||||
nErrorCount += TestBasicStringW<eastl::wstring>();
|
||||
|
||||
#if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
|
||||
nErrorCount += TestBasicString8<eastl::basic_string<char8_t, StompDetectAllocator>>();
|
||||
nErrorCount += TestBasicString8<eastl::u8string>();
|
||||
#endif
|
||||
|
||||
nErrorCount += TestBasicString16<eastl::basic_string<char16_t, StompDetectAllocator>>();
|
||||
nErrorCount += TestBasicString16<eastl::u16string>();
|
||||
|
||||
#if defined(EA_CHAR32_NATIVE) && EA_CHAR32_NATIVE
|
||||
nErrorCount += TestBasicString32<eastl::basic_string<char32_t, StompDetectAllocator>>();
|
||||
nErrorCount += TestBasicString32<eastl::u32string>();
|
||||
#endif
|
||||
|
||||
// Check for memory leaks by using the 'CountingAllocator' to ensure no active allocation after tests have completed.
|
||||
CountingAllocator::resetCount();
|
||||
nErrorCount += TestBasicString<eastl::basic_string<char, CountingAllocator>>();
|
||||
VERIFY(CountingAllocator::getActiveAllocationCount() == 0);
|
||||
|
||||
nErrorCount += TestBasicStringW<eastl::basic_string<wchar_t, CountingAllocator>>();
|
||||
VERIFY(CountingAllocator::getActiveAllocationCount() == 0);
|
||||
|
||||
#if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
|
||||
nErrorCount += TestBasicString8<eastl::basic_string<char8_t, CountingAllocator>>();
|
||||
VERIFY(CountingAllocator::getActiveAllocationCount() == 0);
|
||||
#endif
|
||||
|
||||
nErrorCount += TestBasicString16<eastl::basic_string<char16_t, CountingAllocator>>();
|
||||
VERIFY(CountingAllocator::getActiveAllocationCount() == 0);
|
||||
|
||||
#if defined(EA_CHAR32_NATIVE) && EA_CHAR32_NATIVE
|
||||
nErrorCount += TestBasicString32<eastl::basic_string<char32_t, CountingAllocator>>();
|
||||
VERIFY(CountingAllocator::getActiveAllocationCount() == 0);
|
||||
#endif
|
||||
|
||||
// to_string
|
||||
{
|
||||
VERIFY(eastl::to_string(42) == "42");
|
||||
VERIFY(eastl::to_string(42l) == "42");
|
||||
VERIFY(eastl::to_string(42ll) == "42");
|
||||
VERIFY(eastl::to_string(42u) == "42");
|
||||
VERIFY(eastl::to_string(42ul) == "42");
|
||||
VERIFY(eastl::to_string(42ull) == "42");
|
||||
VERIFY(eastl::to_string(42.f) == "42.000000");
|
||||
VERIFY(eastl::to_string(42.0) == "42.000000");
|
||||
#if !defined(EA_COMPILER_GNUC) && !defined(EA_PLATFORM_MINGW)
|
||||
// todo: long double sprintf functionality is unrealiable on unix-gcc, requires further debugging.
|
||||
VERIFY(eastl::to_string(42.0l) == "42.000000");
|
||||
#endif
|
||||
}
|
||||
|
||||
// to_wstring
|
||||
{
|
||||
VERIFY(eastl::to_wstring(42) == L"42");
|
||||
VERIFY(eastl::to_wstring(42l) == L"42");
|
||||
VERIFY(eastl::to_wstring(42ll) == L"42");
|
||||
VERIFY(eastl::to_wstring(42u) == L"42");
|
||||
VERIFY(eastl::to_wstring(42ul) == L"42");
|
||||
VERIFY(eastl::to_wstring(42ull) == L"42");
|
||||
VERIFY(eastl::to_wstring(42.f) == L"42.000000");
|
||||
VERIFY(eastl::to_wstring(42.0) == L"42.000000");
|
||||
#if !defined(EA_COMPILER_GNUC) && !defined(EA_PLATFORM_MINGW)
|
||||
// todo: long double sprintf functionality is unrealiable on unix-gcc, requires further debugging.
|
||||
VERIFY(eastl::to_wstring(42.0l) == L"42.000000");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if EASTL_USER_LITERALS_ENABLED
|
||||
{
|
||||
VERIFY("cplusplus"s == "cplusplus");
|
||||
VERIFY(L"cplusplus"s == L"cplusplus");
|
||||
VERIFY(u"cplusplus"s == u"cplusplus");
|
||||
VERIFY(U"cplusplus"s == U"cplusplus");
|
||||
VERIFY(u8"cplusplus"s == u8"cplusplus");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
{
|
||||
// CustomAllocator has no data members which reduces the size of an eastl::basic_string via the empty base class optimization.
|
||||
using EboString = eastl::basic_string<char, CustomAllocator>;
|
||||
|
||||
// this must match the eastl::basic_string heap memory layout struct which is a pointer and 2 eastl_size_t.
|
||||
const int expectedSize = sizeof(EboString::pointer) + (2 * sizeof(EboString::size_type));
|
||||
|
||||
static_assert(sizeof(EboString) == expectedSize, "unexpected layout size of basic_string");
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,303 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/string_hash_map.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::string_hash_map<int>;
|
||||
template class eastl::string_hash_map<Align32>;
|
||||
|
||||
static const char* strings[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"};
|
||||
static const size_t kStringCount = 10; // This is intentionally half the length of strings, so that we can test with strings that are not inserted to the map.
|
||||
|
||||
|
||||
int TestStringHashMap()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{ // Test declarations
|
||||
string_hash_map<int> stringHashMap;
|
||||
|
||||
string_hash_map<int> stringHashMap2(stringHashMap);
|
||||
EATEST_VERIFY(stringHashMap2.size() == stringHashMap.size());
|
||||
EATEST_VERIFY(stringHashMap2 == stringHashMap);
|
||||
|
||||
|
||||
// allocator_type& get_allocator();
|
||||
// void set_allocator(const allocator_type& allocator);
|
||||
string_hash_map<int>::allocator_type& allocator = stringHashMap.get_allocator();
|
||||
stringHashMap.set_allocator(EASTLAllocatorType());
|
||||
stringHashMap.set_allocator(allocator);
|
||||
// To do: Try to find something better to test here.
|
||||
|
||||
|
||||
// const key_equal& key_eq() const;
|
||||
// key_equal& key_eq();
|
||||
string_hash_map<int> hs;
|
||||
const string_hash_map<int> hsc;
|
||||
|
||||
const string_hash_map<int>::key_equal& ke = hsc.key_eq();
|
||||
hs.key_eq() = ke;
|
||||
|
||||
|
||||
// const char* get_name() const;
|
||||
// void set_name(const char* pName);
|
||||
#if EASTL_NAME_ENABLED
|
||||
stringHashMap.get_allocator().set_name("test");
|
||||
const char* pName = stringHashMap.get_allocator().get_name();
|
||||
EATEST_VERIFY(equal(pName, pName + 5, "test"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
string_hash_map<int> stringHashMap;
|
||||
|
||||
// Clear a newly constructed, already empty container.
|
||||
stringHashMap.clear(true);
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == 0);
|
||||
EATEST_VERIFY(stringHashMap.bucket_count() == 1);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringHashMap.insert(strings[i], i);
|
||||
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == kStringCount);
|
||||
|
||||
stringHashMap.clear(true);
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == 0);
|
||||
EATEST_VERIFY(stringHashMap.bucket_count() == 1);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringHashMap.insert(strings[i], i);
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == kStringCount);
|
||||
|
||||
stringHashMap.clear(true);
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == 0);
|
||||
EATEST_VERIFY(stringHashMap.bucket_count() == 1);
|
||||
}
|
||||
|
||||
|
||||
{ // Test string_hash_map
|
||||
|
||||
// size_type size() const
|
||||
// bool empty() const
|
||||
// insert_return_type insert(const value_type& value);
|
||||
// insert_return_type insert(const value_type& value, hash_code_t c, node_type* pNodeNew = NULL);
|
||||
// iterator insert(const_iterator, const value_type& value);
|
||||
// iterator find(const key_type& k);
|
||||
// const_iterator find(const key_type& k) const;
|
||||
// size_type count(const key_type& k) const;
|
||||
|
||||
typedef string_hash_map<int> StringHashMapInt;
|
||||
|
||||
StringHashMapInt stringHashMap;
|
||||
|
||||
EATEST_VERIFY(stringHashMap.empty());
|
||||
EATEST_VERIFY(stringHashMap.size() == 0);
|
||||
EATEST_VERIFY(stringHashMap.count(strings[0]) == 0);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringHashMap.insert(strings[i], i);
|
||||
|
||||
EATEST_VERIFY(!stringHashMap.empty());
|
||||
EATEST_VERIFY(stringHashMap.size() == kStringCount);
|
||||
EATEST_VERIFY(stringHashMap.count(strings[0]) == 1);
|
||||
|
||||
int j = 0;
|
||||
for (StringHashMapInt::iterator it = stringHashMap.begin(); it != stringHashMap.end(); ++it, ++j)
|
||||
{
|
||||
int value = (*it).second;
|
||||
EATEST_VERIFY(value < (int)kStringCount);
|
||||
}
|
||||
|
||||
for(int i = 0; i < (int)kStringCount * 2; i++)
|
||||
{
|
||||
StringHashMapInt::iterator it = stringHashMap.find(strings[i]);
|
||||
|
||||
if (i < (int)kStringCount)
|
||||
{
|
||||
EATEST_VERIFY(it != stringHashMap.end());
|
||||
const char* k = it->first;
|
||||
int v = it->second;
|
||||
EATEST_VERIFY(EA::StdC::Strcmp(k, strings[i]) == 0);
|
||||
EATEST_VERIFY(v == i);
|
||||
}
|
||||
else
|
||||
EATEST_VERIFY(it == stringHashMap.end());
|
||||
}
|
||||
|
||||
StringHashMapInt::insert_return_type result = stringHashMap.insert("EASTLTEST");
|
||||
EATEST_VERIFY(result.second == true);
|
||||
result = stringHashMap.insert("EASTLTEST");
|
||||
EATEST_VERIFY(result.second == false);
|
||||
result.first->second = 0;
|
||||
|
||||
// iterator erase(const_iterator);
|
||||
size_t nExpectedSize = stringHashMap.size();
|
||||
|
||||
StringHashMapInt::iterator itD = stringHashMap.find("d");
|
||||
EATEST_VERIFY(itD != stringHashMap.end());
|
||||
|
||||
// erase the element and verify that the size has decreased
|
||||
stringHashMap.erase(itD);
|
||||
nExpectedSize--;
|
||||
EATEST_VERIFY(stringHashMap.size() == nExpectedSize);
|
||||
|
||||
// verify that erased element is gone
|
||||
itD = stringHashMap.find(strings[3]);
|
||||
EATEST_VERIFY(itD == stringHashMap.end());
|
||||
|
||||
// iterator erase(const char*)
|
||||
StringHashMapInt::size_type n = stringHashMap.erase(strings[4]);
|
||||
nExpectedSize--;
|
||||
EATEST_VERIFY(n == 1);
|
||||
EATEST_VERIFY(stringHashMap.size() == nExpectedSize);
|
||||
|
||||
|
||||
// mapped_type& operator[](const key_type& key)
|
||||
stringHashMap.clear();
|
||||
|
||||
int x = stringHashMap["A"]; // A default-constructed int (i.e. 0) should be returned.
|
||||
EATEST_VERIFY(x == 0);
|
||||
|
||||
stringHashMap["B"] = 1;
|
||||
x = stringHashMap["B"];
|
||||
EATEST_VERIFY(x == 1); // Verify that the value we assigned is returned and a default-constructed value is not returned.
|
||||
|
||||
stringHashMap["A"] = 10; // Overwrite our previous 0 with 10.
|
||||
stringHashMap["B"] = 11;
|
||||
x = stringHashMap["A"];
|
||||
EATEST_VERIFY(x == 10); // Verify the value is as expected.
|
||||
x = stringHashMap["B"];
|
||||
EATEST_VERIFY(x == 11);
|
||||
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// string_hash_map(const allocator_type& allocator);
|
||||
// string_hash_map& operator=(const this_type& x);
|
||||
// bool validate() const;
|
||||
|
||||
string_hash_map<int> stringHashMap1(EASTLAllocatorType("TestStringHashMap"));
|
||||
string_hash_map<int> stringHashMap2(stringHashMap1);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
{
|
||||
stringHashMap1.insert(strings[i], i);
|
||||
}
|
||||
|
||||
stringHashMap2 = stringHashMap1;
|
||||
string_hash_map<int> stringHashMap3(stringHashMap1);
|
||||
|
||||
EATEST_VERIFY(stringHashMap1.validate());
|
||||
EATEST_VERIFY(stringHashMap2.validate());
|
||||
EATEST_VERIFY(stringHashMap3.validate());
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
{
|
||||
EATEST_VERIFY(stringHashMap1[strings[i]] == stringHashMap2[strings[i]]);
|
||||
EATEST_VERIFY(stringHashMap1[strings[i]] == stringHashMap3[strings[i]]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// pair<iterator, bool> insert_or_assign(const char* key, const T& value);
|
||||
{
|
||||
{
|
||||
string_hash_map<int> m;
|
||||
|
||||
m.insert_or_assign("hello", 0);
|
||||
EATEST_VERIFY(m["hello"] == 0);
|
||||
|
||||
m.insert_or_assign("hello", 42);
|
||||
EATEST_VERIFY(m["hello"] == 42);
|
||||
|
||||
m.insert_or_assign("hello", 43);
|
||||
EATEST_VERIFY(m["hello"] == 43);
|
||||
|
||||
m.insert_or_assign("hello", 1143);
|
||||
EATEST_VERIFY(m["hello"] == 1143);
|
||||
|
||||
EATEST_VERIFY(m.size() == 1);
|
||||
m.clear();
|
||||
EATEST_VERIFY(m.size() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
string_hash_map<int> m;
|
||||
m.insert_or_assign("hello", 0);
|
||||
m.insert_or_assign("hello2", 0);
|
||||
|
||||
EATEST_VERIFY(m.size() == 2);
|
||||
m.clear();
|
||||
EATEST_VERIFY(m.size() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
string_hash_map<int> m;
|
||||
m.insert_or_assign("hello", 0);
|
||||
m.insert_or_assign("hello2", 0);
|
||||
|
||||
EATEST_VERIFY(m.size() == 2);
|
||||
m.clear(true);
|
||||
EATEST_VERIFY(m.size() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
string_hash_map<int> m;
|
||||
m.insert_or_assign("hello", 0);
|
||||
m.insert_or_assign("hello2", 0);
|
||||
|
||||
EATEST_VERIFY(m.size() == 2);
|
||||
m.clear(false);
|
||||
EATEST_VERIFY(m.size() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
string_hash_map<TestObject> m;
|
||||
|
||||
m.insert_or_assign("hello", TestObject(42));
|
||||
EATEST_VERIFY(m["hello"].mX == 42);
|
||||
|
||||
m.insert_or_assign("hello", TestObject(43));
|
||||
EATEST_VERIFY(m["hello"].mX == 43);
|
||||
|
||||
EATEST_VERIFY(m.size() == 1);
|
||||
}
|
||||
|
||||
{
|
||||
typedef string_hash_map<TestObject, hash<const char*>, str_equal_to<const char*>, CountingAllocator> counting_string_hash_map;
|
||||
counting_string_hash_map m;
|
||||
EATEST_VERIFY(CountingAllocator::getActiveAllocationCount() == 0);
|
||||
|
||||
m.insert_or_assign("hello", TestObject(42));
|
||||
EATEST_VERIFY(CountingAllocator::getActiveAllocationCount() == 3);
|
||||
EATEST_VERIFY(m["hello"].mX == 42);
|
||||
EATEST_VERIFY(CountingAllocator::getActiveAllocationCount() == 3);
|
||||
|
||||
m.insert_or_assign("hello", TestObject(43));
|
||||
EATEST_VERIFY(CountingAllocator::getActiveAllocationCount() == 3);
|
||||
EATEST_VERIFY(m["hello"].mX == 43);
|
||||
EATEST_VERIFY(CountingAllocator::getActiveAllocationCount() == 3);
|
||||
|
||||
EATEST_VERIFY(m.size() == 1);
|
||||
}
|
||||
EATEST_VERIFY(CountingAllocator::getActiveAllocationCount() == 0);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/string_map.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::string_map<int>;
|
||||
template class eastl::string_map<Align32>;
|
||||
|
||||
static const char* strings[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t" };
|
||||
static const size_t kStringCount = 10; // This is intentionally half the length of strings, so that we can test with strings that are not inserted to the map.
|
||||
|
||||
|
||||
int TestStringMap()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{ // Test declarations
|
||||
string_map<int> stringMap;
|
||||
|
||||
string_map<int> stringMap2(stringMap);
|
||||
EATEST_VERIFY(stringMap2.size() == stringMap.size());
|
||||
EATEST_VERIFY(stringMap2 == stringMap);
|
||||
|
||||
|
||||
// allocator_type& get_allocator();
|
||||
// void set_allocator(const allocator_type& allocator);
|
||||
string_map<int>::allocator_type& allocator = stringMap.get_allocator();
|
||||
stringMap.set_allocator(EASTLAllocatorType());
|
||||
stringMap.set_allocator(allocator);
|
||||
// To do: Try to find something better to test here.
|
||||
|
||||
|
||||
// const char* get_name() const;
|
||||
// void set_name(const char* pName);
|
||||
#if EASTL_NAME_ENABLED
|
||||
stringMap.get_allocator().set_name("test");
|
||||
const char* pName = stringMap.get_allocator().get_name();
|
||||
EATEST_VERIFY(equal(pName, pName + 5, "test"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
string_map<int> stringMap;
|
||||
|
||||
// Clear a newly constructed, already empty container.
|
||||
stringMap.clear();
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == 0);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringMap.insert(strings[i], i);
|
||||
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == kStringCount);
|
||||
|
||||
stringMap.clear();
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == 0);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringMap.insert(strings[i], i);
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == kStringCount);
|
||||
|
||||
stringMap.clear();
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == 0);
|
||||
}
|
||||
|
||||
|
||||
{ // Test string_map
|
||||
|
||||
// size_type size() const
|
||||
// bool empty() const
|
||||
// insert_return_type insert(const value_type& value);
|
||||
// insert_return_type insert(const value_type& value, hash_code_t c, node_type* pNodeNew = NULL);
|
||||
// iterator insert(const_iterator, const value_type& value);
|
||||
// iterator find(const key_type& k);
|
||||
// const_iterator find(const key_type& k) const;
|
||||
// size_type count(const key_type& k) const;
|
||||
|
||||
typedef string_map<int> StringMapInt;
|
||||
|
||||
StringMapInt stringMap;
|
||||
|
||||
EATEST_VERIFY(stringMap.empty());
|
||||
EATEST_VERIFY(stringMap.size() == 0);
|
||||
EATEST_VERIFY(stringMap.count(strings[0]) == 0);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringMap.insert(strings[i], i);
|
||||
|
||||
EATEST_VERIFY(!stringMap.empty());
|
||||
EATEST_VERIFY(stringMap.size() == kStringCount);
|
||||
EATEST_VERIFY(stringMap.count(strings[0]) == 1);
|
||||
|
||||
int j = 0;
|
||||
for (StringMapInt::iterator it = stringMap.begin(); it != stringMap.end(); ++it, ++j)
|
||||
{
|
||||
int value = (*it).second;
|
||||
EATEST_VERIFY(value < (int)kStringCount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)kStringCount * 2; i++)
|
||||
{
|
||||
StringMapInt::iterator it = stringMap.find(strings[i]);
|
||||
|
||||
if (i < (int)kStringCount)
|
||||
{
|
||||
EATEST_VERIFY(it != stringMap.end());
|
||||
const char* k = (*it).first;
|
||||
int v = (*it).second;
|
||||
EATEST_VERIFY(EA::StdC::Strcmp(k, strings[i]) == 0);
|
||||
EATEST_VERIFY(v == i);
|
||||
}
|
||||
else
|
||||
EATEST_VERIFY(it == stringMap.end());
|
||||
}
|
||||
|
||||
StringMapInt::insert_return_type result = stringMap.insert("EASTLTEST");
|
||||
EATEST_VERIFY(result.second == true);
|
||||
result = stringMap.insert("EASTLTEST");
|
||||
EATEST_VERIFY(result.second == false);
|
||||
result.first->second = 0;
|
||||
|
||||
// iterator erase(const_iterator);
|
||||
size_t nExpectedSize = stringMap.size();
|
||||
|
||||
StringMapInt::iterator itD = stringMap.find("d");
|
||||
EATEST_VERIFY(itD != stringMap.end());
|
||||
|
||||
// erase the element and verify that the size has decreased
|
||||
stringMap.erase(itD);
|
||||
nExpectedSize--;
|
||||
EATEST_VERIFY(stringMap.size() == nExpectedSize);
|
||||
|
||||
// verify that erased element is gone
|
||||
itD = stringMap.find(strings[3]);
|
||||
EATEST_VERIFY(itD == stringMap.end());
|
||||
|
||||
// iterator erase(const char*)
|
||||
StringMapInt::size_type n = stringMap.erase(strings[4]);
|
||||
nExpectedSize--;
|
||||
EATEST_VERIFY(n == 1);
|
||||
EATEST_VERIFY(stringMap.size() == nExpectedSize);
|
||||
|
||||
|
||||
// mapped_type& operator[](const key_type& key)
|
||||
stringMap.clear();
|
||||
|
||||
int x = stringMap["A"]; // A default-constructed int (i.e. 0) should be returned.
|
||||
EATEST_VERIFY(x == 0);
|
||||
|
||||
stringMap["B"] = 1;
|
||||
x = stringMap["B"];
|
||||
EATEST_VERIFY(x == 1); // Verify that the value we assigned is returned and a default-constructed value is not returned.
|
||||
|
||||
stringMap["A"] = 10; // Overwrite our previous 0 with 10.
|
||||
stringMap["B"] = 11;
|
||||
x = stringMap["A"];
|
||||
EATEST_VERIFY(x == 10); // Verify the value is as expected.
|
||||
x = stringMap["B"];
|
||||
EATEST_VERIFY(x == 11);
|
||||
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// string_map(const allocator_type& allocator);
|
||||
// string_map& operator=(const this_type& x);
|
||||
// bool validate() const;
|
||||
|
||||
string_map<int> stringMap1(EASTLAllocatorType("TestStringMap"));
|
||||
string_map<int> stringMap2(stringMap1);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
{
|
||||
stringMap1.insert(strings[i], i);
|
||||
}
|
||||
|
||||
stringMap2 = stringMap1;
|
||||
string_map<int> stringMap3(stringMap1);
|
||||
|
||||
EATEST_VERIFY(stringMap1.validate());
|
||||
EATEST_VERIFY(stringMap2.validate());
|
||||
EATEST_VERIFY(stringMap3.validate());
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
{
|
||||
EATEST_VERIFY(stringMap1[strings[i]] == stringMap2[strings[i]]);
|
||||
EATEST_VERIFY(stringMap1[strings[i]] == stringMap3[strings[i]]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EABase/eabase.h>
|
||||
#include <EASTL/numeric_limits.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/string_view.h>
|
||||
|
||||
// Verify char8_t support is present if the test build requested it.
|
||||
#if defined(EASTL_EXPECT_CHAR8T_SUPPORT) && !EA_CHAR8_UNIQUE
|
||||
static_assert(false, "Building with char8_t tests enabled, but EA_CHAR8_UNIQUE evaluates to false.");
|
||||
#endif
|
||||
|
||||
// this mess is required inorder to inject string literal string conversion macros into the unit tests
|
||||
#define TEST_STRING_NAME TestBasicStringView
|
||||
#define LITERAL(x) x
|
||||
#include "TestStringView.inl"
|
||||
|
||||
#define TEST_STRING_NAME TestBasicStringViewW
|
||||
#define LITERAL(x) EA_WCHAR(x)
|
||||
#include "TestStringView.inl"
|
||||
|
||||
#define TEST_STRING_NAME TestBasicStringView8
|
||||
#define LITERAL(x) EA_CHAR8(x)
|
||||
#include "TestStringView.inl"
|
||||
|
||||
#define TEST_STRING_NAME TestBasicStringView16
|
||||
#define LITERAL(x) EA_CHAR16(x)
|
||||
#include "TestStringView.inl"
|
||||
|
||||
#define TEST_STRING_NAME TestBasicStringView32
|
||||
#define LITERAL(x) EA_CHAR32(x)
|
||||
#include "TestStringView.inl"
|
||||
|
||||
|
||||
int TestStringView()
|
||||
{
|
||||
using namespace eastl;
|
||||
int nErrorCount = 0;
|
||||
|
||||
nErrorCount += TestBasicStringView<eastl::basic_string_view<char>>();
|
||||
nErrorCount += TestBasicStringView<eastl::string_view>();
|
||||
|
||||
nErrorCount += TestBasicStringViewW<eastl::basic_string_view<wchar_t>>();
|
||||
nErrorCount += TestBasicStringViewW<eastl::wstring_view>();
|
||||
|
||||
#if EA_CHAR8_UNIQUE
|
||||
nErrorCount += TestBasicStringView8<eastl::basic_string_view<char8_t>>();
|
||||
nErrorCount += TestBasicStringView8<eastl::u8string_view>();
|
||||
#endif
|
||||
|
||||
nErrorCount += TestBasicStringView16<eastl::basic_string_view<char16_t>>();
|
||||
nErrorCount += TestBasicStringView16<eastl::u16string_view>();
|
||||
|
||||
#if EA_CHAR32_NATIVE
|
||||
nErrorCount += TestBasicStringView32<eastl::basic_string_view<char32_t>>();
|
||||
nErrorCount += TestBasicStringView32<eastl::u32string_view>();
|
||||
#endif
|
||||
|
||||
|
||||
// constexpr string_view operator "" sv(const char* str, size_t len) noexcept;
|
||||
// constexpr u8string_view operator "" sv(const char8_t* str, size_t len) noexcept;
|
||||
// constexpr u16string_view operator "" sv(const char16_t* str, size_t len) noexcept;
|
||||
// constexpr u32string_view operator "" sv(const char32_t* str, size_t len) noexcept;
|
||||
// constexpr wstring_view operator "" sv(const wchar_t* str, size_t len) noexcept;
|
||||
#if EASTL_USER_LITERALS_ENABLED
|
||||
{
|
||||
VERIFY("cplusplus"_sv.compare("cplusplus") == 0);
|
||||
VERIFY(L"cplusplus"_sv.compare(L"cplusplus") == 0);
|
||||
VERIFY(u"cplusplus"_sv.compare(u"cplusplus") == 0);
|
||||
VERIFY(U"cplusplus"_sv.compare(U"cplusplus") == 0);
|
||||
VERIFY(u8"cplusplus"_sv.compare(u8"cplusplus") == 0);
|
||||
|
||||
static_assert(eastl::is_same_v<decltype("abcdef"_sv), eastl::string_view>, "string_view literal type mismatch");
|
||||
static_assert(eastl::is_same_v<decltype(u8"abcdef"_sv), eastl::u8string_view>, "string_view literal type mismatch");
|
||||
static_assert(eastl::is_same_v<decltype(u"abcdef"_sv), eastl::u16string_view>, "string_view literal type mismatch");
|
||||
static_assert(eastl::is_same_v<decltype(U"abcdef"_sv), eastl::u32string_view>, "string_view literal type mismatch");
|
||||
static_assert(eastl::is_same_v<decltype(L"abcdef"_sv), eastl::wstring_view>, "string_view literal type mismatch");
|
||||
|
||||
|
||||
VERIFY("cplusplus"sv.compare("cplusplus") == 0);
|
||||
VERIFY(L"cplusplus"sv.compare(L"cplusplus") == 0);
|
||||
VERIFY(u"cplusplus"sv.compare(u"cplusplus") == 0);
|
||||
VERIFY(U"cplusplus"sv.compare(U"cplusplus") == 0);
|
||||
VERIFY(u8"cplusplus"sv.compare(u8"cplusplus") == 0);
|
||||
|
||||
static_assert(eastl::is_same_v<decltype("abcdef"sv), eastl::string_view>, "string_view literal type mismatch");
|
||||
static_assert(eastl::is_same_v<decltype(u8"abcdef"sv), eastl::u8string_view>, "string_view literal type mismatch");
|
||||
static_assert(eastl::is_same_v<decltype(u"abcdef"sv), eastl::u16string_view>, "string_view literal type mismatch");
|
||||
static_assert(eastl::is_same_v<decltype(U"abcdef"sv), eastl::u32string_view>, "string_view literal type mismatch");
|
||||
static_assert(eastl::is_same_v<decltype(L"abcdef"sv), eastl::wstring_view>, "string_view literal type mismatch");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// strlen(char_t) compatibility
|
||||
{
|
||||
auto* pStr = "Hello, World";
|
||||
string_view sw(pStr, strlen(pStr));
|
||||
VERIFY(sw.size() == strlen(pStr));
|
||||
}
|
||||
|
||||
// strlen(wchar_t) compatibility
|
||||
{
|
||||
auto* pStr = L"Hello, World";
|
||||
wstring_view sw(pStr, wcslen(pStr));
|
||||
VERIFY(sw.size() == wcslen(pStr));
|
||||
}
|
||||
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,599 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename StringViewT>
|
||||
int TEST_STRING_NAME()
|
||||
{
|
||||
using StringT = eastl::basic_string<typename StringViewT::value_type>;
|
||||
|
||||
int nErrorCount = 0;
|
||||
{
|
||||
// EA_CONSTEXPR basic_string_view()
|
||||
{
|
||||
StringViewT sw;
|
||||
VERIFY(sw.empty());
|
||||
VERIFY(sw.data() == nullptr);
|
||||
VERIFY(sw.size() == 0);
|
||||
VERIFY(sw.size() == sw.length());
|
||||
}
|
||||
|
||||
// User-reported regression: constructing string_view from a nullptr, NULL, 0
|
||||
{
|
||||
{
|
||||
StringViewT sw(nullptr);
|
||||
VERIFY(sw.empty());
|
||||
VERIFY(sw.data() == nullptr);
|
||||
VERIFY(sw.size() == 0);
|
||||
VERIFY(sw.size() == sw.length());
|
||||
}
|
||||
{
|
||||
StringViewT sw(0);
|
||||
VERIFY(sw.empty());
|
||||
VERIFY(sw.data() == nullptr);
|
||||
VERIFY(sw.size() == 0);
|
||||
VERIFY(sw.size() == sw.length());
|
||||
}
|
||||
{
|
||||
StringViewT sw(NULL);
|
||||
VERIFY(sw.empty());
|
||||
VERIFY(sw.data() == nullptr);
|
||||
VERIFY(sw.size() == 0);
|
||||
VERIFY(sw.size() == sw.length());
|
||||
}
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR basic_string_view(const basic_string_view& other) = default;
|
||||
{
|
||||
auto* pLiteral = LITERAL("Hello, World");
|
||||
StringViewT sw1(pLiteral);
|
||||
StringViewT sw2(sw1);
|
||||
VERIFY(sw1.size() == sw2.size());
|
||||
VERIFY(eastl::Compare(sw1.data(), sw2.data(), sw1.size()) == 0);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR basic_string_view(const T* s, size_type count)
|
||||
{
|
||||
{
|
||||
StringViewT sw(LITERAL("Hello, World"), 12);
|
||||
VERIFY(!sw.empty());
|
||||
VERIFY(sw.data() != nullptr);
|
||||
VERIFY(sw.size() == 12);
|
||||
VERIFY(sw.size() == sw.length());
|
||||
}
|
||||
|
||||
{
|
||||
StringViewT sw(LITERAL("Hello, World"), 5);
|
||||
VERIFY(!sw.empty());
|
||||
VERIFY(sw.data() != nullptr);
|
||||
VERIFY(sw.size() == 5);
|
||||
VERIFY(sw.size() == sw.length());
|
||||
VERIFY(eastl::Compare(sw.data(), LITERAL("Hello"), sw.size()) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR basic_string_view(const T* s)
|
||||
{
|
||||
auto* pLiteral = LITERAL("Vancouver, Canada");
|
||||
StringViewT sw(pLiteral);
|
||||
VERIFY(!sw.empty());
|
||||
VERIFY(sw.data() != nullptr);
|
||||
VERIFY(sw.size() == 17);
|
||||
VERIFY(sw.size() == sw.length());
|
||||
VERIFY(eastl::Compare(sw.data(), pLiteral, sw.size()) == 0);
|
||||
}
|
||||
|
||||
// basic_string_view& operator=(const basic_string_view& view) = default;
|
||||
{
|
||||
auto* pLiteral = LITERAL("Hello, World");
|
||||
StringViewT sw1(pLiteral);
|
||||
StringViewT sw2;
|
||||
VERIFY(!sw1.empty());
|
||||
VERIFY(sw2.empty());
|
||||
|
||||
sw2 = sw1;
|
||||
|
||||
VERIFY(!sw1.empty());
|
||||
VERIFY(!sw2.empty());
|
||||
VERIFY(sw1.size() == sw2.size());
|
||||
VERIFY(eastl::Compare(sw1.data(), pLiteral, sw1.size()) == 0);
|
||||
VERIFY(eastl::Compare(sw2.data(), pLiteral, sw2.size()) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
// EA_CONSTEXPR const_iterator begin() const EA_NOEXCEPT
|
||||
// EA_CONSTEXPR const_iterator cbegin() const EA_NOEXCEPT
|
||||
StringViewT sw(LITERAL("abcdefg"));
|
||||
{
|
||||
auto i = sw.begin();
|
||||
auto ci = sw.cbegin();
|
||||
|
||||
VERIFY(*i++ == LITERAL('a'));
|
||||
VERIFY(*i++ == LITERAL('b'));
|
||||
|
||||
VERIFY(*ci++ == LITERAL('a'));
|
||||
VERIFY(*ci++ == LITERAL('b'));
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR const_iterator end() const EA_NOEXCEPT
|
||||
// EA_CONSTEXPR const_iterator cend() const EA_NOEXCEPT
|
||||
{
|
||||
auto i = sw.end();
|
||||
auto ci = sw.cend();
|
||||
|
||||
VERIFY(*i-- == LITERAL('\0'));
|
||||
VERIFY(*i-- == LITERAL('g'));
|
||||
|
||||
VERIFY(*ci-- == LITERAL('\0'));
|
||||
VERIFY(*ci-- == LITERAL('g'));
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR const_reverse_iterator rbegin() const EA_NOEXCEPT
|
||||
// EA_CONSTEXPR const_reverse_iterator crbegin() const EA_NOEXCEPT
|
||||
{
|
||||
auto i = sw.rbegin();
|
||||
auto ci = sw.crbegin();
|
||||
|
||||
VERIFY(*i++ == LITERAL('g'));
|
||||
VERIFY(*i++ == LITERAL('f'));
|
||||
|
||||
VERIFY(*ci++ == LITERAL('g'));
|
||||
VERIFY(*ci++ == LITERAL('f'));
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR const_reverse_iterator rend() const EA_NOEXCEPT
|
||||
// EA_CONSTEXPR const_reverse_iterator crend() const EA_NOEXCEPT
|
||||
{
|
||||
auto i = sw.rend();
|
||||
i--;
|
||||
|
||||
auto ci = sw.crend();
|
||||
ci--;
|
||||
|
||||
VERIFY(*i-- == LITERAL('a'));
|
||||
VERIFY(*i-- == LITERAL('b'));
|
||||
|
||||
VERIFY(*ci-- == LITERAL('a'));
|
||||
VERIFY(*ci-- == LITERAL('b'));
|
||||
}
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR const_pointer data() const
|
||||
{
|
||||
auto* pLiteral = LITERAL("Vancouver, Canada");
|
||||
StringViewT sw(pLiteral);
|
||||
VERIFY(sw.data() != nullptr);
|
||||
VERIFY(eastl::Compare(sw.data(), pLiteral, sw.size()) == 0);
|
||||
VERIFY(eastl::Compare(sw.data() + 11, LITERAL("Canada"), 6) == 0);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR const_reference front() const
|
||||
// EA_CONSTEXPR const_reference back() const
|
||||
{
|
||||
{
|
||||
StringViewT sw(LITERAL("Vancouver, Canada"));
|
||||
VERIFY(sw.front() == LITERAL('V'));
|
||||
VERIFY(sw.back() == LITERAL('a'));
|
||||
|
||||
}
|
||||
{
|
||||
StringViewT sw(LITERAL("Canada"));
|
||||
VERIFY(sw.front() == LITERAL('C'));
|
||||
VERIFY(sw.back() == LITERAL('a'));
|
||||
}
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR const_reference operator[](size_type pos) const
|
||||
{
|
||||
StringViewT sw(LITERAL("Vancouver"));
|
||||
VERIFY(sw[0] == LITERAL('V'));
|
||||
VERIFY(sw[1] == LITERAL('a'));
|
||||
VERIFY(sw[2] == LITERAL('n'));
|
||||
VERIFY(sw[3] == LITERAL('c'));
|
||||
VERIFY(sw[4] == LITERAL('o'));
|
||||
VERIFY(sw[5] == LITERAL('u'));
|
||||
VERIFY(sw[6] == LITERAL('v'));
|
||||
VERIFY(sw[7] == LITERAL('e'));
|
||||
VERIFY(sw[8] == LITERAL('r'));
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR size_type size() const EA_NOEXCEPT
|
||||
// EA_CONSTEXPR size_type length() const EA_NOEXCEPT
|
||||
// EA_CONSTEXPR size_type max_size() const EA_NOEXCEPT
|
||||
// EA_CONSTEXPR bool empty() const EA_NOEXCEPT
|
||||
{
|
||||
StringViewT sw(LITERAL("http://en.cppreference.com/w/cpp/header/string_view"));
|
||||
VERIFY(sw.size() == 51);
|
||||
VERIFY(sw.length() == 51);
|
||||
VERIFY(sw.max_size() == eastl::numeric_limits<typename StringViewT::size_type>::max());
|
||||
VERIFY(!sw.empty());
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR void swap(basic_string_view& v)
|
||||
{
|
||||
auto* pV = LITERAL("Vancouver");
|
||||
auto* pC = LITERAL("Canada");
|
||||
StringViewT sw1(pV);
|
||||
StringViewT sw2(pC);
|
||||
sw1.swap(sw2);
|
||||
VERIFY(eastl::Compare(sw1.data(), pC, sw1.size()) == 0);
|
||||
VERIFY(eastl::Compare(sw2.data(), pV, sw2.size()) == 0);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR void remove_prefix(size_type n)
|
||||
// EA_CONSTEXPR void remove_suffix(size_type n)
|
||||
{
|
||||
StringViewT sw(LITERAL("Vancouver"));
|
||||
sw.remove_prefix(3);
|
||||
VERIFY(eastl::Compare(sw.data(), LITERAL("couver"), sw.size()) == 0);
|
||||
VERIFY(sw.size() == 6);
|
||||
|
||||
sw.remove_prefix(3);
|
||||
VERIFY(eastl::Compare(sw.data(), LITERAL("ver"), sw.size()) == 0);
|
||||
VERIFY(sw.size() == 3);
|
||||
|
||||
sw.remove_suffix(1);
|
||||
VERIFY(eastl::Compare(sw.data(), LITERAL("ve"), sw.size()) == 0);
|
||||
VERIFY(sw.size() == 2);
|
||||
|
||||
sw.remove_suffix(1);
|
||||
VERIFY(eastl::Compare(sw.data(), LITERAL("v"), sw.size()) == 0);
|
||||
VERIFY(sw.size() == 1);
|
||||
|
||||
sw.remove_suffix(1);
|
||||
VERIFY(eastl::Compare(sw.data(), LITERAL(""), sw.size()) == 0);
|
||||
VERIFY(sw.size() == 0);
|
||||
}
|
||||
|
||||
// size_type copy(T* s, size_type n, size_type pos = 0) const;
|
||||
{
|
||||
typename StringViewT::value_type buf[256];
|
||||
StringViewT sw(LITERAL("**Hello, World"));
|
||||
auto cnt = sw.copy(buf, 5, 2);
|
||||
VERIFY(eastl::Compare(buf, LITERAL("Hello"), 5) == 0);
|
||||
VERIFY(cnt == 5);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR basic_string_view substr(size_type pos = 0, size_type n = npos) const;
|
||||
{
|
||||
StringViewT sw(LITERAL("**Hello, World"));
|
||||
auto sw2 = sw.substr(2, 5);
|
||||
VERIFY(eastl::Compare(sw2.data(), LITERAL("Hello"), sw2.size()) == 0);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR int compare(basic_string_view s) const EA_NOEXCEPT;
|
||||
{
|
||||
{
|
||||
VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("A"))) == 0);
|
||||
VERIFY(StringViewT(LITERAL("a")).compare(StringViewT(LITERAL("a"))) == 0);
|
||||
VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("a"))) != 0);
|
||||
VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("a"))) < 0);
|
||||
VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("A"))) <= 0);
|
||||
VERIFY(StringViewT(LITERAL("a")).compare(StringViewT(LITERAL("A"))) > 0);
|
||||
VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("A"))) >= 0);
|
||||
}
|
||||
|
||||
{
|
||||
VERIFY(StringViewT(LITERAL("Aa")).compare(StringViewT(LITERAL("A"))) > 0);
|
||||
VERIFY(StringViewT(LITERAL("A")).compare(StringViewT(LITERAL("Aa"))) < 0);
|
||||
}
|
||||
|
||||
{
|
||||
StringViewT sw1(LITERAL("Hello, World"));
|
||||
StringViewT sw2(LITERAL("Hello, WWorld"));
|
||||
StringViewT sw3(LITERAL("Hello, Wzorld"));
|
||||
VERIFY(sw1.compare(sw1) == 0);
|
||||
VERIFY(sw1.compare(sw2) > 0);
|
||||
VERIFY(sw1.compare(sw3) < 0);
|
||||
}
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR int compare(size_type pos1, size_type n1, basic_string_view s) const;
|
||||
{
|
||||
StringViewT sw1(LITERAL("*** Hello ***"));
|
||||
StringViewT sw2(LITERAL("Hello"));
|
||||
VERIFY(sw1.compare(4, 5, sw2) == 0);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR int compare(size_type pos1, size_type n1, basic_string_view s, size_type pos2, size_type n2) const;
|
||||
{
|
||||
StringViewT sw(LITERAL("Vancouver"));
|
||||
VERIFY(sw.compare(0, 3, StringViewT(LITERAL("Van")), 0, 3) == 0);
|
||||
VERIFY(sw.compare(6, 3, StringViewT(LITERAL("ver")), 0, 3) == 0);
|
||||
VERIFY(sw.compare(0, 3, StringViewT(LITERAL("Tan")), 0, 3) != 0);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR int compare(const T* s) const;
|
||||
{
|
||||
StringViewT sw(LITERAL("Hello"));
|
||||
VERIFY(sw.compare(LITERAL("Vancouver")) != 0);
|
||||
VERIFY(sw.compare(LITERAL("Vancouver!")) != 0);
|
||||
VERIFY(sw.compare(LITERAL("Hello")) == 0);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR int compare(size_type pos1, size_type n1, const T* s) const;
|
||||
{
|
||||
StringViewT sw(LITERAL("*** Hello"));
|
||||
VERIFY(sw.compare(4, 5, LITERAL("Hello")) == 0);
|
||||
VERIFY(sw.compare(4, 5, LITERAL("Hello 555")) != 0);
|
||||
VERIFY(sw.compare(4, 5, LITERAL("hello")) != 0);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR int compare(size_type pos1, size_type n1, const T* s, size_type n2) const;
|
||||
{
|
||||
StringViewT sw(LITERAL("*** Hello ***"));
|
||||
VERIFY(sw.compare(4, 5, LITERAL("Hello"), 5) == 0);
|
||||
VERIFY(sw.compare(0, 1, LITERAL("*"), 1) == 0);
|
||||
VERIFY(sw.compare(0, 2, LITERAL("**"), 1) != 0);
|
||||
VERIFY(sw.compare(0, 2, LITERAL("**"), 2) == 0);
|
||||
VERIFY(sw.compare(0, 2, LITERAL("^^"), 2) != 0);
|
||||
}
|
||||
|
||||
|
||||
// EA_CONSTEXPR size_type find(basic_string_view s, size_type pos = 0) const EA_NOEXCEPT;
|
||||
{
|
||||
StringViewT sw(LITERAL("*** Hello ***"));
|
||||
VERIFY(sw.find(StringViewT(LITERAL("Hello"))) != StringViewT::npos);
|
||||
VERIFY(sw.find(StringViewT(LITERAL("ell"))) != StringViewT::npos);
|
||||
VERIFY(sw.find(StringViewT(LITERAL("FailToFindMe"))) == StringViewT::npos);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR size_type find(T c, size_type pos = 0) const EA_NOEXCEPT;
|
||||
{
|
||||
StringViewT sw(LITERAL("*** Hello ***"));
|
||||
VERIFY(sw.find(LITERAL("H")) == 4);
|
||||
VERIFY(sw.find(LITERAL("e")) == 5);
|
||||
VERIFY(sw.find(LITERAL("l")) == 6);
|
||||
VERIFY(sw.find(LITERAL("o")) == 8);
|
||||
VERIFY(sw.find(LITERAL("&")) == StringViewT::npos);
|
||||
VERIFY(sw.find(LITERAL("@")) == StringViewT::npos);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR size_type find(const T* s, size_type pos, size_type n) const;
|
||||
{
|
||||
StringViewT sw(LITERAL("Hello, Vancouver"));
|
||||
VERIFY(sw.find(LITERAL("Hello"), 0, 3) != StringViewT::npos);
|
||||
VERIFY(sw.find(LITERAL("Hello"), 3, 3) == StringViewT::npos);
|
||||
VERIFY(sw.find(LITERAL("Vancouv"), 7, 7) != StringViewT::npos);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR size_type find(const T* s, size_type pos = 0) const;
|
||||
{
|
||||
StringViewT sw(LITERAL("Hello, Vancouver"));
|
||||
VERIFY(sw.find(LITERAL("Hello"), 0) != StringViewT::npos);
|
||||
VERIFY(sw.find(LITERAL("Hello"), 3) == StringViewT::npos);
|
||||
VERIFY(sw.find(LITERAL("Vancouv"), 7) != StringViewT::npos);
|
||||
}
|
||||
|
||||
|
||||
// EA_CONSTEXPR size_type rfind(basic_string_view s, size_type pos = npos) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type rfind(T c, size_type pos = npos) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type rfind(const T* s, size_type pos, size_type n) const;
|
||||
// EA_CONSTEXPR size_type rfind(const T* s, size_type pos = npos) const;
|
||||
{
|
||||
StringViewT str(LITERAL("abcdefghijklmnopqrstuvwxyz"));
|
||||
|
||||
VERIFY(str.rfind(StringViewT(LITERAL("d"))) != StringViewT::npos);
|
||||
VERIFY(str.rfind(StringViewT(LITERAL("tuv"))) != StringViewT::npos);
|
||||
VERIFY(str.rfind(StringViewT(LITERAL("123r"))) == StringViewT::npos);
|
||||
|
||||
VERIFY(str.rfind(LITERAL("d")) != StringViewT::npos);
|
||||
VERIFY(str.rfind(LITERAL("tuv")) != StringViewT::npos);
|
||||
VERIFY(str.rfind(LITERAL("123r")) == StringViewT::npos);
|
||||
|
||||
VERIFY(str.rfind(LITERAL("d"), str.length()) != StringViewT::npos);
|
||||
VERIFY(str.rfind(LITERAL("tuv"), str.length() - 2) != StringViewT::npos);
|
||||
VERIFY(str.rfind(LITERAL("123r"), str.length() - 2) == StringViewT::npos);
|
||||
|
||||
VERIFY(str.rfind(LITERAL('d'), str.length() - 0) != StringViewT::npos);
|
||||
VERIFY(str.rfind(LITERAL('t'), str.length() - 2) != StringViewT::npos);
|
||||
VERIFY(str.rfind(LITERAL('1'), str.length() - 2) == StringViewT::npos);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR size_type find_first_of(basic_string_view s, size_type pos = 0) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type find_first_of(T c, size_type pos = 0) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type find_first_of(const T* s, size_type pos, size_type n) const;
|
||||
// EA_CONSTEXPR size_type find_first_of(const T* s, size_type pos = 0) const;
|
||||
{
|
||||
StringViewT str(LITERAL("aaaaabbbbbcccdddddeeeeefffggh"));
|
||||
|
||||
VERIFY(str.find_first_of(StringViewT(LITERAL("aaa"))) == 0);
|
||||
VERIFY(str.find_first_of(LITERAL("aab")) == 0);
|
||||
VERIFY(str.find_first_of(LITERAL("baab")) == 0);
|
||||
VERIFY(str.find_first_of(LITERAL("ceg")) == 10);
|
||||
VERIFY(str.find_first_of(LITERAL("eeef"), 1, 2) == 18);
|
||||
VERIFY(str.find_first_of(LITERAL("eeef"), 1, 4) == 18);
|
||||
VERIFY(str.find_first_of(LITERAL('g')) == 26);
|
||||
VERIFY(str.find_first_of(LITERAL('$')) == StringViewT::npos);
|
||||
VERIFY(str.find_first_of(StringViewT(LITERAL(" a"), 1)) == StringViewT::npos);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR size_type find_last_of(basic_string_view s, size_type pos = npos) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type find_last_of(T c, size_type pos = npos) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type find_last_of(const T* s, size_type pos, size_type n) const;
|
||||
// EA_CONSTEXPR size_type find_last_of(const T* s, size_type pos = npos) const;
|
||||
{
|
||||
StringViewT str(LITERAL("aaaaabbbbbcccdddddeeeeefffggh"));
|
||||
|
||||
VERIFY(str.find_last_of(StringViewT(LITERAL("aaa"))) == 4);
|
||||
VERIFY(str.find_last_of(LITERAL("aab")) == 9);
|
||||
VERIFY(str.find_last_of(LITERAL("baab")) == 9);
|
||||
VERIFY(str.find_last_of(LITERAL("ceg")) == 27);
|
||||
// VERIFY(str.find_last_of(LITERAL("eeef"), 1, 2) == StringViewT::npos); // todo: FIX ME
|
||||
// VERIFY(str.find_last_of(LITERAL("eeef"), 1, 4) == StringViewT::npos); // todo: FIX ME
|
||||
VERIFY(str.find_last_of(LITERAL('g')) == 27);
|
||||
VERIFY(str.find_last_of(LITERAL('$')) == StringViewT::npos);
|
||||
}
|
||||
|
||||
// EA_CONSTEXPR size_type find_first_not_of(basic_string_view s, size_type pos = 0) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type find_first_not_of(T c, size_type pos = 0) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type find_first_not_of(const T* s, size_type pos, size_type n) const;
|
||||
// EA_CONSTEXPR size_type find_first_not_of(const T* s, size_type pos = 0) const;
|
||||
{
|
||||
StringViewT str(LITERAL("aaaaabbbbbcccdddddeeeeefffggh"));
|
||||
|
||||
VERIFY(str.find_first_not_of(StringViewT(LITERAL("abcdfg"))) == 18);
|
||||
VERIFY(str.find_first_not_of(LITERAL("abcdfg")) == 18);
|
||||
// VERIFY(str.find_first_not_of(LITERAL("abcdfg"), 2, 2) == 0); // todo: FIX ME
|
||||
// VERIFY(str.find_first_not_of(LITERAL("abcdfg"), 0, 2) == 10); // todo: FIX ME
|
||||
VERIFY(str.find_first_not_of(LITERAL('a')) == 5);
|
||||
}
|
||||
|
||||
|
||||
// EA_CONSTEXPR size_type find_last_not_of(basic_string_view s, size_type pos = npos) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type find_last_not_of(T c, size_type pos = npos) const EA_NOEXCEPT;
|
||||
// EA_CONSTEXPR size_type find_last_not_of(const T* s, size_type pos, size_type n) const;
|
||||
// EA_CONSTEXPR size_type find_last_not_of(const T* s, size_type pos = npos) const;
|
||||
{
|
||||
StringViewT str(LITERAL("aaaaabbbbbcccdddddeeeeefffggh"));
|
||||
|
||||
VERIFY(str.find_last_not_of(StringViewT(LITERAL("a"))) == 28);
|
||||
VERIFY(str.find_last_not_of(StringViewT(LITERAL("abcdfg"))) == 28);
|
||||
VERIFY(str.find_last_not_of(StringViewT(LITERAL("abcdfgh"))) == 22);
|
||||
VERIFY(str.find_last_not_of(LITERAL("abcdfgh")) == 22);
|
||||
// VERIFY(str.find_last_not_of(LITERAL("abcdfg"), 2, 2) == 0); // todo: FIX ME
|
||||
// VERIFY(str.find_last_not_of(LITERAL("abcdfg"), 0, 2) == 10); // todo: FIX ME
|
||||
VERIFY(str.find_last_not_of(LITERAL('a')) == 28);
|
||||
}
|
||||
|
||||
// template <class CharT, class Traits>
|
||||
// constexpr bool operator==(basic_string_view<CharT, Traits> lhs, basic_string_view<CharT, Traits> rhs);
|
||||
// template <class CharT, class Traits>
|
||||
// constexpr bool operator!=(basic_string_view<CharT, Traits> lhs, basic_string_view<CharT, Traits> rhs);
|
||||
// template <class CharT, class Traits>
|
||||
// constexpr bool operator<(basic_string_view<CharT, Traits> lhs, basic_string_view<CharT, Traits> rhs);
|
||||
// template <class CharT, class Traits>
|
||||
// constexpr bool operator<=(basic_string_view<CharT, Traits> lhs, basic_string_view<CharT, Traits> rhs);
|
||||
// template <class CharT, class Traits>
|
||||
// constexpr bool operator>(basic_string_view<CharT, Traits> lhs, basic_string_view<CharT, Traits> rhs);
|
||||
// template <class CharT, class Traits>
|
||||
// constexpr bool operator>=(basic_string_view<CharT, Traits> lhs, basic_string_view<CharT, Traits> rhs);
|
||||
{
|
||||
StringViewT sw1(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH"));
|
||||
StringViewT sw2(LITERAL("aaaaabbbbbcccdddddeeeeefffggh"));
|
||||
|
||||
VERIFY(sw1 == StringViewT(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH")));
|
||||
VERIFY(sw1 != StringViewT(LITERAL("abcdefghijklmnopqrstuvwxyz")));
|
||||
VERIFY(sw1 < sw2);
|
||||
VERIFY(sw1 <= sw2);
|
||||
VERIFY(sw2 > sw1);
|
||||
VERIFY(sw2 >= sw1);
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
VERIFY((sw1 <=> StringViewT(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH"))) == 0);
|
||||
VERIFY((sw1 <=> StringViewT(LITERAL("abcdefghijklmnopqrstuvwxyz"))) != 0);
|
||||
VERIFY((sw1 <=> sw2) < 0);
|
||||
VERIFY((sw1 <=> sw2) <= 0);
|
||||
VERIFY((sw2 <=> sw1) > 0);
|
||||
VERIFY((sw2 <=> sw1) >= 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
auto s = LITERAL("Hello, World");
|
||||
StringViewT sv(s);
|
||||
|
||||
VERIFY(s == sv);
|
||||
VERIFY(sv == s);
|
||||
|
||||
VERIFY(s <= sv);
|
||||
VERIFY(sv <= s);
|
||||
VERIFY(s >= sv);
|
||||
VERIFY(sv >= s);
|
||||
VERIFY(!(s != sv));
|
||||
VERIFY(!(sv != s));
|
||||
VERIFY(!(s < sv));
|
||||
VERIFY(!(sv < s));
|
||||
VERIFY(!(s > sv));
|
||||
VERIFY(!(sv > s));
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
VERIFY((s <=> sv) == 0);
|
||||
VERIFY((sv <=> s) == 0);
|
||||
|
||||
VERIFY((s <=> sv) <= 0);
|
||||
VERIFY((sv <=> s) <= 0);
|
||||
VERIFY((s <=> sv) >= 0);
|
||||
VERIFY((sv <=> s) >= 0);
|
||||
VERIFY(!((s <=> sv) != 0));
|
||||
VERIFY(!((sv <=> s) != 0));
|
||||
VERIFY(!((s <=> sv) > 0));
|
||||
VERIFY(!((sv <=> s) < 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Regression comparison operators should work between basic_string_view and basic_string.
|
||||
// The idea is that type_identity_t on some overloads will force basic_string::operator basic_string_view() to kick in.
|
||||
{
|
||||
StringT s(LITERAL("Hello, Stockholm"));
|
||||
StringViewT sv(s);
|
||||
|
||||
VERIFY(s == sv);
|
||||
VERIFY(sv == s);
|
||||
|
||||
// All the operators bellow used to not work.
|
||||
VERIFY(s <= sv);
|
||||
VERIFY(sv <= s);
|
||||
VERIFY(s >= sv);
|
||||
VERIFY(sv >= s);
|
||||
VERIFY(!(s != sv));
|
||||
VERIFY(!(sv != s));
|
||||
VERIFY(!(s < sv));
|
||||
VERIFY(!(sv < s));
|
||||
VERIFY(!(s > sv));
|
||||
VERIFY(!(sv > s));
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
VERIFY((s <=> sv) == 0);
|
||||
VERIFY((sv <=> s) == 0);
|
||||
|
||||
VERIFY((s <=> sv) <= 0);
|
||||
VERIFY((sv <=> s) <= 0);
|
||||
VERIFY((s <=> sv) >= 0);
|
||||
VERIFY((sv <=> s) >= 0);
|
||||
VERIFY(!((s <=> sv) != 0));
|
||||
VERIFY(!((sv <=> s) != 0));
|
||||
VERIFY(!((s <=> sv) > 0));
|
||||
VERIFY(!((sv <=> s) < 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
// template<> struct hash<std::string_view>;
|
||||
// template<> struct hash<std::wstring_view>;
|
||||
// template<> struct hash<std::u16string_view>;
|
||||
// template<> struct hash<std::u32string_view>;
|
||||
{
|
||||
StringViewT sw1(LITERAL("Hello, World"));
|
||||
StringViewT sw2(LITERAL("Hello, World"), 5);
|
||||
StringViewT sw3(LITERAL("Hello"));
|
||||
auto s = LITERAL("Hello");
|
||||
|
||||
VERIFY(eastl::hash<StringViewT>{}(sw1) != eastl::hash<StringViewT>{}(sw2));
|
||||
VERIFY(eastl::hash<StringViewT>{}(sw2) == eastl::hash<StringViewT>{}(sw3));
|
||||
VERIFY(eastl::hash<StringViewT>{}(sw3) == eastl::hash<decltype(s)>{}(s));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
StringViewT sw1(LITERAL("AAAAABBBBBCCCDDDDDEEEEEFFFGGH"));
|
||||
|
||||
VERIFY( sw1.starts_with(LITERAL('A')));
|
||||
VERIFY(!sw1.starts_with(LITERAL('X')));
|
||||
VERIFY( sw1.starts_with(LITERAL("AAAA")));
|
||||
VERIFY( sw1.starts_with(StringViewT(LITERAL("AAAA"))));
|
||||
VERIFY(!sw1.starts_with(LITERAL("AAAB")));
|
||||
|
||||
VERIFY( sw1.ends_with(LITERAL('H')));
|
||||
VERIFY(!sw1.ends_with(LITERAL('X')));
|
||||
VERIFY( sw1.ends_with(LITERAL("FGGH")));
|
||||
VERIFY( sw1.ends_with(StringViewT(LITERAL("FGGH"))));
|
||||
VERIFY(!sw1.ends_with(LITERAL("FGGH$")));
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
// Required to prevent manual undef of macros when 'TestString.inl' preprocessed at the top of the unit test cpp file.
|
||||
#undef TEST_STRING_NAME
|
||||
#undef LITERAL
|
||||
|
||||
@@ -0,0 +1,587 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
|
||||
EA_DISABLE_VC_WARNING(4623 4625 4413 4510)
|
||||
|
||||
#include <EASTL/tuple.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
|
||||
#if EASTL_TUPLE_ENABLED
|
||||
|
||||
namespace TestTupleInternal
|
||||
{
|
||||
|
||||
struct DefaultConstructibleType
|
||||
{
|
||||
static const int defaultVal = 0x1EE7C0DE;
|
||||
DefaultConstructibleType() : mVal(defaultVal) {}
|
||||
int mVal;
|
||||
};
|
||||
|
||||
struct OperationCountingType
|
||||
{
|
||||
OperationCountingType() : mVal() { ++mDefaultConstructorCalls; }
|
||||
OperationCountingType(int x) : mVal(x) { ++mIntConstructorCalls; }
|
||||
OperationCountingType(const OperationCountingType& x) : mVal(x.mVal) { ++mCopyConstructorCalls; }
|
||||
OperationCountingType(OperationCountingType&& x) : mVal(x.mVal)
|
||||
{
|
||||
++mMoveConstructorCalls;
|
||||
x.mVal = 0;
|
||||
}
|
||||
OperationCountingType& operator=(const OperationCountingType& x)
|
||||
{
|
||||
mVal = x.mVal;
|
||||
++mCopyAssignmentCalls;
|
||||
return *this;
|
||||
}
|
||||
OperationCountingType& operator=(OperationCountingType&& x)
|
||||
{
|
||||
mVal = x.mVal;
|
||||
x.mVal = 0;
|
||||
++mMoveAssignmentCalls;
|
||||
return *this;
|
||||
}
|
||||
~OperationCountingType() { ++mDestructorCalls; }
|
||||
|
||||
int mVal;
|
||||
|
||||
static void ResetCounters()
|
||||
{
|
||||
mDefaultConstructorCalls = 0;
|
||||
mIntConstructorCalls = 0;
|
||||
mCopyConstructorCalls = 0;
|
||||
mMoveConstructorCalls = 0;
|
||||
mCopyAssignmentCalls = 0;
|
||||
mMoveAssignmentCalls = 0;
|
||||
mDestructorCalls = 0;
|
||||
}
|
||||
|
||||
static int mDefaultConstructorCalls;
|
||||
static int mIntConstructorCalls;
|
||||
static int mCopyConstructorCalls;
|
||||
static int mMoveConstructorCalls;
|
||||
static int mCopyAssignmentCalls;
|
||||
static int mMoveAssignmentCalls;
|
||||
static int mDestructorCalls;
|
||||
};
|
||||
|
||||
int OperationCountingType::mDefaultConstructorCalls = 0;
|
||||
int OperationCountingType::mIntConstructorCalls = 0;
|
||||
int OperationCountingType::mCopyConstructorCalls = 0;
|
||||
int OperationCountingType::mMoveConstructorCalls = 0;
|
||||
int OperationCountingType::mCopyAssignmentCalls = 0;
|
||||
int OperationCountingType::mMoveAssignmentCalls = 0;
|
||||
int OperationCountingType::mDestructorCalls = 0;
|
||||
|
||||
} // namespace TestTupleInternal
|
||||
|
||||
int TestTuple()
|
||||
{
|
||||
using namespace eastl;
|
||||
using namespace TestTupleInternal;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
static_assert(tuple_size<tuple<int>>::value == 1, "tuple_size<tuple<T>> test failed.");
|
||||
static_assert(tuple_size<const tuple<int>>::value == 1, "tuple_size<const tuple<T>> test failed.");
|
||||
static_assert(tuple_size<const tuple<const int>>::value == 1, "tuple_size<const tuple<const T>> test failed.");
|
||||
static_assert(tuple_size<volatile tuple<int>>::value == 1, "tuple_size<volatile tuple<T>> test failed.");
|
||||
static_assert(tuple_size<const volatile tuple<int>>::value == 1, "tuple_size<const volatile tuple<T>> test failed.");
|
||||
static_assert(tuple_size<tuple<int, float, bool>>::value == 3, "tuple_size<tuple<T, T, T>> test failed.");
|
||||
|
||||
static_assert(is_same<tuple_element_t<0, tuple<int>>, int>::value, "tuple_element<I, T> test failed.");
|
||||
static_assert(is_same<tuple_element_t<1, tuple<float, int>>, int>::value, "tuple_element<I, T> test failed.");
|
||||
static_assert(is_same<tuple_element_t<1, tuple<float, const int>>, const int>::value, "tuple_element<I, T> test failed.");
|
||||
static_assert(is_same<tuple_element_t<1, tuple<float, volatile int>>, volatile int>::value, "tuple_element<I, T> test failed.");
|
||||
static_assert(is_same<tuple_element_t<1, tuple<float, const volatile int>>, const volatile int>::value, "tuple_element<I, T> test failed.");
|
||||
static_assert(is_same<tuple_element_t<1, tuple<float, int&>>, int&>::value, "tuple_element<I, T> test failed.");
|
||||
|
||||
{
|
||||
tuple<int> aSingleElementTuple(1);
|
||||
EATEST_VERIFY(get<0>(aSingleElementTuple) == 1);
|
||||
get<0>(aSingleElementTuple) = 2;
|
||||
EATEST_VERIFY(get<0>(aSingleElementTuple) == 2);
|
||||
get<int>(aSingleElementTuple) = 3;
|
||||
EATEST_VERIFY(get<int>(aSingleElementTuple) == 3);
|
||||
|
||||
const tuple<int> aConstSingleElementTuple(3);
|
||||
EATEST_VERIFY(get<0>(aConstSingleElementTuple) == 3);
|
||||
EATEST_VERIFY(get<int>(aConstSingleElementTuple) == 3);
|
||||
|
||||
tuple<DefaultConstructibleType> aDefaultConstructedTuple;
|
||||
EATEST_VERIFY(get<0>(aDefaultConstructedTuple).mVal == DefaultConstructibleType::defaultVal);
|
||||
|
||||
OperationCountingType::ResetCounters();
|
||||
tuple<OperationCountingType> anOperationCountingTuple;
|
||||
EATEST_VERIFY(OperationCountingType::mDefaultConstructorCalls == 1 &&
|
||||
get<0>(anOperationCountingTuple).mVal == 0);
|
||||
get<0>(anOperationCountingTuple).mVal = 1;
|
||||
tuple<OperationCountingType> anotherOperationCountingTuple(anOperationCountingTuple);
|
||||
EATEST_VERIFY(OperationCountingType::mDefaultConstructorCalls == 1 &&
|
||||
OperationCountingType::mCopyConstructorCalls == 1 &&
|
||||
get<0>(anotherOperationCountingTuple).mVal == 1);
|
||||
get<0>(anOperationCountingTuple).mVal = 2;
|
||||
anotherOperationCountingTuple = anOperationCountingTuple;
|
||||
EATEST_VERIFY(
|
||||
OperationCountingType::mDefaultConstructorCalls == 1 && OperationCountingType::mCopyConstructorCalls == 1 &&
|
||||
OperationCountingType::mCopyAssignmentCalls == 1 && get<0>(anotherOperationCountingTuple).mVal == 2);
|
||||
|
||||
OperationCountingType::ResetCounters();
|
||||
tuple<OperationCountingType> yetAnotherOperationCountingTuple(OperationCountingType(5));
|
||||
EATEST_VERIFY(
|
||||
OperationCountingType::mMoveConstructorCalls == 1 && OperationCountingType::mDefaultConstructorCalls == 0 &&
|
||||
OperationCountingType::mCopyConstructorCalls == 0 && get<0>(yetAnotherOperationCountingTuple).mVal == 5);
|
||||
}
|
||||
|
||||
EATEST_VERIFY(OperationCountingType::mDestructorCalls == 4);
|
||||
|
||||
{
|
||||
// Test constructor
|
||||
tuple<int, float, bool> aTuple(1, 1.0f, true);
|
||||
EATEST_VERIFY(get<0>(aTuple) == 1);
|
||||
EATEST_VERIFY(get<1>(aTuple) == 1.0f);
|
||||
EATEST_VERIFY(get<2>(aTuple) == true);
|
||||
EATEST_VERIFY(get<int>(aTuple) == 1);
|
||||
EATEST_VERIFY(get<float>(aTuple) == 1.0f);
|
||||
EATEST_VERIFY(get<bool>(aTuple) == true);
|
||||
|
||||
get<1>(aTuple) = 2.0f;
|
||||
EATEST_VERIFY(get<1>(aTuple) == 2.0f);
|
||||
|
||||
// Test copy constructor
|
||||
tuple<int, float, bool> anotherTuple(aTuple);
|
||||
EATEST_VERIFY(get<0>(anotherTuple) == 1 && get<1>(anotherTuple) == 2.0f && get<2>(anotherTuple) == true);
|
||||
|
||||
// Test copy assignment
|
||||
tuple<int, float, bool> yetAnotherTuple(2, 3.0f, true);
|
||||
EATEST_VERIFY(get<0>(yetAnotherTuple) == 2 && get<1>(yetAnotherTuple) == 3.0f &&
|
||||
get<2>(yetAnotherTuple) == true);
|
||||
yetAnotherTuple = anotherTuple;
|
||||
EATEST_VERIFY(get<0>(yetAnotherTuple) == 1 && get<1>(yetAnotherTuple) == 2.0f &&
|
||||
get<2>(yetAnotherTuple) == true);
|
||||
|
||||
// Test converting 'copy' constructor (from a tuple of different type whose members are each convertible)
|
||||
tuple<double, double, bool> aDifferentTuple(aTuple);
|
||||
EATEST_VERIFY(get<0>(aDifferentTuple) == 1.0 && get<1>(aDifferentTuple) == 2.0 &&
|
||||
get<2>(aDifferentTuple) == true);
|
||||
|
||||
// Test converting assignment operator (from a tuple of different type whose members are each convertible)
|
||||
tuple<double, double, bool> anotherDifferentTuple;
|
||||
EATEST_VERIFY(get<0>(anotherDifferentTuple) == 0.0 && get<1>(anotherDifferentTuple) == 0.0 &&
|
||||
get<2>(anotherDifferentTuple) == false);
|
||||
anotherDifferentTuple = anotherTuple;
|
||||
EATEST_VERIFY(get<0>(anotherDifferentTuple) == 1.0 && get<1>(anotherDifferentTuple) == 2.0 &&
|
||||
get<2>(anotherDifferentTuple) == true);
|
||||
|
||||
// Test default initialization (built in types should be value initialized rather than default initialized)
|
||||
tuple<int, float, bool> aDefaultInitializedTuple;
|
||||
EATEST_VERIFY(get<0>(aDefaultInitializedTuple) == 0 && get<1>(aDefaultInitializedTuple) == 0.0f &&
|
||||
get<2>(aDefaultInitializedTuple) == false);
|
||||
}
|
||||
|
||||
{
|
||||
// Test some other cases with typed-getter
|
||||
tuple<double, double, bool> aTupleWithRepeatedType(1.0f, 2.0f, true);
|
||||
EATEST_VERIFY(get<bool>(aTupleWithRepeatedType) == true);
|
||||
|
||||
tuple<double, bool, double> anotherTupleWithRepeatedType(1.0f, true, 2.0f);
|
||||
EATEST_VERIFY(get<bool>(anotherTupleWithRepeatedType) == true);
|
||||
|
||||
tuple<bool, double, double> yetAnotherTupleWithRepeatedType(true, 1.0f, 2.0f);
|
||||
EATEST_VERIFY(get<bool>(anotherTupleWithRepeatedType) == true);
|
||||
|
||||
struct floatOne { float val; };
|
||||
struct floatTwo { float val; };
|
||||
tuple<floatOne, floatTwo> aTupleOfStructs({ 1.0f }, { 2.0f } );
|
||||
EATEST_VERIFY(get<floatOne>(aTupleOfStructs).val == 1.0f);
|
||||
EATEST_VERIFY(get<floatTwo>(aTupleOfStructs).val == 2.0f);
|
||||
|
||||
const tuple<double, double, bool> aConstTuple(aTupleWithRepeatedType);
|
||||
const bool& constRef = get<bool>(aConstTuple);
|
||||
EATEST_VERIFY(constRef == true);
|
||||
|
||||
const bool&& constRval = get<bool>(eastl::move(aTupleWithRepeatedType));
|
||||
EATEST_VERIFY(constRval == true);
|
||||
}
|
||||
|
||||
{
|
||||
tuple<int, float> aTupleWithDefaultInit(1, {});
|
||||
|
||||
// tuple construction from pair
|
||||
pair<int, float> aPair(1, 2.0f);
|
||||
tuple<int, float> aTuple(aPair);
|
||||
EATEST_VERIFY(get<0>(aTuple) == 1 && get<1>(aTuple) == 2.0f);
|
||||
tuple<double, double> anotherTuple(aPair);
|
||||
EATEST_VERIFY(get<0>(anotherTuple) == 1.0 && get<1>(anotherTuple) == 2.0);
|
||||
anotherTuple = make_pair(2, 3);
|
||||
EATEST_VERIFY(get<0>(anotherTuple) == 2.0 && get<1>(anotherTuple) == 3.0);
|
||||
|
||||
// operators: ==, !=, <
|
||||
anotherTuple = aTuple;
|
||||
EATEST_VERIFY(aTuple == anotherTuple);
|
||||
EATEST_VERIFY(!(aTuple < anotherTuple) && !(anotherTuple < aTuple));
|
||||
tuple<double, double> aDefaultInitTuple;
|
||||
EATEST_VERIFY(aTuple != aDefaultInitTuple);
|
||||
EATEST_VERIFY(aDefaultInitTuple < aTuple);
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
EATEST_VERIFY((aTuple <=> anotherTuple) == 0);
|
||||
EATEST_VERIFY((aTuple <=> anotherTuple) >= 0);
|
||||
EATEST_VERIFY((anotherTuple <=> aTuple) >= 0);
|
||||
EATEST_VERIFY((aTuple <=> aDefaultInitTuple) != 0);
|
||||
EATEST_VERIFY((aDefaultInitTuple <=> aTuple) < 0);
|
||||
#endif
|
||||
|
||||
tuple<int, int, int> lesserTuple(1, 2, 3);
|
||||
tuple<int, int, int> greaterTuple(1, 2, 4);
|
||||
EATEST_VERIFY(lesserTuple < greaterTuple && !(greaterTuple < lesserTuple) && greaterTuple > lesserTuple &&
|
||||
!(lesserTuple > greaterTuple));
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
EATEST_VERIFY((lesserTuple <=> greaterTuple) != 0);
|
||||
EATEST_VERIFY((lesserTuple <=> greaterTuple) < 0);
|
||||
EATEST_VERIFY((lesserTuple <=> greaterTuple) <= 0);
|
||||
EATEST_VERIFY((greaterTuple <=> lesserTuple) > 0);
|
||||
EATEST_VERIFY((greaterTuple <=> lesserTuple) >= 0);
|
||||
#endif
|
||||
|
||||
tuple<int, float, TestObject> valTup(2, 2.0f, TestObject(2));
|
||||
tuple<int&, float&, TestObject&> refTup(valTup);
|
||||
tuple<const int&, const float&, const TestObject&> constRefTup(valTup);
|
||||
|
||||
EATEST_VERIFY(get<0>(refTup) == get<0>(valTup));
|
||||
EATEST_VERIFY(get<1>(refTup) == get<1>(valTup));
|
||||
EATEST_VERIFY(refTup == valTup);
|
||||
EATEST_VERIFY(get<0>(refTup) == get<0>(constRefTup));
|
||||
EATEST_VERIFY(get<1>(refTup) == get<1>(constRefTup));
|
||||
EATEST_VERIFY(constRefTup == valTup);
|
||||
EATEST_VERIFY(constRefTup == refTup);
|
||||
|
||||
// swap
|
||||
swap(lesserTuple, greaterTuple);
|
||||
EATEST_VERIFY(get<2>(lesserTuple) == 4 && get<2>(greaterTuple) == 3);
|
||||
swap(greaterTuple, lesserTuple);
|
||||
EATEST_VERIFY(lesserTuple < greaterTuple);
|
||||
}
|
||||
|
||||
{
|
||||
// Test construction of tuple containing a move only type
|
||||
static_assert(is_constructible<MoveOnlyType, MoveOnlyType>::value, "is_constructible type trait giving confusing answers.");
|
||||
static_assert(is_constructible<MoveOnlyType, MoveOnlyType&&>::value, "is_constructible type trait giving wrong answers.");
|
||||
static_assert(is_constructible<MoveOnlyType&&, MoveOnlyType&&>::value, "is_constructible type trait giving bizarre answers.");
|
||||
tuple<MoveOnlyType> aTupleWithMoveOnlyMember(1);
|
||||
EATEST_VERIFY(get<0>(aTupleWithMoveOnlyMember).mVal == 1);
|
||||
get<0>(aTupleWithMoveOnlyMember) = MoveOnlyType(2);
|
||||
EATEST_VERIFY(get<0>(aTupleWithMoveOnlyMember).mVal == 2);
|
||||
|
||||
tuple<const MoveOnlyType&> aTupleWithRefToMoveOnlyMember(aTupleWithMoveOnlyMember);
|
||||
EATEST_VERIFY(get<0>(aTupleWithRefToMoveOnlyMember).mVal == 2);
|
||||
|
||||
tuple<const MoveOnlyType&> aTupleWithConstRefToGetMoveOnly(get<0>(aTupleWithMoveOnlyMember));
|
||||
EATEST_VERIFY(get<0>(aTupleWithConstRefToGetMoveOnly).mVal == 2);
|
||||
|
||||
tuple<MoveOnlyType&> aTupleWithRefToGetMoveOnly(get<0>(aTupleWithMoveOnlyMember));
|
||||
EATEST_VERIFY(get<0>(aTupleWithRefToGetMoveOnly).mVal == 2);
|
||||
}
|
||||
|
||||
{
|
||||
// Test construction of tuple containing r-value references
|
||||
int x = 42;
|
||||
TestObject object{1337};
|
||||
|
||||
tuple<int&&, TestObject&&> aTupleWithRValueReference(eastl::move(x), eastl::move(object));
|
||||
static_assert(is_same<decltype(get<0>(aTupleWithRValueReference)), int&>::value, "wrong return type for get when using r-value reference.");
|
||||
static_assert(is_same<decltype(get<1>(aTupleWithRValueReference)), TestObject&>::value, "wrong return type for get when using r-value reference.");
|
||||
EATEST_VERIFY(get<0>(aTupleWithRValueReference) == 42);
|
||||
EATEST_VERIFY(get<1>(aTupleWithRValueReference).mX == 1337);
|
||||
|
||||
static_assert(!is_constructible<decltype(aTupleWithRValueReference), int&, TestObject&>::value, "it shouldn't be possible to assign r-value references with l-values.");
|
||||
}
|
||||
|
||||
{
|
||||
// Tuple helpers
|
||||
|
||||
// make_tuple
|
||||
auto makeTuple = make_tuple(1, 2.0, true);
|
||||
EATEST_VERIFY(get<0>(makeTuple) == 1 && get<1>(makeTuple) == 2.0 && get<2>(makeTuple) == true);
|
||||
|
||||
// TODO: reference_wrapper implementation needs to be finished to enable this code
|
||||
{
|
||||
int a = 2;
|
||||
float b = 3.0f;
|
||||
auto makeTuple2 = make_tuple(ref(a), b);
|
||||
get<0>(makeTuple2) = 3;
|
||||
get<1>(makeTuple2) = 4.0f;
|
||||
EATEST_VERIFY(get<0>(makeTuple2) == 3 && get<1>(makeTuple2) == 4.0f && a == 3 && b == 3.0f);
|
||||
}
|
||||
|
||||
// forward_as_tuple
|
||||
{
|
||||
auto forwardTest = [](tuple<MoveOnlyType&&, MoveOnlyType&&> x) -> tuple<MoveOnlyType, MoveOnlyType>
|
||||
{
|
||||
return tuple<MoveOnlyType, MoveOnlyType>(move(x));
|
||||
};
|
||||
|
||||
tuple<MoveOnlyType, MoveOnlyType> aMovableTuple(
|
||||
forwardTest(forward_as_tuple(MoveOnlyType(1), MoveOnlyType(2))));
|
||||
|
||||
EATEST_VERIFY(get<0>(aMovableTuple).mVal == 1 && get<1>(aMovableTuple).mVal == 2);
|
||||
}
|
||||
|
||||
{
|
||||
// tie
|
||||
int a = 0;
|
||||
double b = 0.0f;
|
||||
static_assert(is_assignable<const Internal::ignore_t&, int>::value, "ignore_t not assignable");
|
||||
static_assert(Internal::TupleAssignable<tuple<const Internal::ignore_t&>, tuple<int>>::value, "Not assignable");
|
||||
tie(a, ignore, b) = make_tuple(1, 3, 5);
|
||||
EATEST_VERIFY(a == 1 && b == 5.0f);
|
||||
|
||||
// tuple_cat
|
||||
auto tcatRes = tuple_cat(make_tuple(1, 2.0f), make_tuple(3.0, true));
|
||||
EATEST_VERIFY(get<0>(tcatRes) == 1 && get<1>(tcatRes) == 2.0f && get<2>(tcatRes) == 3.0 &&
|
||||
get<3>(tcatRes) == true);
|
||||
|
||||
auto tcatRes2 = tuple_cat(make_tuple(1, 2.0f), make_tuple(3.0, true), make_tuple(5u, '6'));
|
||||
EATEST_VERIFY(get<0>(tcatRes2) == 1 && get<1>(tcatRes2) == 2.0f && get<2>(tcatRes2) == 3.0 &&
|
||||
get<3>(tcatRes2) == true && get<4>(tcatRes2) == 5u && get<5>(tcatRes2) == '6');
|
||||
|
||||
auto aCattedRefTuple = tuple_cat(make_tuple(1), tie(a, ignore, b));
|
||||
get<1>(aCattedRefTuple) = 2;
|
||||
EATEST_VERIFY(a == 2);
|
||||
}
|
||||
|
||||
{
|
||||
// Empty tuple
|
||||
tuple<> emptyTuple;
|
||||
EATEST_VERIFY(tuple_size<decltype(emptyTuple)>::value == 0);
|
||||
emptyTuple = make_tuple();
|
||||
auto anotherEmptyTuple = make_tuple();
|
||||
swap(anotherEmptyTuple, emptyTuple);
|
||||
}
|
||||
}
|
||||
|
||||
// test piecewise_construct
|
||||
{
|
||||
{
|
||||
struct local
|
||||
{
|
||||
local() = default;
|
||||
local(int a, int b) : mA(a), mB(b) {}
|
||||
|
||||
int mA = 0;
|
||||
int mB = 0;
|
||||
};
|
||||
|
||||
auto t = make_tuple(42, 43);
|
||||
|
||||
eastl::pair<local, local> p(eastl::piecewise_construct, t, t);
|
||||
|
||||
EATEST_VERIFY(p.first.mA == 42);
|
||||
EATEST_VERIFY(p.second.mA == 42);
|
||||
EATEST_VERIFY(p.first.mB == 43);
|
||||
EATEST_VERIFY(p.second.mB == 43);
|
||||
}
|
||||
|
||||
{
|
||||
struct local
|
||||
{
|
||||
local() = default;
|
||||
local(int a, int b, int c, int d) : mA(a), mB(b), mC(c), mD(d) {}
|
||||
|
||||
int mA = 0;
|
||||
int mB = 0;
|
||||
int mC = 0;
|
||||
int mD = 0;
|
||||
};
|
||||
|
||||
auto t = make_tuple(42, 43, 44, 45);
|
||||
|
||||
eastl::pair<local, local> p(eastl::piecewise_construct, t, t);
|
||||
|
||||
EATEST_VERIFY(p.first.mA == 42);
|
||||
EATEST_VERIFY(p.second.mA == 42);
|
||||
|
||||
EATEST_VERIFY(p.first.mB == 43);
|
||||
EATEST_VERIFY(p.second.mB == 43);
|
||||
|
||||
EATEST_VERIFY(p.first.mC == 44);
|
||||
EATEST_VERIFY(p.second.mC == 44);
|
||||
|
||||
EATEST_VERIFY(p.first.mD == 45);
|
||||
EATEST_VERIFY(p.second.mD == 45);
|
||||
}
|
||||
|
||||
{
|
||||
struct local1
|
||||
{
|
||||
local1() = default;
|
||||
local1(int a) : mA(a) {}
|
||||
int mA = 0;
|
||||
};
|
||||
|
||||
struct local2
|
||||
{
|
||||
local2() = default;
|
||||
local2(char a) : mA(a) {}
|
||||
char mA = 0;
|
||||
};
|
||||
|
||||
auto t1 = make_tuple(42);
|
||||
auto t2 = make_tuple('a');
|
||||
|
||||
eastl::pair<local1, local2> p(eastl::piecewise_construct, t1, t2);
|
||||
|
||||
EATEST_VERIFY(p.first.mA == 42);
|
||||
EATEST_VERIFY(p.second.mA == 'a');
|
||||
}
|
||||
}
|
||||
|
||||
// apply
|
||||
{
|
||||
// test with tuples
|
||||
{
|
||||
{
|
||||
auto result = eastl::apply([](int i) { return i; }, make_tuple(1));
|
||||
EATEST_VERIFY(result == 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto result = eastl::apply([](int i, int j) { return i + j; }, make_tuple(1, 2));
|
||||
EATEST_VERIFY(result == 3);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto result = eastl::apply([](int i, int j, int k, int m) { return i + j + k + m; }, make_tuple(1, 2, 3, 4));
|
||||
EATEST_VERIFY(result == 10);
|
||||
}
|
||||
}
|
||||
|
||||
// test with pair
|
||||
{
|
||||
auto result = eastl::apply([](int i, int j) { return i + j; }, make_pair(1, 2));
|
||||
EATEST_VERIFY(result == 3);
|
||||
}
|
||||
|
||||
// test with array
|
||||
{
|
||||
// TODO(rparolin):
|
||||
// eastl::array requires eastl::get support before we can support unpacking eastl::arrays with eastl::apply.
|
||||
//
|
||||
// {
|
||||
// auto result = eastl::apply([](int i) { return i; }, eastl::array<int, 1>{1});
|
||||
// EATEST_VERIFY(result == 1);
|
||||
// }
|
||||
// {
|
||||
// auto result = eastl::apply([](int i, int j) { return i + j; }, eastl::array<int, 2>{1,2});
|
||||
// EATEST_VERIFY(result == 3);
|
||||
// }
|
||||
// {
|
||||
// auto result = eastl::apply([](int i, int j, int k, int m) { return i + j + k + m; }, eastl::array<int, 4>{1, 2, 3, 4});
|
||||
// EATEST_VERIFY(result == 10);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// Compilation test to make sure that the conditionally-explicit cast works
|
||||
{
|
||||
eastl::tuple<int, float, TestObject> arrayTup[] = {
|
||||
{1, 1.0f, TestObject(1)},
|
||||
{2, 2.0f, TestObject(2)},
|
||||
{3, 3.0f, TestObject(3)},
|
||||
{4, 4.0f, TestObject(4)}
|
||||
};
|
||||
(void)arrayTup;
|
||||
|
||||
#if false
|
||||
// the following code should not compile with conditionally-explicit behaviour (but does with fully implicit behaviour)
|
||||
eastl::tuple<eastl::vector<float>, float> arrayOfArrayTup[] = {
|
||||
{1.0f, 1.0f},
|
||||
{2.0f, 2.0f}
|
||||
};
|
||||
|
||||
eastl::tuple<eastl::vector<int>, float> arrayOfArrayTup2[] = {
|
||||
{1, 1.0f},
|
||||
{2, 2.0f}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
// Compilation test to make sure that we can handle reference to forward-declared types
|
||||
{
|
||||
struct ForwardDeclared;
|
||||
|
||||
auto fill_tuple = [](ForwardDeclared& f) {
|
||||
eastl::tuple<ForwardDeclared&, const ForwardDeclared&> t{f, f};
|
||||
return t;
|
||||
};
|
||||
|
||||
struct ForwardDeclared
|
||||
{
|
||||
int x;
|
||||
};
|
||||
|
||||
ForwardDeclared f{666};
|
||||
auto t = fill_tuple(f);
|
||||
|
||||
EATEST_VERIFY(get<0>(t).x == 666);
|
||||
EATEST_VERIFY(get<1>(t).x == 666);
|
||||
}
|
||||
|
||||
#ifndef EA_COMPILER_NO_STRUCTURED_BINDING
|
||||
// tuple structured bindings test
|
||||
{
|
||||
eastl::tuple<int, int, int> t = {1,2,3};
|
||||
auto [x,y,z] = t;
|
||||
EATEST_VERIFY(x == 1);
|
||||
EATEST_VERIFY(y == 2);
|
||||
EATEST_VERIFY(z == 3);
|
||||
}
|
||||
|
||||
{ // const unpacking test
|
||||
eastl::tuple<int, int, int> t = {1,2,3};
|
||||
const auto [x,y,z] = t;
|
||||
EATEST_VERIFY(x == 1);
|
||||
EATEST_VERIFY(y == 2);
|
||||
EATEST_VERIFY(z == 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
// user regression for tuple_cat
|
||||
{
|
||||
void* empty = nullptr;
|
||||
auto t = eastl::make_tuple(empty, true);
|
||||
auto tc = eastl::tuple_cat(eastl::make_tuple("asd", 1), t);
|
||||
|
||||
static_assert(eastl::is_same_v<decltype(tc), eastl::tuple<const char*, int, void*, bool>>, "type mismatch");
|
||||
|
||||
EATEST_VERIFY(eastl::string("asd") == eastl::get<0>(tc));
|
||||
EATEST_VERIFY(eastl::get<1>(tc) == 1);
|
||||
EATEST_VERIFY(eastl::get<2>(tc) == nullptr);
|
||||
EATEST_VERIFY(eastl::get<3>(tc) == true);
|
||||
}
|
||||
|
||||
// user reported regression that exercises type_traits trying to pull out the element_type from "fancy pointers"
|
||||
{
|
||||
auto up = eastl::make_unique<int[]>(100);
|
||||
auto t = eastl::make_tuple(eastl::move(up));
|
||||
|
||||
using ResultTuple_t = decltype(t);
|
||||
static_assert(eastl::is_same_v<ResultTuple_t, eastl::tuple<eastl::unique_ptr<int[]>>>);
|
||||
static_assert(eastl::is_same_v<eastl::tuple_element_t<0, ResultTuple_t>, eastl::unique_ptr<int[]>>);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int TestTuple() { return 0; }
|
||||
|
||||
#endif // EASTL_TUPLE_ENABLED
|
||||
|
||||
EA_RESTORE_VC_WARNING()
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,915 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/utility.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
|
||||
struct BasicObject
|
||||
{
|
||||
int mX;
|
||||
BasicObject(int x) : mX(x) {}
|
||||
};
|
||||
|
||||
inline bool operator==(const BasicObject& t1, const BasicObject& t2) { return t1.mX == t2.mX; }
|
||||
|
||||
inline bool operator<(const BasicObject& t1, const BasicObject& t2) { return t1.mX < t2.mX; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestUtilityPair
|
||||
//
|
||||
static int TestUtilityPair()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
int _0 = 0, _2 = 2, _3 = 3;
|
||||
float _1f = 1.f;
|
||||
|
||||
// pair();
|
||||
pair<int, float> ifPair1;
|
||||
EATEST_VERIFY((ifPair1.first == 0) && (ifPair1.second == 0.f));
|
||||
|
||||
// pair(const T1& x, const T2& y);
|
||||
pair<int, float> ifPair2(_0, _1f);
|
||||
EATEST_VERIFY((ifPair2.first == 0) && (ifPair2.second == 1.f));
|
||||
|
||||
// template <typename U, typename V>
|
||||
// pair(U&& u, V&& v);
|
||||
pair<int, float> ifPair3(int(0), float(1.f));
|
||||
EATEST_VERIFY((ifPair3.first == 0) && (ifPair3.second == 1.f));
|
||||
|
||||
// template <typename U>
|
||||
// pair(U&& x, const T2& y);
|
||||
const float fConst1 = 1.f;
|
||||
pair<int, float> ifPair4(int(0), fConst1);
|
||||
EATEST_VERIFY((ifPair4.first == 0) && (ifPair4.second == 1.f));
|
||||
|
||||
// template <typename V>
|
||||
// pair(const T1& x, V&& y);
|
||||
const int intConst0 = 0;
|
||||
pair<int, float> ifPair5(intConst0, float(1.f));
|
||||
EATEST_VERIFY((ifPair5.first == 0) && (ifPair5.second == 1.f));
|
||||
|
||||
pair<const int, const int> constIntPair(_2, _3);
|
||||
EATEST_VERIFY((constIntPair.first == 2) && (constIntPair.second == 3));
|
||||
|
||||
// pair(const pair&) = default;
|
||||
pair<int, float> ifPair2Copy(ifPair2);
|
||||
EATEST_VERIFY((ifPair2Copy.first == 0) && (ifPair2Copy.second == 1.f));
|
||||
|
||||
pair<const int, const int> constIntPairCopy(constIntPair);
|
||||
EATEST_VERIFY((constIntPairCopy.first == 2) && (constIntPairCopy.second == 3));
|
||||
|
||||
// template<typename U, typename V>
|
||||
// pair(const pair<U, V>& p);
|
||||
pair<long, double> idPair2(ifPair2);
|
||||
EATEST_VERIFY((idPair2.first == 0) && (idPair2.second == 1.0));
|
||||
|
||||
// pair(pair&& p);
|
||||
|
||||
// template<typename U, typename V>
|
||||
// pair(pair<U, V>&& p);
|
||||
|
||||
// pair& operator=(const pair& p);
|
||||
|
||||
// template<typename U, typename V>
|
||||
// pair& operator=(const pair<U, V>& p);
|
||||
|
||||
// pair& operator=(pair&& p);
|
||||
|
||||
// template<typename U, typename V>
|
||||
// pair& operator=(pair<U, V>&& p);
|
||||
|
||||
// void swap(pair& p);
|
||||
|
||||
// use_self, use_first, use_second
|
||||
use_self<pair<int, float> > usIFPair;
|
||||
use_first<pair<int, float> > u1IFPair;
|
||||
use_second<pair<int, float> > u2IFPair;
|
||||
|
||||
ifPair2 = usIFPair(ifPair2);
|
||||
EATEST_VERIFY((ifPair2.first == 0) && (ifPair2.second == 1));
|
||||
|
||||
int first = u1IFPair(ifPair2);
|
||||
EATEST_VERIFY(first == 0);
|
||||
|
||||
float second = u2IFPair(ifPair2);
|
||||
EATEST_VERIFY(second == 1);
|
||||
|
||||
// make_pair
|
||||
pair<int, float> p1 = make_pair(int(0), float(1));
|
||||
EATEST_VERIFY((p1.first == 0) && (p1.second == 1.f));
|
||||
|
||||
pair<int, float> p2 = make_pair_ref(int(0), float(1));
|
||||
EATEST_VERIFY((p2.first == 0) && (p2.second == 1.f));
|
||||
|
||||
pair<const char*, int> p3 = eastl::make_pair("a", 1);
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p3.first, "a") == 0) && (p3.second == 1));
|
||||
|
||||
pair<const char*, int> p4 = eastl::make_pair<const char*, int>("a", 1);
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p4.first, "a") == 0) && (p4.second == 1));
|
||||
|
||||
pair<int, const char*> p5 = eastl::make_pair<int, const char*>(1, "b");
|
||||
EATEST_VERIFY((p5.first == 1) && (EA::StdC::Strcmp(p5.second, "b") == 0));
|
||||
|
||||
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
|
||||
pair<int, int> p6 = eastl::make_pair<int, int>(1, 2);
|
||||
pair<int, int> p7 = eastl::make_pair<int, int>(2, 1);
|
||||
pair<int, int> p8 = eastl::make_pair<int, int>(7, 8);
|
||||
pair<int, int> p9 = eastl::make_pair<int, int>(10, 1);
|
||||
|
||||
EATEST_VERIFY( (p6 <=> p7) != 0);
|
||||
EATEST_VERIFY( (p6 <=> p6) == 0);
|
||||
EATEST_VERIFY( (p7 <=> p8) < 0);
|
||||
EATEST_VERIFY( (p7 <=> p8) <= 0);
|
||||
EATEST_VERIFY( (p9 <=> p8) > 0);
|
||||
EATEST_VERIFY( (p9 <=> p8) >= 0);
|
||||
#endif
|
||||
|
||||
#if !defined(EA_COMPILER_NO_AUTO)
|
||||
auto p60 = eastl::make_pair("a", "b"); // Different strings of same length of 1.
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p60.first, "a") == 0) && (EA::StdC::Strcmp(p60.second, "b") == 0));
|
||||
|
||||
auto p61 = eastl::make_pair("ab", "cd"); // Different strings of same length > 1.
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p61.first, "ab") == 0) && (EA::StdC::Strcmp(p61.second, "cd") == 0));
|
||||
|
||||
auto p62 = eastl::make_pair("abc", "bcdef"); // Different strings of different length.
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p62.first, "abc") == 0) && (EA::StdC::Strcmp(p62.second, "bcdef") == 0));
|
||||
|
||||
char strA[] = "a";
|
||||
auto p70 = eastl::make_pair(strA, strA);
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p70.first, "a") == 0) && (EA::StdC::Strcmp(p70.second, "a") == 0));
|
||||
|
||||
char strBC[] = "bc";
|
||||
auto p71 = eastl::make_pair(strA, strBC);
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p71.first, "a") == 0) && (EA::StdC::Strcmp(p71.second, "bc") == 0));
|
||||
|
||||
const char cstrA[] = "a";
|
||||
auto p80 = eastl::make_pair(cstrA, cstrA);
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p80.first, "a") == 0) && (EA::StdC::Strcmp(p80.second, "a") == 0));
|
||||
|
||||
const char cstrBC[] = "bc";
|
||||
auto p81 = eastl::make_pair(cstrA, cstrBC);
|
||||
EATEST_VERIFY((EA::StdC::Strcmp(p81.first, "a") == 0) && (EA::StdC::Strcmp(p81.second, "bc") == 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
// One-off tests and regressions
|
||||
|
||||
#if EASTL_PAIR_CONFORMANCE // See http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#811
|
||||
pair<char*, char*> zeroLiteralPair(0, 0);
|
||||
EATEST_VERIFY((zeroLiteralPair.first == NULL) && (zeroLiteralPair.second == NULL));
|
||||
#endif
|
||||
|
||||
// template<typename U>
|
||||
// pair(U&& x, const T2& y)
|
||||
typedef eastl::pair<uint16_t, const char8_t*> LCIDMapping;
|
||||
LCIDMapping lcidMappingArray[1] = {LCIDMapping(0x0036, EA_CHAR8("af"))}; // Note that 0x0036 is of type int.
|
||||
EATEST_VERIFY((lcidMappingArray[0].first == 0x0036));
|
||||
|
||||
// template<typename V>
|
||||
// pair(const T1& x, V&& y)
|
||||
typedef eastl::pair<const char8_t*, uint16_t> LCIDMapping2;
|
||||
LCIDMapping2 lcidMapping2Array[1] = {LCIDMapping2(EA_CHAR8("af"), 0x0036)};
|
||||
EATEST_VERIFY((lcidMapping2Array[0].second == 0x0036));
|
||||
|
||||
// The following code was giving an EDG compiler:
|
||||
// error 145: a value of type "int" cannot be used to initialize
|
||||
// an entity of type "void *" second(eastl::forward<V>(v)) {}
|
||||
// template <typename U, typename V>
|
||||
// pair(U&& u, V&& v);
|
||||
#if EASTL_PAIR_CONFORMANCE
|
||||
typedef eastl::pair<float*, void*> TestPair1;
|
||||
float fOne = 1.f;
|
||||
TestPair1 testPair1(&fOne, NULL);
|
||||
EATEST_VERIFY(*testPair1.first == 1.f);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef EA_COMPILER_NO_STRUCTURED_BINDING
|
||||
// pair structured bindings test
|
||||
{
|
||||
eastl::pair<int, int> t = {1,2};
|
||||
auto [x,y] = t;
|
||||
EATEST_VERIFY(x == 1);
|
||||
EATEST_VERIFY(y == 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto t = eastl::make_pair(1, 2);
|
||||
auto [x,y] = t;
|
||||
EATEST_VERIFY(x == 1);
|
||||
EATEST_VERIFY(y == 2);
|
||||
}
|
||||
|
||||
{ // reported user-regression structured binding unpacking for iterators
|
||||
eastl::vector<int> v = {1,2,3,4,5,6};
|
||||
auto t = eastl::make_pair(v.begin(), v.end() - 1);
|
||||
auto [x,y] = t;
|
||||
EATEST_VERIFY(*x == 1);
|
||||
EATEST_VERIFY(*y == 6);
|
||||
}
|
||||
|
||||
{ // reported user-regression structured binding unpacking for iterators
|
||||
eastl::vector<int> v = {1,2,3,4,5,6};
|
||||
auto t = eastl::make_pair(v.begin(), v.end());
|
||||
auto [x,y] = t;
|
||||
EATEST_VERIFY(*x == 1);
|
||||
EA_UNUSED(y);
|
||||
}
|
||||
|
||||
{ // reported user-regression for const structured binding unpacking for iterators
|
||||
eastl::vector<int> v = {1,2,3,4,5,6};
|
||||
const auto [x,y] = eastl::make_pair(v.begin(), v.end());;
|
||||
EATEST_VERIFY(*x == 1);
|
||||
EA_UNUSED(y);
|
||||
}
|
||||
#endif
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestUtilityRelops
|
||||
//
|
||||
static int TestUtilityRelops()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
using namespace eastl::rel_ops; // Defines default versions of operators !=, <, >, <=, >= based on == and <.
|
||||
|
||||
BasicObject bo1(1), bo2(2);
|
||||
|
||||
EATEST_VERIFY(!(bo1 == bo2));
|
||||
EATEST_VERIFY((bo1 != bo2));
|
||||
EATEST_VERIFY((bo1 < bo2));
|
||||
EATEST_VERIFY(!(bo1 > bo2));
|
||||
EATEST_VERIFY((bo1 <= bo2));
|
||||
EATEST_VERIFY(!(bo1 >= bo2));
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
// ThrowSwappable
|
||||
struct ThrowSwappable
|
||||
{
|
||||
};
|
||||
|
||||
void swap(ThrowSwappable& x, ThrowSwappable& y) EA_NOEXCEPT_IF(false)
|
||||
{
|
||||
ThrowSwappable temp(x);
|
||||
x = y;
|
||||
y = temp;
|
||||
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
throw int();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if EASTL_TYPE_TRAIT_is_nothrow_swappable_CONFORMANCE
|
||||
// NoThrowSwappable
|
||||
struct NoThrowSwappable
|
||||
{
|
||||
};
|
||||
|
||||
void swap(NoThrowSwappable& x, NoThrowSwappable& y) EA_NOEXCEPT_IF(true)
|
||||
{
|
||||
NoThrowSwappable temp(x);
|
||||
x = y;
|
||||
y = temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Swappable1 {};
|
||||
struct Swappable2 {};
|
||||
struct Swappable3 {};
|
||||
void swap(Swappable1&, Swappable2&) {}
|
||||
void swap(Swappable2&, Swappable1&) {}
|
||||
void swap(Swappable1&, Swappable3&) {} // intentionally missing 'swap(Swappable3, Swappable1)'
|
||||
|
||||
|
||||
static int TestUtilitySwap()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// is_swappable
|
||||
// is_nothrow_swappable
|
||||
#if EASTL_TYPE_TRAIT_is_swappable_CONFORMANCE
|
||||
static_assert((eastl::is_swappable<int>::value == true), "is_swappable failure");
|
||||
static_assert((eastl::is_swappable<eastl::vector<int> >::value == true), "is_swappable failure");
|
||||
static_assert((eastl::is_swappable<ThrowSwappable>::value == true), "is_swappable failure");
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
static_assert((eastl::is_swappable_v<int> == true), "is_swappable failure");
|
||||
static_assert((eastl::is_swappable_v<eastl::vector<int> > == true), "is_swappable failure");
|
||||
static_assert((eastl::is_swappable_v<ThrowSwappable> == true), "is_swappable failure");
|
||||
#endif
|
||||
// Need to come up with a class that's not swappable. How do we do that, given the universal swap template?
|
||||
// static_assert((eastl::is_swappable<?>::value == false), "is_swappable failure");
|
||||
#endif
|
||||
|
||||
#if EASTL_TYPE_TRAIT_is_nothrow_swappable_CONFORMANCE
|
||||
static_assert((eastl::is_nothrow_swappable<int>::value == true), "is_nothrow_swappable failure"); // There currently isn't any specialization for swap of scalar types that's nothrow.
|
||||
static_assert((eastl::is_nothrow_swappable<eastl::vector<int> >::value == false), "is_nothrow_swappable failure");
|
||||
static_assert((eastl::is_nothrow_swappable<ThrowSwappable>::value == false), "is_nothrow_swappable failure");
|
||||
static_assert((eastl::is_nothrow_swappable<NoThrowSwappable>::value == true), "is_nothrow_swappable failure");
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
static_assert((eastl::is_nothrow_swappable_v<int> == true), "is_nothrow_swappable failure"); // There currently isn't any specialization for swap of scalar types that's nothrow.
|
||||
static_assert((eastl::is_nothrow_swappable_v<eastl::vector<int>> == false), "is_nothrow_swappable failure");
|
||||
static_assert((eastl::is_nothrow_swappable_v<ThrowSwappable> == false), "is_nothrow_swappable failure");
|
||||
static_assert((eastl::is_nothrow_swappable_v<NoThrowSwappable> == true), "is_nothrow_swappable failure");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
// is_swappable_with
|
||||
// is_nothrow_swappable_with
|
||||
static_assert(eastl::is_swappable_with<int&, int&>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<int, int>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<int&, int>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<int, int&>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<int, short>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<int, long>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<int, eastl::vector<int>>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<void, void>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<int, void>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<void, int>::value, "is_swappable_with failure");
|
||||
static_assert(!eastl::is_swappable_with<ThrowSwappable, ThrowSwappable>::value, "is_swappable_with failure");
|
||||
static_assert(eastl::is_swappable_with<ThrowSwappable&, ThrowSwappable&>::value, "is_swappable_with failure");
|
||||
static_assert(eastl::is_swappable_with<Swappable1&, Swappable1&>::value, "is_swappable_with failure");
|
||||
static_assert(eastl::is_swappable_with<Swappable1&, Swappable2&>::value, "is_swappable_with failure");
|
||||
static_assert(eastl::is_swappable_with<Swappable2&, Swappable1&>::value, "is_swappable_with failure");
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
static_assert(eastl::is_swappable_with_v<int&, int&>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<int, int>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<int&, int>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<int, int&>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<int, short>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<int, long>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<int, eastl::vector<int>>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<void, void>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<int, void>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<void, int>, "is_swappable_with_v failure");
|
||||
static_assert(!eastl::is_swappable_with_v<ThrowSwappable, ThrowSwappable>, "is_swappable_with_v failure");
|
||||
static_assert(eastl::is_swappable_with_v<ThrowSwappable&, ThrowSwappable&>, "is_swappable_with_v failure");
|
||||
static_assert(eastl::is_swappable_with_v<Swappable1&, Swappable1&>, "is_swappable_with_v failure");
|
||||
static_assert(eastl::is_swappable_with_v<Swappable1&, Swappable2&>, "is_swappable_with_v failure");
|
||||
static_assert(eastl::is_swappable_with_v<Swappable2&, Swappable1&>, "is_swappable_with_v failure");
|
||||
#endif // EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
|
||||
#if EASTL_TYPE_TRAIT_is_nothrow_swappable_with_CONFORMANCE
|
||||
static_assert(eastl::is_nothrow_swappable_with<int&, int&>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<int, int>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<int&, int>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<int, int&>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<int, short>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<int, long>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<int, eastl::vector<int>>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<void, void>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<int, void>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<void, int>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<ThrowSwappable, ThrowSwappable>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<ThrowSwappable&, ThrowSwappable&>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with<NoThrowSwappable, NoThrowSwappable>::value, "is_nothrow_swappable_with failure");
|
||||
static_assert(eastl::is_nothrow_swappable_with<NoThrowSwappable&, NoThrowSwappable&>::value, "is_nothrow_swappable_with failure");
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
static_assert(eastl::is_nothrow_swappable_with_v<int&, int&>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<int, int>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<int&, int>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<int, int&>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<int, short>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<int, long>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<int, eastl::vector<int>>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<void, void>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<int, void>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<void, int>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<ThrowSwappable, ThrowSwappable>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<ThrowSwappable&, ThrowSwappable&>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(!eastl::is_nothrow_swappable_with_v<NoThrowSwappable, NoThrowSwappable>, "is_nothrow_swappable_with_v failure");
|
||||
static_assert(eastl::is_nothrow_swappable_with_v<NoThrowSwappable&, NoThrowSwappable&>, "is_nothrow_swappable_with_v failure");
|
||||
#endif // EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
#endif
|
||||
#endif // EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
#if !defined(EA_COMPILER_NO_NOEXCEPT)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Warning C4626 warns against an implicitly deleted move assignment operator.
|
||||
// This warning was disabled by default in VS2013. It was enabled by default in
|
||||
// VS2015. Since the the tests below are explicitly testing move construction
|
||||
// of the various classes explicitly deleting the move assignment to remove the
|
||||
// warning is safe.
|
||||
//
|
||||
// https://msdn.microsoft.com/en-us/library/23k5d385.aspx
|
||||
|
||||
struct noexcept_move_copy
|
||||
{
|
||||
bool mStatus;
|
||||
|
||||
noexcept_move_copy() : mStatus(true) {}
|
||||
|
||||
noexcept_move_copy(const noexcept_move_copy&) = default;
|
||||
|
||||
noexcept_move_copy(noexcept_move_copy&& r) noexcept { r.mStatus = false; }
|
||||
|
||||
noexcept_move_copy& operator=(const noexcept_move_copy&) = delete; // required as VS2015 enabled C4626 by default.
|
||||
};
|
||||
|
||||
struct noexcept_move_no_copy
|
||||
{
|
||||
bool mStatus;
|
||||
|
||||
noexcept_move_no_copy() : mStatus(true) {}
|
||||
|
||||
noexcept_move_no_copy(const noexcept_move_no_copy&) = delete;
|
||||
|
||||
noexcept_move_no_copy(noexcept_move_no_copy&& r) noexcept { r.mStatus = false; };
|
||||
|
||||
noexcept_move_no_copy& operator=(const noexcept_move_no_copy&) = delete; // required as VS2015 enabled C4626 by default.
|
||||
};
|
||||
|
||||
struct except_move_copy
|
||||
{
|
||||
bool mStatus;
|
||||
|
||||
except_move_copy() : mStatus(true) {}
|
||||
|
||||
except_move_copy(const except_move_copy&) = default;
|
||||
|
||||
except_move_copy(except_move_copy&& r) noexcept(false) { r.mStatus = false; };
|
||||
|
||||
except_move_copy& operator=(const except_move_copy&) = delete; // required as VS2015 enabled C4626 by default.
|
||||
};
|
||||
|
||||
struct except_move_no_copy
|
||||
{
|
||||
bool mStatus;
|
||||
|
||||
except_move_no_copy() : mStatus(true) {}
|
||||
|
||||
except_move_no_copy(const except_move_no_copy&) = delete;
|
||||
|
||||
except_move_no_copy(except_move_no_copy&& r) noexcept(false) { r.mStatus = false; };
|
||||
|
||||
except_move_no_copy& operator=(const except_move_no_copy&) = delete; // required as VS2015 enabled C4626 by default.
|
||||
};
|
||||
#endif
|
||||
|
||||
static int TestUtilityMove()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// move_if_noexcept
|
||||
#if !defined(EA_COMPILER_NO_NOEXCEPT)
|
||||
noexcept_move_copy nemcA;
|
||||
noexcept_move_copy nemcB =
|
||||
eastl::move_if_noexcept(nemcA); // nemcB should be constructed via noexcept_move_copy(noexcept_move_copy&&)
|
||||
EATEST_VERIFY(nemcA.mStatus == false);
|
||||
EA_UNUSED(nemcB);
|
||||
|
||||
noexcept_move_no_copy nemncA;
|
||||
noexcept_move_no_copy nemncB = eastl::move_if_noexcept(
|
||||
nemncA); // nemncB should be constructed via noexcept_move_no_copy(noexcept_move_no_copy&&)
|
||||
EATEST_VERIFY(nemncA.mStatus == false);
|
||||
EA_UNUSED(nemncB);
|
||||
|
||||
except_move_copy emcA;
|
||||
except_move_copy emcB = eastl::move_if_noexcept(
|
||||
emcA); // emcB should be constructed via except_move_copy(const except_move_copy&) if exceptions are enabled.
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
EATEST_VERIFY(emcA.mStatus == true);
|
||||
#else
|
||||
EATEST_VERIFY(emcA.mStatus == false);
|
||||
#endif
|
||||
EA_UNUSED(emcB);
|
||||
|
||||
except_move_no_copy emncA;
|
||||
except_move_no_copy emncB =
|
||||
eastl::move_if_noexcept(emncA); // emncB should be constructed via except_move_no_copy(except_move_no_copy&&)
|
||||
EATEST_VERIFY(emncA.mStatus == false);
|
||||
EA_UNUSED(emncB);
|
||||
#endif
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
static int TestUtilityIntegerSequence()
|
||||
{
|
||||
using namespace eastl;
|
||||
int nErrorCount = 0;
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
|
||||
EATEST_VERIFY((integer_sequence<int, 0, 1, 2, 3, 4>::size() == 5));
|
||||
EATEST_VERIFY((make_integer_sequence<int, 5>::size() == 5));
|
||||
static_assert(is_same<make_integer_sequence<int, 5>, integer_sequence<int, 0, 1, 2, 3, 4>>::value);
|
||||
|
||||
EATEST_VERIFY((index_sequence<0, 1, 2, 3, 4>::size() == 5));
|
||||
EATEST_VERIFY((make_index_sequence<5>::size() == 5));
|
||||
static_assert(is_same<make_index_sequence<5>, index_sequence<0, 1, 2, 3, 4>>::value);
|
||||
static_assert(is_same<make_index_sequence<5>, integer_sequence<size_t, 0, 1, 2, 3, 4>>::value);
|
||||
#endif // EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
static int TestUtilityExchange()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
int a = 0;
|
||||
auto r = eastl::exchange(a, 1);
|
||||
|
||||
EATEST_VERIFY(r == 0);
|
||||
EATEST_VERIFY(a == 1);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 0;
|
||||
auto r = eastl::exchange(a, 1.78);
|
||||
|
||||
EATEST_VERIFY(r == 0);
|
||||
EATEST_VERIFY(a == 1);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 0;
|
||||
auto r = eastl::exchange(a, 1.78f);
|
||||
|
||||
EATEST_VERIFY(r == 0);
|
||||
EATEST_VERIFY(a == 1);
|
||||
}
|
||||
|
||||
{
|
||||
int a = 0, b = 1;
|
||||
auto r = eastl::exchange(a, b);
|
||||
|
||||
EATEST_VERIFY(r == 0);
|
||||
EATEST_VERIFY(a == 1);
|
||||
EATEST_VERIFY(b == 1);
|
||||
}
|
||||
|
||||
{
|
||||
bool b = true;
|
||||
|
||||
auto r = eastl::exchange(b, true);
|
||||
EATEST_VERIFY(r);
|
||||
|
||||
r = eastl::exchange(b, false);
|
||||
EATEST_VERIFY(r);
|
||||
EATEST_VERIFY(!b);
|
||||
|
||||
r = eastl::exchange(b, true);
|
||||
EATEST_VERIFY(!r);
|
||||
EATEST_VERIFY(b);
|
||||
}
|
||||
|
||||
{
|
||||
TestObject::Reset();
|
||||
|
||||
TestObject a(42);
|
||||
auto r = eastl::exchange(a, TestObject(24));
|
||||
|
||||
EATEST_VERIFY(r.mX == 42);
|
||||
EATEST_VERIFY(a.mX == 24);
|
||||
}
|
||||
|
||||
{
|
||||
const char* const pElectronicArts = "Electronic Arts";
|
||||
const char* const pEAVancouver = "EA Vancouver";
|
||||
|
||||
eastl::string a(pElectronicArts);
|
||||
auto r = eastl::exchange(a, pEAVancouver);
|
||||
|
||||
EATEST_VERIFY(r == pElectronicArts);
|
||||
EATEST_VERIFY(a == pEAVancouver);
|
||||
|
||||
r = eastl::exchange(a, "EA Standard Template Library");
|
||||
EATEST_VERIFY(a == "EA Standard Template Library");
|
||||
}
|
||||
|
||||
// Construct pair using single move constructor
|
||||
{
|
||||
struct TestPairSingleMoveConstructor
|
||||
{
|
||||
void test(int&& val)
|
||||
{
|
||||
eastl::pair<int,int> p(eastl::pair_first_construct, eastl::move(val));
|
||||
}
|
||||
};
|
||||
|
||||
int i1 = 1;
|
||||
TestPairSingleMoveConstructor test;
|
||||
test.test(eastl::move(i1));
|
||||
}
|
||||
|
||||
// User reported regression where via reference collapsing, we see the same single element ctor defined twice.
|
||||
//
|
||||
// T = const U&
|
||||
// pair(const T&) -> pair(const const U& &) -> pair(const U&)
|
||||
// pair(T&&) -> pair(const U& &&) -> pair(const U&)
|
||||
{
|
||||
struct FooType {};
|
||||
|
||||
using VectorOfPairWithReference = eastl::vector<eastl::pair<const FooType&, float>>;
|
||||
|
||||
VectorOfPairWithReference v;
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
#if defined(EA_COMPILER_CPP20_ENABLED)
|
||||
template <typename T>
|
||||
static int TestCmpCommon()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_equal(T(0), T(0)));
|
||||
EATEST_VERIFY(eastl::cmp_equal(T(1), T(1)));
|
||||
EATEST_VERIFY(eastl::cmp_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
|
||||
EATEST_VERIFY(eastl::cmp_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
|
||||
EATEST_VERIFY(!eastl::cmp_equal(T(0), T(1)));
|
||||
EATEST_VERIFY(!eastl::cmp_equal(T(1), T(0)));
|
||||
if (eastl::is_signed_v<T>)
|
||||
{
|
||||
EATEST_VERIFY(eastl::cmp_equal(T(-1), T(-1)));
|
||||
EATEST_VERIFY(!eastl::cmp_equal(T(-1), T(-2)));
|
||||
EATEST_VERIFY(!eastl::cmp_equal(T(-2), T(-1)));
|
||||
}
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_not_equal(T(1), T(0)));
|
||||
EATEST_VERIFY(eastl::cmp_not_equal(T(0), T(1)));
|
||||
EATEST_VERIFY(eastl::cmp_not_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
|
||||
EATEST_VERIFY(eastl::cmp_not_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
|
||||
if (eastl::is_signed_v<T>)
|
||||
{
|
||||
EATEST_VERIFY(!eastl::cmp_not_equal(T(-1), T(-1)));
|
||||
EATEST_VERIFY(eastl::cmp_not_equal(T(-1), T(-2)));
|
||||
EATEST_VERIFY(eastl::cmp_not_equal(T(-2), T(-1)));
|
||||
}
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_less(T(0), T(1)));
|
||||
EATEST_VERIFY(eastl::cmp_less(T(5), T(10)));
|
||||
EATEST_VERIFY(!eastl::cmp_less(T(0), T(0)));
|
||||
EATEST_VERIFY(!eastl::cmp_less(T(1), T(0)));
|
||||
EATEST_VERIFY(eastl::cmp_less(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
|
||||
EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
|
||||
EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
|
||||
EATEST_VERIFY(!eastl::cmp_less(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
|
||||
if (eastl::is_signed_v<T>)
|
||||
{
|
||||
EATEST_VERIFY(!eastl::cmp_less(T(-1), T(-1)));
|
||||
EATEST_VERIFY(!eastl::cmp_less(T(-1), T(-2)));
|
||||
EATEST_VERIFY(eastl::cmp_less(T(-2), T(-1)));
|
||||
}
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(T(0), T(1)));
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(T(5), T(10)));
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(T(0), T(0)));
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(T(1), T(1)));
|
||||
EATEST_VERIFY(!eastl::cmp_less_equal(T(1), T(0)));
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
|
||||
EATEST_VERIFY(!eastl::cmp_less_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
|
||||
if (eastl::is_signed_v<T>)
|
||||
{
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(T(-1), T(-1)));
|
||||
EATEST_VERIFY(!eastl::cmp_less_equal(T(-1), T(-2)));
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(T(-2), T(-1)));
|
||||
}
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_greater(T(1), T(0)));
|
||||
EATEST_VERIFY(eastl::cmp_greater(T(10), T(5)));
|
||||
EATEST_VERIFY(!eastl::cmp_greater(T(0), T(0)));
|
||||
EATEST_VERIFY(!eastl::cmp_greater(T(0), T(1)));
|
||||
EATEST_VERIFY(eastl::cmp_greater(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
|
||||
EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
|
||||
EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
|
||||
EATEST_VERIFY(!eastl::cmp_greater(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
|
||||
if (eastl::is_signed_v<T>)
|
||||
{
|
||||
EATEST_VERIFY(!eastl::cmp_greater(T(-1), T(-1)));
|
||||
EATEST_VERIFY(eastl::cmp_greater(T(-1), T(-2)));
|
||||
EATEST_VERIFY(!eastl::cmp_greater(T(-2), T(-1)));
|
||||
}
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(T(1), T(0)));
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(T(10), T(5)));
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(T(0), T(0)));
|
||||
EATEST_VERIFY(!eastl::cmp_greater_equal(T(0), T(1)));
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::min()));
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::min()));
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(eastl::numeric_limits<T>::max(), eastl::numeric_limits<T>::max()));
|
||||
EATEST_VERIFY(!eastl::cmp_greater_equal(eastl::numeric_limits<T>::min(), eastl::numeric_limits<T>::max()));
|
||||
if (eastl::is_signed_v<T>)
|
||||
{
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(T(-1), T(-1)));
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(T(-1), T(-2)));
|
||||
EATEST_VERIFY(!eastl::cmp_greater_equal(T(-2), T(-1)));
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static int TestUtilityCmpEql(const T x, const U y)
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_equal(T(x), U(y)));
|
||||
EATEST_VERIFY(eastl::cmp_equal(U(y), T(x)));
|
||||
EATEST_VERIFY(!eastl::cmp_not_equal(T(x), U(y)));
|
||||
EATEST_VERIFY(!eastl::cmp_not_equal(U(y), T(x)));
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static int TestUtilityCmpLess(const T x, const U y)
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_less(T(x), U(y)));
|
||||
EATEST_VERIFY(!eastl::cmp_less(U(y), T(x)));
|
||||
|
||||
EATEST_VERIFY(!eastl::cmp_greater_equal(T(x), U(y)));
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(U(y), T(x)));
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static int TestUtilityCmpGreater(const T x, const U y)
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_greater(T(x), U(y)));
|
||||
EATEST_VERIFY(!eastl::cmp_greater(U(y), T(x)));
|
||||
|
||||
EATEST_VERIFY(!eastl::cmp_less_equal(T(x), U(y)));
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(U(y), T(x)));
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static int TestUtilityCmpLessEq(const T x, const U y)
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(T(x), U(y)));
|
||||
EATEST_VERIFY(eastl::cmp_less(T(x), U(y)) || eastl::cmp_equal(T(x), U(y)));
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(U(y), T(x)));
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
static int TestUtilityCmpGreaterEq(const T x, const U y)
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_greater_equal(T(x), U(y)));
|
||||
EATEST_VERIFY(eastl::cmp_greater(T(x), U(y)) || eastl::cmp_equal(T(x), U(y)));
|
||||
|
||||
EATEST_VERIFY(eastl::cmp_less_equal(U(y), T(x)));
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
static int TestUtilityIntegralComp()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
// Test integral comparisons among same types
|
||||
nErrorCount += TestCmpCommon<int>();
|
||||
nErrorCount += TestCmpCommon<short>();
|
||||
nErrorCount += TestCmpCommon<long>();
|
||||
nErrorCount += TestCmpCommon<long long>();
|
||||
|
||||
nErrorCount += TestCmpCommon<unsigned int>();
|
||||
nErrorCount += TestCmpCommon<unsigned short>();
|
||||
nErrorCount += TestCmpCommon<unsigned long>();
|
||||
nErrorCount += TestCmpCommon<unsigned long long>();
|
||||
|
||||
// Test integral comparison among different types
|
||||
nErrorCount += TestUtilityCmpEql(int(0), short(0));
|
||||
nErrorCount += TestUtilityCmpEql(short(2), long(2));
|
||||
nErrorCount += TestUtilityCmpEql(short(3), unsigned long(3));
|
||||
nErrorCount += TestUtilityCmpEql(int(-5), long long(-5));
|
||||
nErrorCount += TestUtilityCmpEql(short(-100), long long(-100));
|
||||
nErrorCount += TestUtilityCmpEql(unsigned int(100), long(100));
|
||||
nErrorCount += TestUtilityCmpEql(unsigned long long(100), int(100));
|
||||
|
||||
nErrorCount += TestUtilityCmpLess(int(0), long long(1));
|
||||
nErrorCount += TestUtilityCmpLess(int(-1), unsigned long(1));
|
||||
nErrorCount += TestUtilityCmpLess(short(-100), long long(100));
|
||||
nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<long>::min(), short(0));
|
||||
nErrorCount += TestUtilityCmpLess(short(0), eastl::numeric_limits<int>::max());
|
||||
nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<unsigned short>::min(), eastl::numeric_limits<int>::max());
|
||||
nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<short>::max(), eastl::numeric_limits<long>::max());
|
||||
nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<int>::max(), eastl::numeric_limits<long long>::max());
|
||||
nErrorCount += TestUtilityCmpLess(int(-100), unsigned int(0));
|
||||
nErrorCount += TestUtilityCmpLess(eastl::numeric_limits<int>::min(), eastl::numeric_limits<unsigned int>::min());
|
||||
|
||||
nErrorCount += TestUtilityCmpGreater(int(1), short(0));
|
||||
nErrorCount += TestUtilityCmpGreater(unsigned long(1), int(-1));
|
||||
nErrorCount += TestUtilityCmpGreater(unsigned long long(100), short(-100));
|
||||
nErrorCount += TestUtilityCmpGreater(short(0), eastl::numeric_limits<short>::min());
|
||||
nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long>::max(), unsigned short(5));
|
||||
nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long>::max(), eastl::numeric_limits<int>::min());
|
||||
nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::max());
|
||||
nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<long long>::max(), eastl::numeric_limits<int>::max());
|
||||
nErrorCount += TestUtilityCmpGreater(unsigned int(0), int(-100));
|
||||
nErrorCount += TestUtilityCmpGreater(eastl::numeric_limits<unsigned int>::min(), eastl::numeric_limits<int>::min());
|
||||
|
||||
nErrorCount += TestUtilityCmpLessEq(int(0), short(1));
|
||||
nErrorCount += TestUtilityCmpLessEq(int(-1), long long(-1));
|
||||
nErrorCount += TestUtilityCmpLessEq(short(-100), unsigned long long(100));
|
||||
nErrorCount += TestUtilityCmpLessEq(short(-100), long long(-100));
|
||||
nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::min(), short(0));
|
||||
nErrorCount += TestUtilityCmpLessEq(short(0), eastl::numeric_limits<int>::max());
|
||||
nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<short>::min(), eastl::numeric_limits<short>::min());
|
||||
nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<int>::max());
|
||||
nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<long long>::max());
|
||||
nErrorCount += TestUtilityCmpLessEq(int(50), unsigned int(50));
|
||||
nErrorCount += TestUtilityCmpLessEq(eastl::numeric_limits<int>::min(), eastl::numeric_limits<unsigned int>::min());
|
||||
|
||||
nErrorCount += TestUtilityCmpGreaterEq(int(1), short(1));
|
||||
nErrorCount += TestUtilityCmpGreaterEq(long long(-1), int(-1));
|
||||
nErrorCount += TestUtilityCmpGreaterEq(long long(-100), short(-100));
|
||||
nErrorCount += TestUtilityCmpGreaterEq(short(0), long(0));
|
||||
nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<long>::max(), eastl::numeric_limits<long>::max());
|
||||
nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::min());
|
||||
nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<int>::max(), eastl::numeric_limits<short>::max());
|
||||
nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<long long>::max(), eastl::numeric_limits<int>::max());
|
||||
nErrorCount += TestUtilityCmpGreaterEq(unsigned int(0), int(0));
|
||||
nErrorCount += TestUtilityCmpGreaterEq(eastl::numeric_limits<unsigned int>::min(), eastl::numeric_limits<int>::min());
|
||||
|
||||
// Test in_range
|
||||
EATEST_VERIFY(eastl::in_range<int>(0));
|
||||
EATEST_VERIFY(eastl::in_range<int>(eastl::numeric_limits<int>::min()));
|
||||
EATEST_VERIFY(eastl::in_range<int>(eastl::numeric_limits<int>::max()));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned int>(0));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned int>(eastl::numeric_limits<unsigned int>::min()));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned int>(eastl::numeric_limits<unsigned int>::max()));
|
||||
EATEST_VERIFY(!eastl::in_range<unsigned int>(-1));
|
||||
EATEST_VERIFY(!eastl::in_range<int>(eastl::numeric_limits<unsigned int>::max()));
|
||||
EATEST_VERIFY(!eastl::in_range<unsigned int>(eastl::numeric_limits<int>::min()));
|
||||
|
||||
EATEST_VERIFY(eastl::in_range<short>(100));
|
||||
EATEST_VERIFY(eastl::in_range<short>(eastl::numeric_limits<short>::min()));
|
||||
EATEST_VERIFY(eastl::in_range<short>(eastl::numeric_limits<short>::max()));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned short>(100));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned short>(eastl::numeric_limits<unsigned short>::min()));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned short>(eastl::numeric_limits<unsigned short>::max()));
|
||||
EATEST_VERIFY(!eastl::in_range<unsigned short>(-1));
|
||||
EATEST_VERIFY(!eastl::in_range<short>(eastl::numeric_limits<unsigned int>::max()));
|
||||
EATEST_VERIFY(!eastl::in_range<unsigned short>(eastl::numeric_limits<int>::min()));
|
||||
|
||||
EATEST_VERIFY(eastl::in_range<long>(50));
|
||||
EATEST_VERIFY(eastl::in_range<long>(eastl::numeric_limits<long>::min()));
|
||||
EATEST_VERIFY(eastl::in_range<long>(eastl::numeric_limits<long>::max()));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned long>(50));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned long>(eastl::numeric_limits<unsigned long>::min()));
|
||||
EATEST_VERIFY(eastl::in_range<unsigned long>(eastl::numeric_limits<unsigned long>::max()));
|
||||
EATEST_VERIFY(!eastl::in_range<unsigned long>(-1));
|
||||
EATEST_VERIFY(!eastl::in_range<long>(eastl::numeric_limits<unsigned int>::max()));
|
||||
EATEST_VERIFY(!eastl::in_range<unsigned long>(eastl::numeric_limits<int>::min()));
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestUtility
|
||||
//
|
||||
int TestUtility()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
nErrorCount += TestUtilityPair();
|
||||
nErrorCount += TestUtilityRelops();
|
||||
nErrorCount += TestUtilitySwap();
|
||||
nErrorCount += TestUtilityMove();
|
||||
nErrorCount += TestUtilityIntegerSequence();
|
||||
nErrorCount += TestUtilityExchange();
|
||||
#if defined(EA_COMPILER_CPP20_ENABLED)
|
||||
nErrorCount += TestUtilityIntegralComp();
|
||||
#endif
|
||||
return nErrorCount;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* NOTE:
|
||||
*
|
||||
* DO NOT INCLUDE EATest/EATest.h or ANY OTHER HEADER
|
||||
* There is a bug in MSVC whereby pushing/poping all warnings from a header does not reenable all warnings
|
||||
* in the TU that included the header.
|
||||
* For example C4805 will not reenabled.
|
||||
*/
|
||||
|
||||
#include <EASTL/variant.h>
|
||||
|
||||
int TestVariantGeneratingComparisonOverloads()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
{
|
||||
eastl::variant<int, float, bool> a;
|
||||
eastl::variant<int, float, bool> b;
|
||||
|
||||
auto r = a == b;
|
||||
|
||||
nErrorCount += !r;
|
||||
}
|
||||
|
||||
{
|
||||
eastl::variant<int, float, bool> a;
|
||||
eastl::variant<int, float, bool> b;
|
||||
|
||||
bool r = (a == b);
|
||||
|
||||
nErrorCount += !r;
|
||||
}
|
||||
|
||||
// A variant is permitted to hold the same type more than once, and to hold differently cv-qualified versions of the same type.
|
||||
|
||||
{
|
||||
eastl::variant<int, int, int> a;
|
||||
eastl::variant<int, int, int> b;
|
||||
|
||||
bool r = (a == b);
|
||||
|
||||
nErrorCount += !r;
|
||||
}
|
||||
|
||||
{
|
||||
eastl::variant<signed int, unsigned int> a;
|
||||
eastl::variant<signed int, unsigned int> b;
|
||||
|
||||
bool r = (a == b);
|
||||
|
||||
nErrorCount += !r;
|
||||
}
|
||||
|
||||
{
|
||||
eastl::variant<int, bool> a;
|
||||
eastl::variant<int, bool> b;
|
||||
|
||||
bool r = (a == b);
|
||||
|
||||
nErrorCount += !r;
|
||||
}
|
||||
|
||||
{
|
||||
eastl::variant<volatile int, int, const int, const volatile int> a;
|
||||
eastl::variant<volatile int, int, const int, const volatile int> b;
|
||||
|
||||
bool r = (a == b);
|
||||
|
||||
nErrorCount += !r;
|
||||
}
|
||||
|
||||
{
|
||||
eastl::variant<volatile int, int, const int, const volatile int, bool> a;
|
||||
eastl::variant<volatile int, int, const int, const volatile int, bool> b;
|
||||
|
||||
bool r = (a == b);
|
||||
|
||||
nErrorCount += !r;
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,235 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "TestMap.h"
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/vector_map.h>
|
||||
#include <EASTL/vector_multimap.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/deque.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/fixed_string.h>
|
||||
#include <EASTL/fixed_vector.h>
|
||||
#include <EASTL/utility.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <map>
|
||||
#endif
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::vector_map<int, int>;
|
||||
template class eastl::vector_multimap<float, int>;
|
||||
template class eastl::vector_map<TestObject, TestObject>;
|
||||
template class eastl::vector_multimap<TestObject, TestObject>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// typedefs
|
||||
//
|
||||
typedef eastl::vector_map<int, int> VM1;
|
||||
typedef eastl::vector_map<int, int, eastl::less<int>, EASTLAllocatorType, eastl::deque<eastl::pair<int, int> > > VM2;
|
||||
|
||||
typedef eastl::vector_map<TestObject, TestObject> VM4;
|
||||
typedef eastl::vector_map<TestObject, TestObject, eastl::less<TestObject>, EASTLAllocatorType, eastl::deque<eastl::pair<TestObject, TestObject> > > VM5;
|
||||
|
||||
typedef eastl::vector_multimap<int, int> VMM1;
|
||||
typedef eastl::vector_multimap<int, int, eastl::less<int>, EASTLAllocatorType, eastl::deque<eastl::pair<int, int> > > VMM2;
|
||||
|
||||
typedef eastl::vector_multimap<TestObject, TestObject> VMM4;
|
||||
typedef eastl::vector_multimap<TestObject, TestObject, eastl::less<TestObject>, EASTLAllocatorType, eastl::deque<eastl::pair<TestObject, TestObject> > > VMM5;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
typedef std::map<int, int> VM3;
|
||||
typedef std::map<TestObject, TestObject> VM6;
|
||||
typedef std::multimap<int, int> VMM3;
|
||||
typedef std::multimap<TestObject, TestObject> VMM6;
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
int TestVectorMap()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
{ // Test construction
|
||||
nErrorCount += TestMapConstruction<VM1, VM3, false>();
|
||||
nErrorCount += TestMapConstruction<VM2, VM3, false>();
|
||||
nErrorCount += TestMapConstruction<VM4, VM6, false>();
|
||||
nErrorCount += TestMapConstruction<VM5, VM6, false>();
|
||||
|
||||
nErrorCount += TestMapConstruction<VMM1, VMM3, true>();
|
||||
nErrorCount += TestMapConstruction<VMM2, VMM3, true>();
|
||||
nErrorCount += TestMapConstruction<VMM4, VMM6, true>();
|
||||
nErrorCount += TestMapConstruction<VMM5, VMM6, true>();
|
||||
}
|
||||
|
||||
|
||||
{ // Test mutating functionality.
|
||||
nErrorCount += TestMapMutation<VM1, VM3, false>();
|
||||
nErrorCount += TestMapMutation<VM2, VM3, false>();
|
||||
nErrorCount += TestMapMutation<VM4, VM6, false>();
|
||||
nErrorCount += TestMapMutation<VM5, VM6, false>();
|
||||
|
||||
nErrorCount += TestMapMutation<VMM1, VMM3, true>();
|
||||
nErrorCount += TestMapMutation<VMM2, VMM3, true>();
|
||||
nErrorCount += TestMapMutation<VMM4, VMM6, true>();
|
||||
nErrorCount += TestMapMutation<VMM5, VMM6, true>();
|
||||
}
|
||||
#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
|
||||
{ // Test search functionality.
|
||||
nErrorCount += TestMapSearch<VM1, false>();
|
||||
nErrorCount += TestMapSearch<VM2, false>();
|
||||
nErrorCount += TestMapSearch<VM4, false>();
|
||||
nErrorCount += TestMapSearch<VM5, false>();
|
||||
|
||||
nErrorCount += TestMapSearch<VMM1, true>();
|
||||
nErrorCount += TestMapSearch<VMM2, true>();
|
||||
nErrorCount += TestMapSearch<VMM4, true>();
|
||||
nErrorCount += TestMapSearch<VMM5, true>();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// C++11 emplace and related functionality
|
||||
nErrorCount += TestMapCpp11<eastl::vector_map<int, TestObject> >();
|
||||
nErrorCount += TestMapCpp11<eastl::vector_map<int, TestObject, eastl::less<int>, EASTLAllocatorType, eastl::deque<eastl::pair<int, TestObject> > > >();
|
||||
|
||||
nErrorCount += TestMultimapCpp11<eastl::vector_multimap<int, TestObject> >();
|
||||
nErrorCount += TestMultimapCpp11<eastl::vector_multimap<int, TestObject, eastl::less<int>, EASTLAllocatorType, eastl::deque<eastl::pair<int, TestObject> > > >();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// insert at the upper bound of a range
|
||||
VMM1 vmm = {{0, 0}};
|
||||
VERIFY(vmm.emplace(0, 0) != vmm.begin());
|
||||
}
|
||||
|
||||
|
||||
{ // Misc tests
|
||||
|
||||
// const key_compare& key_comp() const;
|
||||
// key_compare& key_comp();
|
||||
VM2 vm;
|
||||
const VM2 vmc;
|
||||
|
||||
const VM2::key_compare& kc = vmc.key_comp();
|
||||
vm.key_comp() = kc;
|
||||
|
||||
// ensure count can be called from a const object
|
||||
vmc.count(0);
|
||||
}
|
||||
|
||||
{
|
||||
const VMM1 vmm;
|
||||
|
||||
// ensure count can be called from a const object
|
||||
vmm.count(0);
|
||||
}
|
||||
|
||||
{
|
||||
// Misc testing
|
||||
typedef eastl::fixed_vector<eastl::pair<int, float>, 8> FV;
|
||||
typedef eastl::vector_map<int, float, eastl::less<int>, FV::allocator_type, FV> FixedVectorMap;
|
||||
|
||||
FixedVectorMap fvm;
|
||||
|
||||
for(int i = FV::kMaxSize - 1; i >= 0; i--)
|
||||
fvm.insert(eastl::pair<int, float>(i, (float)i));
|
||||
|
||||
FixedVectorMap::iterator it = fvm.find(3);
|
||||
EATEST_VERIFY(it != fvm.end());
|
||||
}
|
||||
|
||||
{
|
||||
// Misc testing
|
||||
typedef eastl::fixed_string<char, 16> KeyStringType;
|
||||
typedef eastl::fixed_string<char, 24> ValueStringType;
|
||||
typedef eastl::pair<ValueStringType, bool> StringMapValueType;
|
||||
|
||||
typedef eastl::vector_map<KeyStringType, StringMapValueType> StringMapType;
|
||||
StringMapType stringMap;
|
||||
|
||||
stringMap.reserve(20);
|
||||
EATEST_VERIFY(stringMap.capacity() == 20);
|
||||
|
||||
StringMapValueType& v1 = stringMap["abc"];
|
||||
EATEST_VERIFY(strlen(v1.first.c_str()) == 0);
|
||||
v1.first.clear();
|
||||
EATEST_VERIFY(strlen(v1.first.c_str()) == 0);
|
||||
|
||||
StringMapValueType& v2 = stringMap["def"];
|
||||
EATEST_VERIFY(strlen(v2.first.c_str()) == 0);
|
||||
v2.first = "def";
|
||||
EATEST_VERIFY(strlen(v2.first.c_str()) == 3);
|
||||
}
|
||||
|
||||
{
|
||||
// Regression for problem observed in EAWebKit
|
||||
typedef eastl::vector_map<eastl::string, void*> TestVectorMap;
|
||||
|
||||
TestVectorMap tvm;
|
||||
|
||||
tvm["Parameters"] = NULL;
|
||||
tvm["ThemeParameters"] = NULL;
|
||||
tvm["CookieInfo"] = NULL;
|
||||
tvm["DiskCacheInfo"] = NULL;
|
||||
tvm["RamCacheInfo"] = NULL;
|
||||
tvm["SSLCert"] = NULL;
|
||||
tvm["AllowedDomain"] = NULL;
|
||||
}
|
||||
|
||||
{ // find_as predicate
|
||||
{ // vector_map
|
||||
eastl::vector_map<string, int> vss = {{"abc", 11}, {"def", 22}, {"ghi", 33}, {"jklmnop", 44},
|
||||
{"qrstu", 55}, {"vw", 66}, {"x", 77}, {"yz", 88}};
|
||||
VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end());
|
||||
}
|
||||
|
||||
{ // const vector_map
|
||||
const eastl::vector_map<string, int> vss = {{"abc", 11}, {"def", 22}, {"ghi", 33}, {"jklmnop", 44},
|
||||
{"qrstu", 55}, {"vw", 66}, {"x", 77}, {"yz", 88}};
|
||||
VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end());
|
||||
}
|
||||
|
||||
// vector_multimap
|
||||
{
|
||||
eastl::vector_multimap<string, int> vss = {{"abc", 11}, {"def", 22}, {"ghi", 33}, {"jklmnop", 44},
|
||||
{"qrstu", 55}, {"vw", 66}, {"x", 77}, {"yz", 88}};
|
||||
VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end());
|
||||
}
|
||||
|
||||
// const vector_multimap
|
||||
{
|
||||
const eastl::vector_multimap<string, int> vss = {{"abc", 11}, {"def", 22}, {"ghi", 33}, {"jklmnop", 44},
|
||||
{"qrstu", 55}, {"vw", 66}, {"x", 77}, {"yz", 88}};
|
||||
VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end());
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#include "TestSet.h"
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/vector_set.h>
|
||||
#include <EASTL/vector_multiset.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/deque.h>
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
#include <set>
|
||||
#endif
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::vector_set<int>;
|
||||
template class eastl::vector_multiset<float>;
|
||||
template class eastl::vector_set<TestObject>;
|
||||
template class eastl::vector_multiset<TestObject>;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// typedefs
|
||||
//
|
||||
typedef eastl::vector_set<int> VS1;
|
||||
typedef eastl::vector_set<int, eastl::less<int>, EASTLAllocatorType, eastl::deque<int> > VS2;
|
||||
typedef eastl::vector_set<TestObject> VS4;
|
||||
typedef eastl::vector_set<TestObject, eastl::less<TestObject>, EASTLAllocatorType, eastl::deque<TestObject> > VS5;
|
||||
typedef eastl::vector_multiset<int> VMS1;
|
||||
typedef eastl::vector_multiset<int, eastl::less<int>, EASTLAllocatorType, eastl::deque<int> > VMS2;
|
||||
typedef eastl::vector_multiset<TestObject> VMS4;
|
||||
typedef eastl::vector_multiset<TestObject, eastl::less<TestObject>, EASTLAllocatorType, eastl::deque<TestObject> > VMS5;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
typedef std::set<int> VS3;
|
||||
typedef std::set<TestObject> VS6;
|
||||
typedef std::multiset<int> VMS3;
|
||||
typedef std::multiset<TestObject> VMS6;
|
||||
#endif
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
int TestVectorSet()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
#ifndef EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
{ // Test construction
|
||||
nErrorCount += TestSetConstruction<VS1, VS3, false>();
|
||||
nErrorCount += TestSetConstruction<VS2, VS3, false>();
|
||||
nErrorCount += TestSetConstruction<VS4, VS6, false>();
|
||||
nErrorCount += TestSetConstruction<VS5, VS6, false>();
|
||||
|
||||
nErrorCount += TestSetConstruction<VMS1, VMS3, true>();
|
||||
nErrorCount += TestSetConstruction<VMS2, VMS3, true>();
|
||||
nErrorCount += TestSetConstruction<VMS4, VMS6, true>();
|
||||
nErrorCount += TestSetConstruction<VMS5, VMS6, true>();
|
||||
}
|
||||
|
||||
|
||||
{ // Test mutating functionality.
|
||||
nErrorCount += TestSetMutation<VS1, VS3, false>();
|
||||
nErrorCount += TestSetMutation<VS2, VS3, false>();
|
||||
nErrorCount += TestSetMutation<VS4, VS6, false>();
|
||||
nErrorCount += TestSetMutation<VS5, VS6, false>();
|
||||
|
||||
nErrorCount += TestSetMutation<VMS1, VMS3, true>();
|
||||
nErrorCount += TestSetMutation<VMS2, VMS3, true>();
|
||||
nErrorCount += TestSetMutation<VMS4, VMS6, true>();
|
||||
nErrorCount += TestSetMutation<VMS5, VMS6, true>();
|
||||
}
|
||||
#endif // EA_COMPILER_NO_STANDARD_CPP_LIBRARY
|
||||
|
||||
|
||||
{ // Test search functionality.
|
||||
nErrorCount += TestSetSearch<VS1, false>();
|
||||
nErrorCount += TestSetSearch<VS2, false>();
|
||||
nErrorCount += TestSetSearch<VS4, false>();
|
||||
nErrorCount += TestSetSearch<VS5, false>();
|
||||
|
||||
nErrorCount += TestSetSearch<VMS1, true>();
|
||||
nErrorCount += TestSetSearch<VMS2, true>();
|
||||
nErrorCount += TestSetSearch<VMS4, true>();
|
||||
nErrorCount += TestSetSearch<VMS5, true>();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// C++11 emplace and related functionality
|
||||
nErrorCount += TestSetCpp11<VS4>();
|
||||
nErrorCount += TestSetCpp11<VS5>();
|
||||
|
||||
nErrorCount += TestMultisetCpp11<VMS4>();
|
||||
nErrorCount += TestMultisetCpp11<VMS5>();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// insert at the upper bound of a range
|
||||
VMS1 vms = {0};
|
||||
VERIFY(vms.insert(0) != vms.begin());
|
||||
}
|
||||
|
||||
|
||||
{ // Misc tests
|
||||
{
|
||||
// const key_compare& key_comp() const;
|
||||
// key_compare& key_comp();
|
||||
VS2 vs;
|
||||
const VS2 vsc;
|
||||
|
||||
// ensure count can be called from a const object
|
||||
const VS2::key_compare& kc = vsc.key_comp();
|
||||
vs.key_comp() = kc;
|
||||
vsc.count(0);
|
||||
}
|
||||
|
||||
{
|
||||
// ensure count can be called from a const object
|
||||
const VMS1 vms;
|
||||
vms.count(0);
|
||||
}
|
||||
}
|
||||
|
||||
{ // find_as predicate
|
||||
{ // vector_set
|
||||
eastl::vector_set<string> vss = {"abc", "def", "ghi", "jklmnop", "qrstu", "vw", "x", "yz"};
|
||||
VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end());
|
||||
}
|
||||
|
||||
{ // const vector_set
|
||||
const eastl::vector_set<string> vss = {"abc", "def", "ghi", "jklmnop", "qrstu", "vw", "x", "yz"};
|
||||
VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end());
|
||||
}
|
||||
|
||||
{ // vector_multiset
|
||||
eastl::vector_multiset<string> vss = {"abc", "def", "ghi", "jklmnop", "qrstu", "vw", "x", "yz"};
|
||||
VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end());
|
||||
}
|
||||
|
||||
{ // const vector_multiset
|
||||
const eastl::vector_multiset<string> vss = {"abc", "def", "ghi", "jklmnop", "qrstu", "vw", "x", "yz"};
|
||||
VERIFY(vss.find_as("GHI", TestStrCmpI_2()) != vss.end());
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EAStdC/EASprintf.h>
|
||||
#include <EASTL/internal/config.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
|
||||
#include "EAMain/EAEntryPointMain.inl"
|
||||
#include "EASTLTestAllocator.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Required by EASTL.
|
||||
//
|
||||
#if !EASTL_EASTDC_VSNPRINTF
|
||||
int Vsnprintf8(char* pDestination, size_t n, const char* pFormat, va_list arguments)
|
||||
{
|
||||
return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments);
|
||||
}
|
||||
|
||||
int Vsnprintf16(char16_t* pDestination, size_t n, const char16_t* pFormat, va_list arguments)
|
||||
{
|
||||
return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments);
|
||||
}
|
||||
|
||||
int Vsnprintf32(char32_t* pDestination, size_t n, const char32_t* pFormat, va_list arguments)
|
||||
{
|
||||
return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments);
|
||||
}
|
||||
|
||||
#if defined(EA_CHAR8_UNIQUE) && EA_CHAR8_UNIQUE
|
||||
int Vsnprintf8(char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments)
|
||||
{
|
||||
return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(EA_WCHAR_UNIQUE) && EA_WCHAR_UNIQUE
|
||||
int VsnprintfW(wchar_t* pDestination, size_t n, const wchar_t* pFormat, va_list arguments)
|
||||
{
|
||||
return EA::StdC::Vsnprintf(pDestination, n, pFormat, arguments);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EAMain
|
||||
//
|
||||
int EAMain(int argc, char* argv[])
|
||||
{
|
||||
using namespace EA::UnitTest;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
EA::EAMain::PlatformStartup();
|
||||
|
||||
EASTLTest_SetGeneralAllocator();
|
||||
|
||||
nErrorCount += EASTLTest_CheckMemory();
|
||||
|
||||
// Parse command line arguments
|
||||
for(int i = 1; i < argc; i++)
|
||||
{
|
||||
// Example usage: -l:7
|
||||
if(strstr(argv[i], "-l:") == argv[i])
|
||||
{
|
||||
gEASTL_TestLevel = atoi(argv[i] + 3);
|
||||
|
||||
if(gEASTL_TestLevel < kEASTL_TestLevelLow)
|
||||
gEASTL_TestLevel = kEASTL_TestLevelLow;
|
||||
if(gEASTL_TestLevel > kEASTL_TestLevelHigh)
|
||||
gEASTL_TestLevel = kEASTL_TestLevelHigh;
|
||||
}
|
||||
}
|
||||
|
||||
TestApplication testSuite("EASTL Unit Tests", argc, argv);
|
||||
|
||||
testSuite.AddTest("Algorithm", TestAlgorithm);
|
||||
testSuite.AddTest("Allocator", TestAllocator);
|
||||
testSuite.AddTest("Any", TestAny);
|
||||
testSuite.AddTest("Array", TestArray);
|
||||
testSuite.AddTest("BitVector", TestBitVector);
|
||||
testSuite.AddTest("Bitset", TestBitset);
|
||||
testSuite.AddTest("CharTraits", TestCharTraits);
|
||||
testSuite.AddTest("Chrono", TestChrono);
|
||||
testSuite.AddTest("Deque", TestDeque);
|
||||
testSuite.AddTest("Extra", TestExtra);
|
||||
testSuite.AddTest("Finally", TestFinally);
|
||||
testSuite.AddTest("FixedFunction", TestFixedFunction);
|
||||
testSuite.AddTest("FixedHash", TestFixedHash);
|
||||
testSuite.AddTest("FixedList", TestFixedList);
|
||||
testSuite.AddTest("FixedMap", TestFixedMap);
|
||||
testSuite.AddTest("FixedSList", TestFixedSList);
|
||||
testSuite.AddTest("FixedSet", TestFixedSet);
|
||||
testSuite.AddTest("FixedString", TestFixedString);
|
||||
testSuite.AddTest("FixedTupleVector", TestFixedTupleVector);
|
||||
testSuite.AddTest("FixedVector", TestFixedVector);
|
||||
testSuite.AddTest("Functional", TestFunctional);
|
||||
testSuite.AddTest("Hash", TestHash);
|
||||
testSuite.AddTest("Heap", TestHeap);
|
||||
testSuite.AddTest("IntrusiveHash", TestIntrusiveHash);
|
||||
testSuite.AddTest("IntrusiveList", TestIntrusiveList);
|
||||
testSuite.AddTest("IntrusiveSDList", TestIntrusiveSDList);
|
||||
testSuite.AddTest("IntrusiveSList", TestIntrusiveSList);
|
||||
testSuite.AddTest("Iterator", TestIterator);
|
||||
testSuite.AddTest("LRUCache", TestLruCache);
|
||||
testSuite.AddTest("List", TestList);
|
||||
testSuite.AddTest("ListMap", TestListMap);
|
||||
testSuite.AddTest("Map", TestMap);
|
||||
testSuite.AddTest("Memory", TestMemory);
|
||||
testSuite.AddTest("Meta", TestMeta);
|
||||
testSuite.AddTest("NumericLimits", TestNumericLimits);
|
||||
testSuite.AddTest("Optional", TestOptional);
|
||||
testSuite.AddTest("Random", TestRandom);
|
||||
testSuite.AddTest("Ratio", TestRatio);
|
||||
testSuite.AddTest("RingBuffer", TestRingBuffer);
|
||||
testSuite.AddTest("SList", TestSList);
|
||||
testSuite.AddTest("SegmentedVector", TestSegmentedVector);
|
||||
testSuite.AddTest("Set", TestSet);
|
||||
testSuite.AddTest("SmartPtr", TestSmartPtr);
|
||||
testSuite.AddTest("Sort", TestSort);
|
||||
testSuite.AddTest("Span", TestSpan);
|
||||
testSuite.AddTest("String", TestString);
|
||||
testSuite.AddTest("StringHashMap", TestStringHashMap);
|
||||
testSuite.AddTest("StringMap", TestStringMap);
|
||||
testSuite.AddTest("StringView", TestStringView);
|
||||
testSuite.AddTest("TestCppCXTypeTraits", TestCppCXTypeTraits);
|
||||
testSuite.AddTest("Tuple", TestTuple);
|
||||
testSuite.AddTest("TupleVector", TestTupleVector);
|
||||
testSuite.AddTest("TypeTraits", TestTypeTraits);
|
||||
testSuite.AddTest("Utility", TestUtility);
|
||||
testSuite.AddTest("Variant", TestVariant);
|
||||
testSuite.AddTest("Vector", TestVector);
|
||||
testSuite.AddTest("VectorMap", TestVectorMap);
|
||||
testSuite.AddTest("VectorSet", TestVectorSet);
|
||||
testSuite.AddTest("AtomicBasic", TestAtomicBasic);
|
||||
testSuite.AddTest("AtomicAsm", TestAtomicAsm);
|
||||
testSuite.AddTest("Bitcast", TestBitcast);
|
||||
|
||||
|
||||
nErrorCount += testSuite.Run();
|
||||
|
||||
nErrorCount += EASTLTest_CheckMemory();
|
||||
|
||||
EA::EAMain::PlatformShutdown(nErrorCount);
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user