hash_ut.cpp 38 KB

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