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) Lumiera.org
5  2016, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
23 
43 #include "lib/error.hpp"
45 
46 
47 
48 namespace lib {
49 namespace diff{
50 
52 
54 
55 
56 
57 
58 
59  /* ======= Implementation of Tree Diff Application via TreeMutator ======= */
60 
61  using util::unConst;
62  using util::_Fmt;
63  using std::move;
64  using std::swap;
65 
66 
72  template<>
73  void
75  {
76  buff.emplace (
78  .attach (*this));
79  }
80 
81 
82 
83 
84 
85  /* == Forwarding: error handling == */
86 
87 
88  void
89  TreeDiffMutatorBinding::__failMismatch (Literal oper, GenNode const& spec)
90  {
91  throw error::State{_Fmt("Unable to %s element %s. Current shape of target "
92  "data does not match expectations") % oper % spec
93  , LERR_(DIFF_CONFLICT)};
94  }
95 
96  void
97  TreeDiffMutatorBinding::__expect_further_elements (GenNode const& elm)
98  {
99  if (not treeMutator_->hasSrc())
100  throw error::State{_Fmt("Premature end of target sequence, still expecting element %s; "
101  "unable to apply diff further.") % elm
102  , LERR_(DIFF_CONFLICT)};
103  }
104 
105  void
106  TreeDiffMutatorBinding::__fail_not_found (GenNode const& elm)
107  {
108  throw error::State{_Fmt("Premature end of sequence; unable to locate "
109  "element %s in the remainder of the target.") % elm
110  , LERR_(DIFF_CONFLICT)};
111  }
112 
113  void
114  TreeDiffMutatorBinding::__expect_end_of_scope (GenNode::ID const& idi)
115  {
116  if (not treeMutator_->completeScope())
117  throw error::State{_Fmt("Diff application floundered in nested scope %s; "
118  "unexpected extra elements found when diff "
119  "should have settled everything.") % idi.getSym()
120  , LERR_(DIFF_STRUCTURE)};
121  }
122 
123  void
124  TreeDiffMutatorBinding::__expect_valid_parent_scope (GenNode::ID const& idi)
125  {
126  if (0 == scopeManger_->depth())
127  throw error::Fatal{_Fmt("Diff application floundered after leaving scope %s; "
128  "unbalanced nested scopes, diff attempts to pop root.") % idi.getSym()
129  , LERR_(DIFF_STRUCTURE)};
130  }
131 
132 
133 
134 
135 
136  /* == Implementation of the list diff application primitives == */
137 
138  void
139  TreeDiffMutatorBinding::ins (GenNode const& n)
140  {
141  bool success = treeMutator_->injectNew(n);
142  if (not success)
143  __failMismatch ("insert", n);
144  }
145 
146  void
147  TreeDiffMutatorBinding::del (GenNode const& n)
148  {
149  __expect_further_elements(n);
150  if (not treeMutator_->matchSrc(n))
151  __failMismatch("remove", n);
152 
153  treeMutator_->skipSrc(n);
154  }
155 
156  void
157  TreeDiffMutatorBinding::pick (GenNode const& n)
158  {
159  bool success = treeMutator_->acceptSrc (n);
160  if (not success)
161  __failMismatch ("pick", n);
162  }
163 
164  void
165  TreeDiffMutatorBinding::skip (GenNode const& n)
166  {
167  __expect_further_elements (n);
168  treeMutator_->skipSrc(n);
169  } // assume the actual content has been moved away by a previous find()
170 
171  void
172  TreeDiffMutatorBinding::find (GenNode const& n)
173  {
174  __expect_further_elements (n);
175  // consume and leave waste, expected to be cleaned-up by skip() later
176  if (not treeMutator_->findSrc(n))
177  __fail_not_found (n);
178  }
179 
180 
181 
182 
183  /* == Implementation of the tree diff application primitives == */
184 
188  void
190  {
191  if (not treeMutator_->accept_until(n))
192  __fail_not_found (n);
193  }
194 
196  void
198  {
199  if (not treeMutator_->assignElm(n))
200  __failMismatch("assign", n);
201  }
202 
204  void
206  {
207  TreeMutator::Handle buffHandle = scopeManger_->openScope(); // hint: treeMutatorSize(...)
208  if (not treeMutator_->mutateChild(n, buffHandle))
209  __failMismatch("enter nested scope", n);
210 
211  TRACE (diff, "tree-diff: ENTER scope %s", cStr(n.idi));
212  treeMutator_ = buffHandle.get();
213  }
214 
216  void
218  {
219  TRACE (diff, "tree-diff: LEAVE scope %s", cStr(n.idi));
220 
221  __expect_end_of_scope (n.idi);
222  treeMutator_ = &scopeManger_->closeScope();
223  __expect_valid_parent_scope (n.idi);
224  }
225 
226 
227 
228 }} // 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:68
virtual ~ScopeManager()
this is an interface
Definition: tree-diff.cpp:53
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
virtual ~TreeMutator()
this is an interface
Definition: tree-diff.cpp:51
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:189
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:217
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:199
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:113
virtual void set(GenNode const &n) override
assignment of changed value in one step
Definition: tree-diff.cpp:197
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:205
Lumiera error handling (C++ interface).
generic data element node within a tree
Definition: gen-node.hpp:231