Enable proper full C++ exception handling on MSVC
[openal-soft.git] / common / almalloc.h
blobe3a7bb5217a82e2e6a067b9ff98090d620e93cb8
1 #ifndef AL_MALLOC_H
2 #define AL_MALLOC_H
4 #include <algorithm>
5 #include <cstddef>
6 #include <limits>
7 #include <new>
8 #include <type_traits>
9 #include <utility>
10 #include <variant>
13 namespace gsl {
14 template<typename T> using owner = T;
18 #define DISABLE_ALLOC \
19 void *operator new(size_t) = delete; \
20 void *operator new[](size_t) = delete; \
21 void operator delete(void*) noexcept = delete; \
22 void operator delete[](void*) noexcept = delete;
25 enum FamCount : size_t { };
27 #define DEF_FAM_NEWDEL(T, FamMem) \
28 static constexpr size_t Sizeof(size_t count) noexcept \
29 { \
30 static_assert(&Sizeof == &T::Sizeof, \
31 "Incorrect container type specified"); \
32 return std::max(decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)), \
33 sizeof(T)); \
34 } \
36 gsl::owner<void*> operator new(size_t /*size*/, FamCount count) \
37 { \
38 const auto alignment = std::align_val_t{alignof(T)}; \
39 return ::operator new[](T::Sizeof(count), alignment); \
40 } \
41 void operator delete(gsl::owner<void*> block, FamCount) noexcept \
42 { ::operator delete[](block, std::align_val_t{alignof(T)}); } \
43 void operator delete(gsl::owner<void*> block) noexcept \
44 { ::operator delete[](block, std::align_val_t{alignof(T)}); } \
45 void *operator new[](size_t /*size*/) = delete; \
46 void operator delete[](void* /*block*/) = delete;
49 namespace al {
51 template<typename T, std::size_t AlignV=alignof(T)>
52 struct allocator {
53 static constexpr auto Alignment = std::max(AlignV, alignof(T));
54 static constexpr auto AlignVal = std::align_val_t{Alignment};
56 using value_type = std::remove_cv_t<std::remove_reference_t<T>>;
57 using reference = value_type&;
58 using const_reference = const value_type&;
59 using pointer = value_type*;
60 using const_pointer = const value_type*;
61 using size_type = std::size_t;
62 using difference_type = std::ptrdiff_t;
63 using is_always_equal = std::true_type;
65 template<typename U, std::enable_if_t<alignof(U) <= Alignment,bool> = true>
66 struct rebind {
67 using other = allocator<U,Alignment>;
70 constexpr explicit allocator() noexcept = default;
71 template<typename U, std::size_t N>
72 constexpr explicit allocator(const allocator<U,N>&) noexcept
73 { static_assert(Alignment == allocator<U,N>::Alignment); }
75 gsl::owner<T*> allocate(std::size_t n)
77 if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
78 return static_cast<gsl::owner<T*>>(::operator new[](n*sizeof(T), AlignVal));
80 void deallocate(gsl::owner<T*> p, std::size_t) noexcept
81 { ::operator delete[](gsl::owner<void*>{p}, AlignVal); }
83 template<typename T, std::size_t N, typename U, std::size_t M>
84 constexpr bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept
85 { return allocator<T,N>::Alignment == allocator<U,M>::Alignment; }
86 template<typename T, std::size_t N, typename U, std::size_t M>
87 constexpr bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept
88 { return allocator<T,N>::Alignment != allocator<U,M>::Alignment; }
91 #ifdef __cpp_lib_to_address
92 using std::to_address;
93 #else
94 template<typename T>
95 constexpr T *to_address(T *p) noexcept
97 static_assert(!std::is_function<T>::value, "Can't be a function type");
98 return p;
101 template<typename T>
102 constexpr auto to_address(const T &p) noexcept
104 return ::al::to_address(p.operator->());
106 #endif
108 template<typename T, typename ...Args>
109 constexpr T* construct_at(T *ptr, Args&& ...args)
110 noexcept(std::is_nothrow_constructible_v<T, Args...>)
112 /* NOLINTBEGIN(cppcoreguidelines-owning-memory) construct_at doesn't
113 * necessarily handle the address from an owner, while placement new
114 * expects to.
116 return ::new(static_cast<void*>(ptr)) T{std::forward<Args>(args)...};
117 /* NOLINTEND(cppcoreguidelines-owning-memory) */
121 template<typename SP, typename PT, typename ...Args>
122 class out_ptr_t {
123 static_assert(!std::is_same_v<PT,void*>);
125 SP &mRes;
126 std::variant<PT,void*> mPtr{};
128 public:
129 out_ptr_t(SP &res) : mRes{res} { }
130 ~out_ptr_t()
132 auto set_res = [this](auto &ptr)
133 { mRes.reset(static_cast<PT>(ptr)); };
134 std::visit(set_res, mPtr);
136 out_ptr_t(const out_ptr_t&) = delete;
137 out_ptr_t& operator=(const out_ptr_t&) = delete;
139 operator PT*() noexcept
140 { return &std::get<PT>(mPtr); }
142 operator void**() noexcept
143 { return &mPtr.template emplace<void*>(); }
146 template<typename T=void, typename SP, typename ...Args>
147 auto out_ptr(SP &res)
149 using ptype = typename SP::element_type*;
150 return out_ptr_t<SP,ptype>{res};
153 } // namespace al
155 #endif /* AL_MALLOC_H */