diff --git a/src/lib/meta/variadic-helper.hpp b/src/lib/meta/variadic-helper.hpp index 557b1f938..66114730c 100644 --- a/src/lib/meta/variadic-helper.hpp +++ b/src/lib/meta/variadic-helper.hpp @@ -232,6 +232,8 @@ namespace meta { + + /* ==== Rebinding Variadic Arguments ==== **/ /** @@ -258,7 +260,101 @@ namespace meta { - + + + /* ==== Build and Rebuild variadic type sequences ==== **/ + + /** + * Variadic type sequence builder. + * This metaprogramming helper template provides an unified view + * to handle _»tuple-like« types and variadic _type sequences._ + * - the constant #SIZ gives the number of elements + * - the nested type #Idx can be used as _index sequence_ + * - #Seq is a _variadic type sequence_ with the extracted types + * - #Tup is a std::tuple over these types + * - the nested template #Apply wraps each type into another template + * - #Rebind likewise instantiates another template with the element types + * - #AndAll applies a predicate and combines the result with _logical and_ + * - #OrAll similarly evaluates _logical or_ on the application results + */ + template + struct ElmTypes + { + static constexpr size_t SIZ = 1; + using Idx = std::index_sequence; + using Seq = TySeq; + using Tup = std::tuple; + + template class META> + using Apply = TySeq>; + template class O> + using Rebind = O; + template class PRED> + using AndAll = std::__and_>; + template class PRED> + using OrAll = std::__or_>; + }; + + /** Partial specialisation to handle type sequences */ + template + struct ElmTypes> + { + static constexpr size_t SIZ = sizeof...(TYPES); + using Idx = std::make_index_sequence; + using Seq = TySeq; + using Tup = std::tuple; + + template class META> + using Apply = TySeq...>; + + template class O> + using Rebind = typename lib::meta::RebindVariadic::Type; + + template class PRED> + using AndAll = typename ElmTypes>::template Rebind; + + template class PRED> + using OrAll = typename ElmTypes>::template Rebind; + }; + + /** partial specialisation to handle types + * supporting the C++ »tuple protocol« + */ + template + struct ElmTypes> + { + template + struct Extract; + template + struct Extract> + { + using ElmTypes = TySeq::type ...>; + }; + + static constexpr size_t SIZ = std::tuple_size::value; + + using Idx = std::make_index_sequence; + using Seq = typename Extract::ElmTypes; + using Tup = typename RebindVariadic::Type; + + template class META> + using Apply = typename ElmTypes::template Apply; + + template class O> + using Rebind = typename RebindVariadic::Type; + + template class PRED> + using AndAll = typename ElmTypes>::template Rebind; + + template class PRED> + using OrAll = typename ElmTypes>::template Rebind; + }; + + + + + + /* ==== Invoke with index from variadic ==== **/ /** helper to invoke a functor, passing instances of std::integral_constant diff --git a/src/steam/engine/feed-manifold.hpp b/src/steam/engine/feed-manifold.hpp index 441315e9d..9eb269e65 100644 --- a/src/steam/engine/feed-manifold.hpp +++ b/src/steam/engine/feed-manifold.hpp @@ -144,6 +144,7 @@ namespace engine { + template class COND> struct isAllElements { @@ -173,8 +174,6 @@ namespace engine { template struct StructType { -// static lib::test::TypeDebugger kacki; - using Seq = TySeq; using Tup = std::tuple; }; @@ -182,8 +181,6 @@ namespace engine { template struct StructType> > { -// static lib::test::TypeDebugger drecky; - template struct AllZ; template diff --git a/tests/12metaprogramming.tests b/tests/12metaprogramming.tests index d991f6d97..8e2b5edbf 100644 --- a/tests/12metaprogramming.tests +++ b/tests/12metaprogramming.tests @@ -671,6 +671,11 @@ return: 0 END +TEST "variadic type manipulations" VariadicHelper_test <──.─┼N<2>──.─┼N<3>──.─┼N<3>──.─┤ out: 4╎N<0>──.─┼N<1>──.─┼N<2>──.─┼N<3>──.─┤ diff --git a/tests/core/steam/engine/node-base-test.cpp b/tests/core/steam/engine/node-base-test.cpp index af60887fe..6894ef2fc 100644 --- a/tests/core/steam/engine/node-base-test.cpp +++ b/tests/core/steam/engine/node-base-test.cpp @@ -27,12 +27,13 @@ #include "steam/engine/buffhandle-attach.hpp" //#include "lib/format-cout.hpp" #include "lib/test/diagnostic-output.hpp"/////////////////////TODO -//#include "lib/util.hpp" +#include "lib/util.hpp" //using std::string; using std::tuple;/////////////TODO using std::array; +using util::isSameAdr; namespace steam { @@ -78,22 +79,42 @@ namespace test { // some random numbers to test... long r1 = rani(100); - // Type setup to build a suitable FeedManifold + // Prepare setup to build a suitable FeedManifold using Buffer = long; /////////////////////////////////////////////////////////////////////////////////TODO using T1 = tuple; using T2 = array; using T3 = int; using T4 = int*; - using T5 = lib::HeteroData; + using T5 = lib::HeteroData; /////////////////////////////////////////////////////////////////////////////////TODO + using lib::meta::ElmTypes; + using S1 = ElmTypes; +SHOW_TYPE(S1) +SHOW_TYPE(S1::Seq) +SHOW_TYPE(S1::Tup) +SHOW_TYPE(S1::Idx) + using S1A = S1::Apply; +SHOW_TYPE(S1A) + using S1AR = ElmTypes::Rebind; +SHOW_TYPE(S1AR) +SHOW_EXPR(S1AR::value) + using S1AA = S1::AndAll; +SHOW_TYPE(S1AA) +SHOW_EXPR(bool(S1AA())) + using S1OA = S1::OrAll; +SHOW_TYPE(S1OA) +SHOW_EXPR(S1OA::value) + auto fun_singleOut = [&](Buffer* buff) { *buff = r1; }; + + // Example-1: a FeedManifold to adapt a simple generator function using M1 = FeedManifold; CHECK (not M1::hasInput()); CHECK (not M1::hasParam()); + // instantiate... M1 m1{fun_singleOut}; CHECK (1 == m1.outBuff.array().size()); -SHOW_EXPR(m1.outArgs) CHECK (nullptr == m1.outArgs ); // CHECK (m1.inArgs ); // does not compile because storage field is not provided // CHECK (m1.param ); @@ -103,19 +124,31 @@ SHOW_EXPR(m1.outArgs) CHECK (buff.isValid()); CHECK (buff.accessAs() == -55); - m1.outBuff.createAt (0, buff); + m1.outBuff.createAt (0, buff); // plant a copy of the BuffHandle into the output slot CHECK (m1.outBuff[0].isValid()); CHECK (m1.outBuff[0].accessAs() == -55); -SHOW_TYPE(M1::ArgI) -SHOW_TYPE(M1::TupI) -SHOW_TYPE(M1::ArgO) -SHOW_TYPE(M1::TupO) - m1.connect(); -SHOW_EXPR(m1.outArgs) -SHOW_EXPR(m1.outBuff[0]) -SHOW_EXPR(util::showAdr(*buff)) -SHOW_EXPR(util::showAdr(*m1.outBuff[0])) + m1.connect(); // instruct the manifold to connect buffers to arguments + CHECK (isSameAdr (m1.outArgs, *buff)); + CHECK (*m1.outArgs == -55); + + m1.invoke(); // invoke the adapted processing function (fun_singleOut) + CHECK (buff.accessAs() == r1); // result: the random number r1 was written into the buffer. + + // Example-2: adapt a function to process input -> output buffer + auto fun_singleInOut = [](Buffer* in, Buffer* out) { *out = *in; }; + using M2 = FeedManifold; + CHECK ( M2::hasInput());///////////////////////////TODO broken due to overly convoluted logic!!!! + CHECK (not M2::hasParam()); + CHECK (1 == M2::FAN_I); + CHECK (1 == M2::FAN_O); + // instantiate... + M2 m2{fun_singleInOut}; +// CHECK (1 == m2.inBuff.array().size()); ///////////TODO : need to »lift« plain types for simplfied logic!!!! + CHECK (1 == m2.outBuff.array().size()); +// CHECK (nullptr == m2.inArgs ); + CHECK (nullptr == m2.outArgs ); + } }; diff --git a/tests/library/meta/variadic-helper-test.cpp b/tests/library/meta/variadic-helper-test.cpp new file mode 100644 index 000000000..e08908ad4 --- /dev/null +++ b/tests/library/meta/variadic-helper-test.cpp @@ -0,0 +1,169 @@ +/* + VariadicHelper(Test) - verify helpers for transforming variadics and tuple-like types + + Copyright (C) + 2024, 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 variadic-helper-test.cpp + ** THe unit test \ref VariadicHelper_test demonstrates the usage of metaprogramming + ** helpers to handle _tuple-like_ types and type sequences in a uniform way. + ** @see variadic-helper.hpp + ** @see tuple-helper.hpp + ** @see feed-manifold.hpp real-world usage scenario + ** + */ + + +#include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +#include "lib/meta/variadic-helper.hpp" +#include "lib/hetero-data.hpp" +#include "lib/test/diagnostic-output.hpp"////////////TODO + +#include +#include + +using lib::test::showType; +using std::array; +using std::tuple; + + +namespace lib { +namespace meta { +namespace test { + + + + + + /*********************************************************************//** + * @test Cover some advanced metaprogramming helpers to support working + * with _tuple like_ types together with simple types. + */ + class VariadicHelper_test : public Test + { + virtual void + run (Arg) + { + rebuild_variadic(); + } + + + /** @test demonstrate uniform handling of... + * - simple types, + * - _tuple-like_ types (usable for structured binding) + * - _generic type sequences_ + */ + void + rebuild_variadic() + { + // CASE-1 : a tuple.... + using T1 = tuple; + + using S1 = ElmTypes; + CHECK (2 == S1::SIZ); + CHECK (showType< S1 >() == "ElmTypes, void>"_expect); + CHECK (showType< S1::Seq >() == "TySeq"_expect); + CHECK (showType< S1::Tup >() == "tuple"_expect); + CHECK (showType< S1::Idx >() == "integer_sequence"_expect); + + using S1A = S1::Apply; + CHECK (showType< S1A >() == "TySeq, is_pointer >"_expect); + + using S1AR = ElmTypes::Rebind; + CHECK (showType< S1AR >() == "__and_, is_pointer >"_expect); + CHECK (false == S1AR::value); + + using S1AA = S1::AndAll; + CHECK (showType< S1AA >() == "__and_, is_pointer >"_expect); + CHECK (false == S1AA::value); + + using S1OA = S1::OrAll; + CHECK (showType< S1OA >() == "__or_, is_pointer >"_expect); + CHECK (false == S1OA::value); + + + + // CASE-0 : handling an unstructured simple type.... + using T0 = int*; + + using S0 = ElmTypes; + CHECK (1 == S0::SIZ); + CHECK (showType< S0 >() == "ElmTypes"_expect); + CHECK (showType< S0::Seq >() == "TySeq"_expect); + CHECK (showType< S0::Tup >() == "tuple"_expect); + CHECK (showType< S0::Idx >() == "integer_sequence"_expect); + + using S0A = S0::Apply; + CHECK (showType< S0A >() == "TySeq >"_expect); + + using S0AA = S0::AndAll; + CHECK (showType< S0AA >() == "__and_ >"_expect); + CHECK (true == S0AA::value); + + using S0OA = S0::OrAll; + CHECK (showType< S0OA >() == "__or_ >"_expect); + CHECK (true == S0OA::value); + + + + // CASE-2 : can also handle a std::array.... + using T2 = array; + + using S2 = ElmTypes; + CHECK (3 == S2::SIZ); + CHECK (showType< S2 >() == "ElmTypes, void>"_expect); + CHECK (showType< S2::Seq >() == "TySeq"_expect); + CHECK (showType< S2::Tup >() == "tuple"_expect); + CHECK (showType< S2::Idx >() == "integer_sequence"_expect); + + using S2A = S2::Apply; + CHECK (showType< S2A >() == "TySeq, is_pointer, is_pointer >"_expect); + + using S2AA = S2::AndAll; + CHECK (showType< S2AA >() == "__and_, is_pointer, is_pointer >"_expect); + CHECK (true == S2AA::value); + + using S2OA = S2::OrAll; + CHECK (showType< S2OA >() == "__or_, is_pointer, is_pointer >"_expect); + CHECK (true == S2OA::value); + + + + // CASE-3 : a custom type which implements the C++ »tuple protocol«.... + using T3 = lib::HeteroData; + + using S3 = ElmTypes; + CHECK (3 == S3::SIZ); + CHECK (showType< S3 >() == "ElmTypes, void>"_expect); + CHECK (showType< S3::Seq >() == "TySeq"_expect); + CHECK (showType< S3::Idx >() == "integer_sequence"_expect); + + using S3A = S3::Apply; + CHECK (showType< S3A >() == "TySeq, is_pointer, is_pointer >"_expect); + + using S3AA = S3::AndAll; + CHECK (showType< S3AA >() == "__and_, is_pointer, is_pointer >"_expect); + CHECK (false == S3AA::value); + + using S3OA = S3::OrAll; + CHECK (showType< S3OA >() == "__or_, is_pointer, is_pointer >"_expect); + CHECK (true == S3OA::value); + } + }; + + + /** Register this test class... */ + LAUNCHER (VariadicHelper_test, "unit meta"); + + + +}}} // namespace lib::meta::test diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index cae1f64ae..9c6d8b194 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -24795,9 +24795,7 @@ - - - +

...es sollte an geeigneter Stelle einen Reset geben, da jeder DisplayEvalutaionPass grundsätzlich das ganze Layout sauber ausrechnen kann @@ -25486,9 +25484,7 @@ - - - +

  • @@ -25944,9 +25940,7 @@ - - - +

    ...das ist zunächst ein Versuch, ein mühsam errungenes Design zu verifizieren... @@ -26800,9 +26794,7 @@ - - - +

    ...und zwar die konkret wirksame Ausdehnung ⟹ meiner Analyse zufolge ist das get_width|height() @@ -27666,9 +27658,7 @@ - - - +

    TrackHeadWidget::accommodateOverallHeight(uint overallHeight) @@ -27803,9 +27793,7 @@ - - - +

    ...der default ist 10, und das erzeugt eine Gehrung nur bis ca 20° @@ -29573,9 +29561,7 @@ - - - +

    d.h. ich will den Standardfall als Standardfall sichtbar haben, @@ -32037,9 +32023,7 @@ - - - +

    Core-Entwickler von GTK @@ -34579,9 +34563,7 @@ - - - +

    das ist ein übergreifendes Thema zum UI-Verhalten @@ -34686,9 +34668,7 @@ - - - +

    diese Alternative würde dann attraktiv, wenn es häufig vorkommt, daß zwischen einem Clip-Widget und einer anderen Repräsentation des ClipDelegate dynamisch hin- und hergeschaltet werden muß. Weil man dann den relativ schwergewichtigen Datencontainer einfach umhängen könnte @@ -35948,9 +35928,7 @@ - - - +

    demnach würde startup sauber beendet, @@ -36762,9 +36740,7 @@ - - - +

    • @@ -37271,9 +37247,7 @@ - - - +

      ...das heißt, durch die Drag-Geste entstehen vorübergehend lokal inkonsistente Koordinaten; der nächste DisplayEvaluation-Pass würde dies wieder beseitigen. Dieser Ansatz wäre rein logisch der konsistentere Weg, denn erst durch eine Rückmeldung von der Session wird eine neue Position auch offiziell. Allerdings müßte man bei diesem Ansatz vorsichtig vorgehen, und mögliche Interferenzen mit der DisplayEvaluation und dem Layout-Managment bedenken; besonders wenn man eine weite Strecke zurücklegt, könnte es passieren, daß der Clip dann plötzlich aus der Anzeige verschwindet und den Fokus verliert, weil eine DisplayEvaluation ihn wieder an seine gegenwärtig nominelle Position geschoben hat. @@ -37503,9 +37477,7 @@ - - - +

      1.Schritt: irgendwie implementieren @@ -55972,8 +55944,7 @@ soll sowohl einfache Tyen, alsauch »strukturierte Typen« (tuple-like) akzeptieren

      - -
      + @@ -56001,8 +55972,7 @@ deshalb ist es sinnvoll, einen λ-closed Code-Block für jeden Index zu instantiieren

      - -
      +
      @@ -56017,17 +55987,32 @@ - + + + + + +

      + lib::meta::enable_if_TupleProtocol<TY> +

      + +
      +
      - + + + + + +
      @@ -88658,8 +88643,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      will sagen ... das ist nicht das Problem; der Compiler macht hier eine verwirrende Transformation, die den Typ eines Funktionspointers mit Template-Argumenten instaniiert. Leider hat das aber zur Folge, daß man das eigentliche Problem nicht sieht (selbst wenn man endlos drauf starrt...)

      - - +
      @@ -88751,8 +88735,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      void (*(std::_Placeholder<1>, int))(void*, int&&)

      - -
      +
      @@ -88765,8 +88748,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      (void (*)(void*, int&&)) (std::_Placeholder<1>, int)

      - - +
      @@ -88865,8 +88847,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - + @@ -91862,7 +91844,24 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - + + + + + +

      + ...wenn möglich alles auf strukturierte Typen heben +

      + + +
      + + + + + +
      +
      @@ -91878,8 +91877,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      man könnte nun sagen: det sollen se halt nit machen!

      - - +
      @@ -91895,8 +91893,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      Beispielsweise in der aktuellen Logik prüfen wir ob der 1.Slot ein »Valu« ist, was dann bei einer leeren Struct dazu führen würde, diese als ein leeres Param-Tupel zu behandeln. Kommt dann darauf an, ob das tatsächlich einen Schaden im Code anrichtet, oder auch leer durchläuft. Denn an sich sollte es ja egal sein, sofern dann nur dieser Slot auch tatsächlich keine Behandlung bekommt

      - -
      +
      @@ -92045,7 +92042,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - + @@ -92067,7 +92064,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - + + @@ -92111,7 +92109,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - + + + @@ -92122,8 +92122,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - - + + @@ -92199,8 +92199,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - - + + + + + + + @@ -92222,6 +92227,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      + @@ -92234,7 +92240,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - + @@ -92255,13 +92261,12 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      Hut ab für den Poster auf Stackoverflow: der hat diese Möglichkeit gesehen und ist dann nur an ein paar Kleinigkeiten gescheitert.

      - -
      +
      - + @@ -92286,8 +92291,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      ...denn diese Mechanik ist im Grunde komplett unabhängig von Tuples (oder auch sonstigen Strukturen)

      - -
      +
      @@ -92326,16 +92330,13 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      - - - -
      - - - + + + + - + @@ -92365,8 +92366,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      MetaUtils_test::detect_tupleProtocol()

      - - +
      @@ -92377,6 +92377,93 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      + das ist doch der Teil der immer so mühsam ist.... +

      + + +
      +
      + + + + + + + + + + + + + + + + + +

      + extrahiert:  ElmTypes<X>  in variadic-helper.hpp +

      + + +
      + + + + + + + + + + + + + + + + + + + + + + + + +