Lumiera  0.pre.03
»edit your freedom«
lazy-init.hpp File Reference

Go to the source code of this file.

Description

Building block to allow delayed initialisation of infrastructure tied to a functor.

This solution is packaged as a mix-in template and engages a hidden mechanism with considerable trickery. It attempts to solve a problem arising notoriously when building elaborate processing by composing functions and user-provided configuration lambdas; the very point of this construction style is to tap into internal context to involve deep details of the implementation without the need to represent these as structures on API level. Unfortunately this has the consequence that capture-by-reference is all over the place, breeding instability. The only solution to defeat this instability is to lock an enclosing implementation scope into a fixed memory location, which boils down to using non-copyable classes. This solution may be in conflict to the intended use, especially when building DSLs, configuration frameworks or symbolic processing, where entities are value like from a semantic point of view. The solution pursued here is to define some linkage for operational state, which allows to lock a scope to a fixed memory location. Assuming that a typical usage scenario will first require setup, then proceed to processing, this solution attempts to tie the usage restrictions to the lifecycle — hopefully hiding the concern from users sight altogether.

Initialisation mechanism

This mix-in assumes that there is a function somewhere, which activates the actual processing, and this processing requires initialisation to be performed reliably before first use. Thus, a »trojan functor« is placed into this work-function, with the goal to activate a „trap“ on first use. This allows to invoke the actual initialisation, which is also configured as a functor, and which is the only part the client must provide actively, to activate the mechanism. Several initialisation steps can be attached consecutively, and will later be triggered in sequence.

There is one gory detail however: the initialisation hook needs the actual instance pointer valid at the time of actual initialisation. And since initialisation shall be performed automatically, the trap mechanism needs a way to derive this location, relying on minimal knowledge only. This challenge can only be overcome by assuming that the »trojan functor« itself is stored somehow embedded into the target object to be initialised. If there is a fixed distance relation in memory, then the target can be derived from the self-position of the functor; if this assumption is broken however, memory corruption and SEGFAULT might ensue. These assumptions are covered by an assertion and unit tests; as long as the function and the LazyInit instance are arranged in a fixed memory layout, this scheme should work. Do not place one or the other into a virtual base class though.

Todo:
11/2023 at the moment I am just desperately trying to get a bye-product of my main effort into usable shape and salvage an design idea that sounded clever on first thought. I am fully aware that »lazy initialisation« is something much more generic, but I am also aware of the potential of the solution coded here. Thus I'll claim that generic component name, assuming that time will tell if we need a more generic framework to serve this purpose eventually....
See also
LazyInit_test
lib::RandomDraw usage example
vault::gear::TestChainLoad::Rule where this setup matters

Definition in file lazy-init.hpp.

#include "lib/error.h"
#include "lib/meta/function.hpp"
#include "lib/opaque-holder.hpp"
#include "lib/util.hpp"
#include <functional>
#include <utility>
#include <memory>

Classes

struct  EmptyBase
 
class  LazyInit< PAR >
 Mix-in for lazy/delayed initialisation of an embedded functor. More...
 
struct  LazyInit< PAR >::MarkDisabled
 
class  TrojanFun< SIG >
 »Trojan Function« builder. More...
 

Typedefs

using RawAddr = void const *
 

Functions

ptrdiff_t captureRawAddrOffset (RawAddr anchor, RawAddr subject)
 
template<class TAR >
static TAR * relocate (RawAddr anchor, ptrdiff_t offset)
 

Variables

const ptrdiff_t FUNCTOR_PAYLOAD_OFFSET
 

Namespaces

 lib
 Implementation namespace for support and library code.
 

Class Documentation

◆ lib::LazyInit::MarkDisabled

struct lib::LazyInit::MarkDisabled
+ Collaboration diagram for LazyInit< PAR >::MarkDisabled: