/* LateBindInstance(Test) - verify rewriting of member function invocation Copyright (C) 2023, Hermann Vosseler   **Lumiera** 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. See the file COPYING for further details. * *****************************************************************/ /** @file late-bind-instance-test.cpp ** unit test \ref LateBindInstance_test */ #include "lib/test/run.hpp" #include "lib/meta/function.hpp" #include "lib/meta/tuple-helper.hpp" #include "lib/test/test-helper.hpp" #include "lib/test/tracking-dummy.hpp" #include "lib/format-cout.hpp" #include "lib/format-util.hpp" #include "lib/util.hpp" #include #include namespace lib { namespace meta { namespace test { using std::move; using std::tuple; using std::string; using lib::meta::dump; using lib::test::Tracker; /**********************************************************************************//** * @test verify a scheme to supply the actual instance for member function invocation. * @remark in the end this is just a value replacement in a tuple, where the position * is marked with a placeholder type. This scheme is used for starting threads, * where the actual thread instance is not known yet at the point where the * arguments for the thread-function are constructed * @see lib::launchDetached */ class LateBindInstance_test : public Test { void run (Arg) { seedRand(); demonstrateUsage(); verify_forwarding(); verify_cornerCases(); } /** @test demonstrate the usage of lib::meta::lateBindInstance(): * - construct an argument tuple * - mark the position of the `this`-ptr with a placeholder * - rewrite the arguments later when the actual instance is known * - member function can now be invoked, since the instance was injected. */ void demonstrateUsage() { uint randomLimit = 2 + rani(98); auto plannedArgs = tuple{InstancePlaceholder{} ,randomLimit }; // the actual instance may be available only later... Test& instanceRef = *this; // now rewrite the argument tuple to inject the instance-ptr auto preparedArgs = lateBindInstance (instanceRef, plannedArgs); uint res = std::apply (&LateBindInstance_test::theMember, preparedArgs); CHECK (res < randomLimit); } uint theMember (uint limit) { return rani (limit); } /** @test verify that the rewriting process does not incur unnecessary data copies */ void verify_forwarding() { auto& log = Tracker::log; log.clear (this); InstancePlaceholder marker; Tracker t1(11); log.event("construct tuple"); tuple tup(t1, marker, Tracker{23}, 55); Test& instanceRef = *this; log.event("invoke lateBindInstance"); auto tup1r = lateBindInstance (instanceRef, tup); log.event("got result"); // before invocation the Tracker instances are created (obviously..) CHECK (log.verifyCall("ctor").arg(11) .beforeCall("ctor-copy").arg("Track{11}") .beforeEvent("invoke lateBindInstance")); CHECK (log.verifyCall("ctor").arg(23) .beforeCall("ctor-move").arg("Track{23}") .beforeCall("dtor").arg(Tracker::DEFUNCT) .beforeEvent("invoke lateBindInstance")); // but there is no copy operation after the invocation CHECK (log.ensureNot("ctor-copy") .afterEvent("invoke lateBindInstance")); // both Tracker instances are moved two times // - once to create the maybeInject-invocation and // - once to consolidate the result // for each instance one moved-away temporary is destroyed CHECK (log.verifyEvent("invoke lateBindInstance") .beforeCall("ctor-move").arg("Track{11}") .beforeCall("ctor-move").arg("Track{11}") .beforeCall("dtor").arg(Tracker::DEFUNCT) .beforeEvent("got result")); CHECK (log.verifyEvent("invoke lateBindInstance") .beforeCall("ctor-move").arg("Track{23}") .beforeCall("ctor-move").arg("Track{23}") .beforeCall("dtor").arg(Tracker::DEFUNCT) .beforeEvent("got result")); cout << "____Tracker-Log_______________\n" << util::join(Tracker::log, "\n") << "\n───╼━━━━━━━━━━━╾──────────────"< marker; CHECK (dump(lateBindInstance (dummy, tuple<>{})) == "()"_expect); CHECK (dump(lateBindInstance (dummy, tuple{42})) == "(42)"_expect); CHECK (dump(lateBindInstance (dummy, tuple{1,2,3})) == "(1,2,3)"_expect); CHECK (dump(lateBindInstance (dummy, tuple{marker,2,3})) == "(↗555,2,3)"_expect); CHECK (dump(lateBindInstance (dummy, tuple{1,marker,3})) == "(1,↗555,3)"_expect); CHECK (dump(lateBindInstance (dummy, tuple{1,2,marker})) == "(1,2,↗555)"_expect); CHECK (dump(lateBindInstance (dummy, tuple{marker})) == "(↗555)"_expect); CHECK (dump(lateBindInstance (dummy, tuple{string{"1"} ,"2" ,marker ,tuple(2,3) , 5.5 })) == "(1,2,↗555,«tuple»──(2,3),5.5)"_expect); } }; /** Register this test class... */ LAUNCHER (LateBindInstance_test, "unit meta"); }}} // namespace lib::meta::test