1#ifndef NEFORCE_CORE_MEMORY_STANDARD_ALLOCATOR_HPP__
2#define NEFORCE_CORE_MEMORY_STANDARD_ALLOCATOR_HPP__
15NEFORCE_BEGIN_NAMESPACE__
29NEFORCE_INLINE17
constexpr size_t MEMORY_ALIGN_THRESHHOLD = 16;
37NEFORCE_INLINE17
constexpr size_t MEMORY_BIG_ALLOC_THRESHHOLD = 4096;
48#ifdef NEFORCE_COMPILER_GCC
56#ifdef NEFORCE_COMPILER_MSVC
64NEFORCE_INLINE17
constexpr size_t MEMORY_BIG_ALLOC_ALIGN = 32;
72NEFORCE_INLINE17
constexpr size_t MEMORY_NO_USER_SIZE =
sizeof(
void*) + MEMORY_BIG_ALLOC_ALIGN -
73 static_cast<size_t>(1)
74# ifdef NEFORCE_STATE_DEBUG
75 *
static_cast<size_t>(2)
85NEFORCE_INLINE17
constexpr size_t MEMORY_BIG_ALLOC_SENTINEL =
86# ifdef NEFORCE_ARCH_BITS_64
103template <
size_t Align>
104NEFORCE_ALLOC_OPTIMIZE NEFORCE_CONSTEXPR20
void* __allocate_aux(
const alloc_size_t bytes) {
105#ifdef NEFORCE_COMPILER_MSVC
106 if (bytes >= MEMORY_BIG_ALLOC_THRESHHOLD) {
107 const size_t block_size = MEMORY_NO_USER_SIZE + bytes;
108 if (block_size <= bytes) {
109 NEFORCE_THROW_EXCEPTION(memory_exception(
"invalid block size."));
111 const auto holder =
reinterpret_cast<uintptr_t>(
operator new(block_size));
112 NEFORCE_DEBUG_VERIFY(holder != 0,
"invalid argument");
113 auto*
const ptr =
reinterpret_cast<void*
>((holder + MEMORY_NO_USER_SIZE) & ~(MEMORY_BIG_ALLOC_ALIGN - 1));
114 static_cast<uintptr_t*
>(ptr)[-1] = holder;
115# ifdef NEFORCE_STATE_DEBUG
116 static_cast<uintptr_t*
>(ptr)[-2] = MEMORY_BIG_ALLOC_SENTINEL;
121 return operator new(bytes);
124#ifdef NEFORCE_STANDARD_17
134template <
size_t Align, enable_if_t<(Align > MEMORY_ALIGN_THRESHHOLD),
int> = 0>
135NEFORCE_ALLOC_OPTIMIZE NEFORCE_CONSTEXPR20
void* __allocate_dispatch(
const alloc_size_t bytes) {
136 size_t align = Align;
137# ifdef NEFORCE_COMPILER_MSVC
138 if (bytes >= MEMORY_BIG_ALLOC_THRESHHOLD) {
139 align = Align > MEMORY_BIG_ALLOC_ALIGN ? Align : MEMORY_BIG_ALLOC_ALIGN;
142# if defined(NEFORCE_COMPILER_CLANG) && defined(NEFORCE_STANDARD_20)
144 return operator new(bytes);
147 return operator new(bytes, std::align_val_t{align});
158template <
size_t Align, enable_if_t<Align <= MEMORY_ALIGN_THRESHHOLD,
int> = 0>
159NEFORCE_ALLOC_OPTIMIZE NEFORCE_CONSTEXPR20
void* __allocate_dispatch(const alloc_
size_t bytes) {
160 return inner::__allocate_aux<Align>(
bytes);
176template <
size_t Align>
177NEFORCE_ALLOC_OPTIMIZE NEFORCE_CONSTEXPR20
void*
allocate(
const inner::alloc_size_t bytes) {
181#ifdef NEFORCE_STANDARD_20
183 return operator new(bytes);
187#ifdef NEFORCE_STANDARD_17
188 return inner::__allocate_dispatch<Align>(bytes);
190 return inner::__allocate_aux<Align>(bytes);
206template <
size_t Align>
207void __deallocate_aux(
void*& ptr, inner::alloc_size_t& bytes)
noexcept {
208#ifdef NEFORCE_COMPILER_MSVC
209 if (bytes >= MEMORY_BIG_ALLOC_THRESHHOLD) {
210 bytes += MEMORY_NO_USER_SIZE;
211 const uintptr_t*
const user_ptr =
static_cast<uintptr_t*
>(ptr);
212 const uintptr_t holder = user_ptr[-1];
213 NEFORCE_DEBUG_VERIFY(user_ptr[-2] == MEMORY_BIG_ALLOC_SENTINEL,
"invalid sentinel.");
214# ifdef NEFORCE_STATE_DEBUG
215 constexpr uintptr_t min_shift = 2 *
sizeof(
void*);
217 constexpr uintptr_t min_shift =
sizeof(
void*);
219 const uintptr_t shift =
reinterpret_cast<uintptr_t
>(ptr) - holder;
220 NEFORCE_DEBUG_VERIFY(shift >= min_shift && shift <= MEMORY_NO_USER_SIZE,
"invalid argument.");
221 ptr =
reinterpret_cast<void*
>(holder);
224#if defined(NEFORCE_STANDARD_14) && defined(NEFORCE_COMPILER_MSVC)
225 operator delete(ptr, bytes);
227 operator delete(ptr);
231#ifdef NEFORCE_STANDARD_17
241template <
size_t Align, enable_if_t<(Align > MEMORY_ALIGN_THRESHHOLD),
int> = 0>
242NEFORCE_CONSTEXPR20
void __deallocate_dispatch(
void*& ptr, inner::alloc_size_t& bytes)
noexcept {
243 size_t align = Align;
244# ifdef NEFORCE_COMPILER_MSVC
245 if (bytes > MEMORY_BIG_ALLOC_THRESHHOLD) {
246 align = Align > MEMORY_BIG_ALLOC_ALIGN ? Align : MEMORY_BIG_ALLOC_ALIGN;
249# if defined(NEFORCE_STANDARD_14) && defined(NEFORCE_COMPILER_MSVC)
250 operator delete(ptr, bytes, std::align_val_t{align});
252 operator delete(ptr, std::align_val_t{align});
262template <
size_t Align, enable_if_t<Align <= MEMORY_ALIGN_THRESHHOLD,
int> = 0>
263NEFORCE_CONSTEXPR20
void __deallocate_dispatch(
void*& ptr, inner::alloc_
size_t&
bytes) noexcept {
264 inner::__deallocate_aux<Align>(ptr,
bytes);
280template <
size_t Align>
281NEFORCE_CONSTEXPR20
void deallocate(
void* ptr, inner::alloc_size_t bytes)
noexcept {
282#ifdef NEFORCE_STANDARD_20
284 operator delete(ptr);
289#ifdef NEFORCE_STANDARD_17
290 inner::__deallocate_dispatch<Align>(ptr, bytes);
292 inner::__deallocate_aux<Align>(ptr, bytes);
306 static_assert(
is_allocable_v<T>,
"allocator can`t alloc void, reference, function or const type.");
320 template <
typename U>
327 static constexpr inner::alloc_size_t align_size =
alignof(T) > MEMORY_ALIGN_THRESHHOLD ?
alignof(T)
328 : MEMORY_ALIGN_THRESHHOLD;
337 template <typename U>
354 NEFORCE_DEBUG_VERIFY(alloc_size <=
static_cast<size_type>(-1),
"allocation will cause memory overflow.");
368 NEFORCE_ALLOC_NODISCARD NEFORCE_CONSTEXPR20 NEFORCE_ALLOC_OPTIMIZE
static pointer allocate() {
379 NEFORCE_DEBUG_VERIFY(p !=
nullptr || n == 0,
"null pointer cannot point to a block of non-zero size");
404template <
typename T,
typename U>
416template <
typename T,
typename U>
435NEFORCE_END_NAMESPACE__
constexpr standard_allocator() noexcept=default
默认构造函数
static constexpr void deallocate(pointer p, const size_type n) noexcept
释放先前分配的内存
static constexpr pointer allocate(const size_type n)
inner::alloc_size_t size_type
大小类型
constexpr ~standard_allocator() noexcept=default
析构函数
static constexpr void deallocate(pointer p) noexcept
释放单个元素内存
static constexpr size_type max_size() noexcept
获取分配器可分配的最大元素数量
static constexpr pointer allocate()
分配单个元素内存
constexpr bool is_allocable_v
is_allocable的便捷变量模板
unsigned int uint32_t
32位无符号整数类型
void unreachable() noexcept
标记不可达代码路径
constexpr bool is_constant_evaluated() noexcept
检查当前上下文是否在常量求值中
bool operator!=(const function< Res(Args...)> &f, nullptr_t np) noexcept
不等于空指针比较
bool operator==(const function< Res(Args...)> &f, nullptr_t np) noexcept
等于空指针比较
constexpr void * allocate(const inner::alloc_size_t bytes)
内存分配函数
constexpr void deallocate(void *ptr, inner::alloc_size_t bytes) noexcept
内存释放函数
standard_allocator< T > allocator
标准分配器别名