Commit graph

308 commits

Author SHA1 Message Date
0782dd4922 investigate and confirm the logic underlying the matchSrc, skipSrc and acceptSrc primitives
In Theory, acceptSrc and skipSrc are to operate symmetrically,
with the sole difference that skipSrc does not move anything
into the new content.

BUT, since skipSrc is also used to implement the `skip` verb,
which serves to discard garbage left back by a preceeding `find`,
we cannot touch the data found in the src position without risk
of SEGFAULT. For this reason, there is a dedicated matchSrc operation,
which shall be used to generate the verification step to properly
implement the `del` verb.

I've spent quite some time to verify the logic of predicate evaluation.
It seems to be OK: whenever the SELECTOR applies, then we'll perform
the local match, and then also we'll perform the skipSrc. Otherwise,
we'll delegate both operations likewise to the next lower layer,
without touching anything here.
2016-08-09 23:42:42 +02:00
43f3560b15 get the first diff verb to work
surprise surprise, no catastrophe thus far....
2016-08-08 14:20:54 +02:00
6e829e3f22 guard applicability by selector predicate
OMG ... this can't possibly work???!
2016-08-07 01:58:26 +02:00
18c9f95cbe integrate the first diff verb 'ins'
--> now it becomes obvious that we've mostly
missed to integrate the Selector predicate properly
in most bindings defined thus far. Which now causes
the sub-object binding to kick in, while actually
the sub-value collection should have handled
the nested values CHILD_B and CHILD_T
2016-07-31 00:33:26 +02:00
cbdc53e2d8 define a TreeMutator binding for our test::Opaque type
OMG, this is intricate stuff....
Questionable if anyone (other than myself) will be able
to get those bindings right???

Probably we'll need yet another abstraction layer to handle
the most common binding situations automatically, so that people
can use the diff framework without intricate knowledge of
TreeMutator construction.
2016-07-31 00:33:26 +02:00
020940545c integrate the complete initialisation sequence
when about to consume the next diff sequence, the
scopeStack will be reset and a new root scope TreeMutator
will be placed into this top buffer
2016-07-31 00:33:26 +02:00
17c78f369c ScopeManager stack based implementation
integrated into the generic DiffApplicationStrategy.
The dedicated, explicit specialisation for DiffMutable is
no longer needed, since the generic template will degrade or
fall back to precisely this functionality, when the target
implements the DiffMutable interface
2016-07-31 00:33:26 +02:00
a7b5a88c60 integrate size traits and ScopeManager implementation 2016-07-31 00:33:25 +02:00
d1bbf01029 solution to integrate heap based storage for nested scopes 2016-07-31 00:33:25 +02:00
78c9b0835e solution draft for integration of the whole tree diff application machinery
This is the first skeleton to combine all the building blocks,
and it passes compilation, while of course most of the binding
implementation still needs to be filled in...
2016-07-31 00:33:25 +02:00
ed18e1161c WIP: code organisation - double layered architecture 2016-07-31 00:33:19 +02:00
40b032c9c2 WIP: code organisation - declaration and definition 2016-07-25 15:21:30 +02:00
0d2335c9ed WIP: code organisation - create dedicated implementation unit
It occurred to me, that 90% of this template specialisation
are entirely generic and not dependant on the actual target type.
While the compiler/linker is able to sort such a situation out,
this might lead to template bloat and possibly subtle errors.

So it seems more adequate to emit the generic part of the code
right away from within a dedicated translation unit within the
library module; so the vtable is already in place and only
the flexible part of the code needs to be re-emitted on
each usage site.
2016-07-24 15:16:06 +02:00
4a2340ca5e solution for access to "tree mutator building closure"
- default recommendation is to implement DiffMutable interface
- ability to pick up similar non-virtual method on target
- for anything else client shall provide free function mutatorBinding(subject)


PERSONAL NOTE: this is the first commit after an extended leave,
where I was in hospital to get an abdominal cancer removed.
Right now it looks like surgery was successful.
2016-07-21 19:29:16 +02:00
5744244f73 considerations how to access the "tree mutator building closure"
this is at the core of the integration problem: how do we expose
the ability of some opaque data structure to create a TreeMutator?

The idea is
 - to use a marker/capability interface
 - to use template specialisation to fabricate an instance of that interface
   based on the given access point to the opaque data structure
2016-06-14 02:33:28 +02:00
61627b26a0 WIP: first attempt to use a TreeMutator based binding
but unfortunately this runs straight into a tough problem,
which I tried to avoid and circumvent all the time:
At some point, we're bound to reveal the concrete type
of the Mutator -- at least to such an extent that we're
able to determine the size of an allocator buffer.

Moreover, by the design chosen thus far, the active
TreeMutator instance (subclass) is assumed to live within
the top-level of a Stack, which means that we need to
place-construct it into that location. Thus, either
we know the type, or we need to move it into place.
2016-06-11 19:40:53 +02:00
57b105bbc5 fix a re-entrance problem
initially, even the diff applicator was meant to be a
"throwaway" object. But then, on writing some tests,
it seemed natural to allow re-using a single applicator,
after having attached it to some target.

With that change, I failed to care for the garbage
left back in the "old" sequence after applying one diff;
since in the typical usage sequence, the first use builds
content from scratch, this problem starts to show up only
with the third usage, where the garbage left from the input
of the second usage appears at the begin of the "new sequence"

