Lumiera  0.pre.03
»edit your freedom«
list-diff-application.hpp
Go to the documentation of this file.
1 /*
2  LIST-DIFF-APPLICATION.hpp - consume and apply a list diff
3 
4  Copyright (C) Lumiera.org
5  2014, 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 
39 #ifndef LIB_DIFF_LIST_DIFF_APPLICATION_H
40 #define LIB_DIFF_LIST_DIFF_APPLICATION_H
41 
42 
43 #include "lib/diff/list-diff.hpp"
44 #include "lib/format-string.hpp"
45 
46 #include <algorithm>
47 #include <vector>
48 #include <tuple>
49 
50 
51 namespace lib {
52 namespace diff{
53 
54  using util::_Fmt;
55  using std::vector;
56  using std::move;
57 
71  template<typename E, typename...ARGS>
72  class DiffApplicationStrategy<vector<E,ARGS...>>
73  : public ListDiffInterpreter<E>
74  {
75  using Vec = vector<E,ARGS...>;
76  using Iter = typename Vec::iterator;
77 
78  Vec orig_;
79  Vec& seq_;
80  Iter pos_;
81 
82  bool
83  end_of_target()
84  {
85  return pos_ == orig_.end();
86  }
87 
88  void
89  __expect_in_target (E const& elm, Literal oper)
90  {
91  if (end_of_target())
92  throw error::State(_Fmt("Unable to %s element %s from target as demanded; "
93  "no (further) elements in target sequence") % oper % elm
94  , LERR_(DIFF_CONFLICT));
95  if (*pos_ != elm)
96  throw error::State(_Fmt("Unable to %s element %s from target as demanded; "
97  "found element %s on current target position instead")
98  % oper % elm % *pos_
99  , LERR_(DIFF_CONFLICT));
100  }
101 
102  void
103  __expect_further_elements (E const& elm)
104  {
105  if (end_of_target())
106  throw error::State(_Fmt("Premature end of target sequence, still expecting element %s; "
107  "unable to apply diff further.") % elm
108  , LERR_(DIFF_CONFLICT));
109  }
110 
111  void
112  __expect_found (E const& elm, Iter const& targetPos)
113  {
114  if (targetPos == orig_.end())
115  throw error::State(_Fmt("Premature end of sequence; unable to locate "
116  "element %s in the remainder of the target.") % elm
117  , LERR_(DIFF_CONFLICT));
118  }
119 
120 
121  /* == Implementation of the diff application primitives == */
122 
123  void
124  ins (E const& elm) override
125  {
126  seq_.push_back(elm);
127  }
128 
129  void
130  del (E const& elm) override
131  {
132  __expect_in_target(elm, "remove");
133  ++pos_;
134  }
135 
136  void
137  pick (E const& elm) override
138  {
139  __expect_in_target(elm, "pick");
140  seq_.push_back (move(*pos_));
141  ++pos_;
142  }
143 
144  void
145  skip (E const& elm) override
146  {
147  __expect_further_elements (elm);
148  ++pos_;
149  } // assume the actual content has been moved away by a previous find()
150 
151  void
152  find (E const& elm) override
153  {
154  __expect_further_elements (elm);
155  Iter found = std::find(pos_, orig_.end(), elm);
156  __expect_found (elm, found);
157  seq_.push_back (move(*found));
158  } // consume and leave waste, expected to be cleaned-up by skip() later
159 
160 
161  public:
162  explicit
163  DiffApplicationStrategy(vector<E>& targetVector)
164  : seq_(targetVector)
165  { }
166 
167  void
168  initDiffApplication()
169  {
170  swap (seq_, orig_);
171  seq_.reserve (orig_.size() * 120 / 100); // heuristics for storage pre-allocation
172  pos_ = orig_.begin();
173  }
174 
175  void
176  completeDiffApplication()
177  {
178  if (not end_of_target())
179  throw error::State(_Fmt("Not all source data consumed after diff application. "
180  "Element %s waiting to be consumed") % *pos_
181  , LERR_(DIFF_STRUCTURE));
182  // discard storage
183  orig_.clear();
184  }
185  };
186 
187 
188 
189 
190 
191 }} // namespace lib::diff
192 #endif /*LIB_DIFF_LIST_DIFF_APPLICATION_H*/
A token language to represent changes in a list of elements.
Interpreter interface to define the operations ("verbs"), which describe differences or changes in a ...
Definition: list-diff.hpp:72
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
Front-end for printf-style string template interpolation.
A front-end for using printf-style formatting.
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
Extension point: define how a specific diff language can be applied to elements in a concrete contain...