9 #ifndef EAGINE_MEMORY_BYTE_ALLOC_HPP
10 #define EAGINE_MEMORY_BYTE_ALLOC_HPP
12 #include "../assert.hpp"
13 #include "../interface.hpp"
14 #include "../tribool.hpp"
15 #include "../types.hpp"
19 namespace eagine::memory {
23 : interface<byte_allocator>
28 virtual auto duplicate() noexcept -> byte_allocator* = 0;
30 virtual auto release() noexcept ->
bool = 0;
32 virtual auto equal(byte_allocator* a) const noexcept ->
bool = 0;
34 virtual auto max_size(size_type a) noexcept -> size_type = 0;
36 virtual auto has_allocated(const owned_block& b, size_type a = 0) noexcept
39 virtual auto allocate(size_type n, size_type a) noexcept -> owned_block = 0;
41 virtual
void deallocate(owned_block&& b, size_type a = 0) noexcept = 0;
44 can_reallocate(const owned_block& b, size_type n, size_type a) noexcept
47 virtual auto reallocate(owned_block&& b, size_type n, size_type a) noexcept
50 void do_reallocate(owned_block& b, size_type n, size_type a) noexcept {
52 if(can_reallocate(b, n, a)) {
53 b = reallocate(std::move(b), n, a);
55 deallocate(std::move(b), a);
61 virtual void eject_self() noexcept = 0;
65 struct byte_alloc_managed_policy {
66 inline auto duplicate(byte_allocator* that) noexcept -> byte_allocator* {
70 inline auto release(byte_allocator*) noexcept ->
bool {
76 class byte_alloc_ref_count_policy {
81 byte_alloc_ref_count_policy(
const byte_alloc_ref_count_policy&) =
delete;
83 auto operator=(
const byte_alloc_ref_count_policy&) =
delete;
84 auto operator=(byte_alloc_ref_count_policy&& tmp) =
delete;
86 byte_alloc_ref_count_policy() noexcept = default;
88 byte_alloc_ref_count_policy(byte_alloc_ref_count_policy&& tmp) noexcept
89 : _ref_count(tmp._ref_count) {
93 ~byte_alloc_ref_count_policy() noexcept {
94 EAGINE_ASSERT(_ref_count == 0);
97 auto duplicate(byte_allocator* that) noexcept -> byte_allocator* {
102 auto release(byte_allocator*) noexcept ->
bool {
103 return (--_ref_count == 0);
108 using default_byte_allocator_policy = byte_alloc_ref_count_policy;
111 template <
typename Policy,
template <
class...>
class DerivedTpl,
typename... Args>
112 class byte_allocator_impl :
public byte_allocator {
116 using Derived = DerivedTpl<Args..., Policy>;
118 auto derived() -> Derived& {
119 return *
static_cast<Derived*
>(
this);
125 byte_allocator_impl() =
default;
126 byte_allocator_impl(byte_allocator_impl&&) noexcept(
127 std::is_nothrow_move_constructible_v<Policy>) = default;
128 byte_allocator_impl(const byte_allocator_impl&) = delete;
130 auto operator=(byte_allocator_impl&&) noexcept(
131 std::is_nothrow_move_assignable_v<Policy>)
132 -> byte_allocator_impl& = default;
133 auto operator=(const byte_allocator_impl&) = delete;
135 ~byte_allocator_impl() noexcept override = default;
137 auto duplicate() noexcept -> byte_allocator*
override {
138 return _policy.duplicate(
this);
141 auto release() noexcept ->
bool override {
142 return _policy.release(
this);
145 auto can_reallocate(
const owned_block&, size_type, size_type) noexcept
150 auto reallocate(owned_block&& b, size_type, size_type) noexcept
151 -> owned_block
override {
155 template <
typename Final>
156 static auto accomodate_derived(Final& that) noexcept -> Final* {
158 that.allocate(span_size_of<Final>(), span_align_of<Final>());
159 auto*
const result =
new(ob.begin()) Final(std::move(that));
160 release_block(std::move(ob));
164 template <
typename Final>
165 static void eject_derived(Final& that) noexcept {
166 Final tmp = std::move(that);
168 acquire_block(
as_bytes(cover_one(that))), span_align_of<Final>());
171 auto accomodate_self() noexcept -> Derived* {
172 return accomodate_derived(derived());
175 void eject_self() noexcept
override {
176 eject_derived(derived());
182 #endif // EAGINE_MEMORY_BYTE_ALLOC_HPP