Skip to content

qlibs/mem

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 

Repository files navigation

// Overview / Examples / API / FAQ

MEM: Memory Allocators

MIT Licence Version Build Try it online

https://en.wikipedia.org/wiki/Allocator_C++

Features

Requirements


Overview

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{};

API

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;
};

FAQ