// Overview / Examples / API / FAQ
- Single header (https://raw.githubusercontent.com/qlibs/mem/main/mem - for integration see FAQ)
- Minimal API
- Verifies itself upon include (can be disabled with
-DNTEST
- see FAQ)
- C++20 (clang++12+, g++11+) / Linux
static_assert(mem::allocator<std::allocator<int>>);
static_assert(mem::allocator<mem::stack_allocator<int, 1024u>>);
static_assert(mem::allocator<mem::huge_page_allocator<int>>);
static_assert(mem::allocator<mem::transparent_huge_page_allocator<int>>);
static_assert(mem::allocator<mem::numa_allocator<int>>);
std::vector<int, mem::stack_allocator<int, 1024u>> v{};
// echo 20 > /proc/sys/vm/nr_hugepages
std::vector<int, mem::huge_page_allocator<int>> v{};
// echo always > /sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled
std::vector<int, mem::transparent_huge_page_allocator<int>> v{};
// -lnuma (requires libnuma-dev)
std::vector<int, mem::numa_allocator<int>> v{};
template<class TAllocator>
concept allocator = requires(TAllocator alloc,
typename TAllocator::value_type* ptr,
std::size_t n) {
typename TAllocator::value_type;
{ alloc.allocate(n) } -> std::same_as<decltype(ptr)>;
{ alloc.deallocate(ptr, n) } -> std::same_as<void>;
#if __cpp_lib_allocate_at_least >= 202302L
{ allocate_at_least(n) } -> std::same_as<std::allocation_result<T*, std::size_t>>;
#endif
};
template<class T,
std::size_t N,
std::size_t alignment = alignof(T),
auto on_error = [] { return nullptr; }>
requires (alignment <= alignof(std::max_align_t)) and (not (N % alignment))
struct stack_allocator {
using value_type = T;
constexpr stack_allocator() noexcept = default;
[[nodiscard]] constexpr auto allocate(std::size_t n) noexcept(noexcept(on_error())) -> T*;
#if __cpp_lib_allocate_at_least >= 202302L
constexpr std::allocation_result<T*, std::size_t>
allocate_at_least(std::size_t n) noexcept(noexcept(allocate(n));
#endif
constexpr void deallocate(T* ptr, std::size_t n) noexcept;
};
template <class T,
std::size_t N = (1u << 21u),
auto on_error = [] { return nullptr; }>
struct huge_page_allocator {
using value_type = T;
constexpr huge_page_allocator() noexcept = default;
[[nodiscard]] constexpr auto allocate(std::size_t n) noexcept(noexcept(on_error())) -> T*;
#if __cpp_lib_allocate_at_least >= 202302L
constexpr std::allocation_result<T*, std::size_t>
allocate_at_least(std::size_t n) noexcept(noexcept(allocate(n));
#endif
constexpr void deallocate(T *ptr, std::size_t n) noexcept;
};
template <class T,
std::size_t N = (1u << 21u),
auto on_error = [] { return nullptr; }>
struct transparent_huge_page_allocator {
using value_type = T;
constexpr transparent_huge_page_allocator() noexcept = default;
T *allocate(std::size_t n);
#if __cpp_lib_allocate_at_least >= 202302L
constexpr std::allocation_result<T*, std::size_t>
allocate_at_least(std::size_t n) noexcept(noexcept(allocate(n));
#endif
constexpr void deallocate(T *ptr, std::size_t n) noexcept;
};
template<class T, auto on_error = [] { return nullptr; }>
struct numa_allocator {
using value_type = T;
constexpr numa_allocator(node_type node = {}) noexcept;
[[nodiscard]] constexpr auto allocate(std::size_t n) noexcept(noexcept(on_error())) -> T*;
#if __cpp_lib_allocate_at_least >= 202302L
constexpr std::allocation_result<T*, std::size_t>
allocate_at_least(std::size_t n) noexcept(noexcept(allocate(n));
#endif
constexpr void deallocate(T* ptr, std::size_t n) noexcept;
};
-
How to integrate with CMake.FetchContent?
include(FetchContent) FetchContent_Declare( qlibs.mem GIT_REPOSITORY https://github.com/qlibs/mem GIT_TAG v1.0.1 ) FetchContent_MakeAvailable(qlibs.mem)
target_link_libraries(${PROJECT_NAME} PUBLIC qlibs.mem);
-
Acknowledgments
std::allocator
Huge Pages (HP)
Transparent Huge Pages (THP)
Non Uniform Memory Access (NUMA)