From c09f44e20f5b0e3a19f46b5be6d338cd6fc7e0e4 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 25 Mar 2024 03:03:18 +0100 Subject: [PATCH] Library: complete implementation of Map-databinding ...using a ''special protocol'' to represent iterative data sequences * use an Index-Key with a CSV list of element prefixes * synthesise key-prefixes for each data element * perform lookup with the decorated key first This allows to somehow ''emulate'' nested associations within a single, flat Map. Obviously this is more like a proof-of-concept; actually the Map-databinding is meant to handle the simple cases, where just placeholders are to be substituted. The logic structures are much more relevant when binding to structural data, most notably to the Lumiera _External Tree Description_ format, which is used for model data and inter-layer communication. --- src/lib/text-template.hpp | 51 ++++++++++-- wiki/thinkPad.ichthyo.mm | 163 +++++++++++++++++++++----------------- 2 files changed, 134 insertions(+), 80 deletions(-) diff --git a/src/lib/text-template.hpp b/src/lib/text-template.hpp index ba548abd6..3d9bad904 100644 --- a/src/lib/text-template.hpp +++ b/src/lib/text-template.hpp @@ -122,6 +122,7 @@ namespace lib { using StrView = std::string_view; using util::_Fmt; + using util::isnil; using util::unConst; @@ -140,7 +141,7 @@ namespace lib { iterNestedKeys (string key, string const& iterDef) { return explore (util::RegexSearchIter{iterDef, ACCEPT_DATA_ELM}) - .transform ([&](smatch mat){ return key+"."+string{mat[1]}; }); + .transform ([&](smatch mat){ return key+"."+string{mat[1]}+"."; }); } @@ -521,37 +522,75 @@ namespace lib { using MapS = std::map; + /** + * Data-binding for a Map-of-strings. + * Simple keys are retrieved by direct lookup. + * For the representation of nested data sequences, + * the following conventions apply + * - the data sequence itself is represented by an index-key + * - the value associated to this index-key is a CSV sequence + * - each element in this sequence defines a key prefix + * - nested keys are then defined as `..` + * - when key decoration is enabled for a nested data source, each + * lookup for a given key is first tried with the prefix, then as-is. + * Consequently, all data in the sequence must be present in the original + * map, stored under the decorated keys. + * @note multiply nested sequences are _not supported._ + * While it _is_ possible to have nested loops, the resulting sets + * of keys must be disjoint and data must be present in the base map. + * @see TextTemplate_test::verify_Map_binding() + */ template<> struct TextTemplate::DataSource { MapS const * data_; - using Iter = decltype(iterNestedKeys("","")); + string keyPrefix_{}; + + bool isNested() { return not isnil (keyPrefix_); } + bool contains (string key) { - return util::contains (*data_, key); + return (isNested() and util::contains (*data_, keyPrefix_+key)) + or util::contains (*data_, key); } string const& retrieveContent (string key) { - auto elm = data_->find (key); + MapS::const_iterator elm; + if (isNested()) + { + elm = data_->find (keyPrefix_+key); + if (elm == data_->end()) + elm = data_->find (key); + } + else + elm = data_->find (key); ENSURE (elm != data_->end()); return elm->second; } + + using Iter = decltype(iterNestedKeys("","")); + Iter getSequence (string key) { - UNIMPLEMENTED ("extract data sequence from definition key"); + if (not contains(key)) + return Iter{}; + else + return iterNestedKeys (key, retrieveContent(key)); } DataSource openContext (Iter& iter) { REQUIRE (iter); - UNIMPLEMENTED ("open a nested sub-data-ctx based on the given iterator"); + DataSource nested{*this}; + nested.keyPrefix_ = *iter; + return nested; } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 7637a9f5d..6657732b6 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -112477,11 +112477,11 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + - - + + @@ -112496,8 +112496,8 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + @@ -112505,12 +112505,12 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + - - + + @@ -112518,12 +112518,13 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + + - - + + @@ -112621,13 +112622,13 @@ std::cout << tmpl.render({"what", "World"}) << s - - - - + + + + - - + + @@ -112645,16 +112646,18 @@ std::cout << tmpl.render({"what", "World"}) << s - - - - + + + + + - - + + - - + + + @@ -112731,8 +112734,8 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + @@ -112854,10 +112857,10 @@ std::cout << tmpl.render({"what", "World"}) << s - - - - + + + + @@ -112908,8 +112911,8 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + @@ -112925,18 +112928,18 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + - - + + - - + + @@ -112954,8 +112957,8 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + @@ -112966,18 +112969,18 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + - + - + @@ -113042,12 +113045,12 @@ std::cout << tmpl.render({"what", "World"}) << s - - + + - + @@ -113383,32 +113386,39 @@ std::cout << tmpl.render({"what", "World"}) << s - - - + + + + + + - + - + - + - - + + + + + - - - - + + + + + @@ -113428,27 +113438,27 @@ std::cout << tmpl.render({"what", "World"}) << s - - - + + + - - - - + + + + - - + + - - + + @@ -113461,6 +113471,10 @@ std::cout << tmpl.render({"what", "World"}) << s + + + + @@ -113513,6 +113527,7 @@ std::cout << tmpl.render({"what", "World"}) << s +