almalloc.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #ifndef AL_MALLOC_H
  2. #define AL_MALLOC_H
  3. #include <algorithm>
  4. #include <cstddef>
  5. #include <limits>
  6. #include <new>
  7. #include <type_traits>
  8. #include <utility>
  9. #include <variant>
  10. namespace gsl {
  11. template<typename T> using owner = T;
  12. }
  13. #define DISABLE_ALLOC \
  14. void *operator new(size_t) = delete; \
  15. void *operator new[](size_t) = delete; \
  16. void operator delete(void*) noexcept = delete; \
  17. void operator delete[](void*) noexcept = delete;
  18. enum FamCount : size_t { };
  19. #define DEF_FAM_NEWDEL(T, FamMem) \
  20. static constexpr size_t Sizeof(size_t count) noexcept \
  21. { \
  22. static_assert(&Sizeof == &T::Sizeof, \
  23. "Incorrect container type specified"); \
  24. return std::max(decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)), \
  25. sizeof(T)); \
  26. } \
  27. \
  28. gsl::owner<void*> operator new(size_t /*size*/, FamCount count) \
  29. { \
  30. const auto alignment = std::align_val_t{alignof(T)}; \
  31. return ::operator new[](T::Sizeof(count), alignment); \
  32. } \
  33. void operator delete(gsl::owner<void*> block, FamCount) noexcept \
  34. { ::operator delete[](block, std::align_val_t{alignof(T)}); } \
  35. void operator delete(gsl::owner<void*> block) noexcept \
  36. { ::operator delete[](block, std::align_val_t{alignof(T)}); } \
  37. void *operator new[](size_t /*size*/) = delete; \
  38. void operator delete[](void* /*block*/) = delete;
  39. namespace al {
  40. template<typename T, std::size_t AlignV=alignof(T)>
  41. struct allocator {
  42. static constexpr auto Alignment = std::max(AlignV, alignof(T));
  43. static constexpr auto AlignVal = std::align_val_t{Alignment};
  44. using value_type = std::remove_cv_t<std::remove_reference_t<T>>;
  45. using reference = value_type&;
  46. using const_reference = const value_type&;
  47. using pointer = value_type*;
  48. using const_pointer = const value_type*;
  49. using size_type = std::size_t;
  50. using difference_type = std::ptrdiff_t;
  51. using is_always_equal = std::true_type;
  52. template<typename U, std::enable_if_t<alignof(U) <= Alignment,bool> = true>
  53. struct rebind {
  54. using other = allocator<U,Alignment>;
  55. };
  56. constexpr explicit allocator() noexcept = default;
  57. template<typename U, std::size_t N>
  58. constexpr explicit allocator(const allocator<U,N>&) noexcept
  59. { static_assert(Alignment == allocator<U,N>::Alignment); }
  60. gsl::owner<T*> allocate(std::size_t n)
  61. {
  62. if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
  63. return static_cast<gsl::owner<T*>>(::operator new[](n*sizeof(T), AlignVal));
  64. }
  65. void deallocate(gsl::owner<T*> p, std::size_t) noexcept
  66. { ::operator delete[](gsl::owner<void*>{p}, AlignVal); }
  67. };
  68. template<typename T, std::size_t N, typename U, std::size_t M>
  69. constexpr bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept
  70. { return allocator<T,N>::Alignment == allocator<U,M>::Alignment; }
  71. template<typename T, std::size_t N, typename U, std::size_t M>
  72. constexpr bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept
  73. { return allocator<T,N>::Alignment != allocator<U,M>::Alignment; }
  74. #ifdef __cpp_lib_to_address
  75. using std::to_address;
  76. #else
  77. template<typename T>
  78. constexpr T *to_address(T *p) noexcept
  79. {
  80. static_assert(!std::is_function<T>::value, "Can't be a function type");
  81. return p;
  82. }
  83. template<typename T>
  84. constexpr auto to_address(const T &p) noexcept
  85. {
  86. return ::al::to_address(p.operator->());
  87. }
  88. #endif
  89. template<typename T, typename ...Args>
  90. constexpr T* construct_at(T *ptr, Args&& ...args)
  91. noexcept(std::is_nothrow_constructible_v<T, Args...>)
  92. {
  93. /* NOLINTBEGIN(cppcoreguidelines-owning-memory) construct_at doesn't
  94. * necessarily handle the address from an owner, while placement new
  95. * expects to.
  96. */
  97. return ::new(static_cast<void*>(ptr)) T{std::forward<Args>(args)...};
  98. /* NOLINTEND(cppcoreguidelines-owning-memory) */
  99. }
  100. template<typename SP, typename PT, typename ...Args>
  101. class out_ptr_t {
  102. static_assert(!std::is_same_v<PT,void*>);
  103. SP &mRes;
  104. std::variant<PT,void*> mPtr{};
  105. public:
  106. out_ptr_t(SP &res) : mRes{res} { }
  107. ~out_ptr_t()
  108. {
  109. auto set_res = [this](auto &ptr)
  110. { mRes.reset(static_cast<PT>(ptr)); };
  111. std::visit(set_res, mPtr);
  112. }
  113. out_ptr_t(const out_ptr_t&) = delete;
  114. out_ptr_t& operator=(const out_ptr_t&) = delete;
  115. operator PT*() noexcept
  116. { return &std::get<PT>(mPtr); }
  117. operator void**() noexcept
  118. { return &mPtr.template emplace<void*>(); }
  119. };
  120. template<typename T=void, typename SP, typename ...Args>
  121. auto out_ptr(SP &res)
  122. {
  123. using ptype = typename SP::element_type*;
  124. return out_ptr_t<SP,ptype>{res};
  125. }
  126. } // namespace al
  127. #endif /* AL_MALLOC_H */