Lumiera  0.pre.03
»edit your freedom«
split-splice.hpp
1 /*
2  SPLIT-SPLICE.hpp - Algorithm to integrate a new interval into an axis-segmentation.
3 
4  Copyright (C) Lumiera.org
5  2023, 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 
80 #ifndef LIB_SPLIT_SPLICE_H
81 #define LIB_SPLIT_SPLICE_H
82 
83 #include "lib/error.hpp"
84 #include "lib/meta/function.hpp"
85 #include "lib/time/timevalue.hpp"
86 #include "lib/nocopy.hpp"
87 
88 #include <array>
89 
90 
91 namespace lib {
92 
93  namespace error = lumiera::error;
94 
95 
96  namespace splitsplice {
97 
98 
106  template<class ORD
107  ,class POS
108  ,class START
109  ,class AFTER
110  ,class CREATE
111  ,class EMPTY
112  ,class CLONE
113  ,class DELETE
114  >
115  class Algo
117  {
118  /* ======= elementary operations ======= */
119 
120  ASSERT_VALID_SIGNATURE (START, ORD(POS))
121  ASSERT_VALID_SIGNATURE (AFTER, ORD(POS))
122  ASSERT_VALID_SIGNATURE (CREATE, POS(POS,ORD,ORD))
123  ASSERT_VALID_SIGNATURE (EMPTY, POS(POS,ORD,ORD))
124  ASSERT_VALID_SIGNATURE (CLONE, POS(POS,ORD,ORD,POS))
125  ASSERT_VALID_SIGNATURE (DELETE, POS(POS,POS))
126 
127  START getStart;
128  AFTER getAfter;
129  CREATE createSeg;
130  EMPTY emptySeg;
131  CLONE cloneSeg;
132  DELETE discard;
133 
134  using OptORD = std::optional<ORD>;
135  const ORD AXIS_END;
136 
137 
138  /* ======= working state ======= */
139 
140  POS pred_, succ_;
141 
142  struct SegBounds
143  { // can be assigned in one step (ORD may be immutable)
144  ORD start,
145  after;
146  } b_;
147 
148  enum Verb { NIL
149  , DROP
150  , TRUNC
151  , INS_NOP
152  , SEAMLESS
153  };
154 
155  Verb opPred_ = NIL,
156  opSucc_ = NIL;
157 
158  public:
166  Algo (START fun_getStart
167  ,AFTER fun_getAfter
168  ,CREATE fun_createSeg
169  ,EMPTY fun_emptySeg
170  ,CLONE fun_cloneSeg
171  ,DELETE fun_discard
172  ,const ORD axisEnd
173  ,POS startAll, POS afterAll
174  ,OptORD start, OptORD after)
175  : getStart{fun_getStart}
176  , getAfter{fun_getAfter}
177  , createSeg{fun_createSeg}
178  , emptySeg{fun_emptySeg}
179  , cloneSeg{fun_cloneSeg}
180  , discard {fun_discard}
181  , AXIS_END{axisEnd}
182  , pred_{}
183  , succ_{}
184  , b_{establishSplitPoint (startAll,afterAll, start,after)}
185  {
186  // Postcondition: ordered start and end times
187  ENSURE (pred_ != afterAll);
188  ENSURE (succ_ != afterAll);
189  ENSURE (b_.start < b_.after);
190  ENSURE (getStart(pred_) <= b_.start);
191  ENSURE (b_.start <= getStart(succ_) or pred_ == succ_);
192  }
193 
199  SegBounds
200  establishSplitPoint (POS startAll, POS afterAll
201  ,OptORD start, OptORD after)
202  { // nominal break point
203  ORD sep = start? *start
204  : after? *after
205  : AXIS_END;
206 
207  // find largest Predecessor with start before separator
208  for (succ_ = startAll, pred_ = afterAll
209  ;succ_ != afterAll and getStart(succ_) < sep
210  ;++succ_)
211  {
212  pred_ = succ_;
213  }
214  REQUIRE (pred_ != succ_, "non-empty segmentation required");
215  if (succ_ == afterAll) succ_=pred_;
216  if (pred_ == afterAll) pred_=succ_; // separator touches bounds
217 
218  // Stage-2 : establish start and end point of new segment
219 
220  ORD startSeg = start? *start
221  : getAfter(pred_) < sep? getAfter(pred_)
222  : getStart(pred_);
223  ORD afterSeg = after? *after
224  : getStart(succ_) > sep? getStart(succ_)
225  : getAfter(succ_);
226  ENSURE (startSeg != afterSeg);
227  if (startSeg < afterSeg)
228  return {startSeg,afterSeg};
229  else
230  return {afterSeg,startSeg};
231  }
232 
233 
239  void
241  {
242  ORD startPred = getStart (pred_),
243  afterPred = getAfter (pred_);
244 
245  if (startPred < b_.start)
246  {
247  if (afterPred < b_.start) opPred_ = INS_NOP;
248  else
249  if (afterPred == b_.start) opPred_ = SEAMLESS;
250  else
251  {
252  opPred_ = TRUNC;
253  if (afterPred > b_.after)
254  { // predecessor actually spans the new segment
255  // thus use it also as successor and truncate both (=SPLIT)
256  succ_ = pred_;
257  opSucc_ = TRUNC;
258  return;
259  } } }
260  else
261  {
262  REQUIRE (startPred == b_.start, "predecessor does not precede start point");
263  opPred_ = DROP;
264  if (b_.after < afterPred )
265  { // predecessor coincides with start of new segment
266  // thus use it rather as successor and truncate at start
267  succ_ = pred_;
268  opSucc_ = TRUNC;
269  return;
270  } }
271 
272  ORD startSucc = getStart (succ_);
273  if (startSucc < b_.after)
274  {
275  while (getAfter(succ_) < b_.after)
276  ++succ_;
277  ASSERT (getStart(succ_) < b_.after // in case we dropped a successor completely spanned,
278  ,"seamless segmentation"); // even the next one must start within the new segment
279 
280  if (b_.after == getAfter(succ_)) opSucc_ = DROP;
281  else
282  if (b_.after < getAfter(succ_)) opSucc_ = TRUNC;
283  }
284  else
285  {
286  if (b_.after == startSucc) opSucc_ = SEAMLESS;
287  else opSucc_ = INS_NOP;
288  }
289  }
290 
291 
299  std::array<POS, 3>
301  {
302  POS refPred = pred_, refSucc = succ_;
303  REQUIRE (opPred_ != NIL and opSucc_ != NIL);
304 
305  // deletions are done by skipping the complete range around the insertion point;
306  // thus to retain a predecessor or successor, this range has to be reduced
307  if (opPred_ == INS_NOP or opPred_ == SEAMLESS)
308  ++pred_;
309  if (opSucc_ == DROP or opSucc_ == TRUNC)
310  ++succ_;
311 
312  // insert the new elements /before/ the range to be dropped, i.e. at pred_
313  POS insPos = pred_;
314  POS n = createSeg (insPos, b_.start, b_.after);
315  POS s = n;
316  //
317  // possibly adapt the predecessor
318  if (opPred_ == INS_NOP)
319  s = emptySeg (n, getAfter(refPred), b_.start);
320  else
321  if (opPred_ == TRUNC)
322  s = cloneSeg (n, getStart(refPred), b_.start, refPred);
323  //
324  // possibly adapt the successor
325  if (opSucc_ == INS_NOP)
326  emptySeg (insPos, b_.after, getStart(refSucc));
327  else
328  if (opSucc_ == TRUNC)
329  cloneSeg (insPos, b_.after, getAfter(refSucc), refSucc);
330 
331  // finally discard superseded segments
332  POS e = discard (insPos, succ_);
333 
334  // indicate the range where changes happened
335  return {s,n,e};
336  }
337  };
338 
339  }//namespace splitsplace
340 } // namespace lib
341 #endif /*LIB_SPLIT_SPLICE_H*/
#define ASSERT_VALID_SIGNATURE(_FUN_, _SIG_)
Macro for a compile-time check to verify the given generic functors or lambdas expose some expected s...
Definition: function.hpp:256
std::array< POS, 3 > performSplitSplice()
Stage-4 of the algorithm performs the actual insert and deleting of segments.
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
SegBounds establishSplitPoint(POS startAll, POS afterAll, OptORD start, OptORD after)
Stage-1 and Stage-2 of the algorithm determine the insert point and establish the actual start and en...
void determineRelations()
Stage-3 of the algorithm works out the precise relation of the predecessor and successor segments to ...
Implementation namespace for support and library code.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Metaprogramming tools for transforming functor types.
Algo(START fun_getStart, AFTER fun_getAfter, CREATE fun_createSeg, EMPTY fun_emptySeg, CLONE fun_cloneSeg, DELETE fun_discard, const ORD axisEnd, POS startAll, POS afterAll, OptORD start, OptORD after)
Setup for a single SplitSplice-operation to insert a new segment start to after.
Lumiera error handling (C++ interface).
Implementation of »SplitSplice« algorithm.
a family of time value like entities and their relationships.