76 #ifndef LIB_LAZY_INIT_H 77 #define LIB_LAZY_INIT_H 101 using RawAddr =
void const*;
107 captureRawAddrOffset (RawAddr anchor, RawAddr subject)
111 char* anchorAddr =
reinterpret_cast<char*
> (unConst(anchor));
112 char* subjectAddr =
reinterpret_cast<char*
> (unConst(subject));
113 return subjectAddr - anchorAddr;
118 relocate (RawAddr anchor, ptrdiff_t offset)
120 char* anchorAddr =
reinterpret_cast<char*
> (unConst(anchor));
121 char* adjusted = anchorAddr + offset;
122 void* rawTarget =
reinterpret_cast<void*
> (adjusted);
123 return static_cast<TAR*
> (rawTarget);
138 std::function<RawAddr(void)> probe = [slot]{
return RawAddr(&slot); };
139 RawAddr functor = &probe;
140 RawAddr payload = probe();
141 if (not util::isCloseBy(functor, payload))
142 throw err::Fatal{
"Unable to use lib::LazyInit because std::function does not " 143 "apply small-object optimisation with inline storage."};
144 return captureRawAddrOffset (functor,payload);
160 template<
class DEL,
typename RET,
typename... ARGS>
162 buildTrapActivator (DEL* delegate,
_Fun<RET(ARGS...)>)
165 (ARGS ...args) -> RET
167 auto currLocation = &delegate;
168 auto& functor = (*delegate) (currLocation);
170 return functor (forward<ARGS> (args)...);
190 static_assert (
_Fun<DEL>(),
"Delegate must be function-like");
192 static_assert (
_Fun<Ret>(),
"Result from invoking delegate must also be function-like");
193 static_assert (
has_Sig<Ret, SIG>(),
"Result from delegate must expose target signature");
197 return buildTrapActivator (delegate,
_Fun<SIG>());
214 template<
class PAR =EmptyBase>
219 using DelegateType = std::function<std::function<SIG>&(RawAddr)>;
221 using PlaceholderType = DelegateType<void(void)>;
233 throw err::State{
"Component was already configured with a processing function, " 234 "which binds into a fixed object location. It can not be moved anymore." 235 , err::LUMIERA_ERROR_LIFECYCLE};
243 throw err::State{
"Component was already configured with a processing function, " 244 "which binds into a fixed object location. It can not be moved anymore." 245 , err::LUMIERA_ERROR_LIFECYCLE};
255 template<
typename...ARGS>
257 : PAR(forward<ARGS> (parentCtorArgs)...)
264 template<
class SIG,
class INI,
typename...ARGS>
265 LazyInit (std::function<SIG>& targetFunctor, INI&& initialiser, ARGS&& ...parentCtorArgs)
266 : PAR(forward<ARGS> (parentCtorArgs)...)
269 installInitialiser (targetFunctor, forward<INI> (initialiser));
280 , pendingInit_{__trapLocked (move(rref.pendingInit_))}
286 if (not util::isSameObject (ref, *
this))
288 PAR::operator= (ref);
297 if (not util::isSameObject (rref, *
this))
299 PAR::operator= (move (rref));
300 pendingInit_ = __trapLocked (move (rref.pendingInit_));
309 return not pendingInit_;
314 installEmptyInitialiser()
316 pendingInit_.reset (
new HeapStorage{emptyInitialiser<SIG>()});
319 template<
class SIG,
class INI>
321 installInitialiser (std::function<SIG>& targetFunctor, INI&& initialiser)
323 pendingInit_ = prepareInitialiser (targetFunctor, forward<INI> (initialiser));
332 using TargetFun = std::function<SIG>;
333 return DelegateType<SIG>([disabledFunctor = TargetFun()]
334 (RawAddr) -> TargetFun&
336 return disabledFunctor;
340 template<
class SIG,
class INI>
342 prepareInitialiser (std::function<SIG>& targetFunctor, INI&& initialiser)
344 if (isInit() and targetFunctor)
346 using ExpectedArg = _FunArg<INI>;
347 initialiser (static_cast<ExpectedArg> (
this));
353 buildInitialiserDelegate (targetFunctor, forward<INI> (initialiser))}};
356 return storageHandle;
360 static DelegateType<SIG>*
363 return reinterpret_cast<DelegateType<SIG>*
> (&buffer);
367 static std::function<SIG>
368 maybeInvoke (
PendingInit const& pendingInit, RawAddr location)
371 return std::function<SIG>();
372 auto* pendingDelegate = getPointerToDelegate<SIG>(*pendingInit);
373 return (*pendingDelegate) (location);
376 template<
class SIG,
class INI>
378 buildInitialiserDelegate (std::function<SIG>& targetFunctor, INI&& initialiser)
380 using TargetFun = std::function<SIG>;
381 using ExpectedArg = _FunArg<INI>;
382 return DelegateType<SIG>{
383 [performInit = forward<INI> (initialiser)
384 ,previousInit = move (pendingInit_)
385 ,targetOffset = captureRawAddrOffset (
this, &targetFunctor)]
386 (RawAddr location) -> TargetFun&
389 LazyInit*
self = relocate<LazyInit> (target, -targetOffset);
392 auto storageHandle = move(self->pendingInit_);
394 (*target) = maybeInvoke<SIG> (previousInit, location);
396 performInit (static_cast<ExpectedArg> (
self));
»Trojan Function« builder.
LazyInit(std::function< SIG > &targetFunctor, INI &&initialiser, ARGS &&...parentCtorArgs)
prepare an initialiser to be activated on first use
Mix-in for lazy/delayed initialisation of an embedded functor.
static auto generateTrap(DEL *delegate)
Invocation: build a Lambda to activate the »Trap« and then to forward the invocation to the actual fu...
Lumiera error handling (C interface).
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera's exception hierarchy.
Metaprogramming tools for transforming functor types.
LazyInit(MarkDisabled, ARGS &&...parentCtorArgs)
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Helper allowing type erasure while holding the actual object inline.
typename _DetectSingleArgFunction< FUN >::Arg _FunArg
abbreviation for referring to a function's single Argument type
PendingInit pendingInit_
manage heap storage for a pending initialisation closure
Buffer to place and maintain an object instance privately within another object.
const ptrdiff_t FUNCTOR_PAYLOAD_OFFSET