67 #ifndef LIB_LAZY_INIT_H 68 #define LIB_LAZY_INIT_H 92 using RawAddr =
void const*;
98 captureRawAddrOffset (RawAddr anchor, RawAddr subject)
102 char* anchorAddr =
reinterpret_cast<char*
> (unConst(anchor));
103 char* subjectAddr =
reinterpret_cast<char*
> (unConst(subject));
104 return subjectAddr - anchorAddr;
109 relocate (RawAddr anchor, ptrdiff_t offset)
111 char* anchorAddr =
reinterpret_cast<char*
> (unConst(anchor));
112 char* adjusted = anchorAddr + offset;
113 void* rawTarget =
reinterpret_cast<void*
> (adjusted);
114 return static_cast<TAR*
> (rawTarget);
129 std::function<RawAddr(void)> probe = [slot]{
return RawAddr(&slot); };
130 RawAddr functor = &probe;
131 RawAddr payload = probe();
132 if (not util::isCloseBy(functor, payload))
133 throw err::Fatal{
"Unable to use lib::LazyInit because std::function does not " 134 "apply small-object optimisation with inline storage."};
135 return captureRawAddrOffset (functor,payload);
151 template<
class DEL,
typename RET,
typename... ARGS>
153 buildTrapActivator (DEL* delegate,
_Fun<RET(ARGS...)>)
156 (ARGS ...args) -> RET
158 auto currLocation = &delegate;
159 auto& functor = (*delegate) (currLocation);
161 return functor (forward<ARGS> (args)...);
181 static_assert (
_Fun<DEL>(),
"Delegate must be function-like");
183 static_assert (
_Fun<Ret>(),
"Result from invoking delegate must also be function-like");
184 static_assert (
has_Sig<Ret, SIG>(),
"Result from delegate must expose target signature");
188 return buildTrapActivator (delegate,
_Fun<SIG>());
205 template<
class PAR =EmptyBase>
210 using DelegateType = std::function<std::function<SIG>&(RawAddr)>;
212 using PlaceholderType = DelegateType<void(void)>;
224 throw err::State{
"Component was already configured with a processing function, " 225 "which binds into a fixed object location. It can not be moved anymore." 226 , err::LUMIERA_ERROR_LIFECYCLE};
234 throw err::State{
"Component was already configured with a processing function, " 235 "which binds into a fixed object location. It can not be moved anymore." 236 , err::LUMIERA_ERROR_LIFECYCLE};
246 template<
typename...ARGS>
248 : PAR(forward<ARGS> (parentCtorArgs)...)
255 template<
class SIG,
class INI,
typename...ARGS>
256 LazyInit (std::function<SIG>& targetFunctor, INI&& initialiser, ARGS&& ...parentCtorArgs)
257 : PAR(forward<ARGS> (parentCtorArgs)...)
260 installInitialiser (targetFunctor, forward<INI> (initialiser));
271 , pendingInit_{__trapLocked (move(rref.pendingInit_))}
277 if (not util::isSameObject (ref, *
this))
279 PAR::operator= (ref);
288 if (not util::isSameObject (rref, *
this))
290 PAR::operator= (move (rref));
291 pendingInit_ = __trapLocked (move (rref.pendingInit_));
300 return not pendingInit_;
305 installEmptyInitialiser()
307 pendingInit_.reset (
new HeapStorage{emptyInitialiser<SIG>()});
310 template<
class SIG,
class INI>
312 installInitialiser (std::function<SIG>& targetFunctor, INI&& initialiser)
314 pendingInit_ = prepareInitialiser (targetFunctor, forward<INI> (initialiser));
323 using TargetFun = std::function<SIG>;
324 return DelegateType<SIG>([disabledFunctor = TargetFun()]
325 (RawAddr) -> TargetFun&
327 return disabledFunctor;
331 template<
class SIG,
class INI>
333 prepareInitialiser (std::function<SIG>& targetFunctor, INI&& initialiser)
335 if (isInit() and targetFunctor)
337 using ExpectedArg = _FunArg<INI>;
338 initialiser (static_cast<ExpectedArg> (
this));
344 buildInitialiserDelegate (targetFunctor, forward<INI> (initialiser))}};
347 return storageHandle;
351 static DelegateType<SIG>*
354 return reinterpret_cast<DelegateType<SIG>*
> (&buffer);
358 static std::function<SIG>
359 maybeInvoke (
PendingInit const& pendingInit, RawAddr location)
362 return std::function<SIG>();
363 auto* pendingDelegate = getPointerToDelegate<SIG>(*pendingInit);
364 return (*pendingDelegate) (location);
367 template<
class SIG,
class INI>
369 buildInitialiserDelegate (std::function<SIG>& targetFunctor, INI&& initialiser)
371 using TargetFun = std::function<SIG>;
372 using ExpectedArg = _FunArg<INI>;
373 return DelegateType<SIG>{
374 [performInit = forward<INI> (initialiser)
375 ,previousInit = move (pendingInit_)
376 ,targetOffset = captureRawAddrOffset (
this, &targetFunctor)]
377 (RawAddr location) -> TargetFun&
380 LazyInit*
self = relocate<LazyInit> (target, -targetOffset);
383 auto storageHandle = move(self->pendingInit_);
385 (*target) = maybeInvoke<SIG> (previousInit, location);
387 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