StringKeyedTest.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /*
  2. * Copyright 2015-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. // Copyright 2013-present Facebook. All Rights Reserved.
  17. #include <folly/experimental/StringKeyedMap.h>
  18. #include <folly/experimental/StringKeyedSet.h>
  19. #include <folly/experimental/StringKeyedUnorderedMap.h>
  20. #include <folly/experimental/StringKeyedUnorderedSet.h>
  21. #include <list>
  22. #include <string>
  23. #include <glog/logging.h>
  24. #include <folly/Range.h>
  25. #include <folly/hash/Hash.h>
  26. #include <folly/portability/GFlags.h>
  27. #include <folly/portability/GTest.h>
  28. using folly::BasicStringKeyedUnorderedSet;
  29. using folly::StringKeyedMap;
  30. using folly::StringKeyedSetBase;
  31. using folly::StringKeyedUnorderedMap;
  32. using folly::StringPiece;
  33. using std::string;
  34. static unsigned long long allocated = 0;
  35. static unsigned long long freed = 0;
  36. template <typename Alloc>
  37. struct MemoryLeakCheckerAllocator {
  38. typedef typename Alloc::value_type value_type;
  39. typedef value_type* pointer;
  40. typedef value_type const* const_pointer;
  41. typedef value_type& reference;
  42. typedef value_type const* const_reference;
  43. typedef std::ptrdiff_t difference_type;
  44. typedef std::size_t size_type;
  45. explicit MemoryLeakCheckerAllocator() {}
  46. explicit MemoryLeakCheckerAllocator(Alloc alloc) : alloc_(alloc) {}
  47. template <class UAlloc>
  48. MemoryLeakCheckerAllocator(const MemoryLeakCheckerAllocator<UAlloc>& other)
  49. : alloc_(other.allocator()) {}
  50. value_type* allocate(size_t n, const void* hint = nullptr) {
  51. auto p = alloc_.allocate(n, hint);
  52. allocated += n * sizeof(value_type);
  53. return p;
  54. }
  55. void deallocate(value_type* p, size_t n) {
  56. alloc_.deallocate(p, n);
  57. freed += n * sizeof(value_type);
  58. }
  59. size_t max_size() const {
  60. return alloc_.max_size();
  61. }
  62. template <class... Args>
  63. void construct(value_type* p, Args&&... args) {
  64. alloc_.construct(p, std::forward<Args>(args)...);
  65. }
  66. void destroy(value_type* p) {
  67. alloc_.destroy(p);
  68. }
  69. template <class U>
  70. struct rebind {
  71. typedef MemoryLeakCheckerAllocator<
  72. typename std::allocator_traits<Alloc>::template rebind_alloc<U>>
  73. other;
  74. };
  75. const Alloc& allocator() const {
  76. return alloc_;
  77. }
  78. bool operator!=(const MemoryLeakCheckerAllocator& other) const {
  79. return alloc_ != other.alloc_;
  80. }
  81. bool operator==(const MemoryLeakCheckerAllocator& other) const {
  82. return alloc_ == other.alloc_;
  83. }
  84. private:
  85. Alloc alloc_;
  86. };
  87. using KeyValuePairLeakChecker = MemoryLeakCheckerAllocator<
  88. std::allocator<std::pair<const StringPiece, int>>>;
  89. using ValueLeakChecker =
  90. MemoryLeakCheckerAllocator<std::allocator<StringPiece>>;
  91. using LeakCheckedUnorderedMap = StringKeyedUnorderedMap<
  92. int,
  93. folly::hasher<StringPiece>,
  94. std::equal_to<StringPiece>,
  95. MemoryLeakCheckerAllocator<
  96. std::allocator<std::pair<const std::string, int>>>>;
  97. typedef StringKeyedSetBase<std::less<StringPiece>, ValueLeakChecker>
  98. LeakCheckedSet;
  99. typedef StringKeyedMap<int, std::less<StringPiece>, KeyValuePairLeakChecker>
  100. LeakCheckedMap;
  101. using LeakCheckedUnorderedSet = BasicStringKeyedUnorderedSet<
  102. folly::hasher<StringPiece>,
  103. std::equal_to<folly::StringPiece>,
  104. MemoryLeakCheckerAllocator<std::allocator<std::string>>>;
  105. TEST(StringKeyedUnorderedMapTest, sanity) {
  106. LeakCheckedUnorderedMap map;
  107. EXPECT_TRUE(map.empty());
  108. EXPECT_EQ(map.size(), 0);
  109. {
  110. string s("hello");
  111. StringPiece piece(s, 3);
  112. map.insert({s, 1});
  113. EXPECT_FALSE(map.emplace(s, 2).second);
  114. EXPECT_TRUE(map.emplace(piece, 3).second);
  115. }
  116. EXPECT_EQ(map.size(), 2);
  117. map = static_cast<decltype(map)&>(map); // suppress self-assign warning
  118. EXPECT_EQ(map.find("hello")->second, 1);
  119. EXPECT_EQ(map.find("lo")->second, 3);
  120. map.erase(map.find("hello"));
  121. EXPECT_EQ(map.size(), 1);
  122. for (auto& it : map) {
  123. EXPECT_EQ(it.first, "lo");
  124. }
  125. }
  126. TEST(StringKeyedUnorderedMapTest, constructors) {
  127. LeakCheckedUnorderedMap map{
  128. {"hello", 1},
  129. {"lo", 3},
  130. };
  131. LeakCheckedUnorderedMap map2(map);
  132. EXPECT_EQ(map2.size(), 2);
  133. EXPECT_TRUE(map2 == map);
  134. map2.erase("lo");
  135. for (auto& it : map2) {
  136. EXPECT_EQ(it.first, "hello");
  137. }
  138. map2.clear();
  139. EXPECT_TRUE(map2.empty());
  140. map2.emplace("key1", 1);
  141. LeakCheckedUnorderedMap map3(std::move(map2));
  142. EXPECT_EQ(map3.size(), 1);
  143. EXPECT_EQ(map3["key1"], 1);
  144. EXPECT_EQ(map3["key0"], 0);
  145. EXPECT_EQ(map3.size(), 2);
  146. map3.reserve(1000);
  147. EXPECT_EQ(map3.size(), 2);
  148. LeakCheckedUnorderedMap map4{
  149. {"key0", 0},
  150. {"key1", 1},
  151. };
  152. EXPECT_EQ(map4.erase("key0"), 1);
  153. EXPECT_EQ(map4.size(), 1);
  154. EXPECT_EQ(map4.find("key0"), map4.end());
  155. map3 = map4;
  156. EXPECT_EQ(map3.size(), 1);
  157. EXPECT_EQ(map4.size(), 1);
  158. EXPECT_EQ(map4.max_size(), map3.max_size());
  159. map4 = std::move(map3);
  160. EXPECT_EQ(map4.size(), 1);
  161. EXPECT_EQ(map4.at("key1"), 1);
  162. }
  163. TEST(StringKeyedSetTest, sanity) {
  164. LeakCheckedSet set;
  165. EXPECT_TRUE(set.empty());
  166. EXPECT_EQ(set.size(), 0);
  167. {
  168. string s("hello");
  169. StringPiece piece(s, 3);
  170. set.insert(s);
  171. EXPECT_FALSE(set.emplace(s).second);
  172. EXPECT_TRUE(set.emplace(piece).second);
  173. }
  174. EXPECT_EQ(set.size(), 2);
  175. set = static_cast<decltype(set)&>(set); // suppress self-assign warning
  176. EXPECT_NE(set.find(StringPiece("hello")), set.end());
  177. EXPECT_NE(set.find("lo"), set.end());
  178. auto it = set.begin();
  179. EXPECT_EQ(*it, "hello");
  180. EXPECT_EQ(*(++it), "lo");
  181. EXPECT_EQ(++it, set.end());
  182. set.erase(set.find("hello"));
  183. EXPECT_EQ(set.size(), 1);
  184. for (auto entry : set) {
  185. EXPECT_EQ(entry, "lo");
  186. }
  187. }
  188. TEST(StringKeyedSetTest, constructors) {
  189. LeakCheckedSet set{
  190. "hello",
  191. "lo",
  192. };
  193. LeakCheckedSet set2(set);
  194. EXPECT_EQ(set2.size(), 2);
  195. set2.erase("lo");
  196. for (auto it : set2) {
  197. EXPECT_EQ(it, "hello");
  198. }
  199. set2.clear();
  200. EXPECT_TRUE(set2.empty());
  201. set2.emplace("key1");
  202. LeakCheckedSet set3(std::move(set2));
  203. EXPECT_EQ(set3.size(), 1);
  204. EXPECT_EQ(set3.insert("key1").second, false);
  205. EXPECT_EQ(set3.emplace("key0").second, true);
  206. EXPECT_EQ(set3.size(), 2);
  207. EXPECT_EQ(set3.size(), 2);
  208. LeakCheckedSet set4{
  209. "key0",
  210. "key1",
  211. };
  212. EXPECT_EQ(set4.erase("key0"), 1);
  213. EXPECT_EQ(set4.size(), 1);
  214. EXPECT_EQ(set4.find("key0"), set4.end());
  215. set3 = set4;
  216. EXPECT_EQ(set3.size(), 1);
  217. EXPECT_EQ(set4.size(), 1);
  218. EXPECT_EQ(set4.max_size(), set3.max_size());
  219. set4 = std::move(set3);
  220. EXPECT_EQ(set4.size(), 1);
  221. EXPECT_NE(set4.find("key1"), set4.end());
  222. }
  223. TEST(StringKeyedUnorderedSetTest, sanity) {
  224. LeakCheckedUnorderedSet set;
  225. EXPECT_TRUE(set.empty());
  226. EXPECT_EQ(set.size(), 0);
  227. {
  228. string s("hello");
  229. StringPiece piece(s, 3);
  230. set.insert(s);
  231. EXPECT_FALSE(set.emplace(s).second);
  232. EXPECT_TRUE(set.emplace(piece).second);
  233. }
  234. EXPECT_EQ(set.size(), 2);
  235. set = static_cast<decltype(set)&>(set); // suppress self-assign warning
  236. EXPECT_NE(set.find("hello"), set.end());
  237. EXPECT_NE(set.find("lo"), set.end());
  238. set.erase(set.find("hello"));
  239. EXPECT_EQ(set.size(), 1);
  240. for (auto entry : set) {
  241. EXPECT_EQ(entry, "lo");
  242. }
  243. }
  244. TEST(StringKeyedUnorderedSetTest, constructors) {
  245. LeakCheckedUnorderedSet s1;
  246. EXPECT_TRUE(s1.empty());
  247. LeakCheckedUnorderedSet s2(10);
  248. EXPECT_TRUE(s2.empty());
  249. EXPECT_GE(s2.bucket_count(), 10);
  250. std::list<StringPiece> lst{"abc", "def"};
  251. LeakCheckedUnorderedSet s3(lst.begin(), lst.end());
  252. EXPECT_EQ(s3.size(), 2);
  253. EXPECT_NE(s3.find("abc"), s3.end());
  254. EXPECT_NE(s3.find("def"), s3.end());
  255. EXPECT_TRUE(s3 == (LeakCheckedUnorderedSet{"abc", "def"}));
  256. LeakCheckedUnorderedSet s4(const_cast<LeakCheckedUnorderedSet&>(s3));
  257. EXPECT_TRUE(s4 == s3);
  258. LeakCheckedUnorderedSet s5(
  259. const_cast<LeakCheckedUnorderedSet&>(s3), ValueLeakChecker());
  260. EXPECT_TRUE(s5 == s3);
  261. LeakCheckedUnorderedSet s6(std::move(s3));
  262. EXPECT_TRUE(s3.empty());
  263. EXPECT_TRUE(s6 == s5);
  264. auto s6_allocator = s6.get_allocator();
  265. LeakCheckedUnorderedSet s7(std::move(s6), s6_allocator);
  266. EXPECT_TRUE(s6.empty());
  267. EXPECT_TRUE(s7 == s5);
  268. LeakCheckedUnorderedSet s8{
  269. "hello",
  270. "lo",
  271. };
  272. EXPECT_EQ(s8.size(), 2);
  273. EXPECT_NE(s8.find("hello"), s8.end());
  274. EXPECT_NE(s8.find("lo"), s8.end());
  275. LeakCheckedUnorderedSet s9(
  276. {
  277. "hello",
  278. "lo",
  279. },
  280. 10);
  281. EXPECT_EQ(s9.size(), 2);
  282. EXPECT_NE(s9.find("hello"), s9.end());
  283. EXPECT_NE(s9.find("lo"), s9.end());
  284. LeakCheckedUnorderedSet set2(s8);
  285. EXPECT_EQ(set2.size(), 2);
  286. set2.erase("lo");
  287. for (auto entry : set2) {
  288. EXPECT_EQ(entry, "hello");
  289. }
  290. set2.clear();
  291. EXPECT_TRUE(set2.empty());
  292. set2.emplace("key1");
  293. LeakCheckedUnorderedSet set3(std::move(set2));
  294. EXPECT_EQ(set3.size(), 1);
  295. EXPECT_EQ(set3.insert("key1").second, false);
  296. EXPECT_EQ(set3.emplace("key0").second, true);
  297. EXPECT_EQ(set3.size(), 2);
  298. set3.reserve(1000);
  299. EXPECT_EQ(set3.size(), 2);
  300. LeakCheckedUnorderedSet set4{
  301. "key0",
  302. "key1",
  303. };
  304. EXPECT_EQ(set4.erase("key0"), 1);
  305. EXPECT_EQ(set4.size(), 1);
  306. EXPECT_EQ(set4.find("key0"), set4.end());
  307. set3 = set4;
  308. EXPECT_EQ(set3.size(), 1);
  309. EXPECT_EQ(set4.size(), 1);
  310. EXPECT_EQ(set4.max_size(), set3.max_size());
  311. set4 = std::move(set3);
  312. EXPECT_EQ(set4.size(), 1);
  313. EXPECT_NE(set4.find("key1"), set4.end());
  314. }
  315. TEST(StringKeyedMapTest, sanity) {
  316. LeakCheckedMap map;
  317. EXPECT_TRUE(map.empty());
  318. EXPECT_EQ(map.size(), 0);
  319. {
  320. string s("hello");
  321. StringPiece piece(s, 3);
  322. map.insert({s, 1});
  323. EXPECT_FALSE(map.emplace(s, 2).second);
  324. EXPECT_TRUE(map.emplace(piece, 3).second);
  325. }
  326. EXPECT_EQ(map.size(), 2);
  327. map = static_cast<decltype(map)&>(map); // suppress self-assign warning
  328. EXPECT_EQ(map.find("hello")->second, 1);
  329. EXPECT_EQ(map.find("lo")->second, 3);
  330. auto it = map.begin();
  331. EXPECT_EQ(it->first, "hello");
  332. EXPECT_EQ((++it)->first, "lo");
  333. EXPECT_EQ(++it, map.end());
  334. map.erase(map.find("hello"));
  335. EXPECT_EQ(map.size(), 1);
  336. for (auto& entry : map) {
  337. EXPECT_EQ(entry.first, "lo");
  338. }
  339. }
  340. TEST(StringKeyedMapTest, constructors) {
  341. LeakCheckedMap map{
  342. {"hello", 1},
  343. {"lo", 3},
  344. };
  345. LeakCheckedMap map2(map);
  346. EXPECT_EQ(map2.size(), 2);
  347. map2.erase("lo");
  348. for (auto& entry : map2) {
  349. EXPECT_EQ(entry.first, "hello");
  350. }
  351. map2.clear();
  352. EXPECT_TRUE(map2.empty());
  353. map2.emplace("key1", 1);
  354. LeakCheckedMap map3(std::move(map2));
  355. EXPECT_EQ(map3.size(), 1);
  356. EXPECT_EQ(map3["key1"], 1);
  357. EXPECT_EQ(map3["key0"], 0);
  358. EXPECT_EQ(map3.size(), 2);
  359. LeakCheckedMap map4{
  360. {"key0", 0},
  361. {"key1", 1},
  362. };
  363. EXPECT_EQ(map4.erase("key0"), 1);
  364. EXPECT_EQ(map4.size(), 1);
  365. EXPECT_EQ(map4.find("key0"), map4.end());
  366. map3 = map4;
  367. EXPECT_EQ(map3.size(), 1);
  368. EXPECT_EQ(map4.size(), 1);
  369. EXPECT_EQ(map4.max_size(), map3.max_size());
  370. map4 = std::move(map3);
  371. EXPECT_EQ(map4.size(), 1);
  372. EXPECT_EQ(map4.at("key1"), 1);
  373. }
  374. int main(int argc, char** argv) {
  375. FLAGS_logtostderr = true;
  376. google::InitGoogleLogging(argv[0]);
  377. testing::InitGoogleTest(&argc, argv);
  378. gflags::ParseCommandLineFlags(&argc, &argv, true);
  379. return RUN_ALL_TESTS();
  380. }
  381. // This MUST be the LAST test.
  382. TEST(StringKeyed, memory_balance) {
  383. auto balance = allocated < freed ? freed - allocated : allocated - freed;
  384. LOG(INFO) << "allocated: " << allocated << " freed: " << freed
  385. << " balance: " << balance
  386. << (allocated < freed
  387. ? " negative (huh?)"
  388. : freed < allocated ? " positive (leak)" : "");
  389. EXPECT_EQ(allocated, freed);
  390. }