Library: change »assignment« of ItemWrapper to destroy-create

This very deep change (which requires almost complete rebuild)
was prompted by the need to process an object (JobPlanning),
which holds several references and is thus move-only, in the
middle of a complex processing pipeline with child expansion.

If this works out well, a long-standing and obnoxious problem
with transforming iterators would be solved, albeit by incurring
a (presumably small) performance overhead, since now the new
value is no longer *assigned*, but rather the existing payload
is destroyed and a new instance is copy/move constructed into
the inline buffer.

The primary purpose (and widely used in Lumieara) is to have a
Lambda create a new Object, which is then returned by value
and thus immediately moved into this inline buffer, where it
resides for further use (as long as the enclosing pipeline
stays alive). Unless such an object does very elaborate
allocations and registrations behind the scene, the
expense of assigning vs creating should be the same.
This commit is contained in:
Fischlurch 2023-06-19 02:33:50 +02:00
parent 9ef3d98de7
commit 2b92dab377
2 changed files with 48 additions and 45 deletions

View file

@ -25,7 +25,6 @@
** This is (intended to become) a loose collection of the various small helper templates
** for wrapping, containing, placing or handling a somewhat \em problematic other object.
** Mostly these are implemented to suit a specific need and then factored out later on.
** - AssignableRefWrapper is not used anymore as of 12/09
** - ItemWrapper is a similar concept, but more like a smart-ptr. Moreover,
** it can be instantiated with a value type, a pointer or a reference type,
** yielding the same behaviour in all cases (useful for building templates)
@ -63,39 +62,6 @@ namespace wrapper {
using std::function;
/**
* Extension to std::reference_wrapper:
* Allows additionally to re-bind to another reference,
* almost like a pointer. Helpful for building templates.
* @warning potentially dangerous
*/
template<typename TY>
class AssignableRefWrapper
: public std::reference_wrapper<TY>
{
typedef std::reference_wrapper<TY> RefWrapper;
public:
explicit AssignableRefWrapper(TY& ref)
: RefWrapper(ref)
{ }
AssignableRefWrapper&
operator= (RefWrapper const& o)
{
RefWrapper::operator= (o);
return *this;
}
AssignableRefWrapper&
operator= (TY& newRef)
{
(*this) = RefWrapper(newRef);
return *this;
}
};
/**
* Reference wrapper implemented as constant function,
@ -128,7 +94,7 @@ namespace wrapper {
* A copyable, assignable value object to hold a given value within
* an embedded inline buffer. It can be default constructed and `bool`
* evaluated to detect an empty holder. The value is retrieved through
* a pointer-like interface, by explicit dereferentiation. (Contrast this
* a pointer-like interface, by explicit dereferentiation. (Contrast this
* to std::ref, where the original reference is retrieved by conversion).
* @note when the embedded value is a pointer, ItemWrapper does _not_ take
* ownership of and manage data the pointer is pointing to.
@ -249,18 +215,23 @@ namespace wrapper {
return *this;
}
/**
* Emulate »assignment« by discarding and then construction of a new payload
* @param something from which TY can be (copy/move)constructed
* @remark allows handling »move-only« types; for the typical use case, something
* new is fabricated in a lambda and then moved into the ItemWrapper; thus
* the performance overhead of destroy/re-created is not deemed relevant.
* SFINAE tricks on hidden/deleted assignment operator can be unreliable.
*/
template<typename X>
ItemWrapper&
operator= (X&& something) ///< accept anything assignable to TY
operator= (X&& something)
{
if (!isSameObject (something, access() ))
{
if (created_)
access() = std::forward<X>(something);
else
build (std::forward<X>(something));
discard();
build (std::forward<X>(something));
}
return *this;
}

View file

@ -76090,12 +76090,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1687131811965" ID="ID_1192855537" MODIFIED="1687131818555" TEXT="Pipeline-Definition umbauen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1687131819547" ID="ID_1957351479" MODIFIED="1687131843128" TEXT="Problem: ItemWrapper weist Werte zu">
<node COLOR="#435e98" CREATED="1687131819547" ID="ID_1957351479" MODIFIED="1687133763828" TEXT="Problem: ItemWrapper weist Werte zu">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1687131845108" ID="ID_1247271270" MODIFIED="1687131867304" TEXT="...und kann deshalb keine non-copyable-Typen handhaben">
<icon BUILTIN="info"/>
</node>
<node CREATED="1687131868445" ID="ID_1704149630" MODIFIED="1687131886190" TEXT="jetzt REICHTS mir langsam mit diesem d&#xe4;mlichen Problem">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1687131868445" ID="ID_1704149630" MODIFIED="1687133767953" TEXT="jetzt REICHTS mir langsam mit diesem d&#xe4;mlichen Problem">
<icon BUILTIN="yes"/>
<icon BUILTIN="smiley-angry"/>
<node CREATED="1687131919997" ID="ID_830496483" MODIFIED="1687132086162">
@ -76120,8 +76120,40 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
</node>
<node CREATED="1687132088191" ID="ID_1816334696" MODIFIED="1687132118495" TEXT="also k&#xe4;me erst mal nur in Frage, dort generell stets neu zu konstruieren"/>
<node CREATED="1687132120955" ID="ID_170368448" MODIFIED="1687132134893" TEXT="(was aber meist auch das ist, was man dort m&#xf6;chte)"/>
<node CREATED="1687133791082" ID="ID_76046380" MODIFIED="1687134081357">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
also k&#228;me erst mal nur in Frage, dort stets die alte Payload
</p>
<p>
zu zerst&#246;ren und eine neue aus dem zugewiesenen Argument
</p>
<p>
zu konstruieren, was aber meist auch das ist, was man dort m&#246;chte
</p>
</body>
</html></richcontent>
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Der typische use-case, f&#252;r den dieser ItemWrapper geschaffen wurde, ist, ein beliebiges Lambda auszuwerten, und das Resultat dann im Puffer vorzuhalten; speziell wenn das Lambda ein neues Objekt konstruiert und per Value zur&#252;ckgibt, sorgt die RVO daf&#252;r, da&#223; dieses Objekt dann (per copy elision) sofort im Puffer im ItemWrapper konstruiert wird &#8212; in der Praxis ist das der h&#228;ufigste use-case und tritt im Besonderen in einem Transform-Iterator auf. Wenn andererseits die Payload ein POD oder einfacher Wert ist, dann sind Destruktor und Konstruktor ohnehin trivial...
</p>
</body>
</html></richcontent>
</node>
</node>
<node COLOR="#338800" CREATED="1687133731282" ID="ID_555251890" MODIFIED="1687133759710" TEXT="Also umbauen: nun zerst&#xf6;rt er und copy/move-konstruiert eine neue Payload">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1687134089434" ID="ID_1039273215" MODIFIED="1687134115826" TEXT="Nach nahezu komplettem reBuild: Testsuite l&#xe4;uft weiterhin">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>