99#include < algorithm>
1010#include < type_traits>
1111#include < limits>
12+ #include < tuple>
1213
1314#include " libipc/imp/aligned.h"
1415#include " libipc/imp/uninitialized.h"
@@ -29,13 +30,13 @@ class LIBIPC_EXPORT block_collector {
2930};
3031
3132#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 ;
3334#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 );
3536#endif
3637
3738static 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 ));
3940
4041// / \brief Select the incremental level based on the size.
4142constexpr inline std::size_t regular_level (std::size_t s) noexcept {
@@ -64,6 +65,11 @@ constexpr inline std::size_t regular_sizeof() noexcept {
6465 return regular_sizeof_impl (regular_head_size + sizeof (T));
6566}
6667
68+ template <>
69+ constexpr inline std::size_t regular_sizeof<void >() noexcept {
70+ return (std::numeric_limits<std::size_t >::max)();
71+ }
72+
6773// / \brief Use block pools to handle memory less than 64K.
6874template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
6975class block_resource_base : public block_pool <BlockSize, BlockPoolExpansion> {
@@ -107,20 +113,21 @@ class block_pool_resource : public block_resource_base<BlockSize, BlockPoolExpan
107113 return &instance;
108114 }
109115
116+ template <typename T>
110117 void *allocate (std::size_t bytes, std::size_t alignment = alignof (std::max_align_t )) noexcept {
111118 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+ };
113124 return static_cast <byte *>(p) + regular_head_size;
114125 }
115126
116127 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);
124131 }
125132};
126133
@@ -141,13 +148,59 @@ auto *get_regular_resource() noexcept {
141148 return dynamic_cast <block_poll_resource_t *>(block_poll_resource_t::get ());
142149}
143150
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+
144197// / \brief Creates an object based on the specified type and parameters with block pool resource.
145198// / \note This function is thread-safe.
146199template <typename T, typename ... A>
147200T *$new (A &&... args) noexcept {
148201 auto *res = get_regular_resource<T>();
149202 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)...);
151204}
152205
153206// / \brief Destroys object previously allocated by the `$new` and releases obtained memory area.
@@ -156,15 +209,9 @@ T *$new(A &&... args) noexcept {
156209template <typename T>
157210void $delete (T *p) noexcept {
158211 if (p == nullptr ) return ;
159- destroy (p);
160212 auto *res = get_regular_resource<T>();
161213 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);
168215}
169216
170217// / \brief The destruction policy used by std::unique_ptr.
0 commit comments