fallback_allocator.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #pragma once
  2. #include <type_traits>
  3. #include <algorithm>
  4. namespace baselib
  5. {
  6. BASELIB_CPP_INTERFACE
  7. {
  8. // Baselib fallback allocator implementation with baselib allocators method coverage.
  9. // If the `Primary` allocator fail to allocate the request it's passed to the `Fallback` Allocator.
  10. //
  11. // The fallback allocator purpose is to provide a template for implementation using an allocator composition approach.
  12. // While providing for the baselib allocators interface(s), it's not intended to be a turn-key, general purpose solution, but rather
  13. // act as a template building block for derived allocators which may extend, add or ignore methods for specific needs.
  14. //
  15. // As a rule of thumb, Both Primary and Secondary allocator method calls may fail depending on their specific implementation.
  16. // What (if any) action is to be taken in such cases is intentionally left to be implemented by the derived class.
  17. //
  18. template<class Primary, class Fallback>
  19. class fallback_allocator : protected Primary, protected Fallback
  20. {
  21. public:
  22. // Allocations are guaranteed to always be aligned to at least the value of `alignment`
  23. // Alignment is the minimal value of Primary and Fallback allocator alignment, which is what can be guaranteed.
  24. static constexpr unsigned alignment = (Primary::alignment < Fallback::alignment) ? Primary::alignment : Fallback::alignment;
  25. // Allocates a memory block large enough to hold `size` number of bytes.
  26. //
  27. // \returns Address to memory block of allocated memory or nullptr if allocation failed.
  28. void* allocate(size_t size)
  29. {
  30. void *ptr = Primary::allocate(size);
  31. if (ptr == nullptr)
  32. ptr = Fallback::allocate(size);
  33. return ptr;
  34. }
  35. // Reallocates previously allocated or reallocated memory block pointer reference `ptr` from `old_size` to `new_size` number of bytes.
  36. // Reallocation will fail if the ownership of the new allocation can't be preserved.
  37. //
  38. // \returns Address to memory block of reallocated memory or nullptr if reallocation failed.
  39. void* reallocate(void* ptr, size_t old_size, size_t new_size)
  40. {
  41. if (Primary::owns(ptr, old_size))
  42. return Primary::reallocate(ptr, old_size, new_size);
  43. return Fallback::reallocate(ptr, old_size, new_size);
  44. }
  45. // Deallocates memory block previously allocated or reallocated with `size` pointed to by `ptr`.
  46. //
  47. // \returns True if the operation was successful.
  48. bool deallocate(void* ptr, size_t size)
  49. {
  50. if (Primary::owns(ptr, size))
  51. return Primary::deallocate(ptr, size);
  52. return Fallback::deallocate(ptr, size);
  53. }
  54. // Calculate optimal allocation size of the primary allocator given `size`.
  55. //
  56. // \returns Optimal size of the primary allocator when allocating memory given `size`.
  57. constexpr size_t optimal_size(size_t size) const
  58. {
  59. return Primary::optimal_size(size);
  60. }
  61. // Checks for the ownership allocation given `ptr` and `size`
  62. // It is implementation defined if either or both of `ptr` and `size` are considered to determine ownership.
  63. //
  64. // \returns True if the primary allocator owns the allocation.
  65. bool owns(const void* ptr, size_t size) const
  66. {
  67. return Primary::owns(ptr, size);
  68. }
  69. };
  70. }
  71. }