Skip to content

Commit 5aaa78a

Browse files
committed
Add comments and refine the implementation.
1 parent 01bbcf7 commit 5aaa78a

File tree

2 files changed

+61
-39
lines changed

2 files changed

+61
-39
lines changed

include/libpmr/new.h

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,75 +14,75 @@
1414
#include "libimp/uninitialized.h"
1515
#include "libimp/byte.h"
1616
#include "libimp/detect_plat.h"
17+
#include "libimp/export.h"
1718

1819
#include "libpmr/def.h"
1920
#include "libpmr/block_pool.h"
2021
#include "libpmr/memory_resource.h"
2122

2223
LIBPMR_NAMESPACE_BEG_
2324

25+
/// \brief Select the incremental level based on the size.
2426
constexpr inline std::size_t regular_level(std::size_t s) noexcept {
2527
return (s <= 128 ) ? 0 :
2628
(s <= 1024 ) ? 1 :
2729
(s <= 8192 ) ? 2 :
2830
(s <= 65536) ? 3 : 4;
2931
}
3032

33+
/// \brief Calculates the appropriate memory block size based on the increment level and size.
3134
constexpr inline std::size_t regular_sizeof_impl(std::size_t l, std::size_t s) noexcept {
3235
return (l == 0) ? std::max<std::size_t>(::LIBIMP::round_up<std::size_t>(s, 8), regular_head_size) :
3336
(l == 1) ? ::LIBIMP::round_up<std::size_t>(s, 128 ) :
3437
(l == 2) ? ::LIBIMP::round_up<std::size_t>(s, 1024) :
3538
(l == 3) ? ::LIBIMP::round_up<std::size_t>(s, 8192) : (std::numeric_limits<std::size_t>::max)();
3639
}
3740

41+
/// \brief Calculates the appropriate memory block size based on the size.
3842
constexpr inline std::size_t regular_sizeof(std::size_t s) noexcept {
3943
return regular_sizeof_impl(regular_level(s), s);
4044
}
4145

46+
/// \brief Calculates the appropriate memory block size based on the specific type.
4247
template <typename T>
4348
constexpr inline std::size_t regular_sizeof() noexcept {
4449
return regular_sizeof(regular_head_size + sizeof(T));
4550
}
4651

47-
class block_pool_like {
52+
/// \brief Defines the memory block collector interface.
53+
class LIBIMP_EXPORT block_collector {
4854
public:
49-
virtual ~block_pool_like() noexcept = default;
50-
virtual void *allocate() noexcept = 0;
55+
virtual ~block_collector() noexcept = default;
5156
virtual void deallocate(void *p) noexcept = 0;
5257
};
5358

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;
57-
}
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 *> &;
5862

63+
/// \brief Defines block pool memory resource based on block pool.
5964
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
6065
class block_pool_resource;
6166

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.
6270
template <>
6371
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-
72+
, public block_collector {
7073
public:
7174
void deallocate(void *p) noexcept override {
7275
block_pool<0, 0>::deallocate(p);
7376
}
7477
};
7578

