Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
allocator-handle.hpp
Go to the documentation of this file.
1/*
2 ALLOCATOR-HANDLE.hpp - front-end handle for custom allocation schemes
3
4 Copyright (C)
5 2023, 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
47#ifndef LIB_ALLOCATOR_HANDLE_H
48#define LIB_ALLOCATOR_HANDLE_H
49
50#include "lib/error.hpp"
51
52#include <cstddef>
53#include <utility>
54#include <list>
55
56
57
58namespace lib {
59 namespace allo {
60
66
67
86 template<class ALO>
88 : private ALO
89 {
90 using Allo = ALO;
91 using AlloT = std::allocator_traits<Allo>;
92 using BaseType = Allo::value_type;
93
94 Allo& baseAllocator() { return *this; }
95
96 template<typename X>
97 auto
99 {
100 using XAllo = AlloT::template rebind_alloc<X>;
101 if constexpr (std::is_constructible_v<XAllo, Allo>)
102 return XAllo{baseAllocator()};
103 else
104 return XAllo{};
105 }
106
107 template<class ALOT, typename...ARGS>
108 ALOT::pointer
109 construct (ALOT::allocator_type& allo, ARGS&& ...args)
110 {
111 auto loc = ALOT::allocate (allo, 1);
112 try { ALOT::construct (allo, loc, std::forward<ARGS>(args)...); }
113 catch(...)
114 {
115 ALOT::deallocate (allo, loc, 1);
116 throw;
117 }
118 return loc;
119 }
120
121 template<class ALOT>
122 void
123 destroy (ALOT::allocator_type& allo, ALOT::pointer elm)
124 {
125 ALOT::destroy (allo, elm);
126 ALOT::deallocate (allo, elm, 1);
127 }
128
129
130 public:
143 : Allo{std::move (allo)}
144 { }
145
146 template<class XALO>
147 bool constexpr operator== (StdFactory<XALO> const& o) const
148 {
149 return baseAllocator() == o.baseAllocator();
150 }
151 template<class XALO>
152 bool constexpr operator!= (StdFactory<XALO> const& o) const
153 {
154 return not (*this == o);
155 }
156
157
158
160 template<class TY, typename...ARGS>
161 TY*
162 create (ARGS&& ...args)
163 {
164 if constexpr (std::is_same_v<TY, BaseType>)
165 {
166 return construct<AlloT> (baseAllocator(), std::forward<ARGS>(args)...);
167 }
168 else
169 {
170 using XAlloT = AlloT::template rebind_traits<TY>;
171 auto xAllo = adaptAllocator<TY>();
172 return construct<XAlloT> (xAllo, std::forward<ARGS>(args)...);
173 }
174 }
175
177 template<class TY>
178 void
179 dispose (TY* elm)
180 {
181 if constexpr (std::is_same_v<TY, BaseType>)
182 {
183 destroy<AlloT> (baseAllocator(), elm);
184 }
185 else
186 {
187 using XAlloT = AlloT::template rebind_traits<TY>;
188 auto xAllo = adaptAllocator<TY>();
189 destroy<XAlloT> (xAllo, elm);
190 }
191 }
192 };
193
194
195
196
198 template<class FAC>
200 : std::__and_< std::is_empty<FAC>
201 , std::is_default_constructible<FAC>
202 >
203 { };
204 template<class FAC>
206
207
208
209
210
222 template<class FAC>
224 : protected FAC
225 {
226 template<typename TY>
227 static void
228 dispose (TY* elm)
229 {
230 FAC factory;
231 factory.dispose (elm);
232 };
233
234 template<typename TY>
236 : protected FAC
237 {
238 void
239 operator() (TY* elm)
240 {
241 FAC::dispose (elm);
242 }
243
244 StatefulDeleter (FAC const& anchor)
245 : FAC{anchor}
246 { }
247 };
248
249
250 public:
251 OwnUniqueAdapter (FAC const& factory)
252 : FAC{factory}
253 { }
254 using FAC::FAC;
255
259 template<class TY, typename...ARGS>
260 auto
261 make_unique (ARGS&& ...args)
262 {
263 if constexpr (is_Stateless_v<FAC>)
264 {
265 using Handle = std::unique_ptr<TY, void(TY*)>;
266 return Handle{FAC::template create<TY> (std::forward<ARGS> (args)...)
268 };
269 }
270 else
271 {
272 using Handle = std::unique_ptr<TY, StatefulDeleter<TY>>;
273 return Handle{FAC::template create<TY> (std::forward<ARGS> (args)...)
274 , StatefulDeleter<TY>{*this}
275 };
276 }
277 }
278 };
279 }
280
281
283
295 template<typename TY>
297 {
299 {
300 alignas(TY)
301 std::byte buf_[sizeof(TY)];
302
303 template<typename...ARGS>
304 TY&
305 create (ARGS&& ...args)
306 {
307 return *new(&buf_) TY {std::forward<ARGS> (args)...};
308 }
309
310 TY&
312 {
313 return * std::launder (reinterpret_cast<TY*> (&buf_));
314 }
315 void
317 {
318 access().~TY();
319 }
320 };
321
322 std::list<Allocation> storage_;
323
324 public:
325 template<typename...ARGS>
326 TY&
327 operator() (ARGS&& ...args)
328 { // EX_STRONG
329 auto pos = storage_.emplace (storage_.end());
330 try {
331 return pos->create (std::forward<ARGS> (args)...);
332 }
333 catch(...)
334 {
335 storage_.erase (pos); // EX_FREE
336
337 CStr errID = lumiera_error();
338 ERROR (memory, "Allocation failed with unknown exception. "
339 "Lumiera errorID=%s", errID?errID:"??");
340 throw;
341 }
342 }
343
348 try {
349 for (auto& alloc : storage_)
350 alloc.discard();
351 }
352 ERROR_LOG_AND_IGNORE (memory, "clean-up of custom AllocatorHandle")
353 };
354
355
356
357} // namespace lib
358#endif /*LIB_ALLOCATOR_HANDLE_H*/
Placeholder implementation for a custom allocator.
TY & operator()(ARGS &&...args)
std::list< Allocation > storage_
Generic opaque reference counting handle, for accessing a service and managing its lifecycle.
Definition handle.hpp:64
Adapter to use a generic factory FAC for creating managed object instances with unique ownership.
auto make_unique(ARGS &&...args)
Factory function: generate object with scoped ownership and automated clean-up.
OwnUniqueAdapter(FAC const &factory)
< Concepts and Adaptors for custom memory management
bool constexpr operator!=(StdFactory< XALO > const &o) const
std::allocator_traits< Allo > AlloT
ALOT::pointer construct(ALOT::allocator_type &allo, ARGS &&...args)
TY * create(ARGS &&...args)
create new element using the embedded allocator
void destroy(ALOT::allocator_type &allo, ALOT::pointer elm)
Allo::value_type BaseType
StdFactory(Allo allo=Allo{})
Create an instance of the adapter factory, forwarding to the embedded standard conforming allocator f...
bool constexpr operator==(StdFactory< XALO > const &o) const
void dispose(TY *elm)
destroy the given element and discard the associated memory
lumiera_err lumiera_error(void)
Get and clear current error state.
Lumiera error handling (C++ interface).
#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:267
const char * CStr
Definition error.hpp:42
Implementation namespace for support and library code.
STL namespace.
Metafunction: probe if the given base factory is possibly monostate.