8#include "plg/config.hpp"
17 using value_type = void;
25 static_assert(!std::is_const_v<T>,
"plg::allocator does not support const types");
26 static_assert(!std::is_volatile_v<T>,
"plg::allocator does not support volatile types");
29 using size_type = std::size_t;
30 using difference_type = std::ptrdiff_t;
40 [[nodiscard]]
constexpr T* allocate(size_type n) {
41 static_assert(
sizeof(T) != 0,
"cannot allocate incomplete types");
42 static_assert((
alignof(T) & (
alignof(T) - 1)) == 0,
"alignof(T) must be a power of 2");
44 if (n > std::allocator_traits<allocator>::max_size(*
this)) {
45 throw_bad_array_new_length();
48 size_type size = n *
sizeof(T);
49 if (std::is_constant_evaluated()) {
50 return static_cast<T*
>(::operator
new(size));
52 return malloc_allocate(size);
56 constexpr void deallocate(T* p, [[maybe_unused]] size_type n) {
57 if (std::is_constant_evaluated()) {
65 static T* malloc_allocate(size_type size) {
67 if constexpr (
alignof(T) >
alignof(std::max_align_t)) {
68 size_type aligned_size = (size + (
alignof(T) - 1)) & ~(
alignof(T) - 1);
69 ret =
static_cast<T*
>(aligned_allocate(
alignof(T), aligned_size));
71 ret =
static_cast<T*
>(std::malloc(size));
79 [[noreturn]]
static void throw_bad_array_new_length() {
80 PLUGIFY_THROW(
"bad array new length", std::bad_array_new_length);
83 [[noreturn]]
static void throw_bad_alloc() {
84 PLUGIFY_THROW(
"bad allocation", std::bad_alloc);
87 static void* aligned_allocate(size_type alignment, size_type size) {
88#if PLUGIFY_PLATFORM_WINDOWS
89 return _aligned_malloc(size, alignment);
91 return std::aligned_alloc(alignment, size);
96 template<
typename T,
typename U>
97 constexpr bool operator==(
const allocator<T>&,
const allocator<U>) {
return true; }
99 template<
typename T,
typename U>
100 constexpr bool operator!=(
const allocator<T>&,
const allocator<U>) {
return false; }
102 template <
typename Alloc>
103 void swap_allocator(Alloc& a1, Alloc& a2, std::true_type) {
108 template <
typename Alloc>
109 void swap_allocator(Alloc&, Alloc&, std::false_type)
noexcept {}
111 template <
typename Alloc>
112 void swap_allocator(Alloc& a1, Alloc& a2) {
113 swap_allocator(a1, a2, std::integral_constant<
bool, std::allocator_traits<Alloc>::propagate_on_container_swap::value>());
116 template <
class Po
inter,
class Size = std::
size_t>
122 template <
class Alloc>
125 return {
alloc.allocate(n), n };
128 template <
class T,
class U>
129 constexpr bool is_pointer_in_range(
const T* begin,
const T* end,
const U* ptr) {
130 if (std::is_constant_evaluated())
132 return reinterpret_cast<const char*
>(begin) <=
reinterpret_cast<const char*
>(ptr) &&
133 reinterpret_cast<const char*
>(ptr) <
reinterpret_cast<const char*
>(end);
136 template <
class T,
class U>
137 constexpr bool is_overlapping_range(
const T* begin,
const T* end,
const U* begin2) {
138 auto size = end - begin;
139 auto end2 = begin2 + size;
140 return is_pointer_in_range(begin, end, begin2) || is_pointer_in_range(begin2, end2, begin);
146#if PLUGIFY_INSTRUMENTED_WITH_ASAN
147 template <
class Alloc>
148 struct asan_annotate_container_with_allocator : std::true_type {};
155 template <
class Allocator>
156 constexpr void annotate_contiguous_container(
157 [[maybe_unused]]
const void* first_storage,
158 [[maybe_unused]]
const void* last_storage,
159 [[maybe_unused]]
const void* old_last_contained,
160 [[maybe_unused]]
const void* new_last_contained
162#if PLUGIFY_INSTRUMENTED_WITH_ASAN
163 if (!std::is_constant_evaluated()
164 && asan_annotate_container_with_allocator<Allocator>::value
165 && first_storage !=
nullptr) {
166 __sanitizer_annotate_contiguous_container(