Lumiera  0.pre.03
»edit your freedom«
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 
58 namespace lib {
59  namespace allo {
60 
66 
67 
86  template<class ALO>
87  class StdFactory
88  : private ALO
89  {
90  using Allo = ALO;
91  using AlloT = std::allocator_traits<Allo>;
92  using BaseType = typename Allo::value_type;
93 
94  Allo& baseAllocator() { return *this; }
95 
96  template<typename X>
97  auto
98  adaptAllocator()
99  {
100  using XAllo = typename 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  typename ALOT::pointer
109  construct (typename 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 (typename ALOT::allocator_type& allo, typename ALOT::pointer elm)
124  {
125  ALOT::destroy (allo, elm);
126  ALOT::deallocate (allo, elm, 1);
127  }
128 
129 
130  public:
142  StdFactory (Allo allo = Allo{})
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 = typename 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 = typename 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>
205  auto is_Stateless_v = is_Stateless<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  {
298  struct Allocation
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&
311  access()
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  const char* 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*/
Adapter to use a generic factory FAC for creating managed object instances with unique ownership...
Generic opaque reference counting handle, for accessing a service and managing its lifecycle...
Definition: handle.hpp:63
< Concepts and Adaptors for custom memory management
void dispose(TY *elm)
destroy the given element and discard the associated memory
TY * create(ARGS &&...args)
create new element using the embedded allocator
#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
Metafunction: probe if the given base factory is possibly monostate.
StdFactory(Allo allo=Allo{})
Create an instance of the adapter factory, forwarding to the embedded standard conforming allocator f...
Implementation namespace for support and library code.
Placeholder implementation for a custom allocator.
lumiera_err lumiera_error(void)
Get and clear current error state.
Definition: error-state.c:115
Lumiera error handling (C++ interface).
static void dispose(TY *elm)
auto make_unique(ARGS &&...args)
Factory function: generate object with scoped ownership and automated clean-up.