Ocean
SegmentUnion.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_BASE_SEGMENT_UNION_H
9 #define META_OCEAN_BASE_SEGMENT_UNION_H
10 
11 #include "ocean/base/Base.h"
12 
13 #include <limits>
14 #include <map>
15 
16 namespace Ocean
17 {
18 
19 /**
20  * This class implements a functionality to determine the union of individual segments.
21  * Each segment is defined by a start point and an end point.<br>
22  * The result of such a uion is depicted below:
23  * <pre>
24  * Segment A: S---------P
25  * Segment B: S--P
26  * Segment C: S-----------P
27  * Segment D: S----P
28  * ...
29  * Segment Z: S-P
30  * Resulting Union: S--P S-----------------P S------P
31  *
32  * (with 's' as including start point, and 'p' as including end point)
33  * </pre>
34  * @tparam T The data type of the start and end point of a segment, should be 'float', 'double', or 'int'
35  * @ingroup base
36  */
37 template <typename T>
39 {
40  public:
41 
42  /**
43  * Definition of a map mapping a start point to the corresponding end point of a segment.
44  */
45  typedef std::map<T, T> SegmentMap;
46 
47  public:
48 
49  /**
50  * Adds a new segment to this union object.
51  * @param startPosition The (including) start position of the segment, with range (-infinity, startPosition)
52  * @param stopPosition The (including) stop position of the segment, with range (stopPosition, infinity)
53  */
54  void addSegment(const T& startPosition, const T& stopPosition);
55 
56  /**
57  * Returns the intersection of this union with a given range (an additional segment).
58  * An intersection between this object an a given range/segment is depicted below:
59  * <pre>
60  * Segments of this object: X------X X---X X-----------X
61  * Intersection Segment: S--------------------------------P
62  * Resulting object: X--X X---X X-----------X
63  * </pre>
64  * @param startPosition The (including) start position of the segment, with range (-infinity, startPosition)
65  * @param stopPosition The (including) stop position of the segment, with range (stopPosition, infinity)
66  * @return The new object holding the intersection of this object and the specified segment, may be empty if no intersection exists
67  */
68  SegmentUnion<T> intersection(const T& startPosition, const T& stopPosition) const;
69 
70  /**
71  * Returns the maximal gap between all successive segments.
72  * @return The maximal gap, 0 if this object is composed of zero or one segments, with range [0, infinity)
73  */
74  T maximalGap() const;
75 
76  /**
77  * Returns the segments of this object.
78  * @return The individual segments defining the union
79  */
80  inline const SegmentMap& segments() const;
81 
82  /**
83  * Returns the sum of all segment sizes.
84  * @return The size of all segments, with range [0, infinity)
85  */
86  T unionSize() const;
87 
88  /**
89  * Returns whether the union is composed of at least one segment.
90  * @return True, if so
91  */
92  explicit inline operator bool() const;
93 
94  protected:
95 
96  /**
97  * Returns whether the data structure of this object is correct.
98  * @return True, if so
99  */
100  bool isCorrect() const;
101 
102  protected:
103 
104  /// The map holding all segments.
106 };
107 
108 template <typename T>
109 void SegmentUnion<T>::addSegment(const T& startPosition, const T& stopPosition)
110 {
111  ocean_assert(isCorrect());
112 
113  ocean_assert(startPosition < stopPosition);
114 
115  // existing segments: X----X X------X X-X X------------X
116  // start/stop position: S----P
117 
118  if (segmentMap_.empty())
119  {
120  segmentMap_.insert(std::make_pair(startPosition, stopPosition));
121  ocean_assert(isCorrect());
122 
123  return;
124  }
125 
126  typename SegmentMap::iterator i = segmentMap_.lower_bound(startPosition); // segment with 'startPosition' <= start position (of found segment)
127 
128  if (i == segmentMap_.end())
129  {
130  ocean_assert(segmentMap_.rbegin() != segmentMap_.rend());
131 
132  typename SegmentMap::reverse_iterator lastSegment = segmentMap_.rbegin();
133 
134  if (startPosition > lastSegment->second)
135  {
136  // existing segments: X---X X--------X
137  // start/stop position: S--------P
138 
139  segmentMap_.insert(std::make_pair(startPosition, stopPosition));
140  ocean_assert(isCorrect());
141 
142  return;
143  }
144 
145  if (startPosition == lastSegment->second)
146  {
147  // existing segments: X---X X--------X
148  // start/stop position: S--------P
149 
150  lastSegment->second = stopPosition;
151  ocean_assert(isCorrect());
152 
153  return;
154  }
155 
156  ocean_assert(startPosition > lastSegment->first);
157  ocean_assert(startPosition < lastSegment->second);
158 
159  if (stopPosition <= lastSegment->second)
160  {
161  // existing segments: X---X X------------X
162  // start/stop position: S----P
163  // start/stop position: S---------P
164 
165  return;
166  }
167 
168  ocean_assert(stopPosition > lastSegment->second);
169 
170  // existing segments: X---X X-------X
171  // start/stop position: S--------P
172 
173  lastSegment->second = stopPosition;
174  ocean_assert(isCorrect());
175 
176  return;
177  }
178 
179  ocean_assert(startPosition <= i->first);
180 
181  if (i == segmentMap_.begin())
182  {
183  if (stopPosition < i->first)
184  {
185  // existing segments: X------------X X--------X
186  // start/stop position: S----P
187 
188  segmentMap_.insert(std::make_pair(startPosition, stopPosition));
189  ocean_assert(isCorrect());
190 
191  return;
192  }
193 
194  if (stopPosition == i->first)
195  {
196  // existing segments: X------------X X--------X
197  // start/stop position: S----P
198 
199  const T newStopPosition = i->second;
200 
201  segmentMap_.erase(i);
202 
203  segmentMap_.insert(std::make_pair(startPosition, newStopPosition));
204 
205  ocean_assert(isCorrect());
206 
207  return;
208  }
209 
210  ocean_assert(stopPosition > i->first);
211 
212  typename SegmentMap::iterator iEnd = i;
213 
214  while (iEnd != segmentMap_.end())
215  {
216  if (stopPosition < iEnd->first)
217  {
218  // existing segments: X--------X X--------X X------X
219  // start/stop position: S--------------P
220  // start/stop position: S------------------------------P
221 
222  segmentMap_.erase(i, iEnd); // remove [i, iEnd - 1]
223 
224  segmentMap_.insert(std::make_pair(startPosition, stopPosition));
225 
226  ocean_assert(isCorrect());
227 
228  return;
229  }
230  else if (stopPosition < iEnd->second)
231  {
232  // existing segments: X------------X X--------X X------X
233  // start/stop position: S------------P
234  // start/stop position: S--------------------------P
235 
236  const T newStopPostion = iEnd->second;
237 
238  segmentMap_.erase(i, ++iEnd); // remove [i, iEnd]
239 
240  segmentMap_.insert(std::make_pair(startPosition, newStopPostion));
241 
242  ocean_assert(isCorrect());
243 
244  return;
245  }
246 
247  ++iEnd;
248  }
249 
250  // existing segments: X------------X X--------X X------X
251  // start/stop position: S--------------------------------------------P
252 
253  segmentMap_.erase(i, segmentMap_.end()); // remove [i, end)
254 
255  segmentMap_.insert(std::make_pair(startPosition, stopPosition));
256 
257  ocean_assert(isCorrect());
258 
259  return;
260  }
261 
262  --i;
263 
264  // existing segments: X------------X X--------X
265  // start/stop position: S----P
266  // start/stop position: S--------P
267  // start/stop position: S------------P
268  // start/stop position: S------------P
269  // start/stop position: S---------------------P
270  // start/stop position: S-P
271  // start/stop position: S------P
272 
273  if (stopPosition <= i->second)
274  {
275  // existing segments: X---X X------------X
276  // start/stop position: S----P
277 
278  return;
279  }
280 
281  if (startPosition <= i->second)
282  {
283  typename SegmentMap::iterator iEnd = i;
284 
285  while (++iEnd != segmentMap_.end())
286  {
287  if (stopPosition < iEnd->first)
288  {
289  // existing segments: X------------X X--------X X------X
290  // start/stop position: S------------P
291  // start/stop position: S--------------------------P
292 
293  i->second = stopPosition;
294 
295  segmentMap_.erase(++i, iEnd); // remove [i + 1, iEnd - 1]
296 
297  ocean_assert(isCorrect());
298 
299  return;
300  }
301  else if (stopPosition < iEnd->second)
302  {
303  // existing segments: X------------X X--------X X------X
304  // start/stop position: S------------------P
305  // start/stop position: S-------------------------------P
306 
307  i->second = iEnd->second;
308 
309  segmentMap_.erase(++i, ++iEnd); // remove [i + 1, iEnd]
310 
311  ocean_assert(isCorrect());
312 
313  return;
314  }
315  }
316 
317  // existing segments: X------------X X--------X
318  // start/stop position: S---------------------------P
319 
320  i->second = stopPosition;
321 
322  segmentMap_.erase(++i, segmentMap_.end()); // remove [i + 1, end)
323 
324  ocean_assert(isCorrect());
325 
326  return;
327  }
328 
329  ocean_assert(startPosition > i->second);
330 
331  typename SegmentMap::iterator iEnd = i;
332 
333  while (++iEnd != segmentMap_.end())
334  {
335  if (stopPosition < iEnd->first)
336  {
337  // existing segments: X------X X--------X X------X
338  // start/stop position: S--P
339  // start/stop position: S---------------P
340  // start/stop position: S-----------------------------P
341 
342  segmentMap_.erase(++i, iEnd); // remove [i + 1, iEnd - 1]
343 
344  segmentMap_.insert(std::make_pair(startPosition, stopPosition));
345 
346  ocean_assert(isCorrect());
347 
348  return;
349  }
350  else if (stopPosition < iEnd->second)
351  {
352  // existing segments: X------------X X--------X
353  // start/stop position: S----------P
354  // start/stop position: S------------------------P
355 
356  const T newStopPosition = iEnd->second;
357 
358  segmentMap_.erase(++i, ++iEnd); // remove [i + 1, iEnd]
359 
360  segmentMap_.insert(std::make_pair(startPosition, newStopPosition));
361 
362  ocean_assert(isCorrect());
363 
364  return;
365  }
366  }
367 
368  // existing segments: X------------X X--------X
369  // start/stop position: S----------------------------------P
370 
371  segmentMap_.erase(++i, segmentMap_.end()); // remove [i + 1, end)
372 
373  segmentMap_.insert(std::make_pair(startPosition, stopPosition));
374 
375  ocean_assert(isCorrect());
376 }
377 
378 template <typename T>
379 SegmentUnion<T> SegmentUnion<T>::intersection(const T& startPosition, const T& stopPosition) const
380 {
381  ocean_assert(isCorrect());
382  ocean_assert(startPosition < stopPosition);
383 
384  // Segments of this object: X------X X---X X-----------X
385  // Intersection Segment: S--------------------------------P
386  // Resulting object: X--X X---X X-----------X
387 
388  if (segmentMap_.empty())
389  {
390  return SegmentUnion<T>();
391  }
392 
393  typename SegmentMap::const_iterator i = segmentMap_.lower_bound(startPosition); // segment with 'startPosition' <= start position (of found segment)
394 
395  if (i == segmentMap_.end())
396  {
397  ocean_assert(segmentMap_.rbegin() != segmentMap_.rend());
398 
399  typename SegmentMap::const_reverse_iterator lastSegment = segmentMap_.crbegin();
400 
401  if (startPosition >= lastSegment->second)
402  {
403  // existing segments: X---X X--------X
404  // start/stop position: S--------P
405  // start/stop position: S--------P
406 
407  return SegmentUnion<T>();
408  }
409 
410  ocean_assert(startPosition > lastSegment->first);
411  ocean_assert(startPosition < lastSegment->second);
412 
413  // existing segments: X---X X------------X
414  // start/stop position: S----P
415  // start/stop position: S---------P
416  // start/stop position: S--------P
417 
418  const T newStartPosition = std::max(lastSegment->first, startPosition);
419  const T newStopPosition = std::min(stopPosition, lastSegment->second);
420 
421  SegmentUnion<T> result;
422  result.segmentMap_.insert(std::make_pair(newStartPosition, newStopPosition));
423 
424  ocean_assert(result.isCorrect());
425 
426  return result;
427  }
428 
429  ocean_assert(startPosition <= i->first);
430 
431  if (i == segmentMap_.begin())
432  {
433  if (stopPosition <= i->first)
434  {
435  // existing segments: X------------X X--------X
436  // start/stop position: S----P
437  // start/stop position: S--------P
438 
439  return SegmentUnion<T>();
440  }
441 
442  ocean_assert(stopPosition > i->first);
443  }
444  else
445  {
446  --i;
447  }
448 
449  // existing segments: X------------X X--------X
450  // start/stop position: S---------P
451  // start/stop position: S------------------P
452  // start/stop position: S----P
453  // start/stop position: S--------P
454  // start/stop position: S------------P
455  // start/stop position: S------------P
456  // start/stop position: S---------------------P
457  // start/stop position: S-P
458  // start/stop position: S------P
459 
460  if (stopPosition <= i->second)
461  {
462  // existing segments: X------------X
463  // start/stop position: S----P
464  // start/stop position: S----------P
465  // start/stop position: S------------P
466 
467  const T newStartPosition = std::max(i->first, startPosition);
468  const T newStopPosition = std::min(stopPosition, i->second);
469 
470  SegmentUnion<T> result;
471  result.segmentMap_.insert(std::make_pair(newStartPosition, newStopPosition));
472 
473  ocean_assert(result.isCorrect());
474 
475  return result;
476  }
477 
478  if (startPosition >= i->second)
479  {
480  i++;
481  }
482 
483  ocean_assert(startPosition < i->second);
484 
485  if (stopPosition <= i->first)
486  {
487  // existing segments: X------X X--------X X------X
488  // start/stop position: S--P
489 
490  return SegmentUnion<T>();
491  }
492 
493  typename SegmentMap::const_iterator iEnd = i;
494 
495  while (++iEnd != segmentMap_.end())
496  {
497  if (stopPosition <= iEnd->first)
498  {
499  // existing segments: X------X X--------X X------X
500  // start/stop position: S--P
501  // start/stop position: S---------------P
502  // start/stop position: S-----------------------------P
503 
504  break;
505  }
506  else if (stopPosition <= iEnd->second)
507  {
508  // existing segments: X------------X X--------X
509  // start/stop position: S----------P
510  // start/stop position: S------------------------P
511 
512  iEnd++;
513  break;
514  }
515  }
516 
517  SegmentUnion<T> result;
518 
519  const T newStartPosition = std::max(startPosition, i->first);
520  result.segmentMap_.insert(std::make_pair(newStartPosition, i->second));
521 
522  i++;
523 
524  for (typename SegmentMap::const_iterator iN = i; iN != iEnd; ++iN)
525  {
526  result.segmentMap_.insert(std::make_pair(iN->first, iN->second));
527  }
528 
529  result.segmentMap_.rbegin()->second = std::min(stopPosition, result.segmentMap_.rbegin()->second);
530 
531  ocean_assert(result.isCorrect());
532 
533  return result;
534 }
535 
536 template <typename T>
538 {
539  ocean_assert(isCorrect());
540 
541  if (segmentMap_.size() <= 1)
542  {
543  return T(0);
544  }
545 
546  typename SegmentMap::const_iterator left = segmentMap_.cbegin();
547  typename SegmentMap::const_iterator right = left;
548  ++right;
549 
550  T maximalValue = right->first - left->second;
551  ocean_assert(maximalValue > T(0));
552 
553  while (++right != segmentMap_.cend())
554  {
555  ++left;
556 
557  const T value = right->first - left->second;
558  ocean_assert(value > T(0));
559 
560  if (value > maximalValue)
561  {
562  maximalValue = value;
563  }
564  }
565 
566  return maximalValue;
567 }
568 
569 template <typename T>
571 {
572  ocean_assert(isCorrect());
573 
574  return segmentMap_;
575 }
576 
577 template <typename T>
579 {
580  ocean_assert(isCorrect());
581 
582  T sum = (0);
583 
584  for (typename SegmentMap::const_iterator i = segmentMap_.cbegin(); i != segmentMap_.cend(); ++i)
585  {
586  ocean_assert(i->first < i->second);
587 
588  sum += i->second - i->first;
589  }
590 
591  return sum;
592 }
593 
594 template <typename T>
595 inline SegmentUnion<T>::operator bool() const
596 {
597  ocean_assert(isCorrect());
598 
599  return !segmentMap_.empty();
600 }
601 
602 template <typename T>
604 {
605  T previousEnd = std::numeric_limits<T>::lowest();
606 
607  for (typename SegmentMap::const_iterator i = segmentMap_.cbegin(); i != segmentMap_.cend(); ++i)
608  {
609  if (i->first <= previousEnd)
610  {
611  return false;
612  }
613 
614  previousEnd = i->second;
615  }
616 
617  return true;
618 }
619 
620 }
621 
622 #endif // META_OCEAN_BASE_RING_MAP_H
This class implements a functionality to determine the union of individual segments.
Definition: SegmentUnion.h:39
const SegmentMap & segments() const
Returns the segments of this object.
Definition: SegmentUnion.h:570
std::map< T, T > SegmentMap
Definition of a map mapping a start point to the corresponding end point of a segment.
Definition: SegmentUnion.h:45
T maximalGap() const
Returns the maximal gap between all successive segments.
Definition: SegmentUnion.h:537
bool isCorrect() const
Returns whether the data structure of this object is correct.
Definition: SegmentUnion.h:603
SegmentMap segmentMap_
The map holding all segments.
Definition: SegmentUnion.h:105
SegmentUnion< T > intersection(const T &startPosition, const T &stopPosition) const
Returns the intersection of this union with a given range (an additional segment).
Definition: SegmentUnion.h:379
void addSegment(const T &startPosition, const T &stopPosition)
Adds a new segment to this union object.
Definition: SegmentUnion.h:109
T unionSize() const
Returns the sum of all segment sizes.
Definition: SegmentUnion.h:578
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15