ORIGINAL
Loading...
Searching...
No Matches
allocator.h
Go to the documentation of this file.
1#ifndef ALLOCATOR_H
2#define ALLOCATOR_H
3
4#include "config.h"
5#include "error.h"
6#include "maths.h"
7#include "type_traits"
8#include "utility"
9
34namespace original {
35
43 public:
53 template <typename TYPE>
54 static TYPE* malloc(u_integer size);
55
62 template <typename TYPE>
63 static void free(TYPE* ptr);
64 };
65
83 template<typename TYPE, template <typename> typename DERIVED>
85 public:
88 using propagate_on_container_swap = std::false_type;
89 using propagate_on_container_merge = std::false_type;
90
95 template <typename O_TYPE>
97
104 constexpr allocatorBase();
105
111 virtual TYPE* allocate(u_integer size) = 0;
112
118 virtual void deallocate(TYPE* ptr, u_integer size) = 0;
119
127 template<typename O_TYPE, typename... Args>
129
135 template<typename O_TYPE>
136 static void destroy(O_TYPE* o_ptr);
137
138 virtual ~allocatorBase() = 0;
139 };
140
152 template<typename TYPE>
153 class allocator : public allocatorBase<TYPE, allocator> {
154 public:
159
167 TYPE* allocate(u_integer size) override;
168
174 void deallocate(TYPE* ptr, u_integer size) override;
175 };
176
201 template<typename TYPE>
202 class objPoolAllocator final : public allocatorBase<TYPE, objPoolAllocator>
203 {
209 class freeChunk
210 {
211 public:
212 freeChunk* next = nullptr;
213 };
214
219 class allocatedChunks {
220 public:
221 void* chunks = nullptr;
222 allocatedChunks* next = nullptr;
223 };
224
232 static constexpr u_integer CHUNK_SIZE = sizeof(TYPE) > sizeof(freeChunk*) ? sizeof(TYPE) : sizeof(freeChunk*);
233
234 u_integer size_class_count;
235 u_integer chunk_count_init;
236 u_integer* chunk_count;
237 freeChunk** free_list_head;
238 allocatedChunks* allocated_list_head;
239 u_integer* chunks_available;
240
250 void poolInit();
251
257 [[nodiscard]] static constexpr u_integer getChunkIndex(u_integer size);
258
265 void chunkAllocate(u_integer num_element, u_integer index);
266
275 void release() noexcept;
276
277 public:
280 using propagate_on_container_swap = std::true_type;
281 using propagate_on_container_merge = std::true_type;
282
288 explicit objPoolAllocator(u_integer size_class_count = 8, u_integer count = 4);
289
292
304
311
320
325 void swap(objPoolAllocator& other) noexcept;
326
334 TYPE* allocate(u_integer size) override;
335
342 void deallocate(TYPE* ptr, u_integer size) override;
343
347 ~objPoolAllocator() override;
348 };
349}
350
351namespace std {
358 template<typename TYPE>
360}
361
362template<typename TYPE>
364 if (size == 0) {
365 return nullptr;
366 }
367
368 try {
369 return static_cast<TYPE*>(operator new(size * sizeof(TYPE)));
370 } catch (const std::bad_alloc&) {
371 throw allocateError();
372 }
373}
374
375template<typename TYPE>
377 ::operator delete(ptr);
378}
379
380template <typename TYPE, template <typename> typename DERIVED>
382{
383 staticError<allocateError, sizeof(TYPE) == 0 || std::is_void_v<TYPE>>::asserts();
384}
385
386template<typename TYPE, template <typename> typename DERIVED>
388
389template<typename TYPE, template <typename> typename DERIVED>
390template<typename O_TYPE, typename... Args>
392 new (o_ptr) O_TYPE{std::forward<Args>(args)...};
393}
394
395template<typename TYPE, template <typename> typename DERIVED>
396template<typename O_TYPE>
400
401template<typename TYPE>
403 return allocators::malloc<TYPE>(size);
404}
405
406template<typename TYPE>
410
411template<typename TYPE>
412constexpr original::u_integer
414 u_integer index = 0;
415 while (static_cast<u_integer>(1) << index < size) {
416 index += 1;
417 }
418 return index;
419}
420
421template<typename TYPE>
423 this->chunk_count = allocators::malloc<u_integer>(this->size_class_count);
424 this->free_list_head = allocators::malloc<freeChunk*>(this->size_class_count);
425 this->chunks_available = allocators::malloc<u_integer>(this->size_class_count);
426 this->allocated_list_head = nullptr;
427
428 for (u_integer i = 0; i < this->size_class_count; i++) {
429 this->chunk_count[i] = this->chunk_count_init;
430 this->free_list_head[i] = nullptr;
431 this->chunks_available[i] = 0;
432 }
433}
434
435template <typename TYPE>
437{
438 const u_integer block_size = (1 << index) * CHUNK_SIZE;
439 auto new_free_chunk = allocators::malloc<byte>(num_element * block_size);
440 auto new_allocated_chunk = allocators::malloc<allocatedChunks>(1);
441
442 new_allocated_chunk->chunks = new_free_chunk;
443 new_allocated_chunk->next = this->allocated_list_head;
444 this->allocated_list_head = new_allocated_chunk;
445
446 for (u_integer i = 0; i < num_element; i++)
447 {
448 auto cur_ptr = reinterpret_cast<freeChunk*>(new_free_chunk + i * block_size);
449 cur_ptr->next = this->free_list_head[index];
450 this->free_list_head[index] = cur_ptr;
451 }
452 this->chunks_available[index] += num_element;
453 this->chunk_count[index] = this->chunk_count[index] + (this->chunk_count[index] >> 1);
454}
455
456template<typename TYPE>
458 while (this->allocated_list_head) {
459 auto next_chunk = this->allocated_list_head->next;
460 allocators::free(this->allocated_list_head->chunks);
461 allocators::free(this->allocated_list_head);
462 this->allocated_list_head = next_chunk;
463 }
464
465 if (this->chunk_count) {
466 allocators::free(this->chunk_count);
467 this->chunk_count = nullptr;
468 }
469 if (this->free_list_head) {
470 allocators::free(this->free_list_head);
471 this->free_list_head = nullptr;
472 }
473 if (this->chunks_available) {
474 allocators::free(this->chunks_available);
475 this->chunks_available = nullptr;
476 }
477}
478
479template <typename TYPE>
481 : size_class_count(size_class_count), chunk_count_init(count), chunk_count(nullptr),
482 free_list_head(nullptr), allocated_list_head(nullptr), chunks_available(nullptr) {
483 this->poolInit();
484}
485
486template<typename TYPE>
488 if (this == &other)
489 return *this;
490
491 auto size_class_count_max = max(this->size_class_count, other.size_class_count);
492 auto chunk_count_init_max = max(this->chunk_count_init, other.chunk_count_init);
493 auto chunk_count_max = allocators::malloc<u_integer>(size_class_count_max);
494 auto free_list_head_max = allocators::malloc<freeChunk*>(size_class_count_max);
495 auto chunks_available_max = allocators::malloc<u_integer>(size_class_count_max);
496
497 for (u_integer i = 0; i < size_class_count_max; i++) {
498 if (i < this->size_class_count && i < other.size_class_count) {
499 chunk_count_max[i] = max(this->chunk_count[i], other.chunk_count[i]);
500 chunks_available_max[i] = this->chunks_available[i] + other.chunks_available[i];
501 auto cur_list_head_i = other.free_list_head[i];
502 if (cur_list_head_i) {
503 while (cur_list_head_i->next) {
505 }
506 cur_list_head_i->next = this->free_list_head[i];
507 free_list_head_max[i] = other.free_list_head[i];
508 }else {
509 free_list_head_max[i] = this->free_list_head[i];
510 }
511 }else if (i < this->size_class_count) {
512 chunk_count_max[i] = this->chunk_count[i];
513 chunks_available_max[i] = this->chunks_available[i];
514 free_list_head_max[i] = this->free_list_head[i];
515 }else {
516 chunk_count_max[i] = other.chunk_count[i];
517 chunks_available_max[i] = other.chunks_available[i];
518 free_list_head_max[i] = other.free_list_head[i];
519 }
520 }
521
522 auto allocated_list_head_max = other.allocated_list_head;
525 while (cur_allocated_list_head->next) {
527 }
528 cur_allocated_list_head->next = this->allocated_list_head;
529 }else {
530 allocated_list_head_max = this->allocated_list_head;
531 }
532 this->allocated_list_head = nullptr;
533 other.allocated_list_head = nullptr;
534
535 this->release();
536 other.release();
537 other.poolInit();
538
539 this->size_class_count = size_class_count_max;
540 this->chunk_count_init = chunk_count_init_max;
541 this->chunk_count = chunk_count_max;
542 this->free_list_head = free_list_head_max;
543 this->chunks_available = chunks_available_max;
544 this->allocated_list_head = allocated_list_head_max;
545
546 return *this;
547}
548
549template<typename TYPE>
553
554template<typename TYPE>
556 if (this == &other)
557 return *this;
558
559 this->release();
560
561 this->size_class_count = other.size_class_count;
562 this->chunk_count_init = other.chunk_count_init;
563 this->chunk_count = other.chunk_count;
564 this->free_list_head = other.free_list_head;
565 this->allocated_list_head = other.allocated_list_head;
566 this->chunks_available = other.chunks_available;
567
568 other.poolInit();
569 return *this;
570}
571
572template <typename TYPE>
574{
575 if (this == &other)
576 return;
577
578 std::swap(this->size_class_count, other.size_class_count);
579 std::swap(this->chunk_count_init, other.chunk_count_init);
580 std::swap(this->chunk_count, other.chunk_count);
581 std::swap(this->free_list_head, other.free_list_head);
582 std::swap(this->allocated_list_head, other.allocated_list_head);
583 std::swap(this->chunks_available, other.chunks_available);
584}
585
586template <typename TYPE>
588{
589 if (size == 0) {
590 return nullptr;
591 }
592
593 u_integer index = getChunkIndex(size);
594
595 if (index >= this->size_class_count) {
596 return allocators::malloc<TYPE>(size);
597 }
598
599 if (!this->free_list_head[index] || this->chunks_available[index] * (static_cast<u_integer>(1) << index) < size) {
600 this->chunkAllocate(max<u_integer>(1, this->chunk_count[index]), index);
601 }
602
603 auto cur_ptr = this->free_list_head[index];
604 this->free_list_head[index] = this->free_list_head[index]->next;
605 this->chunks_available[index] -= 1;
606 return reinterpret_cast<TYPE*>(cur_ptr);
607}
608
609template <typename TYPE>
611{
612 if (size == 0) {
613 return;
614 }
615
616 u_integer index = getChunkIndex(size);
617
618 if (index >= this->size_class_count) {
619 allocators::free(ptr);
620 return;
621 }
622
623 auto p = reinterpret_cast<freeChunk*>(ptr);
624 p->next = this->free_list_head[index];
625 this->free_list_head[index] = p;
626 this->chunks_available[index] += 1;
627}
628
629template<typename TYPE>
633
634template <typename TYPE>
636{
637 lhs.swap(rhs);
638}
639
640#endif //ALLOCATOR_H
Exception for memory allocation failures.
Definition error.h:385
Interface for other memory allocator implementations.
Definition allocator.h:84
std::false_type propagate_on_container_swap
No propagation on swap.
Definition allocator.h:88
std::false_type propagate_on_container_copy_assignment
No propagation on copy.
Definition allocator.h:86
virtual ~allocatorBase()=0
Virtual destructor.
std::false_type propagate_on_container_move_assignment
No propagation on move.
Definition allocator.h:87
void construct(O_TYPE *o_ptr, Args &&... args)
Constructs an object in allocated memory.
Definition allocator.h:391
constexpr allocatorBase()
Constructs a new allocatorBase instance.
Definition allocator.h:381
static void destroy(O_TYPE *o_ptr)
Destroys an object without deallocating.
Definition allocator.h:397
virtual void deallocate(TYPE *ptr, u_integer size)=0
Deallocates memory.
virtual TYPE * allocate(u_integer size)=0
Allocates raw memory.
std::false_type propagate_on_container_merge
No propagation on merge.
Definition allocator.h:89
Default memory allocator using allocators utilities.
Definition allocator.h:153
void deallocate(TYPE *ptr, u_integer size) override
Deallocates memory using global operator delete.
Definition allocator.h:407
TYPE * allocate(u_integer size) override
Allocates memory using global operator new.
Definition allocator.h:402
Utility class providing static memory allocation/de-allocation functions.
Definition allocator.h:42
static TYPE * malloc(u_integer size)
Allocates raw memory using global operator new.
Definition allocator.h:363
static void free(TYPE *ptr)
Deallocates memory using global operator delete.
Definition allocator.h:376
void swap(autoPtr &other) noexcept
Swaps the reference counters between two autoPtr instances.
Definition autoPtr.h:703
Object pool allocator for efficient fixed-size memory management.
Definition allocator.h:203
objPoolAllocator & operator+=(objPoolAllocator &other)
Merges another pool allocator into this one.
Definition allocator.h:487
objPoolAllocator(const objPoolAllocator &)=delete
Copy construction disabled.
TYPE * allocate(u_integer size) override
Allocates memory from the pool.
Definition allocator.h:587
std::true_type propagate_on_container_swap
Allows propagation on swap.
Definition allocator.h:280
void deallocate(TYPE *ptr, u_integer size) override
Returns memory to the pool.
Definition allocator.h:610
std::true_type propagate_on_container_move_assignment
Allows propagation on move.
Definition allocator.h:279
objPoolAllocator(u_integer size_class_count=8, u_integer count=4)
Constructs a new object pool allocator.
Definition allocator.h:480
void swap(objPoolAllocator &other) noexcept
Swaps the contents of two allocators.
Definition allocator.h:573
std::true_type propagate_on_container_merge
Allows propagation on merge.
Definition allocator.h:281
~objPoolAllocator() override
Destructor - releases all allocated memory.
Definition allocator.h:630
objPoolAllocator & operator=(const objPoolAllocator &)=delete
Copy assignment disabled.
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:37
Compile-time error triggering utility.
Definition error.h:167
Platform-independent type definitions and compiler/platform detection.
Custom exception classes and callback validation utilities.
std::uint32_t u_integer
32-bit unsigned integer type for sizes and indexes
Definition config.h:263
Mathematical utilities, constants, and range generators.
Main namespace for the project Original.
Definition algorithms.h:21
TYPE max(TYPE a, TYPE b)
Returns the larger of two given values.
auto count()
Creates a count pipe operation.
Definition generators.h:964
Standard namespace extensions for original::alternative.
Definition allocator.h:351
void swap(original::objPoolAllocator< TYPE > &lhs, original::objPoolAllocator< TYPE > &rhs) noexcept
Specialization of std::swap for objPoolAllocator.
Definition allocator.h:635