79+
/// \brief A block pool memory resource for a block of memory of a specific size.
7680
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
7781
class block_pool_resource : public block_pool<BlockSize, BlockPoolExpansion>
78-
, public block_pool_like {
82+
, public block_collector {
7983

8084
using base_t = block_pool<BlockSize, BlockPoolExpansion>;
8185

82-
void *allocate() noexcept override {
83-
return base_t::allocate();
84-
}
85-
8686
void deallocate(void *p) noexcept override {
8787
base_t::deallocate(p);
8888
}
@@ -105,7 +105,9 @@ class block_pool_resource : public block_pool<BlockSize, BlockPoolExpansion>
105105
base_t::deallocate(p);
106106
return;
107107
}
108-
auto &map = get_block_pool_map();
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();
109111
auto it = map.find(r_size);
110112
if ((it == map.end()) || (it->second == nullptr)) {
111113
block_pool_resource<0, 0> *bp = nullptr;
@@ -128,62 +130,70 @@ class block_pool_resource : public block_pool<BlockSize, BlockPoolExpansion>
128130
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
129131
auto block_pool_resource<BlockSize, BlockPoolExpansion>::get() noexcept
130132
-> block_pool_resource<BlockSize, BlockPoolExpansion> * {
131-
auto &map = get_block_pool_map();
132133
thread_local block_pool_resource *pi = nullptr;
133134
if (pi != nullptr) {
134135
return pi;
135136
}
137+
// Create a new block pool resource for this thread.
138+
auto &map = get_thread_block_pool_map();
136139
auto it = map.find(BlockSize);
137140
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.
138143
auto *bp = static_cast <block_pool<0, 0> *>(
139144
dynamic_cast<block_pool_resource<0, 0> *>(it->second));
140145
if (bp == nullptr) {
141146
return nullptr;
142147
}
143148
thread_local block_pool_resource instance(std::move(*bp));
144149
delete static_cast<block_pool_resource<0, 0> *>(bp);
145-
pi = &instance;
150+
it->second = pi = &instance;
151+
return pi;
146152
} 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.
147155
thread_local block_pool_resource instance;
148-
pi = &instance;
149-
}
150-
LIBIMP_TRY {
151-
map.emplace(BlockSize, pi);
152-
} LIBIMP_CATCH(...) {
153-
return nullptr;
156+
LIBIMP_TRY {
157+
map.emplace(BlockSize, pi = &instance);
158+
return pi;
159+
} LIBIMP_CATCH(...) {
160+
return nullptr;
161+
}
154162
}
155-
return pi;
156163
}
157164

165+
/// \brief Match the appropriate memory block resources
166+
/// according to the size of the specification.
158167
template <std::size_t N, std::size_t L = regular_level(N)>
159168
class regular_resource : public new_delete_resource {};
160169

161-
template <std::size_t N>
162-
class regular_resource<N, 0> : public block_pool_resource<N, 512> {};
163-
164-
template <std::size_t N>
165-
class regular_resource<N, 1> : public block_pool_resource<N, 256> {};
166-
167-
template <std::size_t N>
168-
class regular_resource<N, 2> : public block_pool_resource<N, 128> {};
169-
170-
template <std::size_t N>
171-
class regular_resource<N, 3> : public block_pool_resource<N, 64> {};
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 > {};
172176

177+
/// \brief Creates an object based on the specified type and parameters with block pool resource.
178+
/// \note This function is thread-safe.
173179
template <typename T, typename... A>
174180
T *new$(A &&... args) noexcept {
175181
auto *mem_res = regular_resource<regular_sizeof<T>()>::get();
176182
if (mem_res == nullptr) return nullptr;
177183
return ::LIBIMP::construct<T>(mem_res->allocate(sizeof(T), alignof(T)), std::forward<A>(args)...);
178184
}
179185

186+
/// \brief Destroys object previously allocated by the `new$` and releases obtained memory area.
187+
/// \note This function is thread-safe. If the pointer type passed in is different from `new$`,
188+
/// additional performance penalties may be incurred.
180189
template <typename T>
181190
void delete$(T *p) noexcept {
182191
if (p == nullptr) return;
183192
::LIBIMP::destroy(p);
184193
auto *mem_res = regular_resource<regular_sizeof<T>()>::get();
185194
if (mem_res == nullptr) return;
186195
#if defined(LIBIMP_CC_MSVC_2015)
196+
// `alignof` of vs2015 requires that type must be able to be instantiated.
187197
mem_res->deallocate(p, sizeof(T));
188198
#else
189199
mem_res->deallocate(p, sizeof(T), alignof(T));

src/libpmr/new.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
#include "libpmr/new.h"
3+
4+
LIBPMR_NAMESPACE_BEG_
5+
6+
auto get_thread_block_pool_map() noexcept
7+
-> std::unordered_map<std::size_t, block_collector *> & {
8+
thread_local std::unordered_map<std::size_t, block_collector *> instances;
9+
return instances;
10+
}
11+
12+
LIBPMR_NAMESPACE_END_

0 commit comments

Comments
 (0)