hash_ut.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336
  1. #include "hash.h"
  2. #include "hash_multi_map.h"
  3. #include "vector.h"
  4. #include "hash_set.h"
  5. #include <library/cpp/testing/common/probe.h>
  6. #include <library/cpp/testing/unittest/registar.h>
  7. #include <utility>
  8. #include <util/str_stl.h>
  9. #include <util/digest/multi.h>
  10. static const char star = 42;
  11. class THashTest: public TTestBase {
  12. UNIT_TEST_SUITE(THashTest);
  13. UNIT_TEST(TestHMapConstructorsAndAssignments);
  14. UNIT_TEST(TestHMap1);
  15. UNIT_TEST(TestHMapEqualityOperator);
  16. UNIT_TEST(TestHMMapEqualityOperator);
  17. UNIT_TEST(TestHMMapConstructorsAndAssignments);
  18. UNIT_TEST(TestHMMap1);
  19. UNIT_TEST(TestHMMapHas);
  20. UNIT_TEST(TestHSetConstructorsAndAssignments);
  21. UNIT_TEST(TestHSetSize);
  22. UNIT_TEST(TestHSet2);
  23. UNIT_TEST(TestHSetEqualityOperator);
  24. UNIT_TEST(TestHMSetConstructorsAndAssignments);
  25. UNIT_TEST(TestHMSetSize);
  26. UNIT_TEST(TestHMSet1);
  27. UNIT_TEST(TestHMSetEqualityOperator);
  28. UNIT_TEST(TestHMSetEmplace);
  29. UNIT_TEST(TestInsertErase);
  30. UNIT_TEST(TestResizeOnInsertSmartPtrBug)
  31. UNIT_TEST(TestEmpty);
  32. UNIT_TEST(TestDefaultConstructor);
  33. UNIT_TEST(TestSizeOf);
  34. UNIT_TEST(TestInvariants);
  35. UNIT_TEST(TestAllocation);
  36. UNIT_TEST(TestInsertCopy);
  37. UNIT_TEST(TestEmplace);
  38. UNIT_TEST(TestEmplaceNoresize);
  39. UNIT_TEST(TestEmplaceDirect);
  40. UNIT_TEST(TestTryEmplace);
  41. UNIT_TEST(TestTryEmplaceCopyKey);
  42. UNIT_TEST(TestInsertOrAssign);
  43. UNIT_TEST(TestHMMapEmplace);
  44. UNIT_TEST(TestHMMapEmplaceNoresize);
  45. UNIT_TEST(TestHMMapEmplaceDirect);
  46. UNIT_TEST(TestHSetEmplace);
  47. UNIT_TEST(TestHSetEmplaceNoresize);
  48. UNIT_TEST(TestHSetEmplaceDirect);
  49. UNIT_TEST(TestNonCopyable);
  50. UNIT_TEST(TestValueInitialization);
  51. UNIT_TEST(TestAssignmentClear);
  52. UNIT_TEST(TestReleaseNodes);
  53. UNIT_TEST(TestAt);
  54. UNIT_TEST(TestHMapInitializerList);
  55. UNIT_TEST(TestHMMapInitializerList);
  56. UNIT_TEST(TestHSetInitializerList);
  57. UNIT_TEST(TestHMSetInitializerList);
  58. UNIT_TEST(TestHSetInsertInitializerList);
  59. UNIT_TEST(TestTupleHash);
  60. UNIT_TEST(TestStringHash);
  61. UNIT_TEST_SUITE_END();
  62. using hmset = THashMultiSet<char, hash<char>, TEqualTo<char>>;
  63. protected:
  64. void TestHMapConstructorsAndAssignments();
  65. void TestHMap1();
  66. void TestHMapEqualityOperator();
  67. void TestHMMapEqualityOperator();
  68. void TestHMMapConstructorsAndAssignments();
  69. void TestHMMap1();
  70. void TestHMMapHas();
  71. void TestHSetConstructorsAndAssignments();
  72. void TestHSetSize();
  73. void TestHSet2();
  74. void TestHSetEqualityOperator();
  75. void TestHMSetConstructorsAndAssignments();
  76. void TestHMSetSize();
  77. void TestHMSet1();
  78. void TestHMSetEqualityOperator();
  79. void TestHMSetEmplace();
  80. void TestInsertErase();
  81. void TestResizeOnInsertSmartPtrBug();
  82. void TestEmpty();
  83. void TestDefaultConstructor();
  84. void TestSizeOf();
  85. void TestInvariants();
  86. void TestAllocation();
  87. void TestInsertCopy();
  88. void TestEmplace();
  89. void TestEmplaceNoresize();
  90. void TestEmplaceDirect();
  91. void TestTryEmplace();
  92. void TestTryEmplaceCopyKey();
  93. void TestInsertOrAssign();
  94. void TestHSetEmplace();
  95. void TestHSetEmplaceNoresize();
  96. void TestHSetEmplaceDirect();
  97. void TestHMMapEmplace();
  98. void TestHMMapEmplaceNoresize();
  99. void TestHMMapEmplaceDirect();
  100. void TestNonCopyable();
  101. void TestValueInitialization();
  102. void TestAssignmentClear();
  103. void TestReleaseNodes();
  104. void TestAt();
  105. void TestHMapInitializerList();
  106. void TestHMMapInitializerList();
  107. void TestHSetInitializerList();
  108. void TestHMSetInitializerList();
  109. void TestHSetInsertInitializerList();
  110. void TestTupleHash();
  111. void TestStringHash();
  112. };
  113. UNIT_TEST_SUITE_REGISTRATION(THashTest);
  114. void THashTest::TestHMapConstructorsAndAssignments() {
  115. using container = THashMap<TString, int>;
  116. container c1;
  117. c1["one"] = 1;
  118. c1["two"] = 2;
  119. container c2(c1);
  120. UNIT_ASSERT_VALUES_EQUAL(2, c1.size());
  121. UNIT_ASSERT_VALUES_EQUAL(2, c2.size());
  122. UNIT_ASSERT_VALUES_EQUAL(1, c1.at("one")); /* Note: fails under MSVC since it does not support implicit generation of move constructors. */
  123. UNIT_ASSERT_VALUES_EQUAL(2, c2.at("two"));
  124. container c3(std::move(c1));
  125. UNIT_ASSERT_VALUES_EQUAL(0, c1.size());
  126. UNIT_ASSERT_VALUES_EQUAL(2, c3.size());
  127. UNIT_ASSERT_VALUES_EQUAL(1, c3.at("one"));
  128. c2["three"] = 3;
  129. c3 = c2;
  130. UNIT_ASSERT_VALUES_EQUAL(3, c2.size());
  131. UNIT_ASSERT_VALUES_EQUAL(3, c3.size());
  132. UNIT_ASSERT_VALUES_EQUAL(3, c3.at("three"));
  133. c2["four"] = 4;
  134. c3 = std::move(c2);
  135. UNIT_ASSERT_VALUES_EQUAL(0, c2.size());
  136. UNIT_ASSERT_VALUES_EQUAL(4, c3.size());
  137. UNIT_ASSERT_VALUES_EQUAL(4, c3.at("four"));
  138. const container c4{
  139. {"one", 1},
  140. {"two", 2},
  141. {"three", 3},
  142. {"four", 4},
  143. };
  144. UNIT_ASSERT_VALUES_EQUAL(4, c4.size());
  145. UNIT_ASSERT_VALUES_EQUAL(1, c4.at("one"));
  146. UNIT_ASSERT_VALUES_EQUAL(2, c4.at("two"));
  147. UNIT_ASSERT_VALUES_EQUAL(3, c4.at("three"));
  148. UNIT_ASSERT_VALUES_EQUAL(4, c4.at("four"));
  149. // non-existent values must be zero-initialized
  150. UNIT_ASSERT_VALUES_EQUAL(c1["nonexistent"], 0);
  151. }
  152. void THashTest::TestHMap1() {
  153. using maptype = THashMap<char, TString, THash<char>, TEqualTo<char>>;
  154. maptype m;
  155. // Store mappings between roman numerals and decimals.
  156. m['l'] = "50";
  157. m['x'] = "20"; // Deliberate mistake.
  158. m['v'] = "5";
  159. m['i'] = "1";
  160. UNIT_ASSERT(!strcmp(m['x'].c_str(), "20"));
  161. m['x'] = "10"; // Correct mistake.
  162. UNIT_ASSERT(!strcmp(m['x'].c_str(), "10"));
  163. UNIT_ASSERT(!m.contains('z'));
  164. UNIT_ASSERT(!strcmp(m['z'].c_str(), ""));
  165. UNIT_ASSERT(m.contains('z'));
  166. UNIT_ASSERT(m.count('z') == 1);
  167. auto p = m.insert(std::pair<const char, TString>('c', TString("100")));
  168. UNIT_ASSERT(p.second);
  169. p = m.insert(std::pair<const char, TString>('c', TString("100")));
  170. UNIT_ASSERT(!p.second);
  171. // Some iterators compare check, really compile time checks
  172. maptype::iterator ite(m.begin());
  173. maptype::const_iterator cite(m.begin());
  174. cite = m.begin();
  175. maptype const& cm = m;
  176. cite = cm.begin();
  177. UNIT_ASSERT((maptype::const_iterator)ite == cite);
  178. UNIT_ASSERT(!((maptype::const_iterator)ite != cite));
  179. UNIT_ASSERT(cite == (maptype::const_iterator)ite);
  180. UNIT_ASSERT(!(cite != (maptype::const_iterator)ite));
  181. }
  182. void THashTest::TestHMapEqualityOperator() {
  183. using container = THashMap<TString, int>;
  184. container base;
  185. base["one"] = 1;
  186. base["two"] = 2;
  187. container c1(base);
  188. UNIT_ASSERT(c1 == base);
  189. container c2;
  190. c2["two"] = 2;
  191. c2["one"] = 1;
  192. UNIT_ASSERT(c2 == base);
  193. c2["three"] = 3;
  194. UNIT_ASSERT(c2 != base);
  195. container c3(base);
  196. c3["one"] = 0;
  197. UNIT_ASSERT(c3 != base);
  198. }
  199. void THashTest::TestHMMapEqualityOperator() {
  200. using container = THashMultiMap<TString, int>;
  201. using value = container::value_type;
  202. container base;
  203. base.insert(value("one", 1));
  204. base.insert(value("one", -1));
  205. base.insert(value("two", 2));
  206. container c1(base);
  207. UNIT_ASSERT(c1 == base);
  208. container c2;
  209. c2.insert(value("two", 2));
  210. c2.insert(value("one", -1));
  211. c2.insert(value("one", 1));
  212. UNIT_ASSERT(c2 == base);
  213. c2.insert(value("three", 3));
  214. UNIT_ASSERT(c2 != base);
  215. container c3;
  216. c3.insert(value("one", 0));
  217. c3.insert(value("one", -1));
  218. c3.insert(value("two", 2));
  219. UNIT_ASSERT(c3 != base);
  220. container c4;
  221. c4.insert(value("one", 1));
  222. c4.insert(value("one", -1));
  223. c4.insert(value("one", 0));
  224. c4.insert(value("two", 2));
  225. UNIT_ASSERT(c3 != base);
  226. }
  227. void THashTest::TestHMMapConstructorsAndAssignments() {
  228. using container = THashMultiMap<TString, int>;
  229. container c1;
  230. c1.insert(container::value_type("one", 1));
  231. c1.insert(container::value_type("two", 2));
  232. container c2(c1);
  233. UNIT_ASSERT_VALUES_EQUAL(2, c1.size());
  234. UNIT_ASSERT_VALUES_EQUAL(2, c2.size());
  235. container c3(std::move(c1));
  236. UNIT_ASSERT_VALUES_EQUAL(0, c1.size());
  237. UNIT_ASSERT_VALUES_EQUAL(2, c3.size());
  238. c2.insert(container::value_type("three", 3));
  239. c3 = c2;
  240. UNIT_ASSERT_VALUES_EQUAL(3, c2.size());
  241. UNIT_ASSERT_VALUES_EQUAL(3, c3.size());
  242. c2.insert(container::value_type("four", 4));
  243. c3 = std::move(c2);
  244. UNIT_ASSERT_VALUES_EQUAL(0, c2.size());
  245. UNIT_ASSERT_VALUES_EQUAL(4, c3.size());
  246. }
  247. void THashTest::TestHMMap1() {
  248. using mmap = THashMultiMap<char, int, THash<char>, TEqualTo<char>>;
  249. mmap m;
  250. UNIT_ASSERT(m.count('X') == 0);
  251. m.insert(std::pair<const char, int>('X', 10)); // Standard way.
  252. UNIT_ASSERT(m.count('X') == 1);
  253. m.insert(std::pair<const char, int>('X', 20)); // jbuck: standard way
  254. UNIT_ASSERT(m.count('X') == 2);
  255. m.insert(std::pair<const char, int>('Y', 32)); // jbuck: standard way
  256. mmap::iterator i = m.find('X'); // Find first match.
  257. UNIT_ASSERT((*i).first == 'X');
  258. UNIT_ASSERT((*i).second == 10);
  259. ++i;
  260. UNIT_ASSERT((*i).first == 'X');
  261. UNIT_ASSERT((*i).second == 20);
  262. i = m.find('Y');
  263. UNIT_ASSERT((*i).first == 'Y');
  264. UNIT_ASSERT((*i).second == 32);
  265. i = m.find('Z');
  266. UNIT_ASSERT(i == m.end());
  267. size_t count = m.erase('X');
  268. UNIT_ASSERT(count == 2);
  269. // Some iterators compare check, really compile time checks
  270. mmap::iterator ite(m.begin());
  271. mmap::const_iterator cite(m.begin());
  272. UNIT_ASSERT((mmap::const_iterator)ite == cite);
  273. UNIT_ASSERT(!((mmap::const_iterator)ite != cite));
  274. UNIT_ASSERT(cite == (mmap::const_iterator)ite);
  275. UNIT_ASSERT(!(cite != (mmap::const_iterator)ite));
  276. using HMapType = THashMultiMap<size_t, size_t>;
  277. HMapType hmap;
  278. // We fill the map to implicitely start a rehash.
  279. for (size_t counter = 0; counter < 3077; ++counter) {
  280. hmap.insert(HMapType::value_type(1, counter));
  281. }
  282. hmap.insert(HMapType::value_type(12325, 1));
  283. hmap.insert(HMapType::value_type(12325, 2));
  284. UNIT_ASSERT(hmap.count(12325) == 2);
  285. // At this point 23 goes to the same bucket as 12325, it used to reveal a bug.
  286. hmap.insert(HMapType::value_type(23, 0));
  287. UNIT_ASSERT(hmap.count(12325) == 2);
  288. UNIT_ASSERT(hmap.bucket_count() > 3000);
  289. for (size_t n = 0; n < 10; n++) {
  290. hmap.clear();
  291. hmap.insert(HMapType::value_type(1, 2));
  292. }
  293. UNIT_ASSERT(hmap.bucket_count() < 30);
  294. }
  295. void THashTest::TestHMMapHas() {
  296. using mmap = THashMultiMap<char, int, THash<char>, TEqualTo<char>>;
  297. mmap m;
  298. m.insert(std::pair<const char, int>('X', 10));
  299. m.insert(std::pair<const char, int>('X', 20));
  300. m.insert(std::pair<const char, int>('Y', 32));
  301. UNIT_ASSERT(m.contains('X'));
  302. UNIT_ASSERT(m.contains('Y'));
  303. UNIT_ASSERT(!m.contains('Z'));
  304. }
  305. void THashTest::TestHSetConstructorsAndAssignments() {
  306. using container = THashSet<int>;
  307. container c1;
  308. c1.insert(100);
  309. c1.insert(200);
  310. container c2(c1);
  311. UNIT_ASSERT_VALUES_EQUAL(2, c1.size());
  312. UNIT_ASSERT_VALUES_EQUAL(2, c2.size());
  313. UNIT_ASSERT(c1.contains(100));
  314. UNIT_ASSERT(c2.contains(200));
  315. container c3(std::move(c1));
  316. UNIT_ASSERT_VALUES_EQUAL(0, c1.size());
  317. UNIT_ASSERT_VALUES_EQUAL(2, c3.size());
  318. UNIT_ASSERT(c3.contains(100));
  319. c2.insert(300);
  320. c3 = c2;
  321. UNIT_ASSERT_VALUES_EQUAL(3, c2.size());
  322. UNIT_ASSERT_VALUES_EQUAL(3, c3.size());
  323. UNIT_ASSERT(c3.contains(300));
  324. c2.insert(400);
  325. c3 = std::move(c2);
  326. UNIT_ASSERT_VALUES_EQUAL(0, c2.size());
  327. UNIT_ASSERT_VALUES_EQUAL(4, c3.size());
  328. UNIT_ASSERT(c3.contains(400));
  329. container c4 = {1, 2, 3};
  330. UNIT_ASSERT_VALUES_EQUAL(c4.size(), 3);
  331. UNIT_ASSERT(c4.contains(1));
  332. UNIT_ASSERT(c4.contains(2));
  333. UNIT_ASSERT(c4.contains(3));
  334. }
  335. void THashTest::TestHSetSize() {
  336. using container = THashSet<int>;
  337. container c;
  338. c.insert(100);
  339. c.insert(200);
  340. UNIT_ASSERT_VALUES_EQUAL(2, c.size());
  341. c.insert(200);
  342. UNIT_ASSERT_VALUES_EQUAL(2, c.size());
  343. }
  344. void THashTest::TestHSet2() {
  345. THashSet<int, THash<int>, TEqualTo<int>> s;
  346. auto p = s.insert(42);
  347. UNIT_ASSERT(p.second);
  348. UNIT_ASSERT(*(p.first) == 42);
  349. p = s.insert(42);
  350. UNIT_ASSERT(!p.second);
  351. }
  352. void THashTest::TestHSetEqualityOperator() {
  353. using container = THashSet<int>;
  354. container base;
  355. base.insert(1);
  356. base.insert(2);
  357. container c1(base);
  358. UNIT_ASSERT(c1 == base);
  359. c1.insert(1);
  360. UNIT_ASSERT(c1 == base);
  361. c1.insert(3);
  362. UNIT_ASSERT(c1 != base);
  363. container c2;
  364. c2.insert(2);
  365. c2.insert(1);
  366. UNIT_ASSERT(c2 == base);
  367. container c3;
  368. c3.insert(1);
  369. UNIT_ASSERT(c3 != base);
  370. }
  371. void THashTest::TestHMSetConstructorsAndAssignments() {
  372. using container = THashMultiSet<int>;
  373. container c1;
  374. c1.insert(100);
  375. c1.insert(200);
  376. container c2(c1);
  377. UNIT_ASSERT_VALUES_EQUAL(2, c1.size());
  378. UNIT_ASSERT_VALUES_EQUAL(2, c2.size());
  379. UNIT_ASSERT(c1.find(100) != c1.end());
  380. UNIT_ASSERT(c2.find(200) != c2.end());
  381. container c3(std::move(c1));
  382. UNIT_ASSERT_VALUES_EQUAL(0, c1.size());
  383. UNIT_ASSERT_VALUES_EQUAL(2, c3.size());
  384. UNIT_ASSERT(c3.find(100) != c3.end());
  385. c2.insert(300);
  386. c3 = c2;
  387. UNIT_ASSERT_VALUES_EQUAL(3, c2.size());
  388. UNIT_ASSERT_VALUES_EQUAL(3, c3.size());
  389. UNIT_ASSERT(c3.find(300) != c3.end());
  390. c2.insert(400);
  391. c3 = std::move(c2);
  392. UNIT_ASSERT_VALUES_EQUAL(0, c2.size());
  393. UNIT_ASSERT_VALUES_EQUAL(4, c3.size());
  394. UNIT_ASSERT(c3.find(400) != c3.end());
  395. }
  396. void THashTest::TestHMSetSize() {
  397. using container = THashMultiSet<int>;
  398. container c;
  399. c.insert(100);
  400. c.insert(200);
  401. UNIT_ASSERT_VALUES_EQUAL(2, c.size());
  402. c.insert(200);
  403. UNIT_ASSERT_VALUES_EQUAL(3, c.size());
  404. }
  405. void THashTest::TestHMSet1() {
  406. hmset s;
  407. UNIT_ASSERT(s.count(star) == 0);
  408. s.insert(star);
  409. UNIT_ASSERT(s.count(star) == 1);
  410. s.insert(star);
  411. UNIT_ASSERT(s.count(star) == 2);
  412. auto i = s.find(char(40));
  413. UNIT_ASSERT(i == s.end());
  414. i = s.find(star);
  415. UNIT_ASSERT(i != s.end());
  416. UNIT_ASSERT(*i == '*');
  417. UNIT_ASSERT(s.erase(star) == 2);
  418. }
  419. void THashTest::TestHMSetEqualityOperator() {
  420. using container = THashMultiSet<int>;
  421. container base;
  422. base.insert(1);
  423. base.insert(1);
  424. base.insert(2);
  425. container c1(base);
  426. UNIT_ASSERT(c1 == base);
  427. c1.insert(1);
  428. UNIT_ASSERT(!(c1 == base));
  429. container c2;
  430. c2.insert(2);
  431. c2.insert(1);
  432. c2.insert(1);
  433. UNIT_ASSERT(c2 == base);
  434. container c3;
  435. c3.insert(1);
  436. c3.insert(2);
  437. UNIT_ASSERT(!(c3 == base));
  438. c3.insert(1);
  439. UNIT_ASSERT(c3 == base);
  440. c3.insert(3);
  441. UNIT_ASSERT(!(c3 == base));
  442. }
  443. void THashTest::TestHMSetEmplace() {
  444. class TKey: public NTesting::TProbe {
  445. public:
  446. TKey(NTesting::TProbeState* state, int key)
  447. : TProbe(state)
  448. , Key_(key)
  449. {
  450. }
  451. operator size_t() const {
  452. return THash<int>()(Key_);
  453. }
  454. bool operator==(const TKey& other) const {
  455. return Key_ == other.Key_;
  456. }
  457. private:
  458. int Key_;
  459. };
  460. NTesting::TProbeState state;
  461. {
  462. THashMultiSet<TKey> c;
  463. c.emplace(&state, 1);
  464. c.emplace(&state, 1);
  465. c.emplace(&state, 2);
  466. UNIT_ASSERT_EQUAL(state.CopyAssignments, 0);
  467. UNIT_ASSERT_EQUAL(state.MoveAssignments, 0);
  468. UNIT_ASSERT_EQUAL(state.Constructors, 3);
  469. UNIT_ASSERT_EQUAL(state.MoveConstructors, 0);
  470. UNIT_ASSERT_EQUAL(c.count(TKey(&state, 1)), 2);
  471. UNIT_ASSERT_EQUAL(c.count(TKey(&state, 2)), 1);
  472. UNIT_ASSERT_EQUAL(c.count(TKey(&state, 3)), 0);
  473. UNIT_ASSERT_EQUAL(state.Constructors, 6);
  474. UNIT_ASSERT_EQUAL(state.Destructors, 3);
  475. }
  476. UNIT_ASSERT_EQUAL(state.CopyAssignments, 0);
  477. UNIT_ASSERT_EQUAL(state.MoveAssignments, 0);
  478. UNIT_ASSERT_EQUAL(state.CopyConstructors, 0);
  479. UNIT_ASSERT_EQUAL(state.MoveConstructors, 0);
  480. UNIT_ASSERT_EQUAL(state.Constructors, 6);
  481. UNIT_ASSERT_EQUAL(state.Destructors, 6);
  482. }
  483. void THashTest::TestInsertErase() {
  484. using hmap = THashMap<TString, size_t, THash<TString>, TEqualTo<TString>>;
  485. using val_type = hmap::value_type;
  486. {
  487. hmap values;
  488. UNIT_ASSERT(values.insert(val_type("foo", 0)).second);
  489. UNIT_ASSERT(values.insert(val_type("bar", 0)).second);
  490. UNIT_ASSERT(values.insert(val_type("abc", 0)).second);
  491. UNIT_ASSERT(values.erase("foo") == 1);
  492. UNIT_ASSERT(values.erase("bar") == 1);
  493. UNIT_ASSERT(values.erase("abc") == 1);
  494. }
  495. {
  496. hmap values;
  497. UNIT_ASSERT(values.insert(val_type("foo", 0)).second);
  498. UNIT_ASSERT(values.insert(val_type("bar", 0)).second);
  499. UNIT_ASSERT(values.insert(val_type("abc", 0)).second);
  500. UNIT_ASSERT(values.erase("abc") == 1);
  501. UNIT_ASSERT(values.erase("bar") == 1);
  502. UNIT_ASSERT(values.erase("foo") == 1);
  503. }
  504. }
  505. namespace {
  506. struct TItem: public TSimpleRefCount<TItem> {
  507. const TString Key;
  508. const TString Value;
  509. TItem(const TString& key, const TString& value)
  510. : Key(key)
  511. , Value(value)
  512. {
  513. }
  514. };
  515. using TItemPtr = TIntrusivePtr<TItem>;
  516. struct TSelectKey {
  517. const TString& operator()(const TItemPtr& item) const {
  518. return item->Key;
  519. }
  520. };
  521. using TItemMapBase = THashTable<
  522. TItemPtr,
  523. TString,
  524. THash<TString>,
  525. TSelectKey,
  526. TEqualTo<TString>,
  527. std::allocator<TItemPtr>>;
  528. struct TItemMap: public TItemMapBase {
  529. TItemMap()
  530. : TItemMapBase(1, THash<TString>(), TEqualTo<TString>())
  531. {
  532. }
  533. TItem& Add(const TString& key, const TString& value) {
  534. insert_ctx ins;
  535. iterator it = find_i(key, ins);
  536. if (it == end()) {
  537. it = insert_direct(new TItem(key, value), ins);
  538. }
  539. return **it;
  540. }
  541. };
  542. }
  543. void THashTest::TestResizeOnInsertSmartPtrBug() {
  544. TItemMap map;
  545. map.Add("key1", "value1");
  546. map.Add("key2", "value2");
  547. map.Add("key3", "value3");
  548. map.Add("key4", "value4");
  549. map.Add("key5", "value5");
  550. map.Add("key6", "value6");
  551. map.Add("key7", "value7");
  552. TItem& item = map.Add("key8", "value8");
  553. UNIT_ASSERT_EQUAL(item.Key, "key8");
  554. UNIT_ASSERT_EQUAL(item.Value, "value8");
  555. }
  556. template <typename T>
  557. static void EmptyAndInsertTest(typename T::value_type v) {
  558. T c;
  559. UNIT_ASSERT(!c);
  560. c.insert(v);
  561. UNIT_ASSERT(c);
  562. }
  563. void THashTest::TestEmpty() {
  564. EmptyAndInsertTest<THashSet<int>>(1);
  565. EmptyAndInsertTest<THashMap<int, int>>(std::pair<int, int>(1, 2));
  566. EmptyAndInsertTest<THashMultiMap<int, int>>(std::pair<int, int>(1, 2));
  567. }
  568. void THashTest::TestDefaultConstructor() {
  569. THashSet<int> set;
  570. UNIT_ASSERT(set.begin() == set.end());
  571. UNIT_ASSERT(set.find(0) == set.end());
  572. auto range = set.equal_range(0);
  573. UNIT_ASSERT(range.first == range.second);
  574. }
  575. void THashTest::TestSizeOf() {
  576. /* This test checks that we don't waste memory when all functors passed to
  577. * THashTable are empty. It does rely on knowledge of THashTable internals,
  578. * so if those change, the test will have to be adjusted accordingly. */
  579. size_t expectedSize = sizeof(uintptr_t) + 3 * sizeof(size_t);
  580. UNIT_ASSERT_VALUES_EQUAL(sizeof(THashMap<int, int>), expectedSize);
  581. UNIT_ASSERT_VALUES_EQUAL(sizeof(THashMap<std::pair<int, int>, std::pair<int, int>>), expectedSize);
  582. }
  583. void THashTest::TestInvariants() {
  584. std::set<int> reference_set;
  585. THashSet<int> set;
  586. for (int i = 0; i < 1000; i++) {
  587. set.insert(i);
  588. reference_set.insert(i);
  589. }
  590. UNIT_ASSERT_VALUES_EQUAL(set.size(), 1000);
  591. int count0 = 0;
  592. for (int i = 0; i < 1000; i++) {
  593. count0 += (set.find(i) != set.end()) ? 1 : 0;
  594. }
  595. UNIT_ASSERT_VALUES_EQUAL(count0, 1000);
  596. int count1 = 0;
  597. for (auto pos = set.begin(); pos != set.end(); pos++) {
  598. ++count1;
  599. }
  600. UNIT_ASSERT_VALUES_EQUAL(count1, 1000);
  601. int count2 = 0;
  602. for (const int& value : set) {
  603. count2 += (reference_set.find(value) != reference_set.end()) ? 1 : 0;
  604. }
  605. UNIT_ASSERT_VALUES_EQUAL(count2, 1000);
  606. }
  607. struct TAllocatorCounters {
  608. TAllocatorCounters()
  609. : Allocations(0)
  610. , Deallocations(0)
  611. {
  612. }
  613. ~TAllocatorCounters() {
  614. std::allocator<char> allocator;
  615. /* Release whatever was (intentionally) leaked. */
  616. for (const auto& chunk : Chunks) {
  617. allocator.deallocate(static_cast<char*>(chunk.first), chunk.second);
  618. }
  619. }
  620. size_t Allocations;
  621. size_t Deallocations;
  622. TSet<std::pair<void*, size_t>> Chunks;
  623. };
  624. template <class T>
  625. class TCountingAllocator: public std::allocator<T> {
  626. using base_type = std::allocator<T>;
  627. public:
  628. using size_type = typename base_type::size_type;
  629. template <class Other>
  630. struct rebind {
  631. using other = TCountingAllocator<Other>;
  632. };
  633. TCountingAllocator()
  634. : Counters_(nullptr)
  635. {
  636. }
  637. TCountingAllocator(TAllocatorCounters* counters)
  638. : Counters_(counters)
  639. {
  640. Y_ASSERT(counters);
  641. }
  642. template <class Other>
  643. TCountingAllocator(const TCountingAllocator<Other>& other)
  644. : Counters_(other.Counters)
  645. {
  646. }
  647. T* allocate(size_type n) {
  648. auto result = base_type::allocate(n);
  649. if (Counters_) {
  650. ++Counters_->Allocations;
  651. Counters_->Chunks.emplace(result, n * sizeof(T));
  652. }
  653. return result;
  654. }
  655. void deallocate(T* p, size_type n) {
  656. if (Counters_) {
  657. ++Counters_->Deallocations;
  658. Counters_->Chunks.erase(std::make_pair(p, n * sizeof(T)));
  659. }
  660. base_type::deallocate(p, n);
  661. }
  662. private:
  663. TAllocatorCounters* Counters_;
  664. };
  665. void THashTest::TestAllocation() {
  666. TAllocatorCounters counters;
  667. using int_set = THashSet<int, THash<int>, TEqualTo<int>, TCountingAllocator<int>>;
  668. {
  669. int_set set0(&counters);
  670. int_set set1(set0);
  671. set0.clear();
  672. int_set set2(&counters);
  673. set2 = set1;
  674. UNIT_ASSERT_VALUES_EQUAL(counters.Allocations, 0); /* Copying around null sets should not trigger allocations. */
  675. set0.insert(0);
  676. UNIT_ASSERT_VALUES_EQUAL(counters.Allocations, 2); /* One for buckets array, one for a new node. */
  677. set0.clear();
  678. set1 = set0;
  679. int_set set3(set0);
  680. UNIT_ASSERT_VALUES_EQUAL(counters.Allocations, 2); /* Copying from an empty set with allocated buckets should not trigger allocations. */
  681. for (int i = 0; i < 1000; i++) {
  682. set0.insert(i);
  683. }
  684. size_t allocations = counters.Allocations;
  685. set0.clear();
  686. UNIT_ASSERT_VALUES_EQUAL(counters.Allocations, allocations); /* clear() should not trigger allocations. */
  687. }
  688. UNIT_ASSERT_VALUES_EQUAL(counters.Allocations, counters.Deallocations);
  689. }
  690. template <int Value>
  691. class TNonCopyableInt {
  692. public:
  693. explicit TNonCopyableInt(int) {
  694. }
  695. TNonCopyableInt() = delete;
  696. TNonCopyableInt(const TNonCopyableInt&) = delete;
  697. TNonCopyableInt(TNonCopyable&&) = delete;
  698. TNonCopyableInt& operator=(const TNonCopyable&) = delete;
  699. TNonCopyableInt& operator=(TNonCopyable&&) = delete;
  700. operator int() const {
  701. return Value;
  702. }
  703. };
  704. void THashTest::TestInsertCopy() {
  705. THashMap<int, int> hash;
  706. /* Insertion should not make copies of the provided key. */
  707. hash[TNonCopyableInt<0>(0)] = 0;
  708. }
  709. void THashTest::TestEmplace() {
  710. using hash_t = THashMap<int, TNonCopyableInt<0>>;
  711. hash_t hash;
  712. hash.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(0));
  713. auto it = hash.find(1);
  714. UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(it->second), 0);
  715. }
  716. void THashTest::TestEmplaceNoresize() {
  717. using hash_t = THashMap<int, TNonCopyableInt<0>>;
  718. hash_t hash;
  719. hash.reserve(1);
  720. hash.emplace_noresize(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(0));
  721. auto it = hash.find(1);
  722. UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(it->second), 0);
  723. }
  724. void THashTest::TestEmplaceDirect() {
  725. using hash_t = THashMap<int, TNonCopyableInt<0>>;
  726. hash_t hash;
  727. hash_t::insert_ctx ins;
  728. hash.find(1, ins);
  729. hash.emplace_direct(ins, std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(0));
  730. auto it = hash.find(1);
  731. UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(it->second), 0);
  732. }
  733. void THashTest::TestTryEmplace() {
  734. static unsigned counter = 0u;
  735. struct TCountConstruct {
  736. explicit TCountConstruct(int v)
  737. : value(v)
  738. {
  739. ++counter;
  740. }
  741. TCountConstruct(const TCountConstruct&) = delete;
  742. int value;
  743. };
  744. THashMap<int, TCountConstruct> hash;
  745. {
  746. // try_emplace does not copy key if key is rvalue
  747. auto r = hash.try_emplace(TNonCopyableInt<0>(0), 1);
  748. UNIT_ASSERT(r.second);
  749. UNIT_ASSERT_VALUES_EQUAL(1, counter);
  750. UNIT_ASSERT_VALUES_EQUAL(1, r.first->second.value);
  751. }
  752. {
  753. auto r = hash.try_emplace(0, 2);
  754. UNIT_ASSERT(!r.second);
  755. UNIT_ASSERT_VALUES_EQUAL(1, counter);
  756. UNIT_ASSERT_VALUES_EQUAL(1, r.first->second.value);
  757. }
  758. }
  759. void THashTest::TestTryEmplaceCopyKey() {
  760. static unsigned counter = 0u;
  761. struct TCountCopy {
  762. explicit TCountCopy(int i)
  763. : Value(i)
  764. {
  765. }
  766. TCountCopy(const TCountCopy& other)
  767. : Value(other.Value)
  768. {
  769. ++counter;
  770. }
  771. operator int() const {
  772. return Value;
  773. }
  774. int Value;
  775. };
  776. THashMap<TCountCopy, TNonCopyableInt<0>> hash;
  777. TCountCopy key(1);
  778. {
  779. // try_emplace copy key if key is lvalue
  780. auto r = hash.try_emplace(key, 1);
  781. UNIT_ASSERT(r.second);
  782. UNIT_ASSERT_VALUES_EQUAL(1, counter);
  783. }
  784. {
  785. // no insert - no copy
  786. auto r = hash.try_emplace(key, 2);
  787. UNIT_ASSERT(!r.second);
  788. UNIT_ASSERT_VALUES_EQUAL(1, counter);
  789. }
  790. }
  791. void THashTest::TestInsertOrAssign() {
  792. static int constructorCounter = 0;
  793. static int assignmentCounter = 0;
  794. struct TCountConstruct {
  795. explicit TCountConstruct(int v)
  796. : Value(v)
  797. {
  798. ++constructorCounter;
  799. }
  800. TCountConstruct& operator=(int v) {
  801. Value = v;
  802. ++assignmentCounter;
  803. return *this;
  804. }
  805. TCountConstruct(const TCountConstruct&) = delete;
  806. int Value;
  807. };
  808. THashMap<int, TCountConstruct> hash;
  809. {
  810. auto r = hash.insert_or_assign(TNonCopyableInt<4>(4), 1);
  811. UNIT_ASSERT(r.second);
  812. UNIT_ASSERT_VALUES_EQUAL(1, hash.size());
  813. UNIT_ASSERT_VALUES_EQUAL(1, constructorCounter);
  814. UNIT_ASSERT_VALUES_EQUAL(0, assignmentCounter);
  815. UNIT_ASSERT_VALUES_EQUAL(1, r.first->second.Value);
  816. }
  817. {
  818. auto r = hash.insert_or_assign(TNonCopyableInt<4>(4), 5);
  819. UNIT_ASSERT(!r.second);
  820. UNIT_ASSERT_VALUES_EQUAL(1, hash.size());
  821. UNIT_ASSERT_VALUES_EQUAL(1, constructorCounter);
  822. UNIT_ASSERT_VALUES_EQUAL(1, assignmentCounter);
  823. UNIT_ASSERT_VALUES_EQUAL(5, r.first->second.Value);
  824. }
  825. {
  826. constexpr int iterations = 200;
  827. for (int iteration = 0; iteration < iterations; ++iteration) {
  828. hash.insert_or_assign(iteration, iteration);
  829. }
  830. UNIT_ASSERT_VALUES_EQUAL(iterations, hash.size());
  831. UNIT_ASSERT_VALUES_EQUAL(iterations, constructorCounter);
  832. UNIT_ASSERT_VALUES_EQUAL(2, assignmentCounter);
  833. UNIT_ASSERT_VALUES_EQUAL(4, hash.at(4).Value);
  834. UNIT_ASSERT_VALUES_EQUAL(44, hash.at(44).Value);
  835. }
  836. }
  837. void THashTest::TestHMMapEmplace() {
  838. using hash_t = THashMultiMap<int, TNonCopyableInt<0>>;
  839. hash_t hash;
  840. hash.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(0));
  841. auto it = hash.find(1);
  842. UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(it->second), 0);
  843. }
  844. void THashTest::TestHMMapEmplaceNoresize() {
  845. using hash_t = THashMultiMap<int, TNonCopyableInt<0>>;
  846. hash_t hash;
  847. hash.reserve(1);
  848. hash.emplace_noresize(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(0));
  849. auto it = hash.find(1);
  850. UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(it->second), 0);
  851. }
  852. void THashTest::TestHMMapEmplaceDirect() {
  853. using hash_t = THashMultiMap<int, TNonCopyableInt<0>>;
  854. hash_t hash;
  855. hash_t::insert_ctx ins;
  856. hash.find(1, ins);
  857. hash.emplace_direct(ins, std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(0));
  858. auto it = hash.find(1);
  859. UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(it->second), 0);
  860. }
  861. void THashTest::TestHSetEmplace() {
  862. using hash_t = THashSet<TNonCopyableInt<0>, THash<int>, TEqualTo<int>>;
  863. hash_t hash;
  864. UNIT_ASSERT(!hash.contains(0));
  865. hash.emplace(0);
  866. UNIT_ASSERT(hash.contains(0));
  867. UNIT_ASSERT(!hash.contains(1));
  868. }
  869. void THashTest::TestHSetEmplaceNoresize() {
  870. using hash_t = THashSet<TNonCopyableInt<0>, THash<int>, TEqualTo<int>>;
  871. hash_t hash;
  872. hash.reserve(1);
  873. UNIT_ASSERT(!hash.contains(0));
  874. hash.emplace_noresize(0);
  875. UNIT_ASSERT(hash.contains(0));
  876. UNIT_ASSERT(!hash.contains(1));
  877. }
  878. void THashTest::TestHSetEmplaceDirect() {
  879. using hash_t = THashSet<TNonCopyableInt<0>, THash<int>, TEqualTo<int>>;
  880. hash_t hash;
  881. UNIT_ASSERT(!hash.contains(0));
  882. hash_t::insert_ctx ins;
  883. hash.find(0, ins);
  884. hash.emplace_direct(ins, 1);
  885. UNIT_ASSERT(hash.contains(0));
  886. UNIT_ASSERT(!hash.contains(1));
  887. }
  888. void THashTest::TestNonCopyable() {
  889. struct TValue: public TNonCopyable {
  890. int value;
  891. TValue(int _value = 0)
  892. : value(_value)
  893. {
  894. }
  895. operator int() {
  896. return value;
  897. }
  898. };
  899. THashMap<int, TValue> hash;
  900. hash.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(5));
  901. auto&& value = hash[1];
  902. UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(value), 5);
  903. auto&& not_inserted = hash[2];
  904. UNIT_ASSERT_VALUES_EQUAL(static_cast<int>(not_inserted), 0);
  905. }
  906. void THashTest::TestValueInitialization() {
  907. THashMap<int, int> hash;
  908. int& value = hash[0];
  909. /* Implicitly inserted values should be value-initialized. */
  910. UNIT_ASSERT_VALUES_EQUAL(value, 0);
  911. }
  912. void THashTest::TestAssignmentClear() {
  913. /* This one tests that assigning an empty hash resets the buckets array.
  914. * See operator= for details. */
  915. THashMap<int, int> hash;
  916. size_t emptyBucketCount = hash.bucket_count();
  917. for (int i = 0; i < 100; i++) {
  918. hash[i] = i;
  919. }
  920. hash = THashMap<int, int>();
  921. UNIT_ASSERT_VALUES_EQUAL(hash.bucket_count(), emptyBucketCount);
  922. }
  923. void THashTest::TestReleaseNodes() {
  924. TAllocatorCounters counters;
  925. using TIntSet = THashSet<int, THash<int>, TEqualTo<int>, TCountingAllocator<int>>;
  926. TIntSet set(&counters);
  927. for (int i = 0; i < 3; i++) {
  928. set.insert(i);
  929. }
  930. UNIT_ASSERT_VALUES_EQUAL(counters.Allocations, 4);
  931. set.release_nodes();
  932. UNIT_ASSERT_VALUES_EQUAL(counters.Allocations, 4);
  933. UNIT_ASSERT_VALUES_EQUAL(set.size(), 0);
  934. for (int i = 10; i < 13; i++) {
  935. set.insert(i);
  936. }
  937. UNIT_ASSERT_VALUES_EQUAL(counters.Allocations, 7);
  938. UNIT_ASSERT(set.contains(10));
  939. UNIT_ASSERT(!set.contains(0));
  940. set.basic_clear();
  941. UNIT_ASSERT_VALUES_EQUAL(counters.Deallocations, 3);
  942. TIntSet set2;
  943. set2.release_nodes();
  944. set2.insert(1);
  945. UNIT_ASSERT_VALUES_EQUAL(set2.size(), 1);
  946. }
  947. void THashTest::TestAt() {
  948. #define TEST_AT_THROWN_EXCEPTION(SRC_TYPE, DST_TYPE, KEY_TYPE, KEY, MESSAGE) \
  949. { \
  950. THashMap<SRC_TYPE, DST_TYPE> testMap; \
  951. try { \
  952. KEY_TYPE testKey = KEY; \
  953. testMap.at(testKey); \
  954. UNIT_ASSERT_C(false, "THashMap::at(\"" << KEY << "\") should throw"); \
  955. } catch (const yexception& e) { \
  956. UNIT_ASSERT_C(e.AsStrBuf().Contains(MESSAGE), "Incorrect exception description: got \"" << e.what() << "\", expected: \"" << MESSAGE << "\""); \
  957. } catch (...) { \
  958. UNIT_ASSERT_C(false, "THashMap::at(\"" << KEY << "\") should throw yexception"); \
  959. } \
  960. }
  961. TEST_AT_THROWN_EXCEPTION(TString, TString, TString, "111", "111");
  962. TEST_AT_THROWN_EXCEPTION(TString, TString, const TString, "111", "111");
  963. TEST_AT_THROWN_EXCEPTION(TString, TString, TStringBuf, "111", "111");
  964. TEST_AT_THROWN_EXCEPTION(TString, TString, const TStringBuf, "111", "111");
  965. TEST_AT_THROWN_EXCEPTION(TStringBuf, TStringBuf, const char*, "111", "111");
  966. TEST_AT_THROWN_EXCEPTION(int, int, short, 11, "11");
  967. TEST_AT_THROWN_EXCEPTION(int, int, int, -1, "-1");
  968. TEST_AT_THROWN_EXCEPTION(int, int, long, 111, "111");
  969. TEST_AT_THROWN_EXCEPTION(int, int, long long, -1000000000000ll, "-1000000000000");
  970. TEST_AT_THROWN_EXCEPTION(int, int, unsigned short, 11, "11");
  971. TEST_AT_THROWN_EXCEPTION(int, int, unsigned int, 2, "2");
  972. TEST_AT_THROWN_EXCEPTION(int, int, unsigned long, 131, "131");
  973. TEST_AT_THROWN_EXCEPTION(int, int, unsigned long long, 1000000000000ll, "1000000000000");
  974. char key[] = {11, 12, 0, 1, 2, 11, 0};
  975. TEST_AT_THROWN_EXCEPTION(TString, TString, char*, key, "\\x0B\\x0C");
  976. TEST_AT_THROWN_EXCEPTION(TString, TString, TStringBuf, TStringBuf(key, sizeof(key) - 1), "\\x0B\\x0C\\0\\1\\2\\x0B");
  977. #undef TEST_AT_THROWN_EXCEPTION
  978. }
  979. void THashTest::TestHMapInitializerList() {
  980. THashMap<TString, TString> h1 = {{"foo", "bar"}, {"bar", "baz"}, {"baz", "qux"}};
  981. THashMap<TString, TString> h2;
  982. h2.insert(std::pair<TString, TString>("foo", "bar"));
  983. h2.insert(std::pair<TString, TString>("bar", "baz"));
  984. h2.insert(std::pair<TString, TString>("baz", "qux"));
  985. UNIT_ASSERT_EQUAL(h1, h2);
  986. }
  987. void THashTest::TestHMMapInitializerList() {
  988. THashMultiMap<TString, TString> h1 = {
  989. {"foo", "bar"},
  990. {"foo", "baz"},
  991. {"baz", "qux"}};
  992. THashMultiMap<TString, TString> h2;
  993. h2.insert(std::pair<TString, TString>("foo", "bar"));
  994. h2.insert(std::pair<TString, TString>("foo", "baz"));
  995. h2.insert(std::pair<TString, TString>("baz", "qux"));
  996. UNIT_ASSERT_EQUAL(h1, h2);
  997. }
  998. void THashTest::TestHSetInitializerList() {
  999. THashSet<TString> h1 = {"foo", "bar", "baz"};
  1000. THashSet<TString> h2;
  1001. h2.insert("foo");
  1002. h2.insert("bar");
  1003. h2.insert("baz");
  1004. UNIT_ASSERT_EQUAL(h1, h2);
  1005. }
  1006. void THashTest::TestHMSetInitializerList() {
  1007. THashMultiSet<TString> h1 = {"foo", "foo", "bar", "baz"};
  1008. THashMultiSet<TString> h2;
  1009. h2.insert("foo");
  1010. h2.insert("foo");
  1011. h2.insert("bar");
  1012. h2.insert("baz");
  1013. UNIT_ASSERT_EQUAL(h1, h2);
  1014. }
  1015. namespace {
  1016. struct TFoo {
  1017. int A;
  1018. int B;
  1019. bool operator==(const TFoo& o) const {
  1020. return A == o.A && B == o.B;
  1021. }
  1022. };
  1023. }
  1024. template <>
  1025. struct THash<TFoo> {
  1026. size_t operator()(const TFoo& v) const {
  1027. return v.A ^ v.B;
  1028. }
  1029. };
  1030. template <>
  1031. void Out<TFoo>(IOutputStream& o, const TFoo& v) {
  1032. o << '{' << v.A << ';' << v.B << '}';
  1033. }
  1034. void THashTest::TestHSetInsertInitializerList() {
  1035. {
  1036. const THashSet<int> x = {1};
  1037. THashSet<int> y;
  1038. y.insert({1});
  1039. UNIT_ASSERT_VALUES_EQUAL(x, y);
  1040. }
  1041. {
  1042. const THashSet<int> x = {1, 2};
  1043. THashSet<int> y;
  1044. y.insert({1, 2});
  1045. UNIT_ASSERT_VALUES_EQUAL(x, y);
  1046. }
  1047. {
  1048. const THashSet<int> x = {1, 2, 3, 4, 5};
  1049. THashSet<int> y;
  1050. y.insert({
  1051. 1,
  1052. 2,
  1053. 3,
  1054. 4,
  1055. 5,
  1056. });
  1057. UNIT_ASSERT_VALUES_EQUAL(x, y);
  1058. }
  1059. {
  1060. const THashSet<TFoo> x = {{1, 2}};
  1061. THashSet<TFoo> y;
  1062. y.insert({{1, 2}});
  1063. UNIT_ASSERT_VALUES_EQUAL(x, y);
  1064. }
  1065. {
  1066. const THashSet<TFoo> x = {{1, 2}, {3, 4}};
  1067. THashSet<TFoo> y;
  1068. y.insert({{1, 2}, {3, 4}});
  1069. UNIT_ASSERT_VALUES_EQUAL(x, y);
  1070. }
  1071. }
  1072. /*
  1073. * Sequence for MultiHash is reversed as it calculates hash as
  1074. * f(head:tail) = f(tail)xHash(head)
  1075. */
  1076. void THashTest::TestTupleHash() {
  1077. std::tuple<int, int> tuple{1, 3};
  1078. UNIT_ASSERT_VALUES_EQUAL(THash<decltype(tuple)>()(tuple), MultiHash(3, 1));
  1079. /*
  1080. * This thing checks that we didn't break STL code
  1081. * See https://a.yandex-team.ru/arc/commit/2864838#comment-401
  1082. * for example
  1083. */
  1084. struct A {
  1085. A Foo(const std::tuple<A, float>& v) {
  1086. return std::get<A>(v);
  1087. }
  1088. };
  1089. }
  1090. void THashTest::TestStringHash() {
  1091. // Make sure that different THash<> variants behave in the same way
  1092. const size_t expected = ComputeHash(TString("hehe"));
  1093. UNIT_ASSERT_VALUES_EQUAL(ComputeHash("hehe"), expected); // char[5]
  1094. UNIT_ASSERT_VALUES_EQUAL(ComputeHash("hehe"sv), expected); // std::string_view
  1095. UNIT_ASSERT_VALUES_EQUAL(ComputeHash(TStringBuf("hehe")), expected); // TStringBuf
  1096. UNIT_ASSERT_VALUES_EQUAL(ComputeHash<const char*>("hehe"), expected); // const char*
  1097. }