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)
This commit is contained in:
Fischlurch 2023-07-13 16:34:10 +02:00
parent 42ac55ea7b
commit 5a8463acce
4 changed files with 109 additions and 19 deletions

View file

@ -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 COR>
class CheckedCore
: public COR
{
static_assert (lib::meta::is_StateCore<COR>::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<typename...ARGS>
CheckedCore (ARGS&& ...init)
: COR(std::forward<ARGS>(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<typename T, class COR>
class IterableDecorator

View file

@ -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<class SRC>
struct is_StateCore
: __and_< HasArglessFun_checkPoint<SRC>
, HasArglessFun_iterNext<SRC>
, HasArglessFun_yield<SRC>
>
{ };
template<class SRC>
struct shall_wrap_STL_Iter
: __and_<can_STL_ForEach<SRC>
@ -297,7 +286,7 @@ namespace lib {
struct _DecoratorTraits<SRC, enable_if<is_StateCore<SRC>>>
{
using SrcVal = typename CoreYield<SRC>::value_type;
using SrcIter = lib::IterableDecorator<SrcVal, SRC>;
using SrcIter = lib::IterableDecorator<SrcVal, lib::CheckedCore<SRC>>;
};
template<class SRC>

View file

@ -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<typename T>
class is_StateCore
{
using Type = typename Strip<T>::Type;
META_DETECT_FUNCTION_ARGLESS(checkPoint);
META_DETECT_FUNCTION_ARGLESS(iterNext);
META_DETECT_FUNCTION_ARGLESS(yield);
public:
enum{ value = HasArglessFun_checkPoint<Type>::value
and HasArglessFun_iterNext<Type>::value
and HasArglessFun_yield<Type>::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
*/

View file

@ -54552,8 +54552,8 @@
<icon BUILTIN="help"/>
</node>
<node COLOR="#435e98" CREATED="1689249180884" ID="ID_1169599821" MODIFIED="1689252396083" TEXT="IterableDecorator : minimalistischer Core-Adapter">
<linktarget COLOR="#4b58db" DESTINATION="ID_1169599821" ENDARROW="Default" ENDINCLINATION="-1279;68;" ID="Arrow_ID_1606137974" SOURCE="ID_537950394" STARTARROW="None" STARTINCLINATION="-2178;95;"/>
<linktarget COLOR="#4f65c2" DESTINATION="ID_1169599821" ENDARROW="Default" ENDINCLINATION="-74;-108;" ID="Arrow_ID_680083681" SOURCE="ID_552745986" STARTARROW="None" STARTINCLINATION="-68;10;"/>
<linktarget COLOR="#4b58db" DESTINATION="ID_1169599821" ENDARROW="Default" ENDINCLINATION="-1279;68;" ID="Arrow_ID_1606137974" SOURCE="ID_537950394" STARTARROW="None" STARTINCLINATION="-2178;95;"/>
<icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1689249279721" ID="ID_1459410871" MODIFIED="1689249306148" TEXT="der Name ist gut &#x2014; es handelt sich um ein eigenst&#xe4;ndiges Konzept">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
@ -54570,7 +54570,7 @@
</html></richcontent>
<icon BUILTIN="list"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689249315278" ID="ID_1697871189" MODIFIED="1689252392003" TEXT="hier bewu&#xdf;t alle Checks wegelassen">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1689249315278" ID="ID_1697871189" MODIFIED="1689258312928" TEXT="bewu&#xdf;t keinerlei &#x27d8; - Checks">
<icon BUILTIN="clanbomber"/>
<node CREATED="1689249330748" ID="ID_1202020886" MODIFIED="1689250409855" TEXT="Begr&#xfc;ndung: das erm&#xf6;glicht auch Einsatz in performance-kritischem Bereich">
<icon BUILTIN="yes"/>
@ -54588,6 +54588,9 @@
<icon BUILTIN="idea"/>
</node>
</node>
<node COLOR="#338800" CREATED="1689258251541" ID="ID_1433183043" MODIFIED="1689258347587" TEXT="Adapter zum Nachr&#xfc;sten: lib::CheckedCore">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
<node CREATED="1535890810111" ID="ID_677938944" MODIFIED="1557498707236" TEXT="IterSource">
@ -79888,7 +79891,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1689248943140" ID="ID_1519420651" MODIFIED="1689248965997" TEXT="je h&#xf6;her die Komplexit&#xe4;t (Metaprogramming), deso unsicherer die Optimierung">
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1689249180884" ID="ID_537950394" MODIFIED="1689250698381" TEXT="IterableDecorator aus IterExplorer extrahieren und verschlanken">
<node COLOR="#435e98" CREATED="1689249180884" ID="ID_537950394" MODIFIED="1689258373692" TEXT="IterableDecorator aus IterExplorer extrahieren und verschlanken">
<arrowlink COLOR="#4b58db" DESTINATION="ID_1169599821" ENDARROW="Default" ENDINCLINATION="-1279;68;" ID="Arrow_ID_1606137974" STARTARROW="None" STARTINCLINATION="-2178;95;"/>
<icon BUILTIN="yes"/>
<node CREATED="1689249237435" ID="ID_1601819255" MODIFIED="1689249275064" TEXT="diese Klasse ist eigentlich sehr sauber geschrieben">
@ -79905,6 +79908,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
<node CREATED="1689249330748" ID="ID_1433877445" MODIFIED="1689249348142" TEXT="Begr&#xfc;ndung: normalierweise setzt man sowas in einer Pipeline ein"/>
<node CREATED="1689249349397" ID="ID_1634720720" MODIFIED="1689249372332" TEXT="Policy: dann m&#xfc;ssen eben im Zweifelsfall die Core-API-Funktionen defensiver sein"/>
<node COLOR="#435e98" CREATED="1689258380915" ID="ID_652271152" MODIFIED="1689258405744" TEXT="lib::CheckedCore &#x2014; dar&#xfc;ber in IterExplorer eingebunden">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>