Solution is to throw away that garbage explicitly on re-entrance
2016-06-10 02:48:22 +02:00
6fa54411b3 improved log msg
..because actually we don't know if the intention is
to drop those waste elements -- and for sure this
discarding of waste does not happen through the
invocation logged here; rather it happens by
abandoning the scope
2016-06-09 01:21:06 +02:00
37cfdbb7e1 better name for nested handle type 2016-06-09 01:18:21 +02:00
ef27c09fa2 round-up and document the attribute binding and test 2016-06-09 01:10:52 +02:00
b5ab5df929 supply implementation, basically working already
so this test case is more or less finished,
just needs some more polishing and documentation
2016-06-05 17:26:48 +02:00
6eff16f21c supply missing implementation
standard case of attribute binding, i.e.
the setter invocation is fully functional now.
2016-06-05 16:31:29 +02:00
1ae3c1991d second round of this test implemented
...which mostly just is either ignoring the
operations or indicating failure on attempt to
'reorder' attributes (which don't have any notion of 'ordering')
2016-06-04 15:08:10 +02:00
76b898b602 amend the design and then implement the two concrete setter/mutator cases
overall, the structure of this implementation is still rather confusing,
yet any alternatives seem even less convincing

- if we want to avoid the delegation to base-class, we'd have
  to duplicate several functions and the combined class would
  handle two distinct concerns.
- any attempt to handle the IDs more "symmetrically" seems to
  create additional problems on one side or the other
2016-06-04 14:20:59 +02:00
ee99c405fd Reorganise implementation into base class + overlay
...as preparation for implementing the two flavours of
binding attributes either via  a setter lambda or via
creation of a nested mutator.
2016-05-29 03:01:27 +02:00
e5bbcb27d8 identify attributes through an EntryID (including type hash)
this also supersedes and removes the initial implementation
draft for attribute binding with the 'setAttribute' API
The elementary part of diff application incl. setting
new attribute values works by now.
2016-05-28 03:41:03 +02:00
16086caf42 explicit error message
...turns out that inclusion of format-string.hpp
is almost irrelevant, since diff/record.hpp already
includes even format-util.hpp
2016-05-28 01:49:03 +02:00
201b6542f2 API change to allow to detect missing attribute binding
The way we build this attribute binding, there is no single
entity to handle all attribute bindings. Thus the only way
to detect a missing binding is when none of the binding layers
was able to handle a given INS verb
2016-05-28 01:17:45 +02:00
4073cdf797 first part of the implementation of attribute binding
...the simple checks and direct assignment.
Passes compiler, but test fails where it shouldn't
2016-05-27 03:33:56 +02:00
34f6d38919 WIP: implant outline of the implementation
...again by overriding all TreeMutator operations
2016-05-27 02:08:29 +02:00
06102b74ad rename test (no change) 2016-05-26 02:16:34 +02:00
4571d3fb0f introduce new mutation primitive as pointed out by preceding analysis
to summarise, it turned out that it is impossible to
provide an airtight 'emptySrc' implementation when binding
to object fields -- so we distinguish into positive and
negative tests, allowing to loosen the sanity check
only for the latter ones when binding to object fields.
2016-05-24 23:43:55 +02:00
b47b4c3f94 flip logic of emptySrc -> hasSrc
..as concluded from the preceding analysis.
NOTE this entails a semantical change, since this
predicate is now only meant to be indicative, not conclusive

remarks: the actual implementation of the diff application process
as bound via the TreeMutator remains yet to be written...
2016-05-24 21:34:08 +02:00
d3869d2280 Design/Analysis: Attribute TreeMutator binding
how can ordinary object fields be treated as "Attributes"
and thus tied into the Diff framework defined thus far.
This turns out to be really tricky, even questionable
2016-04-30 00:26:19 +02:00
835c43027d add support for Ref::THIS (questionable, #996)
while simple to add into the implementation, this whole feature
seems rather qestionable to me now, thus I've added a Ticket
to be revisited later.

In a nutshell, right here, when implementing the binding layer
for STL collections, it is easy to enable the framework to treat
Ref::THIS properly, but the *actual implementation* will necessarily
be offloaded onto each and every concrete binding implementation.
Thus client code would have to add support for an rather obscure
shortcut within the Diff language. The only way to avoid this
would be to change the semantics of the "match"-lambda: if this
binding would rather be a back-translation of implementation data
into GenNode::ID values, then we'd be able to implement Ref::THIS
natively. But such an approach looks like a way inferiour deisgn
to me; having delegated the meaning of a "match" to the client
seems like an asset, since it is both natural and opens a lot
of flexibility, without adding complexity.

For that reason I tend to avoid that shortcut now, in the hope
to be able to drop it entirely from the language
2016-04-18 01:21:38 +02:00
7bbfb4bc68 implement nested mutation of sub structures
...basically this worked right away and was easy to put together.
However, when considering how many components, indirections and
nested lambdas are working together here, I feel a bit dizzy...

:-/
2016-04-17 04:51:19 +02:00
69c63045e6 DOC: constituting elements of the TreeMutator
write down a first draft for a definiton section,
to describe the fundamental parts involved, when
applying a diff message onto implementation defined
data structures

After a break of tree weeks, I found it difficult to find may way
amidst all those various levels of abstraction. In addition to this
definition, we'll probably also need a high level overview of the
whole diff system operation.
2016-04-17 03:53:10 +02:00
8167fbff77 implement fast-forward and assignment to value
...all of this implementation boils down to slightly adjusting
the code written for the test-mutation-target. Insofar it pays off now
having implemented this diagnostic and demonstration first.

Moreover I'm implementing this basic scheme of "diff application"
roughly the fourth time, thus things kindof fall into place now.
What's really hard is all those layers of abstraction in between.

Lesson learned (after being off for three weeks, due to LAC and
other obligations): I really need to document the meaning of the
closures, and I need to document the "abstract operational semantics"
of diff application, otherwise no one will be able to provide
the correct closures.
2016-04-17 01:07:07 +02:00
7f42b9b7e7 draft third round of mutation operations to be implemented
...now about opening a sub mutator within a nested scope
2016-04-16 02:20:23 +02:00
54fb335a9c allow to "peek" into an embedded Record's type field
while I still keep my stance not to allow reflection and
switch-on-type, access to the internal / semantic type of
an embedded record seems a valid compromise to allow
to deal with collections of object-like children
of mixed kind.

Indirectly (and quite intentional) this also opens a loophole
to detect if a given GenNode might constitute a nested scope,
but with the for the actual nested element indeed to cary
a type symbol. Effectively this limits the use of this shortcut
to situations where the handling context does have some pre-established
knowledge about what types *might* be expected. This is precisely
the kind of constraint I intend to uphold: I do not want the
false notion of "total flexibility", as is conveyed by introspection.
2016-04-16 00:48:15 +02:00
ad6d348d8f make TreeMutator noncopyable to prevent dangling references
since we're moving elements around to apply the diff,
dangerous situation might arise in case anyone takes a copy
of the mutator. Thus we effectively limit the possible
usage pattern and only allow to build an anonymous
TreeMutator subclass through the Builder-DSL.

The concrete "onion layers" of the TreeMutator are now limited
- to be created by the chaining operations of the Builder DSl
- to be moved into target location, retaining ownership.
2016-03-26 02:01:31 +01:00
f9f2a225c3 implement content reordering mutation primitives
and cover result in test.
This also demonstrates that it is possible to install
a specific lambda on each usage
2016-03-26 01:22:40 +01:00
c49dd04b44 address an insidious dangling reference
I still feel somewhat queasy with this whole situation!
We need to return the product of the DSL/Builder by value,
but we also want to swap away the current contents before
starting the mutation, and we do not want a stateful lifecycle
for the mutator implementation. Which means, we need to swap
right at construction, and then we copy -- TADAAA!

Thus I'm going for the solution to disallow copying of the
mutator, yet to allow moving, and to change the builder
to move its product into place. Probably should even push
this policy up into the base class (TreeMutator) to set
everyone straight.

Looks like this didn't show up with the test dummy implementation
just because in this case the src buffer also lived within th
TestMutationTarget, which is assumed to sit where it is, so
effectively we moved around only pointers.
2016-03-26 00:48:38 +01:00
d98fde5b0e better verification in test
...actually iterate the populated collection
and verify each element in order. Also verify
and document the mutator's storage requirements
2016-03-25 23:12:54 +01:00
e84844142f implement inserting of new elements 2016-03-25 22:43:11 +01:00
91bf75d54a spelling in comments 2016-03-25 21:40:30 +01:00
fb1857423e implement mutation start and lifecycle
the whole implementation will very much be based on
my experiences with the TestMutationTarget and TestWireTap.
Insofar it was a good idea to implement this test dummy first,
as a prototype. Basically what emerges here is a standard pattern
how to implement a tree mutator:

- the TreeMutator will be a one-way-off "throwaway" object.
- its lifecylce starts with sucking away the previous contents
- consuming the diff moves contents back in place
- thus the mutator always attaches onto a target by reference
  and needs the ability to manipulate the target
2016-03-25 20:46:48 +01:00
1bf0753854 mark where function signature helpers should be refactored (#994) 2016-03-25 19:58:09 +01:00
e698a3800b verify signatures of binding lambdas
the collection binding can be configured with various
lambdas to supply the basic building blocks of the generated binding.

Since we allow picking up basically anything (functors,
function pointers, function objects, lamdas), and since
we speculate on inlining optimisation of lambdas, we can not
enforce a specific signature in the builder functions.

But at least we can static_assert on the effective signature
at the point where we're generating the actual binding configuration
2016-03-25 02:51:56 +01:00
7b6713bcab extend lamda-signature-extracting metafunction to several arguments 2016-03-25 02:25:51 +01:00
2098e69981 move metafunction to GenNode
because this is something of wider usage potential.
It allows us to detect if a type in question can be
placed within a GenNode
2016-03-24 21:32:56 +01:00
92d4e87ab9 raise a runtime error when unable to generate a sensible default collection binding
we can't generate a static assertion so easily here.
Problem is, when forming this type, we don't know if
the user will override and provide a custom binding
in some chained call within the nested DSL.

Might still be able to come up with some clever trick,
like e.g. returing an unsuitable marker type from these
dummy default implementations and then, later on, when
actually building the collection binding, to detect
those marker types and rise a static assert at that point.
This would at least give us a better error message,
and in theory, it should always be possible to
detect this kind of misuse at compile time
2016-03-24 17:44:58 +01:00
3b116fe6ef find a way to pick a default implementation for collection binding
...through the use of partial specialisation and SFINAE.
There are some rather specific (yet expectedly not uncommon) cases,
where we'd be able to provide a sensible default for the
- match predicate
- new element constructor
of the binding. While in all other cases, the user
has to provide an explicit implementation for these
crucial building blocks anyway.
2016-03-24 17:33:28 +01:00
cb2a95627d WIP: specify first example binding...
...but does not compile, since all of the fallback functions
will be instantiated, even while in fact we're overriding them
right away with something that *can* be compiled.

this prompts me to reconsider and question the basic approach
with closures for binding, while in fact what I am doing here
is to implement an ABC.
2016-03-24 17:32:30 +01:00
df8ca071a8 first outline of test and aggregate initialisation problem
- the test will use some really private data types,
  valid only within the scope of the test function.

- invoking the builder for real got me into problems
  with the aggregate initialisation I'd used.
  Maybe it's the function pointers? Anyway, working
  around that by definint a telescope ctor
2016-03-19 16:47:40 +01:00
b4fb767109 default/fallback configuration for the collection binding
when setting up a binding to child elements within a STL collection,
all the variable elements are preconfigured to a more or less
disabled and inactive state.
2016-03-19 01:24:11 +01:00
c909a67388 reorg: split, trim down and comment 2016-03-18 20:52:35 +01:00
08657bf199 reorg: split off implementation details
the concern is for the structure of the builder to be
incomprehensible and completely buried within the
implementation details of the various binding layers
2016-03-18 20:03:27 +01:00
1b24453f5b set up the full builder definition chain 2016-03-18 19:35:48 +01:00
5579e9c86f draft a way to configure the binding to a STL collection
this is the most relevant binding layer for TreeMutator,
enabling to transform and mutate child elements managed
within a STL collection.
2016-03-18 00:31:04 +01:00
3646c5df72 rearrange logic to allow for chaining / layering
most of the mutation primitives return bool(true)
when /any/ layer or part of the TreeMuator was able
to cope with the diff verb.

This is based on the assumption to configure the
TreeMutator in such a way that at most one facility
will actually handle and apply a given verb. That is,
we'll assume that the TreeMutator acutally wraps and
adapts *one* custom data structure, to which the
diff has to be applied.

The TestWireTap is special, insofar it indeed targets
a *second* data structure, albeit not a "real" one,
just a dest and diagnostics dummy.
2016-03-12 01:01:26 +01:00
9ef32e0d62 complete dummy/proof-of-concept implementation of TreeMutator primitives
the first part of the unit test (now passing)
is able to demonstrate the full set of diff operations
just by binding to a TestMutationTarget.

Now, after verifying the design of those primmitive operations,
we can now proceed with bindings to "real" data structures
2016-03-11 21:30:25 +01:00
b0c6ba0777 switch implementation of TestMutationTarget to storing full GenNodes
when implementing the assignment and mutation primitives
it became clear that the original approach of just storing
a log or string rendered elements does not work: for
assignment, we need to locate an element by ID
2016-03-11 17:39:25 +01:00
1016d792b9 implement accept_until for the test-dummy 2016-03-10 20:53:36 +01:00
7cceff8708 fix logic bug in existing tree diff applicator
this one went through unnoticed, because the situation
is not covered in unit-test. The tests written thus fare
are more like a proof-of-concept. I didn't want to spend
weeks on writing extensive coverage of all corner cases,
at least not before all aspects of the tree diff protocol
are settled. Seemingly this backfires already
2016-03-10 20:41:11 +01:00
6d5f336d40 fix self-assignment bug 2016-03-10 20:15:19 +01:00
75a6b4c05d specify and stub the test thus far to complete API design
now the full API for the "mutation primitives" is shaped.
Of course the actual implementation is missing, but that
should be low hanging fuit by now.

What still requires some thinking though is how to implement
the selector, so we'll actually get a onion shaped decorator
2016-03-06 03:55:31 +01:00
d2e7e1e06d 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)
2016-03-06 02:26:42 +01:00
75de98fe4d get the unit test to pass again
what's problematic is that we leave back waste in the
internal buffer holding the source. Thus it doesn't make
sense to check if this buffer is empty. Rather the
Mutator must offer an predicate emptySrc().

This will be relevant for other implementations as well
2016-03-04 23:18:25 +01:00
fcc2bc1e60 implement further re-ordering mutation primitives
...all for the first onion layer, which is a test dummy
2016-03-04 22:30:11 +01:00
1a20505c4f implement src position and simple match operation 2016-03-04 21:38:39 +01:00
6cf97f2478 forward operations to test/dummy onion layer
...first round of implementation happens here
2016-03-04 21:26:25 +01:00
b0ee330737 stub and decide about further part of the API 2016-03-04 21:13:49 +01:00
7d63167276 WIP: define usage of the reordering part of the mutation primitives
...this kind of settles the problem with the "opaque" position
2016-03-04 20:55:52 +01:00
9875c93ca7 add iteration and some diagnostics to the test 2016-03-04 19:23:21 +01:00
af50e84737 first partial implementation unit test PASS
that is, the dummy/diagnostic-implementation
of the first "mutation primitive", namely injectNew(elm)
2016-03-04 00:25:36 +01:00
d8fe9bce94 baseline of test-dummy implementation or a mutation target binding
- we're using the source / target buffer paradigm to implement the mutation
 - we're using Record<string> to account for "the current content"
2016-03-03 23:11:36 +01:00
3f8946c157 better naming of Record::Mutator content moving operation
while the original name, 'replace', conveys the intention,
this more standard name 'swap' reveals what is done
and thus opens a wider array of possible usage
2016-03-03 22:58:33 +01:00
48f519e785 align naming of mutation primitives
...convinced myself to retain an uniform naming scheme,
even while the implementation spans several onion-like layers
2016-03-03 22:02:01 +01:00
8bcd37df0a stub first round of mutation primitives to pass compiler again
now this feels like making progress again,
even when just writing stubs ;-)

Moreover, it became clear that the "typing" of typed child collections
will always be ad hoc, and thus needs to be ensured on a case by case
base. As a consequence, all mutation primitives must carry the
necessary information for the internal selector to decide if this
primitive is applicable to a given decorator layer. Because
otherwise it is not possible to uphold the concept of a single,
abstracted "source position", where in fact each typed sub-collection
of children (and thus each "onion layer" in the decorator chain)
maintains its own private position
2016-02-27 01:47:33 +01:00
bdf48e1b7b WIP: desperate attempt to get out of the design deadlock
Arrrrgh.
I go round in circles since hours now.
Whatever I attempt, it again relies on
yet further unsecured suppositions
2016-02-26 22:57:49 +01:00
a10db41d91 WIP: shaping a solution approach 2016-02-26 17:50:44 +01:00
2a037f49ee WIP: daft top layer of generic diff applicator
BUT the daunting question is how to deal with
the allocation of recursive mutator objects
2016-02-21 00:49:13 +01:00
dd1afef970 WIP: consider what kind of changes to support and how
especially the nagging question is:
- do we need to support children of mixed type
- and how can we support those, wihtout massively indirected calls
2016-02-20 00:19:01 +01:00
afbba968b5 WIP: decide how to target the task of mutating "unspecific" data structures 2016-02-19 20:25:30 +01:00
d22cc18c13 introduce a value assignment verb into the tree-diff-language
after sleeping one night over the problem, this seems to be
the most natural solution, since the possibility of assignment
naturally arises from the fact that, for tree diff, we have
to distinguish between the *identity* of an element node and
its payload (which could be recursive). Thus, IFF the payoad
is an assignable value, why not allow to assign it. Doing so
elegnatly solves the problem with assignment of attributes

Signed-off-by: Ichthyostega <prg@ichthyostega.de>
2016-02-19 17:22:41 +01:00
40b69e1fd2 planning: consider implications of tree-diff application to arbitrary data structures 2016-02-19 16:34:32 +01:00
c0ee98d73d planning: find out what the next steps would be like
...we want to attack the structural mutaion, finally
2016-02-17 01:38:04 +01:00
f80982b52b gen-node: fix insidious data conssitency problem
I assumed that, since GenNode is composed of copyable and
assignable types, the standard implementation will do.
But I overlooked the run time type check on the opaque
payload type within lib::Variant. When a type mismatch
is detected, the default implementation has already
assigned and thus altered the IDs.

So we need to roll our own implementation, and to add
insult to injury, we can't use the copy-and-swap idiom either.
2016-02-13 22:55:59 +01:00
121cd41408 ouch: GCC-4.9 doesn't yet support the C++14 transparent comparators
This is actually a STL library feature, and was added precisely
for the reason encountered here: if we want logarithmic search,
we'll have to construct a new GenNode object, just to have something
for the set to invoke the comparison operator.

C++14 introduced the convention that the Comparator of the set
may define a marker type `is_transparent` alongside with a generic
comparison operator. But, as is obvious from the source code of
our GNU Standard library implementation, our std::set has no such
overload to make use of that feature

http://en.cppreference.com/w/cpp/container/set/find
http://stackoverflow.com/questions/20317413/what-are-transparent-comparators

The only good thing is that, just 10 minutes ago, I felt like
a complete moron because I'm writing a unit test for such a simple
storage class. ;-)
2016-02-13 22:55:59 +01:00
94fc160525 implementation of storage for state manager 2016-02-13 22:55:59 +01:00
1e5c1059d3 WIP: draft basics of state manager interface 2016-02-13 22:55:58 +01:00
44785859ea convenience shortcut to simplify command invocation via Bus 2016-02-13 22:55:57 +01:00
3f22150ab3 back to topic: get all the arguments of command binding logged
...when the Test-Nexus processes a command binding message.
In the real system of course we do not want to log every bind message.

