Library: complete test coverage of VerbPack
This commit is contained in:
parent
3d5a67ed14
commit
f6e5886348
9 changed files with 427 additions and 223 deletions
|
|
@ -1530,7 +1530,7 @@ namespace lib {
|
|||
* which for the consumer side behave like `iterNext()` calls. If a layer needs to do something special for
|
||||
* `iterNext()`, it needs to perform a similar action for `expandChildren()`.
|
||||
* - it must be behave like a default-constructible, copyable value object
|
||||
* @return augmented TreeExplorer, incorporating and adpting the injected layer
|
||||
* @return augmented TreeExplorer, incorporating and adapting the injected layer
|
||||
*/
|
||||
template<template<class> class LAY>
|
||||
auto
|
||||
|
|
|
|||
|
|
@ -477,6 +477,12 @@ namespace lib {
|
|||
|
||||
typedef IFA Interface;
|
||||
|
||||
Interface&
|
||||
getPayload()
|
||||
{
|
||||
return accessEmbedded();
|
||||
}
|
||||
|
||||
operator Interface& ()
|
||||
{
|
||||
return accessEmbedded();
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ namespace lib {
|
|||
}
|
||||
|
||||
Literal const&
|
||||
getID()
|
||||
getID() const
|
||||
{
|
||||
return token_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,18 +111,28 @@ namespace lib {
|
|||
}
|
||||
|
||||
|
||||
/** Building block: the Interface to cause the invocation */
|
||||
template<class REC, class RET>
|
||||
struct VerbInvoker
|
||||
: polyvalue::CloneValueSupport<polyvalue::EmptyBase> // mark and mix-in virtual copy construction support
|
||||
{
|
||||
virtual ~VerbInvoker() { }
|
||||
|
||||
virtual RET applyTo (REC&) =0;
|
||||
virtual RET applyTo (REC&) =0;
|
||||
virtual Literal getID() const =0;
|
||||
|
||||
bool operator== (VerbInvoker const& o) const { return getID() == o.getID(); }
|
||||
bool operator!= (VerbInvoker const& o) const { return getID() != o.getID(); }
|
||||
};
|
||||
|
||||
|
||||
template<class REC, class SIG>
|
||||
struct VerbHolder;
|
||||
|
||||
/**
|
||||
* Building block: actual storage for a "verb" (function pointer),
|
||||
* together with the pre-bound invocation arguments for this specific operation.
|
||||
*/
|
||||
template<class REC, class RET, typename... ARGS>
|
||||
struct VerbHolder<REC, RET(ARGS...)>
|
||||
: VerbInvoker<REC,RET>
|
||||
|
|
@ -134,13 +144,21 @@ namespace lib {
|
|||
/** meta-sequence to pick argument values from the storage tuple */
|
||||
using SequenceIterator = typename meta::BuildIdxIter<ARGS...>::Ascending;
|
||||
|
||||
/** Storage for the argument tuple */
|
||||
Args args_;
|
||||
|
||||
VerbHolder (typename Verb::Handler handlerRef, Literal verbID, ARGS&&... args)
|
||||
template<typename...PARS>
|
||||
VerbHolder (typename Verb::Handler handlerRef, Literal verbID, PARS&&... args)
|
||||
: Verb{handlerRef, verbID}
|
||||
, args_{std::forward<ARGS> (args)...}
|
||||
, args_{std::forward<PARS> (args)...}
|
||||
{ }
|
||||
|
||||
Literal
|
||||
getID() const override
|
||||
{
|
||||
return Verb::getID();
|
||||
}
|
||||
|
||||
RET
|
||||
applyTo (REC& receiver) override
|
||||
{
|
||||
|
|
@ -148,45 +166,88 @@ namespace lib {
|
|||
}
|
||||
|
||||
private:
|
||||
/** @internal actual function invocation, thereby unpacking the argument tuple */
|
||||
template<size_t...idx>
|
||||
RET
|
||||
invokeVerb (REC& receiver, meta::IndexSeq<idx...>)
|
||||
{ //////////////////////////////////////////TICKET #1006 | TICKET #1184 why do we need std::forward here? the target is a "perfect forwarding" function, which should be able to receive a LValue reference to the tuple element just fine...
|
||||
return (receiver.*Verb::handler_)(std::get<idx> (args_)...);
|
||||
{
|
||||
return (receiver.*Verb::handler_) (std::get<idx> (args_)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/******************************************************************************************//**
|
||||
* A self-contained token to embody a specific yet abstracted operation,
|
||||
* together with a concrete set of suitable arguments. The concrete operation
|
||||
* is suppled on invocation, when the VerbPack is combined with an actual _receiver_
|
||||
* object, implementing the interface `REC` and thus providing the function implementation.
|
||||
* VerbPack represents a kind of double-dispatch, flexible both on the actual operation
|
||||
* (embodied into the given VerbPack object) and also flexible in the concrete receiver.
|
||||
* @tparam REC the "visitor interface" to invoke operations on
|
||||
* @tparam RET expected (common) return value of the bound operations (can be `void`)
|
||||
* @tparam arg_storage maximum storage size to reserve as buffer for actual function parameters.
|
||||
* @remarks
|
||||
* - binding an operation with arguments exceeding `arg_storage` triggers a static assertion
|
||||
* - the resulting VerbPack object has value semantics and is copyable, to the extent any
|
||||
* embedded function arguments are copyable by themselves.
|
||||
*/
|
||||
template<class REC, class RET, size_t arg_storage>
|
||||
class VerbPack
|
||||
: public PolymorphicValue<VerbInvoker<REC,RET>, storageOverhead(arg_storage)>
|
||||
{
|
||||
using PolyHolder = PolymorphicValue<VerbInvoker<REC,RET>, storageOverhead(arg_storage)>;
|
||||
using Dispatcher = VerbInvoker<REC,RET>; // the interface to talk to our payload
|
||||
using PolyHolder = PolymorphicValue<Dispatcher, storageOverhead(arg_storage)>;
|
||||
|
||||
template<typename FUN>
|
||||
struct HandlerTypeDetector
|
||||
{
|
||||
static_assert (!sizeof(FUN), "handler must be a function member pointer for the given receiver");
|
||||
};
|
||||
template<typename...ARGS>
|
||||
using PayloadType = VerbHolder<REC, RET(ARGS...)>*;
|
||||
struct HandlerTypeDetector<RET (REC::*) (ARGS...)>
|
||||
{
|
||||
using Verb = VerbToken<REC, RET(ARGS...)>;
|
||||
using Payload = VerbHolder<REC, RET(ARGS...)>;
|
||||
};
|
||||
|
||||
template<typename FUN>
|
||||
using PayloadType = typename HandlerTypeDetector<FUN>::Payload *;
|
||||
|
||||
template<typename...ARGS>
|
||||
using Handler = typename VerbToken<REC, RET(ARGS...)>::Handler;
|
||||
|
||||
public:
|
||||
template<typename...ARGS>
|
||||
VerbPack (Handler<ARGS...> handler, Literal verbID, ARGS&&... args)
|
||||
: PolyHolder(PayloadType<ARGS...>(), handler, verbID, std::forward<ARGS>(args)...)
|
||||
/** setup a VerbPack for a given operation on the interface `REC`
|
||||
* @param handler function member-pointer to define the operation
|
||||
* @param verbID unique ID to designate the token; equality is based
|
||||
* on this `verbID`, all tokens with same ID count as equal
|
||||
* @param args arbitrary (yet suitable) arguments to pre-bind and use later
|
||||
* when actually invoking the operation on a concrete receiver
|
||||
*/
|
||||
template<typename FUN, typename...ARGS>
|
||||
VerbPack (FUN handler, Literal verbID, ARGS&&... args)
|
||||
: PolyHolder(PayloadType<FUN>(), handler, verbID, std::forward<ARGS>(args)...)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Core operation: invoke the operation for this "verb" with the pre-bound parameters
|
||||
* @param receiver a subclass of `REC`, providing the function to invoke
|
||||
* @return result of performing the actual operation
|
||||
*/
|
||||
RET
|
||||
applyTo (REC& receiver)
|
||||
{
|
||||
VerbInvoker<REC,RET>& dispatch(*this);
|
||||
return dispatch.applyTo (receiver);
|
||||
return PolyHolder::getPayload().applyTo (receiver);
|
||||
}
|
||||
|
||||
operator string() const
|
||||
{
|
||||
return "VerbPack("
|
||||
+ string{util::unConst(this)->getPayload().getID()}
|
||||
+ ")";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace lib
|
||||
} // namespace lib
|
||||
#endif /*LIB_VERB_VISITOR_H*/
|
||||
|
|
|
|||
|
|
@ -740,6 +740,17 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "verb token with embedded arguments" VerbVisitorDispatch_test <<END
|
||||
out-lit: dispatching VerbPack(woof) -> 'haw-hawhaw-hawhaw-hawhaw-haw'
|
||||
out-lit: dispatching VerbPack(honk) -> 'quaack-quaack!'
|
||||
out-lit: dispatching VerbPack(honk) -> 'Hoonk-Hoonk!'
|
||||
out-lit: dispatching VerbPack(woof) -> 'Woof..Woof..'
|
||||
out-lit: dispatching VerbPack(moo) -> 'Moo__Moo__Moo'
|
||||
out-lit: dispatching VerbPack(meh) -> 'Meh?'
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "VectorTransfer_test" VectorTransfer_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
|
|
|||
|
|
@ -43,18 +43,20 @@ namespace lib {
|
|||
namespace test{
|
||||
|
||||
|
||||
class Receiver
|
||||
{
|
||||
public:
|
||||
virtual ~Receiver() { } ///< this is an interface
|
||||
|
||||
virtual string woof() =0;
|
||||
virtual string honk() =0;
|
||||
virtual string moo() =0;
|
||||
virtual string meh() =0;
|
||||
};
|
||||
|
||||
namespace {
|
||||
namespace { // Test Fixture
|
||||
|
||||
/** the "visitor" interface to invoke */
|
||||
class Receiver
|
||||
{
|
||||
public:
|
||||
virtual ~Receiver() { } ///< this is an interface
|
||||
|
||||
virtual string woof() =0;
|
||||
virtual string honk() =0;
|
||||
virtual string moo() =0;
|
||||
virtual string meh() =0;
|
||||
};
|
||||
|
||||
const string BEGINNING("silence");
|
||||
|
||||
using Verb = VerbToken<Receiver, string(void)>;
|
||||
|
|
@ -65,53 +67,54 @@ namespace test{
|
|||
Verb VERB(Receiver, honk);
|
||||
Verb VERB(Receiver, moo);
|
||||
Verb VERB(Receiver, meh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* a receiver of verb-tokens,
|
||||
* which renders them verbosely
|
||||
*/
|
||||
class VerboseRenderer
|
||||
: public Receiver
|
||||
{
|
||||
string woof() { return "Woof-Woof!"; }
|
||||
string honk() { return "Honk-Honk!"; }
|
||||
string moo() { return "Moo-Moo!"; }
|
||||
string meh() { return "Meh!"; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Statefull receiver of verb-tokens.
|
||||
*/
|
||||
class RecollectingReceiver
|
||||
: public Receiver
|
||||
{
|
||||
string verb_;
|
||||
_Fmt fmt_;
|
||||
|
||||
string
|
||||
buildResultTerm (string nextToken)
|
||||
{
|
||||
string resultExpression (fmt_ % verb_ % nextToken);
|
||||
verb_ = nextToken;
|
||||
return resultExpression;
|
||||
}
|
||||
|
||||
|
||||
string woof() { return buildResultTerm (VERB_woof); }
|
||||
string honk() { return buildResultTerm (VERB_honk); }
|
||||
string moo() { return buildResultTerm (VERB_moo); }
|
||||
string meh() { return buildResultTerm (VERB_meh); }
|
||||
|
||||
|
||||
public:
|
||||
RecollectingReceiver()
|
||||
: verb_(BEGINNING)
|
||||
, fmt_("%s followed by %s")
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* a receiver of verb-tokens,
|
||||
* which renders them verbosely
|
||||
*/
|
||||
class VerboseRenderer
|
||||
: public Receiver
|
||||
{
|
||||
string woof() { return "Woof-Woof!"; }
|
||||
string honk() { return "Honk-Honk!"; }
|
||||
string moo() { return "Moo-Moo!"; }
|
||||
string meh() { return "Meh!"; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Statefull receiver of verb-tokens.
|
||||
*/
|
||||
class RecollectingReceiver
|
||||
: public Receiver
|
||||
{
|
||||
string verb_;
|
||||
_Fmt fmt_;
|
||||
|
||||
string
|
||||
buildResultTerm (string nextToken)
|
||||
{
|
||||
string resultExpression (fmt_ % verb_ % nextToken);
|
||||
verb_ = nextToken;
|
||||
return resultExpression;
|
||||
}
|
||||
|
||||
|
||||
string woof() { return buildResultTerm (VERB_woof); }
|
||||
string honk() { return buildResultTerm (VERB_honk); }
|
||||
string moo() { return buildResultTerm (VERB_moo); }
|
||||
string meh() { return buildResultTerm (VERB_meh); }
|
||||
|
||||
|
||||
public:
|
||||
RecollectingReceiver()
|
||||
: verb_(BEGINNING)
|
||||
, fmt_("%s followed by %s")
|
||||
{ }
|
||||
};
|
||||
|
||||
}//(End) Test fixture
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,118 +31,107 @@
|
|||
#include "lib/format-string.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/iter-tree-explorer.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
using std::string;
|
||||
using util::_Fmt;
|
||||
using util::join;
|
||||
using std::vector;
|
||||
using std::forward;
|
||||
using std::make_tuple;
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
///////////////////////////TODO : Debugging
|
||||
struct Trackr
|
||||
{
|
||||
size_t num;
|
||||
|
||||
Trackr (size_t val)
|
||||
: num(val)
|
||||
{
|
||||
cout <<"Trackr("<<val<<")"<<endl;
|
||||
}
|
||||
~Trackr()
|
||||
{
|
||||
cout <<"~Trackr()"<<endl;
|
||||
}
|
||||
Trackr (Trackr const& lval)
|
||||
: num(lval.num)
|
||||
{
|
||||
cout <<"Trackr()<<-LVal"<<endl;
|
||||
}
|
||||
Trackr (Trackr && rval)
|
||||
: num(rval.num)
|
||||
{
|
||||
cout <<"Trackr()<<-RVal"<<endl;
|
||||
}
|
||||
Trackr&
|
||||
operator= (Trackr const& orig)
|
||||
{
|
||||
cout <<"Tracker = orig"<<endl;
|
||||
num = orig.num;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
///////////////////////////TODO : Debugging
|
||||
|
||||
|
||||
class Receiver
|
||||
{
|
||||
public:
|
||||
virtual ~Receiver() { } ///< this is an interface
|
||||
|
||||
virtual string woof (bool huge, uint cnt) =0;
|
||||
virtual string honk (string) =0;
|
||||
virtual string moo (Trackr num) =0;
|
||||
virtual string meh () =0;
|
||||
};
|
||||
|
||||
namespace {
|
||||
using Token = VerbPack<Receiver, string, sizeof(string)>;
|
||||
namespace { // Test Fixture
|
||||
|
||||
/** the "visitor" interface used by all VerbPacks in this test */
|
||||
class Receiver
|
||||
{
|
||||
public:
|
||||
virtual ~Receiver() { } ///< this is an interface
|
||||
|
||||
virtual string woof (bool huge, uint cnt) =0;
|
||||
virtual string honk (string) =0;
|
||||
virtual string moo (size_t num) =0;
|
||||
virtual string meh () =0;
|
||||
};
|
||||
|
||||
|
||||
using Token = VerbPack<Receiver, string, sizeof(string)>; // the argument list for honk(string) requires the most inline storage
|
||||
using TokenSeq = vector<Token>;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* a receiver of verb-tokens,
|
||||
* which renders them verbosely
|
||||
*/
|
||||
class VerboseRenderer
|
||||
: public Receiver
|
||||
{
|
||||
string
|
||||
woof (bool huge, uint cnt) override
|
||||
{
|
||||
string woof{huge? "Woof..":"haw-haw"};
|
||||
while (0 < cnt--)
|
||||
woof += woof;
|
||||
return woof;
|
||||
}
|
||||
string
|
||||
honk (string theHonk) override
|
||||
{
|
||||
return theHonk+"-"+theHonk+"!";
|
||||
}
|
||||
string
|
||||
moo (Trackr num) override
|
||||
{
|
||||
return join (vector<string>{num.num, "Moo"}, "__");
|
||||
}
|
||||
string
|
||||
meh() override
|
||||
{
|
||||
return "Meh!";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* a concrete receiver of verb-tokens,
|
||||
* which renders them verbosely
|
||||
*/
|
||||
class VerboseRenderer
|
||||
: public Receiver
|
||||
{
|
||||
string
|
||||
woof (bool huge, uint cnt) override
|
||||
{
|
||||
string woof;
|
||||
while (0 < cnt--)
|
||||
woof += isnil(woof)? string {huge? "Woof..":"haw-haw"}
|
||||
: woof;
|
||||
return woof;
|
||||
}
|
||||
string
|
||||
honk (string theHonk) override
|
||||
{
|
||||
return theHonk+"-"+theHonk+"!";
|
||||
}
|
||||
string
|
||||
moo (size_t num) override
|
||||
{
|
||||
return join (vector<string>{num, "Moo"}, "__");
|
||||
}
|
||||
string
|
||||
meh() override
|
||||
{
|
||||
return "Meh?";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* another concrete receiver to report any invocation with arguments
|
||||
*/
|
||||
class DiagnosticRenderer
|
||||
: public Receiver
|
||||
{
|
||||
string woof (bool huge, uint cnt) override { return report("woof", huge, cnt); }
|
||||
string honk (string theHonk) override { return report("honk", theHonk); }
|
||||
string moo (size_t num) override { return report("moo", num); }
|
||||
string meh() override { return report("meh"); }
|
||||
|
||||
template<typename...ARGS>
|
||||
string
|
||||
report (Literal func, ARGS&&...args)
|
||||
{
|
||||
return string(func)
|
||||
+ meta::dump (make_tuple (forward<ARGS>(args)...));
|
||||
}
|
||||
};
|
||||
|
||||
}//(End)Test Fixture
|
||||
|
||||
|
||||
|
||||
|
||||
#define SHOW_TYPE(_TY_) \
|
||||
cout << "typeof( " << STRINGIFY(_TY_) << " )= " << lib::meta::typeStr<_TY_>() <<endl;
|
||||
#define SHOW_EXPR(_XX_) \
|
||||
cout << "Probe " << STRINGIFY(_XX_) << " ? = " << _XX_ <<endl;
|
||||
|
||||
|
||||
|
||||
/***********************************************************************//**
|
||||
* @test Demonstration/Concept: dispatch a specific function
|
||||
* based on the given verbs of an embedded custom language.
|
||||
* Actually what we want to achieve here is a specific form
|
||||
* of double dispatch; thus the implementation relies on a
|
||||
* variation of the visitor pattern.
|
||||
* @test Demonstration/Concept: build pre-bound VerbPack objects to
|
||||
* embody a specific operation on the "receiver" interface,
|
||||
* then invoke them on a given concrete implementation.
|
||||
*
|
||||
* @see DiffListApplication_test
|
||||
*/
|
||||
|
|
@ -153,40 +142,33 @@ namespace test{
|
|||
run (Arg)
|
||||
{
|
||||
TokenSeq tokens = build_and_copy_tokens();
|
||||
render_verbose (tokens);
|
||||
// profile.append_woof(1, 2);
|
||||
apply_VerboseRenderer (tokens);
|
||||
apply_different_receivers (tokens);
|
||||
verify_copy_and_equality (tokens);
|
||||
}
|
||||
|
||||
|
||||
/** prepare a sequence of verbs
|
||||
* for the actual tests to work on */
|
||||
/* VerbSeq
|
||||
build_test_feed()
|
||||
{
|
||||
return {
|
||||
VERB_woof,
|
||||
VERB_honk,
|
||||
VERB_moo,
|
||||
VERB_meh
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
/** @test verify the correct individual dispatch
|
||||
* through a computation specific for the given verb
|
||||
*/
|
||||
TokenSeq
|
||||
build_and_copy_tokens ()
|
||||
{
|
||||
Token littleWoof(&Receiver::woof, "woof", false, 3u);
|
||||
Token bigWoof(&Receiver::woof, "woof", true, 2u);
|
||||
Token quack(&Receiver::honk, "honk", string{"quaack"});
|
||||
Token honk(&Receiver::honk, "honk", string{"Hoonk"});
|
||||
Token moo(&Receiver::moo, "moo", Trackr(3));
|
||||
Token littleWoof(&Receiver::woof, "woof", 0, 3); // NOTE: argument type conversion
|
||||
Token bigWoof(&Receiver::woof, "woof", true, 2);
|
||||
Token quack(&Receiver::honk, "honk", "quaack");
|
||||
Token honk(&Receiver::honk, "honk", "Hoonk");
|
||||
Token moo(&Receiver::moo, "moo", 3);
|
||||
Token meh(&Receiver::meh, "meh");
|
||||
|
||||
CHECK (sizeof(Token) == sizeof(string) // storage size reserved for the arguments (by declaration of type Token)
|
||||
+ sizeof(void*) // additional overhead for the VTable for dispatch
|
||||
+ sizeof(void(Receiver::*)()) // storage for the function pointer to the interface function
|
||||
+ sizeof(Literal) // storage for the verb symbol (for diagnostics and equality comparisions)
|
||||
);
|
||||
|
||||
return TokenSeq{{littleWoof, quack,honk, bigWoof, moo, meh}};
|
||||
// add LVal-copies to result sequence
|
||||
return TokenSeq{{littleWoof, quack, honk, bigWoof, moo, meh}};
|
||||
}
|
||||
|
||||
/** @test demonstrate the dispatching
|
||||
|
|
@ -195,7 +177,7 @@ namespace test{
|
|||
* the name of the invoked verb
|
||||
*/
|
||||
void
|
||||
render_verbose (TokenSeq& tokens)
|
||||
apply_VerboseRenderer (TokenSeq& tokens)
|
||||
{
|
||||
VerboseRenderer receiver;
|
||||
for (Token& tok : tokens)
|
||||
|
|
@ -205,6 +187,52 @@ namespace test{
|
|||
<< "'\n";
|
||||
}
|
||||
|
||||
/** @test demonstrate that another receiver
|
||||
* indeed invokes different implementations
|
||||
* of the Interface functions embedded within
|
||||
* the Verb. Here the implementation just prints
|
||||
* the name of the invoked verb and the arguments.
|
||||
*/
|
||||
void
|
||||
apply_different_receivers (TokenSeq& tokens)
|
||||
{
|
||||
VerboseRenderer verbose;
|
||||
DiagnosticRenderer diagnostic;
|
||||
auto render = [&](Receiver& renderer)
|
||||
{
|
||||
return join (lib::treeExplore(tokens)
|
||||
.transform ([&](Token tok)
|
||||
{
|
||||
return tok.applyTo (renderer);
|
||||
})
|
||||
,"-");
|
||||
};
|
||||
|
||||
CHECK (render(diagnostic) == "woof(false,3)-honk(quaack)-honk(Hoonk)-woof(true,2)-moo(3)-meh()");
|
||||
CHECK (render(verbose) == "haw-hawhaw-hawhaw-hawhaw-haw-quaack-quaack!-Hoonk-Hoonk!-Woof..Woof..-Moo__Moo__Moo-Meh?");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
verify_copy_and_equality (TokenSeq& tokens)
|
||||
{
|
||||
Token bigWoof = tokens[3];
|
||||
Token oldWoof{&Receiver::woof, "woof", true, 1};
|
||||
Token oldWolf{&Receiver::woof, "wolf", true, 0};
|
||||
|
||||
CHECK (bigWoof == oldWoof);
|
||||
CHECK (bigWoof != oldWolf);
|
||||
|
||||
CHECK (not util::isSameObject (bigWoof, oldWoof));
|
||||
CHECK (string(bigWoof) == "VerbPack(woof)");
|
||||
CHECK (string(oldWoof) == "VerbPack(woof)");
|
||||
CHECK (string(oldWolf) == "VerbPack(wolf)");
|
||||
|
||||
VerboseRenderer bark;
|
||||
CHECK (bigWoof.applyTo(bark) == "Woof..Woof..");
|
||||
CHECK (oldWoof.applyTo(bark) == "Woof..");
|
||||
CHECK (oldWolf.applyTo(bark) == "");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -125,8 +125,8 @@ namespace test {
|
|||
/* == ElementAccess interface == */
|
||||
|
||||
RawResult
|
||||
performAccessTo (UICoord::Builder & target, size_t limitCreation) override
|
||||
{
|
||||
performAccessTo (UICoord::Builder & target, size_t) override
|
||||
{ /////////////////////////////////////////////////TICKET #1134 : use a mock component access scheme here instead of some hardwired responses
|
||||
UICoord const& location = target.uiCoord();
|
||||
|
||||
CHECK (existingPath >= location);
|
||||
|
|
|
|||
|
|
@ -19650,8 +19650,8 @@
|
|||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555247320686" ID="ID_1896093043" MODIFIED="1557498707228" TEXT="brauche Visitor mit flexiblen Argumenten">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555247320686" ID="ID_1896093043" MODIFIED="1557590822696" TEXT="brauche Visitor mit flexiblen Argumenten">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1555247502178" ID="ID_297247554" MODIFIED="1557498707228" TEXT="Anforderung">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1555247509182" ID="ID_184476156" MODIFIED="1557498707228" TEXT="funktioniert genauso wie Visitor im Diff, mit Verb-Tokens"/>
|
||||
|
|
@ -19667,15 +19667,19 @@
|
|||
<node CREATED="1555247665396" ID="ID_1210108422" MODIFIED="1557498707228" TEXT="vermutlich werden Lambdas eine Rolle spielen"/>
|
||||
<node CREATED="1555247678988" ID="ID_1615700205" MODIFIED="1557498707228" TEXT="aber ich möchte Heap-Storage vermeiden"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555247704342" ID="ID_929740643" MODIFIED="1557498707228" TEXT="Entwurf/Test">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555247713060" ID="ID_1159666241" MODIFIED="1557498707228" TEXT="proof-of-concept">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1555247704342" ID="ID_929740643" MODIFIED="1557590585181" TEXT="Entwurf/Test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1555247713060" ID="ID_1159666241" MODIFIED="1557590555065" TEXT="proof-of-concept">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1555247744121" ID="ID_1280520595" MODIFIED="1557498707228" TEXT="ausgehend von Kopie des VerbToken"/>
|
||||
<node CREATED="1555247757037" ID="ID_1249615365" MODIFIED="1557498707228" TEXT="(optional) vielleicht letztlich in eine Lösung verschmelzen?"/>
|
||||
<node CREATED="1555247757037" ID="ID_1249615365" MODIFIED="1557590532864" TEXT="(optional) vielleicht letztlich in eine Lösung verschmelzen?">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node CREATED="1557590535366" ID="ID_568258701" MODIFIED="1557590538950" TEXT="vermutlich ehr nicht"/>
|
||||
<node CREATED="1557590539635" ID="ID_1843674392" MODIFIED="1557590549256" TEXT="da PolymorphicValue doch recht komplex ist"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555806526685" ID="ID_192016641" MODIFIED="1557498707228" TEXT="Lösungsansatz: PolymorphicValue">
|
||||
<icon BUILTIN="pencil"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1555806526685" ID="ID_192016641" MODIFIED="1557590525234" TEXT="Lösungsansatz: PolymorphicValue">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1555806541914" ID="ID_1260020116" MODIFIED="1557498707228" TEXT="der bietet genau den flexiblen inline-Buffer, den ich hier brauche">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
|
@ -19703,8 +19707,8 @@
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555806670026" ID="ID_604641822" MODIFIED="1557498707228" TEXT="Probleme bei der Umsetzung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1555806670026" ID="ID_604641822" MODIFIED="1557590449417" TEXT="Probleme bei der Umsetzung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1555807073875" ID="ID_1971528084" MODIFIED="1557498707228" TEXT="std::apply verwenden">
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
<node CREATED="1555807086938" ID="ID_354296634" MODIFIED="1557498707228" TEXT="gitbts noch nicht auf Debian-Stretch"/>
|
||||
|
|
@ -19730,7 +19734,7 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1555806696990" ID="ID_1464210384" MODIFIED="1557498707228" TEXT="kann nicht Tuple-Element per std::forward weitergeben">
|
||||
<node CREATED="1555806696990" FOLDED="true" ID="ID_1464210384" MODIFIED="1557590459821" TEXT="kann nicht Tuple-Element per std::forward weitergeben">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1555806733962" ID="ID_1424612840" MODIFIED="1557498707228" TEXT="Compiler möchte eine RValue-Referenz"/>
|
||||
<node CREATED="1555806760125" ID="ID_1741677842" MODIFIED="1557498707228" TEXT="workaround: das Tuple selber per std::forward an std::get übergeben">
|
||||
|
|
@ -19945,7 +19949,9 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1555807238238" ID="ID_383098394" MODIFIED="1557498707229" TEXT="Copy-Support von PolymorphicValue ist "komisch"">
|
||||
<node CREATED="1555807238238" FOLDED="true" ID="ID_383098394" MODIFIED="1557590514367" TEXT="Copy-Support von PolymorphicValue ist "komisch"">
|
||||
<arrowlink COLOR="#829ebf" DESTINATION="ID_596556632" ENDARROW="Default" ENDINCLINATION="-282;0;" ID="Arrow_ID_1622655110" STARTARROW="None" STARTINCLINATION="-74;193;"/>
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node CREATED="1555807266221" ID="ID_262959695" MODIFIED="1557498707229" TEXT="nach heutigem Stand: unbeholfen implementiert"/>
|
||||
<node CREATED="1555807285055" ID="ID_1456730365" MODIFIED="1557498707229" TEXT="braucht expliziten Support vom Payload typ"/>
|
||||
<node CREATED="1555807297726" ID="ID_1905059435" MODIFIED="1557498707229" TEXT="das wäre heute gar nicht mehr notwendig"/>
|
||||
|
|
@ -20112,16 +20118,17 @@
|
|||
<node CREATED="1555807443642" ID="ID_90620144" MODIFIED="1557498707229" TEXT="sollte selbständig erkennen, ob der Zieltyp kopierbar ist"/>
|
||||
<node CREATED="1555807464657" ID="ID_1089528099" MODIFIED="1557498707229" TEXT="diese meta-Intelligenz sollte komplett in dem Adapter stecken"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1557446611550" ID="ID_596556632" MODIFIED="1557498707229" TEXT="Ticket #1197 : rationalise copy support in PolymorphicValue">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1557446611550" ID="ID_596556632" MODIFIED="1557590501784" TEXT="Ticket #1197 : rationalise copy support in PolymorphicValue">
|
||||
<linktarget COLOR="#1a64bc" DESTINATION="ID_596556632" ENDARROW="Default" ENDINCLINATION="-129;0;" ID="Arrow_ID_884404467" SOURCE="ID_1511870599" STARTARROW="None" STARTINCLINATION="-284;0;"/>
|
||||
<linktarget COLOR="#829ebf" DESTINATION="ID_596556632" ENDARROW="Default" ENDINCLINATION="-282;0;" ID="Arrow_ID_1622655110" SOURCE="ID_383098394" STARTARROW="None" STARTINCLINATION="-74;193;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1555807762543" ID="ID_1645640007" MODIFIED="1557498707229" TEXT="Problem: Puffergröße">
|
||||
<node CREATED="1555807778751" ID="ID_1563586526" MODIFIED="1557498707229" TEXT="PolymorphicValue verlangt, daß man die Puffergröße als Template-Argument definiert"/>
|
||||
<node CREATED="1555807802562" ID="ID_1845631121" MODIFIED="1557498707229" TEXT="hier hängt diese aber von der Storage für die Funktionsargumente ab."/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555807833997" ID="ID_1153160392" MODIFIED="1557498707229" TEXT="Idealfall: das müßte automatisch funktionieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555807833997" ID="ID_1153160392" MODIFIED="1557590273404" TEXT="Idealfall: das müßte automatisch funktionieren">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1555807861314" ID="ID_352919826" MODIFIED="1557498707229" TEXT="geht das überhaupt?"/>
|
||||
<node CREATED="1555807866689" ID="ID_1851833268" MODIFIED="1557498707229" TEXT="würde vermutlich auf ein Builder-Konstrukt hinauslaufen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -20156,22 +20163,26 @@
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555807845319" ID="ID_1999765895" MODIFIED="1557498707229" TEXT="Halbe Lösung: wenigstens eine Hilfsfunktion bereitstellen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1557590275193" ID="ID_756824768" MODIFIED="1557590280062" TEXT="YAGNI">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555808026434" ID="ID_1634107778" MODIFIED="1557498707229" TEXT="automatische Konversionen für konkrete Argumente">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1555807845319" ID="ID_1999765895" MODIFIED="1557590260752" TEXT="Halbe Lösung: wenigstens eine Hilfsfunktion bereitstellen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1555808026434" ID="ID_1634107778" MODIFIED="1557590425363" TEXT="automatische Konversionen für konkrete Argumente">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1555808055328" ID="ID_1683773555" MODIFIED="1557498707229" TEXT="der VerbPack - Konstruktor sollte sich genau so verhalten wie die Zielfunktion">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1555808100082" ID="ID_1008688397" MODIFIED="1557498707229" TEXT="Beispiel: Zielfunktion nimmt einen std::string, gegeben ist ein C-String-Literal"/>
|
||||
<node CREATED="1555808124882" ID="ID_364451047" MODIFIED="1557498707229" TEXT="aktuell wird exakt der korrekte Typ erwartet"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555808138474" ID="ID_847234596" MODIFIED="1557498707229" TEXT="Grund: Funktionsweise der Teplate-Argument-Inferenz">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1555808138474" ID="ID_847234596" MODIFIED="1557590439076" TEXT="Grund: Funktionsweise der Teplate-Argument-Inferenz">
|
||||
<icon BUILTIN="info"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1555808184873" ID="ID_804931772" MODIFIED="1557498707229" TEXT="sinnvoller Workaround">
|
||||
<node COLOR="#435e98" CREATED="1555808184873" ID="ID_804931772" MODIFIED="1557590291568" TEXT="sinnvoller Workaround">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1555808201687" ID="ID_191950649" MODIFIED="1557498707229" TEXT=""Zwiebelschalen-Konstrukt"??">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -20189,15 +20200,70 @@
|
|||
</html></richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node CREATED="1557590299574" ID="ID_1634972448" MODIFIED="1557590314138" TEXT="rein zufällig delegiere ich bereits über zwei Konstrukturen"/>
|
||||
<node COLOR="#338800" CREATED="1557590314884" ID="ID_1086686390" MODIFIED="1557590420718" TEXT="also einfach die Argument-Typen vom Funktions-Handler nehmen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
anstatt, wie es die bisherige (naive) implementierung macht,
|
||||
</p>
|
||||
<p>
|
||||
die typename ARGS... auch dafür zu verwenden, den Handler-Typ zu konstruieren.
|
||||
</p>
|
||||
<p>
|
||||
Mit diesem einfachen Kniff passiert die Konvertierung dann in dem Moment,
|
||||
</p>
|
||||
<p>
|
||||
wo wir die konkreten Argumente in den vorbereiteten Argument-Tupel im Holder schieben
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555808280478" ID="ID_59896827" MODIFIED="1557498707229" TEXT="Testabdeckung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1555808280478" ID="ID_59896827" MODIFIED="1557590523471" TEXT="Testabdeckung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1557590726512" ID="ID_1345932776" MODIFIED="1557590812617" TEXT="mehrere verschiedene Receiver">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1557590733137" ID="ID_297834334" MODIFIED="1557590812186" TEXT="Kopier-Verhalten im Detail untersucht">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...jeodch nicht eigens im Test dokumentiert
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
weil das sehr aufwendig wäre und den kompletten Test dominieren würde
|
||||
</li>
|
||||
<li>
|
||||
weil die Implementierung (in dieser Hinsicht) letztlich banal ist: Anwenden eines Tupel auf eine Funktion
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1557590794163" ID="ID_497379433" MODIFIED="1557590811601" TEXT="Werte kopiert und verglichen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1557590805129" ID="ID_158433397" MODIFIED="1557590810851" TEXT="ausführlich kommentiert">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1555808288856" ID="ID_1931717111" MODIFIED="1557498707229" TEXT="Frage: ist das Design gut?">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1555808288856" ID="ID_1931717111" MODIFIED="1557590603605" TEXT="Frage: ist das Design gut?">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1555808300703" ID="ID_621465643" MODIFIED="1557498707229" TEXT="kann/sollte die Lösong mehr integriert sein?">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
|
@ -20210,7 +20276,7 @@
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1555808311417" ID="ID_1932269477" MODIFIED="1557498707229" TEXT="oder ist es grade ein Vorteil, wenn sie ein roher Baustein ist">
|
||||
<node CREATED="1555808311417" ID="ID_1932269477" MODIFIED="1557590690950" TEXT="oder ist es grade ein Vorteil, wenn sie ein roher Baustein ist">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -20224,9 +20290,38 @@
|
|||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<linktarget COLOR="#fcda04" DESTINATION="ID_1932269477" ENDARROW="Default" ENDINCLINATION="290;0;" ID="Arrow_ID_742389536" SOURCE="ID_128501904" STARTARROW="None" STARTINCLINATION="187;8;"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1557590616683" ID="ID_128501904" MODIFIED="1557590701982" TEXT="ich halte es jetzt für gelungen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
weil ich es geschafft habe,
|
||||
</p>
|
||||
<p>
|
||||
den gesamten Auswahl-Mechanismus in einen einzigen Konstruktur-Aufruf zu packen.
|
||||
</p>
|
||||
<p>
|
||||
Man kann also nach Belieben VerbPacks in allen Varianten bauen,
|
||||
</p>
|
||||
<p>
|
||||
und es obliegt der nächst höheren Schicht, dies auch in sinnvollem Rahmen zu tun...
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<arrowlink COLOR="#fcda04" DESTINATION="ID_1932269477" ENDARROW="Default" ENDINCLINATION="290;0;" ID="Arrow_ID_742389536" STARTARROW="None" STARTINCLINATION="187;8;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1557590586650" ID="ID_1348312855" MODIFIED="1557590595855" TEXT="den (neu gebauten) VerbPack integrieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue