@@ -26,133 +26,43 @@ namespace mem {
26
26
class LIBIPC_EXPORT block_collector {
27
27
public:
28
28
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;
30
31
};
31
32
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 ;
48
35
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 ;
70
39
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 {
125
41
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
147
47
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 ));
149
51
150
52
template <typename T>
151
53
struct 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;
154
58
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;
156
66
} LIBIPC_CATCH (...) {
157
67
return nullptr ;
158
68
}
@@ -161,10 +71,18 @@ struct do_allocate {
161
71
162
72
template <>
163
73
struct 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 {
166
75
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;
168
86
}
169
87
};
170
88
@@ -174,19 +92,16 @@ struct do_allocate<void> {
174
92
// / \note This function is thread-safe.
175
93
template <typename T, typename ... A>
176
94
T *$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)...);
180
96
}
181
97
182
98
// / \brief Destroys object previously allocated by the `$new` and releases obtained memory area.
183
99
// / \note This function is thread-safe. If the pointer type passed in is different from `$new`,
184
100
// / additional performance penalties may be incurred.
185
101
inline void $delete (void *p) noexcept {
186
102
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);
190
105
}
191
106
192
107
// / \brief The destruction policy used by std::unique_ptr.
0 commit comments