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:
parent
1df77cc4ff
commit
94d5801712
3 changed files with 127 additions and 27 deletions
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 Ü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ü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& -> irgendwas">
|
||||
<icon BUILTIN="help"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue