pcsx-redux/third_party/EASTL/test/source/EASTLTest.h
Nicolas 'Pixel' Noble d63f87a7f4 Adding EASTL.
2022-06-29 19:37:35 -07:00

1586 lines
50 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#ifndef EASTLTEST_H
#define EASTLTEST_H
#include <EABase/eabase.h>
#include <EATest/EATest.h>
EA_DISABLE_ALL_VC_WARNINGS()
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <vector> // For the STD_STL_TYPE defines below.
#if EASTL_EXCEPTIONS_ENABLED
#include <stdexcept>
#include <new>
#endif
EA_RESTORE_ALL_VC_WARNINGS();
int TestAlgorithm();
int TestAllocator();
int TestAny();
int TestArray();
int TestBitVector();
int TestBitset();
int TestCharTraits();
int TestChrono();
int TestCppCXTypeTraits();
int TestDeque();
int TestExtra();
int TestFinally();
int TestFixedFunction();
int TestFixedHash();
int TestFixedList();
int TestFixedMap();
int TestFixedSList();
int TestFixedSet();
int TestFixedString();
int TestFixedTupleVector();
int TestFixedVector();
int TestFunctional();
int TestHash();
int TestHeap();
int TestIntrusiveHash();
int TestIntrusiveList();
int TestIntrusiveSDList();
int TestIntrusiveSList();
int TestIterator();
int TestList();
int TestListMap();
int TestLruCache();
int TestMap();
int TestMemory();
int TestMeta();
int TestNumericLimits();
int TestOptional();
int TestRandom();
int TestRatio();
int TestRingBuffer();
int TestSList();
int TestSegmentedVector();
int TestSet();
int TestSmartPtr();
int TestSort();
int TestSpan();
int TestString();
int TestStringHashMap();
int TestStringMap();
int TestStringView();
int TestTuple();
int TestTupleVector();
int TestTypeTraits();
int TestUtility();
int TestVariant();
int TestVector();
int TestVectorMap();
int TestVectorSet();
int TestAtomicBasic();
int TestAtomicAsm();
int TestBitcast();
// Now enable warnings as desired.
#ifdef _MSC_VER
#pragma warning(disable: 4324) // 'struct_name' : structure was padded due to __declspec(align())
//#pragma warning(disable: 4512) // 'class' : assignment operator could not be generated
//#pragma warning(disable: 4100) // 'identifier' : unreferenced formal parameter
//#pragma warning(disable: 4706) // assignment within conditional expression
#pragma warning(default: 4056) // Floating-point constant arithmetic generates a result that exceeds the maximum allowable value
#pragma warning(default: 4061) // The enumerate has no associated handler in a switch statement
#pragma warning(default: 4062) // The enumerate has no associated handler in a switch statement, and there is no default label
#pragma warning(default: 4191) // Calling this function through the result pointer may cause your program to crash
#pragma warning(default: 4217) // Member template functions cannot be used for copy-assignment or copy-construction
//#pragma warning(default: 4242) // 'variable' : conversion from 'type' to 'type', possible loss of data
#pragma warning(default: 4254) // 'operator' : conversion from 'type1' to 'type2', possible loss of data
#pragma warning(default: 4255) // 'function' : no function prototype given: converting '()' to '(void)'
#pragma warning(default: 4263) // 'function' : member function does not override any base class virtual member function
#pragma warning(default: 4264) // 'virtual_function' : no override available for virtual member function from base 'class'; function is hidden
#pragma warning(default: 4287) // 'operator' : unsigned/negative constant mismatch
#pragma warning(default: 4289) // Nonstandard extension used : 'var' : loop control variable declared in the for-loop is used outside the for-loop scope
#pragma warning(default: 4296) // 'operator' : expression is always false
#pragma warning(default: 4302) // 'conversion' : truncation from 'type 1' to 'type 2'
#pragma warning(default: 4339) // 'type' : use of undefined type detected in CLR meta-data - use of this type may lead to a runtime exception
#pragma warning(default: 4347) // Behavior change: 'function template' is called instead of 'function'
//#pragma warning(default: 4514) // unreferenced inline/local function has been removed
#pragma warning(default: 4529) // 'member_name' : forming a pointer-to-member requires explicit use of the address-of operator ('&') and a qualified name
#pragma warning(default: 4545) // Expression before comma evaluates to a function which is missing an argument list
#pragma warning(default: 4546) // Function call before comma missing argument list
#pragma warning(default: 4547) // 'operator' : operator before comma has no effect; expected operator with side-effect
//#pragma warning(default: 4548) // expression before comma has no effect; expected expression with side-effect
#pragma warning(default: 4549) // 'operator' : operator before comma has no effect; did you intend 'operator'?
#pragma warning(default: 4536) // 'type name' : type-name exceeds meta-data limit of 'limit' characters
#pragma warning(default: 4555) // Expression has no effect; expected expression with side-effect
#pragma warning(default: 4557) // '__assume' contains effect 'effect'
//#pragma warning(default: 4619) // #pragma warning : there is no warning number 'number'
#pragma warning(default: 4623) // 'derived class' : default constructor could not be generated because a base class default constructor is inaccessible
//#pragma warning(default: 4625) // 'derived class' : copy constructor could not be generated because a base class copy constructor is inaccessible
//#pragma warning(default: 4626) // 'derived class' : assignment operator could not be generated because a base class assignment operator is inaccessible
#pragma warning(default: 4628) // Digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char'
#pragma warning(default: 4640) // 'instance' : construction of local static object is not thread-safe
#pragma warning(default: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
#pragma warning(default: 4682) // 'parameter' : no directional parameter attribute specified, defaulting to [in]
#pragma warning(default: 4686) // 'user-defined type' : possible change in behavior, change in UDT return calling convention
//#pragma warning(default: 4710) // 'function' : function not inlined
//#pragma warning(default: 4786) // 'identifier' : identifier was truncated to 'number' characters in the debug information
#pragma warning(default: 4793) // Native code generated for function 'function': 'reason'
//#pragma warning(default: 4820) // 'bytes' bytes padding added after member 'member'
#pragma warning(default: 4905) // Wide string literal cast to 'LPSTR'
#pragma warning(default: 4906) // String literal cast to 'LPWSTR'
#pragma warning(default: 4917) // 'declarator' : a GUID cannot only be associated with a class, interface or namespace
#pragma warning(default: 4928) // Illegal copy-initialization; more than one user-defined conversion has been implicitly applied
#pragma warning(default: 4931) // We are assuming the type library was built for number-bit pointers
#pragma warning(default: 4946) // reinterpret_cast used between related classes: 'class1' and 'class2'
#endif
///////////////////////////////////////////////////////////////////////////////
// EASTL includes
//
// Intentionally keep these includes below the warning settings specified above.
//
#include <EASTL/iterator.h>
#include <EASTL/algorithm.h>
/// EASTL_TestLevel
///
/// Defines how extensive our testing is. A low level is for a desktop or
/// nightly build in which the test can run quickly but still hit the
/// majority of functionality. High level is for heavy testing and internal
/// validation which may take numerous hours to run.
///
enum EASTL_TestLevel
{
kEASTL_TestLevelLow = 1, /// ~10 seconds for test completion.
kEASTL_TestLevelHigh = 10 /// Numerous hours for test completion.
};
extern int gEASTL_TestLevel;
/// EASTLTest_CheckMemory
///
/// Does a global memory heap validation check. Returns 0 if OK and
/// an error count if there is a problem.
///
/// Example usage:
/// EASTLTest_CheckMemory();
///
int EASTLTest_CheckMemory_Imp(const char* pFile, int nLine);
#define EASTLTest_CheckMemory() EASTLTest_CheckMemory_Imp(__FILE__, __LINE__)
// EASTLTEST_STD_STL_VER
//
#if defined(_STLPORT_VERSION)
#define EASTLTEST_STD_STL_VER_STLPORT
#elif defined(_RWSTD_VER_STR) || defined(_RWSTD_NAMESPACE_END)
#define EASTLTEST_STD_STL_VER_APACHE
#elif defined(_CPPLIB_VER)
#define EASTLTEST_STD_STL_VER_DINKUMWARE
#elif defined(__GNUC__) && defined(_CXXCONFIG)
#define EASTLTEST_STD_STL_VER_GCC
#else
#define EASTLTEST_STD_STL_VER_UNKNOWN
#endif
/// StdSTLType
///
enum StdSTLType
{
kSTLUnknown, // Unknown type
kSTLPort, // STLPort. Descendent of the old HP / SGI STL.
kSTLApache, // Apache stdcxx (previously RogueWave), which is a descendent of the old HP / SGI STL.
kSTLClang, // Clang native. a.k.a. libc++
kSTLGCC, // GCC native. a.k.a. libstdc++
kSTLMS, // Microsoft. Tweaked version of Dinkumware.
kSTLDinkumware // Generic Dinkumware
};
StdSTLType GetStdSTLType();
/// GetStdSTLName
///
/// Returns the name of the std C++ STL available to the current build.
/// The returned value will be one of:
/// "STLPort"
/// "GCC"
/// "VC++"
// "Apache" // Previously RogueWave
///
const char* GetStdSTLName();
/// gEASTLTest_AllocationCount
///
extern int gEASTLTest_AllocationCount;
extern int gEASTLTest_TotalAllocationCount;
// For backwards compatibility:
#define EASTLTest_Printf EA::UnitTest::Report
#define VERIFY EATEST_VERIFY
///////////////////////////////////////////////////////////////////////////////
/// EASTLTest_Rand
///
/// Implements a basic random number generator for EASTL unit tests. It's not
/// intended to be a robust random number generator (though it is decent),
/// but rather is present so the unit tests can have a portable random number
/// generator they can rely on being present.
///
/// Example usage:
/// EASTLTest_Rand rng;
/// eastl_size_t x = rng(); // Generate value in range of [0, 0xffffffff] (i.e. generate any uint32_t)
/// eastl_ssize_t y = rng.Rand(1000); // Generate value in range of [0, 1000)
/// eastl_ssize_t z = rng.RandRange(-50, +30); // Generate value in range of [-50, +30)
///
/// Example usage in the random_shuffle algorithm:
/// EASTLTest_Rand rng;
/// random_shuffle(first, last, rnd);
///
class EASTLTest_Rand
{
public:
EASTLTest_Rand(eastl_size_t nSeed) // The user must supply a seed; we don't provide default values.
: mnSeed(nSeed) { }
eastl_size_t Rand()
{
// This is not designed to be a high quality random number generator.
if(mnSeed == 0)
mnSeed = UINT64_C(0xfefefefefefefefe); // Can't have a seed of zero.
const uint64_t nResult64A = ((mnSeed * UINT64_C(6364136223846793005)) + UINT64_C(1442695040888963407));
const uint64_t nResult64B = ((nResult64A * UINT64_C(6364136223846793005)) + UINT64_C(1442695040888963407));
mnSeed = (nResult64A >> 32) ^ nResult64B;
return (eastl_size_t)mnSeed; // For eastl_size_t == uint32_t, this is a chop.
}
eastl_size_t operator()() // Returns a pseudorandom value in range of [0, 0xffffffffffffffff)] (i.e. generate any eastl_size_t)
{ return Rand(); }
eastl_size_t operator()(eastl_size_t n) // Returns a pseudorandom value in range of [0, n)
{ return RandLimit(n); }
eastl_size_t RandLimit(eastl_size_t nLimit) // Returns a pseudorandom value in range of [0, nLimit)
{
// Can't do the following correct solution because we don't have a portable int128_t to work with.
// We could implement a 128 bit multiply manually. See EAStdC/int128_t.cpp.
// return (eastl_size_t)((Rand() * (uint128_t)nLimit) >> 64);
return (Rand() % nLimit); // This results in an imperfect distribution, especially for the case of nLimit being high relative to eastl_size_t.
}
eastl_ssize_t RandRange(eastl_ssize_t nBegin, eastl_ssize_t nEnd) // Returns a pseudorandom value in range of [nBegin, nEnd)
{ return nBegin + (eastl_ssize_t)RandLimit((eastl_size_t)(nEnd - nBegin)); }
protected:
uint64_t mnSeed;
};
///////////////////////////////////////////////////////////////////////////////
/// RandGenT
///
/// A wrapper for EASTLTest_Rand which generates values of the given integral
/// data type. This is mostly useful for clearnly avoiding compiler warnings,
/// as we intentionally enable the highest warning levels in these tests.
///
template <typename Integer>
struct RandGenT
{
RandGenT(eastl_size_t nSeed)
: mRand(nSeed) { }
Integer operator()()
{ return (Integer)mRand.Rand(); }
Integer operator()(eastl_size_t n)
{ return (Integer)mRand.RandLimit(n); }
EASTLTest_Rand mRand;
};
///////////////////////////////////////////////////////////////////////////////
/// kMagicValue
///
/// Used as a unique integer. We assign this to TestObject in its constructor
/// and verify in the TestObject destructor that the value is unchanged.
/// This can be used to tell, for example, if an invalid object is being
/// destroyed.
///
const uint32_t kMagicValue = 0x01f1cbe8;
///////////////////////////////////////////////////////////////////////////////
/// TestObject
///
/// Implements a generic object that is suitable for use in container tests.
/// Note that we choose a very restricted set of functions that are available
/// for this class. Do not add any additional functions, as that would
/// compromise the intentions of the unit tests.
///
struct TestObject
{
int mX; // Value for the TestObject.
bool mbThrowOnCopy; // Throw an exception of this object is copied, moved, or assigned to another.
int64_t mId; // Unique id for each object, equal to its creation number. This value is not coped from other TestObjects during any operations, including moves.
uint32_t mMagicValue; // Used to verify that an instance is valid and that it is not corrupted. It should always be kMagicValue.
static int64_t sTOCount; // Count of all current existing TestObjects.
static int64_t sTOCtorCount; // Count of times any ctor was called.
static int64_t sTODtorCount; // Count of times dtor was called.
static int64_t sTODefaultCtorCount; // Count of times the default ctor was called.
static int64_t sTOArgCtorCount; // Count of times the x0,x1,x2 ctor was called.
static int64_t sTOCopyCtorCount; // Count of times copy ctor was called.
static int64_t sTOMoveCtorCount; // Count of times move ctor was called.
static int64_t sTOCopyAssignCount; // Count of times copy assignment was called.
static int64_t sTOMoveAssignCount; // Count of times move assignment was called.
static int sMagicErrorCount; // Number of magic number mismatch errors.
explicit TestObject(int x = 0, bool bThrowOnCopy = false)
: mX(x), mbThrowOnCopy(bThrowOnCopy), mMagicValue(kMagicValue)
{
++sTOCount;
++sTOCtorCount;
++sTODefaultCtorCount;
mId = sTOCtorCount;
}
// This constructor exists for the purpose of testing variadiac template arguments, such as with the emplace container functions.
TestObject(int x0, int x1, int x2, bool bThrowOnCopy = false)
: mX(x0 + x1 + x2), mbThrowOnCopy(bThrowOnCopy), mMagicValue(kMagicValue)
{
++sTOCount;
++sTOCtorCount;
++sTOArgCtorCount;
mId = sTOCtorCount;
}
TestObject(const TestObject& testObject)
: mX(testObject.mX), mbThrowOnCopy(testObject.mbThrowOnCopy), mMagicValue(testObject.mMagicValue)
{
++sTOCount;
++sTOCtorCount;
++sTOCopyCtorCount;
mId = sTOCtorCount;
if(mbThrowOnCopy)
{
#if EASTL_EXCEPTIONS_ENABLED
throw "Disallowed TestObject copy";
#endif
}
}
// Due to the nature of TestObject, there isn't much special for us to
// do in our move constructor. A move constructor swaps its contents with
// the other object, whhich is often a default-constructed object.
TestObject(TestObject&& testObject)
: mX(testObject.mX), mbThrowOnCopy(testObject.mbThrowOnCopy), mMagicValue(testObject.mMagicValue)
{
++sTOCount;
++sTOCtorCount;
++sTOMoveCtorCount;
mId = sTOCtorCount; // testObject keeps its mId, and we assign ours anew.
testObject.mX = 0; // We are swapping our contents with the TestObject, so give it our "previous" value.
if(mbThrowOnCopy)
{
#if EASTL_EXCEPTIONS_ENABLED
throw "Disallowed TestObject copy";
#endif
}
}
TestObject& operator=(const TestObject& testObject)
{
++sTOCopyAssignCount;
if(&testObject != this)
{
mX = testObject.mX;
// Leave mId alone.
mMagicValue = testObject.mMagicValue;
mbThrowOnCopy = testObject.mbThrowOnCopy;
if(mbThrowOnCopy)
{
#if EASTL_EXCEPTIONS_ENABLED
throw "Disallowed TestObject copy";
#endif
}
}
return *this;
}
TestObject& operator=(TestObject&& testObject)
{
++sTOMoveAssignCount;
if(&testObject != this)
{
eastl::swap(mX, testObject.mX);
// Leave mId alone.
eastl::swap(mMagicValue, testObject.mMagicValue);
eastl::swap(mbThrowOnCopy, testObject.mbThrowOnCopy);
if(mbThrowOnCopy)
{
#if EASTL_EXCEPTIONS_ENABLED
throw "Disallowed TestObject copy";
#endif
}
}
return *this;
}
~TestObject()
{
if(mMagicValue != kMagicValue)
++sMagicErrorCount;
mMagicValue = 0;
--sTOCount;
++sTODtorCount;
}
static void Reset()
{
sTOCount = 0;
sTOCtorCount = 0;
sTODtorCount = 0;
sTODefaultCtorCount = 0;
sTOArgCtorCount = 0;
sTOCopyCtorCount = 0;
sTOMoveCtorCount = 0;
sTOCopyAssignCount = 0;
sTOMoveAssignCount = 0;
sMagicErrorCount = 0;
}
static bool IsClear() // Returns true if there are no existing TestObjects and the sanity checks related to that test OK.
{
return (sTOCount == 0) && (sTODtorCount == sTOCtorCount) && (sMagicErrorCount == 0);
}
};
// Operators
// We specifically define only == and <, in order to verify that
// our containers and algorithms are not mistakenly expecting other
// operators for the contained and manipulated classes.
inline bool operator==(const TestObject& t1, const TestObject& t2)
{ return t1.mX == t2.mX; }
inline bool operator<(const TestObject& t1, const TestObject& t2)
{ return t1.mX < t2.mX; }
// TestObject hash
// Normally you don't want to put your hash functions in the eastl namespace, as that namespace is owned by EASTL.
// However, these are the EASTL unit tests and we can say that they are also owned by EASTL.
namespace eastl
{
template <>
struct hash<TestObject>
{
size_t operator()(const TestObject& a) const
{ return static_cast<size_t>(a.mX); }
};
}
// use_mX
// Used for printing TestObject contents via the PrintSequence function,
// which is defined below. See the PrintSequence function for documentation.
// This function is an analog of the eastl::use_self and use_first functions.
// We declare this all in one line because the user should never need to
// debug usage of this function.
template <typename T> struct use_mX { int operator()(const T& t) const { return t.mX; } };
///////////////////////////////////////////////////////////////////////////////
// SizedPOD
//
// Exists for the purpose testing PODs that are larger than built-in types.
//
template <size_t kSize>
struct SizedPOD
{
char memory[kSize];
};
///////////////////////////////////////////////////////////////////////////////
/// ConstType
///
/// Used to test const type containers (e.g. vector<const ConstType>).
///
class ConstType
{
public:
ConstType(int value) : mDummy(value) {};
int mDummy;
};
///////////////////////////////////////////////////////////////////////////////
/// TestObjectHash
///
/// Implements a manually specified hash function for TestObjects.
///
struct TestObjectHash
{
size_t operator()(const TestObject& t) const
{
return (size_t)t.mX;
}
};
///////////////////////////////////////////////////////////////////////////////
/// Align16
///
#if defined(EA_PROCESSOR_ARM)
#define kEASTLTestAlign16 8 //ARM processors can only align to 8
#else
#define kEASTLTestAlign16 16
#endif
EA_PREFIX_ALIGN(kEASTLTestAlign16)
struct Align16
{
explicit Align16(int x = 0) : mX(x) {}
int mX;
} EA_POSTFIX_ALIGN(kEASTLTestAlign16);
inline bool operator==(const Align16& a, const Align16& b)
{ return (a.mX == b.mX); }
inline bool operator<(const Align16& a, const Align16& b)
{ return (a.mX < b.mX); }
///////////////////////////////////////////////////////////////////////////////
/// Align32
///
#if defined(EA_PROCESSOR_ARM)
#define kEASTLTestAlign32 8 //ARM processors can only align to 8
#elif defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) < 400) // GCC 2.x, 3.x
#define kEASTLTestAlign32 16 // Some versions of GCC fail to support any alignment beyond 16.
#else
#define kEASTLTestAlign32 32
#endif
EA_PREFIX_ALIGN(kEASTLTestAlign32)
struct Align32
{
explicit Align32(int x = 0) : mX(x) {}
int mX;
} EA_POSTFIX_ALIGN(kEASTLTestAlign32);
inline bool operator==(const Align32& a, const Align32& b)
{ return (a.mX == b.mX); }
inline bool operator<(const Align32& a, const Align32& b)
{ return (a.mX < b.mX); }
///////////////////////////////////////////////////////////////////////////////
/// Align64
///
/// Used for testing of alignment.
///
#if defined(EA_PROCESSOR_ARM)
#define kEASTLTestAlign64 8
#elif defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) < 400) // GCC 2.x, 3.x
#define kEASTLTestAlign64 16 // Some versions of GCC fail to support any alignment beyond 16.
#else
#define kEASTLTestAlign64 64
#endif
EA_PREFIX_ALIGN(kEASTLTestAlign64)
struct Align64
{
explicit Align64(int x = 0) : mX(x) {}
int mX;
} EA_POSTFIX_ALIGN(kEASTLTestAlign64);
inline bool operator==(const Align64& a, const Align64& b)
{ return (a.mX == b.mX); }
inline bool operator<(const Align64& a, const Align64& b)
{ return (a.mX < b.mX); }
namespace eastl
{
template <>
struct hash < Align64 >
{
size_t operator()(const Align64& a) const
{
return static_cast<size_t>(a.mX);
}
};
}
/// test_use_self
///
/// Intentionally avoiding a dependency on eastl::use_self.
///
template <typename T>
struct test_use_self
{
const T& operator()(const T& x) const
{ return x; }
};
/// GenerateIncrementalIntegers
///
/// Used to seed containers with incremental values based on integers.
///
/// Example usage:
/// vector<int> v(10, 0);
/// generate(v.begin(), v.end(), GenerateIncrementalIntegers<int>());
/// // v will now have 0, 1, 2, ... 8, 9.
///
/// generate_n(intArray.begin(), 10, GenerateIncrementalIntegers<int>());
/// // v will now have 0, 1, 2, ... 8, 9.
///
/// vector<TestObject> vTO(10, 0);
/// generate(vTO.begin(), vTO.end(), GenerateIncrementalIntegers<TestObject>());
/// // vTO will now have 0, 1, 2, ... 8, 9.
///
template <typename T>
struct GenerateIncrementalIntegers
{
int mX;
GenerateIncrementalIntegers(int x = 0)
: mX(x) { }
void reset(int x = 0)
{ mX = x; }
T operator()()
{ return T(mX++); }
};
/// SetIncrementalIntegers
///
/// Used to seed containers with incremental values based on integers.
///
/// Example usage:
/// vector<int> v(10, 0);
/// for_each(v.begin(), v.end(), SetIncrementalIntegers<int>());
/// // v will now have 0, 1, 2, ... 8, 9.
///
template <typename T>
struct SetIncrementalIntegers
{
int mX;
SetIncrementalIntegers(int x = 0)
: mX(x) { }
void reset(int x = 0)
{ mX = x; }
void operator()(T& t)
{ t = T(mX++); }
};
/// CompareContainers
///
/// Does a comparison between the contents of two containers.
///
/// Specifically tests for the following properties:
/// empty() is the same for both
/// size() is the same for both
/// iteration through both element by element yields equal values.
///
template <typename T1, typename T2, typename ExtractValue1, typename ExtractValue2>
int CompareContainers(const T1& t1, const T2& t2, const char* ppName,
ExtractValue1 ev1 = test_use_self<T1>(), ExtractValue2 ev2 = test_use_self<T2>())
{
int nErrorCount = 0;
// Compare emptiness.
VERIFY(t1.empty() == t2.empty());
// Compare sizes.
const size_t nSize1 = t1.size();
const size_t nSize2 = t2.size();
VERIFY(nSize1 == nSize2);
if(nSize1 != nSize2)
EASTLTest_Printf("%s: Container size difference: %u, %u\n", ppName, (unsigned)nSize1, (unsigned)nSize2);
// Compare values.
if(nSize1 == nSize2)
{
// Test iteration
typename T1::const_iterator it1 = t1.begin();
typename T2::const_iterator it2 = t2.begin();
for(unsigned j = 0; it1 != t1.end(); ++it1, ++it2, ++j)
{
const typename T1::value_type& v1 = *it1;
const typename T2::value_type& v2 = *it2;
VERIFY(ev1(v1) == ev2(v2));
if(!(ev1(v1) == ev2(v2)))
{
EASTLTest_Printf("%s: Container iterator difference at index %d\n", ppName, j);
break;
}
}
VERIFY(it1 == t1.end());
VERIFY(it2 == t2.end());
}
return nErrorCount;
}
/// VerifySequence
///
/// Allows the user to specify that a container has a given set of values.
///
/// Example usage:
/// vector<int> v;
/// v.push_back(1); v.push_back(3); v.push_back(5);
/// VerifySequence(v.begin(), v.end(), int(), "v.push_back", 1, 3, 5, -1);
///
/// Note: The StackValue template argument is a hint to the compiler about what type
/// the passed vararg sequence is.
///
template <typename InputIterator, typename StackValue>
bool VerifySequence(InputIterator first, InputIterator last, StackValue /*unused*/, const char* pName, ...)
{
typedef typename eastl::iterator_traits<InputIterator>::value_type value_type;
int argIndex = 0;
int seqIndex = 0;
bool bReturnValue = true;
StackValue next;
va_list args;
va_start(args, pName);
for( ; first != last; ++first, ++argIndex, ++seqIndex)
{
next = va_arg(args, StackValue);
if((next == StackValue(-1)) || !(value_type(next) == *first))
{
if(pName)
EASTLTest_Printf("[%s] Mismatch at index %d\n", pName, argIndex);
else
EASTLTest_Printf("Mismatch at index %d\n", argIndex);
bReturnValue = false;
}
}
for(; first != last; ++first)
++seqIndex;
if(bReturnValue)
{
next = va_arg(args, StackValue);
if(!(next == StackValue(-1)))
{
do {
++argIndex;
next = va_arg(args, StackValue);
} while(!(next == StackValue(-1)));
if(pName)
EASTLTest_Printf("[%s] Too many elements: expected %d, found %d\n", pName, argIndex, seqIndex);
else
EASTLTest_Printf("Too many elements: expected %d, found %d\n", argIndex, seqIndex);
bReturnValue = false;
}
}
va_end(args);
return bReturnValue;
}
/// PrintSequence
///
/// Allows the user to print a sequence of values.
///
/// Example usage:
/// vector<int> v;
/// PrintSequence(v.begin(), v.end(), use_self<int>(), 100, "vector", 1, 3, 5, -1);
///
/// Example usage:
/// template <typename T> struct use_mX { int operator()(const T& t) const { return t.mX; } };
/// vector<TestObject> v;
/// PrintSequence(v.begin(), v.end(), use_mX<TestObject>(), 100, "vector", 1, 3, 5, -1);
///
template <typename InputIterator, typename ExtractInt>
void PrintSequence(InputIterator first, InputIterator last, ExtractInt extractInt, int nMaxCount, const char* pName, ...)
{
if(pName)
EASTLTest_Printf("[%s]", pName);
for(int i = 0; (i < nMaxCount) && (first != last); ++i, ++first)
{
EASTLTest_Printf("%d ", (int)extractInt(*first));
}
EASTLTest_Printf("\n");
}
/// demoted_iterator
///
/// Converts an iterator into a demoted category. For example, you can convert
/// an iterator of type bidirectional_iterator_tag to forward_iterator_tag.
/// The following is a list of iterator types. A demonted iterator can be demoted
/// only to a lower iterator category (earlier in the following list):
/// input_iterator_tag
/// forward_iterator_tag
/// bidirectional_iterator_tag
/// random_access_iterator_tag
/// contiguous_iterator_tag
///
/// Converts something which can be iterated into a formal input iterator.
/// This class is useful for testing functions and algorithms that expect
/// InputIterators, which are the lowest and 'weakest' form of iterators.
///
/// Key traits of InputIterators:
/// Algorithms on input iterators should never attempt to pass
/// through the same iterator twice. They should be single pass
/// algorithms. value_type T is not required to be an lvalue type.
///
/// Example usage:
/// typedef demoted_iterator<int*, eastl::bidirectional_iterator_tag> PointerAsBidirectionalIterator;
/// typedef demoted_iterator<MyVector::iterator, eastl::forward_iterator_tag> VectorIteratorAsForwardIterator;
///
/// Example usage:
/// IntVector v;
/// comb_sort(to_forward_iterator(v.begin()), to_forward_iterator(v.end()));
///
template <typename Iterator, typename IteratorCategory>
class demoted_iterator
{
protected:
Iterator mIterator;
public:
typedef demoted_iterator<Iterator, IteratorCategory> this_type;
typedef Iterator iterator_type;
typedef IteratorCategory iterator_category;
typedef typename eastl::iterator_traits<Iterator>::value_type value_type;
typedef typename eastl::iterator_traits<Iterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<Iterator>::reference reference;
typedef typename eastl::iterator_traits<Iterator>::pointer pointer;
demoted_iterator()
: mIterator() { }
explicit demoted_iterator(const Iterator& i)
: mIterator(i) { }
demoted_iterator(const this_type& x)
: mIterator(x.mIterator) { }
this_type& operator=(const Iterator& i)
{ mIterator = i; return *this; }
this_type& operator=(const this_type& x)
{ mIterator = x.mIterator; return *this; }
reference operator*() const
{ return *mIterator; }
pointer operator->() const
{ return mIterator; }
this_type& operator++()
{ ++mIterator; return *this; }
this_type operator++(int)
{ return this_type(mIterator++); }
this_type& operator--()
{ --mIterator; return *this; }
this_type operator--(int)
{ return this_type(mIterator--); }
reference operator[](const difference_type& n) const
{ return mIterator[n]; }
this_type& operator+=(const difference_type& n)
{ mIterator += n; return *this; }
this_type operator+(const difference_type& n) const
{ return this_type(mIterator + n); }
this_type& operator-=(const difference_type& n)
{ mIterator -= n; return *this; }
this_type operator-(const difference_type& n) const
{ return this_type(mIterator - n); }
const iterator_type& base() const
{ return mIterator; }
}; // class demoted_iterator
template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2>
inline bool
operator==(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b)
{ return a.base() == b.base(); }
template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2>
inline bool
operator!=(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b)
{ return !(a == b); }
template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2>
inline bool
operator<(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b)
{ return a.base() < b.base(); }
template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2>
inline bool
operator<=(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b)
{ return !(b < a); }
template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2>
inline bool
operator>(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b)
{ return b < a; }
template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2>
inline bool
operator>=(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b)
{ return !(a < b); }
template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2>
inline demoted_iterator<Iterator1, IteratorCategory1>
operator-(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b)
{ return demoted_iterator<Iterator1, IteratorCategory1>(a.base() - b.base()); }
template<typename Iterator1, typename IteratorCategory1>
inline demoted_iterator<Iterator1, IteratorCategory1>
operator+(typename demoted_iterator<Iterator1, IteratorCategory1>::difference_type n, const demoted_iterator<Iterator1, IteratorCategory1>& a)
{ return a + n; }
// to_xxx_iterator
//
// Returns a demoted iterator
//
template <typename Iterator>
inline demoted_iterator<Iterator, EASTL_ITC_NS::input_iterator_tag>
to_input_iterator(const Iterator& i)
{ return demoted_iterator<Iterator, EASTL_ITC_NS::input_iterator_tag>(i); }
template <typename Iterator>
inline demoted_iterator<Iterator, EASTL_ITC_NS::forward_iterator_tag>
to_forward_iterator(const Iterator& i)
{ return demoted_iterator<Iterator, EASTL_ITC_NS::forward_iterator_tag>(i); }
template <typename Iterator>
inline demoted_iterator<Iterator, EASTL_ITC_NS::bidirectional_iterator_tag>
to_bidirectional_iterator(const Iterator& i)
{ return demoted_iterator<Iterator, EASTL_ITC_NS::bidirectional_iterator_tag>(i); }
template <typename Iterator>
inline demoted_iterator<Iterator, EASTL_ITC_NS::random_access_iterator_tag>
to_random_access_iterator(const Iterator& i)
{ return demoted_iterator<Iterator, EASTL_ITC_NS::random_access_iterator_tag>(i); }
///////////////////////////////////////////////////////////////////////////////
// MallocAllocator
//
// Implements an EASTL allocator that uses malloc/free as opposed to
// new/delete or PPMalloc Malloc/Free. This is useful for testing
// allocator behaviour of code.
//
// Example usage:
// vector<int, MallocAllocator> intVector;
//
class MallocAllocator
{
public:
MallocAllocator(const char* = EASTL_NAME_VAL("MallocAllocator"))
: mAllocCount(0), mFreeCount(0), mAllocVolume(0) {}
MallocAllocator(const MallocAllocator& x)
: mAllocCount(x.mAllocCount), mFreeCount(x.mFreeCount), mAllocVolume(x.mAllocVolume) {}
MallocAllocator(const MallocAllocator& x, const char*) : MallocAllocator(x) {}
MallocAllocator& operator=(const MallocAllocator& x)
{
mAllocCount = x.mAllocCount;
mFreeCount = x.mFreeCount;
mAllocVolume = x.mAllocVolume;
return *this;
}
void* allocate(size_t n, int = 0);
void* allocate(size_t n, size_t, size_t, int = 0); // We don't support alignment, so you can't use this class where alignment is required.
void deallocate(void* p, size_t n);
const char* get_name() const { return "MallocAllocator"; }
void set_name(const char*) {}
static void reset_all()
{
mAllocCountAll = 0;
mFreeCountAll = 0;
mAllocVolumeAll = 0;
mpLastAllocation = NULL;
}
public:
int mAllocCount;
int mFreeCount;
size_t mAllocVolume;
static int mAllocCountAll;
static int mFreeCountAll;
static size_t mAllocVolumeAll;
static void* mpLastAllocation;
};
inline bool operator==(const MallocAllocator&, const MallocAllocator&) { return true; }
inline bool operator!=(const MallocAllocator&, const MallocAllocator&) { return false; }
///////////////////////////////////////////////////////////////////////////////
// CustomAllocator
//
// Implements an allocator that works just like eastl::allocator but is defined
// within this test as opposed to within EASTL.
//
// Example usage:
// vector<int, CustomAllocator> intVector;
//
class CustomAllocator
{
public:
CustomAllocator(const char* = NULL) {}
CustomAllocator(const CustomAllocator&) {}
CustomAllocator(const CustomAllocator&, const char*) {}
CustomAllocator& operator=(const CustomAllocator&) { return *this; }
void* allocate(size_t n, int flags = 0);
void* allocate(size_t n, size_t, size_t, int flags = 0);
void deallocate(void* p, size_t n);
const char* get_name() const { return "CustomAllocator"; }
void set_name(const char*) {}
};
inline bool operator==(const CustomAllocator&, const CustomAllocator&) { return true; }
inline bool operator!=(const CustomAllocator&, const CustomAllocator&) { return false; }
///////////////////////////////////////////////////////////////////////////////
/// UnequalAllocator
///
/// Acts the same as eastl::allocator, but always compares as unequal to an
/// instance of itself.
///
class UnequalAllocator
{
public:
EASTL_ALLOCATOR_EXPLICIT UnequalAllocator(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME))
: mAllocator(pName) {}
UnequalAllocator(const UnequalAllocator& x) : mAllocator(x.mAllocator) {}
UnequalAllocator(const UnequalAllocator& x, const char* pName) : mAllocator(x.mAllocator) { set_name(pName); }
UnequalAllocator& operator=(const UnequalAllocator& x)
{
mAllocator = x.mAllocator;
return *this;
}
void* allocate(size_t n, int flags = 0) { return mAllocator.allocate(n, flags); }
void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0) { return mAllocator.allocate(n, alignment, offset, flags); }
void deallocate(void* p, size_t n) { return mAllocator.deallocate(p, n); }
const char* get_name() const { return mAllocator.get_name(); }
void set_name(const char* pName) { mAllocator.set_name(pName); }
protected:
eastl::allocator mAllocator;
};
inline bool operator==(const UnequalAllocator&, const UnequalAllocator&) { return false; }
inline bool operator!=(const UnequalAllocator&, const UnequalAllocator&) { return true; }
///////////////////////////////////////////////////////////////////////////////
/// CountingAllocator
///
/// Counts allocation events allowing unit tests to validate assumptions.
///
class CountingAllocator : public eastl::allocator
{
public:
using base_type = eastl::allocator;
EASTL_ALLOCATOR_EXPLICIT CountingAllocator(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME))
: base_type(pName)
{
totalCtorCount++;
defaultCtorCount++;
}
CountingAllocator(const CountingAllocator& x) : base_type(x)
{
totalCtorCount++;
copyCtorCount++;
}
CountingAllocator(const CountingAllocator& x, const char* pName) : base_type(x)
{
totalCtorCount++;
copyCtorCount++;
set_name(pName);
}
CountingAllocator& operator=(const CountingAllocator& x)
{
base_type::operator=(x);
assignOpCount++;
return *this;
}
virtual void* allocate(size_t n, int flags = 0)
{
activeAllocCount++;
totalAllocCount++;
totalAllocatedMemory += n;
activeAllocatedMemory += n;
return base_type::allocate(n, flags);
}
virtual void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0)
{
activeAllocCount++;
totalAllocCount++;
totalAllocatedMemory += n;
activeAllocatedMemory += n;
return base_type::allocate(n, alignment, offset, flags);
}
void deallocate(void* p, size_t n)
{
activeAllocCount--;
totalDeallocCount--;
activeAllocatedMemory -= n;
return base_type::deallocate(p, n);
}
const char* get_name() const { return base_type::get_name(); }
void set_name(const char* pName) { base_type::set_name(pName); }
static auto getTotalAllocationCount() { return totalAllocCount; }
static auto getTotalAllocationSize() { return totalAllocatedMemory; }
static auto getActiveAllocationSize() { return activeAllocatedMemory; }
static auto getActiveAllocationCount() { return activeAllocCount; }
static auto neverUsed() { return totalAllocCount == 0; }
static void resetCount()
{
activeAllocCount = 0;
totalAllocCount = 0;
totalDeallocCount = 0;
totalCtorCount = 0;
defaultCtorCount = 0;
copyCtorCount = 0;
assignOpCount = 0;
totalAllocatedMemory = 0;
activeAllocatedMemory = 0;
}
static uint64_t activeAllocCount;
static uint64_t totalAllocCount;
static uint64_t totalDeallocCount;
static uint64_t totalCtorCount;
static uint64_t defaultCtorCount;
static uint64_t copyCtorCount;
static uint64_t assignOpCount;
static uint64_t totalAllocatedMemory; // the total amount of memory allocated
static uint64_t activeAllocatedMemory; // currently allocated memory by allocator
};
inline bool operator==(const CountingAllocator& rhs, const CountingAllocator& lhs) { return operator==(CountingAllocator::base_type(rhs), CountingAllocator::base_type(lhs)); }
inline bool operator!=(const CountingAllocator& rhs, const CountingAllocator& lhs) { return !(rhs == lhs); }
///////////////////////////////////////////////////////////////////////////////
// InstanceAllocator
//
// Implements an allocator which has a instance id that makes it different
// from other InstanceAllocators of a different id. Allocations between
// InstanceAllocators of different ids are incompatible. An allocation done
// by an InstanceAllocator of id=0 cannot be freed by an InstanceAllocator
// of id=1.
//
// Example usage:
// InstanceAllocator ia0((uint8_t)0);
// InstanceAllocator ia1((uint8_t)1);
//
// eastl::list<int, InstanceAllocator> list0(1, ia0);
// eastl::list<int, InstanceAllocator> list1(1, ia1);
//
// list0 = list1; // list0 cannot free it's current contents with list1's allocator, and InstanceAllocator's purpose is to detect if it mistakenly does so.
//
class InstanceAllocator
{
public:
enum
{
kMultiplier = 16
}; // Use 16 because it's the highest currently known platform alignment requirement.
InstanceAllocator(const char* = NULL, uint8_t instanceId = 0) : mInstanceId(instanceId) {}
InstanceAllocator(uint8_t instanceId) : mInstanceId(instanceId) {}
InstanceAllocator(const InstanceAllocator& x) : mInstanceId(x.mInstanceId) {}
InstanceAllocator(const InstanceAllocator& x, const char*) : mInstanceId(x.mInstanceId) {}
InstanceAllocator& operator=(const InstanceAllocator& x)
{
mInstanceId = x.mInstanceId;
return *this;
}
void* allocate(size_t n, int = 0)
{ // +1 so that we always have space to write mInstanceId.
uint8_t* p8 =
static_cast<uint8_t*>(malloc(n + (kMultiplier * (mInstanceId + 1)))); // We make allocations between
// different instances incompatible by
// tweaking their return values.
eastl::fill(p8, p8 + kMultiplier, 0xff);
EA_ANALYSIS_ASSUME(p8 != NULL);
*p8 = mInstanceId;
return p8 + (kMultiplier * (mInstanceId + 1));
}
void* allocate(size_t n, size_t, size_t, int = 0)
{ // +1 so that we always have space to write mInstanceId.
uint8_t* p8 =
static_cast<uint8_t*>(malloc(n + (kMultiplier * (mInstanceId + 1)))); // We make allocations between
// different instances incompatible by
// tweaking their return values.
eastl::fill(p8, p8 + kMultiplier, 0xff);
EA_ANALYSIS_ASSUME(p8 != NULL);
*p8 = mInstanceId;
return p8 + (kMultiplier * (mInstanceId + 1));
}
void deallocate(void* p, size_t /*n*/)
{
uint8_t* p8 = static_cast<uint8_t*>(p) - (kMultiplier * (mInstanceId + 1));
EASTL_ASSERT(*p8 == mInstanceId); // mInstanceId must match the id used in allocate(), otherwise the behavior is
// undefined (probably a heap assert).
if (*p8 == mInstanceId) // It's possible that *p8 coincidentally matches mInstanceId if p8 is offset into memory
// we don't control.
free(p8);
else
++mMismatchCount;
}
const char* get_name()
{
sprintf(mName, "InstanceAllocator %u", mInstanceId);
return mName;
}
void set_name(const char*) {}
static void reset_all() { mMismatchCount = 0; }
public:
uint8_t mInstanceId;
char mName[32];
static int mMismatchCount;
};
inline bool operator==(const InstanceAllocator& a, const InstanceAllocator& b) { return (a.mInstanceId == b.mInstanceId); }
inline bool operator!=(const InstanceAllocator& a, const InstanceAllocator& b) { return (a.mInstanceId != b.mInstanceId); }
///////////////////////////////////////////////////////////////////////////////
// ThrowingAllocator
//
// Implements an EASTL allocator that uses malloc/free as opposed to
// new/delete or PPMalloc Malloc/Free. This is useful for testing
// allocator behaviour of code.
//
// Example usage:
// vector<int, ThrowingAllocator< false<> > intVector;
//
template <bool initialShouldThrow = true>
class ThrowingAllocator
{
public:
ThrowingAllocator(const char* = EASTL_NAME_VAL("ThrowingAllocator")) : mbShouldThrow(initialShouldThrow) {}
ThrowingAllocator(const ThrowingAllocator& x) : mbShouldThrow(x.mbShouldThrow) {}
ThrowingAllocator(const ThrowingAllocator& x, const char*) : mbShouldThrow(x.mbShouldThrow) {}
ThrowingAllocator& operator=(const ThrowingAllocator& x)
{
mbShouldThrow = x.mbShouldThrow;
return *this;
}
void* allocate(size_t n, int = 0)
{
#if EASTL_EXCEPTIONS_ENABLED
if (mbShouldThrow)
throw std::bad_alloc();
#endif
return malloc(n);
}
void* allocate(size_t n, size_t, size_t, int = 0)
{
#if EASTL_EXCEPTIONS_ENABLED
if (mbShouldThrow)
throw std::bad_alloc();
#endif
return malloc(n); // We don't support alignment, so you can't use this class where alignment is required.
}
void deallocate(void* p, size_t) { free(p); }
const char* get_name() const { return "ThrowingAllocator"; }
void set_name(const char*) {}
void set_should_throw(bool shouldThrow) { mbShouldThrow = shouldThrow; }
bool get_should_throw() const { return mbShouldThrow; }
protected:
bool mbShouldThrow;
};
template <bool initialShouldThrow>
inline bool operator==(const ThrowingAllocator<initialShouldThrow>&, const ThrowingAllocator<initialShouldThrow>&)
{
return true;
}
template <bool initialShouldThrow>
inline bool operator!=(const ThrowingAllocator<initialShouldThrow>&, const ThrowingAllocator<initialShouldThrow>&)
{
return false;
}
///////////////////////////////////////////////////////////////////////////////
// Helper utility that does a case insensitive string comparsion with two sets of overloads
//
struct TestStrCmpI_2
{
bool operator()(const char* pCStr, const eastl::string& str) const { return str.comparei(pCStr) == 0; }
bool operator()(const eastl::string& str, const char* pCStr) const { return str.comparei(pCStr) == 0; }
};
///////////////////////////////////////////////////////////////////////////////
// StompDetectAllocator
//
// An allocator that has sentinal values surrounding its allocator in an
// effort to detected if its internal memory has been stomped.
//
static uint64_t STOMP_MAGIC_V1 = 0x0101DEC1A551F1ED;
static uint64_t STOMP_MAGIC_V2 = 0x12345C1A551F1ED5;
struct StompDetectAllocator
{
StompDetectAllocator() { Validate(); }
~StompDetectAllocator() { Validate(); }
StompDetectAllocator(const char*) { Validate(); }
void* allocate(size_t n, int = 0) { return mMallocAllocator.allocate(n); }
void* allocate(size_t n, size_t, size_t, int = 0) { return mMallocAllocator.allocate(n); }
void deallocate(void* p, size_t n) { mMallocAllocator.deallocate(p, n); }
const char* get_name() const { return "FatAllocator"; }
void set_name(const char*) {}
void Validate() const
{
EASTL_ASSERT(mSentinal1 == STOMP_MAGIC_V1);
EASTL_ASSERT(mSentinal2 == STOMP_MAGIC_V2);
}
uint64_t mSentinal1 = STOMP_MAGIC_V1;
MallocAllocator mMallocAllocator;
uint64_t mSentinal2 = STOMP_MAGIC_V2;
};
inline bool operator==(const StompDetectAllocator& a, const StompDetectAllocator& b)
{
a.Validate();
b.Validate();
return (a.mMallocAllocator == b.mMallocAllocator);
}
inline bool operator!=(const StompDetectAllocator& a, const StompDetectAllocator& b)
{
a.Validate();
b.Validate();
return (a.mMallocAllocator != b.mMallocAllocator);
}
// Commonly used free-standing functions to test callables
inline int ReturnVal(int param) { return param; }
inline int ReturnZero() { return 0; }
inline int ReturnOne() { return 1; }
// ValueInit
template<class T>
struct ValueInitOf
{
ValueInitOf() : mV() {}
~ValueInitOf() = default;
ValueInitOf(const ValueInitOf&) = default;
ValueInitOf(ValueInitOf&&) = default;
ValueInitOf& operator=(const ValueInitOf&) = default;
ValueInitOf& operator=(ValueInitOf&&) = default;
T get() { return mV; }
T mV;
};
// MoveOnlyType - useful for verifying containers that may hold, e.g., unique_ptrs to make sure move ops are implemented
struct MoveOnlyType
{
MoveOnlyType() = delete;
MoveOnlyType(int val) : mVal(val) {}
MoveOnlyType(const MoveOnlyType&) = delete;
MoveOnlyType(MoveOnlyType&& x) : mVal(x.mVal) { x.mVal = 0; }
MoveOnlyType& operator=(const MoveOnlyType&) = delete;
MoveOnlyType& operator=(MoveOnlyType&& x)
{
mVal = x.mVal;
x.mVal = 0;
return *this;
}
bool operator==(const MoveOnlyType& o) const { return mVal == o.mVal; }
int mVal;
};
// MoveOnlyTypeDefaultCtor - useful for verifying containers that may hold, e.g., unique_ptrs to make sure move ops are implemented
struct MoveOnlyTypeDefaultCtor
{
MoveOnlyTypeDefaultCtor() = default;
MoveOnlyTypeDefaultCtor(int val) : mVal(val) {}
MoveOnlyTypeDefaultCtor(const MoveOnlyTypeDefaultCtor&) = delete;
MoveOnlyTypeDefaultCtor(MoveOnlyTypeDefaultCtor&& x) : mVal(x.mVal) { x.mVal = 0; }
MoveOnlyTypeDefaultCtor& operator=(const MoveOnlyTypeDefaultCtor&) = delete;
MoveOnlyTypeDefaultCtor& operator=(MoveOnlyTypeDefaultCtor&& x)
{
mVal = x.mVal;
x.mVal = 0;
return *this;
}
bool operator==(const MoveOnlyTypeDefaultCtor& o) const { return mVal == o.mVal; }
int mVal;
};
//////////////////////////////////////////////////////////////////////////////
// Utility RAII class that sets a new default allocator for the scope
//
struct AutoDefaultAllocator
{
eastl::allocator* mPrevAllocator = nullptr;
AutoDefaultAllocator(eastl::allocator* nextAllocator) { mPrevAllocator = SetDefaultAllocator(nextAllocator); }
~AutoDefaultAllocator() { SetDefaultAllocator(mPrevAllocator); }
};
#endif // Header include guard