Skip to content

Commit 83778aa

Browse files
committed
use shared ptr
1 parent f5436dd commit 83778aa

File tree

3 files changed

+87
-94
lines changed

3 files changed

+87
-94
lines changed

examples/example_pool_allocator.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <dice/template-library/pool_allocator.hpp>
22

3+
#include <cstddef>
34
#include <cstdint>
45
#include <iostream>
56
#include <vector>
@@ -10,10 +11,10 @@ struct list {
1011
};
1112

1213
int main() {
13-
dice::template_library::pool<sizeof(list)> pool;
14+
dice::template_library::pool_allocator<std::byte, sizeof(list)> alloc;
1415

1516
{ // efficient pool allocations for elements of known size
16-
auto list_alloc = pool.get_allocator<list>();
17+
dice::template_library::pool_allocator<list, sizeof(list)> list_alloc = alloc;
1718

1819
auto *head = list_alloc.allocate(1); // efficient pool allocation
1920
new (head) list{.elem = 0, .next = nullptr};
@@ -32,7 +33,7 @@ int main() {
3233
}
3334

3435
{ // fallback allocation with new & support as container allocator
35-
std::vector<uint64_t, dice::template_library::pool_allocator<uint64_t, sizeof(list)>> vec(pool.get_allocator());
36+
std::vector<uint64_t, dice::template_library::pool_allocator<uint64_t, sizeof(list)>> vec(alloc);
3637
vec.resize(1024);
3738
}
3839
}

include/dice/template-library/pool_allocator.hpp

+78-84
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <array>
88
#include <cstddef>
99
#include <type_traits>
10+
#include <memory>
1011

1112
namespace dice::template_library {
1213

@@ -23,79 +24,6 @@ namespace dice::template_library {
2324
* Importantly, it is **not** the arena chunk size, rather it is the size of elements being placed into the arena.
2425
* The chunk size itself as well as the maximum capacity cannot be configured, they are automatically determined by boost::pool.
2526
*/
26-
template<size_t ...bucket_sizes>
27-
struct pool;
28-
29-
/**
30-
* `std`-style allocator that allocates into an underlying pool.
31-
* The bucket size used for allocation is `sizeof(T) * n_elems`.
32-
*
33-
* @tparam T type to be allocated
34-
* @tparam bucket_sizes same as for `pool<bucket_sizes...>`
35-
*/
36-
template<typename T, size_t ...bucket_sizes>
37-
struct pool_allocator {
38-
using value_type = T;
39-
using pointer = T *;
40-
using const_pointer = T const *;
41-
using void_pointer = void *;
42-
using const_void_pointer = void const *;
43-
using size_type = size_t;
44-
using difference_type = std::ptrdiff_t;
45-
46-
using propagate_on_container_copy_assignment = std::true_type;
47-
using propagate_on_container_move_assignment = std::true_type;
48-
using propagate_on_container_swap = std::true_type;
49-
using is_always_equal = std::false_type;
50-
51-
template<typename U>
52-
struct rebind {
53-
using other = pool_allocator<U, bucket_sizes...>;
54-
};
55-
56-
private:
57-
template<typename, size_t ...>
58-
friend struct pool_allocator;
59-
60-
pool<bucket_sizes...> *pool_;
61-
62-
public:
63-
explicit pool_allocator(pool<bucket_sizes...> &parent_pool) noexcept
64-
: pool_{&parent_pool} {
65-
}
66-
67-
pool_allocator(pool_allocator const &other) noexcept = default;
68-
pool_allocator(pool_allocator &&other) noexcept = default;
69-
pool_allocator &operator=(pool_allocator const &other) noexcept = default;
70-
pool_allocator &operator=(pool_allocator &&other) noexcept = default;
71-
~pool_allocator() noexcept = default;
72-
73-
template<typename U>
74-
pool_allocator(pool_allocator<U, bucket_sizes...> const &other) noexcept
75-
: pool_{other.pool_} {
76-
}
77-
78-
pointer allocate(size_t n) {
79-
return static_cast<pointer>(pool_->allocate(sizeof(T) * n));
80-
}
81-
82-
void deallocate(pointer ptr, size_t n) {
83-
pool_->deallocate(ptr, sizeof(T) * n);
84-
}
85-
86-
pool_allocator select_on_container_copy_construction() const {
87-
return pool_allocator{*pool_};
88-
}
89-
90-
friend void swap(pool_allocator &lhs, pool_allocator &rhs) noexcept {
91-
using std::swap;
92-
swap(lhs.pool_, rhs.pool_);
93-
}
94-
95-
bool operator==(pool_allocator const &other) const noexcept = default;
96-
bool operator!=(pool_allocator const &other) const noexcept = default;
97-
};
98-
9927
template<size_t ...bucket_sizes>
10028
struct pool {
10129
static_assert(sizeof...(bucket_sizes) > 0,
@@ -106,9 +34,6 @@ namespace dice::template_library {
10634
using size_type = size_t;
10735
using difference_type = std::ptrdiff_t;
10836

109-
template<typename T>
110-
using allocator_type = pool_allocator<T, bucket_sizes...>;
111-
11237
private:
11338
// note: underlying allocator can not be specified via template parameter
11439
// because that would be of very limited usefulness, as boost::pool requires the allocation/deallocation functions
@@ -188,18 +113,87 @@ namespace dice::template_library {
188113
void deallocate(void *data, size_t n_bytes) {
189114
return deallocate_impl<0, bucket_sizes...>(data, n_bytes);
190115
}
116+
};
117+
118+
/**
119+
* `std`-style allocator that allocates into an underlying pool.
120+
* The bucket size used for allocation is `sizeof(T) * n_elems`.
121+
*
122+
* @tparam T type to be allocated
123+
* @tparam bucket_sizes same as for `pool<bucket_sizes...>`
124+
*/
125+
template<typename T, size_t ...bucket_sizes>
126+
struct pool_allocator {
127+
using value_type = T;
128+
using pointer = T *;
129+
using const_pointer = T const *;
130+
using void_pointer = void *;
131+
using const_void_pointer = void const *;
132+
using size_type = size_t;
133+
using difference_type = std::ptrdiff_t;
191134

135+
using propagate_on_container_copy_assignment = std::true_type;
136+
using propagate_on_container_move_assignment = std::true_type;
137+
using propagate_on_container_swap = std::true_type;
138+
using is_always_equal = std::false_type;
139+
140+
template<typename U>
141+
struct rebind {
142+
using other = pool_allocator<U, bucket_sizes...>;
143+
};
144+
145+
private:
146+
template<typename, size_t ...>
147+
friend struct pool_allocator;
148+
149+
std::shared_ptr<pool<bucket_sizes...>> pool_;
150+
151+
public:
192152
/**
193-
* Retrieve an (`std`-style) allocator that allocates on `*this` pool.
194-
*
195-
* @warning the pool (`*this`) must always outlive the returned `pool_allocator`
196-
* @tparam T the type that should be allocated by the returned allocator
197-
* @return `std`-style allocator for this pool
153+
* Creates a pool_allocator with a default constructed pool
198154
*/
199-
template<typename T = std::byte>
200-
[[nodiscard]] allocator_type<T> get_allocator() noexcept {
201-
return pool_allocator<T, bucket_sizes...>{*this};
155+
pool_allocator()
156+
: pool_{std::make_shared<pool<bucket_sizes...>>()} {
202157
}
158+
159+
explicit pool_allocator(std::shared_ptr<pool<bucket_sizes...>> underlying_pool)
160+
: pool_{std::move(underlying_pool)} {
161+
}
162+
163+
pool_allocator(pool_allocator const &other) noexcept = default;
164+
pool_allocator(pool_allocator &&other) noexcept = default;
165+
pool_allocator &operator=(pool_allocator const &other) noexcept = default;
166+
pool_allocator &operator=(pool_allocator &&other) noexcept = default;
167+
~pool_allocator() noexcept = default;
168+
169+
template<typename U>
170+
pool_allocator(pool_allocator<U, bucket_sizes...> const &other) noexcept
171+
: pool_{other.pool_} {
172+
}
173+
174+
[[nodiscard]] std::shared_ptr<pool<bucket_sizes...>> const &underlying_pool() const noexcept {
175+
return pool_;
176+
}
177+
178+
pointer allocate(size_t n) {
179+
return static_cast<pointer>(pool_->allocate(sizeof(T) * n));
180+
}
181+
182+
void deallocate(pointer ptr, size_t n) {
183+
pool_->deallocate(ptr, sizeof(T) * n);
184+
}
185+
186+
pool_allocator select_on_container_copy_construction() const {
187+
return pool_allocator{pool_};
188+
}
189+
190+
friend void swap(pool_allocator &lhs, pool_allocator &rhs) noexcept {
191+
using std::swap;
192+
swap(lhs.pool_, rhs.pool_);
193+
}
194+
195+
bool operator==(pool_allocator const &other) const noexcept = default;
196+
bool operator!=(pool_allocator const &other) const noexcept = default;
203197
};
204198

205199
} // namespace dice::template_library

tests/tests_pool_allocator.cpp

+5-7
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ TEST_SUITE("pool allocator") {
3838
}
3939

4040
TEST_CASE("many allocations and deallocations") {
41-
dice::template_library::pool<8, 16> pool;
42-
auto alloc1 = pool.get_allocator<uint64_t>(); // first pool
43-
auto alloc2 = pool.get_allocator<std::array<uint64_t, 2>>(); // second pool
44-
auto alloc3 = pool.get_allocator<std::array<uint64_t, 4>>(); // fallback to new
41+
dice::template_library::pool_allocator<std::byte, 8, 16> alloc;
42+
dice::template_library::pool_allocator<uint64_t, 8, 16> alloc1 = alloc; // first pool
43+
dice::template_library::pool_allocator<std::array<uint64_t, 2>, 8, 16> alloc2 = alloc; // second pool
44+
dice::template_library::pool_allocator<std::array<uint64_t, 4>, 8, 16> alloc3 = alloc; // fallback to new
4545

4646
for (size_t ix = 0; ix < 1'000'000; ++ix) {
4747
auto *ptr1 = alloc1.allocate(1);
@@ -55,7 +55,6 @@ TEST_SUITE("pool allocator") {
5555
}
5656

5757
TEST_CASE("allocator interface") {
58-
using pool_type = dice::template_library::pool<8, 16>;
5958
using allocator_type = dice::template_library::pool_allocator<uint64_t, 8, 16>;
6059
using allocator_traits = std::allocator_traits<allocator_type>;
6160

@@ -73,8 +72,7 @@ TEST_SUITE("pool allocator") {
7372
static_assert(std::is_same_v<typename allocator_traits::template rebind_alloc<int64_t>, dice::template_library::pool_allocator<int64_t, 8, 16>>);
7473
static_assert(std::is_same_v<typename allocator_traits::template rebind_traits<int64_t>, std::allocator_traits<dice::template_library::pool_allocator<int64_t, 8, 16>>>);
7574

76-
pool_type pool;
77-
allocator_type alloc = pool.get_allocator<uint64_t>();
75+
allocator_type alloc;
7876

7977
uint64_t *ptr = allocator_traits::allocate(alloc, 1);
8078
*ptr = 123;

0 commit comments

Comments
 (0)