7
7
#pragma once
8
8
9
9
#include < cstddef>
10
+ #include < unordered_map>
11
+ #include < algorithm>
10
12
11
13
#include " libimp/aligned.h"
12
14
#include " libimp/uninitialized.h"
15
+ #include " libimp/byte.h"
16
+ #include " libimp/detect_plat.h"
13
17
14
18
#include " libpmr/def.h"
15
19
#include " libpmr/block_pool.h"
@@ -27,34 +31,126 @@ constexpr inline std::size_t regular_level(std::size_t s) noexcept {
27
31
28
32
constexpr inline std::size_t regular_sizeof (std::size_t s) noexcept {
29
33
switch (regular_level (s)) {
30
- case 0 : return :: LIBIMP::round_up<std::size_t >(s, 8 );
34
+ case 0 : return std::max<std:: size_t >(:: LIBIMP::round_up<std::size_t >(s, 8 ), regular_head_size );
31
35
case 1 : return ::LIBIMP::round_up<std::size_t >(s, 128 );
32
36
case 2 : return ::LIBIMP::round_up<std::size_t >(s, 1024 );
33
37
case 3 : return ::LIBIMP::round_up<std::size_t >(s, 8192 );
34
- default : return 0 ;
38
+ default : return (std::numeric_limits<std:: size_t >::max)() ;
35
39
}
36
40
}
37
41
38
42
template <typename T>
39
43
constexpr inline std::size_t regular_sizeof () noexcept {
40
- return regular_sizeof (sizeof (T));
44
+ return regular_sizeof (regular_head_size + sizeof (T));
45
+ }
46
+
47
+ class block_pool_like {
48
+ public:
49
+ virtual ~block_pool_like () noexcept = default ;
50
+ virtual void *allocate () noexcept = 0;
51
+ virtual void deallocate (void *p) noexcept = 0;
52
+ };
53
+
54
+ inline std::unordered_map<std::size_t , block_pool_like *> &get_block_pool_map () noexcept {
55
+ thread_local std::unordered_map<std::size_t , block_pool_like *> instances;
56
+ return instances;
41
57
}
42
58
43
59
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
44
- class block_pool_resource : public block_pool <BlockSize, BlockPoolExpansion> {
60
+ class block_pool_resource ;
61
+
62
+ template <>
63
+ class block_pool_resource <0 , 0 > : public block_pool<0 , 0 >
64
+ , public block_pool_like {
65
+
66
+ void *allocate () noexcept override {
67
+ return nullptr ;
68
+ }
69
+
45
70
public:
46
- static block_pool_resource *get () noexcept {
47
- thread_local block_pool_resource instance;
48
- return &instance;
71
+ void deallocate (void *p) noexcept override {
72
+ block_pool<0 , 0 >::deallocate (p);
73
+ }
74
+ };
75
+
76
+ template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
77
+ class block_pool_resource : public block_pool <BlockSize, BlockPoolExpansion>
78
+ , public block_pool_like {
79
+
80
+ using base_t = block_pool<BlockSize, BlockPoolExpansion>;
81
+
82
+ void *allocate () noexcept override {
83
+ return base_t::allocate ();
49
84
}
85
+
86
+ void deallocate (void *p) noexcept override {
87
+ base_t::deallocate (p);
88
+ }
89
+
90
+ public:
91
+ static block_pool_resource *get () noexcept ;
92
+
93
+ using base_t ::base_t ;
94
+
50
95
void *allocate (std::size_t /* bytes*/ , std::size_t /* alignment*/ = alignof (std::max_align_t )) noexcept {
51
- return block_pool<BlockSize, BlockPoolExpansion>::allocate ();
96
+ void *p = base_t::allocate ();
97
+ p = ::LIBIMP::construct<std::size_t >(p, BlockSize);
98
+ return reinterpret_cast <::LIBIMP::byte *>(p) + regular_head_size;
52
99
}
100
+
53
101
void deallocate (void *p, std::size_t /* bytes*/ , std::size_t /* alignment*/ = alignof (std::max_align_t )) noexcept {
54
- block_pool<BlockSize, BlockPoolExpansion>::deallocate (p);
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) {
105
+ base_t::deallocate (p);
106
+ return ;
107
+ }
108
+ auto &map = get_block_pool_map ();
109
+ auto it = map.find (r_size);
110
+ if ((it == map.end ()) || (it->second == nullptr )) LIBIMP_TRY {
111
+ // If the corresponding memory resource cannot be found,
112
+ // create a temporary general-purpose block pool to deallocate memory.
113
+ it = map.emplace (r_size, new block_pool_resource<0 , 0 >).first ;
114
+ } LIBIMP_CATCH (...) {
115
+ // If the memory resource cannot be created,
116
+ // store the pointer directly to avoid leakage.
117
+ base_t::deallocate (p);
118
+ return ;
119
+ }
120
+ it->second ->deallocate (p);
55
121
}
56
122
};
57
123
124
+ template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
125
+ auto block_pool_resource<BlockSize, BlockPoolExpansion>::get() noexcept
126
+ -> block_pool_resource<BlockSize, BlockPoolExpansion> * {
127
+ auto &map = get_block_pool_map ();
128
+ thread_local block_pool_resource *pi = nullptr ;
129
+ if (pi != nullptr ) {
130
+ return pi;
131
+ }
132
+ auto it = map.find (BlockSize);
133
+ if ((it != map.end ()) && (it->second != nullptr )) {
134
+ auto *bp = static_cast <block_pool<0 , 0 > *>(
135
+ dynamic_cast <block_pool_resource<0 , 0 > *>(it->second ));
136
+ if (bp == nullptr ) {
137
+ return nullptr ;
138
+ }
139
+ thread_local block_pool_resource instance (std::move (*bp));
140
+ delete static_cast <block_pool_resource<0 , 0 > *>(bp);
141
+ pi = &instance;
142
+ } else {
143
+ thread_local block_pool_resource instance;
144
+ pi = &instance;
145
+ }
146
+ LIBIMP_TRY {
147
+ map.emplace (BlockSize, pi);
148
+ } LIBIMP_CATCH (...) {
149
+ return nullptr ;
150
+ }
151
+ return pi;
152
+ }
153
+
58
154
template <std::size_t N, std::size_t L = regular_level(N)>
59
155
class regular_resource : public new_delete_resource {};
60
156
@@ -71,16 +167,19 @@ template <std::size_t N>
71
167
class regular_resource <N, 3 > : public block_pool_resource<N, 64 > {};
72
168
73
169
template <typename T, typename ... A>
74
- T *new_ (A &&... args) noexcept {
170
+ T *new $ (A &&... args) noexcept {
75
171
auto *mem_res = regular_resource<regular_sizeof<T>()>::get ();
172
+ if (mem_res == nullptr ) return nullptr ;
76
173
return ::LIBIMP::construct<T>(mem_res->allocate (sizeof (T), alignof (T)), std::forward<A>(args)...);
77
174
}
78
175
79
176
template <typename T>
80
- void delete_ (T *p) noexcept {
177
+ void delete $ (T *p) noexcept {
81
178
if (p == nullptr ) return ;
179
+ ::LIBIMP::destroy (p);
82
180
auto *mem_res = regular_resource<regular_sizeof<T>()>::get ();
83
- mem_res->deallocate (::LIBIMP::destroy (p), sizeof (T), alignof (T));
181
+ if (mem_res == nullptr ) return ;
182
+ mem_res->deallocate (p, sizeof (T), alignof (T));
84
183
}
85
184
86
185
LIBPMR_NAMESPACE_END_
0 commit comments