9
9
#include < algorithm>
10
10
#include < type_traits>
11
11
#include < limits>
12
+ #include < tuple>
12
13
13
14
#include " libipc/imp/aligned.h"
14
15
#include " libipc/imp/uninitialized.h"
@@ -29,13 +30,13 @@ class LIBIPC_EXPORT block_collector {
29
30
};
30
31
31
32
#if defined(LIBIPC_CPP_17)
32
- using get_block_collector_t = block_collector * (*)() noexcept ;
33
+ using recycle_t = void (*)(void *p, void *o, std:: size_t bytes, std:: size_t alignment ) noexcept ;
33
34
#else
34
- using get_block_collector_t = block_collector * (*)();
35
+ using recycle_t = void (*)(void *p, void *o, std:: size_t bytes, std:: size_t alignment );
35
36
#endif
36
37
37
38
static constexpr std::size_t regular_head_size
38
- = round_up(sizeof (get_block_collector_t ), alignof (std::max_align_t ));
39
+ = round_up(sizeof (recycle_t ), alignof (std::max_align_t ));
39
40
40
41
// / \brief Select the incremental level based on the size.
41
42
constexpr inline std::size_t regular_level (std::size_t s) noexcept {
@@ -64,6 +65,11 @@ constexpr inline std::size_t regular_sizeof() noexcept {
64
65
return regular_sizeof_impl (regular_head_size + sizeof (T));
65
66
}
66
67
68
+ template <>
69
+ constexpr inline std::size_t regular_sizeof<void >() noexcept {
70
+ return (std::numeric_limits<std::size_t >::max)();
71
+ }
72
+
67
73
// / \brief Use block pools to handle memory less than 64K.
68
74
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
69
75
class block_resource_base : public block_pool <BlockSize, BlockPoolExpansion> {
@@ -107,20 +113,21 @@ class block_pool_resource : public block_resource_base<BlockSize, BlockPoolExpan
107
113
return &instance;
108
114
}
109
115
116
+ template <typename T>
110
117
void *allocate (std::size_t bytes, std::size_t alignment = alignof (std::max_align_t )) noexcept {
111
118
void *p = base_t::allocate (bytes, alignment);
112
- *static_cast <get_block_collector_t *>(p) = get;
119
+ *static_cast <recycle_t *>(p)
120
+ = [](void *p, void *o, std::size_t bytes, std::size_t alignment) noexcept {
121
+ std::ignore = destroy (static_cast <T *>(o));
122
+ get ()->recycle (p, bytes, alignment);
123
+ };
113
124
return static_cast <byte *>(p) + regular_head_size;
114
125
}
115
126
116
127
void deallocate (void *p, std::size_t bytes, std::size_t alignment = alignof (std::max_align_t )) noexcept {
117
- p = static_cast <byte *>(p) - regular_head_size;
118
- auto g = *static_cast <get_block_collector_t *>(p);
119
- if (g == get) {
120
- base_t::deallocate (p, bytes, alignment);
121
- return ;
122
- }
123
- g ()->recycle (p, bytes, alignment);
128
+ void *b = static_cast <byte *>(p) - regular_head_size;
129
+ auto *r = static_cast <recycle_t *>(b);
130
+ (*r)(b, p, bytes, alignment);
124
131
}
125
132
};
126
133
@@ -141,13 +148,59 @@ auto *get_regular_resource() noexcept {
141
148
return dynamic_cast <block_poll_resource_t *>(block_poll_resource_t::get ());
142
149
}
143
150
151
+ namespace detail_new {
152
+
153
+ template <typename T>
154
+ struct do_allocate {
155
+ template <typename R, typename ... A>
156
+ static T *apply (R *res, A &&... args) noexcept {
157
+ LIBIPC_TRY {
158
+ return construct<T>(res->template allocate <T>(sizeof (T), alignof (T)), std::forward<A>(args)...);
159
+ } LIBIPC_CATCH (...) {
160
+ return nullptr ;
161
+ }
162
+ }
163
+ };
164
+
165
+ template <>
166
+ struct do_allocate <void > {
167
+ template <typename R>
168
+ static void *apply (R *res, std::size_t bytes) noexcept {
169
+ if (bytes == 0 ) return nullptr ;
170
+ return res->template allocate <void >(bytes);
171
+ }
172
+ };
173
+
174
+ template <typename T>
175
+ struct do_deallocate {
176
+ template <typename R>
177
+ static void apply (R *res, T *p) noexcept {
178
+ #if (LIBIPC_CC_MSVC > LIBIPC_CC_MSVC_2015)
179
+ res->deallocate (p, sizeof (T), alignof (T));
180
+ #else
181
+ // `alignof` of vs2015 requires that type must be able to be instantiated.
182
+ res->deallocate (p, sizeof (T));
183
+ #endif
184
+ }
185
+ };
186
+
187
+ template <>
188
+ struct do_deallocate <void > {
189
+ template <typename R>
190
+ static void apply (R *res, void *p) noexcept {
191
+ res->deallocate (p, 0 );
192
+ }
193
+ };
194
+
195
+ } // namespace detail_new
196
+
144
197
// / \brief Creates an object based on the specified type and parameters with block pool resource.
145
198
// / \note This function is thread-safe.
146
199
template <typename T, typename ... A>
147
200
T *$new (A &&... args) noexcept {
148
201
auto *res = get_regular_resource<T>();
149
202
if (res == nullptr ) return nullptr ;
150
- return construct <T>(res-> allocate ( sizeof (T), alignof (T)) , std::forward<A>(args)...);
203
+ return detail_new::do_allocate <T>:: apply (res, std::forward<A>(args)...);
151
204
}
152
205
153
206
// / \brief Destroys object previously allocated by the `$new` and releases obtained memory area.
@@ -156,15 +209,9 @@ T *$new(A &&... args) noexcept {
156
209
template <typename T>
157
210
void $delete (T *p) noexcept {
158
211
if (p == nullptr ) return ;
159
- destroy (p);
160
212
auto *res = get_regular_resource<T>();
161
213
if (res == nullptr ) return ;
162
- #if (LIBIPC_CC_MSVC > LIBIPC_CC_MSVC_2015)
163
- res->deallocate (p, sizeof (T), alignof (T));
164
- #else
165
- // `alignof` of vs2015 requires that type must be able to be instantiated.
166
- res->deallocate (p, sizeof (T));
167
- #endif
214
+ detail_new::do_deallocate<T>::apply (res, p);
168
215
}
169
216
170
217
// / \brief The destruction policy used by std::unique_ptr.
0 commit comments