Lumiera  0.pre.03
»edit your freedom«
verb-visitor.hpp File Reference

Go to the source code of this file.

Description

A specific double dispatch variation for function invocation.

While the classic visitor invokes a common handle function with varying arguments, here we allow for pre-binding of arbitrary handler functions on an interface with together with individual, suitable arguments. Yet similar to the classic visitor, the actual receiver can be a subclass of the visitor target interface, which causes the second indirection in the dispatch chain, thus completing a full double-dispatch. Since the actually distinguishing factor is not so much a type, but a specific operation, we refer to the delayed invocation handles created by this binding as verb token on a receiver object (which is the concrete visitor).

This setup is an extension or derivative of the generic verb token used for the diff system and similar applications; likewise the intended usage is to establish a language comprised of several abstract actions ("verbs"), but to allow the concrete operation to be supplied later, at application time, and within a different code context. The most notable use case is for the drawing of track contents in the user interface, where this pattern allows the separation of actual drawing code from the nested track controller structure.

implementation technique

The actual foundation is quite simple: we store a member pointer. Typically, this embedded pointer-to-member shall be bound to an abstract virtual function on the visitor interface. So basically the "verb" boils down to storing an offset into the VTable on the interface. Later, on invocation, a reference to the actual receiver is passed in, typically a concrete subclass of the visitor interface. The invocation then combines this receiver reference with the offset (the member pointer) to invoke the desired virtual function.

However, the complications and technicalities arise from the ability to bind arbitrary function signatures, even together with the actual arguments to use at invocation. Those function arguments are supplied when creating the "packaged verb", and thus need to be stored within this package, together with the member-pointer. The result is a materialised and delayed invocation of an abstract (interface) function, while the actual concrete function implementation shall be supplied later. Obviously, such a VerbPackverb pack"" has value semantics – we want to store it, copy it and pass it along, often even within a sequence of "verbs". And even more: we do not want to pass "hidden references" and we do not want to rely on some management service and heap allocations. Rather, each VerbPack shall be a self-contained value object. Within certain limitations, this is possible in C++ by using an opaque buffer embedded within the outer value object; basically the pre-defined buffer size must be sufficient to hold all possible argument tuples to bind.

The actual implementation here relies on two other components from the Lumiera library:

  • the lib::VerbToken provides us with the dispatch through a stored member pointer
  • the lib::PolymorphicValue allows to embed a subclass within an opaque inline buffer, just exposing the common interface. Yet another challenge is the necessity to unpack the argument values from the storage tuple and pass them to an (at this point abstracted) function with arbitrary signature. Here we rely on the common implementation technique from std::apply, here with the special twist that we don't use a pre-bound function, but rather need to combine the actual invocation target at the moment of the invocation.
See also
drawing on the track canvas
VerbVisitorDispatch_test

Definition in file verb-visitor.hpp.

#include "lib/meta/variadic-helper.hpp"
#include "lib/polymorphic-value.hpp"
#include "lib/verb-token.hpp"
#include "lib/symbol.hpp"
#include "lib/util.hpp"
#include <utility>
#include <string>
#include <tuple>

Classes

struct  VerbPack< REC, RET, arg_storage >::HandlerTypeDetector< FUN >
 
struct  VerbPack< REC, RET, arg_storage >::HandlerTypeDetector< RET(REC::*)(ARGS...)>
 
struct  VerbHolder< REC, SIG >
 
struct  VerbHolder< REC, RET(ARGS...)>
 Building block: actual storage for a "verb" (function pointer), together with the pre-bound invocation arguments for this specific operation. More...
 
struct  VerbInvoker< REC, RET >
 Building block: the Interface to cause the invocation. More...
 
class  VerbPack< REC, RET, arg_storage >
 A self-contained token to embody a specific yet abstracted operation, together with a concrete set of suitable arguments. More...
 

Typedefs

using JustSomeIrrelvantType = struct{}
 

Functions

constexpr size_t storageOverhead (size_t argStorage)
 

Variables

const size_t VERB_TOKEN_SIZE = sizeof(VerbToken<JustSomeIrrelvantType, void(void)>)
 

Namespaces

 lib
 Implementation namespace for support and library code.
 

Class Documentation

◆ lib::VerbPack::HandlerTypeDetector

struct lib::VerbPack::HandlerTypeDetector
+ Collaboration diagram for VerbPack< REC, RET, arg_storage >::HandlerTypeDetector< FUN >:

◆ lib::VerbPack::HandlerTypeDetector< RET(REC::*)(ARGS...)>

struct lib::VerbPack::HandlerTypeDetector< RET(REC::*)(ARGS...)>
Class Members
Verb
Payload
+ Collaboration diagram for VerbPack< REC, RET, arg_storage >::HandlerTypeDetector< RET(REC::*)(ARGS...)>:

◆ lib::VerbHolder

struct lib::VerbHolder
+ Collaboration diagram for VerbHolder< REC, SIG >: