OGLplus  (0.59.0) a C++ wrapper for rendering APIs

object_storage.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_MEMORY_OBJECT_STORAGE_HPP
10 #define EAGINE_MEMORY_OBJECT_STORAGE_HPP
11 
12 #include "../assert.hpp"
13 #include "../types.hpp"
14 #include "block.hpp"
15 #include "default_alloc.hpp"
16 #include "shared_alloc.hpp"
17 #include "std_alloc.hpp"
18 #include <vector>
19 
20 namespace eagine::memory {
21 //------------------------------------------------------------------------------
22 class object_storage {
23 public:
24  template <
25  typename X,
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}} {}
32 
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}} {}
38 
39  object_storage() noexcept
40  : object_storage{default_byte_allocator()} {}
41 
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 {
47  clear();
48  }
49 
50  void reserve(span_size_t n) {
51  const auto sz{std_size(n)};
52  _blks.reserve(sz);
53  _alns.reserve(sz);
54  _dtrs.reserve(sz);
55  }
56 
57  auto is_empty() const noexcept {
58  EAGINE_ASSERT(_blks.size() == _alns.size());
59  EAGINE_ASSERT(_blks.size() == _dtrs.size());
60  return _blks.empty();
61  }
62 
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);
69 
70  if(b.empty()) {
71  throw std::bad_alloc();
72  }
73 
74  EAGINE_ASSERT(is_aligned_to(b.addr(), align));
75  EAGINE_ASSERT(b.size() >= size);
76 
77  _blks.push_back(std::move(b));
78  _alns.push_back(align);
79  _dtrs.push_back(&_destroy<A>);
80 
81  A* result = new(_blks.back().data()) A(std::forward<Args>(args)...);
82  EAGINE_ASSERT(result != nullptr);
83  return *result;
84  }
85 
86  void clear() noexcept {
87  EAGINE_ASSERT(_blks.size() == _alns.size());
88  EAGINE_ASSERT(_blks.size() == _dtrs.size());
89 
90  for(std_size_t i = _blks.size(); i > 0; --i) {
91  _dtrs[i - 1](_blks[i - 1]);
92  }
93 
94  for(std_size_t i = 0; i < _blks.size(); ++i) {
95  _alloc.deallocate(std::move(_blks[i]), _alns[i]);
96  }
97 
98  _dtrs.clear();
99  _alns.clear();
100  _blks.clear();
101  }
102 
103 protected:
104  shared_byte_allocator _alloc{};
105 
106  template <typename T>
107  static void _destroy(block blk) noexcept {
108  auto spn = accomodate<T>(blk);
109  EAGINE_ASSERT(spn);
110  auto& x{extract(spn)};
111  x.~T();
112  }
113 
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;
117 
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]));
122  }
123  }
124 };
125 //------------------------------------------------------------------------------
126 template <typename Signature>
127 class callable_storage;
128 
129 template <typename... Params>
130 class callable_storage<void(Params...)> : private memory::object_storage {
131 public:
132  using base = memory::object_storage;
133 
134  template <
135  typename X,
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}} {}
140 
141  callable_storage(const shared_byte_allocator& a) noexcept
142  : base(a)
143  , _clrs{std_allocator<void (*)(block, Params...)>{base::_alloc}} {}
144 
145  callable_storage() noexcept
146  : callable_storage(default_byte_allocator()) {}
147 
148  void reserve(span_size_t n) {
149  base::reserve(n);
150  _clrs.reserve(std_size(n));
151  }
152 
153  template <
154  typename T,
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>);
160  return result;
161  }
162 
163  auto is_empty() const noexcept {
164  EAGINE_ASSERT(_blks.size() == _clrs.size());
165  return base::is_empty();
166  }
167 
168  void clear() noexcept {
169  base::clear();
170  _clrs.clear();
171  }
172 
173  void operator()(Params... params) noexcept {
174  auto fn = [&](auto i, block blk) {
175  this->_clrs[i](blk, params...);
176  };
177  base::for_each_block(fn);
178  }
179 
180 private:
181  std::vector<
182  void (*)(block, Params...),
183  std_allocator<void (*)(block, Params...)>>
184  _clrs{};
185 
186  template <typename T>
187  static void _call(block blk, Params... params) noexcept {
188  auto spn = accomodate<T>(blk);
189  EAGINE_ASSERT(spn);
190  auto& x{extract(spn)};
191  x(params...);
192  }
193 };
194 //------------------------------------------------------------------------------
195 } // namespace eagine::memory
196 
197 #endif // EAGINE_MEMORY_OBJECT_STORAGE_HPP
static constexpr auto is_aligned_to(const_address addr, span_size_t alignment) noexcept
Indicates if a memory address aligned to the specified alignment.
Definition: address.hpp:229
std::ptrdiff_t span_size_t
Signed span size type used by eagine.
Definition: types.hpp:36
static constexpr auto extract(api_result_value< Result, api_result_validity::never > &) noexcept -> Result &
Overload of extract for api_result_value.
Definition: c_api_wrap.hpp:270
basic_block< false > block
Alias for non-const byte memory span.
Definition: block.hpp:27
std::size_t std_size_t
Size type used by std.
Definition: types.hpp:32
static constexpr auto std_size(T v) noexcept
Converts argument to std size type.
Definition: types.hpp:52

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).