🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

297 lines
11 KiB

  1. #ifndef AL_MALLOC_H
  2. #define AL_MALLOC_H
  3. #include <algorithm>
  4. #include <cstddef>
  5. #include <iterator>
  6. #include <limits>
  7. #include <memory>
  8. #include <new>
  9. #include <type_traits>
  10. #include <utility>
  11. #include "pragmadefs.h"
  12. void al_free(void *ptr) noexcept;
  13. [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]]
  14. void *al_malloc(size_t alignment, size_t size);
  15. [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc]]
  16. void *al_calloc(size_t alignment, size_t size);
  17. #define DISABLE_ALLOC() \
  18. void *operator new(size_t) = delete; \
  19. void *operator new[](size_t) = delete; \
  20. void operator delete(void*) noexcept = delete; \
  21. void operator delete[](void*) noexcept = delete;
  22. #define DEF_NEWDEL(T) \
  23. void *operator new(size_t size) \
  24. { \
  25. static_assert(&operator new == &T::operator new, \
  26. "Incorrect container type specified"); \
  27. if(void *ret{al_malloc(alignof(T), size)}) \
  28. return ret; \
  29. throw std::bad_alloc(); \
  30. } \
  31. void *operator new[](size_t size) { return operator new(size); } \
  32. void operator delete(void *block) noexcept { al_free(block); } \
  33. void operator delete[](void *block) noexcept { operator delete(block); }
  34. #define DEF_PLACE_NEWDEL() \
  35. void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
  36. void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
  37. void operator delete(void *block, void*) noexcept { al_free(block); } \
  38. void operator delete(void *block) noexcept { al_free(block); } \
  39. void operator delete[](void *block, void*) noexcept { al_free(block); } \
  40. void operator delete[](void *block) noexcept { al_free(block); }
  41. enum FamCount : size_t { };
  42. #define DEF_FAM_NEWDEL(T, FamMem) \
  43. static constexpr size_t Sizeof(size_t count) noexcept \
  44. { \
  45. static_assert(&Sizeof == &T::Sizeof, \
  46. "Incorrect container type specified"); \
  47. return std::max(decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)), \
  48. sizeof(T)); \
  49. } \
  50. \
  51. void *operator new(size_t /*size*/, FamCount count) \
  52. { \
  53. if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
  54. return ret; \
  55. throw std::bad_alloc(); \
  56. } \
  57. void *operator new[](size_t /*size*/) = delete; \
  58. void operator delete(void *block, FamCount) { al_free(block); } \
  59. void operator delete(void *block) noexcept { al_free(block); } \
  60. void operator delete[](void* /*block*/) = delete;
  61. namespace al {
  62. template<typename T, std::size_t alignment=alignof(T)>
  63. struct allocator {
  64. using value_type = T;
  65. using reference = T&;
  66. using const_reference = const T&;
  67. using pointer = T*;
  68. using const_pointer = const T*;
  69. using size_type = std::size_t;
  70. using difference_type = std::ptrdiff_t;
  71. using is_always_equal = std::true_type;
  72. template<typename U>
  73. struct rebind {
  74. using other = allocator<U, (alignment<alignof(U))?alignof(U):alignment>;
  75. };
  76. constexpr explicit allocator() noexcept = default;
  77. template<typename U, std::size_t N>
  78. constexpr explicit allocator(const allocator<U,N>&) noexcept { }
  79. T *allocate(std::size_t n)
  80. {
  81. if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
  82. if(auto p = al_malloc(alignment, n*sizeof(T))) return static_cast<T*>(p);
  83. throw std::bad_alloc();
  84. }
  85. void deallocate(T *p, std::size_t) noexcept { al_free(p); }
  86. };
  87. template<typename T, std::size_t N, typename U, std::size_t M>
  88. constexpr bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
  89. template<typename T, std::size_t N, typename U, std::size_t M>
  90. constexpr bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
  91. template<typename T, typename ...Args>
  92. constexpr T* construct_at(T *ptr, Args&& ...args)
  93. noexcept(std::is_nothrow_constructible<T, Args...>::value)
  94. { return ::new(static_cast<void*>(ptr)) T{std::forward<Args>(args)...}; }
  95. /* At least VS 2015 complains that 'ptr' is unused when the given type's
  96. * destructor is trivial (a no-op). So disable that warning for this call.
  97. */
  98. DIAGNOSTIC_PUSH
  99. msc_pragma(warning(disable : 4100))
  100. template<typename T>
  101. constexpr std::enable_if_t<!std::is_array<T>::value>
  102. destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
  103. { ptr->~T(); }
  104. DIAGNOSTIC_POP
  105. template<typename T>
  106. constexpr std::enable_if_t<std::is_array<T>::value>
  107. destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<std::remove_all_extents_t<T>>::value)
  108. {
  109. for(auto &elem : *ptr)
  110. al::destroy_at(std::addressof(elem));
  111. }
  112. template<typename T>
  113. constexpr void destroy(T first, T end) noexcept(noexcept(al::destroy_at(std::addressof(*first))))
  114. {
  115. while(first != end)
  116. {
  117. al::destroy_at(std::addressof(*first));
  118. ++first;
  119. }
  120. }
  121. template<typename T, typename N>
  122. constexpr std::enable_if_t<std::is_integral<N>::value,T>
  123. destroy_n(T first, N count) noexcept(noexcept(al::destroy_at(std::addressof(*first))))
  124. {
  125. if(count != 0)
  126. {
  127. do {
  128. al::destroy_at(std::addressof(*first));
  129. ++first;
  130. } while(--count);
  131. }
  132. return first;
  133. }
  134. template<typename T, typename N>
  135. inline std::enable_if_t<std::is_integral<N>::value,
  136. T> uninitialized_default_construct_n(T first, N count)
  137. {
  138. using ValueT = typename std::iterator_traits<T>::value_type;
  139. T current{first};
  140. if(count != 0)
  141. {
  142. try {
  143. do {
  144. ::new(static_cast<void*>(std::addressof(*current))) ValueT;
  145. ++current;
  146. } while(--count);
  147. }
  148. catch(...) {
  149. al::destroy(first, current);
  150. throw;
  151. }
  152. }
  153. return current;
  154. }
  155. /* Storage for flexible array data. This is trivially destructible if type T is
  156. * trivially destructible.
  157. */
  158. template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
  159. struct FlexArrayStorage {
  160. const size_t mSize;
  161. union {
  162. char mDummy;
  163. alignas(alignment) T mArray[1];
  164. };
  165. static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
  166. {
  167. const size_t len{sizeof(T)*count};
  168. return std::max(offsetof(FlexArrayStorage,mArray)+len, sizeof(FlexArrayStorage)) + base;
  169. }
  170. FlexArrayStorage(size_t size) : mSize{size}
  171. { al::uninitialized_default_construct_n(mArray, mSize); }
  172. ~FlexArrayStorage() = default;
  173. FlexArrayStorage(const FlexArrayStorage&) = delete;
  174. FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
  175. };
  176. template<typename T, size_t alignment>
  177. struct FlexArrayStorage<T,alignment,false> {
  178. const size_t mSize;
  179. union {
  180. char mDummy;
  181. alignas(alignment) T mArray[1];
  182. };
  183. static constexpr size_t Sizeof(size_t count, size_t base) noexcept
  184. {
  185. const size_t len{sizeof(T)*count};
  186. return std::max(offsetof(FlexArrayStorage,mArray)+len, sizeof(FlexArrayStorage)) + base;
  187. }
  188. FlexArrayStorage(size_t size) : mSize{size}
  189. { al::uninitialized_default_construct_n(mArray, mSize); }
  190. ~FlexArrayStorage() { al::destroy_n(mArray, mSize); }
  191. FlexArrayStorage(const FlexArrayStorage&) = delete;
  192. FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
  193. };
  194. /* A flexible array type. Used either standalone or at the end of a parent
  195. * struct, with placement new, to have a run-time-sized array that's embedded
  196. * with its size.
  197. */
  198. template<typename T, size_t alignment=alignof(T)>
  199. struct FlexArray {
  200. using element_type = T;
  201. using value_type = std::remove_cv_t<T>;
  202. using index_type = size_t;
  203. using difference_type = ptrdiff_t;
  204. using pointer = T*;
  205. using const_pointer = const T*;
  206. using reference = T&;
  207. using const_reference = const T&;
  208. using iterator = pointer;
  209. using const_iterator = const_pointer;
  210. using reverse_iterator = std::reverse_iterator<iterator>;
  211. using const_reverse_iterator = std::reverse_iterator<const_iterator>;
  212. using Storage_t_ = FlexArrayStorage<element_type,alignment>;
  213. Storage_t_ mStore;
  214. static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
  215. { return Storage_t_::Sizeof(count, base); }
  216. static std::unique_ptr<FlexArray> Create(index_type count)
  217. {
  218. void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
  219. return std::unique_ptr<FlexArray>{al::construct_at(static_cast<FlexArray*>(ptr), count)};
  220. }
  221. FlexArray(index_type size) : mStore{size} { }
  222. ~FlexArray() = default;
  223. index_type size() const noexcept { return mStore.mSize; }
  224. bool empty() const noexcept { return mStore.mSize == 0; }
  225. pointer data() noexcept { return mStore.mArray; }
  226. const_pointer data() const noexcept { return mStore.mArray; }
  227. reference operator[](index_type i) noexcept { return mStore.mArray[i]; }
  228. const_reference operator[](index_type i) const noexcept { return mStore.mArray[i]; }
  229. reference front() noexcept { return mStore.mArray[0]; }
  230. const_reference front() const noexcept { return mStore.mArray[0]; }
  231. reference back() noexcept { return mStore.mArray[mStore.mSize-1]; }
  232. const_reference back() const noexcept { return mStore.mArray[mStore.mSize-1]; }
  233. iterator begin() noexcept { return mStore.mArray; }
  234. const_iterator begin() const noexcept { return mStore.mArray; }
  235. const_iterator cbegin() const noexcept { return mStore.mArray; }
  236. iterator end() noexcept { return mStore.mArray + mStore.mSize; }
  237. const_iterator end() const noexcept { return mStore.mArray + mStore.mSize; }
  238. const_iterator cend() const noexcept { return mStore.mArray + mStore.mSize; }
  239. reverse_iterator rbegin() noexcept { return end(); }
  240. const_reverse_iterator rbegin() const noexcept { return end(); }
  241. const_reverse_iterator crbegin() const noexcept { return cend(); }
  242. reverse_iterator rend() noexcept { return begin(); }
  243. const_reverse_iterator rend() const noexcept { return begin(); }
  244. const_reverse_iterator crend() const noexcept { return cbegin(); }
  245. DEF_PLACE_NEWDEL()
  246. };
  247. } // namespace al
  248. #endif /* AL_MALLOC_H */