LUMIERA.clone/tests/library/verb-visitor-dispatch-test.cpp
Ichthyostega 8f43c2591e Library: investigate malfunction in metaprogramming
the template lib::PolymorphicValue seemingly picked the wrong
implementation strategy for "virtual copy support": In fact it is possible
to use the optimal strategy here, since our interface inherits from CloneSupport,
yet the metaprogramming logic picked the mix-in-adapter (which requires one additional "slot"
of storage plus a dynamic_cast at runtime).

The reason for this malfunction was the fact that we used META_DETECT_FUNCTION
to detect the presence of a clone-support-function. This is not correct, since
it can only detect a function in the *same* class, not an inherited function.

Thus, switching to META_DETECT_FUNCTION_NAME solves this problem
Well, this solution has some downsides, but since I intend to rewrite the
whole virtual copy support (#1197) anyway, I'll deem this acceptable for now


TODO / WIP: still some diagnostics code to clean up, plus a better solution for the EmptyBase
2019-05-10 02:19:01 +02:00

232 lines
6.2 KiB
C++

/*
VerbVisitorDispatch(Test) - Setup to dispatch to arbitrary functions on a receiver interface
Copyright (C) Lumiera.org
2019, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file verb-visitor-dispatch-test.cpp
** Demonstrate the extended concept of a _verb language_ based on double dispatch.
** @see body-canvas-widget.hpp
*/
#include "lib/test/run.hpp"
#include "lib/verb-visitor.hpp"
#include "lib/format-string.hpp"
#include "lib/format-cout.hpp"
#include "lib/format-util.hpp"
#include <string>
#include <vector>
using std::string;
using util::_Fmt;
using util::join;
using std::vector;
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)>;
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!";
}
};
#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.
*
* @see DiffListApplication_test
*/
class VerbVisitorDispatch_test : public Test
{
virtual void
run (Arg)
{
TokenSeq tokens = build_and_copy_tokens();
render_verbose (tokens);
// profile.append_woof(1, 2);
using IrrelvantType = struct{};
const size_t VERB_TOK_SIZE = sizeof(lib::VerbToken<IrrelvantType, void(void)>);
using HoldL = Holder<Receiver, string(string)>;
const size_t VERB_TOK_SIZ2 = sizeof(HoldL::Verb);
const size_t HOLDER_SIZE = sizeof(HoldL);
const size_t ARG_TUP_SIZE = sizeof(std::tuple<string>);
SHOW_EXPR (VERB_TOK_SIZE);
SHOW_EXPR (VERB_TOK_SIZ2);
SHOW_EXPR (HOLDER_SIZE);
SHOW_EXPR (ARG_TUP_SIZE);
SHOW_EXPR (sizeof(string));
using AdapT = Token::Adapter<HoldL>;
SHOW_TYPE (AdapT);
SHOW_EXPR (sizeof(AdapT));
}
/** 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 meh(&Receiver::meh, "meh");
return TokenSeq{{littleWoof, quack,honk, bigWoof, moo, meh}};
}
/** @test demonstrate the dispatching
* based on the concrete verb token.
* Here the implementation just prints
* the name of the invoked verb
*/
void
render_verbose (TokenSeq& tokens)
{
VerboseRenderer receiver;
for (Token& tok : tokens)
cout << "dispatching " << tok
<< " -> '"
<< tok.applyTo(receiver)
<< "'\n";
}
};
/** Register this test class... */
LAUNCHER (VerbVisitorDispatch_test, "unit common");
}} // namespace lib::test