Lumiera  0.pre.03
»edit your freedom«
allocation-cluster.cpp
Go to the documentation of this file.
1 /*
2  AllocationCluster - allocating and owning a pile of objects
3 
4  Copyright (C)
5  2008, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
14 
33 #include "lib/linked-elements.hpp"
34 #include "lib/format-string.hpp"
35 #include "lib/util-quant.hpp"
36 #include "lib/util.hpp"
37 
38 
39 using util::unConst;
40 using util::isPow2;
41 using util::isnil;
42 using util::_Fmt;
43 using std::byte;
44 
45 
46 namespace lib {
47  namespace {// Internals...
48 
57  {
62  template<class X>
63  void
64  dispose (X* elm)
65  {
66  REQUIRE (elm);
67  elm->~X();
68  }
69  };
70 
71  }//(End)configuration and internals
72 
73 
74 
75 
76 
92  {
93 
95 
97  struct Extent
99  {
100  Extent* next;
101  Destructors dtors;
102  std::byte storage[max_size()];
103  };
105 
106  static_assert (sizeof(Destructors) == sizeof(void*));
107  static_assert (sizeof(Extents) == sizeof(void*));
108 
110  {
111  Storage storage;
112  Extents extents;
113  }; //Note: storage.pos and extents.head_ reside at the same location
114 
115  ManagementView view_;
116 
117  StorageManager() = delete;
118 
119  public:
120  static StorageManager&
121  access (AllocationCluster& clu)
122  {
123  return reinterpret_cast<StorageManager&> (clu);
124  }
125 
126  void
127  addBlock()
128  {
129  closeCurrentBlock();
130  prependNextBlock();
131  }
132 
133  void
134  discardAll()
135  {
136  closeCurrentBlock();
137  view_.extents.clear();
138  }
139 
140  void
141  attach (Destructor& dtor)
142  {
143  getCurrentBlockStart()->dtors.push (dtor);
144  }
145 
146 
147  bool
148  empty() const
149  {
150  return nullptr == view_.storage.pos;
151  }
152 
153  size_t
154  determineExtentCnt() const
155  {
156  return empty()? 0
157  : lib::asLinkedElements (getCurrentBlockStart())
158  .size();
159  }
160 
161  size_t
162  calcAllocInCurrentBlock() const
163  {
164  ENSURE (max_size() >= view_.storage.rest);
165  return max_size() - view_.storage.rest;
166  }
167 
168 
169  private:
170  Extent*
171  getCurrentBlockStart() const
172  {
173  REQUIRE (not empty());
174  void* pos = static_cast<byte*>(view_.storage.pos)
175  + view_.storage.rest
176  - EXTENT_SIZ;
177  return static_cast<Extent*> (pos);
178  }
179 
180  void
181  closeCurrentBlock()
182  {
183  if (empty()) return;
184  // relocate the pos-pointer to the start of the block
185  view_.storage.pos = getCurrentBlockStart();
186  view_.storage.rest = 0;
187  }
188 
189  void
190  prependNextBlock()
191  {
192  view_.extents.emplace();
193  view_.storage.pos = & view_.extents.top().storage;
194  view_.storage.rest = max_size();
195  }
196  };
197 
198 
199 
200 
201 
208  : storage_{}
209  {
210  TRACE (memory, "new AllocationCluster");
211  }
212 
213 
221  try
222  {
223  TRACE (memory, "shutting down AllocationCluster");
224  StorageManager::access(*this).discardAll();
225  }
226  ERROR_LOG_AND_IGNORE (progress, "discarding AllocationCluster")
227 
228 
229 
231 
232 
233 
240  void
241  AllocationCluster::expandStorage (size_t allocRequest)
242  {
243  ENSURE (allocRequest <= max_size());
244  StorageManager::access(*this).addBlock();
245  }
246 
247 
248  void
249  AllocationCluster::registerDestructor (Destructor& dtor)
250  {
251  StorageManager::access(*this).attach (dtor);
252  }
253 
254 
255 
262  void
263  AllocationCluster::__enforce_limits (size_t allocSiz, size_t align)
264  {
265  REQUIRE (allocSiz);
266  REQUIRE (align);
267  REQUIRE (isPow2 (align));
268 
269  if (allocSiz > max_size())
270  throw err::Fatal{_Fmt{"AllocationCluster: desired allocation of %d bytes "
271  "exceeds the fixed extent size of %d"} % allocSiz % max_size()
272  ,LERR_(CAPACITY)};
273 
274  if (align > max_size())
275  throw err::Fatal{_Fmt{"AllocationCluster: data requires alignment at %d bytes, "
276  "which is beyond the fixed extent size of %d"} % align % max_size()
277  ,LERR_(CAPACITY)};
278  }
279 
280 
281 
282  /* === diagnostics helpers === */
283 
284  size_t
285  AllocationCluster::numExtents() const
286  {
287  return StorageManager::access (unConst(*this)).determineExtentCnt();
288  }
289 
295  size_t
297  {
298  size_t extents = numExtents();
299  if (not extents) return 0;
300  size_t bytes = StorageManager::access (unConst(*this)).calcAllocInCurrentBlock();
301  return (extents - 1) * max_size() + bytes;
302  }
303 
304 
305 } // namespace lib
TY & emplace(ARGS &&...args)
prepend object of type TY, forwarding ctor args
void dispose(X *elm)
while this policy doesn&#39;t take ownership, it ensures the destructor is invoked
#define ERROR_LOG_AND_IGNORE(_FLAG_, _OP_DESCR_)
convenience shortcut for a sequence of catch blocks just logging and consuming an error...
Definition: error.hpp:266
An overlay view for the AllocationCluster to add functionality for adding / clearing extents and regi...
Memory management for the low-level model (render nodes network).
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
Front-end for printf-style string template interpolation.
Special allocator-policy for lib::LinkedElements.
A front-end for using printf-style formatting.
void expandStorage(size_t)
Expand the alloted storage pool by a block, suitable to accommodate at least the indicated request...
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
void __enforce_limits(size_t, size_t)
Allocation cluster uses a comparatively small tile size for its extents, which turns out to be a freq...
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Utilities for quantisation (grid alignment) and comparisons.
Intrusive single linked list with optional ownership.
void clear() noexcept
A pile of objects sharing common allocation and lifecycle.
auto & asLinkedElements(N *const &anchor)
transiently reinterpret an element pointer as const LinkedElements, allowing to count, iterate or subscript a chain of elements
maintaining the Allocation
static size_t constexpr max_size()
Maximum individual allocation size that can be handled.
~AllocationCluster() noexcept
The shutdown of an AllocationCluster walks all extents and invokes all registered deleter functions a...
AllocationCluster()
Prepare a new clustered allocation to be expanded by extents of size EXTENT_SIZ, yet discarded all at...
Policy for LinkedElements: never create or destroy any elements, only allow to add already existing n...