10 #include <type_traits>
13 #include "pragmadefs.h"
16 void al_free(void *ptr
) noexcept
;
17 [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc
]]
18 void *al_malloc(size_t alignment
, size_t size
);
19 [[gnu::alloc_align(1), gnu::alloc_size(2), gnu::malloc
]]
20 void *al_calloc(size_t alignment
, size_t size
);
23 #define DISABLE_ALLOC() \
24 void *operator new(size_t) = delete; \
25 void *operator new[](size_t) = delete; \
26 void operator delete(void*) noexcept = delete; \
27 void operator delete[](void*) noexcept = delete;
29 #define DEF_NEWDEL(T) \
30 void *operator new(size_t size) \
32 static_assert(&operator new == &T::operator new, \
33 "Incorrect container type specified"); \
34 if(void *ret{al_malloc(alignof(T), size)}) \
36 throw std::bad_alloc(); \
38 void *operator new[](size_t size) { return operator new(size); } \
39 void operator delete(void *block) noexcept { al_free(block); } \
40 void operator delete[](void *block) noexcept { operator delete(block); }
42 #define DEF_PLACE_NEWDEL() \
43 void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
44 void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
45 void operator delete(void *block, void*) noexcept { al_free(block); } \
46 void operator delete(void *block) noexcept { al_free(block); } \
47 void operator delete[](void *block, void*) noexcept { al_free(block); } \
48 void operator delete[](void *block) noexcept { al_free(block); }
50 enum FamCount
: size_t { };
52 #define DEF_FAM_NEWDEL(T, FamMem) \
53 static constexpr size_t Sizeof(size_t count) noexcept \
55 static_assert(&Sizeof == &T::Sizeof, \
56 "Incorrect container type specified"); \
57 return std::max(decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)), \
61 void *operator new(size_t /*size*/, FamCount count) \
63 if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
65 throw std::bad_alloc(); \
67 void *operator new[](size_t /*size*/) = delete; \
68 void operator delete(void *block, FamCount) { al_free(block); } \
69 void operator delete(void *block) noexcept { al_free(block); } \
70 void operator delete[](void* /*block*/) = delete;
75 template<typename T
, std::size_t alignment
=alignof(T
)>
79 using const_reference
= const T
&;
81 using const_pointer
= const T
*;
82 using size_type
= std::size_t;
83 using difference_type
= std::ptrdiff_t;
84 using is_always_equal
= std::true_type
;
88 using other
= allocator
<U
, (alignment
<alignof(U
))?alignof(U
):alignment
>;
91 constexpr explicit allocator() noexcept
= default;
92 template<typename U
, std::size_t N
>
93 constexpr explicit allocator(const allocator
<U
,N
>&) noexcept
{ }
95 T
*allocate(std::size_t n
)
97 if(n
> std::numeric_limits
<std::size_t>::max()/sizeof(T
)) throw std::bad_alloc();
98 if(auto p
= al_malloc(alignment
, n
*sizeof(T
))) return static_cast<T
*>(p
);
99 throw std::bad_alloc();
101 void deallocate(T
*p
, std::size_t) noexcept
{ al_free(p
); }
103 template<typename T
, std::size_t N
, typename U
, std::size_t M
>
104 constexpr bool operator==(const allocator
<T
,N
>&, const allocator
<U
,M
>&) noexcept
{ return true; }
105 template<typename T
, std::size_t N
, typename U
, std::size_t M
>
106 constexpr bool operator!=(const allocator
<T
,N
>&, const allocator
<U
,M
>&) noexcept
{ return false; }
110 constexpr T
*to_address(T
*p
) noexcept
112 static_assert(!std::is_function
<T
>::value
, "Can't be a function type");
117 constexpr auto to_address(const T
& p
) noexcept
118 { return to_address(p
.operator->()); }
121 template<typename T
, typename
...Args
>
122 constexpr T
* construct_at(T
*ptr
, Args
&& ...args
)
123 noexcept(std::is_nothrow_constructible
<T
, Args
...>::value
)
124 { return ::new(static_cast<void*>(ptr
)) T
{std::forward
<Args
>(args
)...}; }
126 /* At least VS 2015 complains that 'ptr' is unused when the given type's
127 * destructor is trivial (a no-op). So disable that warning for this call.
130 msc_pragma(warning(disable
: 4100))
132 constexpr std::enable_if_t
<!std::is_array
<T
>::value
>
133 destroy_at(T
*ptr
) noexcept(std::is_nothrow_destructible
<T
>::value
)
137 constexpr std::enable_if_t
<std::is_array
<T
>::value
>
138 destroy_at(T
*ptr
) noexcept(std::is_nothrow_destructible
<std::remove_all_extents_t
<T
>>::value
)
140 for(auto &elem
: *ptr
)
141 al::destroy_at(std::addressof(elem
));
145 constexpr void destroy(T first
, T end
) noexcept(noexcept(al::destroy_at(std::addressof(*first
))))
149 al::destroy_at(std::addressof(*first
));
154 template<typename T
, typename N
>
155 constexpr std::enable_if_t
<std::is_integral
<N
>::value
,T
>
156 destroy_n(T first
, N count
) noexcept(noexcept(al::destroy_at(std::addressof(*first
))))
161 al::destroy_at(std::addressof(*first
));
169 template<typename T
, typename N
>
170 inline std::enable_if_t
<std::is_integral
<N
>::value
,
171 T
> uninitialized_default_construct_n(T first
, N count
)
173 using ValueT
= typename
std::iterator_traits
<T
>::value_type
;
179 ::new(static_cast<void*>(std::addressof(*current
))) ValueT
;
184 al::destroy(first
, current
);
192 /* Storage for flexible array data. This is trivially destructible if type T is
193 * trivially destructible.
195 template<typename T
, size_t alignment
, bool = std::is_trivially_destructible
<T
>::value
>
196 struct FlexArrayStorage
{
200 alignas(alignment
) T mArray
[1];
203 static constexpr size_t Sizeof(size_t count
, size_t base
=0u) noexcept
205 const size_t len
{sizeof(T
)*count
};
206 return std::max(offsetof(FlexArrayStorage
,mArray
)+len
, sizeof(FlexArrayStorage
)) + base
;
209 FlexArrayStorage(size_t size
) : mSize
{size
}
210 { al::uninitialized_default_construct_n(mArray
, mSize
); }
211 ~FlexArrayStorage() = default;
213 FlexArrayStorage(const FlexArrayStorage
&) = delete;
214 FlexArrayStorage
& operator=(const FlexArrayStorage
&) = delete;
217 template<typename T
, size_t alignment
>
218 struct FlexArrayStorage
<T
,alignment
,false> {
222 alignas(alignment
) T mArray
[1];
225 static constexpr size_t Sizeof(size_t count
, size_t base
) noexcept
227 const size_t len
{sizeof(T
)*count
};
228 return std::max(offsetof(FlexArrayStorage
,mArray
)+len
, sizeof(FlexArrayStorage
)) + base
;
231 FlexArrayStorage(size_t size
) : mSize
{size
}
232 { al::uninitialized_default_construct_n(mArray
, mSize
); }
233 ~FlexArrayStorage() { al::destroy_n(mArray
, mSize
); }
235 FlexArrayStorage(const FlexArrayStorage
&) = delete;
236 FlexArrayStorage
& operator=(const FlexArrayStorage
&) = delete;
239 /* A flexible array type. Used either standalone or at the end of a parent
240 * struct, with placement new, to have a run-time-sized array that's embedded
243 template<typename T
, size_t alignment
=alignof(T
)>
245 using element_type
= T
;
246 using value_type
= std::remove_cv_t
<T
>;
247 using index_type
= size_t;
248 using difference_type
= ptrdiff_t;
251 using const_pointer
= const T
*;
252 using reference
= T
&;
253 using const_reference
= const T
&;
255 using iterator
= pointer
;
256 using const_iterator
= const_pointer
;
257 using reverse_iterator
= std::reverse_iterator
<iterator
>;
258 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
260 using Storage_t_
= FlexArrayStorage
<element_type
,alignment
>;
264 static constexpr index_type
Sizeof(index_type count
, index_type base
=0u) noexcept
265 { return Storage_t_::Sizeof(count
, base
); }
266 static std::unique_ptr
<FlexArray
> Create(index_type count
)
268 void *ptr
{al_calloc(alignof(FlexArray
), Sizeof(count
))};
269 return std::unique_ptr
<FlexArray
>{al::construct_at(static_cast<FlexArray
*>(ptr
), count
)};
272 FlexArray(index_type size
) : mStore
{size
} { }
273 ~FlexArray() = default;
275 index_type
size() const noexcept
{ return mStore
.mSize
; }
276 bool empty() const noexcept
{ return mStore
.mSize
== 0; }
278 pointer
data() noexcept
{ return mStore
.mArray
; }
279 const_pointer
data() const noexcept
{ return mStore
.mArray
; }
281 reference
operator[](index_type i
) noexcept
{ return mStore
.mArray
[i
]; }
282 const_reference
operator[](index_type i
) const noexcept
{ return mStore
.mArray
[i
]; }
284 reference
front() noexcept
{ return mStore
.mArray
[0]; }
285 const_reference
front() const noexcept
{ return mStore
.mArray
[0]; }
287 reference
back() noexcept
{ return mStore
.mArray
[mStore
.mSize
-1]; }
288 const_reference
back() const noexcept
{ return mStore
.mArray
[mStore
.mSize
-1]; }
290 iterator
begin() noexcept
{ return mStore
.mArray
; }
291 const_iterator
begin() const noexcept
{ return mStore
.mArray
; }
292 const_iterator
cbegin() const noexcept
{ return mStore
.mArray
; }
293 iterator
end() noexcept
{ return mStore
.mArray
+ mStore
.mSize
; }
294 const_iterator
end() const noexcept
{ return mStore
.mArray
+ mStore
.mSize
; }
295 const_iterator
cend() const noexcept
{ return mStore
.mArray
+ mStore
.mSize
; }
297 reverse_iterator
rbegin() noexcept
{ return end(); }
298 const_reverse_iterator
rbegin() const noexcept
{ return end(); }
299 const_reverse_iterator
crbegin() const noexcept
{ return cend(); }
300 reverse_iterator
rend() noexcept
{ return begin(); }
301 const_reverse_iterator
rend() const noexcept
{ return begin(); }
302 const_reverse_iterator
crend() const noexcept
{ return cbegin(); }
309 #endif /* AL_MALLOC_H */