Lumiera  0.pre.03
»edit your freedom«
tree-diff.cpp
Go to the documentation of this file.
1 /*
2  TreeDiff - implementation of diff application to opaque data
3 
4  Copyright (C)
5  2016, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
14 
34 #include "lib/error.hpp"
36 
37 
38 
39 namespace lib {
40 namespace diff{
41 
43 
45 
46 
47 
48 
49 
50  /* ======= Implementation of Tree Diff Application via TreeMutator ======= */
51 
52  using util::unConst;
53  using util::_Fmt;
54  using std::move;
55  using std::swap;
56 
57 
63  template<>
64  void
66  {
67  buff.emplace (
69  .attach (*this));
70  }
71 
72 
73 
74 
75 
76  /* == Forwarding: error handling == */
77 
78 
79  void
80  TreeDiffMutatorBinding::__failMismatch (Literal oper, GenNode const& spec)
81  {
82  throw error::State{_Fmt("Unable to %s element %s. Current shape of target "
83  "data does not match expectations") % oper % spec
84  , LERR_(DIFF_CONFLICT)};
85  }
86 
87  void
88  TreeDiffMutatorBinding::__expect_further_elements (GenNode const& elm)
89  {
90  if (not treeMutator_->hasSrc())
91  throw error::State{_Fmt("Premature end of target sequence, still expecting element %s; "
92  "unable to apply diff further.") % elm
93  , LERR_(DIFF_CONFLICT)};
94  }
95 
96  void
97  TreeDiffMutatorBinding::__fail_not_found (GenNode const& elm)
98  {
99  throw error::State{_Fmt("Premature end of sequence; unable to locate "
100  "element %s in the remainder of the target.") % elm
101  , LERR_(DIFF_CONFLICT)};
102  }
103 
104  void
105  TreeDiffMutatorBinding::__expect_end_of_scope (GenNode::ID const& idi)
106  {
107  if (not treeMutator_->completeScope())
108  throw error::State{_Fmt("Diff application floundered in nested scope %s; "
109  "unexpected extra elements found when diff "
110  "should have settled everything.") % idi.getSym()
111  , LERR_(DIFF_STRUCTURE)};
112  }
113 
114  void
115  TreeDiffMutatorBinding::__expect_valid_parent_scope (GenNode::ID const& idi)
116  {
117  if (0 == scopeManger_->depth())
118  throw error::Fatal{_Fmt("Diff application floundered after leaving scope %s; "
119  "unbalanced nested scopes, diff attempts to pop root.") % idi.getSym()
120  , LERR_(DIFF_STRUCTURE)};
121  }
122 
123 
124 
125 
126 
127  /* == Implementation of the list diff application primitives == */
128 
129  void
130  TreeDiffMutatorBinding::ins (GenNode const& n)
131  {
132  bool success = treeMutator_->injectNew(n);
133  if (not success)
134  __failMismatch ("insert", n);
135  }
136 
137  void
138  TreeDiffMutatorBinding::del (GenNode const& n)
139  {
140  __expect_further_elements(n);
141  if (not treeMutator_->matchSrc(n))
142  __failMismatch("remove", n);
143 
144  treeMutator_->skipSrc(n);
145  }
146 
147  void
148  TreeDiffMutatorBinding::pick (GenNode const& n)
149  {
150  bool success = treeMutator_->acceptSrc (n);
151  if (not success)
152  __failMismatch ("pick", n);
153  }
154 
155  void
156  TreeDiffMutatorBinding::skip (GenNode const& n)
157  {
158  __expect_further_elements (n);
159  treeMutator_->skipSrc(n);
160  } // assume the actual content has been moved away by a previous find()
161 
162  void
163  TreeDiffMutatorBinding::find (GenNode const& n)
164  {
165  __expect_further_elements (n);
166  // consume and leave waste, expected to be cleaned-up by skip() later
167  if (not treeMutator_->findSrc(n))
168  __fail_not_found (n);
169  }
170 
171 
172 
173 
174  /* == Implementation of the tree diff application primitives == */
175 
179  void
181  {
182  if (not treeMutator_->accept_until(n))
183  __fail_not_found (n);
184  }
185 
187  void
189  {
190  if (not treeMutator_->assignElm(n))
191  __failMismatch("assign", n);
192  }
193 
195  void
197  {
198  TreeMutator::Handle buffHandle = scopeManger_->openScope(); // hint: treeMutatorSize(...)
199  if (not treeMutator_->mutateChild(n, buffHandle))
200  __failMismatch("enter nested scope", n);
201 
202  TRACE (diff, "tree-diff: ENTER scope %s", cStr(n.idi));
203  treeMutator_ = buffHandle.get();
204  }
205 
207  void
209  {
210  TRACE (diff, "tree-diff: LEAVE scope %s", cStr(n.idi));
211 
212  __expect_end_of_scope (n.idi);
213  treeMutator_ = &scopeManger_->closeScope();
214  __expect_valid_parent_scope (n.idi);
215  }
216 
217 
218 
219 }} // namespace lib::diff
Concrete implementation to apply structural changes to hierarchical data structures.
CStr cStr(std::string const &rendered)
convenience shortcut: forced conversion to c-String via string.
Definition: symbol.hpp:59
virtual ~ScopeManager()
this is an interface
Definition: tree-diff.cpp:44
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
virtual ~TreeMutator()
this is an interface
Definition: tree-diff.cpp:42
virtual void after(GenNode const &n) override
cue to a position behind the named node, thereby picking (accepting) all traversed elements into the ...
Definition: tree-diff.cpp:180
A front-end for using printf-style formatting.
virtual void emu(GenNode const &n) override
finish and leave child object scope, return to parent
Definition: tree-diff.cpp:208
Implementation namespace for support and library code.
static Builder< TreeMutator > build()
DSL: start building a custom adapted tree mutator, where the operations are tied by closures or wrapp...
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
SUB & emplace(SUB &&implementation)
move-construct an instance of a subclass into the opaque buffer
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
Definition: record.hpp:104
virtual void set(GenNode const &n) override
assignment of changed value in one step
Definition: tree-diff.cpp:188
void buildMutator(BufferHandle)
attachment point to receive and apply tree-diff changes.
virtual void mut(GenNode const &n) override
open nested scope to apply diff to child object
Definition: tree-diff.cpp:196
Lumiera error handling (C++ interface).
generic data element node within a tree
Definition: gen-node.hpp:222