diff --git a/src/lib/diff/gen-node.hpp b/src/lib/diff/gen-node.hpp index a38d3b6ee..4839480d8 100644 --- a/src/lib/diff/gen-node.hpp +++ b/src/lib/diff/gen-node.hpp @@ -662,7 +662,7 @@ namespace diff{ struct GenNode::ScopeExplorerIterator : IterStateWrapper { - using IterStateWrapper::IterStateWrapper; + using IterStateWrapper::IterStateWrapper; size_t level() const { return unConst(this)->stateCore().depth(); } }; diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 1c70f6363..fadacc1e4 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -3,6 +3,7 @@ Copyright (C) 2009, Hermann Vosseler + 2017,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 @@ -24,8 +25,8 @@ ** - the IterAdapter retains an active callback connection to the ** controlling container, thus allowing arbitrary complex behaviour. ** - the IterStateWrapper uses a variation of that approach, where the - ** representation of the current state is embedded as an state value - ** element right into the iterator instance. + ** representation of the current state is embedded as a *State Core* + ** value element right into the iterator instance. ** - very similar is IterableDecorator, but this time directly as ** decorator to inherit from the »state core«, and without checks. ** - the RangeIter allows just to expose a range of elements defined @@ -44,7 +45,7 @@ ** references to pre-existing storage locations (not temporaries). ** ** There are many further ways of building a Lumiera Forward Iterator. - ** For example, lib::IterSource exposes a "iterable" source of data elements, + ** For example, lib::IterSource exposes an "iterable" source of data elements, ** while hiding the actual container or generator implementation behind a ** VTable call. Furthermore, complex processing chains with recursive ** expansion can be built with the \ref IterExporer builder function. @@ -59,8 +60,8 @@ ** # Lumiera Forward Iterator concept ** ** Similar to the STL, instead of using a common "Iterator" base class, - ** we rather define a common set of functions and behaviour which can - ** be expected from any such iterator. These rules are similar to STL's + ** we rather define a common set of functions and behaviour which can be + ** expected from any such iterator. These rules are similar to STL's ** "forward iterator", with the addition of an bool check to detect ** iteration end. The latter is inspired by the \c hasNext() function ** found in many current languages supporting iterators. However, by @@ -68,25 +69,28 @@ ** support the various extended iterator concepts from STL and boost ** (random access iterators, output iterators, arithmetics, difference ** between iterators and the like). According to this concept, - ** _an iterator is a promise for pulling values,_ + ** _an iterator is a promise for pulling values once,_ ** and nothing beyond that. ** - ** - Any Lumiera forward iterator can be in a "exhausted" (invalid) state, - ** which can be checked by the bool conversion. Especially, any instance + ** Notably, + ** - any Lumiera forward iterator can be in a "exhausted" (invalid) state, + ** which can be checked by the bool conversion. Especially, an instance ** created by the default ctor is always fixed to that state. This - ** state is final and can't be reset, meaning that any iterator is - ** a disposable one-way-off object. + ** state is final and can not be reset, meaning that any iterator + ** is a disposable one-way-off object. ** - iterators are copyable and equality comparable ** - when an iterator is _not_ in the exhausted state, it may be - ** _dereferenced_ to yield the "current" value. + ** _dereferenced_ to yield the _current value_. + ** - usually, the _current value_ is exposed by-ref (but by-val is possible) ** - moreover, iterators may be incremented until exhaustion. ** ** Conceptually, a Lumiera Iterator represents a lazy stream of calculations ** rather than a target value considered to be »within« a container. And while - ** the result is deliberately _always exposed as a reference,_ to keep the - ** door open for special-case manipulations, for the typical usage it is - ** _discouraged_ to assume anything about the source, beyond the limited - ** access to some transient state as exposed during active iteration. + ** the result is in may cases deliberately _exposed as a reference,_ in order + ** to keep the door open for special-case manipulations, for the typical usage + ** it is _discouraged_ to assume anything about the source, beyond the limited + ** access to some transient state as exposed during active iteration. Together, + ** these rules enable a _loose coupling_ to the source of data. ** ** @see iter-adapter-test.cpp ** @see itertools.hpp @@ -106,6 +110,13 @@ #include +namespace util { // see lib/util.hpp + template + OBJ* unConst (const OBJ*); + template + OBJ& unConst (OBJ const&); +} + namespace lib { @@ -140,6 +151,11 @@ namespace lib { /** type binding helper: an iterato's actual result type */ template using Yield = decltype(std::declval().operator*()); + + /** the _result type_ yielded by a »state core« */ + template + using CoreYield = decltype(std::declval().yield()); + } @@ -328,20 +344,22 @@ namespace lib { /** * Another Lumiera Forward Iterator building block, based on incorporating a state type - * right into the iterator. Contrast this to IterAdapter, which refers to a managing - * container behind the scenes. Here, all of the state is assumed to live in the - * custom type embedded into this iterator, accessed and manipulated through + * as »*State Core*«, right into the iterator. Contrast this to IterAdapter, which refers to + * a managing container behind the scenes. To the contrary, here all of the state is assumed + * to live in the custom type embedded into this iterator, accessed and manipulated through * a dedicated _iteration control API_ exposed as member functions. * - * \par Assumptions when building iterators based on IterStateWrapper - * There is a custom state representation type ST. - * - default constructible - * - this default state represents the _bottom_ (invalid) state. - * - copyable, because iterators are passed by value + * # Requirements for a »State Core« + * When building iterators with the help of IterStateWrapper or \ref IterableAdapter, + * it is assumed that the adapted _state core_ type represents a process of state evolution, + * which reaches a well defined end state eventually, but this end state is also the _bottom_ + * - the core is default constructible + * - this default state represents the _bottom_ (final, invalid) state. + * - copyable, because iterators are passed by value; ideally also assignable * - this type needs to provide an *iteration control API* with the following operations - * -# \c checkPoint establishes if the given state element represents a valid state + * -# \c checkPoint establishes if the given state element represents a valid active state * -# \c iterNext evolves this state by one step (sideeffect) - * -# \c yield realises the given state, yielding an element of result type `T&` + * -# \c yield realises the given state, yielding an element of _result type_ \a T * @tparam T nominal result type (maybe const, but without reference). * The resulting iterator will yield a reference to this type T * @tparam ST type of the »state core«, defaults to T. @@ -352,7 +370,7 @@ namespace lib { * @see iter-explorer-test.hpp * @see iter-adaptor-test.cpp */ - template + template class IterStateWrapper { ST core_; @@ -481,7 +499,7 @@ namespace lib { IT& srcIter() const { - return unConst(*this); + return util::unConst(*this); } public: @@ -526,7 +544,7 @@ namespace lib { COR& _rawCore() const { - return unConst(*this); + return util::unConst(*this); } void @@ -626,26 +644,29 @@ namespace lib { /** - * Decorator-Adapter to make a »state core« iterable as Lumiera Forward Iterator. + * Decorator-Adapter to make a »*State Core*« iterable as Lumiera Forward Iterator. * This is a fundamental (and low-level) building block and works essentially the * same as IterStateWrapper — with the significant difference however that the * _Core is mixed in by inheritance_ and thus its full interface remains publicly * accessible. Another notable difference is that this adapter deliberately * *performs no sanity-checks*. This can be dangerous, but allows to use this * setup even in performance critical code. - * @warning be sure to understand the consequences of using ´core.yield()´ without - * checks; it might be a good idea to build safety checks into the Core - * API functions instead, or to wrap the Core into \ref CheckedCore. + * @warning be sure to understand the consequences of _using_ ´core.yield()´ without + * checks; an iterator built this way _must be checked_ before each use, unless + * it is guaranteed to be valid (by contextual knowledge). It might be a good idea + * to build some safety checks into the Core API functions instead, maybe even just + * as assertions, or to wrap the Core into \ref CheckedCore for most usages. * @tparam T nominal result type (maybe const, but without reference). - * @tparam COR type of the »state core«. The resulting iterator will _mix-in_ - * this type, and thus inherit properties like copy, move, compare, VTable, POD. + * @tparam COR type of the »state core«. The resulting iterator will _mix-in_ this type, + * and thus inherit properties like copy, move, compare, VTable, „POD-ness“. * The COR must implement the following _iteration control API:_ * -# `checkPoint` establishes if the given state element represents a valid state * -# ´iterNext` evolves this state by one step (sideeffect) * -# `yield` realises the given state, exposing a result of type `T&` + * Furthermore, COR must be default-constructible in _disabled_ state * @note the resulting iterator will attempt to yield a reference to type \a T when possible; - * but when the wrapped `COR::yield()` produces a value, this is passed and also - * #operator-> is then disabled, to prevent taking the adress of the value (temporary) + * but when the wrapped `COR::yield()` produces a value, this is passed as such, moreover + * #operator-> becomes disabled then, to prevent taking the address of the (temporary) value! * @see IterExplorer a pipeline builder framework on top of IterableDecorator * @see iter-explorer-test.hpp * @see iter-adaptor-test.cpp @@ -666,11 +687,7 @@ namespace lib { } public: -// typedef T* pointer; -// typedef T& reference; -// typedef T value_type; - /////////////////////////////////////////////////////////////////////////////OOO new YieldRes code - using CoreYield = decltype(std::declval().yield()); + using CoreYield = iter::CoreYield; using _CommonT = meta::CommonResultYield; using YieldRes = typename _CommonT::ResType; using value_type = typename _CommonT::value_type; @@ -700,19 +717,16 @@ namespace lib { explicit operator bool() const { return isValid(); } YieldRes -// reference operator*() const { - return _core().yield(); // core interface: yield + return _core().yield(); // core interface: yield } -// lib::meta::enable_if_c<_CommonT::isRef, -// pointer > pointer operator->() const { if constexpr (_CommonT::isRef) - return & _core().yield(); // core interface: yield + return & _core().yield(); // core interface: yield else static_assert (_CommonT::isRef, "can not provide operator-> " @@ -722,14 +736,14 @@ namespace lib { IterableDecorator& operator++() { - _core().iterNext(); // core interface: iterNext + _core().iterNext(); // core interface: iterNext return *this; } bool isValid () const { - return _core().checkPoint(); // core interface: checkPoint + return _core().checkPoint(); // core interface: checkPoint } bool @@ -774,7 +788,6 @@ namespace lib { * elements of an embedded STL container, without controlling * the details of the iteration (as is possible using the * more generic IterAdapter). - * * @note * - when IT is just a pointer, we use the pointee as value type * - but when IT is a class, we expect the usual STL style nested typedefs @@ -979,7 +992,7 @@ namespace lib { /// Supporting equality comparisons... bool operator!= (NumIter const& o) const { return not operator==(o); } - bool operator== (NumIter const& o) const { return (empty() and o.empty()) // empty iters must be equal (Lumiera iter requirement) + bool operator== (NumIter const& o) const { return (empty() and o.empty()) // empty iters must be equal (Lumiera iter requirement) or (i_ == o.i_ and e_ == o.e_); } private: diff --git a/src/lib/iter-explorer.hpp b/src/lib/iter-explorer.hpp index f56636aac..585b59621 100644 --- a/src/lib/iter-explorer.hpp +++ b/src/lib/iter-explorer.hpp @@ -3,6 +3,7 @@ Copyright (C) 2017, Hermann Vosseler + 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 @@ -259,10 +260,6 @@ namespace lib { { }; - /** the _result type_ yielded by a »state core« */ - template - using CoreYield = decltype(std::declval().yield()); - /** * @internal Type-selector template to adapt for IterExplorer: @@ -277,7 +274,7 @@ namespace lib { struct _DecoratorTraits>> { using SrcRaw = typename lib::meta::Strip::Type; - using SrcVal = typename meta::RefTraits>::Value; + using SrcVal = typename meta::RefTraits>::Value; using SrcIter = lib::IterableDecorator>; }; @@ -1599,19 +1596,21 @@ namespace lib { /* ==== Builder functions ==== */ - /** preconfigure this IterExplorer to allow for _"expansion of children"_. - * The resulting iterator exposes an `expandChildren()` function, which consumes - * the current head element of this iterator and feeds it through the - * _expansion functor_, which was provided to this builder function here. - * The _expansion functor_ is expected to yield a sequence of "child" elements, - * which will be integrated into the overall result sequence instead of the - * consumed source element. Thus, repeatedly invoking `expand()` until exhaustion - * generates a _depth-first evaluation_, since every child will be expanded until - * reaching the leaf nodes of a tree like structure. + /** preconfigure this IterExplorer to allow for _»expansion of children«_. + * The resulting iterator exposes an `expandChildren()` function, which must be + * invoked explicitly and consumes then the current head element of this iterator + * and feeds it through the _expansion functor_, which was provided to this builder + * function here. This _expansion functor_ is expected to yield a compatible sequence + * of "child" elements, which will be integrated into the overall result sequence + * instead of the consumed source element. Thus, repeatedly invoking `expand()` + * until exhaustion generates a _depth-first evaluation_, since every child + * will be expanded until reaching the leaf nodes of a tree like structure. + * The result-type of the compound will be chosen appropriately + * (which may imply to return by-value instead of by-reference) * * @param expandFunctor a "function-like" entity to perform the actual "expansion". * There are two distinct usage patterns, as determined by the signature - * of the provided function or functor: + * of the provided callable, function or functor: * - _"monad style"_: the functor takes a _value_ from the sequence and * produces a new sequence, iterator or collection of compatible values * - _"opaque state manipulation"_: the functor accepts the concrete source @@ -1623,6 +1622,10 @@ namespace lib { * new "child state core" may likewise collaborate with that original * data source or state core behind the scenes; the latter is guaranteed * to exist during the whole lifetime of this IterExplorer. + * @warning be cautions when relying on stored references into the wrapped state core, + * because the IterExplorer pipeline as a whole is meant to be movable; either + * take those references only after the pipeline is »engaged« and placed at its + * final storage location, or ensure a way to „refresh“ this information on move. * @note there is limited support for generic lambdas, but only for the second case. * The reason is, we can not "probe" a template or generic lambda for possible * argument and result types. Thus, if you provide a generic lambda, IterExplorer diff --git a/src/lib/iter-zip.hpp b/src/lib/iter-zip.hpp index f52732836..7d6c6cf2f 100644 --- a/src/lib/iter-zip.hpp +++ b/src/lib/iter-zip.hpp @@ -13,6 +13,11 @@ /** @file iter-zip.hpp ** Iterator builder to combine several iterables into a tuple sequence. + ** Adaptation is based on the capabilities of IterExplorer, and the result + ** will again be a »Lumiera Forward Iterator« and an IterExplorer pipeline builder. + ** Depending on the source sequences, references may be exposed. Moreover, a variant + ** \ref izip() is provided where the result tuple is prefixed with a counter sequence, + ** allowing to perform _iterator with counter_ style evaluations. ** ** @see IterZip_test ** @see iter-explorer.hpp @@ -32,7 +37,6 @@ namespace lib { - namespace iter { /** construction-helper: apply IterExplorer builder packaged tuple */ @@ -43,6 +47,10 @@ namespace lib { return std::make_tuple (lib::explore (std::forward (iters)) ...); } + /** + * Building block for a tupeled-iterator. + * exposes the iterator API lifted to the product type (tuple). + */ template class ProductCore { diff --git a/src/lib/meta/value-type-binding.hpp b/src/lib/meta/value-type-binding.hpp index 8289f1ef4..446609757 100644 --- a/src/lib/meta/value-type-binding.hpp +++ b/src/lib/meta/value-type-binding.hpp @@ -2,7 +2,7 @@ VALUE-TYPE-BINDING.hpp - control type variations for custom containers Copyright (C) - 2010, Hermann Vosseler + 2010,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 @@ -13,7 +13,7 @@ /** @file value-type-binding.hpp ** Type re-binding helper template for custom containers and adapters. - ** This header defines a trait template which is used by the Iterator + ** This header defines trait templates which are used by the Iterator ** adapters and similar custom containers to figure out the value-, ** pointer- and reference types when wrapping iterators or containers. ** @@ -38,6 +38,11 @@ ** treatment, an explicit specialisation to this rebinding trait may be ** injected alongside with the definition of the payload type. ** + ** The CommonResultYield type rebinding helper allows to reconcile several + ** essentially compatible result types; it is used in iterator pipelines, + ** especially for the case of _child expansion,_ where some additional + ** sub-sequences are to be integrated into a main sequence. + ** ** @see ValueTypeBinding_test ** @see iter-adapter.hpp ** @see scope-path.hpp usage example (explicit specialisation) @@ -119,12 +124,16 @@ namespace meta { }; + + /** * Decision helper to select between returning results by value or reference. - * - when both types can not be reconciled, not type result is provided + * - when both types can not be reconciled, _no type result_ is provided; + * this case can be detected by a compile-time bool-check * - when one of both types is `const`, the `ResType` will be const * - when both types are LValue-references, then the result will be a reference, * otherwise the result will be a value type + * @see IterExplorer::expand() */ template>()> struct CommonResultYield diff --git a/tests/library/iter-core-adapter-test.cpp b/tests/library/iter-core-adapter-test.cpp index cfe0c84a0..1659a595e 100644 --- a/tests/library/iter-core-adapter-test.cpp +++ b/tests/library/iter-core-adapter-test.cpp @@ -20,31 +20,24 @@ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "lib/util.hpp" -#include "lib/test/diagnostic-output.hpp"////////////TODO #include "lib/iter-adapter.hpp" -//#include -//#include +#include namespace lib { - using util::unConst; namespace test{ using LERR_(ITER_EXHAUST); -// using boost::lexical_cast; -// using util::for_each; -// using util::isnil; using util::isSameObject; -// using std::vector; + using std::string; - - namespace { + namespace { // Test fixture /** - * A »*State Core*« to step down numbers to zero. + * A test »*State Core*« which steps down a number to zero. * @note this is a minimal description of a state progression towards a goal * - default constructed is equivalent to _goal was reached_ * - can be copied, manipulated and compared @@ -83,7 +76,7 @@ namespace test{ return n == o.n; } }; - } // (END) impl test dummy container + }// (END) test dummy @@ -95,6 +88,7 @@ namespace test{ * @test cover the concept of a »state core«, which is used in Lumiera * for various aspects of data generation and iteration. * @see IterStateWrapper + * @see iter-adapter.hpp * @see iter-explorer.hpp */ class IterCoreAdapter_test : public Test @@ -106,14 +100,14 @@ namespace test{ stateManipulation(); checked_and_protected(); value_and_reference_yield(); + verify_TypeReconciliation(); } - /** @test build a »Lumiera Forward Iterator« - * to transition a State-Core towards it final state + * to transition a State-Core towards it final state. */ void simpleUsage() @@ -186,10 +180,10 @@ namespace test{ /** @test adapters can (transparently) handle a core which yields values - * - demonstrate how cores can be augmented by decoration - * - the decorated core here yields by-value - * - both CheckedCore and IterableDecorator can cope with that - * - the result is then also delivered by-value from the iterator + * - demonstrate how cores can be augmented by decoration... + * - the decorated core here yields by-value, not by-ref. + * - Both CheckedCore and IterableDecorator can cope with that + * - the result is then also delivered by-value from the iterator. * @remark the »Lumiera Forward Iterator« concept does not exactly specify * what to expect when dereferencing an iterator; yet for obvious reasons, * most iterators in practice expose a reference to some underlying container @@ -199,7 +193,7 @@ namespace test{ * for the compiler, the code using the iterator is not tightly coupled). This * scheme has ramifications for the way any iterator pipeline works; notably * any _transformation_ will have to capture a function result. However, - * sometimes an iterator can only return a computed value; such a usage + * sometimes an iterator can only return a computed value; such an usage * can be valid and acceptable and is supported to the degree possible. */ void @@ -233,6 +227,61 @@ namespace test{ } + /** @test construction of a common result type. + * - based on `std::common_type` + * - so there must be some common ground + * - if any of the types is by-value, the result is + * - if any of the types is const, the result is const + */ + void + verify_TypeReconciliation() + { + using C1 = Common; + CHECK (not C1()); + CHECK (not C1::value); + + using C2 = Common; + CHECK (not C2()); // can not be reconciled + CHECK (not C2::value); +// using X = C2::ResType; // does not (and should not) compile + + using C3 = Common; + CHECK (C3()); + CHECK (showType() == "string"_expect ); + + using C4 = Common; + CHECK (showType() == "string"_expect ); + + using C5 = Common; + CHECK (showType() == "string&"_expect ); // ref access to both is possible + + using C6 = Common; + CHECK (showType() == "string"_expect ); // caution, RValue might be a temporary + + using C7 = Common; + CHECK (showType() == "string"_expect ); + + using C8 = Common; + CHECK (showType() == "string const&"_expect ); + + using C9 = Common; + CHECK (showType() == "string const&"_expect ); // reconcile to const& + + using C10 = Common; + CHECK (showType() == "const string"_expect ); + + using C11 = Common; + CHECK (showType() == "const string"_expect ); // reconciled to value type + + using C12 = Common; + CHECK (showType() == "const long"_expect ); // reconciled to the larger number type + + using C13 = Common; + CHECK (showType() == "double const&"_expect ); // usual in C++ (loss of precision possible) + } + + template + using Common = meta::CommonResultYield; }; LAUNCHER (IterCoreAdapter_test, "unit common"); diff --git a/tests/library/iter-zip-test.cpp b/tests/library/iter-zip-test.cpp index d61e4fd8f..4f8aaa628 100644 --- a/tests/library/iter-zip-test.cpp +++ b/tests/library/iter-zip-test.cpp @@ -410,7 +410,7 @@ namespace test{ /** @test the result is actually an IterExplorer pipeline builder, - * which can be used to attach further processing. + * which can be used to attach further processing downstream. * @note the design of IterExplorer inherently requires that * generic lambdas accept the _iterator type_ by reference; * structural bindings can only be used in a second step. @@ -418,6 +418,16 @@ namespace test{ void verify_pipelining() { + // for reference: this is the base data....... + CHECK (materialise ( + zip (num31(), num32(), num33()) + ) + == "«tuple»──(1,2,3)-" + "«tuple»──(4,5,6)-" + "«tuple»──(7,8,9)-" + "«tuple»──(10,11,12)-" + "«tuple»──(13,14,15)"_expect); + // transform the tuple into another data value CHECK (materialise ( zip (num31(), num32(), num33()) @@ -447,23 +457,7 @@ namespace test{ } - template - void - resu() - { MARK_TEST_FUN - using RT = meta::CommonResultYield; -SHOW_EXPR(RT()) - if constexpr (RT()) - { -SHOW_EXPR(RT::isConst) -SHOW_EXPR(RT::isRef) -SHOW_TYPE(typename RT::_Common ) -SHOW_TYPE(typename RT::_ConstT ) -SHOW_TYPE(typename RT::_ValRef ) -SHOW_TYPE(typename RT::ResType ) -SHOW_TYPE(typename RT::reference) - } - } + /** @test verify the interplay of _child expansion_ and tuple-zipping. * @remark the expansion mechanism implies that a _child sequence_ is generated * by an _expand functor,_ based on the current iterator value at that point. @@ -483,18 +477,6 @@ SHOW_TYPE(typename RT::reference) void verify_exploration() { -/* - resu(); - resu(); - resu(); - resu(); - resu(); - resu(); - resu(); - resu(); - resu(); -*/ - CHECK (materialise ( num31() ) @@ -519,7 +501,7 @@ SHOW_TYPE(typename RT::reference) ( eachNum(10) , explore(num31()) .expand ([](int i){ return NumIter{noneg(i-1),i}; }) - .expandAll() + .expandAll() // ◁────────────────────────────────────────────── expand triggered in source pipeline, before the zip() , explore(num31()) .expand ([](int i){ return NumIter{noneg(i-2),i-1}; }) .expandAll() @@ -579,17 +561,6 @@ SHOW_TYPE(typename RT::reference) "«tuple»──(10,6,3)-" "«tuple»──(10,5,1)"_expect); } -/* -SHOW_EXPR - (materialise ( - zip (num31(), num32(), num33()) - ) - ) - CHECK (materialise ( - zip (num31(), num32(), num33()) - ) - == ""_expect); -*/ }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 8825a4b7b..11610ed0d 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -19639,9 +19639,7 @@ - - - +

das Kind-Widget muß ElementBox überleben; und das bedeutet, es muß ein Sibling sein... (problematisch für die Struktur vom ClipWidget, es sei denn, man macht ElementBox dort zu einem Member — was allerdings wiederum der Anforderung widerspricht, daß das Clip-Delegate direkt ein Widget ist und sich darstellen kann) @@ -20117,9 +20115,7 @@ - - - +

Höhe nur 16px, obwohl doch das Icon mindestens 18px braucht (incl.Border), und das get_required_height() diesen Wert eigentlich liefern sollte @@ -20628,9 +20624,7 @@ - - - +

...denn: @@ -21090,9 +21084,7 @@ - - - +

um zu dokumentieren, daß wir in diesem Visitor-Mischfall am Konzept vorbei implementieren @@ -22078,9 +22070,7 @@ - - - +

weil dieses nicht weiß, daß es sich um eine Subtyp-Beziehung handelt @@ -23583,9 +23573,7 @@ - - - +

 �� generische ZoomWindow-Komponente @@ -27019,9 +27007,7 @@ - - - +

In Anspielung auf @@ -36158,9 +36144,7 @@ - - - +

Helper to build the menu and for registering and handling of user action events @@ -39701,9 +39685,7 @@ - - - +

  • @@ -41058,9 +41040,7 @@ - - - +

    Konkretes Rechenbeispiel: @@ -42021,9 +42001,7 @@ - - - +

    ...und das betrachte ich als gutmütig und hinreichend abgesichert... @@ -42535,9 +42513,7 @@ - - - +

    ...welche ich inzwischen nahezu komplett einmal umgepflügt habe... @@ -42911,9 +42887,7 @@ - - - +

    sonst kann man eine fehlerfreie Kalkulation nicht garantieren @@ -43336,9 +43310,7 @@ - - - +

    wir rechnen von der Duration auf eine Metrik um, weil wir den Mechanismus zur relativen Positionierung haben wollen. Dieser muß aber detox() verwenden, weil sonst die Division mit der Pixel-Zahl einen numeric-wrap machen würde.... @@ -52625,13 +52597,16 @@ - + + - - - - + + + + + + @@ -52650,16 +52625,17 @@ - - + + - - + + + @@ -52945,8 +52921,8 @@ - - + + @@ -52956,7 +52932,7 @@ - + @@ -53143,8 +53119,8 @@ - - + + @@ -53191,8 +53167,7 @@ ...auch wenn es normalerweise kein Performance-Problem darstellt, weil der Optimiser redundante Aufrufe problemlos eliminiert, macht es die Typen für den Außenstehend noch viel undurchtringbarer, und belastet auch die Debug-Builds durch den Umfang unnötiger Typ-Information

    - -
    +
    @@ -53326,9 +53301,9 @@ - + - + @@ -53341,7 +53316,7 @@ - + @@ -53349,7 +53324,7 @@ - + @@ -53369,8 +53344,7 @@ habe die mehrfachen Adapter nun allesamt weg; daher wäre es nun doch denkbar, da die Call-Pfade nun von einem Punkt aus aufspalten (nämlich Core::yield ->  entweder operator* oder operator-> )

    - -
    +
    @@ -53378,7 +53352,7 @@ - + @@ -53402,8 +53376,7 @@ Booo!  is_const_v<T&> ist immer false

    - - +
    @@ -53418,9 +53391,8 @@ - - - + + @@ -53449,8 +53421,7 @@
- -
+
@@ -53470,8 +53441,7 @@ es wird vermutlich auf wenige Fälle beschränkt bleiben, in denen es aber durchaus hilfreich ist, da sowohl Generatoren als auch Transformatoren einfacher zu schreiben sind

- -
+
@@ -53499,15 +53469,15 @@ der auto-Expander kann und darf ja nicht wissen, wo genau unterhalb die Expansion stattfindet; wenn eben gar keine stattfindet, dann bleiben alle durchgereichten expandChildren()-Aufrufe ohne Wirkung, aber ein iterNext() wird dann auch nicht mehr gesendet

- - + - + + @@ -53517,21 +53487,65 @@ - - - + + + - - + + + + + + + +

+ ich kann mir keinen Fall vorstellen, in dem der Default gelten könnte; vermutlich habe ich den Default damals angeschrieben, als ich mir das Konzept neu ausgedacht habe, und mir noch nicht klar war, wohin das führt (und wie bedeutend das mal wird....) +

+ +
- + + + + + + + + + + + + +

+ ...und zwar in LinkedElements. +

+

+ Das ist nicht irgend ein Randfall, sondern eine der zentralen Nutzungsmöglichkeiten: um nämlich einen iterator und einen const-iterator aus der gleichen Core zu erzeugen +

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