fennec
Loading...
Searching...
No Matches
allocator.h
Go to the documentation of this file.
1// =====================================================================================================================
2// fennec, a free and open source game engine
3// Copyright © 2025 Medusa Slockbower
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17// =====================================================================================================================
18
30
31
32#ifndef FENNEC_MEMORY_ALLOCATOR_H
33#define FENNEC_MEMORY_ALLOCATOR_H
34
35#include <fennec/memory/pointer_traits.h>
36#include <fennec/memory/new.h>
37
40#include <fennec/lang/types.h>
42
44#include <fennec/math/common.h>
45
46
47#ifdef FENNEC_COMPILER_GCC
48#pragma GCC diagnostic push
49#pragma GCC diagnostic ignored "-Wchanges-meaning"
50#endif
51
52
53namespace fennec
54{
55
59template<class Alloc>
61{
62private:
63 // These help with using concepts in `detect_t`
64 template<typename ClassT> using _pointer = typename ClassT::pointer_t;
65 template<typename ClassT> using _const_pointer = typename ClassT::const_pointer_t;
66 template<typename ClassT> using _void_pointer = typename ClassT::void_pointer_t;
67 template<typename ClassT> using _void_const_pointer = typename ClassT::void_const_pointer_t;
68
69 // Propagation Patterns
70 template<typename ClassT> using _propagate_on_containter_copy_assignment = typename ClassT::propagate_on_containter_copy_assignment;
71 template<typename ClassT> using _propagate_on_containter_move_assignment = typename ClassT::propagate_on_containter_move_assignment;
72 template<typename ClassT> using _propagate_on_containter_swap = typename ClassT::propagate_on_containter_swap;
73
74 template<typename ClassT> using _is_always_equal = typename ClassT::is_always_equal;
75
76 template<typename AllocT, typename TypeT>
77 struct _rebind : replace_first_element<AllocT, TypeT> {};
78
79 template<typename AllocT, typename TypeT>
80 requires requires { typename AllocT::template rebind<TypeT>::other; }
81 struct _rebind<AllocT, TypeT> { using type = typename AllocT::template rebind<TypeT>::other; };
82
83 // This detects AllocT::diff_t if present, otherwise uses the diff_t associated with PtrT
84 // It works using SFINAE, 'typename = void' forces the second _diff to be evaluated first when
85 // _diff is substituted using only two template arguments. That one uses 'type = typename AllocT::diff_t'
86 // however, if it fails, the compiler moves on to the original definition. _size works in the same manner.
87 template<typename AllocT, typename PtrT, typename = void>
88 struct _diff { using type = typename pointer_traits<PtrT>::diff_t; };
89
90 template<typename AllocT, typename PtrT>
91 struct _diff<AllocT, PtrT, void_t<typename AllocT::diff_t>> { using type = typename AllocT::diff_t; };
92
93 template<typename AllocT, typename DiffT, typename = void>
94 struct _size : make_unsigned<DiffT> {};
95
96 template<typename AllocT, typename DiffT>
97 struct _size<AllocT, DiffT, void_t<typename AllocT::size_t>> { using type = typename AllocT::size_t; };
98
99public:
100
102 using alloc_t = Alloc;
103
105 using value_t = typename Alloc::value_t;
106
109
112
115
118
120 using diff_t = typename _diff<Alloc, pointer_t>::type;
121
123 using size_t = typename _size<Alloc, pointer_t>::type;
124
125 // TODO: Document propagation
126 using propagate_on_container_copy_assignment = detect_t<false_type, _propagate_on_containter_copy_assignment, Alloc>;
127 using propagate_on_container_move_assignment = detect_t<false_type, _propagate_on_containter_move_assignment, Alloc>;
128 using propagate_on_container_swap = detect_t<false_type, _propagate_on_containter_swap, Alloc>;
129
132
134 template<typename TypeT> using rebind = typename _rebind<Alloc, TypeT>::type;
135
136 // TODO: allocator_traits static functions
137};
138
139
143template<typename T>
145{
146public:
148 using value_t = T;
149
151 template<typename R> using rebind = allocator<R>;
152
154 constexpr allocator() = default;
155
157 constexpr ~allocator() = default;
158
160 constexpr allocator(const allocator&) = default;
161
163 constexpr allocator& operator=(const allocator&) = default;
164
165
167 constexpr bool_t operator==(const allocator&) {
168 return true;
169 }
170
172 constexpr bool_t operator!=(const allocator&) {
173 return false;
174 }
175
177 template<typename U> constexpr bool_t operator==(const allocator<U>&) {
178 return true;
179 }
180
182 template<typename U> constexpr bool_t operator!=(const allocator<U>&) {
183 return true;
184 }
185
187 constexpr T* allocate(size_t n) {
188 return static_cast<T*>(::operator new(n * sizeof(T)));
189 }
190
192 constexpr T* allocate(size_t n, align_t align) {
193 return static_cast<T*>(::operator new(n * sizeof(T), align));
194 }
195
197 constexpr void deallocate(T* ptr) {
198 return ::operator delete(ptr);
199 }
200
202 constexpr void deallocate(T* ptr, align_t align) {
203 return ::operator delete(ptr, align);
204 }
205};
206
207
211template<typename T>
212class allocator<T[]>
213{
214public:
216 using value_t = T;
217
219 template<typename R> using rebind = allocator<R>;
220
222 constexpr allocator() = default;
223
225 constexpr ~allocator() = default;
226
228 constexpr allocator(const allocator&) = default;
229
231 constexpr allocator& operator=(const allocator&) = default;
232
233
235 constexpr bool_t operator==(const allocator&) {
236 return true;
237 }
238
240 constexpr bool_t operator!=(const allocator&) {
241 return false;
242 }
243
245 template<typename U> constexpr bool_t operator==(const allocator<U>&) {
246 return true;
247 }
248
250 template<typename U> constexpr bool_t operator!=(const allocator<U>&) {
251 return true;
252 }
253
255 constexpr T* allocate(size_t n) {
256 return static_cast<T*>(::operator new[](n * sizeof(T)));
257 }
258
260 constexpr T* allocate(size_t n, align_t align) {
261 return static_cast<T*>(::operator new[](n * sizeof(T), align));
262 }
263
265 constexpr void deallocate(T* ptr) {
266 return ::operator delete[](ptr);
267 }
268
270 constexpr void deallocate(T* ptr, align_t align) {
271 return ::operator delete[](ptr, align);
272 }
273};
274
275
283template<typename T, class AllocT = allocator<T>>
285{
286public:
288 using alloc_t = typename allocator_traits<AllocT>::template rebind<T>;
289
291 using value_t = T;
292
294 using size_t = size_t;
295
298
299
300 // Cosntructors ========================================================================================================
301
304 constexpr allocation() noexcept
305 : _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
306 }
307
311 explicit constexpr allocation(size_t n) noexcept
312 : _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
313 callocate(n);
314 }
315
321 constexpr allocation(const T* data, size_t n)
322 : allocation(n) {
323 fennec::memmove(_data, data, n);
324 }
325
330 constexpr allocation(size_t n, align_t align) noexcept
331 : _data(nullptr)
332 , _capacity(0)
333 , _alignment(align) {
334 callocate(n, align);
335 }
336
343 constexpr allocation(const T* data, size_t n, align_t align)
344 : allocation(n, align) {
345 fennec::memmove(static_cast<void*>(_data), data, n);
346 }
347
353 explicit constexpr allocation(const alloc_t& alloc) noexcept
354 : _alloc(alloc)
355 , _data(nullptr)
356 , _capacity(0)
357 , _alignment(zero<align_t>()){
358 }
359
366 constexpr allocation(size_t n, const alloc_t& alloc) noexcept
367 : _alloc(alloc)
368 , _data(nullptr)
369 , _capacity(0)
370 , _alignment(zero<align_t>()) {
371 callocate(n);
372 }
373
382 constexpr allocation(const T* data, size_t n, const alloc_t& alloc)
383 : allocation(n, alloc) {
384 fennec::memmove(static_cast<void*>(_data), data, n);
385 }
386
394 constexpr allocation(size_t n, align_t align, const alloc_t& alloc) noexcept
395 : _alloc(alloc)
396 , _data(nullptr)
397 , _capacity(0)
398 , _alignment(zero<align_t>()) {
399 callocate(n, align);
400 }
401
411 constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc)
412 : allocation(n, align, alloc) {
413 fennec::memmove(_data, data, n);
414 }
415
419 constexpr allocation(const allocation& alloc) noexcept
420 : _alloc(alloc._alloc)
421 , _data(_alloc.allocate(alloc._capacity))
422 , _capacity(alloc._capacity)
423 , _alignment(alloc._alignment) {
424 fennec::memmove(static_cast<void*>(_data), alloc._data, alloc._capacity * sizeof(T));
425 }
426
431 constexpr allocation(allocation&& alloc) noexcept
432 : _alloc(alloc._alloc)
433 , _data(alloc._data)
434 , _capacity(alloc._capacity)
435 , _alignment(alloc._alignment) {
436 alloc._data = nullptr; alloc._capacity = 0;
437 }
438
439
442 constexpr ~allocation() noexcept {
443 if (_data) {
444 _alloc.deallocate(_data);
445 _data = nullptr;
446 }
447 }
448
449
450// Assignment ==========================================================================================================
451
456 constexpr allocation& operator=(const allocation& alloc) {
457 allocation::allocate(alloc.capacity(), alloc.alignment());
458 fennec::memmove(_data, alloc, size());
459 return *this;
460 }
461
466 constexpr allocation& operator=(allocation&& alloc) noexcept {
467
468 // Copy contents
469 fennec::swap(_alloc, alloc._alloc);
470 fennec::swap(_data, alloc._data);
471 fennec::swap(_capacity, alloc._capacity);
472 fennec::swap(_alignment, alloc._alignment);
473
474 return *this;
475 }
476
477
478// Allocation and Deallocation =========================================================================================
479
484 constexpr void allocate(size_t n, align_t align = zero<align_t>()) noexcept {
485 deallocate();
486
487 if (align != zero<align_t>()) {
488 _data = _alloc.allocate(_capacity = n, _alignment = align);
489 } else {
490 _data = _alloc.allocate(_capacity = n);
491 }
492 }
493
498 constexpr void callocate(size_t n, align_t align = zero<align_t>()) noexcept {
499 allocate(n, align);
500 fennec::memset(static_cast<void*>(_data), 0, _capacity * sizeof(T));
501 }
502
505 constexpr void deallocate() noexcept {
506 if (_data) {
507 if (_alignment != zero<align_t>()) {
508 _alloc.deallocate(_data, _alignment);
509 } else {
510 _alloc.deallocate(_data);
511 }
512 }
513
514 _data = nullptr;
515 _capacity = 0;
516 _alignment = zero<align_t>();
517 }
518
522 constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept {
523 if (_data == nullptr) {
524 allocate(n, align);
525 return;
526 }
527
528 value_t* old = _data; size_t old_cap = _capacity;
529 _data = nullptr;
530 allocate(n, align);
531
532 fennec::memmove(static_cast<void*>(_data), old, min(_capacity, old_cap) * sizeof(T));
533
534 _alloc.deallocate(old);
535 _capacity = n;
536 }
537
541 constexpr void creallocate(size_t n, align_t align = zero<align_t>()) noexcept {
542 if (_data == nullptr) {
543 callocate(n, align);
544 return;
545 }
546
547 value_t* old = _data; size_t old_cap = _capacity;
548 _data = nullptr;
549 allocate(n, align);
550
551 fennec::memmove(static_cast<void*>(_data), old, min(_capacity, old_cap) * sizeof(T));
552
553 if (_capacity > old_cap) {
554 fennec::memset(static_cast<void*>(_data + old_cap), 0, _capacity - old_cap);
555 }
556
557 _alloc.deallocate(old);
558 _capacity = n;
559 }
560
561
562// Access ==============================================================================================================
563
564 constexpr value_t& operator[](size_t i) {
565 assertd(i < capacity(), "Array Out of Bounds");
566 return _data[i];
567 }
568
569 constexpr const value_t& operator[](size_t i) const {
570 assertd(i < capacity(), "Array Out of Bounds");
571 return _data[i];
572 }
573
574 constexpr operator value_t*() {
575 return _data;
576 }
577
578 constexpr operator const value_t*() const {
579 return _data;
580 }
581
582 value_t* begin() {
583 return _data;
584 }
585
586 value_t* end() {
587 return _data + capacity();
588 }
589
590 const value_t* begin() const {
591 return _data;
592 }
593
594 const value_t* end() const {
595 return _data + capacity();
596 }
597
598
599// Modification ========================================================================================================
600
603 constexpr void clear() noexcept {
604 fennec::memset(_data, 0, _capacity * sizeof(T));
605 }
606
610 constexpr size_t size() const {
611 return _capacity * sizeof(T);
612 }
613
617 constexpr size_t capacity() const {
618 return _capacity;
619 }
620
624 constexpr value_t* data() {
625 return _data;
626 }
627
631 constexpr const value_t* data() const {
632 return _data;
633 }
634
635 constexpr align_t alignment() const {
636 return _alignment;
637 }
638
639protected:
640 alloc_t _alloc; // Allocator object
641 value_t* _data; // Handle for the memory block
642 size_t _capacity; // Capacity of the memory block in elements.
643 align_t _alignment; // Alignment information
644};
645
646#ifdef FENNEC_COMPILER_GCC
647#pragma GCC diagnostic pop
648#endif
649
650}
651
652#endif // FENNEC_MEMORY_ALLOCATOR_H
constexpr bool_t operator!=(const allocator< U > &)
Inequality operator for allocators of same type but with different data type.
Definition allocator.h:250
constexpr allocator(const allocator &)=default
Copy Constructor.
constexpr bool_t operator==(const allocator &)
Equality operator.
Definition allocator.h:235
constexpr T * allocate(size_t n)
Allocate a block of memory large enough to hold n elements of type T
Definition allocator.h:255
T value_t
Alias for the data type used for metaprogramming.
Definition allocator.h:216
constexpr bool_t operator==(const allocator< U > &)
Equality operator for allocators of same type but with different data type.
Definition allocator.h:245
constexpr void deallocate(T *ptr, align_t align)
Deallocate a block of memory with type T
Definition allocator.h:270
allocator< R > rebind
Metaprogramming utility to rebind an allocator to a different data type.
Definition allocator.h:219
constexpr void deallocate(T *ptr)
Deallocate a block of memory with type T
Definition allocator.h:265
constexpr T * allocate(size_t n, align_t align)
Allocate a block of memory large enough to hold n elements of type T
Definition allocator.h:260
constexpr allocator()=default
Default Constructor.
constexpr ~allocator()=default
Default Destructor.
constexpr bool_t operator!=(const allocator &)
Inequality operator.
Definition allocator.h:240
constexpr allocator & operator=(const allocator &)=default
Copy Assignment.
Allocator implementation, uses new and delete operators.
Definition allocator.h:145
constexpr bool_t operator==(const allocator< U > &)
Equality operator for allocators of same type but with different data type.
Definition allocator.h:177
constexpr void deallocate(T *ptr)
Deallocate a block of memory with type T
Definition allocator.h:197
allocator< R > rebind
Metaprogramming utility to rebind an allocator to a different data type.
Definition allocator.h:151
T value_t
Alias for the data type used for metaprogramming.
Definition allocator.h:148
constexpr bool_t operator==(const allocator &)
Equality operator.
Definition allocator.h:167
constexpr T * allocate(size_t n, align_t align)
Allocate a block of memory large enough to hold n elements of type T
Definition allocator.h:192
constexpr void deallocate(T *ptr, align_t align)
Deallocate a block of memory with type T
Definition allocator.h:202
constexpr ~allocator()=default
Default Destructor.
constexpr bool_t operator!=(const allocator &)
Inequality operator.
Definition allocator.h:172
constexpr allocator()=default
Default Constructor.
constexpr allocator & operator=(const allocator &)=default
Copy Assignment.
constexpr bool_t operator!=(const allocator< U > &)
Inequality operator for allocators of same type but with different data type.
Definition allocator.h:182
constexpr T * allocate(size_t n)
Allocate a block of memory large enough to hold n elements of type T
Definition allocator.h:187
constexpr allocator(const allocator &)=default
Copy Constructor.
Conditional Types
Common
constexpr genType min(genType x, genType y)
Returns if otherwise it returns .
Definition common.h:688
Constants
This header contains functions related to analyzing, modifying or copying buffers interpreted as byte...
Numeric Transforms
Container to hold a memory allocation.
Definition allocator.h:285
constexpr void callocate(size_t n, align_t align=zero< align_t >()) noexcept
Allocate a block of memory for the allocation. If there is already an allocated block of memory,...
Definition allocator.h:498
constexpr void clear() noexcept
Clear the block of memory, setting all bytes to 0.
Definition allocator.h:603
constexpr allocation(const T *data, size_t n, align_t align)
Buffer Copy Constructor, initializes the allocation with a block of size n * sizeof(T) bytes....
Definition allocator.h:343
constexpr allocation(const alloc_t &alloc) noexcept
Allocator Constructor.
Definition allocator.h:353
constexpr allocation & operator=(allocation &&alloc) noexcept
Move Assignment Operator.
Definition allocator.h:466
constexpr allocation(const T *data, size_t n, align_t align, const alloc_t &alloc)
Buffer Copy Allocator Constructor, initializes the allocation with a block of size n * sizeof(T) byte...
Definition allocator.h:411
constexpr const value_t * data() const
Getter for the real pointer to the allocated block of memory.
Definition allocator.h:631
constexpr value_t * data()
Getter for the real pointer to the allocated block of memory.
Definition allocator.h:624
typename allocator_traits< AllocT >::template rebind< T > alloc_t
alias for the allocator type
Definition allocator.h:288
T value_t
alias for the data type
Definition allocator.h:291
constexpr allocation(const allocation &alloc) noexcept
Copy Constructor, creates an allocation of equal size and performs a byte-wise copy.
Definition allocator.h:419
constexpr size_t capacity() const
Getter for the number of elements n of type T that the allocation can hold.
Definition allocator.h:617
constexpr allocation(allocation &&alloc) noexcept
Move Constructor, moves the data in alloc to the new object and cleans alloc so that it can safely de...
Definition allocator.h:431
constexpr void allocate(size_t n, align_t align=zero< align_t >()) noexcept
Allocate a block of memory for the allocation. If there is already an allocated block of memory,...
Definition allocator.h:484
ptrdiff_t diff_t
diff type definition for ptr_traits
Definition allocator.h:297
constexpr allocation(const T *data, size_t n)
Buffer Copy Constructor, initializes the allocation with a block of size n * sizeof(T) bytes....
Definition allocator.h:321
constexpr allocation(const T *data, size_t n, const alloc_t &alloc)
Buffer Copy Allocator Constructor, initializes the allocation with a block of size n * sizeof(T) byte...
Definition allocator.h:382
constexpr allocation(size_t n, align_t align) noexcept
Sized Constructor, initializes the allocation with a block of size n * sizeof(T) bytes.
Definition allocator.h:330
size_t size_t
size type definition for ptr_traits
Definition allocator.h:294
constexpr ~allocation() noexcept
Default Destructor, releases the memory block if still present.
Definition allocator.h:442
constexpr allocation(size_t n) noexcept
Sized Constructor, initializes the allocation with a block of size n * sizeof(T) bytes.
Definition allocator.h:311
constexpr void reallocate(size_t n, align_t align=zero< align_t >()) noexcept
Reallocate the block with a new size. Contents are copied to the new allocation.
Definition allocator.h:522
constexpr allocation(size_t n, align_t align, const alloc_t &alloc) noexcept
Sized Allocator Constructor.
Definition allocator.h:394
constexpr size_t size() const
Getter for the byte size of the allocation.
Definition allocator.h:610
constexpr allocation(size_t n, const alloc_t &alloc) noexcept
Sized Allocator Constructor.
Definition allocator.h:366
constexpr void deallocate() noexcept
Release the block of memory.
Definition allocator.h:505
constexpr allocation() noexcept
Default Constructor, initializes internal data to null and the capacity to 0
Definition allocator.h:304
constexpr void creallocate(size_t n, align_t align=zero< align_t >()) noexcept
Reallocate the block with a new size. Contents are copied to the new allocation.
Definition allocator.h:541
constexpr allocation & operator=(const allocation &alloc)
Copy Assignment Operator.
Definition allocator.h:456
Helper structure for obtaining traits of an allocator class.
Definition allocator.h:61
detect_t< false_type, _is_always_equal, Alloc > is_always_equal
Checks if this allocator type is always equal to another allocator of similar type.
Definition allocator.h:131
detect_t< value_t *, _pointer, Alloc > pointer_t
Alias for a pointer to the value type. Will use Alloc::pointer_t if present.
Definition allocator.h:108
detect_t< const value_t *, _const_pointer, Alloc > const_pointer_t
Alias for a const pointer to the value type. Will use Alloc::const_pointer_t if present.
Definition allocator.h:111
detect_t< void *, _void_pointer, Alloc > void_pointer_t
Alias for a pointer to void. Will use Alloc::void_pointer_t if present.
Definition allocator.h:114
typename _diff< Alloc, pointer_t >::type diff_t
Alias for differences between pointers. Will use Alloc::diff_t if present.
Definition allocator.h:120
Alloc alloc_t
Alias for the allocator type.
Definition allocator.h:102
typename _size< Alloc, pointer_t >::type size_t
Alias for the size of allocations. Will use Alloc::size_t if present.
Definition allocator.h:123
typename Alloc::value_t value_t
Alias for the value type of the allocator.
Definition allocator.h:105
detect_t< const void *, _void_const_pointer, Alloc > const_void_pointer_t
Alias for a const pointer to void. Will use Alloc::const_void_pointer_t if present.
Definition allocator.h:117
typename _rebind< Alloc, TypeT >::type rebind
Rebinds the allocator type to produce an element type of type TypeT
Definition allocator.h:134
Get the corresponding unsigned integral type of TypeT.
Definition numeric_transforms.h:76
Class for retrieving the traits of Pointer-like types.
Definition pointer_traits.h:33
Take a Template with a Pack ClassT<ArgsT...> and replace the first ArgT of ArgsT.....
Definition type_sequences.h:101
Type Traits
Types
bool bool_t
A conditional type.
Definition types.h:214
void void_t
Void type used for SFINAE.
Definition types.h:256
__PTRDIFF_TYPE__ ptrdiff_t
Signed Integer Type Returned by the Subtraction of two Pointers.
Definition types.h:251
constexpr void swap(T &x, T &y) noexcept
Swaps x and y.
Definition utility.h:114