small_map_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "butil/containers/small_map.h"
  5. #include <stddef.h>
  6. #include <algorithm>
  7. #include <functional>
  8. #include <map>
  9. #include "butil/containers/hash_tables.h"
  10. #include "butil/logging.h"
  11. #include <gtest/gtest.h>
  12. namespace butil {
  13. TEST(SmallMap, General) {
  14. SmallMap<hash_map<int, int> > m;
  15. EXPECT_TRUE(m.empty());
  16. m[0] = 5;
  17. EXPECT_FALSE(m.empty());
  18. EXPECT_EQ(m.size(), 1u);
  19. m[9] = 2;
  20. EXPECT_FALSE(m.empty());
  21. EXPECT_EQ(m.size(), 2u);
  22. EXPECT_EQ(m[9], 2);
  23. EXPECT_EQ(m[0], 5);
  24. EXPECT_FALSE(m.UsingFullMap());
  25. SmallMap<hash_map<int, int> >::iterator iter(m.begin());
  26. ASSERT_TRUE(iter != m.end());
  27. EXPECT_EQ(iter->first, 0);
  28. EXPECT_EQ(iter->second, 5);
  29. ++iter;
  30. ASSERT_TRUE(iter != m.end());
  31. EXPECT_EQ((*iter).first, 9);
  32. EXPECT_EQ((*iter).second, 2);
  33. ++iter;
  34. EXPECT_TRUE(iter == m.end());
  35. m[8] = 23;
  36. m[1234] = 90;
  37. m[-5] = 6;
  38. EXPECT_EQ(m[ 9], 2);
  39. EXPECT_EQ(m[ 0], 5);
  40. EXPECT_EQ(m[1234], 90);
  41. EXPECT_EQ(m[ 8], 23);
  42. EXPECT_EQ(m[ -5], 6);
  43. EXPECT_EQ(m.size(), 5u);
  44. EXPECT_FALSE(m.empty());
  45. EXPECT_TRUE(m.UsingFullMap());
  46. iter = m.begin();
  47. for (int i = 0; i < 5; i++) {
  48. EXPECT_TRUE(iter != m.end());
  49. ++iter;
  50. }
  51. EXPECT_TRUE(iter == m.end());
  52. const SmallMap<hash_map<int, int> >& ref = m;
  53. EXPECT_TRUE(ref.find(1234) != m.end());
  54. EXPECT_TRUE(ref.find(5678) == m.end());
  55. }
  56. TEST(SmallMap, PostFixIteratorIncrement) {
  57. SmallMap<hash_map<int, int> > m;
  58. m[0] = 5;
  59. m[2] = 3;
  60. {
  61. SmallMap<hash_map<int, int> >::iterator iter(m.begin());
  62. SmallMap<hash_map<int, int> >::iterator last(iter++);
  63. ++last;
  64. EXPECT_TRUE(last == iter);
  65. }
  66. {
  67. SmallMap<hash_map<int, int> >::const_iterator iter(m.begin());
  68. SmallMap<hash_map<int, int> >::const_iterator last(iter++);
  69. ++last;
  70. EXPECT_TRUE(last == iter);
  71. }
  72. }
  73. // Based on the General testcase.
  74. TEST(SmallMap, CopyConstructor) {
  75. SmallMap<hash_map<int, int> > src;
  76. {
  77. SmallMap<hash_map<int, int> > m(src);
  78. EXPECT_TRUE(m.empty());
  79. }
  80. src[0] = 5;
  81. {
  82. SmallMap<hash_map<int, int> > m(src);
  83. EXPECT_FALSE(m.empty());
  84. EXPECT_EQ(m.size(), 1u);
  85. }
  86. src[9] = 2;
  87. {
  88. SmallMap<hash_map<int, int> > m(src);
  89. EXPECT_FALSE(m.empty());
  90. EXPECT_EQ(m.size(), 2u);
  91. EXPECT_EQ(m[9], 2);
  92. EXPECT_EQ(m[0], 5);
  93. EXPECT_FALSE(m.UsingFullMap());
  94. }
  95. src[8] = 23;
  96. src[1234] = 90;
  97. src[-5] = 6;
  98. {
  99. SmallMap<hash_map<int, int> > m(src);
  100. EXPECT_EQ(m[ 9], 2);
  101. EXPECT_EQ(m[ 0], 5);
  102. EXPECT_EQ(m[1234], 90);
  103. EXPECT_EQ(m[ 8], 23);
  104. EXPECT_EQ(m[ -5], 6);
  105. EXPECT_EQ(m.size(), 5u);
  106. EXPECT_FALSE(m.empty());
  107. EXPECT_TRUE(m.UsingFullMap());
  108. }
  109. }
  110. template<class inner>
  111. static bool SmallMapIsSubset(SmallMap<inner> const& a,
  112. SmallMap<inner> const& b) {
  113. typename SmallMap<inner>::const_iterator it;
  114. for (it = a.begin(); it != a.end(); ++it) {
  115. typename SmallMap<inner>::const_iterator it_in_b = b.find(it->first);
  116. if (it_in_b == b.end() || it_in_b->second != it->second)
  117. return false;
  118. }
  119. return true;
  120. }
  121. template<class inner>
  122. static bool SmallMapEqual(SmallMap<inner> const& a,
  123. SmallMap<inner> const& b) {
  124. return SmallMapIsSubset(a, b) && SmallMapIsSubset(b, a);
  125. }
  126. TEST(SmallMap, AssignmentOperator) {
  127. SmallMap<hash_map<int, int> > src_small;
  128. SmallMap<hash_map<int, int> > src_large;
  129. src_small[1] = 20;
  130. src_small[2] = 21;
  131. src_small[3] = 22;
  132. EXPECT_FALSE(src_small.UsingFullMap());
  133. src_large[1] = 20;
  134. src_large[2] = 21;
  135. src_large[3] = 22;
  136. src_large[5] = 23;
  137. src_large[6] = 24;
  138. src_large[7] = 25;
  139. EXPECT_TRUE(src_large.UsingFullMap());
  140. // Assignments to empty.
  141. SmallMap<hash_map<int, int> > dest_small;
  142. dest_small = src_small;
  143. EXPECT_TRUE(SmallMapEqual(dest_small, src_small));
  144. EXPECT_EQ(dest_small.UsingFullMap(),
  145. src_small.UsingFullMap());
  146. SmallMap<hash_map<int, int> > dest_large;
  147. dest_large = src_large;
  148. EXPECT_TRUE(SmallMapEqual(dest_large, src_large));
  149. EXPECT_EQ(dest_large.UsingFullMap(),
  150. src_large.UsingFullMap());
  151. // Assignments which assign from full to small, and vice versa.
  152. dest_small = src_large;
  153. EXPECT_TRUE(SmallMapEqual(dest_small, src_large));
  154. EXPECT_EQ(dest_small.UsingFullMap(),
  155. src_large.UsingFullMap());
  156. dest_large = src_small;
  157. EXPECT_TRUE(SmallMapEqual(dest_large, src_small));
  158. EXPECT_EQ(dest_large.UsingFullMap(),
  159. src_small.UsingFullMap());
  160. // Double check that SmallMapEqual works:
  161. dest_large[42] = 666;
  162. EXPECT_FALSE(SmallMapEqual(dest_large, src_small));
  163. }
  164. TEST(SmallMap, Insert) {
  165. SmallMap<hash_map<int, int> > sm;
  166. // loop through the transition from small map to map.
  167. for (int i = 1; i <= 10; ++i) {
  168. VLOG(1) << "Iteration " << i;
  169. // insert an element
  170. std::pair<SmallMap<hash_map<int, int> >::iterator,
  171. bool> ret;
  172. ret = sm.insert(std::make_pair(i, 100*i));
  173. EXPECT_TRUE(ret.second);
  174. EXPECT_TRUE(ret.first == sm.find(i));
  175. EXPECT_EQ(ret.first->first, i);
  176. EXPECT_EQ(ret.first->second, 100*i);
  177. // try to insert it again with different value, fails, but we still get an
  178. // iterator back with the original value.
  179. ret = sm.insert(std::make_pair(i, -i));
  180. EXPECT_FALSE(ret.second);
  181. EXPECT_TRUE(ret.first == sm.find(i));
  182. EXPECT_EQ(ret.first->first, i);
  183. EXPECT_EQ(ret.first->second, 100*i);
  184. // check the state of the map.
  185. for (int j = 1; j <= i; ++j) {
  186. SmallMap<hash_map<int, int> >::iterator it = sm.find(j);
  187. EXPECT_TRUE(it != sm.end());
  188. EXPECT_EQ(it->first, j);
  189. EXPECT_EQ(it->second, j * 100);
  190. }
  191. EXPECT_EQ(sm.size(), static_cast<size_t>(i));
  192. EXPECT_FALSE(sm.empty());
  193. }
  194. }
  195. TEST(SmallMap, InsertRange) {
  196. // loop through the transition from small map to map.
  197. for (int elements = 0; elements <= 10; ++elements) {
  198. VLOG(1) << "Elements " << elements;
  199. hash_map<int, int> normal_map;
  200. for (int i = 1; i <= elements; ++i) {
  201. normal_map.insert(std::make_pair(i, 100*i));
  202. }
  203. SmallMap<hash_map<int, int> > sm;
  204. sm.insert(normal_map.begin(), normal_map.end());
  205. EXPECT_EQ(normal_map.size(), sm.size());
  206. for (int i = 1; i <= elements; ++i) {
  207. VLOG(1) << "Iteration " << i;
  208. EXPECT_TRUE(sm.find(i) != sm.end());
  209. EXPECT_EQ(sm.find(i)->first, i);
  210. EXPECT_EQ(sm.find(i)->second, 100*i);
  211. }
  212. }
  213. }
  214. TEST(SmallMap, Erase) {
  215. SmallMap<hash_map<std::string, int> > m;
  216. SmallMap<hash_map<std::string, int> >::iterator iter;
  217. m["monday"] = 1;
  218. m["tuesday"] = 2;
  219. m["wednesday"] = 3;
  220. EXPECT_EQ(m["monday" ], 1);
  221. EXPECT_EQ(m["tuesday" ], 2);
  222. EXPECT_EQ(m["wednesday"], 3);
  223. EXPECT_EQ(m.count("tuesday"), 1u);
  224. EXPECT_FALSE(m.UsingFullMap());
  225. iter = m.begin();
  226. ASSERT_TRUE(iter != m.end());
  227. EXPECT_EQ(iter->first, "monday");
  228. EXPECT_EQ(iter->second, 1);
  229. ++iter;
  230. ASSERT_TRUE(iter != m.end());
  231. EXPECT_EQ(iter->first, "tuesday");
  232. EXPECT_EQ(iter->second, 2);
  233. ++iter;
  234. ASSERT_TRUE(iter != m.end());
  235. EXPECT_EQ(iter->first, "wednesday");
  236. EXPECT_EQ(iter->second, 3);
  237. ++iter;
  238. EXPECT_TRUE(iter == m.end());
  239. EXPECT_EQ(m.erase("tuesday"), 1u);
  240. EXPECT_EQ(m["monday" ], 1);
  241. EXPECT_EQ(m["wednesday"], 3);
  242. EXPECT_EQ(m.count("tuesday"), 0u);
  243. EXPECT_EQ(m.erase("tuesday"), 0u);
  244. iter = m.begin();
  245. ASSERT_TRUE(iter != m.end());
  246. EXPECT_EQ(iter->first, "monday");
  247. EXPECT_EQ(iter->second, 1);
  248. ++iter;
  249. ASSERT_TRUE(iter != m.end());
  250. EXPECT_EQ(iter->first, "wednesday");
  251. EXPECT_EQ(iter->second, 3);
  252. ++iter;
  253. EXPECT_TRUE(iter == m.end());
  254. m["thursday"] = 4;
  255. m["friday"] = 5;
  256. EXPECT_EQ(m.size(), 4u);
  257. EXPECT_FALSE(m.empty());
  258. EXPECT_FALSE(m.UsingFullMap());
  259. m["saturday"] = 6;
  260. EXPECT_TRUE(m.UsingFullMap());
  261. EXPECT_EQ(m.count("friday"), 1u);
  262. EXPECT_EQ(m.erase("friday"), 1u);
  263. EXPECT_TRUE(m.UsingFullMap());
  264. EXPECT_EQ(m.count("friday"), 0u);
  265. EXPECT_EQ(m.erase("friday"), 0u);
  266. EXPECT_EQ(m.size(), 4u);
  267. EXPECT_FALSE(m.empty());
  268. EXPECT_EQ(m.erase("monday"), 1u);
  269. EXPECT_EQ(m.size(), 3u);
  270. EXPECT_FALSE(m.empty());
  271. m.clear();
  272. EXPECT_FALSE(m.UsingFullMap());
  273. EXPECT_EQ(m.size(), 0u);
  274. EXPECT_TRUE(m.empty());
  275. }
  276. TEST(SmallMap, NonHashMap) {
  277. SmallMap<std::map<int, int>, 4, std::equal_to<int> > m;
  278. EXPECT_TRUE(m.empty());
  279. m[9] = 2;
  280. m[0] = 5;
  281. EXPECT_EQ(m[9], 2);
  282. EXPECT_EQ(m[0], 5);
  283. EXPECT_EQ(m.size(), 2u);
  284. EXPECT_FALSE(m.empty());
  285. EXPECT_FALSE(m.UsingFullMap());
  286. SmallMap<std::map<int, int>, 4, std::equal_to<int> >::iterator iter(
  287. m.begin());
  288. ASSERT_TRUE(iter != m.end());
  289. EXPECT_EQ(iter->first, 9);
  290. EXPECT_EQ(iter->second, 2);
  291. ++iter;
  292. ASSERT_TRUE(iter != m.end());
  293. EXPECT_EQ(iter->first, 0);
  294. EXPECT_EQ(iter->second, 5);
  295. ++iter;
  296. EXPECT_TRUE(iter == m.end());
  297. --iter;
  298. ASSERT_TRUE(iter != m.end());
  299. EXPECT_EQ(iter->first, 0);
  300. EXPECT_EQ(iter->second, 5);
  301. m[8] = 23;
  302. m[1234] = 90;
  303. m[-5] = 6;
  304. EXPECT_EQ(m[ 9], 2);
  305. EXPECT_EQ(m[ 0], 5);
  306. EXPECT_EQ(m[1234], 90);
  307. EXPECT_EQ(m[ 8], 23);
  308. EXPECT_EQ(m[ -5], 6);
  309. EXPECT_EQ(m.size(), 5u);
  310. EXPECT_FALSE(m.empty());
  311. EXPECT_TRUE(m.UsingFullMap());
  312. iter = m.begin();
  313. ASSERT_TRUE(iter != m.end());
  314. EXPECT_EQ(iter->first, -5);
  315. EXPECT_EQ(iter->second, 6);
  316. ++iter;
  317. ASSERT_TRUE(iter != m.end());
  318. EXPECT_EQ(iter->first, 0);
  319. EXPECT_EQ(iter->second, 5);
  320. ++iter;
  321. ASSERT_TRUE(iter != m.end());
  322. EXPECT_EQ(iter->first, 8);
  323. EXPECT_EQ(iter->second, 23);
  324. ++iter;
  325. ASSERT_TRUE(iter != m.end());
  326. EXPECT_EQ(iter->first, 9);
  327. EXPECT_EQ(iter->second, 2);
  328. ++iter;
  329. ASSERT_TRUE(iter != m.end());
  330. EXPECT_EQ(iter->first, 1234);
  331. EXPECT_EQ(iter->second, 90);
  332. ++iter;
  333. EXPECT_TRUE(iter == m.end());
  334. --iter;
  335. ASSERT_TRUE(iter != m.end());
  336. EXPECT_EQ(iter->first, 1234);
  337. EXPECT_EQ(iter->second, 90);
  338. }
  339. TEST(SmallMap, DefaultEqualKeyWorks) {
  340. // If these tests compile, they pass. The EXPECT calls are only there to avoid
  341. // unused variable warnings.
  342. SmallMap<hash_map<int, int> > hm;
  343. EXPECT_EQ(0u, hm.size());
  344. SmallMap<std::map<int, int> > m;
  345. EXPECT_EQ(0u, m.size());
  346. }
  347. namespace {
  348. class hash_map_add_item : public hash_map<int, int> {
  349. public:
  350. hash_map_add_item() : hash_map<int, int>() {}
  351. explicit hash_map_add_item(const std::pair<int, int>& item)
  352. : hash_map<int, int>() {
  353. insert(item);
  354. }
  355. };
  356. void InitMap(ManualConstructor<hash_map_add_item>* map_ctor) {
  357. map_ctor->Init(std::make_pair(0, 0));
  358. }
  359. class hash_map_add_item_initializer {
  360. public:
  361. explicit hash_map_add_item_initializer(int item_to_add)
  362. : item_(item_to_add) {}
  363. hash_map_add_item_initializer()
  364. : item_(0) {}
  365. void operator()(ManualConstructor<hash_map_add_item>* map_ctor) const {
  366. map_ctor->Init(std::make_pair(item_, item_));
  367. }
  368. int item_;
  369. };
  370. } // anonymous namespace
  371. TEST(SmallMap, SubclassInitializationWithFunctionPointer) {
  372. SmallMap<hash_map_add_item, 4, std::equal_to<int>,
  373. void (*)(ManualConstructor<hash_map_add_item>*)> m(InitMap);
  374. EXPECT_TRUE(m.empty());
  375. m[1] = 1;
  376. m[2] = 2;
  377. m[3] = 3;
  378. m[4] = 4;
  379. EXPECT_EQ(4u, m.size());
  380. EXPECT_EQ(0u, m.count(0));
  381. m[5] = 5;
  382. EXPECT_EQ(6u, m.size());
  383. // Our function adds an extra item when we convert to a map.
  384. EXPECT_EQ(1u, m.count(0));
  385. }
  386. TEST(SmallMap, SubclassInitializationWithFunctionObject) {
  387. SmallMap<hash_map_add_item, 4, std::equal_to<int>,
  388. hash_map_add_item_initializer> m(hash_map_add_item_initializer(-1));
  389. EXPECT_TRUE(m.empty());
  390. m[1] = 1;
  391. m[2] = 2;
  392. m[3] = 3;
  393. m[4] = 4;
  394. EXPECT_EQ(4u, m.size());
  395. EXPECT_EQ(0u, m.count(-1));
  396. m[5] = 5;
  397. EXPECT_EQ(6u, m.size());
  398. // Our functor adds an extra item when we convert to a map.
  399. EXPECT_EQ(1u, m.count(-1));
  400. }
  401. } // namespace butil