openMSX
ObjectPool_test.cc
Go to the documentation of this file.
1 #include "catch.hpp"
2 
3 #include "ObjectPool.hh"
4 #include "xrange.hh"
5 #include <vector>
6 
7 
8 struct Tracked
9 {
10  static inline std::vector<int> constructed;
11  static inline std::vector<int> destructed;
12 
13  Tracked(int i_) : i(i_) {
14  constructed.push_back(i);
15  }
17  destructed.push_back(i);
18  }
19  int i;
20 };
21 
22 TEST_CASE("ObjectPool")
23 {
24  REQUIRE(Tracked::constructed.empty());
25  REQUIRE(Tracked::destructed.empty());
26 
27  {
29  CHECK(pool.capacity() == 0); // empty pool does no memory allocation
30 
31  // insert '10'
32  auto [idx1, ptr1] = pool.emplace(10);
33  CHECK(ptr1->i == 10);
34  CHECK(&pool[idx1] == ptr1);
35  CHECK(Tracked::constructed == std::vector{10});
36  CHECK(Tracked::destructed == std::vector<int>{});
37  CHECK(pool.capacity() == 256); // allocates in chunks of 256
38 
39  // insert '20'
40  auto [idx2, ptr2] = pool.emplace(20);
41  CHECK(ptr1->i == 10);
42  CHECK(ptr2->i == 20);
43  CHECK(&pool[idx1] == ptr1);
44  CHECK(&pool[idx2] == ptr2);
45  CHECK(Tracked::constructed == std::vector{10, 20});
46  CHECK(Tracked::destructed == std::vector<int>{});
47 
48  // insert '30'
49  auto [idx3, ptr3] = pool.emplace(30);
50  CHECK(ptr1->i == 10);
51  CHECK(ptr2->i == 20);
52  CHECK(ptr3->i == 30);
53  CHECK(&pool[idx1] == ptr1);
54  CHECK(&pool[idx2] == ptr2);
55  CHECK(&pool[idx3] == ptr3);
56  CHECK(Tracked::constructed == std::vector{10, 20, 30});
57  CHECK(Tracked::destructed == std::vector<int>{});
58 
59  // remove '20'
60  pool.remove(idx2);
61  CHECK(ptr1->i == 10);
62  CHECK(ptr3->i == 30);
63  CHECK(&pool[idx1] == ptr1);
64  CHECK(&pool[idx3] == ptr3);
65  CHECK(Tracked::constructed == std::vector{10, 20, 30});
66  CHECK(Tracked::destructed == std::vector{20});
67 
68  // insert '40'
69  auto [idx4, ptr4] = pool.emplace(40);
70  CHECK(idx4 == idx2); // recycled
71  CHECK(ptr1->i == 10);
72  CHECK(ptr3->i == 30);
73  CHECK(ptr4->i == 40);
74  CHECK(&pool[idx1] == ptr1);
75  CHECK(&pool[idx3] == ptr3);
76  CHECK(&pool[idx4] == ptr4);
77  CHECK(Tracked::constructed == std::vector{10, 20, 30, 40});
78  CHECK(Tracked::destructed == std::vector{20});
79  CHECK(pool.capacity() == 256);
80 
81  // insert a lot more (force allocating more memory in the pool)
82  for (auto i : xrange(1000)) {
83  auto val = 1000 + i;
84  auto [idx, ptr] = pool.emplace(val);
85  CHECK(ptr->i == val);
86  CHECK(&pool[idx] == ptr);
87  }
88  CHECK(Tracked::constructed.size() == 1004);
89  CHECK(Tracked::destructed == std::vector{20});
90  CHECK(pool.capacity() == 1024);
91  }
92 
93  // When 'pool' goes out of scope it does _not_ destruct the elements it
94  // still contained. (But it does free the memory it used to store those
95  // elements.)
96  CHECK(Tracked::constructed.size() == 1004);
97  CHECK(Tracked::destructed == std::vector{20});
98 }
99 
100 
101 // To (manually) inspect quality of generated code
102 #if 0
103 
104 auto inspect_operator(ObjectPool<int>& pool, unsigned idx)
105 {
106  return pool[idx];
107 }
108 
109 auto inspect_emplace(ObjectPool<int>& pool, int val)
110 {
111  return pool.emplace(val);
112 }
113 
114 void inspect_remove(ObjectPool<int>& pool, unsigned idx)
115 {
116  return pool.remove(idx);
117 }
118 
119 #endif
TEST_CASE("ObjectPool")
Index capacity() const
Definition: ObjectPool.hh:119
void remove(Index idx)
Definition: ObjectPool.hh:95
EmplaceResult emplace(Args &&...args)
Definition: ObjectPool.hh:75
CHECK(m3==m3)
size_t size(std::string_view utf8)
static std::vector< int > constructed
Tracked(int i_)
static std::vector< int > destructed
constexpr auto xrange(T e)
Definition: xrange.hh:155