diff --git a/src/lib/replaceable-item.hpp b/src/lib/replaceable-item.hpp index a03f263ba..683b92043 100644 --- a/src/lib/replaceable-item.hpp +++ b/src/lib/replaceable-item.hpp @@ -29,6 +29,27 @@ ** 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 proc::control::MementoTie ** */ @@ -42,24 +63,25 @@ #include "lib/meta/util.hpp" #include "lib/util.hpp" -#include #include +#include namespace lib { namespace wrapper { - using util::unConst; using util::isSameObject; + using util::unConst; using std::forward; -// using lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE; /** - * + * 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 @@ -105,6 +127,12 @@ namespace wrapper { return reinterpret_cast(content_); } + void + destroy() + { + access().~X(); + } + template void emplace (Z&& otherValue) @@ -115,12 +143,6 @@ namespace wrapper { NullValue::build (&content_); } - void - destroy() - { - access().~X(); - } - template void reAssign (Z&& otherValue) @@ -131,12 +153,16 @@ namespace wrapper { }; + template struct is_assignable_value : std::__and_, std::__not_>> { }; - + /** + * simple delegating implementation + * to use for regular cases + */ template class ReplaceableItem>> { @@ -159,6 +185,7 @@ namespace wrapper { }; + /** disallow embedding references */ template class ReplaceableItem>> { diff --git a/tests/15library.tests b/tests/15library.tests index aaeb97294..fc78c4517 100644 --- a/tests/15library.tests +++ b/tests/15library.tests @@ -405,6 +405,11 @@ return: 0 END +TEST "inline adapter for state snapshot" ReplaceableItem_test < [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] out-lit: removed 0 ---> [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] out-lit: removed 9 ---> [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ] @@ -430,7 +435,7 @@ return: 0 END -TEST "SanitizedIdentifier_test" SanitizedIdentifier_test < 'Word' out-lit: 'a Sentence' --> 'a_Sentence' out-lit: 'trailing Withespace diff --git a/tests/library/replaceable-item-test.cpp b/tests/library/replaceable-item-test.cpp index 46916158c..c9922b92d 100644 --- a/tests/library/replaceable-item-test.cpp +++ b/tests/library/replaceable-item-test.cpp @@ -26,15 +26,9 @@ #include "lib/test/test-helper.hpp" #include "lib/util.hpp" #include "lib/time/timevalue.hpp" -#include "lib/format-cout.hpp"////////////TODO #include "lib/replaceable-item.hpp" -//#include -//#include -//#include -//#include -//#include @@ -49,8 +43,6 @@ namespace test{ using time::Time; using time::Duration; -// using std::ref; -// using std::vector; using std::string; using std::rand; using std::swap; @@ -91,11 +83,16 @@ namespace test{ /***************************************************************************//** - * @test use the ItemWrapper to define inline-storage holding values, - * pointers and references. Verify correct behaviour in each case, - * including (self)assignment, empty check, invalid dereferentiation. + * @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 wrapper.hpp + * @see replaceable-item.hpp + * @see proc::control::MementoTie */ class ReplaceableItem_test : public Test { @@ -113,23 +110,24 @@ namespace test{ Time t1{randTime()}, t2{randTime()}; Duration d1{randTime()}, d2{randTime()}; - verifyWrapper (l1, l2); - verifyWrapper (&l1, &l2); + verifyUsage (l1, l2); + verifyUsage (&l1, &l2); - verifyWrapper (s1, s2); - verifyWrapper (&s1, &s2); + verifyUsage (s1, s2); + verifyUsage (&s1, &s2); -#if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #888 - verifyWrapper (cp, "Lumiera"); - verifyWrapper (cp, "Lumiera"); - verifyWrapper (cp, s2); + verifyUsage (s2, cp); + verifyUsage (cp, "Lumiera"); + verifyUsage (cp, "Lumiera"); - verifyWrapper