idea how to crack the (daunting) problem regarding mutator storage

basically we'll establish a collaboration where both sides
know only the interface (contract) of the partner; a safe margin
for allocation size has to be established through metaprogramming (TODO)
This commit is contained in:
Fischlurch 2016-03-06 02:26:42 +01:00
parent 7b73aa6950
commit d2e7e1e06d
7 changed files with 215 additions and 42 deletions

View file

@ -395,6 +395,24 @@ namespace diff{
}
}
/** locate element already accepted into the taget sequence
* and assigne the designated payload value to it. */
virtual bool
assignElm (GenNode const& spec)
{
UNIMPLEMENTED("locate and assign");
return false;
}
/** locate the designated target element and build a suittable
* sub-mutator for this element into the provided target buffer */
virtual bool
mutateChild (GenNode const& spec, TreeMutator::MutatorBuffer targetBuff)
{
UNIMPLEMENTED("locate and open sub mutator");
return false;
}
TestWireTap(Target& dummy, PAR const& chain)
: PAR(chain)

View file

@ -327,19 +327,19 @@ namespace diff{
}
void
locate_and_assign (GenNode const& n)
assignElm (GenNode const& n)
{
UNIMPLEMENTED("locate allready accepted element and assign given new payload");
}
void
locate_and_openSubScope (GenNode const& n)
open_subScope (GenNode const& n)
{
UNIMPLEMENTED("locate allready accepted element and open recursive sub-scope for mutation");
}
void
closeSubScope()
close_subScope()
{
UNIMPLEMENTED("finish and leave sub scope and return to invoking parent scope");
}
@ -401,14 +401,14 @@ namespace diff{
virtual void
set (GenNode const& n) override
{
locate_and_assign (n);
assignElm (n);
}
/** open nested scope to apply diff to child object */
virtual void
mut (GenNode const& n) override
{
locate_and_openSubScope (n);
open_subScope (n);
Rec const& childRecord = child.data.get<Rec>();
TRACE (diff, "tree-diff: ENTER scope %s", cStr(childRecord));
@ -421,7 +421,7 @@ namespace diff{
TRACE (diff, "tree-diff: LEAVE scope %s", cStr(describeScope()));
__expect_end_of_scope (n.idi);
closeSubScope();
close_subScope();
__expect_valid_parent_scope (n.idi);
}

View file

@ -72,16 +72,67 @@
#include "lib/error.hpp"
#include "lib/symbol.hpp"
#include "lib/diff/gen-node.hpp"
#include "lib/opaque-holder.hpp"
//#include "lib/util.hpp"
//#include "lib/format-string.hpp"
#include <functional>
#include <utility> ////TODO
#include <string>
//#include <vector>
//#include <map>
namespace lib {
/////////////////////////////TODO move over into opaque-holder.hpp
/**
* handle to allow for safe _»remote implantation«_
* of an unknown subclass into a given OpaqueHolder buffer,
* without having to disclose the concrete buffer type or size.
* @remarks this is especially geared towards use in APIs, allowing
* a not yet known implementation to implant an agent or collaboration
* partner into the likewise undisclosed innards of the exposed service.
* @warning the type BA must expose a virtual dtor, since the targetted
* OpaqueHolder has to take ownership of the implanted object.
*/
template<class BA>
class PlantingHandle
{
void* buffer_;
size_t maxSiz_;
///////TODO static assert to virtual dtor??
public:
template<size_t maxSiz>
PlantingHandle (OpaqueHolder<BA, maxSiz>& targetBuffer)
: buffer_(&targetBuffer)
, maxSiz_(maxSiz_)
{ }
template<class SUB, typename...ARGS>
BA&
create (ARGS&& ...args)
{
if (sizeof(SUB) > maxSiz_)
throw error::Fatal("Unable to implant implementation object of size "
"exceeding the pre-established storage buffer capacity."
,error::LUMIERA_ERROR_CAPACITY);
using Holder = OpaqueHolder<BA, sizeof(SUB)>;
Holder& holder = *static_cast<Holder*> (buffer_);
return holder.create<SUB> (std::forward<ARGS> (args)...);
}
template<class SUB>
bool
canCreate() const
{
return sizeof(SUB) <= maxSiz_;
}
};
/////////////////////////////TODO move over into opaque-holder.hpp
namespace diff{
namespace error = lumiera::error;
@ -92,6 +143,8 @@ namespace diff{
using std::string;
class TestMutationTarget; // for unit testing
@ -166,10 +219,31 @@ namespace diff{
return false;
}
virtual TreeMutator&
mutateChild (ID id)
/** locate the designated target element
* (must be already accepted into the target sequence).
* Perform an assignement with the given payload value
* @throw when assignement fails (typically error::Logic)
* @return false when unable to locate the target */
virtual bool
assignElm (GenNode const&)
{
UNIMPLEMENTED("expose a recursive TreeMutator to transform the denoted child");
// do nothing by default
return false;
}
using MutatorBuffer = PlantingHandle<TreeMutator>;
/** locate the designated target element
* and build a suittable sub-mutator for this element
* into the provided target buffer
* @throw error::Fatal when buffer is insufficient
* @return false when unable to locate the target */
virtual bool
mutateChild (GenNode const&, MutatorBuffer)
{
// do nothing by default
return false;
}
virtual void setAttribute (ID, Attribute&) { /* do nothing by default */ }

View file

@ -490,7 +490,7 @@ namespace lib {
* The whole compound is copyable if and only if the contained
* object is copyable.
*
* \par using OpaqueHolder
* ## using OpaqueHolder
* OpaqueHolder instances are copyable value objects. They are created
* either empty, by copy from an existing OpaqueHolder, or by directly
* specifying the concrete object to embed. This target object will be
@ -500,16 +500,19 @@ namespace lib {
* Later on, the embedded value might be accessed
* - using the smart-ptr-like access through the common base interface BA
* - when knowing the exact type to access, the templated #get might be an option
* - the empty state of the container and a \c isValid() on the target may be checked
* - a combination of both is available as a \c bool check on the OpaqueHolder instance.
* - the empty state of the container and a `isValid()` on the target may be checked
* - a combination of both is available as a `bool` check on the OpaqueHolder instance.
*
* For using OpaqueHolder, several \b assumptions need to be fulfilled
* For using OpaqueHolder, several *assumptions* need to be fulfilled
* - any instance placed into OpaqueHolder is below the specified maximum size
* - the caller cares for thread safety. No concurrent get calls while in mutation!
*
* @tparam BA the nominal Base/Interface class for a family of types
* @tparam siz maximum storage required for the targets to be held inline
*/
template
< class BA ///< the nominal Base/Interface class for a family of types
, size_t siz = sizeof(BA) ///< maximum storage required for the targets to be held inline
< class BA
, size_t siz = sizeof(BA)
>
class OpaqueHolder
: public InPlaceAnyHolder<siz, InPlaceAnyHolder_useCommonBase<BA> >
@ -568,11 +571,15 @@ namespace lib {
* and especially it is mandatory for the base class to provide a
* virtual dtor. On the other hand, just the (alignment rounded)
* storage for the object(s) placed into the buffer is required.
*
* @tparam BA the nominal Base/Interface class for a family of types
* @tparam siz maximum storage required for the targets to be held inline
* @tparam DEFAULT the default instance to place initially
*/
template
< class BA ///< the nominal Base/Interface class for a family of types
, size_t siz = sizeof(BA) ///< maximum storage required for the targets to be held inline
, class DEFAULT = BA ///< the default instance to place initially
< class BA
, size_t siz = sizeof(BA)
, class DEFAULT = BA
>
class InPlaceBuffer
: boost::noncopyable

View file

@ -43,7 +43,7 @@
** number of objects is (heap) allocated right away, but no objects are
** created. Later on, individual objects are "pushed" into the collection
** by invoking #appendNewElement() to create a new element of the default
** type I) or #appendNew<Type>(args) to create some subtype. This way,
** type `I`) or #appendNew<Type>(args) to create some subtype. This way,
** the container is being filled successively.
** - the "RAII style" usage strives to create all of the content objects
** right away, immediately after the memory allocation. This usage pattern
@ -53,7 +53,7 @@
** @note intentionally there is no operation to discard individual objects,
** all you can do is to #clear() the whole container.
** @note the container can hold instances of a subclass of the type defined
** by the template parameter I. But you need to ensure in this case
** by the template parameter `I`. But you need to ensure in this case
** that the defined buffer size for each element (2nt template parameter)
** is sufficient to hold any of these subclass instances. This condition
** is protected by a static assertion (compilation failure).
@ -93,10 +93,12 @@ namespace lib {
* All child objects reside in a common chunk of storage
* and are owned and managed by this collection holder.
* Array style access and iteration is provided.
* @tparam I the nominal Base/Interface class for a family of types
* @tparam siz maximum storage required for the targets to be held inline
*/
template
< class I ///< the nominal Base/Interface class for a family of types
, size_t siz = sizeof(I) ///< maximum storage required for the targets to be held inline
< class I
, size_t siz = sizeof(I)
>
class ScopedCollection
: boost::noncopyable

View file

@ -44,7 +44,9 @@
** supporting dynamic growth (like in std::vector#resize() ) additionally
** requires a facility to transfer the lifecycle management control between
** holder instances. This is the purpose of the \c transfer_control
** friend function.
** friend function.
**
** @deprecated this is a pre C++11 concept and superseded by rvalue references
**
** @see scoped-holder-test.cpp
** @see scoped-holder-transfer.hpp use in std::vector

View file

@ -899,39 +899,102 @@
<node CREATED="1455928166683" ID="ID_1779120290" MODIFIED="1455928691589" TEXT="accept_until">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1455928383765" ID="ID_1859031782" MODIFIED="1455928389737" TEXT="accept until condition is met"/>
<node CREATED="1457120353283" ID="ID_997608114" MODIFIED="1457120364470" TEXT="meta operation"/>
<node COLOR="#e5500c" CREATED="1457120353283" ID="ID_997608114" MODIFIED="1457190890254" TEXT="meta operation">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1455927510666" ID="ID_14225718" MODIFIED="1455928690029" TEXT="locate">
</node>
<node CREATED="1455928184504" ID="ID_1474129407" MODIFIED="1457190163357" TEXT="assignElm">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1455928393788" ID="ID_1084411962" MODIFIED="1455928398936" TEXT="locate by ID comparison">
<node CREATED="1455928565869" ID="ID_197213145" MODIFIED="1455928572200" TEXT="incremental pos ref"/>
<node CREATED="1455928573028" ID="ID_1321605846" MODIFIED="1455928576391" TEXT="ID"/>
<node CREATED="1455928393788" ID="ID_1084411962" MODIFIED="1457190205367" TEXT="locate target">
<node CREATED="1457190206827" ID="ID_897956826" MODIFIED="1457190220485" TEXT="allready accepted element"/>
<node CREATED="1457190227089" ID="ID_265366260" MODIFIED="1457190234435" TEXT="find by ID comparison"/>
<node CREATED="1457190235191" ID="ID_1385656813" MODIFIED="1457190240027" TEXT="try current element first"/>
</node>
</node>
<node CREATED="1455928184504" ID="ID_1474129407" MODIFIED="1455928687942" TEXT="assign">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1455928403931" ID="ID_1442292399" MODIFIED="1455928412462" TEXT="assign payload">
<node CREATED="1455928583523" ID="ID_1874089052" MODIFIED="1455928585686" TEXT="pos ref"/>
<node CREATED="1455928586506" ID="ID_567539648" MODIFIED="1455928611275" TEXT="Type context"/>
<node CREATED="1455928586506" ID="ID_567539648" MODIFIED="1457190259104" TEXT="implicit Type context"/>
<node CREATED="1455928612239" ID="ID_1377931073" MODIFIED="1455928619186" TEXT="embedded target data"/>
</node>
</node>
<node CREATED="1455928189695" ID="ID_1518531652" MODIFIED="1455928686421" TEXT="mutator">
<node CREATED="1455928189695" ID="ID_1518531652" MODIFIED="1457190272990" TEXT="buildMutator">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1455928415161" ID="ID_316051704" MODIFIED="1455928425468" TEXT="build mutator for target">
<node CREATED="1455928625269" ID="ID_1510952440" MODIFIED="1455928628073" TEXT="pos ref"/>
<node CREATED="1457190279001" ID="ID_555722741" MODIFIED="1457190300305" TEXT="locate target">
<node CREATED="1457190288624" ID="ID_688053219" MODIFIED="1457190296115" TEXT="same as in &apos;assignElm&apos;"/>
</node>
<node CREATED="1455928415161" ID="ID_316051704" MODIFIED="1457190369739" TEXT="fabricate mutator">
<node CREATED="1457190370846" ID="ID_914587366" MODIFIED="1457190374749" TEXT="suitable for target"/>
<node CREATED="1455928625269" ID="ID_1510952440" MODIFIED="1457190388167" TEXT="open / init mutator"/>
</node>
<node CREATED="1457190320444" ID="ID_1175346415" MODIFIED="1457190328199" TEXT="place into provided buffer">
<node CREATED="1457190396170" ID="ID_1295881596" MODIFIED="1457190419158">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<i>throw </i>when
</p>
<p>
insufficent space
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1455928193863" ID="ID_879541123" MODIFIED="1455928685054" TEXT="push">
</node>
<node CREATED="1455928193863" ID="ID_879541123" MODIFIED="1457190610865" TEXT="open_subScope">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1455928427432" ID="ID_1222674854" MODIFIED="1455928435275" TEXT="push mutator on stack">
<node CREATED="1455928632684" ID="ID_1171317180" MODIFIED="1455928651005" TEXT="mutator or mutator ref"/>
<node CREATED="1455928657257" ID="ID_914429679" MODIFIED="1455928668323" TEXT="Type context for stack frame"/>
<node CREATED="1455928427432" ID="ID_1222674854" MODIFIED="1455928435275" TEXT="push mutator on stack"/>
<node CREATED="1457190622236" ID="ID_589756146" MODIFIED="1457190641456">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
invoke <b>buildMutator</b>
</p>
</body>
</html>
</richcontent>
</node>
<node COLOR="#e5500c" CREATED="1457190642993" ID="ID_1140350120" MODIFIED="1457190901922" STYLE="fork" TEXT="meta operation">
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
</node>
<node CREATED="1455928198718" ID="ID_593000833" MODIFIED="1455928683343" TEXT="pop">
<node CREATED="1455928198718" ID="ID_593000833" MODIFIED="1457190657851" TEXT="close_subScope">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<node CREATED="1455928440366" ID="ID_1859099649" MODIFIED="1455928446696" TEXT="pop previous mutator from stack"/>
<node CREATED="1455928440366" ID="ID_1859099649" MODIFIED="1457190669578" TEXT="just pop mutator"/>
<node CREATED="1457190670069" ID="ID_331099500" MODIFIED="1457190818805" TEXT="abandon mutator">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
<b>NOTE</b>: mutator need to be written in such a way
</p>
<p>
to be just discarded when done with the alterations.
</p>
<p>
That is, the mutator<i>&#160;must not</i>&#160;incorporate the target data, rather it is expected
</p>
<p>
to construct the new target data efficiently in place.
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1457190826145" ID="ID_1231904441" MODIFIED="1457190834604" TEXT="return to previous mutator"/>
<node COLOR="#e5500c" CREATED="1457190844318" ID="ID_614952113" MODIFIED="1457190936915" STYLE="fork" TEXT="meta operation">
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
</node>
</node>
</node>
@ -1771,6 +1834,13 @@
<node CREATED="1457119959408" ID="ID_275413703" MODIFIED="1457119961803" TEXT="sondern NOP"/>
</node>
</node>
<node CREATED="1457227228502" ID="ID_845299775" MODIFIED="1457227233433" TEXT="sub-Mutator">
<node CREATED="1457227237269" ID="ID_1175871622" MODIFIED="1457227296340" TEXT="wird &#xfc;ber ein Handle implantiert">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1457227248779" ID="ID_1765753442" MODIFIED="1457227279155" TEXT="Implementierungs-Schicht kennt Typ"/>
<node CREATED="1457227279703" ID="ID_347493370" MODIFIED="1457227288610" TEXT="aber Tree-Mutator &#xfc;bernimmt ownership"/>
</node>
</node>
</node>
<node CREATED="1456528462585" HGAP="27" ID="ID_1770521063" MODIFIED="1457038563027" TEXT="Elemente" VSHIFT="12">