hash_ut.cpp 36 KB

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