Hashed.cpp 94 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "UserTypes.h"
  9. #include <AzCore/std/hash_table.h>
  10. #include <AzCore/std/containers/array.h>
  11. #include <AzCore/std/containers/unordered_set.h>
  12. #include <AzCore/std/containers/unordered_map.h>
  13. #include <AzCore/std/containers/fixed_unordered_set.h>
  14. #include <AzCore/std/containers/fixed_unordered_map.h>
  15. #include <AzCore/std/containers/span.h>
  16. #include <AzCore/std/ranges/transform_view.h>
  17. #include <AzCore/std/string/string.h>
  18. #include <AzCore/std/typetraits/has_member_function.h>
  19. #if defined(HAVE_BENCHMARK)
  20. #include <benchmark/benchmark.h>
  21. #endif // HAVE_BENCHMARK
  22. namespace UnitTest
  23. {
  24. using namespace AZStd;
  25. using namespace UnitTestInternal;
  26. AZ_HAS_MEMBER(HashValidate, validate, void, ());
  27. /**
  28. * Hash functions test.
  29. */
  30. class HashedContainers
  31. : public LeakDetectionFixture
  32. {
  33. public:
  34. template <class H, bool hasValidate>
  35. struct Validator
  36. {
  37. static void Validate(H& h)
  38. {
  39. EXPECT_TRUE(h.validate());
  40. }
  41. };
  42. template <class H>
  43. struct Validator<H, false>
  44. {
  45. static void Validate(H&) {}
  46. };
  47. template <class H>
  48. static void ValidateHash(H& h, size_t numElements = 0)
  49. {
  50. Validator<H, HasHashValidate_v<H>>::Validate(h);
  51. EXPECT_EQ(numElements, h.size());
  52. if (numElements > 0)
  53. {
  54. EXPECT_FALSE(h.empty());
  55. EXPECT_TRUE(h.begin() != h.end());
  56. }
  57. else
  58. {
  59. EXPECT_TRUE(h.empty());
  60. EXPECT_TRUE(h.begin() == h.end());
  61. }
  62. }
  63. };
  64. TEST_F(HashedContainers, Test)
  65. {
  66. EXPECT_EQ(1, hash<bool>()(true));
  67. EXPECT_EQ(0, hash<bool>()(false));
  68. char ch = 11;
  69. EXPECT_EQ(11, hash<char>()(ch));
  70. signed char sc = 127;
  71. EXPECT_EQ(127, hash<signed char>()(sc));
  72. unsigned char uc = 202;
  73. EXPECT_EQ(202, hash<unsigned char>()(uc));
  74. short sh = 16533;
  75. EXPECT_EQ(16533, hash<short>()(sh));
  76. signed short ss = 16333;
  77. EXPECT_EQ(16333, hash<signed short>()(ss));
  78. unsigned short us = 24533;
  79. EXPECT_EQ(24533, hash<unsigned short>()(us));
  80. int in = 5748538;
  81. EXPECT_EQ(5748538, hash<int>()(in));
  82. unsigned int ui = 0x0fffffff;
  83. EXPECT_EQ(0x0fffffff, hash<unsigned int>()(ui));
  84. AZ_TEST_ASSERT(hash<float>()(103.0f) != 0);
  85. EXPECT_EQ(hash<float>()(103.0f), hash<float>()(103.0f));
  86. AZ_TEST_ASSERT(hash<float>()(103.0f) != hash<float>()(103.1f));
  87. AZ_TEST_ASSERT(hash<double>()(103.0) != 0);
  88. EXPECT_EQ(hash<double>()(103.0), hash<double>()(103.0));
  89. AZ_TEST_ASSERT(hash<double>()(103.0) != hash<double>()(103.1));
  90. const char* string_literal = "Bla";
  91. const char* string_literal1 = "Cla";
  92. AZ_TEST_ASSERT(hash<const char*>()(string_literal) != 0);
  93. AZ_TEST_ASSERT(hash<const char*>()(string_literal) != hash<const char*>()(string_literal1));
  94. string str1(string_literal);
  95. string str2(string_literal1);
  96. AZ_TEST_ASSERT(hash<string>()(str1) != 0);
  97. AZ_TEST_ASSERT(hash<string>()(str1) != hash<string>()(str2));
  98. wstring wstr1(L"BLA");
  99. wstring wstr2(L"CLA");
  100. AZ_TEST_ASSERT(hash<wstring>()(wstr1) != 0);
  101. AZ_TEST_ASSERT(hash<wstring>()(wstr1) != hash<wstring>()(wstr2));
  102. }
  103. TEST_F(HashedContainers, HashRange_HashCombine_CompileWhenUsedInConstexprContext)
  104. {
  105. constexpr AZStd::array<int, 3> hashList{ { 4, 8, 3 } };
  106. static_assert(hash_range(hashList.begin(), hashList.end()) != 0);
  107. auto TestHashCombine = [](size_t hashValue) constexpr -> size_t
  108. {
  109. size_t seed = 0;
  110. hash_combine(seed, hashValue);
  111. return seed;
  112. };
  113. static_assert(TestHashCombine(42) != 0);
  114. }
  115. /**
  116. * HashTableSetTraits
  117. */
  118. // HashTableTest-Begin
  119. template<class T, bool isMultiSet, bool isDynamic>
  120. struct HashTableSetTestTraits
  121. {
  122. typedef T key_type;
  123. typedef typename AZStd::equal_to<T> key_equal;
  124. typedef typename AZStd::hash<T> hasher;
  125. typedef T value_type;
  126. typedef AZStd::allocator allocator_type;
  127. enum
  128. {
  129. max_load_factor = 4,
  130. min_buckets = 7,
  131. has_multi_elements = isMultiSet,
  132. is_dynamic = isDynamic,
  133. fixed_num_buckets = 101, // a prime number between 1/3 - 1/4 of the number of elements.
  134. fixed_num_elements = 300,
  135. };
  136. static AZ_FORCE_INLINE const key_type& key_from_value(const value_type& value) { return value; }
  137. };
  138. TEST_F(HashedContainers, HashTable_Dynamic)
  139. {
  140. array<int, 5> elements = {
  141. { 10, 100, 11, 2, 301 }
  142. };
  143. typedef HashTableSetTestTraits< int, false, true > hash_set_traits;
  144. typedef hash_table< hash_set_traits > hash_key_table_type;
  145. hash_set_traits::hasher set_hasher;
  146. //
  147. hash_key_table_type hTable(set_hasher, hash_set_traits::key_equal(), hash_set_traits::allocator_type());
  148. ValidateHash(hTable);
  149. //
  150. hash_key_table_type hTable1(elements.begin(), elements.end(), set_hasher, hash_set_traits::key_equal(), hash_set_traits::allocator_type());
  151. ValidateHash(hTable1, elements.size());
  152. //
  153. hash_key_table_type hTable2(hTable1);
  154. ValidateHash(hTable1, hTable1.size());
  155. //
  156. hTable = hTable1;
  157. ValidateHash(hTable, hTable1.size());
  158. //AZ_TEST_ASSERT(hTable.bucket_count()==hash_set_traits::min_buckets);
  159. EXPECT_EQ((float)hash_set_traits::max_load_factor, hTable.max_load_factor());
  160. hTable.reserve(50);
  161. ValidateHash(hTable, hTable1.size());
  162. AZ_TEST_ASSERT(hTable.bucket_count() * hTable.max_load_factor() >= 50);
  163. AZ_TEST_ASSERT(hTable.bucket_count() < 100); // Make sure it doesn't interfere with the next test
  164. hTable.rehash(100);
  165. ValidateHash(hTable, hTable1.size());
  166. AZ_TEST_ASSERT(hTable.bucket_count() >= 100);
  167. hTable.insert(201);
  168. ValidateHash(hTable, hTable1.size() + 1);
  169. array<int, 5> toInsert = {
  170. { 17, 101, 27, 7, 501 }
  171. };
  172. hTable.insert(toInsert.begin(), toInsert.end());
  173. ValidateHash(hTable, hTable1.size() + 1 + toInsert.size());
  174. hTable.erase(hTable.begin());
  175. ValidateHash(hTable, hTable1.size() + toInsert.size());
  176. hTable.erase(hTable.begin(), next(hTable.begin(), (int)hTable1.size()));
  177. ValidateHash(hTable, toInsert.size());
  178. hTable.clear();
  179. ValidateHash(hTable);
  180. hTable.insert(toInsert.begin(), toInsert.end());
  181. hTable.erase(17);
  182. ValidateHash(hTable, toInsert.size() - 1);
  183. hTable.erase(18);
  184. ValidateHash(hTable, toInsert.size() - 1);
  185. hTable.clear();
  186. ValidateHash(hTable);
  187. hTable.insert(toInsert.begin(), toInsert.end());
  188. hash_key_table_type::iterator iter = hTable.find(7);
  189. AZ_TEST_ASSERT(iter != hTable.end());
  190. hash_key_table_type::const_iterator citer = hTable.find(7);
  191. AZ_TEST_ASSERT(citer != hTable.end());
  192. iter = hTable.find(57);
  193. AZ_TEST_ASSERT(iter == hTable.end());
  194. EXPECT_EQ(1, hTable.count(101));
  195. EXPECT_EQ(0, hTable.count(201));
  196. iter = hTable.lower_bound(17);
  197. AZ_TEST_ASSERT(iter != hTable.end());
  198. AZ_TEST_ASSERT(*prev(iter) != 17);
  199. citer = hTable.lower_bound(17);
  200. AZ_TEST_ASSERT(citer != hTable.end());
  201. AZ_TEST_ASSERT(*prev(citer) != 17);
  202. iter = hTable.lower_bound(57);
  203. AZ_TEST_ASSERT(iter == hTable.end());
  204. iter = hTable.upper_bound(101);
  205. AZ_TEST_ASSERT(iter == hTable.end() || *iter != 101);
  206. EXPECT_EQ(101, *prev(iter));
  207. citer = hTable.upper_bound(101);
  208. AZ_TEST_ASSERT(citer == hTable.end() || *citer != 101);
  209. EXPECT_EQ(101, *prev(citer));
  210. iter = hTable.upper_bound(57);
  211. AZ_TEST_ASSERT(iter == hTable.end());
  212. hash_key_table_type::pair_iter_iter rangeIt = hTable.equal_range(17);
  213. AZ_TEST_ASSERT(rangeIt.first != hTable.end());
  214. AZ_TEST_ASSERT(next(rangeIt.first) == rangeIt.second);
  215. hash_key_table_type::pair_citer_citer crangeIt = hTable.equal_range(17);
  216. AZ_TEST_ASSERT(crangeIt.first != hTable.end());
  217. AZ_TEST_ASSERT(next(crangeIt.first) == crangeIt.second);
  218. hTable1.clear();
  219. hTable.swap(hTable1);
  220. ValidateHash(hTable);
  221. ValidateHash(hTable1, toInsert.size());
  222. typedef HashTableSetTestTraits< int, true, true > hash_multiset_traits;
  223. typedef hash_table< hash_multiset_traits > hash_key_multitable_type;
  224. hash_key_multitable_type hMultiTable(set_hasher, hash_set_traits::key_equal(), hash_set_traits::allocator_type());
  225. array<int, 7> toInsert2 = {
  226. { 17, 101, 27, 7, 501, 101, 101 }
  227. };
  228. hMultiTable.insert(toInsert2.begin(), toInsert2.end());
  229. ValidateHash(hMultiTable, toInsert2.size());
  230. EXPECT_EQ(3, hMultiTable.count(101));
  231. AZ_TEST_ASSERT(hMultiTable.lower_bound(101) != prev(hMultiTable.upper_bound(101)));
  232. AZ_TEST_ASSERT(hMultiTable.lower_bound(501) == prev(hMultiTable.upper_bound(501)));
  233. hash_key_multitable_type::pair_iter_iter rangeIt2 = hMultiTable.equal_range(101);
  234. AZ_TEST_ASSERT(rangeIt2.first != rangeIt2.second);
  235. EXPECT_EQ(3, distance(rangeIt2.first, rangeIt2.second));
  236. hash_key_multitable_type::iterator iter2 = rangeIt2.first;
  237. for (; iter2 != rangeIt2.second; ++iter2)
  238. {
  239. EXPECT_EQ(101, *iter2);
  240. }
  241. }
  242. TEST_F(HashedContainers, HashTable_InsertionDuplicateOnRehash)
  243. {
  244. struct TwoPtrs
  245. {
  246. void* m_ptr1;
  247. void* m_ptr2;
  248. bool operator==(const TwoPtrs& other) const
  249. {
  250. if (m_ptr1 == other.m_ptr1)
  251. {
  252. return m_ptr2 == other.m_ptr2;
  253. }
  254. else if (m_ptr1 == other.m_ptr2)
  255. {
  256. return m_ptr2 == other.m_ptr1;
  257. }
  258. return false;
  259. }
  260. };
  261. // This hashing function produces different hashes for two equal values,
  262. // which violates the requirement for hashing functions.
  263. // The test makes sure that this does not reproduce an issue that caused the insert() function to loop infinitely.
  264. struct TwoPtrsHasher
  265. {
  266. size_t operator()(const TwoPtrs& p) const
  267. {
  268. size_t hash{ 0 };
  269. AZStd::hash_combine(hash, p.m_ptr1, p.m_ptr2);
  270. return hash;
  271. }
  272. };
  273. using PairSet = AZStd::unordered_set<TwoPtrs, TwoPtrsHasher>;
  274. PairSet set;
  275. set.insert({ (void*)1, (void*)2 });
  276. set.insert({ (void*)3, (void*)4 });
  277. set.insert({ (void*)5, (void*)6 });
  278. set.insert({ (void*)7, (void*)8 });
  279. // Elements with different hashes, but equal
  280. set.insert({ (void*)0x000001ceddd9ca20, (void*)0x000001ceddd9cba0 }); // hash(148335135725641)
  281. set.insert({ (void*)0x000001ceddd9cba0, (void*)0x000001ceddd9ca20 }); // hash(148335135764189)
  282. AZ_TEST_START_TRACE_SUPPRESSION;
  283. // This will trigger the assertion of duplicated elements found
  284. // A bucket size of 23 since is where the collision between different hashes happens
  285. set.rehash(23);
  286. AZ_TEST_STOP_TRACE_SUPPRESSION(1); // 1 assertion
  287. }
  288. TEST_F(HashedContainers, HashTable_Fixed)
  289. {
  290. array<int, 5> elements = {
  291. { 10, 100, 11, 2, 301 }
  292. };
  293. typedef HashTableSetTestTraits< int, false, false > hash_set_traits;
  294. typedef hash_table< hash_set_traits > hash_key_table_type;
  295. hash_set_traits::hasher set_hasher;
  296. //
  297. hash_key_table_type hTable(set_hasher, hash_set_traits::key_equal(), hash_set_traits::allocator_type());
  298. ValidateHash(hTable);
  299. //
  300. hash_key_table_type hTable1(elements.begin(), elements.end(), set_hasher, hash_set_traits::key_equal(), hash_set_traits::allocator_type());
  301. ValidateHash(hTable1, elements.size());
  302. //
  303. hash_key_table_type hTable2(hTable1);
  304. ValidateHash(hTable1, hTable1.size());
  305. //
  306. hTable = hTable1;
  307. ValidateHash(hTable, hTable1.size());
  308. hTable.rehash(100);
  309. ValidateHash(hTable, hTable1.size());
  310. AZ_TEST_ASSERT(hTable.bucket_count() >= 100);
  311. hTable.insert(201);
  312. ValidateHash(hTable, hTable1.size() + 1);
  313. array<int, 5> toInsert = {
  314. { 17, 101, 27, 7, 501 }
  315. };
  316. hTable.insert(toInsert.begin(), toInsert.end());
  317. ValidateHash(hTable, hTable1.size() + 1 + toInsert.size());
  318. hTable.erase(hTable.begin());
  319. ValidateHash(hTable, hTable1.size() + toInsert.size());
  320. hTable.erase(hTable.begin(), next(hTable.begin(), (int)hTable1.size()));
  321. ValidateHash(hTable, toInsert.size());
  322. hTable.clear();
  323. ValidateHash(hTable);
  324. hTable.insert(toInsert.begin(), toInsert.end());
  325. hTable.erase(17);
  326. ValidateHash(hTable, toInsert.size() - 1);
  327. hTable.erase(18);
  328. ValidateHash(hTable, toInsert.size() - 1);
  329. hTable.clear();
  330. ValidateHash(hTable);
  331. hTable.insert(toInsert.begin(), toInsert.end());
  332. hash_key_table_type::iterator iter = hTable.find(7);
  333. AZ_TEST_ASSERT(iter != hTable.end());
  334. hash_key_table_type::const_iterator citer = hTable.find(7);
  335. AZ_TEST_ASSERT(citer != hTable.end());
  336. iter = hTable.find(57);
  337. AZ_TEST_ASSERT(iter == hTable.end());
  338. EXPECT_EQ(1, hTable.count(101));
  339. EXPECT_EQ(0, hTable.count(201));
  340. iter = hTable.lower_bound(17);
  341. AZ_TEST_ASSERT(iter != hTable.end());
  342. citer = hTable.lower_bound(17);
  343. AZ_TEST_ASSERT(citer != hTable.end());
  344. iter = hTable.lower_bound(57);
  345. AZ_TEST_ASSERT(iter == hTable.end());
  346. iter = hTable.upper_bound(101);
  347. AZ_TEST_ASSERT(iter != hTable.end());
  348. citer = hTable.upper_bound(101);
  349. AZ_TEST_ASSERT(citer != hTable.end());
  350. iter = hTable.upper_bound(57);
  351. AZ_TEST_ASSERT(iter == hTable.end());
  352. hash_key_table_type::pair_iter_iter rangeIt = hTable.equal_range(17);
  353. AZ_TEST_ASSERT(rangeIt.first != hTable.end());
  354. AZ_TEST_ASSERT(next(rangeIt.first) == rangeIt.second);
  355. hash_key_table_type::pair_citer_citer crangeIt = hTable.equal_range(17);
  356. AZ_TEST_ASSERT(crangeIt.first != hTable.end());
  357. AZ_TEST_ASSERT(next(crangeIt.first) == crangeIt.second);
  358. hTable1.clear();
  359. hTable.swap(hTable1);
  360. ValidateHash(hTable);
  361. ValidateHash(hTable1, toInsert.size());
  362. typedef HashTableSetTestTraits< int, true, false > hash_multiset_traits;
  363. typedef hash_table< hash_multiset_traits > hash_key_multitable_type;
  364. hash_key_multitable_type hMultiTable(set_hasher, hash_set_traits::key_equal(), hash_set_traits::allocator_type());
  365. array<int, 7> toInsert2 = {
  366. { 17, 101, 27, 7, 501, 101, 101 }
  367. };
  368. hMultiTable.insert(toInsert2.begin(), toInsert2.end());
  369. ValidateHash(hMultiTable, toInsert2.size());
  370. EXPECT_EQ(3, hMultiTable.count(101));
  371. AZ_TEST_ASSERT(hMultiTable.lower_bound(101) != prev(hMultiTable.upper_bound(101)));
  372. AZ_TEST_ASSERT(hMultiTable.lower_bound(501) == prev(hMultiTable.upper_bound(501)));
  373. hash_key_multitable_type::pair_iter_iter rangeIt2 = hMultiTable.equal_range(101);
  374. AZ_TEST_ASSERT(rangeIt2.first != rangeIt2.second);
  375. EXPECT_EQ(3, distance(rangeIt2.first, rangeIt2.second));
  376. hash_key_multitable_type::iterator iter2 = rangeIt2.first;
  377. for (; iter2 != rangeIt2.second; ++iter2)
  378. {
  379. EXPECT_EQ(101, *iter2);
  380. }
  381. }
  382. TEST_F(HashedContainers, UnorderedSetTest)
  383. {
  384. typedef unordered_set<int> int_set_type;
  385. int_set_type::hasher myHasher;
  386. int_set_type::key_equal myKeyEqCmp;
  387. int_set_type::allocator_type myAllocator;
  388. int_set_type int_set;
  389. ValidateHash(int_set);
  390. int_set_type int_set1(100);
  391. ValidateHash(int_set1);
  392. AZ_TEST_ASSERT(int_set1.bucket_count() >= 100);
  393. int_set_type int_set2(100, myHasher, myKeyEqCmp);
  394. ValidateHash(int_set2);
  395. AZ_TEST_ASSERT(int_set2.bucket_count() >= 100);
  396. int_set_type int_set3(100, myHasher, myKeyEqCmp, myAllocator);
  397. ValidateHash(int_set3);
  398. AZ_TEST_ASSERT(int_set3.bucket_count() >= 100);
  399. array<int, 5> uniqueArray = {
  400. { 17, 101, 27, 7, 501 }
  401. };
  402. int_set_type int_set4(uniqueArray.begin(), uniqueArray.end());
  403. ValidateHash(int_set4, uniqueArray.size());
  404. int_set_type int_set5(uniqueArray.begin(), uniqueArray.end(), 100);
  405. ValidateHash(int_set5, uniqueArray.size());
  406. AZ_TEST_ASSERT(int_set5.bucket_count() >= 100);
  407. int_set_type int_set6(uniqueArray.begin(), uniqueArray.end(), 100, myHasher, myKeyEqCmp);
  408. ValidateHash(int_set6, uniqueArray.size());
  409. AZ_TEST_ASSERT(int_set6.bucket_count() >= 100);
  410. int_set_type int_set7(uniqueArray.begin(), uniqueArray.end(), 100, myHasher, myKeyEqCmp, myAllocator);
  411. ValidateHash(int_set7, uniqueArray.size());
  412. AZ_TEST_ASSERT(int_set7.bucket_count() >= 100);
  413. int_set_type int_set8({ 1, 2, 3, 4, 4, 5 });
  414. ValidateHash(int_set8, 5);
  415. EXPECT_EQ(1, int_set8.count(1));
  416. EXPECT_EQ(1, int_set8.count(2));
  417. EXPECT_EQ(1, int_set8.count(3));
  418. EXPECT_EQ(1, int_set8.count(4));
  419. EXPECT_EQ(1, int_set8.count(5));
  420. int_set_type int_set9 = int_set8;
  421. EXPECT_EQ(int_set9, int_set8);
  422. EXPECT_TRUE(int_set1 != int_set9);
  423. int_set_type int_set10;
  424. int_set10.insert({ 1, 2, 3, 4, 4, 5 });
  425. EXPECT_EQ(int_set8, int_set10);
  426. }
  427. TEST_F(HashedContainers, FixedUnorderedSetTest)
  428. {
  429. typedef fixed_unordered_set<int, 101, 300> int_set_type;
  430. int_set_type::hasher myHasher;
  431. int_set_type::key_equal myKeyEqCmp;
  432. int_set_type int_set;
  433. ValidateHash(int_set);
  434. EXPECT_EQ(101, int_set.bucket_count());
  435. int_set_type int_set1(myHasher, myKeyEqCmp);
  436. ValidateHash(int_set1);
  437. EXPECT_EQ(101, int_set1.bucket_count());
  438. array<int, 5> uniqueArray = {
  439. { 17, 101, 27, 7, 501 }
  440. };
  441. int_set_type int_set4(uniqueArray.begin(), uniqueArray.end());
  442. ValidateHash(int_set4, uniqueArray.size());
  443. int_set_type int_set6(uniqueArray.begin(), uniqueArray.end(), 0, myHasher, myKeyEqCmp);
  444. ValidateHash(int_set6, uniqueArray.size());
  445. EXPECT_EQ(101, int_set6.bucket_count());
  446. }
  447. TEST_F(HashedContainers, UnorderedMultiSet)
  448. {
  449. typedef unordered_multiset<int> int_multiset_type;
  450. int_multiset_type::hasher myHasher;
  451. int_multiset_type::key_equal myKeyEqCmp;
  452. int_multiset_type::allocator_type myAllocator;
  453. int_multiset_type int_set;
  454. ValidateHash(int_set);
  455. int_multiset_type int_set1(100);
  456. ValidateHash(int_set1);
  457. AZ_TEST_ASSERT(int_set1.bucket_count() >= 100);
  458. int_multiset_type int_set2(100, myHasher, myKeyEqCmp);
  459. ValidateHash(int_set2);
  460. AZ_TEST_ASSERT(int_set2.bucket_count() >= 100);
  461. int_multiset_type int_set3(100, myHasher, myKeyEqCmp, myAllocator);
  462. ValidateHash(int_set3);
  463. AZ_TEST_ASSERT(int_set3.bucket_count() >= 100);
  464. array<int, 7> uniqueArray = {
  465. { 17, 101, 27, 7, 501, 101, 101 }
  466. };
  467. int_multiset_type int_set4(uniqueArray.begin(), uniqueArray.end());
  468. ValidateHash(int_set4, uniqueArray.size());
  469. int_multiset_type int_set5(uniqueArray.begin(), uniqueArray.end(), 100);
  470. ValidateHash(int_set5, uniqueArray.size());
  471. AZ_TEST_ASSERT(int_set5.bucket_count() >= 100);
  472. int_multiset_type int_set6(uniqueArray.begin(), uniqueArray.end(), 100, myHasher, myKeyEqCmp);
  473. ValidateHash(int_set6, uniqueArray.size());
  474. AZ_TEST_ASSERT(int_set6.bucket_count() >= 100);
  475. int_multiset_type int_set7(uniqueArray.begin(), uniqueArray.end(), 100, myHasher, myKeyEqCmp, myAllocator);
  476. ValidateHash(int_set7, uniqueArray.size());
  477. AZ_TEST_ASSERT(int_set7.bucket_count() >= 100);
  478. int_multiset_type int_set8({ 1, 2, 3, 4, 4, 5 });
  479. ValidateHash(int_set8, 6);
  480. EXPECT_EQ(1, int_set8.count(1));
  481. EXPECT_EQ(1, int_set8.count(2));
  482. EXPECT_EQ(1, int_set8.count(3));
  483. EXPECT_EQ(2, int_set8.count(4));
  484. EXPECT_EQ(1, int_set8.count(5));
  485. int_multiset_type int_set9 = int_set8;
  486. AZ_TEST_ASSERT(int_set8 == int_set9);
  487. AZ_TEST_ASSERT(int_set1 != int_set9);
  488. int_multiset_type int_set10;
  489. int_set10.insert({ 1, 2, 3, 4, 4, 5 });
  490. EXPECT_EQ(int_set8, int_set10);
  491. }
  492. TEST_F(HashedContainers, FixedUnorderedMultiSet)
  493. {
  494. typedef fixed_unordered_multiset<int, 101, 300> int_multiset_type;
  495. int_multiset_type::hasher myHasher;
  496. int_multiset_type::key_equal myKeyEqCmp;
  497. int_multiset_type int_set;
  498. ValidateHash(int_set);
  499. EXPECT_EQ(101, int_set.bucket_count());
  500. int_multiset_type int_set2(myHasher, myKeyEqCmp);
  501. ValidateHash(int_set2);
  502. EXPECT_EQ(101, int_set2.bucket_count());
  503. array<int, 7> uniqueArray = {
  504. { 17, 101, 27, 7, 501, 101, 101 }
  505. };
  506. int_multiset_type int_set4(uniqueArray.begin(), uniqueArray.end());
  507. ValidateHash(int_set4, uniqueArray.size());
  508. EXPECT_EQ(101, int_set4.bucket_count());
  509. int_multiset_type int_set6(uniqueArray.begin(), uniqueArray.end(), 0, myHasher, myKeyEqCmp);
  510. ValidateHash(int_set6, uniqueArray.size());
  511. EXPECT_EQ(101, int_set6.bucket_count());
  512. }
  513. TEST_F(HashedContainers, UnorderedMapBasic)
  514. {
  515. typedef unordered_map<int, int> int_int_map_type;
  516. int_int_map_type::hasher myHasher;
  517. int_int_map_type::key_equal myKeyEqCmp;
  518. int_int_map_type::allocator_type myAllocator;
  519. int_int_map_type intint_map;
  520. ValidateHash(intint_map);
  521. int_int_map_type intint_map1(100);
  522. ValidateHash(intint_map1);
  523. AZ_TEST_ASSERT(intint_map1.bucket_count() >= 100);
  524. int_int_map_type intint_map2(100, myHasher, myKeyEqCmp);
  525. ValidateHash(intint_map2);
  526. AZ_TEST_ASSERT(intint_map2.bucket_count() >= 100);
  527. int_int_map_type intint_map3(100, myHasher, myKeyEqCmp, myAllocator);
  528. ValidateHash(intint_map3);
  529. AZ_TEST_ASSERT(intint_map3.bucket_count() >= 100);
  530. // insert with default value.
  531. intint_map.insert_key(16);
  532. ValidateHash(intint_map, 1);
  533. EXPECT_EQ(16, intint_map.begin()->first);
  534. intint_map.insert(AZStd::make_pair(22, 11));
  535. ValidateHash(intint_map, 2);
  536. // map look up
  537. int& mappedValue = intint_map[22];
  538. EXPECT_EQ(11, mappedValue);
  539. int& mappedValueNew = intint_map[33]; // insert a new element
  540. mappedValueNew = 100;
  541. EXPECT_EQ(100, mappedValueNew);
  542. EXPECT_EQ(100, intint_map.at(33));
  543. array<int_int_map_type::value_type, 5> uniqueArray;
  544. uniqueArray[0] = int_int_map_type::value_type(17, 1);
  545. uniqueArray[1] = int_int_map_type::value_type(101, 2);
  546. uniqueArray[2] = int_int_map_type::value_type(27, 3);
  547. uniqueArray[3] = int_int_map_type::value_type(7, 4);
  548. uniqueArray[4] = int_int_map_type::value_type(501, 5);
  549. int_int_map_type intint_map4(uniqueArray.begin(), uniqueArray.end());
  550. ValidateHash(intint_map4, uniqueArray.size());
  551. int_int_map_type intint_map5(uniqueArray.begin(), uniqueArray.end(), 100);
  552. ValidateHash(intint_map5, uniqueArray.size());
  553. AZ_TEST_ASSERT(intint_map5.bucket_count() >= 100);
  554. int_int_map_type intint_map6(uniqueArray.begin(), uniqueArray.end(), 100, myHasher, myKeyEqCmp);
  555. ValidateHash(intint_map6, uniqueArray.size());
  556. AZ_TEST_ASSERT(intint_map6.bucket_count() >= 100);
  557. int_int_map_type intint_map7(uniqueArray.begin(), uniqueArray.end(), 100, myHasher, myKeyEqCmp, myAllocator);
  558. ValidateHash(intint_map7, uniqueArray.size());
  559. AZ_TEST_ASSERT(intint_map7.bucket_count() >= 100);
  560. int_int_map_type intint_map8({
  561. { 1, 10 },{ 2, 200 },{ 3, 3000 },{ 4, 40000 },{ 4, 40001 },{ 5, 500000 }
  562. });
  563. ValidateHash(intint_map8, 5);
  564. EXPECT_EQ(10, intint_map8[1]);
  565. EXPECT_EQ(200, intint_map8[2]);
  566. EXPECT_EQ(3000, intint_map8[3]);
  567. EXPECT_EQ(40000, intint_map8[4]);
  568. EXPECT_EQ(500000, intint_map8[5]);
  569. EXPECT_EQ(1, intint_map8.find(1)->first);
  570. EXPECT_EQ(2, intint_map8.find(2)->first);
  571. EXPECT_EQ(3, intint_map8.find(3)->first);
  572. EXPECT_EQ(4, intint_map8.find(4)->first);
  573. EXPECT_EQ(5, intint_map8.find(5)->first);
  574. EXPECT_EQ(10, intint_map8.find(1)->second);
  575. EXPECT_EQ(200, intint_map8.find(2)->second);
  576. EXPECT_EQ(3000, intint_map8.find(3)->second);
  577. EXPECT_EQ(40000, intint_map8.find(4)->second);
  578. EXPECT_EQ(500000, intint_map8.find(5)->second);
  579. int_int_map_type intint_map9;
  580. intint_map9.insert({ { 1, 10 }, { 2, 200 }, { 3, 3000 }, { 4, 40000 }, { 4, 40001 }, { 5, 500000 } });
  581. EXPECT_EQ(intint_map8, intint_map9);
  582. }
  583. TEST_F(HashedContainers, UnorderedMapNoncopyableValue)
  584. {
  585. using nocopy_map = unordered_map<int, MyNoCopyClass>;
  586. nocopy_map ptr_map;
  587. nocopy_map::value_type test_pair;
  588. test_pair.second.m_bool = true;
  589. ptr_map.insert(AZStd::move(test_pair));
  590. for (const auto& pair : ptr_map)
  591. {
  592. AZ_TEST_ASSERT(pair.second.m_bool);
  593. }
  594. }
  595. TEST_F(HashedContainers, UnorderedMapNonTrivialValue)
  596. {
  597. typedef unordered_map<int, MyClass> int_myclass_map_type;
  598. int_myclass_map_type::hasher myHasher;
  599. int_myclass_map_type::key_equal myKeyEqCmp;
  600. int_myclass_map_type::allocator_type myAllocator;
  601. int_myclass_map_type intclass_map;
  602. ValidateHash(intclass_map);
  603. int_myclass_map_type intclass_map1(100);
  604. ValidateHash(intclass_map1);
  605. AZ_TEST_ASSERT(intclass_map1.bucket_count() >= 100);
  606. int_myclass_map_type intclass_map2(100, myHasher, myKeyEqCmp);
  607. ValidateHash(intclass_map2);
  608. AZ_TEST_ASSERT(intclass_map2.bucket_count() >= 100);
  609. int_myclass_map_type intclass_map3(100, myHasher, myKeyEqCmp, myAllocator);
  610. ValidateHash(intclass_map3);
  611. AZ_TEST_ASSERT(intclass_map3.bucket_count() >= 100);
  612. // insert with default value.
  613. intclass_map.insert_key(16);
  614. ValidateHash(intclass_map, 1);
  615. intclass_map.insert(AZStd::make_pair(22, MyClass(11)));
  616. ValidateHash(intclass_map, 2);
  617. // Emplace
  618. auto result = intclass_map.emplace(33, MyClass(37));
  619. AZ_TEST_ASSERT(result.second);
  620. EXPECT_EQ(37, result.first->second.m_data);
  621. ValidateHash(intclass_map, 3);
  622. // map look up
  623. MyClass& mappedValue = intclass_map[22];
  624. EXPECT_EQ(11, mappedValue.m_data);
  625. MyClass& mappedValueNew = intclass_map[33]; // insert a new element
  626. mappedValueNew.m_data = 100;
  627. EXPECT_EQ(100, mappedValueNew.m_data);
  628. EXPECT_EQ(100, intclass_map.at(33).m_data);
  629. array<int_myclass_map_type::value_type, 5> uniqueArray;
  630. uniqueArray[0] = AZStd::make_pair(17, MyClass(1));
  631. uniqueArray[1] = AZStd::make_pair(101, MyClass(2));
  632. uniqueArray[2] = AZStd::make_pair(27, MyClass(3));
  633. uniqueArray[3] = int_myclass_map_type::value_type(7, MyClass(4));
  634. uniqueArray[4] = int_myclass_map_type::value_type(501, MyClass(5));
  635. int_myclass_map_type intclass_map4(uniqueArray.begin(), uniqueArray.end());
  636. ValidateHash(intclass_map4, uniqueArray.size());
  637. int_myclass_map_type intclass_map5(uniqueArray.begin(), uniqueArray.end(), 100);
  638. ValidateHash(intclass_map5, uniqueArray.size());
  639. AZ_TEST_ASSERT(intclass_map5.bucket_count() >= 100);
  640. int_myclass_map_type intclass_map6(uniqueArray.begin(), uniqueArray.end(), 100, myHasher, myKeyEqCmp);
  641. ValidateHash(intclass_map6, uniqueArray.size());
  642. AZ_TEST_ASSERT(intclass_map6.bucket_count() >= 100);
  643. int_myclass_map_type intclass_map7(uniqueArray.begin(), uniqueArray.end(), 100, myHasher, myKeyEqCmp, myAllocator);
  644. ValidateHash(intclass_map7, uniqueArray.size());
  645. AZ_TEST_ASSERT(intclass_map7.bucket_count() >= 100);
  646. int_myclass_map_type intclass_map8({
  647. { 1, MyClass(10) },{ 2, MyClass(200) },{ 3, MyClass(3000) },{ 4, MyClass(40000) },{ 4, MyClass(40001) },{ 5, MyClass(500000) }
  648. });
  649. ValidateHash(intclass_map8, 5);
  650. AZ_TEST_ASSERT(intclass_map8[1] == MyClass(10));
  651. AZ_TEST_ASSERT(intclass_map8[2] == MyClass(200));
  652. AZ_TEST_ASSERT(intclass_map8[3] == MyClass(3000));
  653. AZ_TEST_ASSERT(intclass_map8[4] == MyClass(40000));
  654. AZ_TEST_ASSERT(intclass_map8[5] == MyClass(500000));
  655. EXPECT_EQ(1, intclass_map8.find(1)->first);
  656. EXPECT_EQ(2, intclass_map8.find(2)->first);
  657. EXPECT_EQ(3, intclass_map8.find(3)->first);
  658. EXPECT_EQ(4, intclass_map8.find(4)->first);
  659. EXPECT_EQ(5, intclass_map8.find(5)->first);
  660. AZ_TEST_ASSERT(intclass_map8.find(1)->second == MyClass(10));
  661. AZ_TEST_ASSERT(intclass_map8.find(2)->second == MyClass(200));
  662. AZ_TEST_ASSERT(intclass_map8.find(3)->second == MyClass(3000));
  663. AZ_TEST_ASSERT(intclass_map8.find(4)->second == MyClass(40000));
  664. AZ_TEST_ASSERT(intclass_map8.find(5)->second == MyClass(500000));
  665. int_myclass_map_type intclass_map9;
  666. intclass_map9.insert({ { 1, MyClass(10) },{ 2, MyClass(200) },{ 3, MyClass(3000) },{ 4, MyClass(40000) },{ 4, MyClass(40001) },{ 5, MyClass(500000) } });
  667. EXPECT_EQ(intclass_map8, intclass_map9);
  668. }
  669. TEST_F(HashedContainers, UnorderedMapNonTrivialKey)
  670. {
  671. typedef unordered_map<AZStd::string, MyClass> string_myclass_map_type;
  672. string_myclass_map_type stringclass_map;
  673. ValidateHash(stringclass_map);
  674. // insert with default value.
  675. stringclass_map.insert_key("Hello");
  676. ValidateHash(stringclass_map, 1);
  677. stringclass_map.insert(AZStd::make_pair("World", MyClass(11)));
  678. ValidateHash(stringclass_map, 2);
  679. // Emplace
  680. auto result = stringclass_map.emplace("Goodbye", MyClass(37));
  681. AZ_TEST_ASSERT(result.second);
  682. EXPECT_EQ(37, result.first->second.m_data);
  683. ValidateHash(stringclass_map, 3);
  684. // map look up
  685. MyClass& mappedValue = stringclass_map["World"];
  686. EXPECT_EQ(11, mappedValue.m_data);
  687. MyClass& mappedValueNew = stringclass_map["Goodbye"]; // insert a new element
  688. mappedValueNew.m_data = 100;
  689. EXPECT_EQ(100, mappedValueNew.m_data);
  690. EXPECT_EQ(100, stringclass_map.at("Goodbye").m_data);
  691. }
  692. TEST_F(HashedContainers, FixedUnorderedMapBasic)
  693. {
  694. typedef fixed_unordered_map<int, int, 101, 300> int_int_map_type;
  695. int_int_map_type::hasher myHasher;
  696. int_int_map_type::key_equal myKeyEqCmp;
  697. int_int_map_type intint_map;
  698. ValidateHash(intint_map);
  699. EXPECT_EQ(101, intint_map.bucket_count());
  700. int_int_map_type intint_map2(myHasher, myKeyEqCmp);
  701. ValidateHash(intint_map2);
  702. EXPECT_EQ(101, intint_map2.bucket_count());
  703. // insert with default value.
  704. intint_map.insert_key(16);
  705. ValidateHash(intint_map, 1);
  706. EXPECT_EQ(16, intint_map.begin()->first);
  707. intint_map.insert(AZStd::make_pair(22, 11));
  708. ValidateHash(intint_map, 2);
  709. // map look up
  710. int& mappedValue = intint_map[22];
  711. EXPECT_EQ(11, mappedValue);
  712. int& mappedValueNew = intint_map[33]; // insert a new element
  713. mappedValueNew = 100;
  714. EXPECT_EQ(100, mappedValueNew);
  715. EXPECT_EQ(100, intint_map.at(33));
  716. array<int_int_map_type::value_type, 5> uniqueArray;
  717. uniqueArray[0] = int_int_map_type::value_type(17, 1);
  718. uniqueArray[1] = int_int_map_type::value_type(101, 2);
  719. uniqueArray[2] = int_int_map_type::value_type(27, 3);
  720. uniqueArray[3] = int_int_map_type::value_type(7, 4);
  721. uniqueArray[4] = int_int_map_type::value_type(501, 5);
  722. int_int_map_type intint_map4(uniqueArray.begin(), uniqueArray.end());
  723. ValidateHash(intint_map4, uniqueArray.size());
  724. EXPECT_EQ(101, intint_map4.bucket_count());
  725. int_int_map_type intint_map6(uniqueArray.begin(), uniqueArray.end(), 0, myHasher, myKeyEqCmp);
  726. ValidateHash(intint_map6, uniqueArray.size());
  727. EXPECT_EQ(101, intint_map6.bucket_count());
  728. }
  729. TEST_F(HashedContainers, FixedUnorderedMapNonTrivialValue)
  730. {
  731. typedef fixed_unordered_map<int, MyClass, 101, 300> int_myclass_map_type;
  732. int_myclass_map_type::hasher myHasher;
  733. int_myclass_map_type::key_equal myKeyEqCmp;
  734. int_myclass_map_type intclass_map;
  735. ValidateHash(intclass_map);
  736. EXPECT_EQ(101, intclass_map.bucket_count());
  737. int_myclass_map_type intclass_map2(myHasher, myKeyEqCmp);
  738. ValidateHash(intclass_map2);
  739. EXPECT_EQ(101, intclass_map2.bucket_count());
  740. // insert with default value.
  741. intclass_map.insert_key(16);
  742. ValidateHash(intclass_map, 1);
  743. intclass_map.insert(AZStd::make_pair(22, MyClass(11)));
  744. ValidateHash(intclass_map, 2);
  745. // map look up
  746. MyClass& mappedValue = intclass_map[22];
  747. EXPECT_EQ(11, mappedValue.m_data);
  748. MyClass& mappedValueNew = intclass_map[33]; // insert a new element
  749. mappedValueNew.m_data = 100;
  750. EXPECT_EQ(100, mappedValueNew.m_data);
  751. EXPECT_EQ(100, intclass_map.at(33).m_data);
  752. array<int_myclass_map_type::value_type, 5> uniqueArray;
  753. uniqueArray[0] = AZStd::make_pair(17, MyClass(1));
  754. uniqueArray[1] = AZStd::make_pair(101, MyClass(2));
  755. uniqueArray[2] = AZStd::make_pair(27, MyClass(3));
  756. uniqueArray[3] = int_myclass_map_type::value_type(7, MyClass(4));
  757. uniqueArray[4] = int_myclass_map_type::value_type(501, MyClass(5));
  758. int_myclass_map_type intclass_map4(uniqueArray.begin(), uniqueArray.end());
  759. ValidateHash(intclass_map4, uniqueArray.size());
  760. EXPECT_EQ(101, intclass_map4.bucket_count());
  761. int_myclass_map_type intclass_map6(uniqueArray.begin(), uniqueArray.end(), 0, myHasher, myKeyEqCmp);
  762. ValidateHash(intclass_map6, uniqueArray.size());
  763. EXPECT_EQ(101, intclass_map6.bucket_count());
  764. }
  765. TEST_F(HashedContainers, UnorderedMultiMapBasic)
  766. {
  767. typedef unordered_multimap<int, int> int_int_multimap_type;
  768. int_int_multimap_type::hasher myHasher;
  769. int_int_multimap_type::key_equal myKeyEqCmp;
  770. int_int_multimap_type::allocator_type myAllocator;
  771. int_int_multimap_type intint_map;
  772. ValidateHash(intint_map);
  773. int_int_multimap_type intint_map1(100);
  774. ValidateHash(intint_map1);
  775. AZ_TEST_ASSERT(intint_map1.bucket_count() >= 100);
  776. int_int_multimap_type intint_map2(100, myHasher, myKeyEqCmp);
  777. ValidateHash(intint_map2);
  778. AZ_TEST_ASSERT(intint_map2.bucket_count() >= 100);
  779. int_int_multimap_type intint_map3(100, myHasher, myKeyEqCmp, myAllocator);
  780. ValidateHash(intint_map3);
  781. AZ_TEST_ASSERT(intint_map3.bucket_count() >= 100);
  782. // insert with default value.
  783. intint_map.insert_key(16);
  784. intint_map.insert_key(16);
  785. ValidateHash(intint_map, 2);
  786. intint_map.insert(AZStd::make_pair(16, 44));
  787. intint_map.insert(AZStd::make_pair(16, 55));
  788. ValidateHash(intint_map, 4);
  789. array<int_int_multimap_type::value_type, 7> multiArray;
  790. multiArray[0] = int_int_multimap_type::value_type(17, 1);
  791. multiArray[1] = int_int_multimap_type::value_type(0, 2);
  792. multiArray[2] = int_int_multimap_type::value_type(27, 3);
  793. multiArray[3] = int_int_multimap_type::value_type(7, 4);
  794. multiArray[4] = int_int_multimap_type::value_type(501, 5);
  795. multiArray[5] = int_int_multimap_type::value_type(0, 6);
  796. multiArray[6] = int_int_multimap_type::value_type(0, 7);
  797. int_int_multimap_type intint_map4(multiArray.begin(), multiArray.end());
  798. ValidateHash(intint_map4, multiArray.size());
  799. int_int_multimap_type intint_map5(multiArray.begin(), multiArray.end(), 100);
  800. ValidateHash(intint_map5, multiArray.size());
  801. AZ_TEST_ASSERT(intint_map5.bucket_count() >= 100);
  802. int_int_multimap_type intint_map6(multiArray.begin(), multiArray.end(), 100, myHasher, myKeyEqCmp);
  803. ValidateHash(intint_map6, multiArray.size());
  804. AZ_TEST_ASSERT(intint_map6.bucket_count() >= 100);
  805. int_int_multimap_type intint_map7(multiArray.begin(), multiArray.end(), 100, myHasher, myKeyEqCmp, myAllocator);
  806. ValidateHash(intint_map7, multiArray.size());
  807. AZ_TEST_ASSERT(intint_map7.bucket_count() >= 100);
  808. int_int_multimap_type intint_map8({
  809. { 1, 10 },{ 2, 200 },{ 3, 3000 },{ 4, 40000 },{ 4, 40001 },{ 5, 500000 }
  810. });
  811. ValidateHash(intint_map8, 6);
  812. EXPECT_EQ(1, intint_map8.count(1));
  813. EXPECT_EQ(1, intint_map8.count(2));
  814. EXPECT_EQ(1, intint_map8.count(3));
  815. EXPECT_EQ(2, intint_map8.count(4));
  816. EXPECT_EQ(1, intint_map8.count(5));
  817. EXPECT_EQ(10, intint_map8.lower_bound(1)->second);
  818. EXPECT_EQ(200, intint_map8.lower_bound(2)->second);
  819. EXPECT_EQ(3000, intint_map8.lower_bound(3)->second);
  820. AZ_TEST_ASSERT(intint_map8.lower_bound(4)->second == 40000 || intint_map8.lower_bound(4)->second == 40001);
  821. AZ_TEST_ASSERT((++intint_map8.lower_bound(4))->second == 40000 || (++intint_map8.lower_bound(4))->second == 40001);
  822. AZ_TEST_ASSERT(intint_map8.lower_bound(5)->second == 500000);
  823. int_int_multimap_type intint_map9;
  824. intint_map9.insert({ { 1, 10 },{ 2, 200 },{ 3, 3000 },{ 4, 40000 },{ 4, 40001 },{ 5, 500000 } });
  825. EXPECT_EQ(intint_map8, intint_map9);
  826. }
  827. TEST_F(HashedContainers, FixedUnorderedMultiMapBasic)
  828. {
  829. typedef fixed_unordered_multimap<int, int, 101, 300> int_int_multimap_type;
  830. int_int_multimap_type::hasher myHasher;
  831. int_int_multimap_type::key_equal myKeyEqCmp;
  832. int_int_multimap_type intint_map;
  833. ValidateHash(intint_map);
  834. EXPECT_EQ(101, intint_map.bucket_count());
  835. int_int_multimap_type intint_map2(myHasher, myKeyEqCmp);
  836. ValidateHash(intint_map2);
  837. EXPECT_EQ(101, intint_map2.bucket_count());
  838. // insert with default value.
  839. intint_map.insert_key(16);
  840. intint_map.insert_key(16);
  841. ValidateHash(intint_map, 2);
  842. intint_map.insert(AZStd::make_pair(16, 44));
  843. intint_map.insert(AZStd::make_pair(16, 55));
  844. ValidateHash(intint_map, 4);
  845. array<int_int_multimap_type::value_type, 7> multiArray;
  846. multiArray[0] = int_int_multimap_type::value_type(17, 1);
  847. multiArray[1] = int_int_multimap_type::value_type(0, 2);
  848. multiArray[2] = int_int_multimap_type::value_type(27, 3);
  849. multiArray[3] = int_int_multimap_type::value_type(7, 4);
  850. multiArray[4] = int_int_multimap_type::value_type(501, 5);
  851. multiArray[5] = int_int_multimap_type::value_type(0, 6);
  852. multiArray[6] = int_int_multimap_type::value_type(0, 7);
  853. int_int_multimap_type intint_map4(multiArray.begin(), multiArray.end());
  854. ValidateHash(intint_map4, multiArray.size());
  855. EXPECT_EQ(101, intint_map4.bucket_count());
  856. int_int_multimap_type intint_map6(multiArray.begin(), multiArray.end(), 0, myHasher, myKeyEqCmp);
  857. ValidateHash(intint_map6, multiArray.size());
  858. EXPECT_EQ(101, intint_map6.bucket_count());
  859. }
  860. struct MoveOnlyType
  861. {
  862. MoveOnlyType() = default;
  863. MoveOnlyType(const AZStd::string name)
  864. : m_name(name)
  865. {}
  866. MoveOnlyType(const MoveOnlyType&) = delete;
  867. MoveOnlyType(MoveOnlyType&& other)
  868. : m_name(AZStd::move(other.m_name))
  869. {
  870. }
  871. MoveOnlyType& operator=(const MoveOnlyType&) = delete;
  872. MoveOnlyType& operator=(MoveOnlyType&& other)
  873. {
  874. m_name = AZStd::move(other.m_name);
  875. return *this;
  876. }
  877. bool operator==(const MoveOnlyType& other) const
  878. {
  879. return m_name == other.m_name;
  880. }
  881. AZStd::string m_name;
  882. };
  883. struct MoveOnlyTypeHasher
  884. {
  885. size_t operator()(const MoveOnlyType& moveOnlyType) const
  886. {
  887. return AZStd::hash<AZStd::string>()(moveOnlyType.m_name);
  888. }
  889. };
  890. TEST_F(HashedContainers, UnorderedSetMoveOnlyKeyTest)
  891. {
  892. AZStd::unordered_set<MoveOnlyType, MoveOnlyTypeHasher> ownedStringSet;
  893. AZStd::string nonOwnedString1("Test String");
  894. ownedStringSet.emplace(nonOwnedString1);
  895. auto keyEqual = [](const AZStd::string& testString, const MoveOnlyType& key)
  896. {
  897. return testString == key.m_name;
  898. };
  899. auto entityIt = ownedStringSet.find_as(nonOwnedString1, AZStd::hash<AZStd::string>(), keyEqual);
  900. EXPECT_NE(ownedStringSet.end(), entityIt);
  901. EXPECT_EQ(nonOwnedString1, entityIt->m_name);
  902. AZStd::string nonOwnedString2("Hashed Value");
  903. entityIt = ownedStringSet.find_as(nonOwnedString2, AZStd::hash<AZStd::string>(), keyEqual);
  904. EXPECT_EQ(ownedStringSet.end(), entityIt);
  905. }
  906. TEST_F(HashedContainers, UnorderedSetEquals)
  907. {
  908. AZStd::unordered_set<AZStd::string> aset1 = { "PlayerBase", "DamageableBase", "PlacementObstructionBase", "PredatorBase" };
  909. AZStd::unordered_set<AZStd::string> aset2;
  910. aset2.insert("PredatorBase");
  911. aset2.insert("PlayerBase");
  912. aset2.insert("PlacementObstructionBase");
  913. aset2.insert("DamageableBase");
  914. EXPECT_EQ(aset1, aset2);
  915. }
  916. TEST_F(HashedContainers, UnorderedMapIterateEmpty)
  917. {
  918. AZStd::unordered_map<int, MoveOnlyType> map;
  919. for (auto& item : map)
  920. {
  921. AZ_UNUSED(item);
  922. EXPECT_TRUE(false) << "Iteration should never have occurred on an empty unordered_map";
  923. }
  924. }
  925. TEST_F(HashedContainers, UnorderedMapIterateItems)
  926. {
  927. AZStd::unordered_map<int, int> map{
  928. {1, 2},
  929. {3, 4},
  930. {5, 6},
  931. {7, 8}
  932. };
  933. unsigned idx = 0;
  934. for (auto& item : map)
  935. {
  936. EXPECT_EQ(item.second, item.first + 1);
  937. ++idx;
  938. }
  939. EXPECT_EQ(idx, map.size());
  940. }
  941. template<typename ContainerType>
  942. class HashedSetContainers
  943. : public LeakDetectionFixture
  944. {
  945. };
  946. struct MoveOnlyIntType
  947. {
  948. MoveOnlyIntType() = default;
  949. MoveOnlyIntType(int32_t value)
  950. : m_value(value)
  951. {}
  952. MoveOnlyIntType(const MoveOnlyIntType&) = delete;
  953. MoveOnlyIntType& operator=(const MoveOnlyIntType&) = delete;
  954. MoveOnlyIntType(MoveOnlyIntType&& other)
  955. : m_value(other.m_value)
  956. {
  957. }
  958. MoveOnlyIntType& operator=(MoveOnlyIntType&& other)
  959. {
  960. m_value = other.m_value;
  961. other.m_value = {};
  962. return *this;
  963. }
  964. explicit operator int32_t()
  965. {
  966. return m_value;
  967. }
  968. bool operator==(const MoveOnlyIntType& other) const
  969. {
  970. return m_value == other.m_value;
  971. }
  972. int32_t m_value;
  973. };
  974. struct MoveOnlyIntTypeHasher
  975. {
  976. size_t operator()(const MoveOnlyIntType& moveOnlyType) const
  977. {
  978. return AZStd::hash<int32_t>()(moveOnlyType.m_value);
  979. }
  980. };
  981. template<typename ContainerType>
  982. struct HashedSetConfig
  983. {
  984. using SetType = ContainerType;
  985. static SetType Create()
  986. {
  987. SetType testSet;
  988. testSet.emplace(1);
  989. testSet.emplace(2);
  990. testSet.emplace(84075);
  991. testSet.emplace(-73);
  992. testSet.emplace(534);
  993. testSet.emplace(-845920);
  994. testSet.emplace(-42);
  995. testSet.emplace(0b1111'0000);
  996. return testSet;
  997. }
  998. };
  999. using SetContainerConfigs = ::testing::Types<
  1000. HashedSetConfig<AZStd::unordered_set<int32_t>>
  1001. , HashedSetConfig<AZStd::unordered_multiset<int32_t>>
  1002. , HashedSetConfig<AZStd::unordered_set<MoveOnlyIntType, MoveOnlyIntTypeHasher>>
  1003. , HashedSetConfig<AZStd::unordered_multiset<MoveOnlyIntType, MoveOnlyIntTypeHasher>>
  1004. >;
  1005. TYPED_TEST_CASE(HashedSetContainers, SetContainerConfigs);
  1006. TYPED_TEST(HashedSetContainers, ExtractNodeHandleByKeySucceeds)
  1007. {
  1008. using SetType = typename TypeParam::SetType;
  1009. using node_type = typename SetType::node_type;
  1010. SetType testContainer = TypeParam::Create();
  1011. node_type extractedNode = testContainer.extract(84075);
  1012. EXPECT_EQ(7, testContainer.size());
  1013. EXPECT_FALSE(extractedNode.empty());
  1014. EXPECT_EQ(84075, static_cast<int32_t>(extractedNode.value()));
  1015. }
  1016. TYPED_TEST(HashedSetContainers, ExtractNodeHandleByKeyFails)
  1017. {
  1018. using SetType = typename TypeParam::SetType;
  1019. using node_type = typename SetType::node_type;
  1020. SetType testContainer = TypeParam::Create();
  1021. node_type extractedNode = testContainer.extract(10000001);
  1022. EXPECT_EQ(8, testContainer.size());
  1023. EXPECT_TRUE(extractedNode.empty());
  1024. }
  1025. TYPED_TEST(HashedSetContainers, ExtractNodeHandleByIteratorSucceeds)
  1026. {
  1027. using SetType = typename TypeParam::SetType;
  1028. using node_type = typename SetType::node_type;
  1029. SetType testContainer = TypeParam::Create();
  1030. auto foundIter = testContainer.find(-73);
  1031. node_type extractedNode = testContainer.extract(foundIter);
  1032. EXPECT_EQ(7, testContainer.size());
  1033. EXPECT_FALSE(extractedNode.empty());
  1034. EXPECT_EQ(-73, static_cast<int32_t>(extractedNode.value()));
  1035. }
  1036. TYPED_TEST(HashedSetContainers, InsertNodeHandleSucceeds)
  1037. {
  1038. using SetType = typename TypeParam::SetType;
  1039. using node_type = typename SetType::node_type;
  1040. SetType testContainer = TypeParam::Create();
  1041. node_type extractedNode = testContainer.extract(84075);
  1042. EXPECT_EQ(7, testContainer.size());
  1043. EXPECT_FALSE(extractedNode.empty());
  1044. EXPECT_EQ(84075, static_cast<int32_t>(extractedNode.value()));
  1045. extractedNode.value() = 0;
  1046. testContainer.insert(AZStd::move(extractedNode));
  1047. EXPECT_NE(0, testContainer.count(0));
  1048. EXPECT_EQ(8, testContainer.size());
  1049. }
  1050. TEST_F(HashedContainers, UnorderedSetInsertNodeHandleSucceeds)
  1051. {
  1052. using SetType = AZStd::unordered_set<int32_t>;
  1053. using node_type = typename SetType::node_type;
  1054. using insert_return_type = typename SetType::insert_return_type;
  1055. SetType testContainer = HashedSetConfig<SetType>::Create();
  1056. node_type extractedNode = testContainer.extract(84075);
  1057. EXPECT_EQ(7, testContainer.size());
  1058. EXPECT_FALSE(extractedNode.empty());
  1059. EXPECT_EQ(84075, static_cast<int32_t>(extractedNode.value()));
  1060. extractedNode.value() = -60;
  1061. insert_return_type insertResult = testContainer.insert(AZStd::move(extractedNode));
  1062. EXPECT_NE(testContainer.end(), insertResult.position);
  1063. EXPECT_TRUE(insertResult.inserted);
  1064. EXPECT_TRUE(insertResult.node.empty());
  1065. EXPECT_NE(0, testContainer.count(-60));
  1066. EXPECT_EQ(8, testContainer.size());
  1067. }
  1068. TEST_F(HashedContainers, UnorderedSetInsertNodeHandleWithEmptyNodeHandleFails)
  1069. {
  1070. using SetType = AZStd::unordered_set<int32_t>;
  1071. using node_type = typename SetType::node_type;
  1072. using insert_return_type = typename SetType::insert_return_type;
  1073. SetType testContainer = HashedSetConfig<SetType>::Create();
  1074. node_type extractedNode;
  1075. EXPECT_TRUE(extractedNode.empty());
  1076. insert_return_type insertResult = testContainer.insert(AZStd::move(extractedNode));
  1077. EXPECT_EQ(testContainer.end(), insertResult.position);
  1078. EXPECT_FALSE(insertResult.inserted);
  1079. EXPECT_TRUE(insertResult.node.empty());
  1080. EXPECT_EQ(8, testContainer.size());
  1081. }
  1082. TEST_F(HashedContainers, UnorderedSetInsertNodeHandleWithDuplicateValueInNodeHandleFails)
  1083. {
  1084. using SetType = AZStd::unordered_set<int32_t>;
  1085. using node_type = typename SetType::node_type;
  1086. using insert_return_type = typename SetType::insert_return_type;
  1087. SetType testContainer = HashedSetConfig<SetType>::Create();
  1088. node_type extractedNode = testContainer.extract(2);
  1089. EXPECT_EQ(7, testContainer.size());
  1090. EXPECT_FALSE(extractedNode.empty());
  1091. EXPECT_EQ(2, static_cast<int32_t>(extractedNode.value()));
  1092. // Set node handle value to a key that is currently within the container
  1093. extractedNode.value() = 534;
  1094. insert_return_type insertResult = testContainer.insert(AZStd::move(extractedNode));
  1095. EXPECT_NE(testContainer.end(), insertResult.position);
  1096. EXPECT_FALSE(insertResult.inserted);
  1097. EXPECT_FALSE(insertResult.node.empty());
  1098. EXPECT_EQ(7, testContainer.size());
  1099. }
  1100. TEST_F(HashedContainers, UnorderedSetExtractedNodeCanBeInsertedIntoUnorderedMultiset)
  1101. {
  1102. using SetType = AZStd::unordered_set<int32_t>;
  1103. using MultisetType = AZStd::unordered_multiset<int32_t>;
  1104. SetType uniqueSet{ 1, 2, 3 };
  1105. MultisetType multiSet{ 1, 4, 1 };
  1106. auto extractedNode = uniqueSet.extract(1);
  1107. EXPECT_EQ(2, uniqueSet.size());
  1108. EXPECT_FALSE(extractedNode.empty());
  1109. auto insertIt = multiSet.insert(AZStd::move(extractedNode));
  1110. EXPECT_NE(multiSet.end(), insertIt);
  1111. EXPECT_EQ(4, multiSet.size());
  1112. EXPECT_EQ(3, multiSet.count(1));
  1113. }
  1114. TEST_F(HashedContainers, UnorderedMultisetExtractedNodeCanBeInsertedIntoUnorderedSet)
  1115. {
  1116. using SetType = AZStd::unordered_set<int32_t>;
  1117. using MultisetType = AZStd::unordered_multiset<int32_t>;
  1118. SetType uniqueSet{ 1, 2, 3 };
  1119. MultisetType multiSet{ 1, 4, 1 };
  1120. auto extractedNode = multiSet.extract(4);
  1121. EXPECT_EQ(2, multiSet.size());
  1122. EXPECT_FALSE(extractedNode.empty());
  1123. auto insertResult = uniqueSet.insert(AZStd::move(extractedNode));
  1124. EXPECT_TRUE(insertResult.inserted);
  1125. EXPECT_EQ(4, uniqueSet.size());
  1126. EXPECT_EQ(1, uniqueSet.count(4));
  1127. }
  1128. template <typename ContainerType>
  1129. class HashedSetDifferentAllocatorFixture
  1130. : public LeakDetectionFixture
  1131. {
  1132. };
  1133. template<template <typename, typename, typename, typename> class ContainerTemplate>
  1134. struct HashedSetWithCustomAllocatorConfig
  1135. {
  1136. using ContainerType = ContainerTemplate<int32_t, AZStd::hash<int32_t>, AZStd::equal_to<int32_t>, AZ::AZStdIAllocator>;
  1137. static ContainerType Create(std::initializer_list<typename ContainerType::value_type> intList, AZ::IAllocator* allocatorInstance)
  1138. {
  1139. ContainerType allocatorSet(intList, 0, AZStd::hash<int32_t>{}, AZStd::equal_to<int32_t>{}, AZ::AZStdIAllocator{ allocatorInstance });
  1140. return allocatorSet;
  1141. }
  1142. };
  1143. using SetTemplateConfigs = ::testing::Types<
  1144. HashedSetWithCustomAllocatorConfig<AZStd::unordered_set>
  1145. , HashedSetWithCustomAllocatorConfig<AZStd::unordered_multiset>
  1146. >;
  1147. TYPED_TEST_CASE(HashedSetDifferentAllocatorFixture, SetTemplateConfigs);
  1148. #if GTEST_HAS_DEATH_TEST
  1149. #if AZ_TRAIT_DISABLE_FAILED_DEATH_TESTS
  1150. TYPED_TEST(HashedSetDifferentAllocatorFixture, DISABLED_InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages)
  1151. #else
  1152. TYPED_TEST(HashedSetDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages)
  1153. #endif // AZ_TRAIT_DISABLE_FAILED_DEATH_TESTS
  1154. {
  1155. using ContainerType = typename TypeParam::ContainerType;
  1156. ContainerType systemAllocatorSet = TypeParam::Create({ {1}, {2}, {3} }, &AZ::AllocatorInstance<AZ::SystemAllocator>::Get());
  1157. auto extractedNode = systemAllocatorSet.extract(1);
  1158. ContainerType osAllocatorSet = TypeParam::Create({ {2} }, &AZ::AllocatorInstance<AZ::OSAllocator>::Get());
  1159. // Attempt to insert an extracted node from a container using the AZ::SystemAllocator into a container using the AZ::OSAllocator
  1160. EXPECT_DEATH(
  1161. {
  1162. UnitTest::TestRunner::Instance().StartAssertTests();
  1163. osAllocatorSet.insert(AZStd::move(extractedNode));
  1164. if (UnitTest::TestRunner::Instance().StopAssertTests() > 0)
  1165. {
  1166. // AZ_Assert does not cause the application to exit in profile_test configuration
  1167. // Therefore an exit with a non-zero error code is invoked to trigger the death condition
  1168. exit(1);
  1169. }
  1170. }, ".*");
  1171. }
  1172. #endif // GTEST_HAS_DEATH_TEST
  1173. template<typename ContainerType>
  1174. class HashedMapContainers
  1175. : public LeakDetectionFixture
  1176. {
  1177. };
  1178. template<typename ContainerType>
  1179. struct HashedMapConfig
  1180. {
  1181. using MapType = ContainerType;
  1182. static MapType Create()
  1183. {
  1184. MapType testMap;
  1185. testMap.emplace(8001, 1337);
  1186. testMap.emplace(-200, 31337);
  1187. testMap.emplace(-932, 0xbaddf00d);
  1188. testMap.emplace(73, 0xfee1badd);
  1189. testMap.emplace(1872, 0xCDCDCDCD);
  1190. testMap.emplace(0xFF, 7000000);
  1191. testMap.emplace(0777, 0b00110000010);
  1192. testMap.emplace(0b11010110110000101, 0xDDDDDDDD);
  1193. return testMap;
  1194. }
  1195. };
  1196. using MapContainerConfigs = ::testing::Types<
  1197. HashedMapConfig<AZStd::unordered_map<int32_t, int32_t>>
  1198. , HashedMapConfig<AZStd::unordered_multimap<int32_t, int32_t>>
  1199. , HashedMapConfig<AZStd::unordered_map<MoveOnlyIntType, int32_t, MoveOnlyIntTypeHasher>>
  1200. , HashedMapConfig<AZStd::unordered_multimap<MoveOnlyIntType, int32_t, MoveOnlyIntTypeHasher>>
  1201. >;
  1202. TYPED_TEST_CASE(HashedMapContainers, MapContainerConfigs);
  1203. TYPED_TEST(HashedMapContainers, ExtractNodeHandleByKeySucceeds)
  1204. {
  1205. using MapType = typename TypeParam::MapType;
  1206. using node_type = typename MapType::node_type;
  1207. MapType testContainer = TypeParam::Create();
  1208. node_type extractedNode = testContainer.extract(0777);
  1209. EXPECT_EQ(7, testContainer.size());
  1210. EXPECT_FALSE(extractedNode.empty());
  1211. EXPECT_EQ(0777, static_cast<int32_t>(extractedNode.key()));
  1212. EXPECT_EQ(0b00110000010, extractedNode.mapped());
  1213. }
  1214. TYPED_TEST(HashedMapContainers, ExtractNodeHandleByKeyFails)
  1215. {
  1216. using MapType = typename TypeParam::MapType;
  1217. using node_type = typename MapType::node_type;
  1218. MapType testContainer = TypeParam::Create();
  1219. node_type extractedNode = testContainer.extract(3);
  1220. EXPECT_EQ(8, testContainer.size());
  1221. EXPECT_TRUE(extractedNode.empty());
  1222. }
  1223. TYPED_TEST(HashedMapContainers, ExtractNodeHandleByIteratorSucceeds)
  1224. {
  1225. using MapType = typename TypeParam::MapType;
  1226. using node_type = typename MapType::node_type;
  1227. MapType testContainer = TypeParam::Create();
  1228. auto foundIter = testContainer.find(73);
  1229. node_type extractedNode = testContainer.extract(foundIter);
  1230. EXPECT_EQ(7, testContainer.size());
  1231. EXPECT_FALSE(extractedNode.empty());
  1232. EXPECT_EQ(73, static_cast<int32_t>(extractedNode.key()));
  1233. EXPECT_EQ(0xfee1badd, extractedNode.mapped());
  1234. }
  1235. TYPED_TEST(HashedMapContainers, InsertNodeHandleSucceeds)
  1236. {
  1237. using MapType = typename TypeParam::MapType;
  1238. using node_type = typename MapType::node_type;
  1239. MapType testContainer = TypeParam::Create();
  1240. node_type extractedNode = testContainer.extract(0777);
  1241. EXPECT_EQ(7, testContainer.size());
  1242. EXPECT_FALSE(extractedNode.empty());
  1243. EXPECT_EQ(0777, static_cast<int32_t>(extractedNode.key()));
  1244. extractedNode.key() = 0644;
  1245. extractedNode.mapped() = 1'212;
  1246. testContainer.insert(AZStd::move(extractedNode));
  1247. auto foundIt = testContainer.find(0644);
  1248. EXPECT_NE(testContainer.end(), foundIt);
  1249. EXPECT_EQ(0644, static_cast<int32_t>(foundIt->first));
  1250. EXPECT_EQ(1'212, foundIt->second);
  1251. EXPECT_EQ(8, testContainer.size());
  1252. }
  1253. TEST_F(HashedContainers, UnorderedMapInsertNodeHandleSucceeds)
  1254. {
  1255. using MapType = AZStd::unordered_map<int32_t, int32_t>;
  1256. using node_type = typename MapType::node_type;
  1257. using insert_return_type = typename MapType::insert_return_type;
  1258. MapType testContainer = HashedMapConfig<MapType>::Create();
  1259. node_type extractedNode = testContainer.extract(0b11010110110000101);
  1260. EXPECT_EQ(7, testContainer.size());
  1261. EXPECT_FALSE(extractedNode.empty());
  1262. EXPECT_EQ(0b11010110110000101, extractedNode.key());
  1263. extractedNode.key() = -60;
  1264. extractedNode.mapped() = -1;
  1265. insert_return_type insertResult = testContainer.insert(AZStd::move(extractedNode));
  1266. EXPECT_NE(testContainer.end(), insertResult.position);
  1267. EXPECT_TRUE(insertResult.inserted);
  1268. EXPECT_TRUE(insertResult.node.empty());
  1269. auto foundIt = testContainer.find(-60);
  1270. EXPECT_NE(testContainer.end(), foundIt);
  1271. EXPECT_EQ(-60, foundIt->first);
  1272. EXPECT_EQ(-1, foundIt->second);
  1273. EXPECT_EQ(8, testContainer.size());
  1274. }
  1275. TEST_F(HashedContainers, UnorderedMapInsertNodeHandleWithEmptyNodeHandleFails)
  1276. {
  1277. using MapType = AZStd::unordered_map<int32_t, int32_t>;
  1278. using node_type = typename MapType::node_type;
  1279. using insert_return_type = typename MapType::insert_return_type;
  1280. MapType testContainer = HashedMapConfig<MapType>::Create();
  1281. node_type extractedNode;
  1282. EXPECT_TRUE(extractedNode.empty());
  1283. EXPECT_EQ(8, testContainer.size());
  1284. insert_return_type insertResult = testContainer.insert(AZStd::move(extractedNode));
  1285. EXPECT_EQ(testContainer.end(), insertResult.position);
  1286. EXPECT_FALSE(insertResult.inserted);
  1287. EXPECT_TRUE(insertResult.node.empty());
  1288. EXPECT_EQ(8, testContainer.size());
  1289. }
  1290. TEST_F(HashedContainers, UnorderedMapInsertNodeHandleWithDuplicateValueInNodeHandleFails)
  1291. {
  1292. using MapType = AZStd::unordered_map<int32_t, int32_t>;
  1293. using node_type = typename MapType::node_type;
  1294. using insert_return_type = typename MapType::insert_return_type;
  1295. MapType testContainer = HashedMapConfig<MapType>::Create();
  1296. node_type extractedNode = testContainer.extract(0xFF);
  1297. EXPECT_EQ(7, testContainer.size());
  1298. EXPECT_FALSE(extractedNode.empty());
  1299. EXPECT_EQ(0xFF, static_cast<int32_t>(extractedNode.key()));
  1300. // Update the extracted node to have the same key as one of the elements currently within the container
  1301. extractedNode.key() = -200;
  1302. insert_return_type insertResult = testContainer.insert(AZStd::move(extractedNode));
  1303. EXPECT_NE(testContainer.end(), insertResult.position);
  1304. EXPECT_FALSE(insertResult.inserted);
  1305. EXPECT_FALSE(insertResult.node.empty());
  1306. EXPECT_EQ(7, testContainer.size());
  1307. }
  1308. TEST_F(HashedContainers, UnorderedMapExtractedNodeCanBeInsertedIntoUnorderedMultimap)
  1309. {
  1310. using MapType = AZStd::unordered_map<int32_t, int32_t>;
  1311. using MultimapType = AZStd::unordered_multimap<int32_t, int32_t>;
  1312. MapType uniqueMap{ {1, 2}, {2, 4}, {3, 6} };
  1313. MultimapType multiMap{ {1, 2}, { 4, 8}, {1, 3} };
  1314. auto extractedNode = uniqueMap.extract(1);
  1315. EXPECT_EQ(2, uniqueMap.size());
  1316. EXPECT_FALSE(extractedNode.empty());
  1317. auto insertIt = multiMap.insert(AZStd::move(extractedNode));
  1318. EXPECT_NE(multiMap.end(), insertIt);
  1319. EXPECT_EQ(4, multiMap.size());
  1320. EXPECT_EQ(3, multiMap.count(1));
  1321. }
  1322. TEST_F(HashedContainers, UnorderedMultimapExtractedNodeCanBeInsertedIntoUnorderedMap)
  1323. {
  1324. using MapType = AZStd::unordered_map<int32_t, int32_t>;
  1325. using MultimapType = AZStd::unordered_multimap<int32_t, int32_t>;
  1326. MapType uniqueMap{ {1, 2}, {2, 4}, {3, 6} };
  1327. MultimapType multiMap{ {1, 2}, { 4, 8}, {1, 3} };
  1328. auto extractedNode = multiMap.extract(4);
  1329. EXPECT_EQ(2, multiMap.size());
  1330. EXPECT_FALSE(extractedNode.empty());
  1331. auto insertResult = uniqueMap.insert(AZStd::move(extractedNode));
  1332. EXPECT_TRUE(insertResult.inserted);
  1333. EXPECT_EQ(4, uniqueMap.size());
  1334. EXPECT_EQ(1, uniqueMap.count(4));
  1335. }
  1336. TEST_F(HashedContainers, CheckADL)
  1337. {
  1338. // ensure this compiles and not does fail due to ADL (Koenig Lookup)
  1339. std::vector<AZStd::unordered_map<int, int>> test_adl;
  1340. EXPECT_TRUE(test_adl.empty());
  1341. }
  1342. TEST_F(HashedContainers, UnorderedMapTryEmplace_DoesNotConstruct_OnExistingKey)
  1343. {
  1344. static int s_tryEmplaceConstructorCallCount;
  1345. s_tryEmplaceConstructorCallCount = 0;
  1346. struct TryEmplaceConstructorCalls
  1347. {
  1348. TryEmplaceConstructorCalls()
  1349. {
  1350. ++s_tryEmplaceConstructorCallCount;
  1351. }
  1352. TryEmplaceConstructorCalls(int value)
  1353. : m_value{ value }
  1354. {
  1355. ++s_tryEmplaceConstructorCallCount;
  1356. }
  1357. TryEmplaceConstructorCalls(const TryEmplaceConstructorCalls&)
  1358. {
  1359. ++s_tryEmplaceConstructorCallCount;
  1360. }
  1361. int m_value{};
  1362. };
  1363. using TryEmplaceTestMap = AZStd::unordered_map<int, TryEmplaceConstructorCalls>;
  1364. TryEmplaceTestMap testContainer;
  1365. // try_emplace move key
  1366. AZStd::pair<TryEmplaceTestMap::iterator, bool> emplacePairIter = testContainer.try_emplace(1, 5);
  1367. EXPECT_EQ(1, s_tryEmplaceConstructorCallCount);
  1368. EXPECT_TRUE(emplacePairIter.second);
  1369. EXPECT_EQ(5, emplacePairIter.first->second.m_value);
  1370. // try_emplace copy key
  1371. int testKey = 3;
  1372. emplacePairIter = testContainer.try_emplace(testKey, 72);
  1373. EXPECT_EQ(2, s_tryEmplaceConstructorCallCount);
  1374. EXPECT_TRUE(emplacePairIter.second);
  1375. EXPECT_EQ(72, emplacePairIter.first->second.m_value);
  1376. // invoke try_emplace with hint and move key
  1377. TryEmplaceTestMap::iterator emplaceIter = testContainer.try_emplace(testContainer.end(), 5, 4092);
  1378. EXPECT_EQ(3, s_tryEmplaceConstructorCallCount);
  1379. EXPECT_EQ(4092, emplaceIter->second.m_value);
  1380. // invoke try_emplace with hint and copy key
  1381. testKey = 48;
  1382. emplaceIter = testContainer.try_emplace(testContainer.end(), testKey, 824);
  1383. EXPECT_EQ(4, s_tryEmplaceConstructorCallCount);
  1384. EXPECT_EQ(824, emplaceIter->second.m_value);
  1385. // Since the key of '1' exist, nothing should be constructed
  1386. emplacePairIter = testContainer.try_emplace(1, -6354);
  1387. EXPECT_EQ(4, s_tryEmplaceConstructorCallCount);
  1388. EXPECT_FALSE(emplacePairIter.second);
  1389. EXPECT_EQ(5, emplacePairIter.first->second.m_value);
  1390. }
  1391. TEST_F(HashedContainers, UnorderedMapTryEmplace_DoesNotMoveValue_OnExistingKey)
  1392. {
  1393. AZStd::unordered_map<int, AZStd::unique_ptr<int>> testMap;
  1394. auto testPtr = AZStd::make_unique<int>(5);
  1395. auto [emplaceIter, inserted] = testMap.try_emplace(1, AZStd::move(testPtr));
  1396. EXPECT_TRUE(inserted);
  1397. EXPECT_EQ(nullptr, testPtr);
  1398. testPtr = AZStd::make_unique<int>(7000);
  1399. auto [emplaceIter2, inserted2] = testMap.try_emplace(1, AZStd::move(testPtr));
  1400. EXPECT_FALSE(inserted2);
  1401. ASSERT_NE(nullptr, testPtr);
  1402. EXPECT_EQ(7000, *testPtr);
  1403. }
  1404. TEST_F(HashedContainers, UnorderedMapInsertOrAssign_PerformsAssignment_OnExistingKey)
  1405. {
  1406. static int s_tryInsertOrAssignConstructorCalls;
  1407. static int s_tryInsertOrAssignAssignmentCalls;
  1408. s_tryInsertOrAssignConstructorCalls = 0;
  1409. s_tryInsertOrAssignAssignmentCalls = 0;
  1410. struct InsertOrAssignInitCalls
  1411. {
  1412. InsertOrAssignInitCalls()
  1413. {
  1414. ++s_tryInsertOrAssignConstructorCalls;
  1415. }
  1416. InsertOrAssignInitCalls(int value)
  1417. : m_value{ value }
  1418. {
  1419. ++s_tryInsertOrAssignConstructorCalls;
  1420. }
  1421. InsertOrAssignInitCalls(const InsertOrAssignInitCalls& other)
  1422. : m_value{ other.m_value }
  1423. {
  1424. ++s_tryInsertOrAssignConstructorCalls;
  1425. }
  1426. InsertOrAssignInitCalls& operator=(int value)
  1427. {
  1428. m_value = value;
  1429. ++s_tryInsertOrAssignAssignmentCalls;
  1430. return *this;
  1431. }
  1432. int m_value{};
  1433. };
  1434. using InsertOrAssignTestMap = AZStd::unordered_map<int, InsertOrAssignInitCalls>;
  1435. InsertOrAssignTestMap testContainer;
  1436. // insert_or_assign move key
  1437. AZStd::pair<InsertOrAssignTestMap::iterator, bool> insertOrAssignPairIter = testContainer.insert_or_assign(1, 5);
  1438. EXPECT_EQ(1, s_tryInsertOrAssignConstructorCalls);
  1439. EXPECT_EQ(0, s_tryInsertOrAssignAssignmentCalls);
  1440. EXPECT_TRUE(insertOrAssignPairIter.second);
  1441. EXPECT_EQ(5, insertOrAssignPairIter.first->second.m_value);
  1442. // insert_or_assign copy key
  1443. int testKey = 3;
  1444. insertOrAssignPairIter = testContainer.insert_or_assign(testKey, 72);
  1445. EXPECT_EQ(2, s_tryInsertOrAssignConstructorCalls);
  1446. EXPECT_EQ(0, s_tryInsertOrAssignAssignmentCalls);
  1447. EXPECT_TRUE(insertOrAssignPairIter.second);
  1448. EXPECT_EQ(72, insertOrAssignPairIter.first->second.m_value);
  1449. // invoke insert_or_assign with hint and move key
  1450. InsertOrAssignTestMap::iterator insertOrAssignIter = testContainer.insert_or_assign(testContainer.end(), 5, 4092);
  1451. EXPECT_EQ(3, s_tryInsertOrAssignConstructorCalls);
  1452. EXPECT_EQ(0, s_tryInsertOrAssignAssignmentCalls);
  1453. EXPECT_EQ(4092, insertOrAssignIter->second.m_value);
  1454. // invoke insert_or_assign with hint and copy key
  1455. testKey = 48;
  1456. insertOrAssignIter = testContainer.insert_or_assign(testContainer.end(), testKey, 824);
  1457. EXPECT_EQ(4, s_tryInsertOrAssignConstructorCalls);
  1458. EXPECT_EQ(0, s_tryInsertOrAssignAssignmentCalls);
  1459. EXPECT_EQ(824, insertOrAssignIter->second.m_value);
  1460. // Since the key of '1' exist, only an assignment should take place
  1461. insertOrAssignPairIter = testContainer.insert_or_assign(1, -6354);
  1462. EXPECT_EQ(4, s_tryInsertOrAssignConstructorCalls);
  1463. EXPECT_EQ(1, s_tryInsertOrAssignAssignmentCalls);
  1464. EXPECT_FALSE(insertOrAssignPairIter.second);
  1465. EXPECT_EQ(-6354, insertOrAssignPairIter.first->second.m_value);
  1466. }
  1467. template<template<class...> class SetTemplate>
  1468. static void HashSetRangeConstructorSucceeds()
  1469. {
  1470. constexpr AZStd::string_view testView = "abc";
  1471. SetTemplate testSet(AZStd::from_range, testView);
  1472. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1473. testSet = SetTemplate(AZStd::from_range, AZStd::vector<char>{testView.begin(), testView.end()});
  1474. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1475. testSet = SetTemplate(AZStd::from_range, AZStd::list<char>{testView.begin(), testView.end()});
  1476. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1477. testSet = SetTemplate(AZStd::from_range, AZStd::deque<char>{testView.begin(), testView.end()});
  1478. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1479. testSet = SetTemplate(AZStd::from_range, AZStd::unordered_set<char>{testView.begin(), testView.end()});
  1480. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1481. testSet = SetTemplate(AZStd::from_range, AZStd::fixed_vector<char, 8>{testView.begin(), testView.end()});
  1482. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1483. testSet = SetTemplate(AZStd::from_range, AZStd::array{ 'a', 'b', 'c' });
  1484. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1485. testSet = SetTemplate(AZStd::from_range, AZStd::span(testView));
  1486. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1487. testSet = SetTemplate(AZStd::from_range, AZStd::span(testView));
  1488. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1489. AZStd::fixed_string<8> testValue(testView);
  1490. testSet = SetTemplate(AZStd::from_range, testValue);
  1491. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1492. testSet = SetTemplate(AZStd::from_range, AZStd::string(testView));
  1493. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c'));
  1494. // Test Range views
  1495. testSet = SetTemplate(AZStd::from_range, testValue | AZStd::views::transform([](const char elem) -> char { return elem + 1; }));
  1496. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('b', 'c', 'd'));
  1497. }
  1498. template<template<class...> class MapTemplate>
  1499. static void HashMapRangeConstructorSucceeds()
  1500. {
  1501. using ValueType = AZStd::pair<char, int>;
  1502. constexpr AZStd::array testArray{ ValueType{'a', 1}, ValueType{'b', 2}, ValueType{'c', 3} };
  1503. MapTemplate testMap(AZStd::from_range, testArray);
  1504. EXPECT_THAT(testMap, ::testing::UnorderedElementsAre(ValueType{ 'a', 1 }, ValueType{ 'b', 2 }, ValueType{ 'c', 3 }));
  1505. testMap = MapTemplate(AZStd::from_range, AZStd::vector<ValueType>{testArray.begin(), testArray.end()});
  1506. EXPECT_THAT(testMap, ::testing::UnorderedElementsAre(ValueType{ 'a', 1 }, ValueType{ 'b', 2 }, ValueType{ 'c', 3 }));
  1507. testMap = MapTemplate(AZStd::from_range, AZStd::list<ValueType>{testArray.begin(), testArray.end()});
  1508. EXPECT_THAT(testMap, ::testing::UnorderedElementsAre(ValueType{ 'a', 1 }, ValueType{ 'b', 2 }, ValueType{ 'c', 3 }));
  1509. testMap = MapTemplate(AZStd::from_range, AZStd::deque<ValueType>{testArray.begin(), testArray.end()});
  1510. EXPECT_THAT(testMap, ::testing::UnorderedElementsAre(ValueType{ 'a', 1 }, ValueType{ 'b', 2 }, ValueType{ 'c', 3 }));
  1511. testMap = MapTemplate(AZStd::from_range, AZStd::unordered_set<ValueType>{testArray.begin(), testArray.end()});
  1512. EXPECT_THAT(testMap, ::testing::UnorderedElementsAre(ValueType{ 'a', 1 }, ValueType{ 'b', 2 }, ValueType{ 'c', 3 }));
  1513. testMap = MapTemplate(AZStd::from_range, AZStd::fixed_vector<ValueType, 8>{testArray.begin(), testArray.end()});
  1514. EXPECT_THAT(testMap, ::testing::UnorderedElementsAre(ValueType{ 'a', 1 }, ValueType{ 'b', 2 }, ValueType{ 'c', 3 }));
  1515. testMap = MapTemplate(AZStd::from_range, AZStd::span(testArray));
  1516. EXPECT_THAT(testMap, ::testing::UnorderedElementsAre(ValueType{ 'a', 1 }, ValueType{ 'b', 2 }, ValueType{ 'c', 3 }));
  1517. }
  1518. TEST_F(HashedContainers, RangeConstructor_Succeeds)
  1519. {
  1520. HashSetRangeConstructorSucceeds<AZStd::unordered_set>();
  1521. HashSetRangeConstructorSucceeds<AZStd::unordered_multiset>();
  1522. HashMapRangeConstructorSucceeds<AZStd::unordered_map>();
  1523. HashMapRangeConstructorSucceeds<AZStd::unordered_multimap>();
  1524. }
  1525. template<template<class...> class SetTemplate>
  1526. static void HashSetInsertRangeSucceeds()
  1527. {
  1528. constexpr AZStd::string_view testView = "abc";
  1529. SetTemplate testSet{ 'd', 'e', 'f' };
  1530. testSet.insert_range(AZStd::vector<char>{testView.begin(), testView.end()});
  1531. testSet.insert_range(testView | AZStd::views::transform([](const char elem) -> char { return elem + 6; }));
  1532. EXPECT_THAT(testSet, ::testing::UnorderedElementsAre('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'));
  1533. }
  1534. template<template<class...> class MapTemplate>
  1535. static void HashMapInsertRangeSucceeds()
  1536. {
  1537. using ValueType = AZStd::pair<char, int>;
  1538. constexpr AZStd::array testArray{ ValueType{'a', 1}, ValueType{'b', 2}, ValueType{'c', 3} };
  1539. MapTemplate testMap(AZStd::from_range, testArray);
  1540. testMap.insert_range(AZStd::vector<ValueType>{ValueType{ 'd', 4 }, ValueType{ 'e', 5 }, ValueType{ 'f', 6 }});
  1541. EXPECT_THAT(testMap, ::testing::UnorderedElementsAre(ValueType{ 'a', 1 }, ValueType{ 'b', 2 }, ValueType{ 'c', 3 },
  1542. ValueType{ 'd', 4 }, ValueType{ 'e', 5 }, ValueType{ 'f', 6 }));
  1543. }
  1544. TEST_F(HashedContainers, InsertRange_Succeeds)
  1545. {
  1546. HashSetInsertRangeSucceeds<AZStd::unordered_set>();
  1547. HashSetInsertRangeSucceeds<AZStd::unordered_multiset>();
  1548. HashMapInsertRangeSucceeds<AZStd::unordered_map>();
  1549. HashMapInsertRangeSucceeds<AZStd::unordered_multimap>();
  1550. }
  1551. template <typename ContainerType>
  1552. class HashedMapDifferentAllocatorFixture
  1553. : public LeakDetectionFixture
  1554. {
  1555. };
  1556. template<template <typename, typename, typename, typename, typename> class ContainerTemplate>
  1557. struct HashedMapWithCustomAllocatorConfig
  1558. {
  1559. using ContainerType = ContainerTemplate<int32_t, int32_t, AZStd::hash<int32_t>, AZStd::equal_to<int32_t>, AZ::AZStdIAllocator>;
  1560. static ContainerType Create(std::initializer_list<typename ContainerType::value_type> intList, AZ::IAllocator* allocatorInstance)
  1561. {
  1562. ContainerType allocatorMap(intList, 0, AZStd::hash<int32_t>{}, AZStd::equal_to<int32_t>{}, AZ::AZStdIAllocator{ allocatorInstance });
  1563. return allocatorMap;
  1564. }
  1565. };
  1566. using MapTemplateConfigs = ::testing::Types<
  1567. HashedMapWithCustomAllocatorConfig<AZStd::unordered_map>
  1568. , HashedMapWithCustomAllocatorConfig<AZStd::unordered_multimap>
  1569. >;
  1570. TYPED_TEST_CASE(HashedMapDifferentAllocatorFixture, MapTemplateConfigs);
  1571. #if GTEST_HAS_DEATH_TEST
  1572. #if AZ_TRAIT_DISABLE_FAILED_DEATH_TESTS
  1573. TYPED_TEST(HashedMapDifferentAllocatorFixture, DISABLED_InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages)
  1574. #else
  1575. TYPED_TEST(HashedMapDifferentAllocatorFixture, InsertNodeHandleWithDifferentAllocatorsLogsTraceMessages)
  1576. #endif // AZ_TRAIT_DISABLE_FAILED_DEATH_TESTS
  1577. {
  1578. using ContainerType = typename TypeParam::ContainerType;
  1579. ContainerType systemAllocatorMap = TypeParam::Create({ {1, 2}, {2, 4}, {3, 6} }, &AZ::AllocatorInstance<AZ::SystemAllocator>::Get());
  1580. auto extractedNode = systemAllocatorMap.extract(1);
  1581. ContainerType osAllocatorMap = TypeParam::Create({ {2, 4} }, &AZ::AllocatorInstance<AZ::OSAllocator>::Get());
  1582. // Attempt to insert an extracted node from a container using the AZ::SystemAllocator into a container using the AZ::OSAllocator
  1583. EXPECT_DEATH(
  1584. {
  1585. UnitTest::TestRunner::Instance().StartAssertTests();
  1586. osAllocatorMap.insert(AZStd::move(extractedNode));
  1587. if (UnitTest::TestRunner::Instance().StopAssertTests() > 0)
  1588. {
  1589. // AZ_Assert does not cause the application to exit in profile_test configuration
  1590. // Therefore an exit with a non-zero error code is invoked to trigger the death condition
  1591. exit(1);
  1592. }
  1593. } , ".*");
  1594. }
  1595. #endif // GTEST_HAS_DEATH_TEST
  1596. namespace HashedContainerTransparentTestInternal
  1597. {
  1598. static int s_allConstructorCount;
  1599. static int s_allAssignmentCount;
  1600. struct TrackConstructorCalls
  1601. {
  1602. TrackConstructorCalls()
  1603. {
  1604. ++s_allConstructorCount;
  1605. }
  1606. TrackConstructorCalls(int value)
  1607. : m_value(value)
  1608. {
  1609. ++s_allConstructorCount;
  1610. }
  1611. TrackConstructorCalls(const TrackConstructorCalls& other)
  1612. : m_value(other.m_value)
  1613. {
  1614. ++s_allConstructorCount;
  1615. };
  1616. TrackConstructorCalls& operator=(const TrackConstructorCalls& other)
  1617. {
  1618. ++s_allAssignmentCount;
  1619. m_value = other.m_value;
  1620. return *this;
  1621. }
  1622. operator int() const
  1623. {
  1624. return m_value;
  1625. }
  1626. int m_value{}; // Used for comparison
  1627. };
  1628. bool operator==(const TrackConstructorCalls& lhs, const TrackConstructorCalls& rhs)
  1629. {
  1630. return lhs.m_value == rhs.m_value;
  1631. }
  1632. bool operator==(int lhs, const TrackConstructorCalls& rhs)
  1633. {
  1634. return lhs== rhs.m_value;
  1635. }
  1636. bool operator==(const TrackConstructorCalls& lhs, int rhs)
  1637. {
  1638. return lhs.m_value == rhs;
  1639. }
  1640. }
  1641. }
  1642. namespace AZStd
  1643. {
  1644. using is_transparent = void;
  1645. template<>
  1646. struct hash<UnitTest::HashedContainerTransparentTestInternal::TrackConstructorCalls>
  1647. {
  1648. using is_transparent = void;
  1649. template<typename ConvertableToKey>
  1650. constexpr size_t operator()(const ConvertableToKey& key) const
  1651. {
  1652. return static_cast<int>(key);
  1653. }
  1654. };
  1655. }
  1656. namespace UnitTest
  1657. {
  1658. template<typename Container>
  1659. struct HashedContainerTransparentConfig
  1660. {
  1661. using ContainerType = Container;
  1662. };
  1663. template <typename ContainerType>
  1664. class HashedContainerTransparentFixture
  1665. : public LeakDetectionFixture
  1666. {
  1667. protected:
  1668. void SetUp() override
  1669. {
  1670. HashedContainerTransparentTestInternal::s_allConstructorCount = 0;
  1671. HashedContainerTransparentTestInternal::s_allAssignmentCount = 0;
  1672. }
  1673. void TearDown() override
  1674. {
  1675. HashedContainerTransparentTestInternal::s_allConstructorCount = 0;
  1676. HashedContainerTransparentTestInternal::s_allAssignmentCount = 0;
  1677. }
  1678. };
  1679. using HashedContainerConfigs = ::testing::Types <
  1680. HashedContainerTransparentConfig<
  1681. AZStd::unordered_set<HashedContainerTransparentTestInternal::TrackConstructorCalls, AZStd::hash<HashedContainerTransparentTestInternal::TrackConstructorCalls>, AZStd::equal_to<>>
  1682. >
  1683. , HashedContainerTransparentConfig<
  1684. AZStd::unordered_multiset<HashedContainerTransparentTestInternal::TrackConstructorCalls, AZStd::hash<HashedContainerTransparentTestInternal::TrackConstructorCalls>, AZStd::equal_to<>>
  1685. >
  1686. , HashedContainerTransparentConfig<
  1687. AZStd::unordered_map<HashedContainerTransparentTestInternal::TrackConstructorCalls, int, AZStd::hash<HashedContainerTransparentTestInternal::TrackConstructorCalls>, AZStd::equal_to<>>
  1688. >
  1689. , HashedContainerTransparentConfig<
  1690. AZStd::unordered_multimap<HashedContainerTransparentTestInternal::TrackConstructorCalls, int, AZStd::hash<HashedContainerTransparentTestInternal::TrackConstructorCalls>, AZStd::equal_to<>>
  1691. >
  1692. >;
  1693. TYPED_TEST_CASE(HashedContainerTransparentFixture, HashedContainerConfigs);
  1694. TYPED_TEST(HashedContainerTransparentFixture, FindDoesNotConstructKeyForTransparentHashEqual_NoKeyConstructed_Succeeds)
  1695. {
  1696. typename TypeParam::ContainerType container;
  1697. container.emplace(1);
  1698. container.emplace(2);
  1699. container.emplace(3);
  1700. container.emplace(4);
  1701. container.emplace(5);
  1702. container.emplace(1);
  1703. // Reset constructor count to zero
  1704. HashedContainerTransparentTestInternal::s_allConstructorCount = 0;
  1705. // The following call will construct a TrackConstructorCalls element
  1706. auto foundIt = container.find(HashedContainerTransparentTestInternal::TrackConstructorCalls{ 2 });
  1707. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1708. EXPECT_NE(container.end(), foundIt);
  1709. // The transparent find function should be invoked and no constructor of TrackConstructorCallsElement should be invoked
  1710. foundIt = container.find(1);
  1711. // The ConstructorCount should still be the same
  1712. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1713. EXPECT_NE(container.end(), foundIt);
  1714. // When find fails to locate an element, TrackConstructorCallsElement shouldn't be construction
  1715. foundIt = container.find(-1);
  1716. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1717. EXPECT_EQ(container.end(), foundIt);
  1718. // No assignments should have taken place from any of the container operations
  1719. EXPECT_EQ(0, HashedContainerTransparentTestInternal::s_allAssignmentCount);
  1720. }
  1721. TYPED_TEST(HashedContainerTransparentFixture, ContainsDoesNotConstructKeyForTransparentHashEqual_NoKeyConstructed_Succeeds)
  1722. {
  1723. typename TypeParam::ContainerType container;
  1724. container.emplace(1);
  1725. container.emplace(2);
  1726. container.emplace(3);
  1727. container.emplace(4);
  1728. container.emplace(5);
  1729. container.emplace(1);
  1730. // Reset constructor count to zero
  1731. HashedContainerTransparentTestInternal::s_allConstructorCount = 0;
  1732. // The following call will construct a TrackConstructorCalls element
  1733. EXPECT_TRUE(container.contains(HashedContainerTransparentTestInternal::TrackConstructorCalls{ 2 }));
  1734. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1735. // The transparent contain function should be invoked and no constructor of TrackConstructorCallsElement should be invoked
  1736. EXPECT_TRUE(container.contains(2));
  1737. // The ConstructorCount should still be the same
  1738. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1739. // In the case when the element isn't found, no constructor shouldn't be invoked as well
  1740. EXPECT_FALSE(container.contains(27));
  1741. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1742. // No assignments should have taken place from any of the container operations
  1743. EXPECT_EQ(0, HashedContainerTransparentTestInternal::s_allAssignmentCount);
  1744. }
  1745. TYPED_TEST(HashedContainerTransparentFixture, CountDoesNotConstructKeyForTransparentHashEqual_NoKeyConstructed_Succeeds)
  1746. {
  1747. typename TypeParam::ContainerType container;
  1748. container.emplace(1);
  1749. container.emplace(2);
  1750. container.emplace(3);
  1751. container.emplace(4);
  1752. container.emplace(5);
  1753. container.emplace(1);
  1754. // Reset constructor count to zero
  1755. HashedContainerTransparentTestInternal::s_allConstructorCount = 0;
  1756. // The following call will construct a TrackConstructorCalls element
  1757. EXPECT_EQ(1, container.count(HashedContainerTransparentTestInternal::TrackConstructorCalls{ 2 }));
  1758. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1759. // The transparent count function should be invoked and no constructor of TrackConstructorCallsElement should be invoked
  1760. EXPECT_EQ(1, container.count(2));
  1761. // The ConstructorCount should still be the same
  1762. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1763. // In the case when the element isn't found, no constructor shouldn't be invoked as well
  1764. EXPECT_EQ(0, container.count(27));
  1765. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1766. // No assignments should have taken place from any of the container operations
  1767. EXPECT_EQ(0, HashedContainerTransparentTestInternal::s_allAssignmentCount);
  1768. }
  1769. TYPED_TEST(HashedContainerTransparentFixture, LowerBoundDoesNotConstructKeyForTransparentHashEqual_NoKeyConstructed_Succeeds)
  1770. {
  1771. typename TypeParam::ContainerType container;
  1772. container.emplace(21);
  1773. container.emplace(4);
  1774. container.emplace(3);
  1775. container.emplace(7);
  1776. container.emplace(15);
  1777. container.emplace(42);
  1778. // Lower Bound and Upper Bound doesn't make any sense for an Unordered Container, because there is no ordering
  1779. // So the values returned from those calls are non-nonsensical.
  1780. // i.e invoking upper_bound(16) with current data could return an iterator to 332, an iterator 1, or even the end iterator()
  1781. // depending on how the data is stored in the node based hash table
  1782. // Reset constructor count to zero
  1783. HashedContainerTransparentTestInternal::s_allConstructorCount = 0;
  1784. // The following call will construct a TrackConstructorCalls element
  1785. auto foundIt = container.lower_bound(HashedContainerTransparentTestInternal::TrackConstructorCalls{ 4 });
  1786. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1787. // The transparent lower_bound function should be invoked and no constructor of TrackConstructorCallsElement should be invoked
  1788. foundIt = container.lower_bound(7);
  1789. // The ConstructorCount should still be the same
  1790. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1791. // No assignments should have taken place from any of the container operations
  1792. EXPECT_EQ(0, HashedContainerTransparentTestInternal::s_allAssignmentCount);
  1793. }
  1794. TYPED_TEST(HashedContainerTransparentFixture, UpperBoundDoesNotConstructKeyForTransparentHashEqual_NoKeyConstructed_Succeeds)
  1795. {
  1796. typename TypeParam::ContainerType container;
  1797. container.emplace(2);
  1798. container.emplace(4);
  1799. container.emplace(15);
  1800. container.emplace(332);
  1801. container.emplace(5);
  1802. container.emplace(1);
  1803. // Lower Bound and Upper Bound doesn't make any sense for an Unordered Container, because there is no ordering
  1804. // So the values returned from those calls are non-nonsensical.
  1805. // i.e invoking upper_bound(16) with current data could return an iterator to 332, an iterator 1, or even the end iterator()
  1806. // depending on how the data is stored in the node based hash table
  1807. // Reset constructor count to zero
  1808. HashedContainerTransparentTestInternal::s_allConstructorCount = 0;
  1809. // The following call will construct a TrackConstructorCalls element
  1810. auto foundIt = container.upper_bound(HashedContainerTransparentTestInternal::TrackConstructorCalls{ 15 });
  1811. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1812. // The transparent upper_bound function should be invoked and no constructor of TrackConstructorCallsElement should be invoked
  1813. foundIt = container.upper_bound(5);
  1814. // The ConstructorCount should still be the same
  1815. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1816. // No assignments should have taken place from any of the container operations
  1817. EXPECT_EQ(0, HashedContainerTransparentTestInternal::s_allAssignmentCount);
  1818. }
  1819. TYPED_TEST(HashedContainerTransparentFixture, EqualRangeDoesNotConstructKeyForTransparentHashEqual_NoKeyConstructed_Succeeds)
  1820. {
  1821. typename TypeParam::ContainerType container;
  1822. container.emplace(-2352);
  1823. container.emplace(3534);
  1824. container.emplace(535408957);
  1825. container.emplace(1310556522);
  1826. container.emplace(55546193);
  1827. container.emplace(1582);
  1828. // Reset constructor count to zero
  1829. HashedContainerTransparentTestInternal::s_allConstructorCount = 0;
  1830. // The following call will construct a TrackConstructorCalls element
  1831. auto foundRange = container.equal_range(HashedContainerTransparentTestInternal::TrackConstructorCalls{ -2352 });
  1832. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1833. EXPECT_NE(container.end(), foundRange.first);
  1834. EXPECT_NE(foundRange.first, foundRange.second);
  1835. // The transparent upper_bound function should be invoked and no constructor of TrackConstructorCallsElement should be invoked
  1836. foundRange = container.equal_range(55546193);
  1837. // The ConstructorCount should still be the same
  1838. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1839. EXPECT_NE(foundRange.first, foundRange.second);
  1840. // In the case when the element isn't found, no constructor shouldn't be invoked as well
  1841. foundRange = container.equal_range(0x9034);
  1842. EXPECT_EQ(1, HashedContainerTransparentTestInternal::s_allConstructorCount);
  1843. EXPECT_EQ(foundRange.first, foundRange.second);
  1844. // No assignments should have taken place from any of the container operations
  1845. EXPECT_EQ(0, HashedContainerTransparentTestInternal::s_allAssignmentCount);
  1846. }
  1847. #if defined(HAVE_BENCHMARK)
  1848. template <template <typename...> class Hash>
  1849. void Benchmark_Lookup(benchmark::State& state)
  1850. {
  1851. const int count = 1024;
  1852. Hash<int, int, AZStd::hash<int>, AZStd::equal_to<int>, AZStd::allocator> map;
  1853. for (int i = 0; i < count; ++i)
  1854. {
  1855. map.emplace(i, i);
  1856. }
  1857. int val = 0;
  1858. while (state.KeepRunning())
  1859. {
  1860. val += map[rand() % count];
  1861. }
  1862. }
  1863. template <template <typename...> class Hash>
  1864. void Benchmark_Insert(benchmark::State& state)
  1865. {
  1866. const int count = 1024;
  1867. Hash<int, int, AZStd::hash<int>, AZStd::equal_to<int>, AZStd::allocator> map;
  1868. int i = 0;
  1869. while (state.KeepRunning())
  1870. {
  1871. i = (i == count) ? 0 : i + 1;
  1872. map[i] = i;
  1873. }
  1874. }
  1875. template <template <typename ...> class Hash>
  1876. void Benchmark_Erase(benchmark::State& state)
  1877. {
  1878. const int count = 1024;
  1879. Hash<int, int, AZStd::hash<int>, AZStd::equal_to<int>, AZStd::allocator> map;
  1880. for (int i = 0; i < count; ++i)
  1881. {
  1882. map.emplace(i, i);
  1883. }
  1884. while (state.KeepRunning())
  1885. {
  1886. int val = rand() % count;
  1887. map.erase(val);
  1888. }
  1889. }
  1890. template <template <typename ...> class Hash>
  1891. void Benchmark_Thrash(benchmark::State& state)
  1892. {
  1893. const int choices = 100;
  1894. Hash<int, int, AZStd::hash<int>, AZStd::equal_to<int>, AZStd::allocator> map;
  1895. size_t ops = 0;
  1896. while (state.KeepRunning())
  1897. {
  1898. int val = rand() % choices;
  1899. switch (rand() % 3)
  1900. {
  1901. case 0:
  1902. ops += map.emplace(val, val).second;
  1903. break;
  1904. case 1:
  1905. ops += map.erase(val);
  1906. break;
  1907. case 2:
  1908. ops += map.find(val) == map.end();
  1909. break;
  1910. }
  1911. }
  1912. }
  1913. void Benchmark_UnorderedMapLookup(benchmark::State& state)
  1914. {
  1915. Benchmark_Lookup<AZStd::unordered_map>(state);
  1916. }
  1917. BENCHMARK(Benchmark_UnorderedMapLookup);
  1918. void Benchmark_UnorderedMapInsert(benchmark::State& state)
  1919. {
  1920. Benchmark_Insert<AZStd::unordered_map>(state);
  1921. }
  1922. BENCHMARK(Benchmark_UnorderedMapInsert);
  1923. void Benchmark_UnorderedMapErase(benchmark::State& state)
  1924. {
  1925. Benchmark_Erase<AZStd::unordered_map>(state);
  1926. }
  1927. BENCHMARK(Benchmark_UnorderedMapErase);
  1928. void Benchmark_UnorderedMapThrash(benchmark::State& state)
  1929. {
  1930. Benchmark_Thrash<AZStd::unordered_map>(state);
  1931. }
  1932. BENCHMARK(Benchmark_UnorderedMapThrash);
  1933. #endif
  1934. } // namespace UnitTest
  1935. #if defined(HAVE_BENCHMARK)
  1936. namespace Benchmark
  1937. {
  1938. const int kNumInsertions = 10000;
  1939. const int kModuloForDuplicates = 10;
  1940. struct A
  1941. {
  1942. int m_int = 0;
  1943. };
  1944. using UnorderedMap = AZStd::unordered_map<int, A>;
  1945. using AZStd::make_pair;
  1946. // BM_UnorderedMap_InsertUniqueViaXXX: benchmark filling a map with unique values
  1947. static void BM_UnorderedMap_InsertUniqueViaInsert(::benchmark::State& state)
  1948. {
  1949. while (state.KeepRunning())
  1950. {
  1951. UnorderedMap map;
  1952. for (int mapKey = 0; mapKey < kNumInsertions; ++mapKey)
  1953. {
  1954. A& a = map.insert(make_pair(mapKey, A{})).first->second;
  1955. a.m_int += 1;
  1956. }
  1957. }
  1958. }
  1959. BENCHMARK(BM_UnorderedMap_InsertUniqueViaInsert);
  1960. static void BM_UnorderedMap_InsertUniqueViaEmplace(::benchmark::State& state)
  1961. {
  1962. while (state.KeepRunning())
  1963. {
  1964. UnorderedMap map;
  1965. for (int mapKey = 0; mapKey < kNumInsertions; ++mapKey)
  1966. {
  1967. A& a = map.emplace(mapKey, A()).first->second;
  1968. a.m_int += 1;
  1969. }
  1970. }
  1971. }
  1972. BENCHMARK(BM_UnorderedMap_InsertUniqueViaEmplace);
  1973. static void BM_UnorderedMap_InsertUniqueViaBracket(::benchmark::State& state)
  1974. {
  1975. while (state.KeepRunning())
  1976. {
  1977. UnorderedMap map;
  1978. for (int mapKey = 0; mapKey < kNumInsertions; ++mapKey)
  1979. {
  1980. A& a = map[mapKey];
  1981. a.m_int += 1;
  1982. }
  1983. }
  1984. }
  1985. BENCHMARK(BM_UnorderedMap_InsertUniqueViaBracket);
  1986. // BM_UnorderedMap_InsertDuplicatesViaXXX: benchmark filling a map with keys that repeat
  1987. static void BM_UnorderedMap_InsertDuplicatesViaInsert(::benchmark::State& state)
  1988. {
  1989. while (state.KeepRunning())
  1990. {
  1991. UnorderedMap map;
  1992. for (int mapKey = 0; mapKey < kNumInsertions; ++mapKey)
  1993. {
  1994. A& a = map.insert(make_pair(mapKey % kModuloForDuplicates, A())).first->second;
  1995. a.m_int += 1;
  1996. }
  1997. }
  1998. }
  1999. BENCHMARK(BM_UnorderedMap_InsertDuplicatesViaInsert);
  2000. static void BM_UnorderedMap_InsertDuplicatesViaEmplace(::benchmark::State& state)
  2001. {
  2002. while (state.KeepRunning())
  2003. {
  2004. UnorderedMap map;
  2005. for (int mapKey = 0; mapKey < kNumInsertions; ++mapKey)
  2006. {
  2007. A& a = map.emplace(mapKey % kModuloForDuplicates, A{}).first->second;
  2008. a.m_int += 1;
  2009. }
  2010. }
  2011. }
  2012. BENCHMARK(BM_UnorderedMap_InsertDuplicatesViaEmplace);
  2013. static void BM_UnorderedMap_InsertDuplicatesViaBracket(::benchmark::State& state)
  2014. {
  2015. while (state.KeepRunning())
  2016. {
  2017. UnorderedMap map;
  2018. for (int mapKey = 0; mapKey < kNumInsertions; ++mapKey)
  2019. {
  2020. A& a = map[mapKey % kModuloForDuplicates];
  2021. a.m_int += 1;
  2022. }
  2023. }
  2024. }
  2025. BENCHMARK(BM_UnorderedMap_InsertDuplicatesViaBracket);
  2026. } // namespace Benchmark
  2027. #endif // HAVE_BENCHMARK