diff --git a/src/lib/replaceable-item.hpp b/src/lib/replaceable-item.hpp deleted file mode 100644 index b593b0877..000000000 --- a/src/lib/replaceable-item.hpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - REPLACEABLE-ITEM.hpp - adapter to take snapshot from non-assignable values - - Copyright (C) - 2017, Hermann Vosseler - -  **Lumiera** is free software; you can redistribute it and/or modify it -  under the terms of the GNU General Public License as published by the -  Free Software Foundation; either version 2 of the License, or (at your -  option) any later version. See the file COPYING for further details. - -*/ - -/** @file replaceable-item.hpp - ** Adapter wrapper to treat non-assignable values as if they were assignable. - ** Prerequisite is for the type to be copy constructible (maybe even just move constructible). - ** The typical usage is when we want to take a _snapshot_ from some value, but do not actually - ** need the ability to assign something to a specific object instance. In such a situation, - ** we may just destroy a previous snapshot and then place a new copy initialised value into - ** the same storage space. For all really assignable types we fall back to a trivial - ** implementation. - ** - ** \par motivation - ** The typical usage is in library or framework code, where we do not know what types to expect. - ** For example, the Lumiera command framework automatically captures an _UNDO memento_ based - ** on the return type of a state capturing function. It would be highly surprising for the - ** user if it wasn't possible to capture e.g. time values or durations as _old state_, - ** because these entities can not be re-assigned with new values, only created. - ** But obviously a command handling framework needs the ability to capture - ** state consecutively several times, and this adapter was created - ** to bridge this conceptual discrepancy - ** - ** \par extensions - ** - the type can be solely move constructible, in which case the payload needs to be - ** moved explicitly when embedding into this adapter ///////////////////////////////////////////////TICKET 1059 : does not work yet on GCC-4.9 - ** - when the payload is equality comparable, the container is as well, by delegation - ** - container instances can be default created, which emplaces an _empty value_. - ** The actual value to embed is retrieved from the lib::NullValue template, - ** which is a static per-type singleton. - ** - thus types which are not even default constructible can still be used, - ** by providing an explicit specialisation of lib::NullValue for this type. - ** - ** @see ReplaceableIterm_test - ** @see steam::control::MementoTie - ** - */ - - -#ifndef LIB_REPLACEABLE_ITEM_H -#define LIB_REPLACEABLE_ITEM_H - -#include "lib/error.hpp" -#include "lib/null-value.hpp" -#include "lib/meta/util.hpp" -#include "lib/util.hpp" - -#include -#include -#include - - - -namespace lib { -namespace wrapper { - - using util::isSameObject; - using util::unConst; - using std::forward; - - - - - /** - * Adapter container to take snapshots from non-assignable values. - * Implemented by placing the subject into an inline buffer. - * @note uses lib::NullValue to retrieve an _empty payload_. - */ - template - class ReplaceableItem - { - alignas(X) - std::byte content_[sizeof(X)]; - - public: - ReplaceableItem() - { - emplace (NullValue::get()); - } - ~ReplaceableItem() - { - destroy(); - } - - template - ReplaceableItem (Z&& otherValue) - { - emplace (forward (otherValue)); - } - - template - ReplaceableItem& - operator= (Z&& otherValue) - { - if (not isSameObject(*this, otherValue)) - reAssign (forward (otherValue)); - return *this; - } - - ReplaceableItem& - clear() noexcept - { - reAssign (NullValue::get()); - return *this; - } - - operator X&() { return access(); } - operator X const&() const { return unConst(this)->access(); } - - X& get() { return access(); } - X const& get() const { return unConst(this)->access(); } - - - private: - X& - access() - { - return * std::launder (reinterpret_cast (&content_)); - } - - void - destroy() - { - access().~X(); - } - - template - void - emplace (Z&& otherValue) - try { - new(&content_) X{forward (otherValue)}; - } - catch(...) { - new(&content_) X{NullValue::get()}; - } - - template - void - reAssign (Z&& otherValue) - { - destroy(); - emplace (forward (otherValue)); - } - }; - - - - template - struct is_assignable_value - : std::__and_, std::__not_>> - { }; - - /** - * simple delegating implementation - * to use for regular cases - */ - template - class ReplaceableItem>> - { - X val_; - - public: - ReplaceableItem() : val_(NullValue::get()) { } - - ReplaceableItem(X const& val) : val_(val) { } - ReplaceableItem(X && val) : val_(forward(val)) { } - - ReplaceableItem& operator= (X const& val) { val_=val; return *this; } - ReplaceableItem& operator= (X && val) { val_=forward(val); return *this; } - ReplaceableItem& clear() noexcept { val_=NullValue::get(); return *this; } - - operator X&() { return val_; } - operator X const&() const { return val_; } - - X& get() { return val_; } - X const& get() const { return val_; } - }; - - - /** disallow embedding references */ - template - class ReplaceableItem>> - { - static_assert( not sizeof(X), "ReplaceableItem for references is pointless"); - }; - - - /* ===== Equality comparison delegated to contained element ===== */ - - template - inline bool - operator== (ReplaceableItem const& li, ReplaceableItem const& ri) - { - return li.get() == ri.get(); - } - template - inline bool - operator!= (ReplaceableItem const& li, ReplaceableItem const& ri) - { - return li.get() != ri.get(); - } - - template - inline bool - operator== (ReplaceableItem const& item, Z const& something) - { - return item.get() == something; - } - template - inline bool - operator!= (ReplaceableItem const& item, Z const& something) - { - return item.get() != something; - } - - template - inline bool - operator== (Z const& something, ReplaceableItem const& item) - { - return item.get() == something; - } - template - inline bool - operator!= (Z const& something, ReplaceableItem const& item) - { - return item.get() != something; - } - - - -}} // namespace lib::wrap -#endif /*LIB_REPLACEABLE_ITEM_H*/ diff --git a/src/steam/control/memento-tie.hpp b/src/steam/control/memento-tie.hpp index 209799e77..278e4f142 100644 --- a/src/steam/control/memento-tie.hpp +++ b/src/steam/control/memento-tie.hpp @@ -34,7 +34,8 @@ #include "lib/meta/maybe-compare.hpp" #include "lib/meta/function-closure.hpp" #include "steam/control/command-signature.hpp" -#include "lib/replaceable-item.hpp" +//#include "lib/replaceable-item.hpp" +#include "lib/wrapper.hpp" #include "lib/format-obj.hpp" #include "lib/util.hpp" @@ -51,7 +52,7 @@ namespace control { using lib::meta::func::bindLast; using lib::meta::func::chained; using lib::meta::equals_safeInvoke; - using lib::wrapper::ReplaceableItem; + using lib::wrapper::ItemWrapper; /** @@ -82,7 +83,7 @@ namespace control { typedef typename CommandSignature::CaptureSig SIG_cap; typedef typename CommandSignature::UndoOp_Sig SIG_undo; - ReplaceableItem memento_; ///< storage holding the captured state for undo + ItemWrapper memento_; ///< storage holding the captured state for undo bool isCaptured_; @@ -110,10 +111,10 @@ namespace control { */ MementoTie (function const& undoFunc, function const& captureFunc) - : memento_() - , isCaptured_(false) - , undo_(undoFunc) - , capture_(captureFunc) + : memento_{} + , isCaptured_{false} + , undo_{undoFunc} + , capture_{captureFunc} { } @@ -124,7 +125,7 @@ namespace control { clear() { isCaptured_ = false; - memento_.clear(); + memento_.reset(); } /** bind the undo function to the internal memento store within this object. @@ -163,10 +164,10 @@ namespace control { MEM& getState () { - if (!isCaptured_) + if (not isCaptured_) throw err::State{"need to invoke memento state capturing beforehand" , LERR_(MISSING_MEMENTO)}; - return memento_; + return *memento_; } @@ -183,7 +184,7 @@ namespace control { bool isValid () const { - return undo_ && capture_ && isCaptured_; + return undo_ and capture_ and isCaptured_; } /** for diagnostics: include format-util.hpp */ @@ -195,14 +196,14 @@ namespace control { template MementoTie::operator std::string() const { - if (!undo_ || !capture_) + if (!undo_ or !capture_) return "·noUNDO·"; - if (!isCaptured_) + if (not isCaptured_) return ""; return ""; } diff --git a/tests/15library.tests b/tests/15library.tests index 86331a4b5..cf0416473 100644 --- a/tests/15library.tests +++ b/tests/15library.tests @@ -527,11 +527,6 @@ return: 0 END -TEST "inline adapter for state snapshot" ReplaceableItem_test < int Tracker::instanceCnt (0); - /** prepare a (singleton) _empty value_ for the memento. - * @remarks This is done prior to observing the Tracker instanceCnt, - * because this empty value obviously remains allocated forever. - * The memento is stored within a [special holder](\ref lib::ReplaceableItem) - * to allow capturing memento state even from immutable values, which only can - * be copy constructed. This mechanism uses lib::NullValue to retrieve an - * empty placeholder value when the memento has not yet been captured. - */ - void - prepareEmptyMemento() - { - lib::NullValue>::get(); - } /** Dummy custom memento datatype * @note memento needs to be equality comparable @@ -202,7 +189,6 @@ namespace test { { seedRand(); ArgTuples testTuples; - prepareEmptyMemento(); Tracker::instanceCnt = 0; Tracker::instanceCnt = 0; diff --git a/tests/core/steam/control/memento-tie-test.cpp b/tests/core/steam/control/memento-tie-test.cpp index 1c625b3a3..2d30033d5 100644 --- a/tests/core/steam/control/memento-tie-test.cpp +++ b/tests/core/steam/control/memento-tie-test.cpp @@ -92,10 +92,6 @@ namespace test { MemHolder mementoHolder (undo_func,cap_func); - CHECK (sizeof(MemHolder) <= sizeof(int) // storage for the memento - + 2 * sizeof(function) // storage for the 2 undecorated functors - + ALIGNMENT); - function bound_undo_func = mementoHolder.tieUndoFunc(); function bound_cap_func = mementoHolder.tieCaptureFunc(); diff --git a/tests/library/replaceable-item-test.cpp b/tests/library/replaceable-item-test.cpp deleted file mode 100644 index 3bb518663..000000000 --- a/tests/library/replaceable-item-test.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - ReplaceableItem(Test) - adapter to take snapshot from non-assignable values - - Copyright (C) - 2017, Hermann Vosseler - -  **Lumiera** is free software; you can redistribute it and/or modify it -  under the terms of the GNU General Public License as published by the -  Free Software Foundation; either version 2 of the License, or (at your -  option) any later version. See the file COPYING for further details. - -* *****************************************************************/ - - - -#include "lib/test/run.hpp" -#include "lib/test/test-helper.hpp" -#include "lib/util.hpp" -#include "lib/time/timevalue.hpp" - -#include "lib/replaceable-item.hpp" - - - - -namespace lib { -namespace wrapper { -namespace test{ - - using ::Test; - using lib::test::randStr; - using lib::test::randTime; - using util::isSameObject; - - using time::Time; - using time::Duration; - using std::string; - using std::swap; - - - - namespace { // Test helper: yet another ctor/dtor counting class - - long cntTracker = 0; - - struct Tracker - { - uint i_; - - Tracker() : i_(rani(500)) { ++cntTracker; } - Tracker(Tracker const& ot) : i_(ot.i_) { ++cntTracker; } - Tracker(uint i) : i_(i) { ++cntTracker; } - ~Tracker() { --cntTracker; } - - Tracker& operator= (Tracker const&) = default; - }; - - struct NonAssign - : Tracker - { - using Tracker::Tracker; - NonAssign& operator= (NonAssign const&) =delete; - }; - - - bool operator== (Tracker const& t1, Tracker const& t2) { return t1.i_ == t2.i_; } - bool operator!= (Tracker const& t1, Tracker const& t2) { return t1.i_ != t2.i_; } - - } // (END) Test helpers - - - - - - - - /***************************************************************************//** - * @test scrutinise an adapter to snapshot non-assignable values. - * - create instantiations for various types - * - both assignable and non-assignable types - * - empty-construct and copy construct the adapter - * - perform assignments and even content swapping - * - use counting to verify proper instance management - * - compare by delegating to element comparison - * - * @see replaceable-item.hpp - * @see steam::control::MementoTie - */ - class ReplaceableItem_test : public Test - { - - - virtual void - run (Arg) - { - seedRand(); - ulong l1 (1 + rani(1000)); - ulong l2 (1 + rani(1000)); - string s1 (randStr(50)); - string s2 (randStr(50)); - const char* cp (s1.c_str()); - - Time t1{randTime()}, t2{randTime()}; - Duration d1{randTime()}, d2{randTime()}; - - verifyUsage (l1, l2); - verifyUsage (&l1, &l2); - - verifyUsage (s1, s2); - verifyUsage (&s1, &s2); - - verifyUsage (s2, cp); - verifyUsage (cp, "Lumiera"); - verifyUsage (cp, "Lumiera"); - - // non-assignable types... - verifyUsage