10 #include <type_traits>
15 #define DIAGNOSTIC_PUSH __pragma(warning(push))
16 #define GNUDIAGNOSTIC(x)
17 #define MVSDIAGNOSTIC(...) __pragma(__VA_ARGS__)
18 #define DIAGNOSTIC_POP __pragma(warning(pop))
19 #elif defined(__GNUC__) || defined(__clang__)
20 #define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
21 #define GNUDIAGNOSTIC(x) _Pragma(x)
22 #define MVSDIAGNOSTIC(...)
23 #define DIAGNOSTIC_POP _Pragma("GCC diagnostic push")
25 #define DIAGNOSTIC_PUSH
26 #define GNUDIAGNOSTIC(x)
27 #define MVSDIAGNOSTIC(...)
28 #define DIAGNOSTIC_POP
31 void *al_malloc(size_t alignment
, size_t size
);
32 void *al_calloc(size_t alignment
, size_t size
);
33 void al_free(void *ptr
) noexcept
;
36 #define DEF_NEWDEL(T) \
37 void *operator new(size_t size) \
39 void *ret = al_malloc(alignof(T), size); \
40 if(!ret) throw std::bad_alloc(); \
43 void operator delete(void *block) noexcept { al_free(block); }
45 #define DEF_PLACE_NEWDEL() \
46 void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
47 void operator delete(void *block, void*) noexcept { al_free(block); } \
48 void operator delete(void *block) noexcept { al_free(block); }
50 struct FamCount
{ size_t mCount
; };
52 #define DEF_FAM_NEWDEL(T, FamMem) \
53 static constexpr size_t Sizeof(size_t count) noexcept \
54 { return decltype(FamMem)::Sizeof(count, offsetof(T, FamMem)); } \
56 void *operator new(size_t /*size*/, FamCount fam) \
58 if(void *ret{al_malloc(alignof(T), T::Sizeof(fam.mCount))}) \
60 throw std::bad_alloc(); \
62 void operator delete(void *block, FamCount) { al_free(block); } \
63 void operator delete(void *block) noexcept { al_free(block); }
68 #define REQUIRES(...) typename std::enable_if<(__VA_ARGS__),int>::type = 0
70 template<typename T
, std::size_t alignment
=alignof(T
)>
74 using const_reference
= const T
&;
76 using const_pointer
= const T
*;
77 using size_type
= std::size_t;
78 using difference_type
= std::ptrdiff_t;
79 using is_always_equal
= std::true_type
;
83 using other
= allocator
<U
, (alignment
<alignof(U
))?alignof(U
):alignment
>;
86 allocator() = default;
87 template<typename U
, std::size_t N
>
88 constexpr allocator(const allocator
<U
,N
>&) noexcept
{ }
90 T
*allocate(std::size_t n
)
92 if(n
> std::numeric_limits
<std::size_t>::max()/sizeof(T
)) throw std::bad_alloc();
93 if(auto p
= static_cast<T
*>(al_malloc(alignment
, n
*sizeof(T
)))) return p
;
94 throw std::bad_alloc();
96 void deallocate(T
*p
, std::size_t) noexcept
{ al_free(p
); }
98 template<typename T
, std::size_t N
, typename U
, std::size_t M
>
99 bool operator==(const allocator
<T
,N
>&, const allocator
<U
,M
>&) noexcept
{ return true; }
100 template<typename T
, std::size_t N
, typename U
, std::size_t M
>
101 bool operator!=(const allocator
<T
,N
>&, const allocator
<U
,M
>&) noexcept
{ return false; }
103 template<size_t alignment
, typename T
>
104 inline T
* assume_aligned(T
*ptr
) noexcept
106 static_assert((alignment
& (alignment
-1)) == 0, "alignment must be a power of 2");
108 return static_cast<T
*>(__builtin_assume_aligned(ptr
, alignment
));
109 #elif defined(_MSC_VER)
110 auto ptrval
= reinterpret_cast<uintptr_t>(ptr
);
111 if((ptrval
&(alignment
-1)) != 0) __assume(0);
112 return reinterpret_cast<T
*>(ptrval
);
118 /* At least VS 2015 complains that 'ptr' is unused when the given type's
119 * destructor is trivial (a no-op). So disable that warning for this call.
122 MVSDIAGNOSTIC(warning(disable
: 4100))
124 inline void destroy_at(T
*ptr
) { ptr
->~T(); }
128 inline void destroy(T first
, const T end
)
132 al::destroy_at(std::addressof(*first
));
137 template<typename T
, typename N
, REQUIRES(std::is_integral
<N
>::value
)>
138 inline T
destroy_n(T first
, N count
)
143 al::destroy_at(std::addressof(*first
));
152 inline void uninitialized_default_construct(T first
, const T last
)
154 using ValueT
= typename
std::iterator_traits
<T
>::value_type
;
157 while(current
!= last
)
159 ::new (static_cast<void*>(std::addressof(*current
))) ValueT
;
164 destroy(first
, current
);
169 template<typename T
, typename N
, REQUIRES(std::is_integral
<N
>::value
)>
170 inline T
uninitialized_default_construct_n(T first
, N count
)
172 using ValueT
= typename
std::iterator_traits
<T
>::value_type
;
178 ::new (static_cast<void*>(std::addressof(*current
))) ValueT
;
183 destroy(first
, current
);
191 template<typename T0
, typename T1
>
192 inline T1
uninitialized_move(T0 first
, const T0 last
, const T1 output
)
194 using ValueT
= typename
std::iterator_traits
<T1
>::value_type
;
199 ::new (static_cast<void*>(std::addressof(*current
))) ValueT
{std::move(*first
)};
205 destroy(output
, current
);
211 template<typename T0
, typename N
, typename T1
, REQUIRES(std::is_integral
<N
>::value
)>
212 inline T1
uninitialized_move_n(T0 first
, N count
, const T1 output
)
214 using ValueT
= typename
std::iterator_traits
<T1
>::value_type
;
220 ::new (static_cast<void*>(std::addressof(*current
))) ValueT
{std::move(*first
)};
226 destroy(output
, current
);
234 /* std::make_unique was added with C++14, so until we rely on that, make our
237 template<typename T
, typename
...ArgsT
>
238 std::unique_ptr
<T
> make_unique(ArgsT
&&...args
)
239 { return std::unique_ptr
<T
>{new T
{std::forward
<ArgsT
>(args
)...}}; }
242 /* A flexible array type. Used either standalone or at the end of a parent
243 * struct, with placement new, to have a run-time-sized array that's embedded
246 template<typename T
, size_t alignment
=alignof(T
)>
248 using element_type
= T
;
249 using value_type
= typename
std::remove_cv
<T
>::type
;
250 using index_type
= size_t;
251 using difference_type
= ptrdiff_t;
254 using const_pointer
= const T
*;
255 using reference
= T
&;
256 using const_reference
= const T
&;
258 using iterator
= pointer
;
259 using const_iterator
= const_pointer
;
260 using reverse_iterator
= std::reverse_iterator
<iterator
>;
261 using const_reverse_iterator
= std::reverse_iterator
<const_iterator
>;
264 const index_type mSize
;
266 GNUDIAGNOSTIC("GCC diagnostic ignored \"-Wpedantic\"")
267 MVSDIAGNOSTIC(warning(disable
: 4200))
268 alignas(alignment
) element_type mArray
[0];
271 static std::unique_ptr
<FlexArray
> Create(index_type count
)
273 void *ptr
{al_calloc(alignof(FlexArray
), Sizeof(count
))};
274 return std::unique_ptr
<FlexArray
>{new (ptr
) FlexArray
{count
}};
276 static constexpr index_type
Sizeof(index_type count
, index_type base
=0u) noexcept
279 std::max
<index_type
>(offsetof(FlexArray
, mArray
) + sizeof(T
)*count
, sizeof(FlexArray
));
282 FlexArray(index_type size
) : mSize
{size
}
283 { uninitialized_default_construct_n(mArray
, mSize
); }
284 ~FlexArray() { destroy_n(mArray
, mSize
); }
286 FlexArray(const FlexArray
&) = delete;
287 FlexArray
& operator=(const FlexArray
&) = delete;
289 index_type
size() const noexcept
{ return mSize
; }
290 bool empty() const noexcept
{ return mSize
== 0; }
292 pointer
data() noexcept
{ return mArray
; }
293 const_pointer
data() const noexcept
{ return mArray
; }
295 reference
operator[](index_type i
) noexcept
{ return mArray
[i
]; }
296 const_reference
operator[](index_type i
) const noexcept
{ return mArray
[i
]; }
298 reference
front() noexcept
{ return mArray
[0]; }
299 const_reference
front() const noexcept
{ return mArray
[0]; }
301 reference
back() noexcept
{ return mArray
[mSize
-1]; }
302 const_reference
back() const noexcept
{ return mArray
[mSize
-1]; }
304 iterator
begin() noexcept
{ return mArray
; }
305 const_iterator
begin() const noexcept
{ return mArray
; }
306 const_iterator
cbegin() const noexcept
{ return mArray
; }
307 iterator
end() noexcept
{ return mArray
+ mSize
; }
308 const_iterator
end() const noexcept
{ return mArray
+ mSize
; }
309 const_iterator
cend() const noexcept
{ return mArray
+ mSize
; }
311 reverse_iterator
rbegin() noexcept
{ return end(); }
312 const_reverse_iterator
rbegin() const noexcept
{ return end(); }
313 const_reverse_iterator
crbegin() const noexcept
{ return cend(); }
314 reverse_iterator
rend() noexcept
{ return begin(); }
315 const_reverse_iterator
rend() const noexcept
{ return begin(); }
316 const_reverse_iterator
crend() const noexcept
{ return cbegin(); }
325 #endif /* AL_MALLOC_H */