The challenge here is the fact that command binding as such
is opaque, and the types of the data within the bind message
are opaque as well. Finally I settled on the compromise
to log them as strings, but only the DataCap part;
most value types applicable within GenNode
have a string representation to match.
2016-02-05 15:55:22 +01:00
536a3a94b9 add special iteration mechanism to visit enclosed child data
the rationale is that I deliberately do not want to provide
a mechanism to iterate "over all contents in stringified form".
Because this could be seen as an invitation to process GenNode-
datastructures in an imperative way. Please recall we do not
want that. Users shall either *match* contents (using a visitor),
or they are required to know the type of the contents beforehand.
Both cases favour structural and type based programming over
dynamic run-time based inspection of contents

The actual task prompting me to add this iteration mechanism
is that I want to build a diagnostic, which allows to verify
that a binding message was sent over the bus with some
specific parameter values.
2016-02-05 04:03:11 +01:00
ae7912dc99 refactoring: move new library helpers into final destination 2016-01-28 15:19:09 +01:00
f743784bc9 add accessor for Nth child to our Record type 2016-01-23 17:10:44 +01:00
334f542897 clean-up(#985): remove code superseded by this rework
now finally able to remove most of the cruft from format-util.hpp
and get rid of the infamous util::str
2016-01-09 02:05:23 +01:00
3c24b4f8e4 should provide a generic entry point for all "state mark" messages 2015-12-26 03:03:46 +01:00
5874b1b4dc change lib::Record string representation to handle empty parts better
...no need to enclose empty sections when there are no
attributes or no children. Makes test code way more readable.



TestEventLog_test PASS as far as implemented
2015-12-05 03:57:11 +01:00
d68b881fab fix test failure due to compilation order (see #973)
some tests rely on additional diagnostics code being linked in,
which happens, when lib/format-util.hpp is included prior to
the instantiation of lib::diff::Record rsp. lib::Variant.

The reason why i opended this can of worms was to avoid includion
of this formatting and diagnostics code into such basic headers
as lib/variant.hpp or lib/diff/gen-node.hpp

Now it turns out, that on some platforms the linker will use
a later instantiation of lib::Variant::Buff<GenNode>::operator string
in spite of a complete instantiation of this virtual function
being available already in liblumierasupport.so

But the real reason is that -- with this trickery -- we're violating
the single definition rule, so we get what we deserved.

TODO (Ticket #973): at a later point in development we have to re-assess,
the precise impact of including lib/format-util.hpp into
lib/diff/gen-node.hpp
Right now I expect GenNode to be used pervasively, so I am
reluctant to make that header too heavyweight.
2015-11-15 02:11:08 +01:00
0e615e531f DOC: extension of the diff framework to represent structural changes 2015-11-02 03:51:04 +01:00
4a3b077824 Bugfix: find verb should check for ID match
because otherwise we'd need to send a whole subtree
over the wire and then descend into it just to find an element.

This too is a ripple effect of making '==' deep
2015-11-01 23:11:55 +01:00
34d79ee8df tree-diff-application: unit test PASS
well... this was quite a piece of work
Added some documentation, but a complete documentation,
preferably to the website, would be desirable, as would
be a more complete test covering the negative corner cases
2015-11-01 07:03:47 +01:00
eb829e6994 Bugfix: yet another init problem after swapping contents
yeah, working with open fire is dangerous...

For performace reasons I've undercut the premise
to make GenNode / Record immutable. Now I'm dealing with
raw storage layout together with this quite hairy distinction
between "attribute scope" and "child scope"

In hindsight, it might have been better to implement Record
as a single list, and to maintain a shortcut pointer to jump
to the start of the attributes.
2015-11-01 04:49:22 +01:00
83bea7c6ef Bugfix: need also to init sub scopes
this is a consequence of b14943
we use now an explicit init() call, instead of preparing everything in the ctor
2015-11-01 04:12:55 +01:00
9e7680d688 allow for trace-logging the processed diff-tokens
run the program with NOBUG_LOG=diff:TRACE
2015-11-01 03:54:43 +01:00
289bc7114c implement mutation of the current element (_THIS_)
while implementing this, I've discovered a conceptual error:
we allow to accept attributes, even when we've already entered
the child scope. This means that we can not predictable get back
at the "last" (i.e. the currently touched) element, because this
might be such an attribute. So a really correct implementation
would have to memorise the "current" element, which is really
tricky, given the various ways of touching elements in our
diff language.

In the end I've decided to ignore this problem (maybe a better
solution would have been to disallow those "late" attributes?)
My reasoning is that attributes are unlikely to be full records,
rather just values, and values are never mutated. (but note
that it is definitively possible to have an record as attribute!)
2015-11-01 03:29:35 +01:00
daa13ab6dc implement anonymous pick or delete of children
...while I must admit that I'm a bit doubtful about that
language feature, but it does come in handy when manually
writing diff messages. The reason is the automatic naming
of child objects, which makes it often hard to refer to
a child after the fact, since the name can not be
reconstructed systematically.

Obviously the downside of this "anonymous pick / delete"
is that we allow to pick (accept) or even delete just
any child, which happens to sit there, without being
able to detect a synchronisation mismatch between
sender and receiver.
2015-11-01 02:33:35 +01:00
73eaa10caf semantics change: allow referral just by ID
i.e. flat match, not deep equality.
This allows to send just an Ref (with the ID) over the
wire to refer to an complete object to be picked, moved
or deleted on the receiver side.
2015-11-01 02:20:54 +01:00
b149432512 fix/change DiffApplicator to allow applying several diffs
basically we need a reset-Hook before applying the next diff,
because the existing elements need to be swaped and the
position reset to start
2015-10-31 05:15:47 +01:00
52b1a2b9ae wrong -- need to treat each case explicitly
and its better this way; those nested lambdas
where just a bit too much trickery
2015-10-31 04:43:18 +01:00
2dec96663f implement the last missing verb 'after' 2015-10-31 04:25:43 +01:00
614e1f81e5 Generic Record: implement equivalence of Record and RecRef in comparison
...that is, we have "magic" in the access functions, which allows
a RecRef to "stand-in" for the Record it points to
2015-10-30 22:02:09 +01:00
bc072ab336 Generic Record: change semantics of the "match" operation for objects
in the first version, I defined equality to just compare the IDs
But that didn't seem right, or what one would expect by the concept
of equality (this is a long standing discussion with persistent
object-relationally mapped data).

So I changed the semantics of equaility to be "deep".
As this means possiblty to visit a whole tree depth-first,
it seems reasonable to provide the shallow "identity-comparison" likewise.
And the most reaonable choice is to use the "matches(object)" API
for that, since, in case of objects, the matches was defined
as full equality, which now seems redundant.

Thus: from now on: obj.matches(otherObj)
means they share the same IDs
2015-10-30 21:44:43 +01:00
9267b57c54 fix endless recursion on copy initialisation from Ref
The Ref-GenNode is just a specifically constructed GenNode,
and intended to be sliced down to an ordinary GenNode
immediately after construction. It seems, GCC didn't "get that"
and instead emitted an recursive invocation of the same ctor,
which obviously leads to stack overflow.

Problem solved by explicitly coding the copy initialisation,
after the full definition of Ref is available.
2015-10-30 05:41:36 +01:00
0e769601b7 add explicit handling to change the typeID
the type is the only meta attribute supported by now,
thus the decision was to handle this manually, instead of
introducing a full scope for meta attributes. Unfortunately
this leads to an assymetry: while it is possible to send an
attribute named "type", which will be intercepted and used
as a new type ID, the type will not show up when iterating
or searching through attributes.

When applying a diff, the only possibility is to *insert*
a new type attribute, and we need to check and handle this
likewise manually.
2015-10-30 05:10:16 +01:00
e231a51dc6 implement closing nested scope and return to parent 2015-10-30 04:51:13 +01:00
1101ce7210 implement opening a nested child scope for diff application 2015-10-30 04:45:22 +01:00
c94bbcbb15 extend storage arrangement to deal with nested child objects
It is difficult to reconcile our general architecture for the
linearised diff representation with the processing of recursive,
tree-like data structures. The natural and most clean way to
deal with trees is to use recursion, i.e. the processor stack.
But in our case, this means we'd have to peek into the next
token of the language and then forward the diff iterator
into a recursive call on the nested scope. Essentially, this
breaks the separation between receiving a token sequence and
interpretation for a concrete target data structure.

For this reason, it is preferrable to make the stack an
internal state of the concrete interpreter. The downside of
this approach is the quite confusing data storage management;
we try to make the role of the storage elements a bit more
clear through descriptive accessor functions.
2015-10-30 03:11:33 +01:00
e5ffcf224f implementation: list diff operations in tree-diff-applicator
implement the list handling primitives analogous to the
implementation of list-diff-applicator -- just again with
the additional twist to keep the attribute and child scopes
separated.
2015-10-29 04:14:18 +01:00
2882d78755 implementation: simplest case (insert element)
...so now the stage is set. We can reimplement
the handling of the list diff cases here in the context
of tree diff application. The additional twist of course
being the distinction between attribute and child scope
2015-10-24 03:15:35 +02:00
4356315021 diff-language interpreter: prefer to take payload by const&
each language token of our "linearised diff representation"
carries a payload data element, which typically is the piece
of data to be altered (added, mutated, etc).

Basically, these elements have value semantics and are
"sent over wire", and thus it seems natural when the
language interpreter functions accept that piece of payload
by-value. But since we're now sending GenNode elements as
parameter data in our diff, which typically are of the
size of 10 data elements (640 bit on a 64bit machine),
it seems more resonable to pass these argument elements
by const& through the interpreter function. This still
means we can (and will indeed) copy the mutated data
values when applying the diff, but we're able to
relay the data more efficiently to the point where
it's consumed.
2015-10-24 02:42:13 +02:00
2b619d6622 implement RecordContentMutator - unit test pass 2015-10-24 01:49:07 +02:00
aa46940daa indicate how RecordContentMutator will be used 2015-10-23 21:08:33 +02:00
5cbdcc0f22 stub ContentMutator implementation 2015-10-23 20:55:02 +02:00
e438a9fe51 chosing an implementation approach for tree-diff-application 2015-10-23 19:24:34 +02:00
c90e6a6f65 on second thought: yet a better solution
...is to let the diff applicator work *on* a Rec::Mutator
This is outright natural -- why is it that I needed 2 days
to come up with this solution?
2015-10-23 01:32:47 +02:00
eabeee3b7b decide on the implementation approach for tree diff application
this boils down to the two alternatives
 - manipulate the target data structure
 - build an altered copy

since our goal is to handle large tree structures efficiently,
the decision was cast in favour of data manipulation
2015-10-23 00:40:02 +02:00
90f31df8c0 stub the diff verb operations.
passes compilation again
2015-10-09 03:44:38 +02:00
2704b38da6 WIP rework demonstration diff to be valid type-wise
so basically it's time to explicate the way
our diff language will actually be written.

Similar to the list diff case, it's a linear sequence
of verb tokens, but in this case, the payload value
in each token is a GenNode. This is the very reason
why GenNode was conceived as value object with an
opaque DataCap payload
2015-10-09 03:03:27 +02:00
f43fb2167f WIP demonstration draft continued... 2015-10-02 19:41:14 +02:00
eaba418d15 WIP start definition with a basic tree diff example... 2015-10-02 18:47:44 +02:00
08e7e3df15 prefer more readable bool operator spelling
especially the '!' for negation is sometimes too terse
and easily overlooked.
2015-09-25 03:12:04 +02:00
6da0785d0a decision how to support tree exploration/reconstruction
initially the intention was to include a "bracketing construct"
into the values returned by the iterator. After considering
the various implementation and representation approaches,
it seems more appropriate just to expose a measure for the
depth-in-tree through the iterator itself, leaving any concerns
about navigation and structure reconstruction to the usage site.

As rationale we consider the full tree reconstruction as a very
specialised use case, and as such the normal "just iteration" usage
should not pay for this in terms of iterator size and implementation
complexity. Once a "level" measure is exposed, the usage site
can do precisely the same, with the help of the
HierarchyOrientationIndicator.
2015-09-24 20:59:04 +02:00
8e8a67e6df test fixes up to (not including) the iteration scope bracketing
...since for the latter I'll actually chose quite another
approach, based on the HierarchyOrientationIndicator
2015-09-17 19:39:34 +02:00
269ef07655 introduce special treatment for RecRef payload
The intention is to allow a Ref to "stand-in" for
a GenNode holding a full Record inline
2015-09-17 19:00:55 +02:00
7f2e328ab3 generalise containment check to anything that matches the GenNode
Whooa!
Templates are powerful.
programming this way is really fun.

under the assumption that the parts are logical,
all conceivable combinations of theses parts are bound to be correct
2015-09-11 20:25:39 +02:00
07f45a58de implement containment check based on iteration 2015-09-11 20:12:26 +02:00
3576b30cd2 formally complete implementation of GenNode iteration
it passes compilation, but the test still fails, since
I've changed the expected semantics of the iteration,
in the light of the insights I've gained during
re-investigation of the IterExplorer.

What I now actually intend is rather to embed a
HierarchyOrientationIndicator into the iterator,
instead of returning a special "bracket" marker
reference to indicate return from a nested scope.
2015-09-11 20:00:36 +02:00
823b4fd322 WIP: implement the recursive scope expansion
Only a Record payload constitutes a nested scope.
For all other (primitive) values, we return an empty iterator.
When used within ScopeExplorer, this implementation will just
lead to exposing any simple value once, while delving into
iteration of nested scopes
2015-09-11 19:23:40 +02:00
3f91997cf1 WIP: rearrange types to make the recursive iteration work
The only substantial change (besides compilation fixes) is
to confine the iteration to *const access*

This is a good thing; the whole Record/GenNode structure
was designed to represent immutable data, necessitating
a dedicated *Mutator* for any reshaping.
2015-09-11 18:41:18 +02:00
0d10e62851 WIP: draft a monad-like scope expanding iterator implementation
Initially I intended just to supply an addapter to use
the monadic IterExplorer for this recursive expansion
of GenNode contents. Investigating this approach was
relevant to highlight the minimum requirements for
such an evaluation mechanics: since our GenNode
is an hierarchical structure without back-links,
we are bound to use a stack at some point. And
since an Iterator is a materialised continuation,
we can not use the processor stack and are forced
to represent this stack in memory.

Yet, on second thought, we do not need the full power
of the IterExplorer monad; especially we do not need
to bind arbitrary functions into the monad, just one
single scope exploring function, implemented as
Variant visitor. Based on these observations, we can
"inline" the monad structure into a double nested
iterator, where the outer capsule carries a stack
of scopes to be explored.
2015-09-11 04:06:51 +02:00
bcd6308dee reorganise compilation units
this really turned into an implementation part of GenNode
2015-08-30 04:57:32 +02:00
a56ca7308f implement the data matching predicate on GenNode
TODO: need built-in special treatment for RecRef
2015-08-30 04:44:20 +02:00
25f78bfa83 draft a more premissive matching predicate
the intention is to combine this with content iteration
to build containment check and find operations
2015-08-30 00:00:41 +02:00
b0368a6d2b full unit test coverage of equality
horay!
seems like madness?
well -- found and squashed a bug: equality on RecordRef
implicitly converted to GenNode(RecordRef), which always
generates new (distinct) IDs and so never succeeds. What
we really want is equality test on the references
2015-08-29 21:27:33 +02:00
261b51998a rewrite equality on GenNode to rely on the new Predicate-Visitor 2015-08-29 19:14:42 +02:00
a05c9f81a6 Segfault: one move to much
the temporary was destroyed before moving it out.
2015-08-29 01:46:24 +02:00
bb92b49340 GenNode diagnostics -- debugging 2015-08-28 23:09:10 +02:00