Skip to content

Commit 81a097f

Browse files
committed
mempool: implement move semantics for MempoolInstance
Currently it uses default implementations that does not set pointers of moved objects to `NULL` and they are still by moved object. Let's manually implement move semantics because we will need to move MempoolInstance as a part of `tnt::Buffer` later. Along the way, mark other constructors and operators as `noexcept`. Part of #110
1 parent e4f81df commit 81a097f

File tree

2 files changed

+93
-7
lines changed

2 files changed

+93
-7
lines changed

src/Utils/Mempool.hpp

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <cstddef>
3535
#include <cstdint>
3636
#include <cstring>
37+
#include <utility>
3738

3839
namespace tnt {
3940

@@ -44,6 +45,20 @@ class MempoolStats {
4445
void statAddBlock() { ++m_BlockCount; }
4546
void statDelBlock() { --m_BlockCount; }
4647
public:
48+
MempoolStats() = default;
49+
MempoolStats(MempoolStats &&other) noexcept
50+
{
51+
/* Call move assignment operator. */
52+
*this = std::forward<MempoolStats>(other);
53+
}
54+
MempoolStats &operator=(MempoolStats &&other) noexcept
55+
{
56+
m_SlabCount = other.m_SlabCount;
57+
m_BlockCount = other.m_BlockCount;
58+
other.m_SlabCount = 0;
59+
other.m_BlockCount = 0;
60+
}
61+
4762
/** Count of allocated (used) blocks. */
4863
size_t statBlockCount() const { return m_BlockCount; }
4964
/** Count of allocated (total) slabs. */
@@ -60,6 +75,10 @@ class MempoolStats<false> {
6075
void statAddBlock() { }
6176
void statDelBlock() { }
6277
public:
78+
MempoolStats() = default;
79+
MempoolStats(MempoolStats &&other) noexcept = default;
80+
MempoolStats &operator=(MempoolStats &&other) noexcept = default;
81+
6382
/** Disabled. return SIZE_MAX. */
6483
size_t statBlockCount() const { return SIZE_MAX; }
6584
/** Disabled. return SIZE_MAX. */
@@ -106,6 +125,15 @@ class MempoolInstance : public MempoolStats<ENABLE_STATS> {
106125

107126
using Stats_t = MempoolStats<ENABLE_STATS>;
108127

128+
void ReleaseSlabList(void) noexcept
129+
{
130+
while (m_SlabList != nullptr) {
131+
Slab *tmp = m_SlabList;
132+
m_SlabList = m_SlabList->next;
133+
delete tmp;
134+
}
135+
}
136+
109137
public:
110138
// Constants for stat.
111139
static constexpr size_t REAL_SIZE = B;
@@ -114,15 +142,32 @@ class MempoolInstance : public MempoolStats<ENABLE_STATS> {
114142
static constexpr size_t BLOCK_ALIGN = BA;
115143
static constexpr size_t SLAB_ALIGN = SA;
116144

117-
MempoolInstance() = default;
118-
~MempoolInstance() noexcept
145+
MempoolInstance() noexcept = default;
146+
MempoolInstance(const MempoolInstance &other) = delete;
147+
MempoolInstance &operator=(const MempoolInstance &other) = delete;
148+
MempoolInstance(MempoolInstance &&other) noexcept
119149
{
120-
while (m_SlabList != nullptr) {
121-
Slab *tmp = m_SlabList;
122-
m_SlabList = m_SlabList->next;
123-
delete tmp;
124-
}
150+
/* Call move assignment operator. */
151+
*this = std::forward<MempoolInstance>(other);
152+
}
153+
MempoolInstance &operator=(MempoolInstance &&other) noexcept
154+
{
155+
if (this == &other)
156+
return *this;
157+
/* Move base class. */
158+
MempoolStats<ENABLE_STATS>::operator=(std::forward<MempoolInstance>(other));
159+
ReleaseSlabList();
160+
m_SlabList = other.m_SlabList;
161+
m_FreeList = other.m_FreeList;
162+
m_SlabDataBeg = other.m_SlabDataBeg;
163+
m_SlabDataEnd = other.m_SlabDataEnd;
164+
other.m_SlabList = nullptr;
165+
other.m_FreeList = nullptr;
166+
other.m_SlabDataBeg = nullptr;
167+
other.m_SlabDataEnd = nullptr;
168+
return *this;
125169
}
170+
~MempoolInstance() noexcept { ReleaseSlabList(); }
126171
static MempoolInstance& defaultInstance()
127172
{
128173
static MempoolInstance instance;

test/MempoolUnitTest.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "../src/Utils/Mempool.hpp"
3333
#include "Utils/Helpers.hpp"
3434
#include <iostream>
35+
#include <utility>
3536

3637
template <size_t S>
3738
struct Allocation {
@@ -247,6 +248,40 @@ test_alignment()
247248
}
248249
}
249250

251+
template <size_t S>
252+
void
253+
test_move()
254+
{
255+
TEST_INIT(2, S, 0);
256+
constexpr size_t N = 1024;
257+
tnt::MempoolInstance<S> mp;
258+
259+
Allocations<S, N * 6> all;
260+
for (size_t i = 0; i < N; i++)
261+
all.add(mp.allocate());
262+
fail_unless(all.are_valid());
263+
264+
tnt::MempoolInstance<S> mp_move_constructed(std::move(mp));
265+
for (size_t i = 0; i < N; i++) {
266+
all.add(mp_move_constructed.allocate());
267+
all.add(mp.allocate());
268+
}
269+
fail_unless(all.are_valid());
270+
271+
tnt::MempoolInstance<S> mp_move_copied;
272+
/* Allocate some memory and let ASAN check if it won't be leaked. */
273+
for (size_t i = 0; i < N; i++) {
274+
char *ptr = mp_move_copied.allocate();
275+
(void)ptr;
276+
}
277+
mp_move_copied = std::move(mp);
278+
for (size_t i = 0; i < N; i++) {
279+
all.add(mp_move_copied.allocate());
280+
all.add(mp.allocate());
281+
}
282+
fail_unless(all.are_valid());
283+
}
284+
250285
int main()
251286
{
252287
test_default<8>();
@@ -275,4 +310,10 @@ int main()
275310
test_alignment<120, 2>();
276311
test_alignment<120, 13>();
277312
test_alignment<120, 64>();
313+
314+
test_move<8>();
315+
test_move<64>();
316+
test_move<14>();
317+
test_move<72>();
318+
test_move<80>();
278319
}

0 commit comments

Comments
 (0)