🛠️🐜 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.

148 lines
4.7 KiB

  1. #ifndef AL_MALLOC_H
  2. #define AL_MALLOC_H
  3. #include <stddef.h>
  4. #include <memory>
  5. #include <limits>
  6. #include <algorithm>
  7. /* Minimum alignment required by posix_memalign. */
  8. #define DEF_ALIGN sizeof(void*)
  9. void *al_malloc(size_t alignment, size_t size);
  10. void *al_calloc(size_t alignment, size_t size);
  11. void al_free(void *ptr) noexcept;
  12. size_t al_get_page_size(void) noexcept;
  13. /**
  14. * Returns non-0 if the allocation function has direct alignment handling.
  15. * Otherwise, the standard malloc is used with an over-allocation and pointer
  16. * offset strategy.
  17. */
  18. int al_is_sane_alignment_allocator(void) noexcept;
  19. #define DEF_NEWDEL(T) \
  20. void *operator new(size_t size) \
  21. { \
  22. void *ret = al_malloc(alignof(T), size); \
  23. if(!ret) throw std::bad_alloc(); \
  24. return ret; \
  25. } \
  26. void operator delete(void *block) noexcept { al_free(block); }
  27. #define DEF_PLACE_NEWDEL() \
  28. void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
  29. void operator delete(void *block) noexcept { al_free(block); } \
  30. void operator delete(void* /*block*/, void* /*ptr*/) noexcept { }
  31. namespace al {
  32. template<typename T, size_t alignment=DEF_ALIGN>
  33. struct allocator : public std::allocator<T> {
  34. using size_type = size_t;
  35. using pointer = T*;
  36. using const_pointer = const T*;
  37. template<typename U>
  38. struct rebind {
  39. using other = allocator<U, alignment>;
  40. };
  41. pointer allocate(size_type n, const void* = nullptr)
  42. {
  43. if(n > std::numeric_limits<size_t>::max() / sizeof(T))
  44. throw std::bad_alloc();
  45. void *ret{al_malloc(alignment, n*sizeof(T))};
  46. if(!ret) throw std::bad_alloc();
  47. return static_cast<pointer>(ret);
  48. }
  49. void deallocate(pointer p, size_type)
  50. { al_free(p); }
  51. allocator() : std::allocator<T>() { }
  52. allocator(const allocator &a) : std::allocator<T>(a) { }
  53. template<class U>
  54. allocator(const allocator<U,alignment> &a) : std::allocator<T>(a)
  55. { }
  56. };
  57. template<size_t alignment, typename T>
  58. inline T* assume_aligned(T *ptr) noexcept
  59. {
  60. static_assert((alignment & (alignment-1)) == 0, "alignment must be a power of 2");
  61. #ifdef __GNUC__
  62. return static_cast<T*>(__builtin_assume_aligned(ptr, alignment));
  63. #elif defined(_MSC_VER)
  64. auto ptrval = reinterpret_cast<uintptr_t>(ptr);
  65. if((ptrval&(alignment-1)) != 0) __assume(0);
  66. return reinterpret_cast<T*>(ptrval);
  67. #else
  68. return ptr;
  69. #endif
  70. }
  71. /* std::make_unique was added with C++14, so until we rely on that, make our
  72. * own version.
  73. */
  74. template<typename T, typename ...ArgsT>
  75. std::unique_ptr<T> make_unique(ArgsT&&...args)
  76. { return std::unique_ptr<T>{new T{std::forward<ArgsT>(args)...}}; }
  77. /* A flexible array type. Used either standalone or at the end of a parent
  78. * struct, with placement new, to have a run-time-sized array that's embedded
  79. * with its size.
  80. */
  81. template<typename T,size_t alignment=DEF_ALIGN>
  82. struct FlexArray {
  83. const size_t mSize;
  84. alignas(alignment) T mArray[];
  85. static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
  86. {
  87. return base +
  88. std::max<size_t>(offsetof(FlexArray, mArray) + sizeof(T)*count, sizeof(FlexArray));
  89. }
  90. FlexArray(size_t size) : mSize{size}
  91. { new (mArray) T[mSize]; }
  92. ~FlexArray()
  93. {
  94. for(size_t i{0u};i < mSize;++i)
  95. mArray[i].~T();
  96. }
  97. FlexArray(const FlexArray&) = delete;
  98. FlexArray& operator=(const FlexArray&) = delete;
  99. size_t size() const noexcept { return mSize; }
  100. T *data() noexcept { return mArray; }
  101. const T *data() const noexcept { return mArray; }
  102. T& operator[](size_t i) noexcept { return mArray[i]; }
  103. const T& operator[](size_t i) const noexcept { return mArray[i]; }
  104. T& front() noexcept { return mArray[0]; }
  105. const T& front() const noexcept { return mArray[0]; }
  106. T& back() noexcept { return mArray[mSize-1]; }
  107. const T& back() const noexcept { return mArray[mSize-1]; }
  108. T *begin() noexcept { return mArray; }
  109. const T *begin() const noexcept { return mArray; }
  110. const T *cbegin() const noexcept { return mArray; }
  111. T *end() noexcept { return mArray + mSize; }
  112. const T *end() const noexcept { return mArray + mSize; }
  113. const T *cend() const noexcept { return mArray + mSize; }
  114. DEF_PLACE_NEWDEL()
  115. };
  116. } // namespace al
  117. #endif /* AL_MALLOC_H */