Lumiera  0.pre.03
»edit your freedom«
allocation-cluster.hpp
Go to the documentation of this file.
1 /*
2  ALLOCATION-CLUSTER.hpp - 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 
58 #ifndef LIB_ALLOCATION_CLUSTER_H
59 #define LIB_ALLOCATION_CLUSTER_H
60 
61 #include "lib/error.hpp"
62 #include "lib/nocopy.hpp"
63 
64 #include <type_traits>
65 #include <utility>
66 #include <memory>
67 
68 
69 
70 namespace lib {
71  namespace test { class AllocationCluster_test; } // declared friend for low-level-checks
72  namespace err = lumiera::error;
73 
74 
89  {
90  class StorageManager;
91 
93  struct Storage
94  {
95  void* pos{nullptr};
96  size_t rest{0};
97 
98  auto bytePos() { return static_cast<std::byte*> (pos); }
99 
100  void*
101  allot (size_t bytes, size_t alignment)
102  {
103  void* loc = std::align (alignment, bytes, pos, rest);
104  if (loc)
105  { // requested allocation indeed fits in space
106  pos = bytePos() + bytes;
107  rest -= bytes;
108  }
109  return loc;
110  }
111 
112  void adjustPos (int offset);
113  bool hasReserve (int offset) const;
114  bool matches_last_allocation (void const* loc, size_t siz) const;
115  };
116  Storage storage_;
117 
118 
119  public:
121  ~AllocationCluster () noexcept;
122 
124  static size_t constexpr EXTENT_SIZ = 256;
125  static size_t constexpr max_size();
126 
127 
128  /* === diagnostics === */
129  size_t numExtents() const;
130  size_t numBytes() const;
131 
132 
133  template<class TY, typename...ARGS>
134  TY& create (ARGS&& ...);
135 
136  template<class TY, typename...ARGS>
137  TY& createDisposable (ARGS&& ...);
138 
139 
140  template<typename X>
141  struct Allocator
142  {
143  using value_type = X;
144 
145  [[nodiscard]] X* allocate (size_t n) { return mother_->allot<X>(n); }
146  void deallocate (X*, size_t) noexcept { /* rejoice */ }
147 
148  Allocator(AllocationCluster* m) : mother_{m} { }
149  // standard copy acceptable
150  template<typename T>
151  Allocator(Allocator<T> const& o) : mother_{o.mother_} { }
152 
153  template<typename T>
154  bool operator== (Allocator<T> const& o) const { return mother_ == o.mother_; }
155 
156  AllocationCluster* mother_;
157  };
158 
159  template<typename X>
160  Allocator<X> getAllocator() { return this; }
161 
162 
163  bool canAdjust (void* loc, size_t oldSiz, size_t newSiz) const;
164  void doAdjust (void* loc, size_t oldSiz, size_t newSiz);
165 
166  private:
171  void*
172  allotMemory (size_t bytes, size_t alignment)
173  {
174  __enforce_limits (bytes, alignment);
175  void* loc = storage_.allot(bytes, alignment);
176  if (loc) return loc;
177  expandStorage (bytes);
178  return allotMemory (bytes, alignment);
179  }
180 
181  template<typename X>
182  X*
183  allot (size_t cnt =1)
184  {
185  return static_cast<X*> (allotMemory (cnt * sizeof(X), alignof(X)));
186  }
187 
188 
191  {
192  public:
193  virtual ~Destructor();
194  Destructor* next{nullptr};// intrusive linked list...
195  };
196 
200  template<typename X>
202  : Destructor
203  {
204  X payload;
205 
206  template<typename...ARGS>
207  AllocationWithDestructor (ARGS&& ...args)
208  : payload(std::forward<ARGS> (args)...)
209  { }
210  };
211 
212  void expandStorage (size_t);
213  void registerDestructor (Destructor&);
214  void __enforce_limits (size_t,size_t);
215 
216  friend class test::AllocationCluster_test;
217  };
218 
219 
220 
221 
222 
223  //-----implementation-details------------------------
224 
233  size_t constexpr
235  {
236  size_t ADMIN_OVERHEAD = 2 * sizeof(void*);
237  return EXTENT_SIZ - ADMIN_OVERHEAD;
238  }
239 
244  template<class TY, typename...ARGS>
245  inline TY&
246  AllocationCluster::createDisposable (ARGS&& ...args)
247  {
248  return * new(allot<TY>()) TY (std::forward<ARGS> (args)...);
249  }
250 
256  template<class TY, typename...ARGS>
257  inline TY&
258  AllocationCluster::create (ARGS&& ...args)
259  {
260  if constexpr (std::is_trivial_v<TY>)
261  return createDisposable<TY> (std::forward<ARGS> (args)...);
262 
263  using Frame = AllocationWithDestructor<TY>;
264  auto& frame = createDisposable<Frame> (std::forward<ARGS> (args)...);
265  registerDestructor (frame);
266  return frame.payload;
267  }
268 
269 
282  inline void
283  AllocationCluster::doAdjust(void* loc, size_t oldSiz, size_t newSiz)
284  {
285  if (not canAdjust (loc,oldSiz,newSiz))
286  throw err::Invalid {"AllocationCluster: unable to perform this allocation adjustment."};
287  storage_.adjustPos (int(newSiz) - int(oldSiz));
288  }
289 
290  inline bool
291  AllocationCluster::canAdjust(void* loc, size_t oldSiz, size_t newSiz) const
292  {
293  int offset{int(newSiz) - int(oldSiz)}; // is properly limited iff oldSiz is correct
294  return storage_.matches_last_allocation (loc, oldSiz)
295  and storage_.hasReserve (offset);
296  }
297 
298  inline void
300  {
301  REQUIRE (pos);
302  REQUIRE (hasReserve (offset));
303  pos = bytePos() + offset;
304  rest -= offset;
305  }
306 
307  inline bool
308  AllocationCluster::Storage::hasReserve (int offset) const
309  {
310  return offset <= int(rest);
311  }
312 
313  inline bool
314  AllocationCluster::Storage::matches_last_allocation (void const* loc, size_t siz) const
315  {
316  return loc == static_cast<std::byte const*> (pos) - siz;
317  }
318 
319 
320 
321 
322 
323  //-----Policies-to-use-AllocationCluster------------------------
324 
325  namespace allo { // Setup for custom allocator policies
326 
327  // Forward declaration: configuration policy for lib::SeveralBuilder
328  template<class I, class E, template<typename> class ALO>
330 
331  template<template<typename> class ALO, typename...ARGS>
332  struct SetupSeveral;
333 
346  template<>
348  {
349  template<typename X>
350  using Adapter = typename AllocationCluster::template Allocator<X>;
351 
352  template<class I, class E>
353  struct Policy
354  : AllocationPolicy<I,E,Adapter>
355  {
357  using Bucket = typename Base::Bucket;
358 
360  size_t static constexpr ALLOC_LIMIT = AllocationCluster::max_size();
361 
362 
363  Policy (AllocationCluster& clu)
364  : AllocationPolicy<I,E,Adapter> (clu.getAllocator<std::byte>())
365  { }
366 
367  bool
368  canExpand (Bucket* bucket, size_t request)
369  {
370  if (not bucket) return false;
371  size_t currSize = bucket->getAllocSize();
372  long delta = long(request) - long(bucket->buffSiz);
373  return this->mother_->canAdjust (bucket,currSize, currSize+delta);
374  }
375 
376  Bucket*
377  realloc (Bucket* bucket, size_t cnt, size_t spread)
378  {
379  size_t request = cnt*spread;
380  REQUIRE (request);
381  if (not canExpand (bucket,request))
382  return Base::realloc (bucket,cnt,spread);
383 
384  size_t currSize = bucket->getAllocSize();
385  size_t delta = request - bucket->buffSiz;
386  this->mother_->doAdjust (bucket, currSize, currSize+delta);
387  bucket->buffSiz += delta;
388  ENSURE (bucket->buffSiz == request);
389  return bucket;
390  }
391  };
392  };
393  //
394  }//(End)Allocator configuration
395 
396 
397 } // namespace lib
398 #endif /*LIB_ALLOCATION_CLUSTER_H*/
std::function< UICoord(UICoord)> Allocator
Allocator is a functor to resolve a given, desired location of a view within the UI, resulting in creation or allocation of the view – which happens as side-effect. The result of this invocation are the UI coordinates of an existing or newly created view.
void doAdjust(void *loc, size_t oldSiz, size_t newSiz)
Adjust the size of the latest raw memory allocation dynamically.
Definition: run.hpp:40
An overlay view for the AllocationCluster to add functionality for adding / clearing extents and regi...
Any copy and copy construction prohibited.
Definition: nocopy.hpp:37
STL namespace.
Types marked with this mix-in may be moved but not copied.
Definition: nocopy.hpp:49
bool operator==(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
Supporting equality comparisons...
Extension point: how to configure the SeveralBuilder to use an allocator ALO, initialised by ARGS...
Implementation namespace for support and library code.
void * allotMemory(size_t bytes, size_t alignment)
portion out the requested amount of memory, possibly claiming a new pool block.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Lumiera error handling (C++ interface).
A pile of objects sharing common allocation and lifecycle.
Policy Mix-In used to adapt to the ElementFactory and Allocator.
maintaining the Allocation
static size_t constexpr max_size()
Maximum individual allocation size that can be handled.