1 ///////////////////////////////////////////////////////////////////////////// 2 // Copyright (c) Electronic Arts Inc. All rights reserved. 3 ///////////////////////////////////////////////////////////////////////////// 4 5 6 #ifndef EASTLTEST_H 7 #define EASTLTEST_H 8 9 10 #include <EABase/eabase.h> 11 #include <EATest/EATest.h> 12 13 EA_DISABLE_ALL_VC_WARNINGS() 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <stdarg.h> 17 #include <vector> // For the STD_STL_TYPE defines below. 18 #if EASTL_EXCEPTIONS_ENABLED 19 #include <stdexcept> 20 #include <new> 21 #endif 22 EA_RESTORE_VC_WARNING() 23 24 25 int TestAlgorithm(); 26 int TestAllocator(); 27 int TestAny(); 28 int TestArray(); 29 int TestBitVector(); 30 int TestBitset(); 31 int TestCharTraits(); 32 int TestChrono(); 33 int TestCppCXTypeTraits(); 34 int TestDeque(); 35 int TestExtra(); 36 int TestFixedFunction(); 37 int TestFixedHash(); 38 int TestFixedList(); 39 int TestFixedMap(); 40 int TestFixedSList(); 41 int TestFixedSet(); 42 int TestFixedString(); 43 int TestFixedTupleVector(); 44 int TestFixedVector(); 45 int TestFunctional(); 46 int TestHash(); 47 int TestHeap(); 48 int TestIntrusiveHash(); 49 int TestIntrusiveList(); 50 int TestIntrusiveSDList(); 51 int TestIntrusiveSList(); 52 int TestIterator(); 53 int TestList(); 54 int TestListMap(); 55 int TestLruCache(); 56 int TestMap(); 57 int TestMemory(); 58 int TestMeta(); 59 int TestNumericLimits(); 60 int TestOptional(); 61 int TestRandom(); 62 int TestRatio(); 63 int TestRingBuffer(); 64 int TestSList(); 65 int TestSegmentedVector(); 66 int TestSet(); 67 int TestSmartPtr(); 68 int TestSort(); 69 int TestSpan(); 70 int TestSparseMatrix(); 71 int TestString(); 72 int TestStringHashMap(); 73 int TestStringMap(); 74 int TestStringView(); 75 int TestTuple(); 76 int TestTypeTraits(); 77 int TestUtility(); 78 int TestVariant(); 79 int TestVector(); 80 int TestVectorMap(); 81 int TestVectorSet(); 82 int TestTupleVector(); 83 84 85 // Now enable warnings as desired. 86 #ifdef _MSC_VER 87 #pragma warning(disable: 4324) // 'struct_name' : structure was padded due to __declspec(align()) 88 //#pragma warning(disable: 4512) // 'class' : assignment operator could not be generated 89 //#pragma warning(disable: 4100) // 'identifier' : unreferenced formal parameter 90 //#pragma warning(disable: 4706) // assignment within conditional expression 91 92 #pragma warning(default: 4056) // Floating-point constant arithmetic generates a result that exceeds the maximum allowable value 93 #pragma warning(default: 4061) // The enumerate has no associated handler in a switch statement 94 #pragma warning(default: 4062) // The enumerate has no associated handler in a switch statement, and there is no default label 95 #pragma warning(default: 4191) // Calling this function through the result pointer may cause your program to crash 96 #pragma warning(default: 4217) // Member template functions cannot be used for copy-assignment or copy-construction 97 //#pragma warning(default: 4242) // 'variable' : conversion from 'type' to 'type', possible loss of data 98 #pragma warning(default: 4254) // 'operator' : conversion from 'type1' to 'type2', possible loss of data 99 #pragma warning(default: 4255) // 'function' : no function prototype given: converting '()' to '(void)' 100 #pragma warning(default: 4263) // 'function' : member function does not override any base class virtual member function 101 #pragma warning(default: 4264) // 'virtual_function' : no override available for virtual member function from base 'class'; function is hidden 102 #pragma warning(default: 4287) // 'operator' : unsigned/negative constant mismatch 103 #pragma warning(default: 4289) // Nonstandard extension used : 'var' : loop control variable declared in the for-loop is used outside the for-loop scope 104 #pragma warning(default: 4296) // 'operator' : expression is always false 105 #pragma warning(default: 4302) // 'conversion' : truncation from 'type 1' to 'type 2' 106 #pragma warning(default: 4339) // 'type' : use of undefined type detected in CLR meta-data - use of this type may lead to a runtime exception 107 #pragma warning(default: 4347) // Behavior change: 'function template' is called instead of 'function' 108 //#pragma warning(default: 4514) // unreferenced inline/local function has been removed 109 #pragma warning(default: 4529) // 'member_name' : forming a pointer-to-member requires explicit use of the address-of operator ('&') and a qualified name 110 #pragma warning(default: 4545) // Expression before comma evaluates to a function which is missing an argument list 111 #pragma warning(default: 4546) // Function call before comma missing argument list 112 #pragma warning(default: 4547) // 'operator' : operator before comma has no effect; expected operator with side-effect 113 //#pragma warning(default: 4548) // expression before comma has no effect; expected expression with side-effect 114 #pragma warning(default: 4549) // 'operator' : operator before comma has no effect; did you intend 'operator'? 115 #pragma warning(default: 4536) // 'type name' : type-name exceeds meta-data limit of 'limit' characters 116 #pragma warning(default: 4555) // Expression has no effect; expected expression with side-effect 117 #pragma warning(default: 4557) // '__assume' contains effect 'effect' 118 //#pragma warning(default: 4619) // #pragma warning : there is no warning number 'number' 119 #pragma warning(default: 4623) // 'derived class' : default constructor could not be generated because a base class default constructor is inaccessible 120 #pragma warning(default: 4625) // 'derived class' : copy constructor could not be generated because a base class copy constructor is inaccessible 121 #pragma warning(default: 4626) // 'derived class' : assignment operator could not be generated because a base class assignment operator is inaccessible 122 #pragma warning(default: 4628) // Digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char' 123 #pragma warning(default: 4640) // 'instance' : construction of local static object is not thread-safe 124 #pragma warning(default: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives' 125 #pragma warning(default: 4682) // 'parameter' : no directional parameter attribute specified, defaulting to [in] 126 #pragma warning(default: 4686) // 'user-defined type' : possible change in behavior, change in UDT return calling convention 127 //#pragma warning(default: 4710) // 'function' : function not inlined 128 //#pragma warning(default: 4786) // 'identifier' : identifier was truncated to 'number' characters in the debug information 129 #pragma warning(default: 4793) // Native code generated for function 'function': 'reason' 130 //#pragma warning(default: 4820) // 'bytes' bytes padding added after member 'member' 131 #pragma warning(default: 4905) // Wide string literal cast to 'LPSTR' 132 #pragma warning(default: 4906) // String literal cast to 'LPWSTR' 133 #pragma warning(default: 4917) // 'declarator' : a GUID cannot only be associated with a class, interface or namespace 134 #pragma warning(default: 4928) // Illegal copy-initialization; more than one user-defined conversion has been implicitly applied 135 #pragma warning(default: 4931) // We are assuming the type library was built for number-bit pointers 136 #pragma warning(default: 4946) // reinterpret_cast used between related classes: 'class1' and 'class2' 137 138 #endif 139 140 141 /////////////////////////////////////////////////////////////////////////////// 142 // EASTL includes 143 // 144 // Intentionally keep these includes below the warning settings specified above. 145 // 146 #include <EASTL/iterator.h> 147 #include <EASTL/algorithm.h> 148 149 150 151 152 /// EASTL_TestLevel 153 /// 154 /// Defines how extensive our testing is. A low level is for a desktop or 155 /// nightly build in which the test can run quickly but still hit the 156 /// majority of functionality. High level is for heavy testing and internal 157 /// validation which may take numerous hours to run. 158 /// 159 enum EASTL_TestLevel 160 { 161 kEASTL_TestLevelLow = 1, /// ~10 seconds for test completion. 162 kEASTL_TestLevelHigh = 10 /// Numerous hours for test completion. 163 }; 164 165 extern int gEASTL_TestLevel; 166 167 168 169 /// EASTLTest_CheckMemory 170 /// 171 /// Does a global memory heap validation check. Returns 0 if OK and 172 /// an error count if there is a problem. 173 /// 174 /// Example usage: 175 /// EASTLTest_CheckMemory(); 176 /// 177 int EASTLTest_CheckMemory_Imp(const char* pFile, int nLine); 178 #define EASTLTest_CheckMemory() EASTLTest_CheckMemory_Imp(__FILE__, __LINE__) 179 180 181 182 // EASTLTEST_STD_STL_VER 183 // 184 #if defined(_STLPORT_VERSION) 185 #define EASTLTEST_STD_STL_VER_STLPORT 186 #elif defined(_RWSTD_VER_STR) || defined(_RWSTD_NAMESPACE_END) 187 #define EASTLTEST_STD_STL_VER_APACHE 188 #elif defined(_CPPLIB_VER) 189 #define EASTLTEST_STD_STL_VER_DINKUMWARE 190 #elif defined(__GNUC__) && defined(_CXXCONFIG) 191 #define EASTLTEST_STD_STL_VER_GCC 192 #else 193 #define EASTLTEST_STD_STL_VER_UNKNOWN 194 #endif 195 196 197 198 /// StdSTLType 199 /// 200 enum StdSTLType 201 { 202 kSTLUnknown, // Unknown type 203 kSTLPort, // STLPort. Descendent of the old HP / SGI STL. 204 kSTLApache, // Apache stdcxx (previously RogueWave), which is a descendent of the old HP / SGI STL. 205 kSTLClang, // Clang native. a.k.a. libc++ 206 kSTLGCC, // GCC native. a.k.a. libstdc++ 207 kSTLMS, // Microsoft. Tweaked version of Dinkumware. 208 kSTLDinkumware // Generic Dinkumware 209 }; 210 211 StdSTLType GetStdSTLType(); 212 213 214 215 216 /// GetStdSTLName 217 /// 218 /// Returns the name of the std C++ STL available to the current build. 219 /// The returned value will be one of: 220 /// "STLPort" 221 /// "GCC" 222 /// "VC++" 223 // "Apache" // Previously RogueWave 224 /// 225 const char* GetStdSTLName(); 226 227 228 /// gEASTLTest_AllocationCount 229 /// 230 extern int gEASTLTest_AllocationCount; 231 extern int gEASTLTest_TotalAllocationCount; 232 233 234 235 // For backwards compatibility: 236 #define EASTLTest_Printf EA::UnitTest::Report 237 #define VERIFY EATEST_VERIFY 238 239 240 /////////////////////////////////////////////////////////////////////////////// 241 /// EASTLTest_Rand 242 /// 243 /// Implements a basic random number generator for EASTL unit tests. It's not 244 /// intended to be a robust random number generator (though it is decent), 245 /// but rather is present so the unit tests can have a portable random number 246 /// generator they can rely on being present. 247 /// 248 /// Example usage: 249 /// EASTLTest_Rand rng; 250 /// eastl_size_t x = rng(); // Generate value in range of [0, 0xffffffff] (i.e. generate any uint32_t) 251 /// eastl_ssize_t y = rng.Rand(1000); // Generate value in range of [0, 1000) 252 /// eastl_ssize_t z = rng.RandRange(-50, +30); // Generate value in range of [-50, +30) 253 /// 254 /// Example usage in the random_shuffle algorithm: 255 /// EASTLTest_Rand rng; 256 /// random_shuffle(first, last, rnd); 257 /// 258 class EASTLTest_Rand 259 { 260 public: EASTLTest_Rand(eastl_size_t nSeed)261 EASTLTest_Rand(eastl_size_t nSeed) // The user must supply a seed; we don't provide default values. 262 : mnSeed(nSeed) { } 263 Rand()264 eastl_size_t Rand() 265 { 266 // This is not designed to be a high quality random number generator. 267 if(mnSeed == 0) 268 mnSeed = UINT64_C(0xfefefefefefefefe); // Can't have a seed of zero. 269 270 const uint64_t nResult64A = ((mnSeed * UINT64_C(6364136223846793005)) + UINT64_C(1442695040888963407)); 271 const uint64_t nResult64B = ((nResult64A * UINT64_C(6364136223846793005)) + UINT64_C(1442695040888963407)); 272 273 mnSeed = (nResult64A >> 32) ^ nResult64B; 274 275 return (eastl_size_t)mnSeed; // For eastl_size_t == uint32_t, this is a chop. 276 } 277 operator()278 eastl_size_t operator()() // Returns a pseudorandom value in range of [0, 0xffffffffffffffff)] (i.e. generate any eastl_size_t) 279 { return Rand(); } 280 operator()281 eastl_size_t operator()(eastl_size_t n) // Returns a pseudorandom value in range of [0, n) 282 { return RandLimit(n); } 283 RandLimit(eastl_size_t nLimit)284 eastl_size_t RandLimit(eastl_size_t nLimit) // Returns a pseudorandom value in range of [0, nLimit) 285 { 286 // Can't do the following correct solution because we don't have a portable int128_t to work with. 287 // We could implement a 128 bit multiply manually. See EAStdC/int128_t.cpp. 288 // return (eastl_size_t)((Rand() * (uint128_t)nLimit) >> 64); 289 290 return (Rand() % nLimit); // This results in an imperfect distribution, especially for the case of nLimit being high relative to eastl_size_t. 291 } 292 RandRange(eastl_ssize_t nBegin,eastl_ssize_t nEnd)293 eastl_ssize_t RandRange(eastl_ssize_t nBegin, eastl_ssize_t nEnd) // Returns a pseudorandom value in range of [nBegin, nEnd) 294 { return nBegin + (eastl_ssize_t)RandLimit((eastl_size_t)(nEnd - nBegin)); } 295 296 protected: 297 uint64_t mnSeed; 298 }; 299 300 301 /////////////////////////////////////////////////////////////////////////////// 302 /// RandGenT 303 /// 304 /// A wrapper for EASTLTest_Rand which generates values of the given integral 305 /// data type. This is mostly useful for clearnly avoiding compiler warnings, 306 /// as we intentionally enable the highest warning levels in these tests. 307 /// 308 template <typename Integer> 309 struct RandGenT 310 { RandGenTRandGenT311 RandGenT(eastl_size_t nSeed) 312 : mRand(nSeed) { } 313 operatorRandGenT314 Integer operator()() 315 { return (Integer)mRand.Rand(); } 316 operatorRandGenT317 Integer operator()(eastl_size_t n) 318 { return (Integer)mRand.RandLimit(n); } 319 320 EASTLTest_Rand mRand; 321 }; 322 323 324 325 /////////////////////////////////////////////////////////////////////////////// 326 /// kMagicValue 327 /// 328 /// Used as a unique integer. We assign this to TestObject in its constructor 329 /// and verify in the TestObject destructor that the value is unchanged. 330 /// This can be used to tell, for example, if an invalid object is being 331 /// destroyed. 332 /// 333 const uint32_t kMagicValue = 0x01f1cbe8; 334 335 336 /////////////////////////////////////////////////////////////////////////////// 337 /// TestObject 338 /// 339 /// Implements a generic object that is suitable for use in container tests. 340 /// Note that we choose a very restricted set of functions that are available 341 /// for this class. Do not add any additional functions, as that would 342 /// compromise the intentions of the unit tests. 343 /// 344 struct TestObject 345 { 346 int mX; // Value for the TestObject. 347 bool mbThrowOnCopy; // Throw an exception of this object is copied, moved, or assigned to another. 348 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. 349 uint32_t mMagicValue; // Used to verify that an instance is valid and that it is not corrupted. It should always be kMagicValue. 350 static int64_t sTOCount; // Count of all current existing TestObjects. 351 static int64_t sTOCtorCount; // Count of times any ctor was called. 352 static int64_t sTODtorCount; // Count of times dtor was called. 353 static int64_t sTODefaultCtorCount; // Count of times the default ctor was called. 354 static int64_t sTOArgCtorCount; // Count of times the x0,x1,x2 ctor was called. 355 static int64_t sTOCopyCtorCount; // Count of times copy ctor was called. 356 static int64_t sTOMoveCtorCount; // Count of times move ctor was called. 357 static int64_t sTOCopyAssignCount; // Count of times copy assignment was called. 358 static int64_t sTOMoveAssignCount; // Count of times move assignment was called. 359 static int sMagicErrorCount; // Number of magic number mismatch errors. 360 361 explicit TestObject(int x = 0, bool bThrowOnCopy = false) mXTestObject362 : mX(x), mbThrowOnCopy(bThrowOnCopy), mMagicValue(kMagicValue) 363 { 364 ++sTOCount; 365 ++sTOCtorCount; 366 ++sTODefaultCtorCount; 367 mId = sTOCtorCount; 368 } 369 370 // This constructor exists for the purpose of testing variadiac template arguments, such as with the emplace container functions. 371 TestObject(int x0, int x1, int x2, bool bThrowOnCopy = false) 372 : mX(x0 + x1 + x2), mbThrowOnCopy(bThrowOnCopy), mMagicValue(kMagicValue) 373 { 374 ++sTOCount; 375 ++sTOCtorCount; 376 ++sTOArgCtorCount; 377 mId = sTOCtorCount; 378 } 379 TestObjectTestObject380 TestObject(const TestObject& testObject) 381 : mX(testObject.mX), mbThrowOnCopy(testObject.mbThrowOnCopy), mMagicValue(testObject.mMagicValue) 382 { 383 ++sTOCount; 384 ++sTOCtorCount; 385 ++sTOCopyCtorCount; 386 mId = sTOCtorCount; 387 if(mbThrowOnCopy) 388 { 389 #if EASTL_EXCEPTIONS_ENABLED 390 throw "Disallowed TestObject copy"; 391 #endif 392 } 393 } 394 395 // Due to the nature of TestObject, there isn't much special for us to 396 // do in our move constructor. A move constructor swaps its contents with 397 // the other object, whhich is often a default-constructed object. TestObjectTestObject398 TestObject(TestObject&& testObject) 399 : mX(testObject.mX), mbThrowOnCopy(testObject.mbThrowOnCopy), mMagicValue(testObject.mMagicValue) 400 { 401 ++sTOCount; 402 ++sTOCtorCount; 403 ++sTOMoveCtorCount; 404 mId = sTOCtorCount; // testObject keeps its mId, and we assign ours anew. 405 testObject.mX = 0; // We are swapping our contents with the TestObject, so give it our "previous" value. 406 if(mbThrowOnCopy) 407 { 408 #if EASTL_EXCEPTIONS_ENABLED 409 throw "Disallowed TestObject copy"; 410 #endif 411 } 412 } 413 414 TestObject& operator=(const TestObject& testObject) 415 { 416 ++sTOCopyAssignCount; 417 418 if(&testObject != this) 419 { 420 mX = testObject.mX; 421 // Leave mId alone. 422 mMagicValue = testObject.mMagicValue; 423 mbThrowOnCopy = testObject.mbThrowOnCopy; 424 if(mbThrowOnCopy) 425 { 426 #if EASTL_EXCEPTIONS_ENABLED 427 throw "Disallowed TestObject copy"; 428 #endif 429 } 430 } 431 return *this; 432 } 433 434 TestObject& operator=(TestObject&& testObject) 435 { 436 ++sTOMoveAssignCount; 437 438 if(&testObject != this) 439 { 440 eastl::swap(mX, testObject.mX); 441 // Leave mId alone. 442 eastl::swap(mMagicValue, testObject.mMagicValue); 443 eastl::swap(mbThrowOnCopy, testObject.mbThrowOnCopy); 444 445 if(mbThrowOnCopy) 446 { 447 #if EASTL_EXCEPTIONS_ENABLED 448 throw "Disallowed TestObject copy"; 449 #endif 450 } 451 } 452 return *this; 453 } 454 ~TestObjectTestObject455 ~TestObject() 456 { 457 if(mMagicValue != kMagicValue) 458 ++sMagicErrorCount; 459 mMagicValue = 0; 460 --sTOCount; 461 ++sTODtorCount; 462 } 463 ResetTestObject464 static void Reset() 465 { 466 sTOCount = 0; 467 sTOCtorCount = 0; 468 sTODtorCount = 0; 469 sTODefaultCtorCount = 0; 470 sTOArgCtorCount = 0; 471 sTOCopyCtorCount = 0; 472 sTOMoveCtorCount = 0; 473 sTOCopyAssignCount = 0; 474 sTOMoveAssignCount = 0; 475 sMagicErrorCount = 0; 476 } 477 IsClearTestObject478 static bool IsClear() // Returns true if there are no existing TestObjects and the sanity checks related to that test OK. 479 { 480 return (sTOCount == 0) && (sTODtorCount == sTOCtorCount) && (sMagicErrorCount == 0); 481 } 482 }; 483 484 // Operators 485 // We specifically define only == and <, in order to verify that 486 // our containers and algorithms are not mistakenly expecting other 487 // operators for the contained and manipulated classes. 488 inline bool operator==(const TestObject& t1, const TestObject& t2) 489 { return t1.mX == t2.mX; } 490 491 inline bool operator<(const TestObject& t1, const TestObject& t2) 492 { return t1.mX < t2.mX; } 493 494 495 // TestObject hash 496 // Normally you don't want to put your hash functions in the eastl namespace, as that namespace is owned by EASTL. 497 // However, these are the EASTL unit tests and we can say that they are also owned by EASTL. 498 namespace eastl 499 { 500 template <> 501 struct hash<TestObject> 502 { 503 size_t operator()(const TestObject& a) const 504 { return static_cast<size_t>(a.mX); } 505 }; 506 } 507 508 509 // use_mX 510 // Used for printing TestObject contents via the PrintSequence function, 511 // which is defined below. See the PrintSequence function for documentation. 512 // This function is an analog of the eastl::use_self and use_first functions. 513 // We declare this all in one line because the user should never need to 514 // debug usage of this function. 515 template <typename T> struct use_mX { int operator()(const T& t) const { return t.mX; } }; 516 517 518 519 /////////////////////////////////////////////////////////////////////////////// 520 // SizedPOD 521 // 522 // Exists for the purpose testing PODs that are larger than built-in types. 523 // 524 template <size_t kSize> 525 struct SizedPOD 526 { 527 char memory[kSize]; 528 }; 529 530 531 532 /////////////////////////////////////////////////////////////////////////////// 533 /// ConstType 534 /// 535 /// Used to test const type containers (e.g. vector<const ConstType>). 536 /// 537 class ConstType 538 { 539 public: 540 ConstType(int value) : mDummy(value) {}; 541 int mDummy; 542 }; 543 544 545 546 547 /////////////////////////////////////////////////////////////////////////////// 548 /// TestObjectHash 549 /// 550 /// Implements a manually specified hash function for TestObjects. 551 /// 552 struct TestObjectHash 553 { 554 size_t operator()(const TestObject& t) const 555 { 556 return (size_t)t.mX; 557 } 558 }; 559 560 561 562 563 564 /////////////////////////////////////////////////////////////////////////////// 565 /// Align16 566 /// 567 568 #if defined(EA_PROCESSOR_ARM) 569 #define kEASTLTestAlign16 8 //ARM processors can only align to 8 570 #else 571 #define kEASTLTestAlign16 16 572 #endif 573 574 575 EA_PREFIX_ALIGN(kEASTLTestAlign16) 576 struct Align16 577 { 578 explicit Align16(int x = 0) : mX(x) {} 579 int mX; 580 } EA_POSTFIX_ALIGN(kEASTLTestAlign16); 581 582 inline bool operator==(const Align16& a, const Align16& b) 583 { return (a.mX == b.mX); } 584 585 inline bool operator<(const Align16& a, const Align16& b) 586 { return (a.mX < b.mX); } 587 588 589 590 /////////////////////////////////////////////////////////////////////////////// 591 /// Align32 592 /// 593 #if defined(EA_PROCESSOR_ARM) 594 #define kEASTLTestAlign32 8 //ARM processors can only align to 8 595 #elif defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) < 400) // GCC 2.x, 3.x 596 #define kEASTLTestAlign32 16 // Some versions of GCC fail to support any alignment beyond 16. 597 #else 598 #define kEASTLTestAlign32 32 599 #endif 600 601 EA_PREFIX_ALIGN(kEASTLTestAlign32) 602 struct Align32 603 { 604 explicit Align32(int x = 0) : mX(x) {} 605 int mX; 606 } EA_POSTFIX_ALIGN(kEASTLTestAlign32); 607 608 inline bool operator==(const Align32& a, const Align32& b) 609 { return (a.mX == b.mX); } 610 611 inline bool operator<(const Align32& a, const Align32& b) 612 { return (a.mX < b.mX); } 613 614 615 616 /////////////////////////////////////////////////////////////////////////////// 617 /// Align64 618 /// 619 /// Used for testing of alignment. 620 /// 621 #if defined(EA_PROCESSOR_ARM) 622 #define kEASTLTestAlign64 8 623 #elif defined(__GNUC__) && (((__GNUC__ * 100) + __GNUC_MINOR__) < 400) // GCC 2.x, 3.x 624 #define kEASTLTestAlign64 16 // Some versions of GCC fail to support any alignment beyond 16. 625 #else 626 #define kEASTLTestAlign64 64 627 #endif 628 629 EA_PREFIX_ALIGN(kEASTLTestAlign64) 630 struct Align64 631 { 632 explicit Align64(int x = 0) : mX(x) {} 633 int mX; 634 } EA_POSTFIX_ALIGN(kEASTLTestAlign64); 635 636 inline bool operator==(const Align64& a, const Align64& b) 637 { return (a.mX == b.mX); } 638 639 inline bool operator<(const Align64& a, const Align64& b) 640 { return (a.mX < b.mX); } 641 642 namespace eastl 643 { 644 template <> 645 struct hash < Align64 > 646 { 647 size_t operator()(const Align64& a) const 648 { 649 return static_cast<size_t>(a.mX); 650 } 651 }; 652 } 653 654 655 656 657 658 /// test_use_self 659 /// 660 /// Intentionally avoiding a dependency on eastl::use_self. 661 /// 662 template <typename T> 663 struct test_use_self 664 { 665 const T& operator()(const T& x) const 666 { return x; } 667 }; 668 669 670 671 /// GenerateIncrementalIntegers 672 /// 673 /// Used to seed containers with incremental values based on integers. 674 /// 675 /// Example usage: 676 /// vector<int> v(10, 0); 677 /// generate(v.begin(), v.end(), GenerateIncrementalIntegers<int>()); 678 /// // v will now have 0, 1, 2, ... 8, 9. 679 /// 680 /// generate_n(intArray.begin(), 10, GenerateIncrementalIntegers<int>()); 681 /// // v will now have 0, 1, 2, ... 8, 9. 682 /// 683 /// vector<TestObject> vTO(10, 0); 684 /// generate(vTO.begin(), vTO.end(), GenerateIncrementalIntegers<TestObject>()); 685 /// // vTO will now have 0, 1, 2, ... 8, 9. 686 /// 687 template <typename T> 688 struct GenerateIncrementalIntegers 689 { 690 int mX; 691 692 GenerateIncrementalIntegers(int x = 0) 693 : mX(x) { } 694 695 void reset(int x = 0) 696 { mX = x; } 697 698 T operator()() 699 { return T(mX++); } 700 }; 701 702 703 704 /// SetIncrementalIntegers 705 /// 706 /// Used to seed containers with incremental values based on integers. 707 /// 708 /// Example usage: 709 /// vector<int> v(10, 0); 710 /// for_each(v.begin(), v.end(), SetIncrementalIntegers<int>()); 711 /// // v will now have 0, 1, 2, ... 8, 9. 712 /// 713 template <typename T> 714 struct SetIncrementalIntegers 715 { 716 int mX; 717 718 SetIncrementalIntegers(int x = 0) 719 : mX(x) { } 720 721 void reset(int x = 0) 722 { mX = x; } 723 724 void operator()(T& t) 725 { t = T(mX++); } 726 }; 727 728 729 730 /// CompareContainers 731 /// 732 /// Does a comparison between the contents of two containers. 733 /// 734 /// Specifically tests for the following properties: 735 /// empty() is the same for both 736 /// size() is the same for both 737 /// iteration through both element by element yields equal values. 738 /// 739 template <typename T1, typename T2, typename ExtractValue1, typename ExtractValue2> 740 int CompareContainers(const T1& t1, const T2& t2, const char* ppName, 741 ExtractValue1 ev1 = test_use_self<T1>(), ExtractValue2 ev2 = test_use_self<T2>()) 742 { 743 int nErrorCount = 0; 744 745 // Compare emptiness. 746 VERIFY(t1.empty() == t2.empty()); 747 748 // Compare sizes. 749 const size_t nSize1 = t1.size(); 750 const size_t nSize2 = t2.size(); 751 752 VERIFY(nSize1 == nSize2); 753 if(nSize1 != nSize2) 754 EASTLTest_Printf("%s: Container size difference: %u, %u\n", ppName, (unsigned)nSize1, (unsigned)nSize2); 755 756 // Compare values. 757 if(nSize1 == nSize2) 758 { 759 // Test iteration 760 typename T1::const_iterator it1 = t1.begin(); 761 typename T2::const_iterator it2 = t2.begin(); 762 763 for(unsigned j = 0; it1 != t1.end(); ++it1, ++it2, ++j) 764 { 765 const typename T1::value_type& v1 = *it1; 766 const typename T2::value_type& v2 = *it2; 767 768 VERIFY(ev1(v1) == ev2(v2)); 769 if(!(ev1(v1) == ev2(v2))) 770 { 771 EASTLTest_Printf("%s: Container iterator difference at index %d\n", ppName, j); 772 break; 773 } 774 } 775 776 VERIFY(it1 == t1.end()); 777 VERIFY(it2 == t2.end()); 778 } 779 780 return nErrorCount; 781 } 782 783 784 785 786 787 /// VerifySequence 788 /// 789 /// Allows the user to specify that a container has a given set of values. 790 /// 791 /// Example usage: 792 /// vector<int> v; 793 /// v.push_back(1); v.push_back(3); v.push_back(5); 794 /// VerifySequence(v.begin(), v.end(), int(), "v.push_back", 1, 3, 5, -1); 795 /// 796 /// Note: The StackValue template argument is a hint to the compiler about what type 797 /// the passed vararg sequence is. 798 /// 799 template <typename InputIterator, typename StackValue> 800 bool VerifySequence(InputIterator first, InputIterator last, StackValue /*unused*/, const char* pName, ...) 801 { 802 typedef typename eastl::iterator_traits<InputIterator>::value_type value_type; 803 804 int argIndex = 0; 805 int seqIndex = 0; 806 bool bReturnValue = true; 807 StackValue next; 808 809 va_list args; 810 va_start(args, pName); 811 812 for( ; first != last; ++first, ++argIndex, ++seqIndex) 813 { 814 next = va_arg(args, StackValue); 815 816 if((next == StackValue(-1)) || !(value_type(next) == *first)) 817 { 818 if(pName) 819 EASTLTest_Printf("[%s] Mismatch at index %d\n", pName, argIndex); 820 else 821 EASTLTest_Printf("Mismatch at index %d\n", argIndex); 822 bReturnValue = false; 823 } 824 } 825 826 for(; first != last; ++first) 827 ++seqIndex; 828 829 if(bReturnValue) 830 { 831 next = va_arg(args, StackValue); 832 833 if(!(next == StackValue(-1))) 834 { 835 do { 836 ++argIndex; 837 next = va_arg(args, StackValue); 838 } while(!(next == StackValue(-1))); 839 840 if(pName) 841 EASTLTest_Printf("[%s] Too many elements: expected %d, found %d\n", pName, argIndex, seqIndex); 842 else 843 EASTLTest_Printf("Too many elements: expected %d, found %d\n", argIndex, seqIndex); 844 bReturnValue = false; 845 } 846 } 847 848 va_end(args); 849 850 return bReturnValue; 851 } 852 853 854 855 856 /// PrintSequence 857 /// 858 /// Allows the user to print a sequence of values. 859 /// 860 /// Example usage: 861 /// vector<int> v; 862 /// PrintSequence(v.begin(), v.end(), use_self<int>(), 100, "vector", 1, 3, 5, -1); 863 /// 864 /// Example usage: 865 /// template <typename T> struct use_mX { int operator()(const T& t) const { return t.mX; } }; 866 /// vector<TestObject> v; 867 /// PrintSequence(v.begin(), v.end(), use_mX<TestObject>(), 100, "vector", 1, 3, 5, -1); 868 /// 869 template <typename InputIterator, typename ExtractInt> 870 void PrintSequence(InputIterator first, InputIterator last, ExtractInt extractInt, int nMaxCount, const char* pName, ...) 871 { 872 if(pName) 873 EASTLTest_Printf("[%s]", pName); 874 875 for(int i = 0; (i < nMaxCount) && (first != last); ++i, ++first) 876 { 877 EASTLTest_Printf("%d ", (int)extractInt(*first)); 878 } 879 880 EASTLTest_Printf("\n"); 881 } 882 883 884 885 886 /// demoted_iterator 887 /// 888 /// Converts an iterator into a demoted category. For example, you can convert 889 /// an iterator of type bidirectional_iterator_tag to forward_iterator_tag. 890 /// The following is a list of iterator types. A demonted iterator can be demoted 891 /// only to a lower iterator category (earlier in the following list): 892 /// input_iterator_tag 893 /// forward_iterator_tag 894 /// bidirectional_iterator_tag 895 /// random_access_iterator_tag 896 /// contiguous_iterator_tag 897 /// 898 /// Converts something which can be iterated into a formal input iterator. 899 /// This class is useful for testing functions and algorithms that expect 900 /// InputIterators, which are the lowest and 'weakest' form of iterators. 901 /// 902 /// Key traits of InputIterators: 903 /// Algorithms on input iterators should never attempt to pass 904 /// through the same iterator twice. They should be single pass 905 /// algorithms. value_type T is not required to be an lvalue type. 906 /// 907 /// Example usage: 908 /// typedef demoted_iterator<int*, eastl::bidirectional_iterator_tag> PointerAsBidirectionalIterator; 909 /// typedef demoted_iterator<MyVector::iterator, eastl::forward_iterator_tag> VectorIteratorAsForwardIterator; 910 /// 911 /// Example usage: 912 /// IntVector v; 913 /// comb_sort(to_forward_iterator(v.begin()), to_forward_iterator(v.end())); 914 /// 915 template <typename Iterator, typename IteratorCategory> 916 class demoted_iterator 917 { 918 protected: 919 Iterator mIterator; 920 921 public: 922 typedef demoted_iterator<Iterator, IteratorCategory> this_type; 923 typedef Iterator iterator_type; 924 typedef IteratorCategory iterator_category; 925 typedef typename eastl::iterator_traits<Iterator>::value_type value_type; 926 typedef typename eastl::iterator_traits<Iterator>::difference_type difference_type; 927 typedef typename eastl::iterator_traits<Iterator>::reference reference; 928 typedef typename eastl::iterator_traits<Iterator>::pointer pointer; 929 930 demoted_iterator() 931 : mIterator() { } 932 933 explicit demoted_iterator(const Iterator& i) 934 : mIterator(i) { } 935 936 demoted_iterator(const this_type& x) 937 : mIterator(x.mIterator) { } 938 939 this_type& operator=(const Iterator& i) 940 { mIterator = i; return *this; } 941 942 this_type& operator=(const this_type& x) 943 { mIterator = x.mIterator; return *this; } 944 945 reference operator*() const 946 { return *mIterator; } 947 948 pointer operator->() const 949 { return mIterator; } 950 951 this_type& operator++() 952 { ++mIterator; return *this; } 953 954 this_type operator++(int) 955 { return this_type(mIterator++); } 956 957 this_type& operator--() 958 { --mIterator; return *this; } 959 960 this_type operator--(int) 961 { return this_type(mIterator--); } 962 963 reference operator[](const difference_type& n) const 964 { return mIterator[n]; } 965 966 this_type& operator+=(const difference_type& n) 967 { mIterator += n; return *this; } 968 969 this_type operator+(const difference_type& n) const 970 { return this_type(mIterator + n); } 971 972 this_type& operator-=(const difference_type& n) 973 { mIterator -= n; return *this; } 974 975 this_type operator-(const difference_type& n) const 976 { return this_type(mIterator - n); } 977 978 const iterator_type& base() const 979 { return mIterator; } 980 981 }; // class demoted_iterator 982 983 template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2> 984 inline bool 985 operator==(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b) 986 { return a.base() == b.base(); } 987 988 template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2> 989 inline bool 990 operator!=(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b) 991 { return !(a == b); } 992 993 template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2> 994 inline bool 995 operator<(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b) 996 { return a.base() < b.base(); } 997 998 template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2> 999 inline bool 1000 operator<=(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b) 1001 { return !(b < a); } 1002 1003 template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2> 1004 inline bool 1005 operator>(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b) 1006 { return b < a; } 1007 1008 template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2> 1009 inline bool 1010 operator>=(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b) 1011 { return !(a < b); } 1012 1013 template<typename Iterator1, typename IteratorCategory1, typename Iterator2, typename IteratorCategory2> 1014 inline demoted_iterator<Iterator1, IteratorCategory1> 1015 operator-(const demoted_iterator<Iterator1, IteratorCategory1>& a, const demoted_iterator<Iterator2, IteratorCategory2>& b) 1016 { return demoted_iterator<Iterator1, IteratorCategory1>(a.base() - b.base()); } 1017 1018 template<typename Iterator1, typename IteratorCategory1> 1019 inline demoted_iterator<Iterator1, IteratorCategory1> 1020 operator+(typename demoted_iterator<Iterator1, IteratorCategory1>::difference_type n, const demoted_iterator<Iterator1, IteratorCategory1>& a) 1021 { return a + n; } 1022 1023 1024 // to_xxx_iterator 1025 // 1026 // Returns a demoted iterator 1027 // 1028 template <typename Iterator> 1029 inline demoted_iterator<Iterator, EASTL_ITC_NS::input_iterator_tag> 1030 to_input_iterator(const Iterator& i) 1031 { return demoted_iterator<Iterator, EASTL_ITC_NS::input_iterator_tag>(i); } 1032 1033 template <typename Iterator> 1034 inline demoted_iterator<Iterator, EASTL_ITC_NS::forward_iterator_tag> 1035 to_forward_iterator(const Iterator& i) 1036 { return demoted_iterator<Iterator, EASTL_ITC_NS::forward_iterator_tag>(i); } 1037 1038 template <typename Iterator> 1039 inline demoted_iterator<Iterator, EASTL_ITC_NS::bidirectional_iterator_tag> 1040 to_bidirectional_iterator(const Iterator& i) 1041 { return demoted_iterator<Iterator, EASTL_ITC_NS::bidirectional_iterator_tag>(i); } 1042 1043 template <typename Iterator> 1044 inline demoted_iterator<Iterator, EASTL_ITC_NS::random_access_iterator_tag> 1045 to_random_access_iterator(const Iterator& i) 1046 { return demoted_iterator<Iterator, EASTL_ITC_NS::random_access_iterator_tag>(i); } 1047 1048 1049 1050 1051 1052 1053 /////////////////////////////////////////////////////////////////////////////// 1054 // MallocAllocator 1055 // 1056 // Implements an EASTL allocator that uses malloc/free as opposed to 1057 // new/delete or PPMalloc Malloc/Free. This is useful for testing 1058 // allocator behaviour of code. 1059 // 1060 // Example usage: 1061 // vector<int, MallocAllocator> intVector; 1062 // 1063 class MallocAllocator 1064 { 1065 public: 1066 MallocAllocator(const char* = EASTL_NAME_VAL("MallocAllocator")) 1067 : mAllocCount(0), mFreeCount(0), mAllocVolume(0) {} 1068 1069 MallocAllocator(const MallocAllocator& x) 1070 : mAllocCount(x.mAllocCount), mFreeCount(x.mFreeCount), mAllocVolume(x.mAllocVolume) {} 1071 1072 MallocAllocator(const MallocAllocator&, const char*) {} 1073 1074 MallocAllocator& operator=(const MallocAllocator& x) 1075 { 1076 mAllocCount = x.mAllocCount; 1077 mFreeCount = x.mFreeCount; 1078 mAllocVolume = x.mAllocVolume; 1079 return *this; 1080 } 1081 1082 void* allocate(size_t n, int = 0); 1083 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. 1084 void deallocate(void* p, size_t n); 1085 1086 const char* get_name() const { return "MallocAllocator"; } 1087 void set_name(const char*) {} 1088 1089 static void reset_all() 1090 { 1091 mAllocCountAll = 0; 1092 mFreeCountAll = 0; 1093 mAllocVolumeAll = 0; 1094 mpLastAllocation = NULL; 1095 } 1096 1097 public: 1098 int mAllocCount; 1099 int mFreeCount; 1100 size_t mAllocVolume; 1101 1102 static int mAllocCountAll; 1103 static int mFreeCountAll; 1104 static size_t mAllocVolumeAll; 1105 static void* mpLastAllocation; 1106 }; 1107 1108 inline bool operator==(const MallocAllocator&, const MallocAllocator&) { return true; } 1109 inline bool operator!=(const MallocAllocator&, const MallocAllocator&) { return false; } 1110 1111 1112 /////////////////////////////////////////////////////////////////////////////// 1113 // CustomAllocator 1114 // 1115 // Implements an allocator that works just like eastl::allocator but is defined 1116 // within this test as opposed to within EASTL. 1117 // 1118 // Example usage: 1119 // vector<int, CustomAllocator> intVector; 1120 // 1121 class CustomAllocator 1122 { 1123 public: 1124 CustomAllocator(const char* = NULL) {} 1125 CustomAllocator(const CustomAllocator&) {} 1126 CustomAllocator(const CustomAllocator&, const char*) {} 1127 CustomAllocator& operator=(const CustomAllocator&) { return *this; } 1128 1129 void* allocate(size_t n, int flags = 0); 1130 void* allocate(size_t n, size_t, size_t, int flags = 0); 1131 void deallocate(void* p, size_t n); 1132 1133 const char* get_name() const { return "CustomAllocator"; } 1134 void set_name(const char*) {} 1135 }; 1136 1137 inline bool operator==(const CustomAllocator&, const CustomAllocator&) { return true; } 1138 inline bool operator!=(const CustomAllocator&, const CustomAllocator&) { return false; } 1139 1140 1141 /////////////////////////////////////////////////////////////////////////////// 1142 /// UnequalAllocator 1143 /// 1144 /// Acts the same as eastl::allocator, but always compares as unequal to an 1145 /// instance of itself. 1146 /// 1147 class UnequalAllocator 1148 { 1149 public: 1150 EASTL_ALLOCATOR_EXPLICIT UnequalAllocator(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME)) 1151 : mAllocator(pName) {} 1152 1153 UnequalAllocator(const UnequalAllocator& x) : mAllocator(x.mAllocator) {} 1154 UnequalAllocator(const UnequalAllocator& x, const char* pName) : mAllocator(x.mAllocator) { set_name(pName); } 1155 UnequalAllocator& operator=(const UnequalAllocator& x) 1156 { 1157 mAllocator = x.mAllocator; 1158 return *this; 1159 } 1160 1161 void* allocate(size_t n, int flags = 0) { return mAllocator.allocate(n, flags); } 1162 void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0) { return mAllocator.allocate(n, alignment, offset, flags); } 1163 void deallocate(void* p, size_t n) { return mAllocator.deallocate(p, n); } 1164 1165 const char* get_name() const { return mAllocator.get_name(); } 1166 void set_name(const char* pName) { mAllocator.set_name(pName); } 1167 1168 protected: 1169 eastl::allocator mAllocator; 1170 }; 1171 1172 inline bool operator==(const UnequalAllocator&, const UnequalAllocator&) { return false; } 1173 inline bool operator!=(const UnequalAllocator&, const UnequalAllocator&) { return true; } 1174 1175 1176 /////////////////////////////////////////////////////////////////////////////// 1177 /// CountingAllocator 1178 /// 1179 /// Counts allocation events allowing unit tests to validate assumptions. 1180 /// 1181 class CountingAllocator : public eastl::allocator 1182 { 1183 public: 1184 using base_type = eastl::allocator; 1185 1186 EASTL_ALLOCATOR_EXPLICIT CountingAllocator(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME)) 1187 : base_type(pName) 1188 { 1189 totalCtorCount++; 1190 defaultCtorCount++; 1191 } 1192 1193 CountingAllocator(const CountingAllocator& x) : base_type(x) 1194 { 1195 totalCtorCount++; 1196 copyCtorCount++; 1197 } 1198 1199 CountingAllocator(const CountingAllocator& x, const char* pName) : base_type(x) 1200 { 1201 totalCtorCount++; 1202 copyCtorCount++; 1203 set_name(pName); 1204 } 1205 1206 CountingAllocator& operator=(const CountingAllocator& x) 1207 { 1208 base_type::operator=(x); 1209 assignOpCount++; 1210 return *this; 1211 } 1212 1213 virtual void* allocate(size_t n, int flags = 0) 1214 { 1215 activeAllocCount++; 1216 totalAllocCount++; 1217 totalAllocatedMemory += n; 1218 activeAllocatedMemory += n; 1219 return base_type::allocate(n, flags); 1220 } 1221 1222 virtual void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0) 1223 { 1224 activeAllocCount++; 1225 totalAllocCount++; 1226 totalAllocatedMemory += n; 1227 activeAllocatedMemory += n; 1228 return base_type::allocate(n, alignment, offset, flags); 1229 } 1230 1231 void deallocate(void* p, size_t n) 1232 { 1233 activeAllocCount--; 1234 totalDeallocCount--; 1235 activeAllocatedMemory -= n; 1236 return base_type::deallocate(p, n); 1237 } 1238 1239 const char* get_name() const { return base_type::get_name(); } 1240 void set_name(const char* pName) { base_type::set_name(pName); } 1241 1242 static auto getTotalAllocationCount() { return totalAllocCount; } 1243 static auto getTotalAllocationSize() { return totalAllocatedMemory; } 1244 static auto getActiveAllocationSize() { return activeAllocatedMemory; } 1245 static auto getActiveAllocationCount() { return activeAllocCount; } 1246 static auto neverUsed() { return totalAllocCount == 0; } 1247 1248 static void resetCount() 1249 { 1250 activeAllocCount = 0; 1251 totalAllocCount = 0; 1252 totalDeallocCount = 0; 1253 totalCtorCount = 0; 1254 defaultCtorCount = 0; 1255 copyCtorCount = 0; 1256 assignOpCount = 0; 1257 totalAllocatedMemory = 0; 1258 activeAllocatedMemory = 0; 1259 } 1260 1261 static uint64_t activeAllocCount; 1262 static uint64_t totalAllocCount; 1263 static uint64_t totalDeallocCount; 1264 static uint64_t totalCtorCount; 1265 static uint64_t defaultCtorCount; 1266 static uint64_t copyCtorCount; 1267 static uint64_t assignOpCount; 1268 static uint64_t totalAllocatedMemory; // the total amount of memory allocated 1269 static uint64_t activeAllocatedMemory; // currently allocated memory by allocator 1270 }; 1271 1272 inline bool operator==(const CountingAllocator& rhs, const CountingAllocator& lhs) { return operator==(CountingAllocator::base_type(rhs), CountingAllocator::base_type(lhs)); } 1273 inline bool operator!=(const CountingAllocator& rhs, const CountingAllocator& lhs) { return !(rhs == lhs); } 1274 1275 1276 1277 1278 /////////////////////////////////////////////////////////////////////////////// 1279 // InstanceAllocator 1280 // 1281 // Implements an allocator which has a instance id that makes it different 1282 // from other InstanceAllocators of a different id. Allocations between 1283 // InstanceAllocators of different ids are incompatible. An allocation done 1284 // by an InstanceAllocator of id=0 cannot be freed by an InstanceAllocator 1285 // of id=1. 1286 // 1287 // Example usage: 1288 // InstanceAllocator ia0((uint8_t)0); 1289 // InstanceAllocator ia1((uint8_t)1); 1290 // 1291 // eastl::list<int, InstanceAllocator> list0(1, ia0); 1292 // eastl::list<int, InstanceAllocator> list1(1, ia1); 1293 // 1294 // 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. 1295 // 1296 class InstanceAllocator 1297 { 1298 public: 1299 enum 1300 { 1301 kMultiplier = 16 1302 }; // Use 16 because it's the highest currently known platform alignment requirement. 1303 1304 InstanceAllocator(const char* = NULL, uint8_t instanceId = 0) : mInstanceId(instanceId) {} 1305 InstanceAllocator(uint8_t instanceId) : mInstanceId(instanceId) {} 1306 InstanceAllocator(const InstanceAllocator& x) : mInstanceId(x.mInstanceId) {} 1307 InstanceAllocator(const InstanceAllocator& x, const char*) : mInstanceId(x.mInstanceId) {} 1308 1309 InstanceAllocator& operator=(const InstanceAllocator& x) 1310 { 1311 mInstanceId = x.mInstanceId; 1312 return *this; 1313 } 1314 1315 void* allocate(size_t n, int = 0) 1316 { // +1 so that we always have space to write mInstanceId. 1317 uint8_t* p8 = 1318 static_cast<uint8_t*>(malloc(n + (kMultiplier * (mInstanceId + 1)))); // We make allocations between 1319 // different instances incompatible by 1320 // tweaking their return values. 1321 eastl::fill(p8, p8 + kMultiplier, 0xff); 1322 EA_ANALYSIS_ASSUME(p8 != NULL); 1323 *p8 = mInstanceId; 1324 return p8 + (kMultiplier * (mInstanceId + 1)); 1325 } 1326 1327 void* allocate(size_t n, size_t, size_t, int = 0) 1328 { // +1 so that we always have space to write mInstanceId. 1329 uint8_t* p8 = 1330 static_cast<uint8_t*>(malloc(n + (kMultiplier * (mInstanceId + 1)))); // We make allocations between 1331 // different instances incompatible by 1332 // tweaking their return values. 1333 eastl::fill(p8, p8 + kMultiplier, 0xff); 1334 EA_ANALYSIS_ASSUME(p8 != NULL); 1335 *p8 = mInstanceId; 1336 return p8 + (kMultiplier * (mInstanceId + 1)); 1337 } 1338 1339 void deallocate(void* p, size_t /*n*/) 1340 { 1341 uint8_t* p8 = static_cast<uint8_t*>(p) - (kMultiplier * (mInstanceId + 1)); 1342 EASTL_ASSERT(*p8 == mInstanceId); // mInstanceId must match the id used in allocate(), otherwise the behavior is 1343 // undefined (probably a heap assert). 1344 if (*p8 == mInstanceId) // It's possible that *p8 coincidentally matches mInstanceId if p8 is offset into memory 1345 // we don't control. 1346 free(p8); 1347 else 1348 ++mMismatchCount; 1349 } 1350 1351 const char* get_name() 1352 { 1353 sprintf(mName, "InstanceAllocator %u", mInstanceId); 1354 return mName; 1355 } 1356 1357 void set_name(const char*) {} 1358 1359 static void reset_all() { mMismatchCount = 0; } 1360 1361 public: 1362 uint8_t mInstanceId; 1363 char mName[32]; 1364 1365 static int mMismatchCount; 1366 }; 1367 1368 inline bool operator==(const InstanceAllocator& a, const InstanceAllocator& b) { return (a.mInstanceId == b.mInstanceId); } 1369 inline bool operator!=(const InstanceAllocator& a, const InstanceAllocator& b) { return (a.mInstanceId != b.mInstanceId); } 1370 1371 1372 /////////////////////////////////////////////////////////////////////////////// 1373 // ThrowingAllocator 1374 // 1375 // Implements an EASTL allocator that uses malloc/free as opposed to 1376 // new/delete or PPMalloc Malloc/Free. This is useful for testing 1377 // allocator behaviour of code. 1378 // 1379 // Example usage: 1380 // vector<int, ThrowingAllocator< false<> > intVector; 1381 // 1382 template <bool initialShouldThrow = true> 1383 class ThrowingAllocator 1384 { 1385 public: 1386 ThrowingAllocator(const char* = EASTL_NAME_VAL("ThrowingAllocator")) : mbShouldThrow(initialShouldThrow) {} 1387 ThrowingAllocator(const ThrowingAllocator& x) : mbShouldThrow(x.mbShouldThrow) {} 1388 ThrowingAllocator(const ThrowingAllocator& x, const char*) : mbShouldThrow(x.mbShouldThrow) {} 1389 1390 ThrowingAllocator& operator=(const ThrowingAllocator& x) 1391 { 1392 mbShouldThrow = x.mbShouldThrow; 1393 return *this; 1394 } 1395 1396 void* allocate(size_t n, int = 0) 1397 { 1398 #if EASTL_EXCEPTIONS_ENABLED 1399 if (mbShouldThrow) 1400 throw std::bad_alloc(); 1401 #endif 1402 return malloc(n); 1403 } 1404 1405 void* allocate(size_t n, size_t, size_t, int = 0) 1406 { 1407 #if EASTL_EXCEPTIONS_ENABLED 1408 if (mbShouldThrow) 1409 throw std::bad_alloc(); 1410 #endif 1411 return malloc(n); // We don't support alignment, so you can't use this class where alignment is required. 1412 } 1413 1414 void deallocate(void* p, size_t) { free(p); } 1415 1416 const char* get_name() const { return "ThrowingAllocator"; } 1417 void set_name(const char*) {} 1418 1419 void set_should_throw(bool shouldThrow) { mbShouldThrow = shouldThrow; } 1420 bool get_should_throw() const { return mbShouldThrow; } 1421 1422 protected: 1423 bool mbShouldThrow; 1424 }; 1425 1426 template <bool initialShouldThrow> 1427 inline bool operator==(const ThrowingAllocator<initialShouldThrow>&, const ThrowingAllocator<initialShouldThrow>&) 1428 { 1429 return true; 1430 } 1431 1432 template <bool initialShouldThrow> 1433 inline bool operator!=(const ThrowingAllocator<initialShouldThrow>&, const ThrowingAllocator<initialShouldThrow>&) 1434 { 1435 return false; 1436 } 1437 1438 1439 /////////////////////////////////////////////////////////////////////////////// 1440 // Helper utility that does a case insensitive string comparsion with two sets of overloads 1441 // 1442 struct TestStrCmpI_2 1443 { 1444 bool operator()(const char* pCStr, const eastl::string& str) const { return str.comparei(pCStr) == 0; } 1445 bool operator()(const eastl::string& str, const char* pCStr) const { return str.comparei(pCStr) == 0; } 1446 }; 1447 1448 1449 /////////////////////////////////////////////////////////////////////////////// 1450 // StompDetectAllocator 1451 // 1452 // An allocator that has sentinal values surrounding its allocator in an 1453 // effort to detected if its internal memory has been stomped. 1454 // 1455 static uint64_t STOMP_MAGIC_V1 = 0x0101DEC1A551F1ED; 1456 static uint64_t STOMP_MAGIC_V2 = 0x12345C1A551F1ED5; 1457 1458 struct StompDetectAllocator 1459 { 1460 StompDetectAllocator() { Validate(); } 1461 ~StompDetectAllocator() { Validate(); } 1462 1463 StompDetectAllocator(const char*) { Validate(); } 1464 1465 void* allocate(size_t n, int = 0) { return mMallocAllocator.allocate(n); } 1466 void* allocate(size_t n, size_t, size_t, int = 0) { return mMallocAllocator.allocate(n); } 1467 void deallocate(void* p, size_t n) { mMallocAllocator.deallocate(p, n); } 1468 1469 const char* get_name() const { return "FatAllocator"; } 1470 void set_name(const char*) {} 1471 1472 void Validate() const 1473 { 1474 EASTL_ASSERT(mSentinal1 == STOMP_MAGIC_V1); 1475 EASTL_ASSERT(mSentinal2 == STOMP_MAGIC_V2); 1476 } 1477 1478 uint64_t mSentinal1 = STOMP_MAGIC_V1; 1479 MallocAllocator mMallocAllocator; 1480 uint64_t mSentinal2 = STOMP_MAGIC_V2; 1481 }; 1482 1483 inline bool operator==(const StompDetectAllocator& a, const StompDetectAllocator& b) 1484 { 1485 a.Validate(); 1486 b.Validate(); 1487 1488 return (a.mMallocAllocator == b.mMallocAllocator); 1489 } 1490 1491 inline bool operator!=(const StompDetectAllocator& a, const StompDetectAllocator& b) 1492 { 1493 a.Validate(); 1494 b.Validate(); 1495 1496 return (a.mMallocAllocator != b.mMallocAllocator); 1497 } 1498 1499 1500 // Commonly used free-standing functions to test callables 1501 inline int ReturnVal(int param) { return param; } 1502 inline int ReturnZero() { return 0; } 1503 inline int ReturnOne() { return 1; } 1504 1505 1506 // ValueInit 1507 template<class T> 1508 struct ValueInitOf 1509 { 1510 ValueInitOf() : mV() {} 1511 ~ValueInitOf() = default; 1512 1513 ValueInitOf(const ValueInitOf&) = default; 1514 ValueInitOf(ValueInitOf&&) = default; 1515 1516 ValueInitOf& operator=(const ValueInitOf&) = default; 1517 ValueInitOf& operator=(ValueInitOf&&) = default; 1518 1519 T get() { return mV; } 1520 1521 T mV; 1522 }; 1523 1524 // MoveOnlyType - useful for verifying containers that may hold, e.g., unique_ptrs to make sure move ops are implemented 1525 struct MoveOnlyType 1526 { 1527 MoveOnlyType() = delete; 1528 MoveOnlyType(int val) : mVal(val) {} 1529 MoveOnlyType(const MoveOnlyType&) = delete; 1530 MoveOnlyType(MoveOnlyType&& x) : mVal(x.mVal) { x.mVal = 0; } 1531 MoveOnlyType& operator=(const MoveOnlyType&) = delete; 1532 MoveOnlyType& operator=(MoveOnlyType&& x) 1533 { 1534 mVal = x.mVal; 1535 x.mVal = 0; 1536 return *this; 1537 } 1538 bool operator==(const MoveOnlyType& o) const { return mVal == o.mVal; } 1539 1540 int mVal; 1541 }; 1542 1543 // MoveOnlyTypeDefaultCtor - useful for verifying containers that may hold, e.g., unique_ptrs to make sure move ops are implemented 1544 struct MoveOnlyTypeDefaultCtor 1545 { 1546 MoveOnlyTypeDefaultCtor() = default; 1547 MoveOnlyTypeDefaultCtor(int val) : mVal(val) {} 1548 MoveOnlyTypeDefaultCtor(const MoveOnlyTypeDefaultCtor&) = delete; 1549 MoveOnlyTypeDefaultCtor(MoveOnlyTypeDefaultCtor&& x) : mVal(x.mVal) { x.mVal = 0; } 1550 MoveOnlyTypeDefaultCtor& operator=(const MoveOnlyTypeDefaultCtor&) = delete; 1551 MoveOnlyTypeDefaultCtor& operator=(MoveOnlyTypeDefaultCtor&& x) 1552 { 1553 mVal = x.mVal; 1554 x.mVal = 0; 1555 return *this; 1556 } 1557 bool operator==(const MoveOnlyTypeDefaultCtor& o) const { return mVal == o.mVal; } 1558 1559 int mVal; 1560 }; 1561 1562 1563 1564 ////////////////////////////////////////////////////////////////////////////// 1565 // Utility RAII class that sets a new default allocator for the scope 1566 // 1567 struct AutoDefaultAllocator 1568 { 1569 eastl::allocator* mPrevAllocator = nullptr; 1570 1571 AutoDefaultAllocator(eastl::allocator* nextAllocator) { mPrevAllocator = SetDefaultAllocator(nextAllocator); } 1572 ~AutoDefaultAllocator() { SetDefaultAllocator(mPrevAllocator); } 1573 }; 1574 1575 1576 #endif // Header include guard 1577 1578 1579 1580 1581 1582 1583 1584