proxygen
ConcurrentHashMapTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-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 
18 
19 #include <atomic>
20 #include <memory>
21 #include <thread>
22 
23 #include <folly/hash/Hash.h>
26 
27 using namespace folly::test;
28 using namespace folly;
29 using namespace std;
30 
31 DEFINE_int64(seed, 0, "Seed for random number generators");
32 
35  foomap.max_load_factor(1.05);
36  EXPECT_TRUE(foomap.empty());
37  EXPECT_EQ(foomap.find(1), foomap.cend());
38  auto r = foomap.insert(1, 0);
39  EXPECT_TRUE(r.second);
40  auto r2 = foomap.insert(1, 0);
41  EXPECT_EQ(r.first->second, 0);
42  EXPECT_EQ(r.first->first, 1);
43  EXPECT_EQ(r2.first->second, 0);
44  EXPECT_EQ(r2.first->first, 1);
45  EXPECT_EQ(r.first, r2.first);
46  EXPECT_TRUE(r.second);
47  EXPECT_FALSE(r2.second);
48  EXPECT_FALSE(foomap.empty());
49  EXPECT_TRUE(foomap.insert(std::make_pair(2, 0)).second);
50  EXPECT_TRUE(foomap.insert_or_assign(2, 0).second);
51  EXPECT_TRUE(foomap.assign_if_equal(2, 0, 3));
52  EXPECT_TRUE(foomap.insert(3, 0).second);
53  EXPECT_NE(foomap.find(1), foomap.cend());
54  EXPECT_NE(foomap.find(2), foomap.cend());
55  EXPECT_EQ(foomap.find(2)->second, 3);
56  EXPECT_EQ(foomap[2], 3);
57  EXPECT_EQ(foomap[20], 0);
58  EXPECT_EQ(foomap.at(20), 0);
59  EXPECT_FALSE(foomap.insert(1, 0).second);
60  auto l = foomap.find(1);
61  foomap.erase(l);
62  EXPECT_FALSE(foomap.erase(1));
63  EXPECT_EQ(foomap.find(1), foomap.cend());
64  auto res = foomap.find(2);
65  EXPECT_NE(res, foomap.cend());
66  EXPECT_EQ(3, res->second);
67  EXPECT_FALSE(foomap.empty());
68  foomap.clear();
69  EXPECT_TRUE(foomap.empty());
70 }
71 
72 TEST(ConcurrentHashMap, MaxSizeTest) {
74  bool insert_failed = false;
75  for (int i = 0; i < 32; i++) {
76  auto res = foomap.insert(0, 0);
77  if (!res.second) {
78  insert_failed = true;
79  }
80  }
81  EXPECT_TRUE(insert_failed);
82 }
83 
84 TEST(ConcurrentHashMap, MoveTest) {
86  auto other = std::move(foomap);
87  auto other2 = std::move(other);
88  other = std::move(other2);
89 }
90 
91 struct foo {
92  static int moved;
93  static int copied;
95  moved++;
96  }
98  moved++;
99  return *this;
100  }
101  foo& operator=(const foo&) {
102  copied++;
103  return *this;
104  }
105  foo(const foo&) {
106  copied++;
107  }
108  foo() {}
109 };
110 int foo::moved{0};
111 int foo::copied{0};
112 
113 TEST(ConcurrentHashMap, EmplaceTest) {
115  foo bar; // Make sure to test copy
116  foomap.insert(1, bar);
117  EXPECT_EQ(foo::moved, 0);
119  foo::copied = 0;
120  // The difference between emplace and try_emplace:
121  // If insertion fails, try_emplace does not move its argument
122  foomap.try_emplace(1, foo());
123  EXPECT_EQ(foo::moved, 0);
125  foomap.emplace(1, foo());
126  EXPECT_EQ(foo::moved, 1);
128 }
129 
130 TEST(ConcurrentHashMap, MapResizeTest) {
132  EXPECT_EQ(foomap.find(1), foomap.cend());
133  EXPECT_TRUE(foomap.insert(1, 0).second);
134  EXPECT_TRUE(foomap.insert(2, 0).second);
135  EXPECT_TRUE(foomap.insert(3, 0).second);
136  EXPECT_TRUE(foomap.insert(4, 0).second);
137  foomap.reserve(512);
138  EXPECT_NE(foomap.find(1), foomap.cend());
139  EXPECT_NE(foomap.find(2), foomap.cend());
140  EXPECT_FALSE(foomap.insert(1, 0).second);
141  EXPECT_TRUE(foomap.erase(1));
142  EXPECT_EQ(foomap.find(1), foomap.cend());
143  auto res = foomap.find(2);
144  EXPECT_NE(res, foomap.cend());
145  if (res != foomap.cend()) {
146  EXPECT_EQ(0, res->second);
147  }
148 }
149 
150 // Ensure we can insert objects without copy constructors.
151 TEST(ConcurrentHashMap, MapNoCopiesTest) {
152  struct Uncopyable {
153  int i_;
154  Uncopyable(int i) {
155  i_ = i;
156  }
157  Uncopyable(const Uncopyable& that) = delete;
158  bool operator==(const Uncopyable& o) const {
159  return i_ == o.i_;
160  }
161  };
162  struct Hasher {
163  size_t operator()(const Uncopyable&) const {
164  return 0;
165  }
166  };
168  EXPECT_TRUE(foomap.try_emplace(1, 1).second);
169  EXPECT_TRUE(foomap.try_emplace(2, 2).second);
170  auto res = foomap.find(2);
171  EXPECT_NE(res, foomap.cend());
172 
173  EXPECT_TRUE(foomap.try_emplace(3, 3).second);
174 
175  auto res2 = foomap.find(2);
176  EXPECT_NE(res2, foomap.cend());
177  EXPECT_EQ(&(res->second), &(res2->second));
178 }
179 
180 TEST(ConcurrentHashMap, MapMovableKeysTest) {
181  struct Movable {
182  int i_;
183  Movable(int i) {
184  i_ = i;
185  }
186  Movable(const Movable&) = delete;
187  Movable(Movable&& o) {
188  i_ = o.i_;
189  o.i_ = 0;
190  }
191  bool operator==(const Movable& o) const {
192  return i_ == o.i_;
193  }
194  };
195  struct Hasher {
196  size_t operator()(const Movable&) const {
197  return 0;
198  }
199  };
201  EXPECT_TRUE(foomap.insert(std::make_pair(Movable(10), Movable(1))).second);
202  EXPECT_TRUE(foomap.assign(Movable(10), Movable(2)));
203  EXPECT_TRUE(foomap.insert(Movable(11), Movable(1)).second);
204  EXPECT_TRUE(foomap.emplace(Movable(12), Movable(1)).second);
205  EXPECT_TRUE(foomap.insert_or_assign(Movable(10), Movable(3)).second);
206  EXPECT_TRUE(foomap.assign_if_equal(Movable(10), Movable(3), Movable(4)));
207  EXPECT_FALSE(foomap.try_emplace(Movable(10), Movable(3)).second);
208  EXPECT_TRUE(foomap.try_emplace(Movable(13), Movable(3)).second);
209 }
210 
211 TEST(ConcurrentHashMap, MapUpdateTest) {
213  EXPECT_TRUE(foomap.insert(1, 10).second);
214  EXPECT_TRUE(bool(foomap.assign(1, 11)));
215  auto res = foomap.find(1);
216  EXPECT_NE(res, foomap.cend());
217  EXPECT_EQ(11, res->second);
218 }
219 
220 TEST(ConcurrentHashMap, MapIterateTest2) {
222  auto begin = foomap.cbegin();
223  auto end = foomap.cend();
224  EXPECT_EQ(begin, end);
225 }
226 
227 TEST(ConcurrentHashMap, MapIterateTest) {
229  EXPECT_EQ(foomap.cbegin(), foomap.cend());
230  EXPECT_TRUE(foomap.insert(1, 1).second);
231  EXPECT_TRUE(foomap.insert(2, 2).second);
232  auto iter = foomap.cbegin();
233  EXPECT_NE(iter, foomap.cend());
234  EXPECT_EQ(iter->first, 1);
235  EXPECT_EQ(iter->second, 1);
236  ++iter;
237  EXPECT_NE(iter, foomap.cend());
238  EXPECT_EQ(iter->first, 2);
239  EXPECT_EQ(iter->second, 2);
240  ++iter;
241  EXPECT_EQ(iter, foomap.cend());
242 
243  int count = 0;
244  for (auto it = foomap.cbegin(); it != foomap.cend(); ++it) {
245  count++;
246  }
247  EXPECT_EQ(count, 2);
248 }
249 
250 TEST(ConcurrentHashMap, MoveIterateAssignIterate) {
252  Map tmp;
253  Map map{std::move(tmp)};
254 
255  map.insert(0, 0);
256  ++map.cbegin();
258  other.insert(0, 0);
259  map = std::move(other);
260  ++map.cbegin();
261 }
262 
263 TEST(ConcurrentHashMap, EraseTest) {
265  foomap.insert(1, 0);
266  auto f1 = foomap.find(1);
267  EXPECT_EQ(1, foomap.erase(1));
268  foomap.erase(f1);
269 }
270 
271 TEST(ConcurrentHashMap, CopyIterator) {
273  map.insert(0, 0);
274  for (auto cit = map.cbegin(); cit != map.cend(); ++cit) {
275  std::pair<int const, int> const ckv{0, 0};
276  EXPECT_EQ(*cit, ckv);
277  }
278 }
279 
280 TEST(ConcurrentHashMap, EraseInIterateTest) {
282  for (uint64_t k = 0; k < 10; ++k) {
283  foomap.insert(k, k);
284  }
285  EXPECT_EQ(10, foomap.size());
286  for (auto it = foomap.cbegin(); it != foomap.cend();) {
287  if (it->second > 3) {
288  it = foomap.erase(it);
289  } else {
290  ++it;
291  }
292  }
293  EXPECT_EQ(4, foomap.size());
294  for (auto it = foomap.cbegin(); it != foomap.cend(); ++it) {
295  EXPECT_GE(3, it->second);
296  }
297 }
298 
299 // TODO: hazptrs must support DeterministicSchedule
300 
301 #define Atom std::atomic // DeterministicAtomic
302 #define Mutex std::mutex // DeterministicMutex
303 #define lib std // DeterministicSchedule
304 #define join t.join() // DeterministicSchedule::join(t)
305 // #define Atom DeterministicAtomic
306 // #define Mutex DeterministicMutex
307 // #define lib DeterministicSchedule
308 // #define join DeterministicSchedule::join(t)
309 
310 TEST(ConcurrentHashMap, UpdateStressTest) {
312 
313  // size must match iters for this test.
314  unsigned size = 128 * 128;
315  unsigned iters = size;
317  unsigned long,
318  unsigned long,
319  std::hash<unsigned long>,
320  std::equal_to<unsigned long>,
321  std::allocator<uint8_t>,
322  8,
323  Atom,
324  Mutex>
325  m(2);
326 
327  for (uint32_t i = 0; i < size; i++) {
328  m.insert(i, i);
329  }
330  std::vector<std::thread> threads;
331  unsigned int num_threads = 32;
332  for (uint32_t t = 0; t < num_threads; t++) {
333  threads.push_back(lib::thread([&, t]() {
334  int offset = (iters * t / num_threads);
335  for (uint32_t i = 0; i < iters / num_threads; i++) {
336  unsigned long k = folly::hash::jenkins_rev_mix32((i + offset));
337  k = k % (iters / num_threads) + offset;
338  unsigned long val = 3;
339  {
340  auto res = m.find(k);
341  EXPECT_NE(res, m.cend());
342  EXPECT_EQ(k, res->second);
343  auto r = m.assign(k, res->second);
344  EXPECT_TRUE(r);
345  }
346  {
347  auto res = m.find(k);
348  EXPECT_NE(res, m.cend());
349  EXPECT_EQ(k, res->second);
350  }
351  // Another random insertion to force table resizes
352  val = size + i + offset;
353  EXPECT_TRUE(m.insert(val, val).second);
354  }
355  }));
356  }
357  for (auto& t : threads) {
358  join;
359  }
360 }
361 
362 TEST(ConcurrentHashMap, EraseStressTest) {
364 
365  unsigned size = 2;
366  unsigned iters = size * 128 * 2;
368  unsigned long,
369  unsigned long,
370  std::hash<unsigned long>,
371  std::equal_to<unsigned long>,
372  std::allocator<uint8_t>,
373  8,
374  Atom,
375  Mutex>
376  m(2);
377 
378  for (uint32_t i = 0; i < size; i++) {
379  unsigned long k = folly::hash::jenkins_rev_mix32(i);
380  m.insert(k, k);
381  }
382  std::vector<std::thread> threads;
383  unsigned int num_threads = 32;
384  for (uint32_t t = 0; t < num_threads; t++) {
385  threads.push_back(lib::thread([&, t]() {
386  int offset = (iters * t / num_threads);
387  for (uint32_t i = 0; i < iters / num_threads; i++) {
388  unsigned long k = folly::hash::jenkins_rev_mix32((i + offset));
389  auto res = m.insert(k, k).second;
390  if (res) {
391  res = m.erase(k);
392  if (!res) {
393  printf("Faulre to erase thread %i val %li\n", t, k);
394  exit(0);
395  }
396  EXPECT_TRUE(res);
397  }
398  res = m.insert(k, k).second;
399  if (res) {
400  res = bool(m.assign(k, k));
401  if (!res) {
402  printf("Thread %i update fail %li res%i\n", t, k, res);
403  exit(0);
404  }
405  EXPECT_TRUE(res);
406  auto result = m.find(k);
407  if (result == m.cend()) {
408  printf("Thread %i lookup fail %li\n", t, k);
409  exit(0);
410  }
411  EXPECT_EQ(k, result->second);
412  }
413  }
414  }));
415  }
416  for (auto& t : threads) {
417  join;
418  }
419 }
420 
421 TEST(ConcurrentHashMap, IterateStressTest) {
423 
424  unsigned size = 2;
425  unsigned iters = size * 128 * 2;
427  unsigned long,
428  unsigned long,
429  std::hash<unsigned long>,
430  std::equal_to<unsigned long>,
431  std::allocator<uint8_t>,
432  8,
433  Atom,
434  Mutex>
435  m(2);
436 
437  for (uint32_t i = 0; i < size; i++) {
438  unsigned long k = folly::hash::jenkins_rev_mix32(i);
439  m.insert(k, k);
440  }
441  for (uint32_t i = 0; i < 10; i++) {
442  m.insert(i, i);
443  }
444  std::vector<std::thread> threads;
445  unsigned int num_threads = 32;
446  for (uint32_t t = 0; t < num_threads; t++) {
447  threads.push_back(lib::thread([&, t]() {
448  int offset = (iters * t / num_threads);
449  for (uint32_t i = 0; i < iters / num_threads; i++) {
450  unsigned long k = folly::hash::jenkins_rev_mix32((i + offset));
451  auto res = m.insert(k, k).second;
452  if (res) {
453  res = m.erase(k);
454  if (!res) {
455  printf("Faulre to erase thread %i val %li\n", t, k);
456  exit(0);
457  }
458  EXPECT_TRUE(res);
459  }
460  int count = 0;
461  for (auto it = m.cbegin(); it != m.cend(); ++it) {
462  printf("Item is %li\n", it->first);
463  if (it->first < 10) {
464  count++;
465  }
466  }
467  EXPECT_EQ(count, 10);
468  }
469  }));
470  }
471  for (auto& t : threads) {
472  join;
473  }
474 }
475 
476 TEST(ConcurrentHashMap, insertStressTest) {
478 
479  unsigned size = 2;
480  unsigned iters = size * 64 * 4;
482  unsigned long,
483  unsigned long,
484  std::hash<unsigned long>,
485  std::equal_to<unsigned long>,
486  std::allocator<uint8_t>,
487  8,
488  Atom,
489  Mutex>
490  m(2);
491 
492  EXPECT_TRUE(m.insert(0, 0).second);
493  EXPECT_FALSE(m.insert(0, 0).second);
494  std::vector<std::thread> threads;
495  unsigned int num_threads = 32;
496  for (uint32_t t = 0; t < num_threads; t++) {
497  threads.push_back(lib::thread([&, t]() {
498  int offset = (iters * t / num_threads);
499  for (uint32_t i = 0; i < iters / num_threads; i++) {
500  auto var = offset + i + 1;
501  EXPECT_TRUE(m.insert(var, var).second);
502  EXPECT_FALSE(m.insert(0, 0).second);
503  }
504  }));
505  }
506  for (auto& t : threads) {
507  join;
508  }
509 }
510 
511 TEST(ConcurrentHashMap, assignStressTest) {
513 
514  unsigned size = 2;
515  unsigned iters = size * 64 * 4;
516  struct big_value {
517  uint64_t v1;
518  uint64_t v2;
519  uint64_t v3;
520  uint64_t v4;
521  uint64_t v5;
522  uint64_t v6;
523  uint64_t v7;
524  uint64_t v8;
525  void set(uint64_t v) {
526  v1 = v2 = v3 = v4 = v5 = v6 = v7 = v8 = v;
527  }
528  void check() const {
529  auto v = v1;
530  EXPECT_EQ(v, v8);
531  EXPECT_EQ(v, v7);
532  EXPECT_EQ(v, v6);
533  EXPECT_EQ(v, v5);
534  EXPECT_EQ(v, v4);
535  EXPECT_EQ(v, v3);
536  EXPECT_EQ(v, v2);
537  }
538  };
540  unsigned long,
541  big_value,
542  std::hash<unsigned long>,
543  std::equal_to<unsigned long>,
544  std::allocator<uint8_t>,
545  8,
546  Atom,
547  Mutex>
548  m(2);
549 
550  for (uint32_t i = 0; i < iters; i++) {
551  big_value a;
552  a.set(i);
553  m.insert(i, a);
554  }
555 
556  std::vector<std::thread> threads;
557  unsigned int num_threads = 32;
558  for (uint32_t t = 0; t < num_threads; t++) {
559  threads.push_back(lib::thread([&]() {
560  for (uint32_t i = 0; i < iters; i++) {
561  auto res = m.find(i);
562  EXPECT_NE(res, m.cend());
563  res->second.check();
564  big_value b;
565  b.set(res->second.v1 + 1);
566  m.assign(i, b);
567  }
568  }));
569  }
570  for (auto& t : threads) {
571  join;
572  }
573 }
574 
575 TEST(ConcurrentHashMap, RefcountTest) {
576  struct badhash {
577  size_t operator()(uint64_t) const {
578  return 0;
579  }
580  };
582  uint64_t,
583  uint64_t,
584  badhash,
585  std::equal_to<uint64_t>,
586  std::allocator<uint8_t>,
587  0>
588  foomap(3);
589  foomap.insert(0, 0);
590  foomap.insert(1, 1);
591  foomap.insert(2, 2);
592  for (int32_t i = 0; i < 300; ++i) {
593  foomap.insert_or_assign(1, i);
594  }
595 }
596 
597 struct Wrapper {
598  explicit Wrapper(bool& del_) : del(del_) {}
600  del = true;
601  }
602 
603  bool& del;
604 };
605 
607  bool del{false};
608 
609  {
611 
612  map.insert(0, std::make_shared<Wrapper>(del));
613  }
614 
616 
617  EXPECT_TRUE(del);
618 }
619 
620 TEST(ConcurrentHashMap, DeletionWithErase) {
621  bool del{false};
622 
623  {
625 
626  map.insert(0, std::make_shared<Wrapper>(del));
627  map.erase(0);
628  }
629 
631 
632  EXPECT_TRUE(del);
633 }
634 
635 TEST(ConcurrentHashMap, DeletionWithIterator) {
636  bool del{false};
637 
638  {
640 
641  map.insert(0, std::make_shared<Wrapper>(del));
642  auto it = map.find(0);
643  map.erase(it);
644  }
645 
647 
648  EXPECT_TRUE(del);
649 }
650 
651 TEST(ConcurrentHashMap, DeletionWithForLoop) {
652  bool del{false};
653 
654  {
656 
657  map.insert(0, std::make_shared<Wrapper>(del));
658  for (auto it = map.cbegin(); it != map.cend(); ++it) {
659  EXPECT_EQ(it->first, 0);
660  }
661  }
662 
664 
665  EXPECT_TRUE(del);
666 }
667 
668 TEST(ConcurrentHashMap, DeletionMultiple) {
669  bool del1{false}, del2{false};
670 
671  {
673 
674  map.insert(0, std::make_shared<Wrapper>(del1));
675  map.insert(1, std::make_shared<Wrapper>(del2));
676  }
677 
679 
680  EXPECT_TRUE(del1);
681  EXPECT_TRUE(del2);
682 }
683 
684 TEST(ConcurrentHashMap, DeletionAssigned) {
685  bool del1{false}, del2{false};
686 
687  {
689 
690  map.insert(0, std::make_shared<Wrapper>(del1));
691  map.insert_or_assign(0, std::make_shared<Wrapper>(del2));
692  }
693 
695 
696  EXPECT_TRUE(del1);
697  EXPECT_TRUE(del2);
698 }
699 
700 TEST(ConcurrentHashMap, DeletionMultipleMaps) {
701  bool del1{false}, del2{false};
702 
703  {
706 
707  map1.insert(0, std::make_shared<Wrapper>(del1));
708  map2.insert(0, std::make_shared<Wrapper>(del2));
709  }
710 
712 
713  EXPECT_TRUE(del1);
714  EXPECT_TRUE(del2);
715 }
716 
717 TEST(ConcurrentHashMap, ForEachLoop) {
719  map.insert(1, 2);
720  size_t iters = 0;
721  for (const auto& kv : map) {
722  EXPECT_EQ(kv.first, 1);
723  EXPECT_EQ(kv.second, 2);
724  ++iters;
725  }
726  EXPECT_EQ(iters, 1);
727 }
728 
729 TEST(ConcurrentHashMap, IteratorMove) {
730  using CHM = ConcurrentHashMap<int, int>;
731  using Iter = CHM::ConstIterator;
732  struct Foo {
733  Iter it;
734  explicit Foo(Iter&& it_) : it(std::move(it_)) {}
735  Foo(Foo&&) = default;
736  Foo& operator=(Foo&&) = default;
737  };
738  CHM map;
739  int k = 111;
740  int v = 999999;
741  map.insert(k, v);
742  Foo foo(map.find(k));
743  ASSERT_EQ(foo.it->second, v);
744  Foo foo2(map.find(0));
745  foo2 = std::move(foo);
746  ASSERT_EQ(foo2.it->second, v);
747 }
bool empty() const noexcept
auto v
static int copied
#define ASSERT_EQ(val1, val2)
Definition: gtest.h:1956
std::pair< ConstIterator, bool > try_emplace(Key &&k, Args &&...args)
char b
ConstIterator cbegin() const noexcept
ConstIterator cend() const noexcept
static const int seed
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
folly::Optional< ConstIterator > assign(Key &&k, Value &&v)
#define Mutex
STL namespace.
FOLLY_NOINLINE void foo2()
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
double val
Definition: String.cpp:273
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
size_type erase(const key_type &k)
#define EXPECT_GE(val1, val2)
Definition: gtest.h:1932
DEFINE_int64(threadtimeout_ms, 60000,"Idle time before ThreadPoolExecutor threads are joined")
const ValueType at(const KeyType &key) const
uint32_t jenkins_rev_mix32(uint32_t key) noexcept
Definition: Hash.h:97
std::unordered_map< int64_t, VecT > Map
folly::Optional< ConstIterator > assign_if_equal(Key &&k, const ValueType &expected, Value &&desired)
std::vector< std::thread::id > threads
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
static std::function< size_t(size_t)> uniform(uint64_t seed)
auto const foo
Definition: LazyTest.cpp:49
ConstIterator find(const KeyType &k) const
def Iter(n, format, sep='')
#define Atom
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
static Map map(mapCap)
static map< string, int > m
void hazptr_cleanup(hazptr_domain< Atom > &domain=default_hazptr_domain< Atom >()) noexcept
Definition: HazptrDomain.h:384
char a
foo(const foo &)
std::pair< ConstIterator, bool > insert(std::pair< key_type, mapped_type > &&foo)
std::pair< ConstIterator, bool > emplace(Args &&...args)
folly::Singleton< int > bar
bool operator==(const MovableInt &a, const MovableInt &b)
TEST(ProgramOptionsTest, Errors)
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
size_t size() const noexcept
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
void join(const Delim &delimiter, Iterator begin, Iterator end, String &output)
Definition: String-inl.h:498
static int moved
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
void reserve(size_t count)
foo & operator=(foo &&)
KeyT k
bool check(const dynamic &schema, const dynamic &value, bool check=true)
std::pair< ConstIterator, bool > insert_or_assign(Key &&k, Value &&v)
foo(foo &&) noexcept
Wrapper(bool &del_)
foo & operator=(const foo &)