Library: add move-support to ItemWrapper

...especially relevant in the context of TreeExplorer,
where the general understanding is that the "Data Source" (whatever it is)
will be piggy-backed into the pipeline builder, and this wrapping is
conceived as being essentially a no-op.

It is quite possible we'll even start using such pipeline builders
in concert with move-only types. Just consider a UI-navigator state
hooked up with a massive implementation internal pointer tree attached
to all of the major widgets in the UI. Nothing you want to copy in passing by.
This commit is contained in:
Fischlurch 2017-12-02 04:35:16 +01:00
parent 1df77cc4ff
commit 94d5801712
3 changed files with 127 additions and 27 deletions

View file

@ -61,11 +61,11 @@ namespace wrapper {
using std::function;
/**
* Extension to std::reference_wrapper:
/**
* Extension to std::reference_wrapper:
* Allows additionally to re-bind to another reference,
* almost like a pointer. Helpful for building templates.
* @warning potentially dangerous
* @warning potentially dangerous
*/
template<typename TY>
class AssignableRefWrapper
@ -95,7 +95,7 @@ namespace wrapper {
/**
/**
* Reference wrapper implemented as constant function,
* returning the (fixed) reference on invocation
*/
@ -124,7 +124,7 @@ namespace wrapper {
/**
* Universal value/ref wrapper behaving like a pointer.
* A copyable, assignable value object, not managing ownership.
* It can be default constructed and \c bool evaluated to detect
* It can be default constructed and `bool` evaluated to detect
* an empty holder. The value is retrieved pointer-like, by
* explicit dereferentiation. (Contrast this to std::ref,
* where the original reference is retrieved by conversion)
@ -143,14 +143,15 @@ namespace wrapper {
using TY_unconst = typename meta::UnConst<TY>::Type ;
mutable
mutable
char content_[sizeof(TY)];
bool created_;
template<typename REF>
void
build (TY const& ref)
build (REF&& ref)
{
new(&content_) TY(ref);
new(&content_) TY{std::forward<REF> (ref)};
created_ = true;
}
@ -170,7 +171,7 @@ namespace wrapper {
TY_unconst&
access_unconst() const ///< used to assign new buffer contents
{
return const_cast<TY_unconst&> (access());
return const_cast<TY_unconst&> (access());
}
public:
@ -183,6 +184,11 @@ namespace wrapper {
{
build (o);
}
explicit
ItemWrapper(TY && ro)
{
build (std::move(ro));
}
~ItemWrapper()
{
@ -191,35 +197,62 @@ namespace wrapper {
/* == copy and assignment == */
ItemWrapper (ItemWrapper const& ref)
: created_(false)
{
if (ref.isValid())
build (*ref);
}
ItemWrapper (ItemWrapper && rref)
: created_(false)
{
if (rref.isValid())
{
build (std::move (*rref));
rref.discard();
}
}
ItemWrapper&
operator= (ItemWrapper const& ref)
operator= (ItemWrapper const& cref)
{
if (!ref.isValid())
if (!cref.isValid())
discard();
else
this->operator= (*ref);
this->operator= (*cref);
return *this;
}
ItemWrapper&
operator= (ItemWrapper & ref)
{
return *this = (ItemWrapper const&)ref;
}
ItemWrapper&
operator= (ItemWrapper && rref)
{
if (!rref.isValid())
discard();
else
{
this->operator= (std::move(*rref));
rref.discard();
}
return *this;
}
template<typename X>
ItemWrapper&
operator= (X const& something) ///< accept anything assignable to TY
operator= (X&& something) ///< accept anything assignable to TY
{
if (!isSameObject (something, access() ))
{
if (created_)
access() = something;
access() = std::forward<X>(something);
else
build (something);
build (std::forward<X>(something));
}
return *this;
@ -241,10 +274,16 @@ namespace wrapper {
return access();
}
TY*
operator-> () const
{
return & **this;
}
bool
isValid () const
{
return created_;
return created_;
}
void
@ -253,12 +292,12 @@ namespace wrapper {
discard();
}
};
/**
* Specialisation of the ItemWrapper to deal with references,
* as if they were pointer values. Allows the reference value
* to be default constructed to \c NULL and to be re-assigned.
* to be default constructed to `NULL` and to be re-assigned.
*/
template<typename TY>
class ItemWrapper<TY &>
@ -305,7 +344,7 @@ namespace wrapper {
bool
isValid () const
{
return bool(content_);
return bool(content_);
}
void
@ -334,12 +373,13 @@ namespace wrapper {
/**
/**
* Extension of ItemWrapper: a function remembering
* the result of the last invocation. Initially, the "value"
* is bottom (undefined, NIL), until the function is invoked
* for the first time. After that, the result of the last
* invocation can be accessed by \c operator*()
* is bottom (undefined, NIL), until the function is invoked
* for the first time. After that, the result of the last
* invocation can be accessed by `operator* ()`
*
* @note non-copyable. (removing this limitation would
* require a much more expensive implementation,
@ -370,7 +410,7 @@ namespace wrapper {
/** Create result-remembering functor
* by binding the given function. Explanation:
* - *this is a \em function
* - `*this` is a _function_
* - initially it is defined as invalid
* - then we build the function composition of
* the target function, and a function storing
@ -386,7 +426,7 @@ namespace wrapper {
using lib::meta::func::chained;
// note: binding "this" mandates noncopyable
function<Res(Res)> doCaptureResult = bind (&FunctionResult::captureResult, this, _1 );
function<SIG> chainedWithResCapture = chained (targetFunction, doCaptureResult);
function<SIG> chainedWithResCapture = chained (targetFunction, doCaptureResult);
function<SIG>::operator= (chainedWithResCapture); // define the function (baseclass)
}

View file

@ -35,6 +35,7 @@
#include <functional>
#include <iostream>
#include <cstdlib>
#include <memory>
#include <string>
#include <vector>
@ -51,6 +52,7 @@ namespace test{
using std::placeholders::_1;
using std::ref;
using std::shared_ptr;
using std::vector;
using std::string;
using std::rand;
@ -131,6 +133,7 @@ namespace test{
verifySaneInstanceHandling();
verifySaneMoveHandling();
verifyWrappedRef ();
verifyFunctionResult ();
@ -221,6 +224,60 @@ namespace test{
}
/** @test proper handling of move and rvalue references */
void
verifySaneMoveHandling()
{
using Data = shared_ptr<int>;
using Wrap = ItemWrapper<Data>;
Data data{new int(12345)};
CHECK (1 == data.use_count());
Wrap wrap{data};
CHECK (2 == data.use_count());
CHECK (12345 == **wrap);
CHECK (isSameObject (*data, **wrap));
CHECK (!isSameObject (data, *wrap));
Wrap wcopy{wrap};
CHECK (3 == data.use_count());
Wrap wmove{move (wcopy)};
CHECK (3 == data.use_count());
CHECK (not wcopy);
CHECK (wmove);
wcopy = move(wmove);
CHECK (3 == data.use_count());
CHECK (not wmove);
CHECK (wcopy);
Wrap wmove2{move (data)};
CHECK (0 == data.use_count());
CHECK (3 == wmove2->use_count());
CHECK (not data);
CHECK (wmove2);
CHECK (wrap);
wmove2 = move (wcopy);
CHECK (2 == wmove2->use_count());
CHECK (not wcopy);
CHECK (wmove2);
CHECK (wrap);
wmove2 = move (wrap);
CHECK (1 == wmove2->use_count());
CHECK (not wrap);
CHECK (wmove2);
wmove2 = move (wmove);
CHECK (not wcopy);
CHECK (not wmove);
CHECK (not wmove2);
}
/** @test verify especially that we can wrap and handle
* a reference "value" in a pointer-like manner
*/

View file

@ -5546,7 +5546,7 @@
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1511835691963" ID="ID_175353270" MODIFIED="1511835736414" TEXT="Transform: generic Lambda">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1512181480616" FOLDED="true" ID="ID_1099744034" MODIFIED="1512349511547" TEXT="Beobachtung: move in join">
<node COLOR="#338800" CREATED="1512181480616" FOLDED="true" ID="ID_1099744034" MODIFIED="1512355551250" TEXT="Beobachtung: move in join">
<icon BUILTIN="button_ok"/>
<node CREATED="1512181493551" ID="ID_1834475937" MODIFIED="1512181507297" TEXT="Bei &#xdc;bergabe in stringify() fehlt std::forward"/>
<node CREATED="1512181508053" ID="ID_1058623354" MODIFIED="1512181516343" TEXT="transformIterator strippt die Referenz"/>
@ -5618,6 +5618,9 @@
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1512355552695" ID="ID_1326048469" MODIFIED="1512355578832" TEXT="Beobachtung: ItemWrapper unterst&#xfc;tzt kein move">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1511835901999" ID="ID_1717235881" MODIFIED="1511836238870" TEXT="Transform: Core&amp; -&gt; irgendwas">
<icon BUILTIN="help"/>