diff --git a/src/lib/verb-token.hpp b/src/lib/verb-token.hpp index 78c9f82a1..532bb0dab 100644 --- a/src/lib/verb-token.hpp +++ b/src/lib/verb-token.hpp @@ -53,7 +53,6 @@ #include #include -#include namespace lib { diff --git a/src/lib/verb-visitor.hpp b/src/lib/verb-visitor.hpp index 3efb9512c..58c4d7348 100644 --- a/src/lib/verb-visitor.hpp +++ b/src/lib/verb-visitor.hpp @@ -50,94 +50,47 @@ #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 #include -#include #include namespace lib { - using std::string; - - - /** - * Action token implemented by double dispatch to a handler function, - * as defined in the "receiver" interface (parameter \c REC). - * The token is typically part of a DSL and can be applied - * to a concrete receiver subclass. - * @tparam REC the type receiving the verb invocations - * @tparam SIG signature of the actual verb function, expected - * to exist on the receiver (REC) interface - * @remarks while the included ID Literal is mostly for diagnostics, - * it also serves as identity for comparisons. Conceptually what - * we want is to compare the function "offset", but this leads - * into relying on implementation defined behaviour. - * @note the #VERB macro simplifies definition of actual tokens - */ - template - class VerbToken; - - template - class VerbToken + namespace { + using JustSomeIrrelvantType = struct{}; + const size_t VERB_TOKEN_SIZE = sizeof(VerbToken); + + constexpr size_t + storageOverhead(size_t argStorage) { - public: - typedef RET (REC::*Handler) (ARGS...); + return argStorage + VERB_TOKEN_SIZE; + } + + /** + * Helper: pass a reference to an tuple element into a "perfect forwarding" call + * This is the equivalent of calling std::forward (TY&) + * ////////////////////////////////////////////////////////////////////TODO verify this reasoning is sound!! + */ + template + decltype(auto) constexpr + get_ref (std::tuple& tuple) + { + using Elm = std::remove_reference_t< + std::tuple_element_t>>; - private: - Handler handler_; - Literal token_; - - public: - RET - applyTo (REC& receiver, ARGS&& ...args) - { - REQUIRE ("NIL" != token_); - return (receiver.*handler_)(std::forward(args)...); - } - - VerbToken(Handler handlerFunction, Literal token) - : handler_(handlerFunction) - , token_(token) - { } - - VerbToken() - : handler_{} - , token_("NIL") - { } - - /* default copyable */ - - operator string() const - { - return string(token_); - } - - Literal const& - getID() - { - return token_; - } - - /** equality of VerbToken, based on equality of the #token_ Literal - * @remarks member pointers to virtual functions aren't comparable, for good reason - */ - bool operator== (VerbToken const& o) const { return token_ == o.token_; } - bool operator!= (VerbToken const& o) const { return token_ != o.token_; } - }; - -#define VERB(RECEIVER, FUN) VERB_##FUN (&RECEIVER::FUN, STRINGIFY(FUN)) - - using JustSomeIrrelvantType = struct{}; - const size_t VERB_TOKEN_SIZE = sizeof(VerbToken); + return static_cast (std::get (tuple)); + } + } template - struct Hook + struct VerbInvoker { - virtual ~Hook() { } + virtual ~VerbInvoker() { } virtual RET applyTo (REC&) =0; }; @@ -148,7 +101,7 @@ namespace lib { template struct Holder : polyvalue::CopySupport< // mix-in virtual copy/move support - Hook> // ...the common interface to use + VerbInvoker> // ...the common interface to use { using Verb = VerbToken; using Args = std::tuple; @@ -174,22 +127,17 @@ namespace lib { RET invokeVerb (REC& receiver, meta::IndexSeq) { - return verb_.applyTo (receiver, std::get (args_)...); + return verb_.applyTo (receiver, get_ref (args_)...); } }; - static constexpr size_t - storageOverhead(size_t argStorage) - { - return argStorage + VERB_TOKEN_SIZE; - } template class VerbPack - : public PolymorphicValue, storageOverhead(arg_storage)> + : public PolymorphicValue, storageOverhead(arg_storage)> { - using PolyHolder = PolymorphicValue, storageOverhead(arg_storage)>; + using PolyHolder = PolymorphicValue, storageOverhead(arg_storage)>; template using PayloadType = Holder*; diff --git a/tests/library/verb-visitor-dispatch-test.cpp b/tests/library/verb-visitor-dispatch-test.cpp index 38426d729..343d142d2 100644 --- a/tests/library/verb-visitor-dispatch-test.cpp +++ b/tests/library/verb-visitor-dispatch-test.cpp @@ -27,16 +27,17 @@ #include "lib/test/run.hpp" -//#include "lib/verb-token.hpp" #include "lib/verb-visitor.hpp" #include "lib/format-string.hpp" #include "lib/format-cout.hpp" +#include "lib/format-util.hpp" #include #include using std::string; using util::_Fmt; +using util::join; using std::vector; @@ -49,23 +50,15 @@ namespace test{ public: virtual ~Receiver() { } ///< this is an interface - virtual string woof() =0; - virtual string honk() =0; - virtual string moo() =0; - virtual string meh() =0; + virtual string woof (bool huge, uint cnt) =0; + virtual string honk (string) =0; + virtual string moo (size_t num) =0; + virtual string meh () =0; }; namespace { - const string BEGINNING("silence"); - - using Verb = VerbToken; - using VerbSeq = vector; - - - Verb VERB(Receiver, woof); - Verb VERB(Receiver, honk); - Verb VERB(Receiver, moo); - Verb VERB(Receiver, meh); + using Token = VerbPack; + using TokenSeq = vector; } @@ -76,42 +69,29 @@ namespace test{ 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) + woof (bool huge, uint cnt) override { - string resultExpression (fmt_ % verb_ % nextToken); - verb_ = nextToken; - return resultExpression; + string woof{huge? "Woof..":"haw-haw"}; + while (0 < cnt--) + woof += woof; + return woof; + } + string + honk (string theHonk) override + { + return theHonk+"-"+theHonk+"!"; + } + string + moo (size_t num) override + { + return join (vector{num, "Moo"}, "__"); + } + string + meh() override + { + return "Meh!"; } - - - 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") - { } }; @@ -119,6 +99,7 @@ namespace test{ + /***********************************************************************//** * @test Demonstration/Concept: dispatch a specific function * based on the given verbs of an embedded custom language. @@ -134,19 +115,15 @@ namespace test{ virtual void run (Arg) { - VerbSeq tokens = build_test_feed(); + TokenSeq tokens = build_and_copy_tokens(); render_verbose (tokens); - verify_dispatch (tokens); - - VerbPack woof(&Receiver::woof, "woof"); - // profile.append_woof(1, 2); } /** prepare a sequence of verbs * for the actual tests to work on */ - VerbSeq +/* VerbSeq build_test_feed() { return { @@ -156,7 +133,24 @@ namespace test{ VERB_meh }; } +*/ + /** @test verify the correct individual dispatch + * through a computation specific for the given verb + */ + TokenSeq + build_and_copy_tokens () + { + Token bigWoof(&Receiver::woof, "woof", true, 2u); + Token littleWoof(&Receiver::woof, "woof", false, 3u); + Token quack(&Receiver::honk, "honk", string{"quaack"}); + Token honk(&Receiver::honk, "honk", string{"Hoonk"}); + Token moo(&Receiver::moo, "moo", size_t(3)); + Token meh(&Receiver::meh, "meh"); + + + return TokenSeq{{littleWoof, quack,honk, bigWoof, moo, meh}}; + } /** @test demonstrate the dispatching * based on the concrete verb token. @@ -164,31 +158,16 @@ namespace test{ * the name of the invoked verb */ void - render_verbose (VerbSeq tokens) + render_verbose (TokenSeq& tokens) { VerboseRenderer receiver; - for (Verb verb : tokens) - cout << "consuming " << verb - << " -> '" - << verb.applyTo(receiver) - << "'\n"; +// for (Token tok : tokens) +// cout << "dispatching " << tok +// << " -> '" +// << tok.applyTo(receiver) +// << "'\n"; } - - /** @test verify the correct individual dispatch - * through a computation specific for the given verb - */ - void - verify_dispatch (VerbSeq tokens) - { - RecollectingReceiver receiver; - string previous = BEGINNING; - for (Verb verb : tokens) - { - CHECK (previous+" followed by "+string(verb) == verb.applyTo(receiver)); - previous = string(verb); - } - } };