9 #ifndef EAGINE_MEMORY_OBJECT_STORAGE_HPP
10 #define EAGINE_MEMORY_OBJECT_STORAGE_HPP
12 #include "../assert.hpp"
13 #include "../types.hpp"
20 namespace eagine::memory {
22 class object_storage {
26 typename = shared_byte_allocator::enable_if_compatible_t<X>>
27 object_storage(X&& x) noexcept
28 : _alloc(std::forward<X>(x))
29 , _blks{std_allocator<owned_block>{_alloc}}
30 , _alns{std_allocator<span_size_t>{_alloc}}
31 , _dtrs{std_allocator<void (*)(
block)>{_alloc}} {}
33 object_storage(shared_byte_allocator a) noexcept
34 : _alloc(std::move(a))
35 , _blks{std_allocator<owned_block>{_alloc}}
36 , _alns{std_allocator<span_size_t>{_alloc}}
37 , _dtrs{std_allocator<void (*)(
block)>{_alloc}} {}
39 object_storage() noexcept
40 : object_storage{default_byte_allocator()} {}
42 object_storage(object_storage&&) =
delete;
43 object_storage(
const object_storage&) =
delete;
44 auto operator=(object_storage&&) =
delete;
45 auto operator=(
const object_storage&) =
delete;
46 ~object_storage() noexcept {
57 auto is_empty() const noexcept {
58 EAGINE_ASSERT(_blks.size() == _alns.size());
59 EAGINE_ASSERT(_blks.size() == _dtrs.size());
63 template <
typename T,
typename... Args>
64 auto emplace(Args&&... args) -> std::remove_const_t<T>& {
65 using A = std::remove_const_t<T>;
66 const auto size = span_size_of<A>();
67 const auto align = span_align_of<A>();
68 owned_block b = _alloc.allocate(size, align);
71 throw std::bad_alloc();
75 EAGINE_ASSERT(b.size() >= size);
77 _blks.push_back(std::move(b));
78 _alns.push_back(align);
79 _dtrs.push_back(&_destroy<A>);
81 A* result =
new(_blks.back().data()) A(std::forward<Args>(args)...);
82 EAGINE_ASSERT(result !=
nullptr);
86 void clear() noexcept {
87 EAGINE_ASSERT(_blks.size() == _alns.size());
88 EAGINE_ASSERT(_blks.size() == _dtrs.size());
91 _dtrs[i - 1](_blks[i - 1]);
95 _alloc.deallocate(std::move(_blks[i]), _alns[i]);
104 shared_byte_allocator _alloc{};
106 template <
typename T>
107 static void _destroy(
block blk) noexcept {
108 auto spn = accomodate<T>(blk);
114 std::vector<owned_block, std_allocator<owned_block>> _blks;
115 std::vector<span_size_t, std_allocator<span_size_t>> _alns;
116 std::vector<void (*)(
block), std_allocator<
void (*)(
block)>> _dtrs;
118 template <
typename Func>
119 void for_each_block(Func& func) noexcept {
120 for(
std_size_t i = 0; i < _blks.size(); ++i) {
121 func(i,
block(_blks[i]));
126 template <
typename Signature>
127 class callable_storage;
129 template <
typename... Params>
130 class callable_storage<void(Params...)> :
private memory::object_storage {
132 using base = memory::object_storage;
136 typename = shared_byte_allocator::enable_if_compatible_t<X>>
137 callable_storage(X&& x) noexcept
138 : base(std::forward<X>(x))
139 , _clrs{std_allocator<void (*)(
block, Params...)>{base::_alloc}} {}
141 callable_storage(
const shared_byte_allocator& a) noexcept
143 , _clrs{std_allocator<void (*)(
block, Params...)>{base::_alloc}} {}
145 callable_storage() noexcept
146 : callable_storage(default_byte_allocator()) {}
155 typename = std::enable_if_t<std::is_invocable_v<T, Params...>>>
156 auto add(T x) ->
auto& {
157 using A = std::remove_const_t<T>;
158 auto& result = base::template emplace<A>(std::move(x));
159 _clrs.push_back(&_call<A>);
163 auto is_empty() const noexcept {
164 EAGINE_ASSERT(_blks.size() == _clrs.size());
165 return base::is_empty();
168 void clear() noexcept {
173 void operator()(Params... params) noexcept {
174 auto fn = [&](
auto i,
block blk) {
175 this->_clrs[i](blk, params...);
177 base::for_each_block(fn);
182 void (*)(
block, Params...),
183 std_allocator<void (*)(
block, Params...)>>
186 template <
typename T>
187 static void _call(
block blk, Params... params) noexcept {
188 auto spn = accomodate<T>(blk);
197 #endif // EAGINE_MEMORY_OBJECT_STORAGE_HPP