aboutsummaryrefslogtreecommitdiffstats
path: root/common/almalloc.h
diff options
context:
space:
mode:
Diffstat (limited to 'common/almalloc.h')
-rw-r--r--common/almalloc.h208
1 files changed, 41 insertions, 167 deletions
diff --git a/common/almalloc.h b/common/almalloc.h
index 873473ca..3b9965e6 100644
--- a/common/almalloc.h
+++ b/common/almalloc.h
@@ -13,39 +13,17 @@
#include "pragmadefs.h"
-void al_free(void *ptr) noexcept;
-[[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]]
-void *al_malloc(size_t alignment, size_t size);
-[[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]]
-void *al_calloc(size_t alignment, size_t size);
+namespace gsl {
+template<typename T> using owner = T;
+};
-#define DISABLE_ALLOC() \
+#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;
-#define DEF_NEWDEL(T) \
- void *operator new(size_t size) \
- { \
- 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(); \
- } \
- 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); }
-
-#define DEF_PLACE_NEWDEL() \
- void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
- void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
- void operator delete(void *block, void*) noexcept { al_free(block); } \
- 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); }
enum FamCount : size_t { };
@@ -58,54 +36,59 @@ enum FamCount : size_t { };
sizeof(T)); \
} \
\
- void *operator new(size_t /*size*/, FamCount count) \
+ gsl::owner<void*> operator new(size_t /*size*/, FamCount count) \
{ \
- if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
- return ret; \
- throw std::bad_alloc(); \
+ const auto alignment = std::align_val_t{alignof(T)}; \
+ return ::operator new[](T::Sizeof(count), alignment); \
} \
+ void operator delete(gsl::owner<void*> block, FamCount) noexcept \
+ { ::operator delete[](block, std::align_val_t{alignof(T)}); } \
+ void operator delete(gsl::owner<void*> block) noexcept \
+ { ::operator delete[](block, std::align_val_t{alignof(T)}); } \
void *operator new[](size_t /*size*/) = delete; \
- void operator delete(void *block, FamCount) { al_free(block); } \
- void operator delete(void *block) noexcept { al_free(block); } \
void operator delete[](void* /*block*/) = delete;
namespace al {
-template<typename T, std::size_t Align=alignof(T)>
+template<typename T, std::size_t AlignV=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*;
+ static constexpr auto Alignment = std::max(AlignV, alignof(T));
+ static constexpr auto AlignVal = std::align_val_t{Alignment};
+
+ using value_type = std::remove_cv_t<std::remove_reference_t<T>>;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using is_always_equal = std::true_type;
- template<typename U>
+ template<typename U, std::enable_if_t<alignof(U) <= Alignment,bool> = true>
struct rebind {
- using other = allocator<U, Align>;
+ using other = allocator<U,Alignment>;
};
constexpr explicit allocator() noexcept = default;
template<typename U, std::size_t N>
- constexpr explicit allocator(const allocator<U,N>&) noexcept { }
+ constexpr explicit allocator(const allocator<U,N>&) noexcept
+ { static_assert(Alignment == allocator<U,N>::Alignment); }
- T *allocate(std::size_t n)
+ gsl::owner<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();
+ return static_cast<gsl::owner<T*>>(::operator new[](n*sizeof(T), AlignVal));
}
- void deallocate(T *p, std::size_t) noexcept { al_free(p); }
+ void deallocate(gsl::owner<T*> p, std::size_t) noexcept
+ { ::operator delete[](gsl::owner<void*>{p}, AlignVal); }
};
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; }
+constexpr bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept
+{ return allocator<T,N>::Alignment == allocator<U,M>::Alignment; }
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 false; }
+constexpr bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept
+{ return allocator<T,N>::Alignment != allocator<U,M>::Alignment; }
template<typename T>
@@ -124,124 +107,15 @@ constexpr auto to_address(const T &p) noexcept
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)...}; }
-
-
-/* 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}
- { std::uninitialized_default_construct_n(mArray, mSize); }
- ~FlexArrayStorage() = default;
-
- FlexArrayStorage(const FlexArrayStorage&) = delete;
- FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
-};
-
-template<typename T, size_t alignment>
-struct FlexArrayStorage<T,alignment,false> {
- 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;
- }
-
- FlexArrayStorage(size_t size) : mSize{size}
- { std::uninitialized_default_construct_n(mArray, mSize); }
- ~FlexArrayStorage() { std::destroy_n(mArray, mSize); }
-
- FlexArrayStorage(const FlexArrayStorage&) = delete;
- FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
-};
-
-/* 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 {
- 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&;
-
- using iterator = pointer;
- using const_iterator = const_pointer;
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
- 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)};
- }
-
- FlexArray(index_type size) : mStore{size} { }
- ~FlexArray() = default;
-
- index_type size() const noexcept { return mStore.mSize; }
- bool empty() const noexcept { return mStore.mSize == 0; }
-
- pointer data() noexcept { return mStore.mArray; }
- const_pointer data() const noexcept { return mStore.mArray; }
-
- reference operator[](index_type i) noexcept { return mStore.mArray[i]; }
- const_reference operator[](index_type i) const noexcept { return mStore.mArray[i]; }
-
- reference front() noexcept { return mStore.mArray[0]; }
- const_reference front() const noexcept { return mStore.mArray[0]; }
-
- reference back() noexcept { return mStore.mArray[mStore.mSize-1]; }
- const_reference back() const noexcept { return mStore.mArray[mStore.mSize-1]; }
-
- 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; }
-
- 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(); }
-
- DEF_PLACE_NEWDEL()
-};
+ noexcept(std::is_nothrow_constructible_v<T, Args...>)
+{
+ /* NOLINTBEGIN(cppcoreguidelines-owning-memory) construct_at doesn't
+ * necessarily handle the address from an owner, while placement new
+ * expects to.
+ */
+ return ::new(static_cast<void*>(ptr)) T{std::forward<Args>(args)...};
+ /* NOLINTEND(cppcoreguidelines-owning-memory) */
+}
} // namespace al