diff options
Diffstat (limited to 'test/source/EASTLTest.h')
-rw-r--r-- | test/source/EASTLTest.h | 1585 |
1 files changed, 1585 insertions, 0 deletions
diff --git a/test/source/EASTLTest.h b/test/source/EASTLTest.h new file mode 100644 index 0000000..1cb298b --- /dev/null +++ b/test/source/EASTLTest.h @@ -0,0 +1,1585 @@ +///////////////////////////////////////////////////////////////////////////// +// 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(); + + +// 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 + + + + + + + |