Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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
70namespace 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 };
117
118
119 public:
121 ~AllocationCluster () noexcept;
122
124 static constexpr size_t EXTENT_SIZ = 256;
125 static constexpr size_t 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>
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
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 {
205
206 template<typename...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
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&
247 {
248 return * new(allot<TY>()) TY (std::forward<ARGS> (args)...);
249 }
250
256 template<class TY, typename...ARGS>
257 inline TY&
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
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>
329 struct AllocationPolicy;
330
331 template<template<typename> class ALO, typename...ARGS>
333
346 template<>
348 {
349 template<typename X>
350 using Adapter = AllocationCluster::template Allocator<X>;
351
352 template<class I, class E>
353 struct Policy
354 : AllocationPolicy<I,E,Adapter>
355 {
358
360 size_t static constexpr ALLOC_LIMIT = AllocationCluster::max_size();
361
362
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*/
virtual ~Destructor()
this is an interface
An overlay view for the AllocationCluster to add functionality for adding / clearing extents and regi...
A pile of objects sharing common allocation and lifecycle.
~AllocationCluster() noexcept
The shutdown of an AllocationCluster walks all extents and invokes all registered deleter functions a...
void expandStorage(size_t)
Expand the alloted storage pool by a block, suitable to accommodate at least the indicated request.
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...
void * allotMemory(size_t bytes, size_t alignment)
portion out the requested amount of memory, possibly claiming a new pool block.
static constexpr size_t EXTENT_SIZ
hard wired size of storage extents
void doAdjust(void *loc, size_t oldSiz, size_t newSiz)
Adjust the size of the latest raw memory allocation dynamically.
AllocationCluster()
Prepare a new clustered allocation to be expanded by extents of size EXTENT_SIZ, yet discarded all at...
bool canAdjust(void *loc, size_t oldSiz, size_t newSiz) const
void registerDestructor(Destructor &)
TY & createDisposable(ARGS &&...)
static constexpr size_t max_size()
Maximum individual allocation size that can be handled.
TY & create(ARGS &&...)
Derived specific exceptions within Lumiera's exception hierarchy.
Definition error.hpp:193
Types marked with this mix-in may be moved but not copied.
Definition nocopy.hpp:50
Any copy and copy construction prohibited.
Definition nocopy.hpp:38
Lumiera error handling (C++ interface).
Extension point: how to configure the SeveralBuilder to use an allocator ALO, initialised by ARGS.
Implementation namespace for support and library code.
bool operator==(PtrDerefIter< I1 > const &il, PtrDerefIter< I2 > const &ir)
Supporting equality comparisons...
STL namespace.
Test runner and basic definitions for tests.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
void deallocate(X *, size_t) noexcept
bool matches_last_allocation(void const *loc, size_t siz) const
void * allot(size_t bytes, size_t alignment)
Policy Mix-In used to adapt to the ElementFactory and Allocator.