2016-03-29 07:44:58 +00:00
|
|
|
#ifndef AL_MALLOC_H
|
|
|
|
#define AL_MALLOC_H
|
|
|
|
|
2019-01-11 16:07:25 +00:00
|
|
|
#include <algorithm>
|
2019-07-29 16:29:35 +00:00
|
|
|
#include <cstddef>
|
|
|
|
#include <iterator>
|
|
|
|
#include <limits>
|
|
|
|
#include <memory>
|
|
|
|
#include <new>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <utility>
|
2018-11-18 09:33:26 +00:00
|
|
|
|
2019-10-07 22:17:45 +00:00
|
|
|
#include "pragmadefs.h"
|
2017-02-28 04:43:16 +00:00
|
|
|
|
2019-09-18 19:16:08 +00:00
|
|
|
|
2018-11-18 08:38:31 +00:00
|
|
|
void al_free(void *ptr) noexcept;
|
2023-03-29 11:07:38 +00:00
|
|
|
|
2021-02-14 12:07:26 +00:00
|
|
|
void *al_malloc(size_t alignment, size_t size);
|
2023-03-29 11:07:38 +00:00
|
|
|
|
2021-02-14 12:07:26 +00:00
|
|
|
void *al_calloc(size_t alignment, size_t size);
|
2016-03-29 07:44:58 +00:00
|
|
|
|
2018-11-18 08:38:31 +00:00
|
|
|
|
2020-03-23 23:00:50 +00:00
|
|
|
#define DISABLE_ALLOC() \
|
|
|
|
void *operator new(size_t) = delete; \
|
|
|
|
void *operator new[](size_t) = delete; \
|
|
|
|
void operator delete(void*) noexcept = delete; \
|
|
|
|
void operator delete[](void*) noexcept = delete;
|
|
|
|
|
2018-11-18 08:38:31 +00:00
|
|
|
#define DEF_NEWDEL(T) \
|
|
|
|
void *operator new(size_t size) \
|
|
|
|
{ \
|
2022-05-17 06:08:07 +00:00
|
|
|
static_assert(&operator new == &T::operator new, \
|
|
|
|
"Incorrect container type specified"); \
|
|
|
|
if(void *ret{al_malloc(alignof(T), size)}) \
|
|
|
|
return ret; \
|
|
|
|
throw std::bad_alloc(); \
|
2018-11-18 08:38:31 +00:00
|
|
|
} \
|
2020-03-22 20:28:45 +00:00
|
|
|
void *operator new[](size_t size) { return operator new(size); } \
|
|
|
|
void operator delete(void *block) noexcept { al_free(block); } \
|
|
|
|
void operator delete[](void *block) noexcept { operator delete(block); }
|
2016-03-29 07:44:58 +00:00
|
|
|
|
2018-11-22 15:06:42 +00:00
|
|
|
#define DEF_PLACE_NEWDEL() \
|
|
|
|
void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
|
2020-03-22 20:28:45 +00:00
|
|
|
void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
|
2019-09-11 10:59:53 +00:00
|
|
|
void operator delete(void *block, void*) noexcept { al_free(block); } \
|
2020-03-22 20:28:45 +00:00
|
|
|
void operator delete(void *block) noexcept { al_free(block); } \
|
|
|
|
void operator delete[](void *block, void*) noexcept { al_free(block); } \
|
|
|
|
void operator delete[](void *block) noexcept { al_free(block); }
|
2019-09-11 10:59:53 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
enum FamCount : size_t
|
|
|
|
{ };
|
2019-09-11 10:59:53 +00:00
|
|
|
|
|
|
|
#define DEF_FAM_NEWDEL(T, FamMem) \
|
|
|
|
static constexpr size_t Sizeof(size_t count) noexcept \
|
2020-08-16 06:53:43 +00:00
|
|
|
{ \
|
2022-05-17 06:08:07 +00:00
|
|
|
static_assert(&Sizeof == &T::Sizeof, \
|
|
|
|
"Incorrect container type specified"); \
|
2022-03-24 23:12:23 +00:00
|
|
|
return std::max(decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)), \
|
|
|
|
sizeof(T)); \
|
2020-08-16 06:53:43 +00:00
|
|
|
} \
|
2019-09-11 10:59:53 +00:00
|
|
|
\
|
2020-05-19 19:15:57 +00:00
|
|
|
void *operator new(size_t /*size*/, FamCount count) \
|
2019-09-11 10:59:53 +00:00
|
|
|
{ \
|
2020-05-19 19:15:57 +00:00
|
|
|
if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
|
2019-09-11 10:59:53 +00:00
|
|
|
return ret; \
|
|
|
|
throw std::bad_alloc(); \
|
|
|
|
} \
|
2020-03-22 20:28:45 +00:00
|
|
|
void *operator new[](size_t /*size*/) = delete; \
|
2019-09-12 11:30:52 +00:00
|
|
|
void operator delete(void *block, FamCount) { al_free(block); } \
|
2020-03-22 20:28:45 +00:00
|
|
|
void operator delete(void *block) noexcept { al_free(block); } \
|
|
|
|
void operator delete[](void* /*block*/) = delete;
|
2019-09-11 10:59:53 +00:00
|
|
|
|
2018-11-22 15:06:42 +00:00
|
|
|
|
2018-11-18 09:33:26 +00:00
|
|
|
namespace al {
|
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T, std::size_t Align=alignof(T)>
|
|
|
|
struct allocator
|
|
|
|
{
|
|
|
|
static constexpr std::size_t alignment { std::max(Align, alignof(T)) };
|
|
|
|
|
|
|
|
using value_type = T;
|
|
|
|
using reference = T &;
|
|
|
|
using const_reference = const T &;
|
|
|
|
using pointer = T *;
|
|
|
|
using const_pointer = const T *;
|
|
|
|
using size_type = std::size_t;
|
|
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
using is_always_equal = std::true_type;
|
|
|
|
|
|
|
|
template<typename U>
|
|
|
|
struct rebind
|
|
|
|
{
|
|
|
|
using other = allocator<U, Align>;
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr explicit allocator() noexcept = default;
|
|
|
|
template<typename U, std::size_t N>
|
|
|
|
constexpr explicit allocator(const allocator<U, N> &) noexcept
|
|
|
|
{ }
|
|
|
|
|
|
|
|
T *allocate(std::size_t n)
|
|
|
|
{
|
|
|
|
if (n > std::numeric_limits<std::size_t>::max() / sizeof(T)) throw std::bad_alloc();
|
|
|
|
if (auto p = al_malloc(alignment, n * sizeof(T))) return static_cast<T *>(p);
|
|
|
|
throw std::bad_alloc();
|
|
|
|
}
|
|
|
|
void deallocate(T *p, std::size_t) noexcept
|
|
|
|
{
|
|
|
|
al_free(p);
|
|
|
|
}
|
2018-11-18 09:33:26 +00:00
|
|
|
};
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T, std::size_t N, typename U, std::size_t M>
|
|
|
|
constexpr bool operator==(const allocator<T, N> &, const allocator<U, M> &) noexcept
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
template<typename T, std::size_t N, typename U, std::size_t M>
|
|
|
|
constexpr bool operator!=(const allocator<T, N> &, const allocator<U, M> &) noexcept
|
2019-09-11 10:22:10 +00:00
|
|
|
{
|
2023-03-29 11:07:38 +00:00
|
|
|
return false;
|
2018-11-18 09:33:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T>
|
|
|
|
constexpr T *to_address(T *p) noexcept
|
2019-09-11 10:22:10 +00:00
|
|
|
{
|
2023-03-29 11:07:38 +00:00
|
|
|
static_assert(!std::is_function<T>::value, "Can't be a function type");
|
|
|
|
return p;
|
|
|
|
}
|
2022-12-15 01:39:47 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T>
|
|
|
|
constexpr auto to_address(const T &p) noexcept
|
|
|
|
{
|
|
|
|
return to_address(p.operator->());
|
2018-11-18 09:33:26 +00:00
|
|
|
}
|
|
|
|
|
2022-12-15 01:39:47 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T, typename ...Args>
|
|
|
|
constexpr T *construct_at(T *ptr, Args&& ...args)
|
|
|
|
noexcept(std::is_nothrow_constructible<T, Args...>::value)
|
|
|
|
{
|
|
|
|
return ::new(static_cast<void *>(ptr)) T { std::forward<Args>(args)... };
|
|
|
|
}
|
2018-12-20 19:46:40 +00:00
|
|
|
|
2019-09-18 19:16:08 +00:00
|
|
|
/* At least VS 2015 complains that 'ptr' is unused when the given type's
|
|
|
|
* destructor is trivial (a no-op). So disable that warning for this call.
|
|
|
|
*/
|
2023-03-29 11:07:38 +00:00
|
|
|
DIAGNOSTIC_PUSH
|
|
|
|
msc_pragma(warning(disable : 4100))
|
|
|
|
template<typename T>
|
|
|
|
constexpr std::enable_if_t<!std::is_array<T>::value>
|
|
|
|
destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
|
|
|
|
{
|
|
|
|
ptr->~T();
|
|
|
|
}
|
|
|
|
DIAGNOSTIC_POP
|
|
|
|
template<typename T>
|
|
|
|
constexpr std::enable_if_t<std::is_array<T>::value>
|
|
|
|
destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<std::remove_all_extents_t<T>>::value)
|
2019-06-05 23:38:53 +00:00
|
|
|
{
|
2023-03-29 11:07:38 +00:00
|
|
|
for (auto &elem : *ptr)
|
|
|
|
al::destroy_at(std::addressof(elem));
|
2019-06-05 23:38:53 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T>
|
|
|
|
constexpr void destroy(T first, T end) noexcept(noexcept(al::destroy_at(std::addressof(*first))))
|
2019-06-05 23:38:53 +00:00
|
|
|
{
|
2023-03-29 11:07:38 +00:00
|
|
|
while (first != end)
|
|
|
|
{
|
2019-06-21 16:25:09 +00:00
|
|
|
al::destroy_at(std::addressof(*first));
|
2019-06-05 23:38:53 +00:00
|
|
|
++first;
|
2023-03-29 11:07:38 +00:00
|
|
|
}
|
2019-06-05 23:38:53 +00:00
|
|
|
}
|
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T, typename N>
|
|
|
|
constexpr std::enable_if_t<std::is_integral<N>::value, T>
|
|
|
|
destroy_n(T first, N count) noexcept(noexcept(al::destroy_at(std::addressof(*first))))
|
2019-06-05 23:38:53 +00:00
|
|
|
{
|
2023-03-29 11:07:38 +00:00
|
|
|
if (count != 0)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
al::destroy_at(std::addressof(*first));
|
|
|
|
++first;
|
|
|
|
}
|
|
|
|
while (--count);
|
2019-06-05 23:38:53 +00:00
|
|
|
}
|
2023-03-29 11:07:38 +00:00
|
|
|
return first;
|
2019-06-05 23:38:53 +00:00
|
|
|
}
|
|
|
|
|
2020-12-27 12:29:54 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T, typename N>
|
|
|
|
inline std::enable_if_t<std::is_integral<N>::value,
|
|
|
|
T> uninitialized_default_construct_n(T first, N count)
|
2020-12-27 12:29:54 +00:00
|
|
|
{
|
2023-03-29 11:07:38 +00:00
|
|
|
using ValueT = typename std::iterator_traits<T>::value_type;
|
|
|
|
T current { first };
|
|
|
|
if (count != 0)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
::new(static_cast<void *>(std::addressof(*current))) ValueT;
|
|
|
|
++current;
|
|
|
|
}
|
|
|
|
while (--count);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
al::destroy(first, current);
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return current;
|
2020-12-27 12:29:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
/* Storage for flexible array data. This is trivially destructible if type T is
|
|
|
|
* trivially destructible.
|
|
|
|
*/
|
|
|
|
template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
|
|
|
|
struct FlexArrayStorage
|
|
|
|
{
|
|
|
|
const size_t mSize;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
char mDummy;
|
|
|
|
alignas(alignment) T mArray[1];
|
|
|
|
};
|
|
|
|
|
|
|
|
static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
|
|
|
|
{
|
|
|
|
const size_t len { sizeof(T) * count };
|
|
|
|
return std::max(offsetof(FlexArrayStorage, mArray) + len, sizeof(FlexArrayStorage)) + base;
|
|
|
|
}
|
|
|
|
|
|
|
|
FlexArrayStorage(size_t size) : mSize { size }
|
|
|
|
{
|
|
|
|
al::uninitialized_default_construct_n(mArray, mSize);
|
|
|
|
}
|
|
|
|
~FlexArrayStorage() = default;
|
2020-12-27 12:29:54 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
FlexArrayStorage(const FlexArrayStorage &) = delete;
|
|
|
|
FlexArrayStorage &operator=(const FlexArrayStorage &) = delete;
|
2020-12-27 12:29:54 +00:00
|
|
|
};
|
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
template<typename T, size_t alignment>
|
|
|
|
struct FlexArrayStorage<T, alignment, false>
|
2020-12-27 12:29:54 +00:00
|
|
|
{
|
2023-03-29 11:07:38 +00:00
|
|
|
const size_t mSize;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
char mDummy;
|
|
|
|
alignas(alignment) T mArray[1];
|
|
|
|
};
|
|
|
|
|
|
|
|
static constexpr size_t Sizeof(size_t count, size_t base) noexcept
|
|
|
|
{
|
|
|
|
const size_t len { sizeof(T) * count };
|
|
|
|
return std::max(offsetof(FlexArrayStorage, mArray) + len, sizeof(FlexArrayStorage)) + base;
|
|
|
|
}
|
2020-12-27 12:29:54 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
FlexArrayStorage(size_t size) : mSize { size }
|
|
|
|
{
|
|
|
|
al::uninitialized_default_construct_n(mArray, mSize);
|
|
|
|
}
|
|
|
|
~FlexArrayStorage()
|
|
|
|
{
|
|
|
|
al::destroy_n(mArray, mSize);
|
|
|
|
}
|
2020-12-27 12:29:54 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
FlexArrayStorage(const FlexArrayStorage &) = delete;
|
|
|
|
FlexArrayStorage &operator=(const FlexArrayStorage &) = delete;
|
|
|
|
};
|
2020-12-27 12:29:54 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
/* A flexible array type. Used either standalone or at the end of a parent
|
|
|
|
* struct, with placement new, to have a run-time-sized array that's embedded
|
|
|
|
* with its size.
|
|
|
|
*/
|
|
|
|
template<typename T, size_t alignment=alignof(T)>
|
|
|
|
struct FlexArray
|
2019-08-03 21:59:01 +00:00
|
|
|
{
|
2023-03-29 11:07:38 +00:00
|
|
|
using element_type = T;
|
|
|
|
using value_type = std::remove_cv_t<T>;
|
|
|
|
using index_type = size_t;
|
|
|
|
using difference_type = ptrdiff_t;
|
|
|
|
|
|
|
|
using pointer = T *;
|
|
|
|
using const_pointer = const T *;
|
|
|
|
using reference = T &;
|
|
|
|
using const_reference = const T &;
|
2019-01-11 14:00:41 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
using iterator = pointer;
|
|
|
|
using const_iterator = const_pointer;
|
|
|
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
|
|
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
2019-01-11 14:00:41 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
using Storage_t_ = FlexArrayStorage<element_type, alignment>;
|
|
|
|
|
|
|
|
Storage_t_ mStore;
|
|
|
|
|
|
|
|
static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
|
|
|
|
{
|
|
|
|
return Storage_t_::Sizeof(count, base);
|
|
|
|
}
|
|
|
|
static std::unique_ptr<FlexArray> Create(index_type count)
|
|
|
|
{
|
|
|
|
void *ptr { al_calloc(alignof(FlexArray), Sizeof(count)) };
|
|
|
|
return std::unique_ptr<FlexArray>{al::construct_at(static_cast<FlexArray *>(ptr), count)};
|
|
|
|
}
|
2019-06-08 06:42:31 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
FlexArray(index_type size) : mStore { size }
|
|
|
|
{ }
|
|
|
|
~FlexArray() = default;
|
2019-01-11 14:00:41 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
index_type size() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mSize;
|
|
|
|
}
|
|
|
|
bool empty() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mSize == 0;
|
|
|
|
}
|
2019-06-08 06:42:31 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
pointer data() noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray;
|
|
|
|
}
|
|
|
|
const_pointer data() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray;
|
|
|
|
}
|
2019-01-11 14:00:41 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
reference operator[](index_type i) noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray[i];
|
|
|
|
}
|
|
|
|
const_reference operator[](index_type i) const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray[i];
|
|
|
|
}
|
2019-01-11 14:00:41 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
reference front() noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray[0];
|
|
|
|
}
|
|
|
|
const_reference front() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray[0];
|
|
|
|
}
|
2019-01-11 14:00:41 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
reference back() noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray[mStore.mSize - 1];
|
|
|
|
}
|
|
|
|
const_reference back() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray[mStore.mSize - 1];
|
|
|
|
}
|
2019-01-17 10:23:57 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
iterator begin() noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray;
|
|
|
|
}
|
|
|
|
const_iterator begin() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray;
|
|
|
|
}
|
|
|
|
const_iterator cbegin() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray;
|
|
|
|
}
|
|
|
|
iterator end() noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray + mStore.mSize;
|
|
|
|
}
|
|
|
|
const_iterator end() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray + mStore.mSize;
|
|
|
|
}
|
|
|
|
const_iterator cend() const noexcept
|
|
|
|
{
|
|
|
|
return mStore.mArray + mStore.mSize;
|
|
|
|
}
|
2019-01-17 10:23:57 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
reverse_iterator rbegin() noexcept
|
|
|
|
{
|
|
|
|
return end();
|
|
|
|
}
|
|
|
|
const_reverse_iterator rbegin() const noexcept
|
|
|
|
{
|
|
|
|
return end();
|
|
|
|
}
|
|
|
|
const_reverse_iterator crbegin() const noexcept
|
|
|
|
{
|
|
|
|
return cend();
|
|
|
|
}
|
|
|
|
reverse_iterator rend() noexcept
|
|
|
|
{
|
|
|
|
return begin();
|
|
|
|
}
|
|
|
|
const_reverse_iterator rend() const noexcept
|
|
|
|
{
|
|
|
|
return begin();
|
|
|
|
}
|
|
|
|
const_reverse_iterator crend() const noexcept
|
|
|
|
{
|
|
|
|
return cbegin();
|
|
|
|
}
|
2019-01-11 14:00:41 +00:00
|
|
|
|
2023-03-29 11:07:38 +00:00
|
|
|
DEF_PLACE_NEWDEL()
|
|
|
|
};
|
2019-01-11 14:00:41 +00:00
|
|
|
|
2018-11-18 09:33:26 +00:00
|
|
|
} // namespace al
|
|
|
|
|
2016-03-29 07:44:58 +00:00
|
|
|
#endif /* AL_MALLOC_H */
|