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:
parent
9ef3d98de7
commit
2b92dab377
2 changed files with 48 additions and 45 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76090,12 +76090,12 @@ Date:   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ämlichen Problem">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1687131868445" ID="ID_1704149630" MODIFIED="1687133767953" TEXT="jetzt REICHTS mir langsam mit diesem dämlichen Problem">
|
||||
<icon BUILTIN="yes"/>
|
||||
<icon BUILTIN="smiley-angry"/>
|
||||
<node CREATED="1687131919997" ID="ID_830496483" MODIFIED="1687132086162">
|
||||
|
|
@ -76120,8 +76120,40 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1687132088191" ID="ID_1816334696" MODIFIED="1687132118495" TEXT="also kä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öchte)"/>
|
||||
<node CREATED="1687133791082" ID="ID_76046380" MODIFIED="1687134081357">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
also käme erst mal nur in Frage, dort stets die alte Payload
|
||||
</p>
|
||||
<p>
|
||||
zu zerstören und eine neue aus dem zugewiesenen Argument
|
||||
</p>
|
||||
<p>
|
||||
zu konstruieren, was aber meist auch das ist, was man dort möchte
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Der typische use-case, fü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ückgibt, sorgt die RVO dafür, daß dieses Objekt dann (per copy elision) sofort im Puffer im ItemWrapper konstruiert wird — in der Praxis ist das der hä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ö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äuft weiterhin">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue