7
7
#pragma once
8
8
9
9
#include < cstddef>
10
- #include < unordered_map>
11
10
#include < algorithm>
12
11
13
12
#include " libimp/aligned.h"
22
21
23
22
LIBPMR_NAMESPACE_BEG_
24
23
24
+ // / \brief Defines the memory block collector interface.
25
+ class LIBIMP_EXPORT block_collector {
26
+ public:
27
+ virtual ~block_collector () noexcept = default ;
28
+ virtual void deallocate (void *p) noexcept = 0;
29
+ };
30
+
31
+ using get_block_collector_t = block_collector *(*)() noexcept ;
32
+
33
+ static constexpr std::size_t regular_head_size
34
+ = ::LIBIMP::round_up(sizeof (get_block_collector_t ), alignof (std::max_align_t ));
35
+
25
36
// / \brief Select the incremental level based on the size.
26
37
constexpr inline std::size_t regular_level (std::size_t s) noexcept {
27
38
return (s <= 128 ) ? 0 :
@@ -32,52 +43,25 @@ constexpr inline std::size_t regular_level(std::size_t s) noexcept {
32
43
33
44
// / \brief Calculates the appropriate memory block size based on the increment level and size.
34
45
constexpr inline std::size_t regular_sizeof_impl (std::size_t l, std::size_t s) noexcept {
35
- return (l == 0 ) ? std::max<std:: size_t >(:: LIBIMP::round_up<std::size_t >(s, 8 ) , regular_head_size) :
46
+ return (l == 0 ) ? :: LIBIMP::round_up<std::size_t >(s, regular_head_size) :
36
47
(l == 1 ) ? ::LIBIMP::round_up<std::size_t >(s, 128 ) :
37
48
(l == 2 ) ? ::LIBIMP::round_up<std::size_t >(s, 1024 ) :
38
49
(l == 3 ) ? ::LIBIMP::round_up<std::size_t >(s, 8192 ) : (std::numeric_limits<std::size_t >::max)();
39
50
}
40
51
41
52
// / \brief Calculates the appropriate memory block size based on the size.
42
- constexpr inline std::size_t regular_sizeof (std::size_t s) noexcept {
53
+ constexpr inline std::size_t regular_sizeof_impl (std::size_t s) noexcept {
43
54
return regular_sizeof_impl (regular_level (s), s);
44
55
}
45
56
46
57
// / \brief Calculates the appropriate memory block size based on the specific type.
47
58
template <typename T>
48
59
constexpr inline std::size_t regular_sizeof () noexcept {
49
- return regular_sizeof (regular_head_size + sizeof (T));
60
+ return regular_sizeof_impl (regular_head_size + sizeof (T));
50
61
}
51
62
52
- // / \brief Defines the memory block collector interface.
53
- class LIBIMP_EXPORT block_collector {
54
- public:
55
- virtual ~block_collector () noexcept = default ;
56
- virtual void deallocate (void *p) noexcept = 0;
57
- };
58
-
59
- // / \brief Gets all block pools of the thread cache.
60
- LIBIMP_EXPORT auto get_thread_block_pool_map () noexcept
61
- -> std::unordered_map<std::size_t, block_collector *> &;
62
-
63
63
// / \brief Defines block pool memory resource based on block pool.
64
64
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
65
- class block_pool_resource ;
66
-
67
- // / \brief Memory block collector of unknown size.
68
- // / \note This memory resource is only used to temporarily collect memory blocks
69
- // / that cannot find a suitable block pool memory resource.
70
- template <>
71
- class block_pool_resource <0 , 0 > : public block_pool<0 , 0 >
72
- , public block_collector {
73
- public:
74
- void deallocate (void *p) noexcept override {
75
- block_pool<0 , 0 >::deallocate (p);
76
- }
77
- };
78
-
79
- // / \brief A block pool memory resource for a block of memory of a specific size.
80
- template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
81
65
class block_pool_resource : public block_pool <BlockSize, BlockPoolExpansion>
82
66
, public block_collector {
83
67
@@ -88,99 +72,59 @@ class block_pool_resource : public block_pool<BlockSize, BlockPoolExpansion>
88
72
}
89
73
90
74
public:
91
- static block_pool_resource *get () noexcept ;
75
+ static block_collector *get () noexcept {
76
+ thread_local block_pool_resource instance;
77
+ return &instance;
78
+ }
92
79
93
80
using base_t ::base_t ;
94
81
95
82
void *allocate (std::size_t /* bytes*/ , std::size_t /* alignment*/ = alignof (std::max_align_t )) noexcept {
96
83
void *p = base_t::allocate ();
97
- p = ::LIBIMP::construct<std:: size_t >(p, BlockSize) ;
98
- return reinterpret_cast <::LIBIMP::byte *>(p) + regular_head_size;
84
+ * static_cast < get_block_collector_t * >(p) = get ;
85
+ return static_cast <::LIBIMP::byte *>(p) + regular_head_size;
99
86
}
100
87
101
88
void deallocate (void *p, std::size_t /* bytes*/ , std::size_t /* alignment*/ = alignof (std::max_align_t )) noexcept {
102
- p = reinterpret_cast <::LIBIMP::byte *>(p) - regular_head_size;
103
- auto r_size = *static_cast <std:: size_t *>(p);
104
- if (r_size <= BlockSize ) {
89
+ p = static_cast <::LIBIMP::byte *>(p) - regular_head_size;
90
+ auto g = *static_cast <get_block_collector_t *>(p);
91
+ if (g == get ) {
105
92
base_t::deallocate (p);
106
93
return ;
107
94
}
108
- // When the actual size exceeds the current memory block size,
109
- // try to find a suitable pool among all memory block pools for this thread.
110
- auto &map = get_thread_block_pool_map ();
111
- auto it = map.find (r_size);
112
- if ((it == map.end ()) || (it->second == nullptr )) {
113
- block_pool_resource<0 , 0 > *bp = nullptr ;
114
- LIBIMP_TRY {
115
- // If the corresponding memory resource cannot be found,
116
- // create a temporary general-purpose block pool to deallocate memory.
117
- it = map.emplace (r_size, bp = new block_pool_resource<0 , 0 >).first ;
118
- } LIBIMP_CATCH (...) {
119
- // If the memory resource cannot be created,
120
- // store the pointer directly to avoid leakage.
121
- delete bp;
122
- base_t::deallocate (p);
123
- return ;
124
- }
125
- }
126
- it->second ->deallocate (p);
95
+ g ()->deallocate (p);
127
96
}
128
97
};
129
98
130
- template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
131
- auto block_pool_resource<BlockSize, BlockPoolExpansion>::get() noexcept
132
- -> block_pool_resource<BlockSize, BlockPoolExpansion> * {
133
- thread_local block_pool_resource *pi = nullptr ;
134
- if (pi != nullptr ) {
135
- return pi;
136
- }
137
- // Create a new block pool resource for this thread.
138
- auto &map = get_thread_block_pool_map ();
139
- auto it = map.find (BlockSize);
140
- if ((it != map.end ()) && (it->second != nullptr )) {
141
- // If there are existing block pool resources in the thread cache,
142
- // a new block pool resource is constructed based on it and the cache is updated.
143
- auto *bp = static_cast <block_pool<0 , 0 > *>(
144
- dynamic_cast <block_pool_resource<0 , 0 > *>(it->second ));
145
- if (bp == nullptr ) {
146
- return nullptr ;
147
- }
148
- thread_local block_pool_resource instance (std::move (*bp));
149
- delete static_cast <block_pool_resource<0 , 0 > *>(bp);
150
- it->second = pi = &instance;
151
- return pi;
152
- } else {
153
- // If there are no existing block pool resources in the thread cache,
154
- // the thread local storage instance is constructed and the pointer is cached.
155
- thread_local block_pool_resource instance;
156
- LIBIMP_TRY {
157
- map.emplace (BlockSize, pi = &instance);
158
- return pi;
159
- } LIBIMP_CATCH (...) {
160
- return nullptr ;
161
- }
162
- }
163
- }
99
+ // / \brief Different increment levels match different chunk sizes.
100
+ // / 512 means that 512 consecutive memory blocks are allocated at a time, and the block size is N.
101
+ template <std::size_t L>
102
+ constexpr static std::size_t block_pool_expansion = 0 ;
103
+
104
+ template <> constexpr static std::size_t block_pool_expansion<0 > = 512 ;
105
+ template <> constexpr static std::size_t block_pool_expansion<1 > = 256 ;
106
+ template <> constexpr static std::size_t block_pool_expansion<2 > = 128 ;
107
+ template <> constexpr static std::size_t block_pool_expansion<3 > = 64 ;
164
108
165
- // / \brief Match the appropriate memory block resources
166
- // / according to the size of the specification.
109
+ // / \brief Match the appropriate memory block resources according to the size of the specification.
167
110
template <std::size_t N, std::size_t L = regular_level(N)>
168
- class regular_resource : public new_delete_resource {};
111
+ struct regular_resource {
112
+ static auto *get () noexcept {
113
+ using block_poll_resource_t = block_pool_resource<N, block_pool_expansion<L>>;
114
+ return dynamic_cast <block_poll_resource_t *>(block_poll_resource_t::get ());
115
+ }
116
+ };
169
117
170
- // / \brief Different increment levels match different chunk sizes.
171
- // / 512 means that 512 consecutive memory blocks are allocated at a time, and the block size is N.
172
- template <std::size_t N> class regular_resource <N, 0 > : public block_pool_resource<N, 512 > {};
173
- template <std::size_t N> class regular_resource <N, 1 > : public block_pool_resource<N, 256 > {};
174
- template <std::size_t N> class regular_resource <N, 2 > : public block_pool_resource<N, 128 > {};
175
- template <std::size_t N> class regular_resource <N, 3 > : public block_pool_resource<N, 64 > {};
118
+ template <std::size_t N>
119
+ struct regular_resource <N, 4 > : new_delete_resource {};
176
120
177
121
// / \brief Creates an object based on the specified type and parameters with block pool resource.
178
122
// / \note This function is thread-safe.
179
123
template <typename T, typename ... A>
180
124
T *new $(A &&... args) noexcept {
181
- auto *mem_res = regular_resource<regular_sizeof<T>()>::get ();
182
- if (mem_res == nullptr ) return nullptr ;
183
- return ::LIBIMP::construct<T>(mem_res ->allocate (sizeof (T), alignof (T)), std::forward<A>(args)...);
125
+ auto *res = regular_resource<regular_sizeof<T>()>::get ();
126
+ if (res == nullptr ) return nullptr ;
127
+ return ::LIBIMP::construct<T>(res ->allocate (sizeof (T), alignof (T)), std::forward<A>(args)...);
184
128
}
185
129
186
130
// / \brief Destroys object previously allocated by the `new$` and releases obtained memory area.
@@ -190,13 +134,13 @@ template <typename T>
190
134
void delete $(T *p) noexcept {
191
135
if (p == nullptr ) return ;
192
136
::LIBIMP::destroy (p);
193
- auto *mem_res = regular_resource<regular_sizeof<T>()>::get ();
194
- if (mem_res == nullptr ) return ;
137
+ auto *res = regular_resource<regular_sizeof<T>()>::get ();
138
+ if (res == nullptr ) return ;
195
139
#if defined(LIBIMP_CC_MSVC_2015)
196
140
// `alignof` of vs2015 requires that type must be able to be instantiated.
197
- mem_res ->deallocate (p, sizeof (T));
141
+ res ->deallocate (p, sizeof (T));
198
142
#else
199
- mem_res ->deallocate (p, sizeof (T), alignof (T));
143
+ res ->deallocate (p, sizeof (T), alignof (T));
200
144
#endif
201
145
}
202
146
0 commit comments