mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
Refactoring the generic memory allocator
This commit is contained in:
parent
10c0d14de6
commit
a1f858f560
@ -285,15 +285,17 @@ namespace detail_horrible_cast {
|
|||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
union temp {
|
union temp {
|
||||||
std::decay_t<U> in;
|
U in;
|
||||||
T out;
|
T out;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail_horrible_cast
|
} // namespace detail_horrible_cast
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr T horrible_cast(U &&in) noexcept {
|
constexpr auto horrible_cast(U &&in) noexcept
|
||||||
return detail_horrible_cast::temp<T, U>{std::forward<U>(in)}.out;
|
-> typename std::enable_if<std::is_trivially_copyable<T>::value
|
||||||
|
&& std::is_trivially_copyable<std::decay_t<U>>::value, T>::type {
|
||||||
|
return detail_horrible_cast::temp<T, std::decay_t<U>>{std::forward<U>(in)}.out;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "libipc/imp/uninitialized.h"
|
#include "libipc/imp/uninitialized.h"
|
||||||
#include "libipc/mem/new.h"
|
#include "libipc/mem/new.h"
|
||||||
@ -56,19 +57,32 @@ public:
|
|||||||
container_allocator& operator=(container_allocator &&) noexcept = default;
|
container_allocator& operator=(container_allocator &&) noexcept = default;
|
||||||
|
|
||||||
constexpr size_type max_size() const noexcept {
|
constexpr size_type max_size() const noexcept {
|
||||||
return 1;
|
return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer allocate(size_type count) noexcept {
|
pointer allocate(size_type count) noexcept {
|
||||||
if (count == 0) return nullptr;
|
if (count == 0) return nullptr;
|
||||||
if (count > this->max_size()) return nullptr;
|
if (count > this->max_size()) return nullptr;
|
||||||
|
if (count == 1) {
|
||||||
return mem::$new<value_type>();
|
return mem::$new<value_type>();
|
||||||
|
} else {
|
||||||
|
void *p = mem::alloc(sizeof(value_type) * count);
|
||||||
|
if (p == nullptr) return nullptr;
|
||||||
|
for (std::size_t i = 0; i < count; ++i) {
|
||||||
|
std::ignore = ipc::construct<value_type>(static_cast<byte *>(p) + sizeof(value_type) * i);
|
||||||
|
}
|
||||||
|
return static_cast<pointer>(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void deallocate(pointer p, size_type count) noexcept {
|
void deallocate(pointer p, size_type count) noexcept {
|
||||||
if (count == 0) return;
|
if (count == 0) return;
|
||||||
if (count > this->max_size()) return;
|
if (count > this->max_size()) return;
|
||||||
|
if (count == 1) {
|
||||||
mem::$delete(p);
|
mem::$delete(p);
|
||||||
|
} else {
|
||||||
|
mem::free(ipc::destroy_n(p, count), sizeof(value_type) * count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... P>
|
template <typename... P>
|
||||||
|
|||||||
@ -26,133 +26,43 @@ namespace mem {
|
|||||||
class LIBIPC_EXPORT block_collector {
|
class LIBIPC_EXPORT block_collector {
|
||||||
public:
|
public:
|
||||||
virtual ~block_collector() noexcept = default;
|
virtual ~block_collector() noexcept = default;
|
||||||
virtual void recycle(void */*p*/) noexcept {}
|
virtual void *allocate(std::size_t /*bytes*/) noexcept = 0;
|
||||||
|
virtual void deallocate(void */*p*/, std::size_t /*bytes*/) noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(LIBIPC_CPP_17)
|
/// \brief Matches the appropriate memory block resource based on a specified size.
|
||||||
using recycle_t = void (*)(void *p, void *o) noexcept;
|
LIBIPC_EXPORT block_collector &get_regular_resource(std::size_t s) noexcept;
|
||||||
#else
|
|
||||||
using recycle_t = void (*)(void *p, void *o);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static constexpr std::size_t regular_head_size
|
/// \brief Allocates storage with a size of at least bytes bytes.
|
||||||
= round_up(sizeof(recycle_t), alignof(std::max_align_t));
|
LIBIPC_EXPORT void *alloc(std::size_t bytes) noexcept;
|
||||||
|
LIBIPC_EXPORT void free (void *p, std::size_t bytes) noexcept;
|
||||||
/// \brief Select the incremental level based on the size.
|
|
||||||
constexpr inline std::size_t regular_level(std::size_t s) noexcept {
|
|
||||||
return (s <= 128 ) ? 0 :
|
|
||||||
(s <= 1024 ) ? 1 :
|
|
||||||
(s <= 8192 ) ? 2 :
|
|
||||||
(s <= 65536) ? 3 : 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Calculates the appropriate memory block size based on the increment level and size.
|
|
||||||
constexpr inline std::size_t regular_sizeof_impl(std::size_t l, std::size_t s) noexcept {
|
|
||||||
return (l == 0) ? round_up<std::size_t>(s, regular_head_size) :
|
|
||||||
(l == 1) ? round_up<std::size_t>(s, 128 ) :
|
|
||||||
(l == 2) ? round_up<std::size_t>(s, 1024) :
|
|
||||||
(l == 3) ? round_up<std::size_t>(s, 8192) : (std::numeric_limits<std::size_t>::max)();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Calculates the appropriate memory block size based on the size.
|
|
||||||
constexpr inline std::size_t regular_sizeof_impl(std::size_t s) noexcept {
|
|
||||||
return regular_sizeof_impl(regular_level(s), s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Calculates the appropriate memory block size based on the specific type.
|
|
||||||
constexpr inline std::size_t regular_sizeof(std::size_t s) noexcept {
|
|
||||||
return regular_sizeof_impl(regular_head_size + s);
|
|
||||||
}
|
|
||||||
template <typename T, std::size_t S = sizeof(T)>
|
|
||||||
constexpr inline std::size_t regular_sizeof() noexcept {
|
|
||||||
return regular_sizeof(S);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Use block pools to handle memory less than 64K.
|
|
||||||
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
|
|
||||||
class block_resource_base : public block_pool<BlockSize, BlockPoolExpansion> {
|
|
||||||
public:
|
|
||||||
void *allocate(std::size_t /*bytes*/, std::size_t /*alignment*/) noexcept {
|
|
||||||
return block_pool<BlockSize, BlockPoolExpansion>::allocate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate(void *p) noexcept {
|
|
||||||
block_pool<BlockSize, BlockPoolExpansion>::deallocate(p);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Use `new`/`delete` to handle memory larger than 64K.
|
|
||||||
template <std::size_t BlockSize>
|
|
||||||
class block_resource_base<BlockSize, 0> : public new_delete_resource {
|
|
||||||
public:
|
|
||||||
void *allocate(std::size_t bytes, std::size_t alignment) noexcept {
|
|
||||||
return new_delete_resource::allocate(regular_head_size + bytes, alignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate(void *p) noexcept {
|
|
||||||
new_delete_resource::deallocate(p, regular_head_size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Defines block pool memory resource based on block pool.
|
|
||||||
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
|
|
||||||
class block_pool_resource : public block_resource_base<BlockSize, BlockPoolExpansion>
|
|
||||||
, public block_collector {
|
|
||||||
|
|
||||||
using base_t = block_resource_base<BlockSize, BlockPoolExpansion>;
|
|
||||||
|
|
||||||
void recycle(void *p) noexcept override {
|
|
||||||
base_t::deallocate(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
static block_collector *get() noexcept {
|
|
||||||
thread_local block_pool_resource instance;
|
|
||||||
return &instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void *allocate(std::size_t bytes, std::size_t alignment = alignof(std::max_align_t)) noexcept {
|
|
||||||
void *b = base_t::allocate(bytes, alignment);
|
|
||||||
*static_cast<recycle_t *>(b)
|
|
||||||
= [](void *b, void *p) noexcept {
|
|
||||||
std::ignore = destroy(static_cast<T *>(p));
|
|
||||||
get()->recycle(b);
|
|
||||||
};
|
|
||||||
return static_cast<byte *>(b) + regular_head_size;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// \brief Different increment levels match different chunk sizes.
|
|
||||||
/// 512 means that 512 consecutive memory blocks are allocated at a time.
|
|
||||||
template <std::size_t L>
|
|
||||||
constexpr std::size_t block_pool_expansion = 0;
|
|
||||||
|
|
||||||
template <> constexpr std::size_t block_pool_expansion<0> = 512;
|
|
||||||
template <> constexpr std::size_t block_pool_expansion<1> = 256;
|
|
||||||
template <> constexpr std::size_t block_pool_expansion<2> = 128;
|
|
||||||
template <> constexpr std::size_t block_pool_expansion<3> = 64;
|
|
||||||
|
|
||||||
/// \brief Matches the appropriate memory block resource based on the specified type.
|
|
||||||
template <typename T, std::size_t N = regular_sizeof<T>(), std::size_t L = regular_level(N)>
|
|
||||||
auto *get_regular_resource() noexcept {
|
|
||||||
using block_poll_resource_t = block_pool_resource<N, block_pool_expansion<L>>;
|
|
||||||
return dynamic_cast<block_poll_resource_t *>(block_poll_resource_t::get());
|
|
||||||
}
|
|
||||||
template <typename T, std::enable_if_t<std::is_void<T>::value, bool> = true>
|
|
||||||
auto *get_regular_resource() noexcept {
|
|
||||||
using block_poll_resource_t = block_pool_resource<0, 0>;
|
|
||||||
return dynamic_cast<block_poll_resource_t *>(block_poll_resource_t::get());
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail_new {
|
namespace detail_new {
|
||||||
|
|
||||||
|
#if defined(LIBIPC_CPP_17)
|
||||||
|
using recycle_t = void (*)(void *p) noexcept;
|
||||||
|
#else
|
||||||
|
using recycle_t = void (*)(void *p);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr std::size_t recycler_size = round_up(sizeof(recycle_t), alignof(std::size_t));
|
||||||
|
static constexpr std::size_t allocated_size = sizeof(std::size_t);
|
||||||
|
static constexpr std::size_t regular_head_size = round_up(recycler_size + allocated_size, alignof(std::max_align_t));
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct do_allocate {
|
struct do_allocate {
|
||||||
template <typename R, typename... A>
|
template <typename... A>
|
||||||
static T *apply(R *res, A &&... args) noexcept {
|
static T *apply(A &&... args) noexcept {
|
||||||
|
void *b = mem::alloc(regular_head_size + sizeof(T));
|
||||||
|
auto *p = static_cast<byte *>(b) + regular_head_size;
|
||||||
LIBIPC_TRY {
|
LIBIPC_TRY {
|
||||||
return construct<T>(res->template allocate<T>(sizeof(T), alignof(T)), std::forward<A>(args)...);
|
T *t = construct<T>(p, std::forward<A>(args)...);
|
||||||
|
*reinterpret_cast<recycle_t *>(b)
|
||||||
|
= [](void *p) noexcept {
|
||||||
|
mem::free(static_cast<byte *>(destroy(static_cast<T *>(p))) - regular_head_size
|
||||||
|
, regular_head_size + sizeof(T));
|
||||||
|
};
|
||||||
|
return t;
|
||||||
} LIBIPC_CATCH(...) {
|
} LIBIPC_CATCH(...) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -161,10 +71,18 @@ struct do_allocate {
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct do_allocate<void> {
|
struct do_allocate<void> {
|
||||||
template <typename R>
|
static void *apply(std::size_t bytes) noexcept {
|
||||||
static void *apply(R *res, std::size_t bytes) noexcept {
|
|
||||||
if (bytes == 0) return nullptr;
|
if (bytes == 0) return nullptr;
|
||||||
return res->template allocate<void>(bytes);
|
std::size_t rbz = regular_head_size + bytes;
|
||||||
|
void *b = mem::alloc(rbz);
|
||||||
|
*reinterpret_cast<recycle_t *>(b)
|
||||||
|
= [](void *p) noexcept {
|
||||||
|
auto *b = static_cast<byte *>(p) - regular_head_size;
|
||||||
|
mem::free(b, *reinterpret_cast<std::size_t *>(b + recycler_size));
|
||||||
|
};
|
||||||
|
auto *z = static_cast<byte *>(b) + recycler_size;
|
||||||
|
*reinterpret_cast<std::size_t *>(z) = rbz;
|
||||||
|
return static_cast<byte *>(b) + regular_head_size;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -174,9 +92,7 @@ struct do_allocate<void> {
|
|||||||
/// \note This function is thread-safe.
|
/// \note This function is thread-safe.
|
||||||
template <typename T, typename... A>
|
template <typename T, typename... A>
|
||||||
T *$new(A &&... args) noexcept {
|
T *$new(A &&... args) noexcept {
|
||||||
auto *res = get_regular_resource<T>();
|
return detail_new::do_allocate<T>::apply(std::forward<A>(args)...);
|
||||||
if (res == nullptr) return nullptr;
|
|
||||||
return detail_new::do_allocate<T>::apply(res, std::forward<A>(args)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Destroys object previously allocated by the `$new` and releases obtained memory area.
|
/// \brief Destroys object previously allocated by the `$new` and releases obtained memory area.
|
||||||
@ -184,9 +100,8 @@ T *$new(A &&... args) noexcept {
|
|||||||
/// additional performance penalties may be incurred.
|
/// additional performance penalties may be incurred.
|
||||||
inline void $delete(void *p) noexcept {
|
inline void $delete(void *p) noexcept {
|
||||||
if (p == nullptr) return;
|
if (p == nullptr) return;
|
||||||
auto *b = reinterpret_cast<byte *>(p) - regular_head_size;
|
auto *r = reinterpret_cast<detail_new::recycle_t *>(static_cast<byte *>(p) - detail_new::regular_head_size);
|
||||||
auto *r = reinterpret_cast<recycle_t *>(b);
|
(*r)(p);
|
||||||
(*r)(b, p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief The destruction policy used by std::unique_ptr.
|
/// \brief The destruction policy used by std::unique_ptr.
|
||||||
|
|||||||
121
src/libipc/mem/new.cpp
Normal file
121
src/libipc/mem/new.cpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
|
||||||
|
#include "libipc/mem/new.h"
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace mem {
|
||||||
|
|
||||||
|
/// \brief Select the incremental level based on the size.
|
||||||
|
constexpr inline std::size_t regular_level(std::size_t s) noexcept {
|
||||||
|
return (s <= 128 ) ? 0 :
|
||||||
|
(s <= 1024 ) ? 1 :
|
||||||
|
(s <= 8192 ) ? 2 :
|
||||||
|
(s <= 65536) ? 3 : 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Use block pools to handle memory less than 64K.
|
||||||
|
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
|
||||||
|
class block_resource_base : public block_pool<BlockSize, BlockPoolExpansion>
|
||||||
|
, public block_collector {
|
||||||
|
public:
|
||||||
|
void *allocate(std::size_t /*bytes*/) noexcept override {
|
||||||
|
return block_pool<BlockSize, BlockPoolExpansion>::allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void *p, std::size_t /*bytes*/) noexcept override {
|
||||||
|
block_pool<BlockSize, BlockPoolExpansion>::deallocate(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Use `new`/`delete` to handle memory larger than 64K.
|
||||||
|
template <>
|
||||||
|
class block_resource_base<0, 0> : public new_delete_resource
|
||||||
|
, public block_collector {
|
||||||
|
public:
|
||||||
|
void *allocate(std::size_t bytes) noexcept override {
|
||||||
|
return new_delete_resource::allocate(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(void *p, std::size_t bytes) noexcept override {
|
||||||
|
new_delete_resource::deallocate(p, bytes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Defines block pool memory resource based on block pool.
|
||||||
|
template <std::size_t BlockSize, std::size_t BlockPoolExpansion>
|
||||||
|
class block_pool_resource : public block_resource_base<BlockSize, BlockPoolExpansion> {
|
||||||
|
public:
|
||||||
|
static block_collector &get() noexcept {
|
||||||
|
thread_local block_pool_resource instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Matches the appropriate memory block resource based on a specified size.
|
||||||
|
block_collector &get_regular_resource(std::size_t s) noexcept {
|
||||||
|
std::size_t l = regular_level(s);
|
||||||
|
switch (l) {
|
||||||
|
case 0:
|
||||||
|
switch (round_up<std::size_t>(s, 16)) {
|
||||||
|
case 16 : return block_pool_resource<16 , 512>::get();
|
||||||
|
case 32 : return block_pool_resource<32 , 512>::get();
|
||||||
|
case 48 : return block_pool_resource<48 , 512>::get();
|
||||||
|
case 64 : return block_pool_resource<64 , 512>::get();
|
||||||
|
case 80 : return block_pool_resource<80 , 512>::get();
|
||||||
|
case 96 : return block_pool_resource<96 , 512>::get();
|
||||||
|
case 112: return block_pool_resource<112, 512>::get();
|
||||||
|
case 128: return block_pool_resource<128, 512>::get();
|
||||||
|
default : break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
switch (round_up<std::size_t>(s, 128)) {
|
||||||
|
case 256 : return block_pool_resource<256 , 256>::get();
|
||||||
|
case 384 : return block_pool_resource<384 , 256>::get();
|
||||||
|
case 512 : return block_pool_resource<512 , 256>::get();
|
||||||
|
case 640 : return block_pool_resource<640 , 256>::get();
|
||||||
|
case 768 : return block_pool_resource<768 , 256>::get();
|
||||||
|
case 896 : return block_pool_resource<896 , 256>::get();
|
||||||
|
case 1024: return block_pool_resource<1024, 256>::get();
|
||||||
|
default : break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
switch (round_up<std::size_t>(s, 1024)) {
|
||||||
|
case 2048: return block_pool_resource<2048, 128>::get();
|
||||||
|
case 3072: return block_pool_resource<3072, 128>::get();
|
||||||
|
case 4096: return block_pool_resource<4096, 128>::get();
|
||||||
|
case 5120: return block_pool_resource<5120, 128>::get();
|
||||||
|
case 6144: return block_pool_resource<6144, 128>::get();
|
||||||
|
case 7168: return block_pool_resource<7168, 128>::get();
|
||||||
|
case 8192: return block_pool_resource<8192, 128>::get();
|
||||||
|
default : break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
switch (round_up<std::size_t>(s, 8192)) {
|
||||||
|
case 16384: return block_pool_resource<16384, 64>::get();
|
||||||
|
case 24576: return block_pool_resource<24576, 64>::get();
|
||||||
|
case 32768: return block_pool_resource<32768, 64>::get();
|
||||||
|
case 40960: return block_pool_resource<40960, 64>::get();
|
||||||
|
case 49152: return block_pool_resource<49152, 64>::get();
|
||||||
|
case 57344: return block_pool_resource<57344, 64>::get();
|
||||||
|
case 65536: return block_pool_resource<65536, 64>::get();
|
||||||
|
default : break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return block_pool_resource<0, 0>::get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *alloc(std::size_t bytes) noexcept {
|
||||||
|
return get_regular_resource(bytes).allocate(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *p, std::size_t bytes) noexcept {
|
||||||
|
return get_regular_resource(bytes).deallocate(p, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mem
|
||||||
|
} // namespace ipc
|
||||||
@ -44,18 +44,6 @@ enum {
|
|||||||
// #endif/*__cplusplus < 201703L*/
|
// #endif/*__cplusplus < 201703L*/
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename U>
|
|
||||||
auto horrible_cast(U rhs) noexcept
|
|
||||||
-> typename std::enable_if<std::is_trivially_copyable<T>::value
|
|
||||||
&& std::is_trivially_copyable<U>::value, T>::type {
|
|
||||||
union {
|
|
||||||
T t;
|
|
||||||
U u;
|
|
||||||
} r = {};
|
|
||||||
r.u = rhs;
|
|
||||||
return r.t;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPC_CONSTEXPR_ std::size_t make_align(std::size_t align, std::size_t size) {
|
IPC_CONSTEXPR_ std::size_t make_align(std::size_t align, std::size_t size) {
|
||||||
// align must be 2^n
|
// align must be 2^n
|
||||||
return (size + align - 1) & ~(align - 1);
|
return (size + align - 1) & ~(align - 1);
|
||||||
|
|||||||
@ -9,19 +9,6 @@
|
|||||||
|
|
||||||
#include "libipc/mem/new.h"
|
#include "libipc/mem/new.h"
|
||||||
|
|
||||||
TEST(new, regular_sizeof) {
|
|
||||||
ASSERT_EQ(ipc::mem::regular_sizeof<std::int8_t >(), ipc::mem::regular_head_size + alignof(std::max_align_t));
|
|
||||||
ASSERT_EQ(ipc::mem::regular_sizeof<std::int16_t>(), ipc::mem::regular_head_size + alignof(std::max_align_t));
|
|
||||||
ASSERT_EQ(ipc::mem::regular_sizeof<std::int32_t>(), ipc::mem::regular_head_size + alignof(std::max_align_t));
|
|
||||||
ASSERT_EQ(ipc::mem::regular_sizeof<std::int64_t>(), ipc::mem::regular_head_size + alignof(std::max_align_t));
|
|
||||||
|
|
||||||
ASSERT_EQ((ipc::mem::regular_sizeof<std::array<char, 10 >>()), ipc::round_up<std::size_t>(ipc::mem::regular_head_size + 10 , alignof(std::max_align_t)));
|
|
||||||
ASSERT_EQ((ipc::mem::regular_sizeof<std::array<char, 100 >>()), ipc::round_up<std::size_t>(ipc::mem::regular_head_size + 100 , alignof(std::max_align_t)));
|
|
||||||
ASSERT_EQ((ipc::mem::regular_sizeof<std::array<char, 1000 >>()), ipc::round_up<std::size_t>(ipc::mem::regular_head_size + 1000 , 128));
|
|
||||||
ASSERT_EQ((ipc::mem::regular_sizeof<std::array<char, 10000 >>()), ipc::round_up<std::size_t>(ipc::mem::regular_head_size + 10000, 8192));
|
|
||||||
ASSERT_EQ((ipc::mem::regular_sizeof<std::array<char, 100000>>()), (std::numeric_limits<std::size_t>::max)());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(new, new) {
|
TEST(new, new) {
|
||||||
auto p = ipc::mem::$new<int>();
|
auto p = ipc::mem::$new<int>();
|
||||||
ASSERT_NE(p, nullptr);
|
ASSERT_NE(p, nullptr);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user