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 @@
-
-
-
+
-
-
-
+
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+