@@ -26,133 +26,43 @@ namespace mem {
2626class LIBIPC_EXPORT block_collector {
2727public:
2828 virtual ~block_collector () noexcept = default ;
29- virtual void recycle (void */*p*/) noexcept {}
29+ virtual void *allocate (std::size_t /* bytes*/ ) noexcept = 0;
30+ virtual void deallocate (void */*p*/, std::size_t /*bytes*/) noexcept = 0;
3031};
3132
32- #if defined(LIBIPC_CPP_17)
33- using recycle_t = void (*)(void *p, void *o) noexcept ;
34- #else
35- using recycle_t = void (*)(void *p, void *o);
36- #endif
37-
38- static constexpr std::size_t regular_head_size
39- = round_up(sizeof (recycle_t ), alignof(std::max_align_t ));
40-
41- // / \brief Select the incremental level based on the size.
42- constexpr inline std::size_t regular_level (std::size_t s) noexcept {
43- return (s <= 128 ) ? 0 :
44- (s <= 1024 ) ? 1 :
45- (s <= 8192 ) ? 2 :
46- (s <= 65536 ) ? 3 : 4 ;
47- }
33+ // / \brief Matches the appropriate memory block resource based on a specified size.
34+ LIBIPC_EXPORT block_collector &get_regular_resource (std::size_t s) noexcept ;
4835
49- // / \brief Calculates the appropriate memory block size based on the increment level and size.
50- constexpr inline std::size_t regular_sizeof_impl (std::size_t l, std::size_t s) noexcept {
51- return (l == 0 ) ? round_up<std::size_t >(s, regular_head_size) :
52- (l == 1 ) ? round_up<std::size_t >(s, 128 ) :
53- (l == 2 ) ? round_up<std::size_t >(s, 1024 ) :
54- (l == 3 ) ? round_up<std::size_t >(s, 8192 ) : (std::numeric_limits<std::size_t >::max)();
55- }
56-
57- // / \brief Calculates the appropriate memory block size based on the size.
58- constexpr inline std::size_t regular_sizeof_impl (std::size_t s) noexcept {
59- return regular_sizeof_impl (regular_level (s), s);
60- }
61-
62- // / \brief Calculates the appropriate memory block size based on the specific type.
63- constexpr inline std::size_t regular_sizeof (std::size_t s) noexcept {
64- return regular_sizeof_impl (regular_head_size + s);
65- }
66- template <typename T, std::size_t S = sizeof (T)>
67- constexpr inline std::size_t regular_sizeof () noexcept {
68- return regular_sizeof (S);
69- }
36+ // / \brief Allocates storage with a size of at least bytes bytes.
37+ LIBIPC_EXPORT void *alloc (std::size_t bytes) noexcept ;
38+ LIBIPC_EXPORT void free (void *p, std::size_t bytes) noexcept ;
7039
71- // / \brief Use block pools to handle memory less than 64K.
72- template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
73- class block_resource_base : public block_pool <BlockSize, BlockPoolExpansion> {
74- public:
75- void *allocate (std::size_t /* bytes*/ , std::size_t /* alignment*/ ) noexcept {
76- return block_pool<BlockSize, BlockPoolExpansion>::allocate ();
77- }
78-
79- void deallocate (void *p) noexcept {
80- block_pool<BlockSize, BlockPoolExpansion>::deallocate (p);
81- }
82- };
83-
84- // / \brief Use `new`/`delete` to handle memory larger than 64K.
85- template <std::size_t BlockSize>
86- class block_resource_base <BlockSize, 0 > : public new_delete_resource {
87- public:
88- void *allocate (std::size_t bytes, std::size_t alignment) noexcept {
89- return new_delete_resource::allocate (regular_head_size + bytes, alignment);
90- }
91-
92- void deallocate (void *p) noexcept {
93- new_delete_resource::deallocate (p, regular_head_size);
94- }
95- };
96-
97- // / \brief Defines block pool memory resource based on block pool.
98- template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
99- class block_pool_resource : public block_resource_base <BlockSize, BlockPoolExpansion>
100- , public block_collector {
101-
102- using base_t = block_resource_base<BlockSize, BlockPoolExpansion>;
103-
104- void recycle (void *p) noexcept override {
105- base_t::deallocate (p);
106- }
107-
108- public:
109- static block_collector *get () noexcept {
110- thread_local block_pool_resource instance;
111- return &instance;
112- }
113-
114- template <typename T>
115- void *allocate (std::size_t bytes, std::size_t alignment = alignof (std::max_align_t )) noexcept {
116- void *b = base_t::allocate (bytes, alignment);
117- *static_cast <recycle_t *>(b)
118- = [](void *b, void *p) noexcept {
119- std::ignore = destroy (static_cast <T *>(p));
120- get ()->recycle (b);
121- };
122- return static_cast <byte *>(b) + regular_head_size;
123- }
124- };
40+ namespace detail_new {
12541
126- // / \brief Different increment levels match different chunk sizes.
127- // / 512 means that 512 consecutive memory blocks are allocated at a time.
128- template <std::size_t L>
129- constexpr std::size_t block_pool_expansion = 0 ;
130-
131- template <> constexpr std::size_t block_pool_expansion<0 > = 512 ;
132- template <> constexpr std::size_t block_pool_expansion<1 > = 256 ;
133- template <> constexpr std::size_t block_pool_expansion<2 > = 128 ;
134- template <> constexpr std::size_t block_pool_expansion<3 > = 64 ;
135-
136- // / \brief Matches the appropriate memory block resource based on the specified type.
137- template <typename T, std::size_t N = regular_sizeof<T>(), std::size_t L = regular_level(N)>
138- auto *get_regular_resource () noexcept {
139- using block_poll_resource_t = block_pool_resource<N, block_pool_expansion<L>>;
140- return dynamic_cast <block_poll_resource_t *>(block_poll_resource_t::get ());
141- }
142- template <typename T, std::enable_if_t <std::is_void<T>::value, bool > = true >
143- auto *get_regular_resource () noexcept {
144- using block_poll_resource_t = block_pool_resource<0 , 0 >;
145- return dynamic_cast <block_poll_resource_t *>(block_poll_resource_t::get ());
146- }
42+ #if defined(LIBIPC_CPP_17)
43+ using recycle_t = void (*)(void *p) noexcept ;
44+ #else
45+ using recycle_t = void (*)(void *p);
46+ #endif
14747
148- namespace detail_new {
48+ static constexpr std::size_t recycler_size = round_up(sizeof (recycle_t ), alignof (std::size_t ));
49+ static constexpr std::size_t allocated_size = sizeof (std::size_t );
50+ static constexpr std::size_t regular_head_size = round_up(recycler_size + allocated_size, alignof (std::max_align_t ));
14951
15052template <typename T>
15153struct do_allocate {
152- template <typename R, typename ... A>
153- static T *apply (R *res, A &&... args) noexcept {
54+ template <typename ... A>
55+ static T *apply (A &&... args) noexcept {
56+ void *b = mem::alloc (regular_head_size + sizeof (T));
57+ auto *p = static_cast <byte *>(b) + regular_head_size;
15458 LIBIPC_TRY {
155- return construct<T>(res->template allocate <T>(sizeof (T), alignof (T)), std::forward<A>(args)...);
59+ T *t = construct<T>(p, std::forward<A>(args)...);
60+ *reinterpret_cast <recycle_t *>(b)
61+ = [](void *p) noexcept {
62+ mem::free (static_cast <byte *>(destroy (static_cast <T *>(p))) - regular_head_size
63+ , regular_head_size + sizeof (T));
64+ };
65+ return t;
15666 } LIBIPC_CATCH (...) {
15767 return nullptr ;
15868 }
@@ -161,10 +71,18 @@ struct do_allocate {
16171
16272template <>
16373struct do_allocate <void > {
164- template <typename R>
165- static void *apply (R *res, std::size_t bytes) noexcept {
74+ static void *apply (std::size_t bytes) noexcept {
16675 if (bytes == 0 ) return nullptr ;
167- return res->template allocate <void >(bytes);
76+ std::size_t rbz = regular_head_size + bytes;
77+ void *b = mem::alloc (rbz);
78+ *reinterpret_cast <recycle_t *>(b)
79+ = [](void *p) noexcept {
80+ auto *b = static_cast <byte *>(p) - regular_head_size;
81+ mem::free (b, *reinterpret_cast <std::size_t *>(b + recycler_size));
82+ };
83+ auto *z = static_cast <byte *>(b) + recycler_size;
84+ *reinterpret_cast <std::size_t *>(z) = rbz;
85+ return static_cast <byte *>(b) + regular_head_size;
16886 }
16987};
17088
@@ -174,19 +92,16 @@ struct do_allocate<void> {
17492// / \note This function is thread-safe.
17593template <typename T, typename ... A>
17694T *$new (A &&... args) noexcept {
177- auto *res = get_regular_resource<T>();
178- if (res == nullptr ) return nullptr ;
179- return detail_new::do_allocate<T>::apply (res, std::forward<A>(args)...);
95+ return detail_new::do_allocate<T>::apply (std::forward<A>(args)...);
18096}
18197
18298// / \brief Destroys object previously allocated by the `$new` and releases obtained memory area.
18399// / \note This function is thread-safe. If the pointer type passed in is different from `$new`,
184100// / additional performance penalties may be incurred.
185101inline void $delete (void *p) noexcept {
186102 if (p == nullptr ) return ;
187- auto *b = reinterpret_cast <byte *>(p) - regular_head_size;
188- auto *r = reinterpret_cast <recycle_t *>(b);
189- (*r)(b, p);
103+ auto *r = reinterpret_cast <detail_new::recycle_t *>(static_cast <byte *>(p) - detail_new::regular_head_size);
104+ (*r)(p);
190105}
191106
192107// / \brief The destruction policy used by std::unique_ptr.
0 commit comments