From 5a8463acceb3687e49e371ef603c2c8c5bf83d7b Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Thu, 13 Jul 2023 16:34:10 +0200 Subject: [PATCH] Block-Flow: allow optionally to supply sanity checks Especially for the BlockFlow allocator, sanity checks are elided for performance reasons; yet, generally speaking, it can be a very bad idea to "optimise" away sanity checks. Thus an additional adaptor is provided to layer such checks on top of an existing core; and IterEplorer now always wires in this additional adaptor, and so the original behaviour is now restored in this respect (and for the largest part of the code base) --- src/lib/iter-adapter.hpp | 78 +++++++++++++++++++++++++++++++++++++-- src/lib/iter-explorer.hpp | 15 +------- src/lib/meta/trait.hpp | 23 ++++++++++++ wiki/thinkPad.ichthyo.mm | 12 ++++-- 4 files changed, 109 insertions(+), 19 deletions(-) diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 97a7d1256..23f29865e 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -35,6 +35,8 @@ ** - 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. + ** - 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 ** by a STL-like pair of "start" and "end" iterators ** @@ -332,7 +334,7 @@ namespace lib { * The resulting iterator will hold an instance of ST, which thus * needs to be copyable and default constructible to the extent * this is required for the iterator as such. - * @see IterExplorer a pipeline builder framework on top of IterStateWrapper + * @see IterableDecorator for variation of the same concept * @see iter-explorer-test.hpp * @see iter-adaptor-test.cpp */ @@ -496,6 +498,73 @@ namespace lib { + /** + * Adapter to add sanity checks to a »state core«. + * @remark It is recommended to perform this kind of sanity checking by default, + * since the performance overhead is minute compared even to a virtual function + * call. However, there might be high-performance usage scenarios, where it is + * essential for the optimiser to be able to "strip every wart". + */ + template + class CheckedCore + : public COR + { + static_assert (lib::meta::is_StateCore::value + ,"Adapted type must expose a »state core« API"); + protected: + COR& + _rawCore() const + { + return unConst(*this); + } + + void + __throw_if_empty() const + { + if (not checkPoint()) + _throwIterExhausted(); + } + + public: + /** blindly pass-down any argument... + * @remark allows slicing move-initialisation from decorated + */ + template + CheckedCore (ARGS&& ...init) + : COR(std::forward(init)...) + { } + + CheckedCore() =default; + CheckedCore (CheckedCore&&) =default; + CheckedCore (CheckedCore const&) =default; + CheckedCore& operator= (CheckedCore&&) =default; + CheckedCore& operator= (CheckedCore const&) =default; + + + /* === state protocol API for IterStateWrapper === */ + bool + checkPoint() const + { + return _rawCore().checkPoint(); + } + + decltype(auto) + yield() const + { + __throw_if_empty(); + return _rawCore().yield(); + } + + void + iterNext() + { + __throw_if_empty(); + _rawCore().iterNext(); + } + }; + + + /** * Decorator-Adapter to make a »state core« iterable as Lumiera Forward Iterator. @@ -507,15 +576,18 @@ namespace lib { * 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. + * API functions instead, or to wrap the Core into \ref CheckedCore. * @tparam T nominal result type (maybe const, but without reference). * The resulting iterator will yield a reference to this type T * @tparam COR type of the »state core«. The resulting iterator will _mix-in_ - * this type, and thus inherit properties like copy, move, VTable, POD. + * this type, and thus inherit properties like copy, move, compare, VTable, POD. * 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&` + * @see IterExplorer a pipeline builder framework on top of IterableDecorator + * @see iter-explorer-test.hpp + * @see iter-adaptor-test.cpp */ template class IterableDecorator diff --git a/src/lib/iter-explorer.hpp b/src/lib/iter-explorer.hpp index 20a59bf51..cb54a74e2 100644 --- a/src/lib/iter-explorer.hpp +++ b/src/lib/iter-explorer.hpp @@ -241,24 +241,13 @@ namespace lib { using std::conditional_t; using std::is_convertible; using std::remove_reference_t; + using meta::is_StateCore; using meta::can_IterForEach; using meta::can_STL_ForEach; using meta::ValueTypeBinding; using meta::has_TypeResult; - META_DETECT_FUNCTION_ARGLESS(checkPoint); - META_DETECT_FUNCTION_ARGLESS(iterNext); - META_DETECT_FUNCTION_ARGLESS(yield); - - template - struct is_StateCore - : __and_< HasArglessFun_checkPoint - , HasArglessFun_iterNext - , HasArglessFun_yield - > - { }; - template struct shall_wrap_STL_Iter : __and_ @@ -297,7 +286,7 @@ namespace lib { struct _DecoratorTraits>> { using SrcVal = typename CoreYield::value_type; - using SrcIter = lib::IterableDecorator; + using SrcIter = lib::IterableDecorator>; }; template diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index cde6023d7..0497d16ab 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -504,6 +504,29 @@ namespace meta { + /** Trait template to detect a type exposing a »state core« API. + * Such a type can be dressed up as "Lumiera Forward Iterator" + * with the help of lib::IterStateWrapper or lib::IterableDecorator. + * This check is heuristic, based on the presence of function names. + */ + template + class is_StateCore + { + using Type = typename Strip::Type; + + META_DETECT_FUNCTION_ARGLESS(checkPoint); + META_DETECT_FUNCTION_ARGLESS(iterNext); + META_DETECT_FUNCTION_ARGLESS(yield); + + public: + enum{ value = HasArglessFun_checkPoint::value + and HasArglessFun_iterNext::value + and HasArglessFun_yield::value + }; + }; + + + /** Trait template to detect a type usable with the STL for-each loop. * Basically we're looking for the functions to get the begin/end iterator */ diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 8914df022..b1e0258b5 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -54552,8 +54552,8 @@ - + @@ -54570,7 +54570,7 @@ - + @@ -54588,6 +54588,9 @@ + + + @@ -79888,7 +79891,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
- + @@ -79905,6 +79908,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
+ + +