1 | /* -*- c++ -*- |
---|
2 | |
---|
3 | C++ Interval set template with boolean operations. |
---|
4 | |
---|
5 | This file is part of the dpp library of C++ template classes |
---|
6 | |
---|
7 | doc: http://diaxen.ssji.net/dpp/index.html |
---|
8 | repo: https://www.ssji.net/svn/projets/trunk/libdpp |
---|
9 | |
---|
10 | This program is free software: you can redistribute it and/or |
---|
11 | modify it under the terms of the GNU Lesser General Public License |
---|
12 | as published by the Free Software Foundation, either version 3 of |
---|
13 | the License, or (at your option) any later version. |
---|
14 | |
---|
15 | This program is distributed in the hope that it will be useful, but |
---|
16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
18 | Lesser General Public License for more details. |
---|
19 | |
---|
20 | You should have received a copy of the GNU Lesser General Public |
---|
21 | License along with this program. If not, see |
---|
22 | <http://www.gnu.org/licenses/>. |
---|
23 | |
---|
24 | (c) 2008 Alexandre Becoulet <alexandre.becoulet@free.fr> |
---|
25 | |
---|
26 | */ |
---|
27 | |
---|
28 | #ifndef DPP_INTERVAL_SET_HH_ |
---|
29 | #define DPP_INTERVAL_SET_HH_ |
---|
30 | |
---|
31 | #include <cassert> |
---|
32 | #include <vector> |
---|
33 | #include <stdexcept> |
---|
34 | #include <limits> |
---|
35 | #include <ios> |
---|
36 | |
---|
37 | /** @file @module{Interval set} */ |
---|
38 | |
---|
39 | namespace dpp { |
---|
40 | |
---|
41 | template <typename X> |
---|
42 | class interval_bound; |
---|
43 | |
---|
44 | template <typename X> |
---|
45 | class interval_bound_inclusive; |
---|
46 | |
---|
47 | template <typename X> |
---|
48 | class interval_bound_exclusive; |
---|
49 | |
---|
50 | template <typename X> |
---|
51 | class interval_scalar_limits; |
---|
52 | |
---|
53 | template <typename X, class Bound = interval_bound<X> > |
---|
54 | class interval; |
---|
55 | |
---|
56 | template <typename X, class Bound = interval_bound<X>, |
---|
57 | class Limits = interval_scalar_limits<X> > |
---|
58 | class interval_set; |
---|
59 | |
---|
60 | ////////////////////////////////////////////////////////////////////// |
---|
61 | // interval bound classes |
---|
62 | ////////////////////////////////////////////////////////////////////// |
---|
63 | |
---|
64 | /** @short Default interval bound class |
---|
65 | @module {Interval set} |
---|
66 | @header dpp/interval_set |
---|
67 | |
---|
68 | @This may be used with the @ref interval and @ref interval_set |
---|
69 | classes to specify interval bounds inclusivity. |
---|
70 | |
---|
71 | This class must be used to handles both inclusive and exclusive |
---|
72 | interval bounds in the same interval set. This is the default |
---|
73 | behavior and more generic choice but @ref interval_bound_inclusive |
---|
74 | and @ref interval_bound_exclusive may be used instead to allow |
---|
75 | further optimization of the code. |
---|
76 | */ |
---|
77 | |
---|
78 | template <typename X> |
---|
79 | class interval_bound |
---|
80 | { |
---|
81 | template <typename, class> friend class interval; |
---|
82 | template <typename, class, class> friend class interval_set; |
---|
83 | |
---|
84 | X _bound; |
---|
85 | bool _inclusive; |
---|
86 | |
---|
87 | interval_bound() |
---|
88 | { |
---|
89 | } |
---|
90 | |
---|
91 | interval_bound(const X bound, bool inclusive) |
---|
92 | : _bound(bound), |
---|
93 | _inclusive(inclusive) |
---|
94 | { |
---|
95 | } |
---|
96 | |
---|
97 | X bound() const |
---|
98 | { |
---|
99 | return _bound; |
---|
100 | } |
---|
101 | |
---|
102 | void set_bound(X b) |
---|
103 | { |
---|
104 | _bound = b; |
---|
105 | } |
---|
106 | |
---|
107 | bool inclusive() const |
---|
108 | { |
---|
109 | return _inclusive; |
---|
110 | } |
---|
111 | |
---|
112 | void set_inclusive(bool i) |
---|
113 | { |
---|
114 | _inclusive = i; |
---|
115 | } |
---|
116 | |
---|
117 | bool operator==(const interval_bound &b) const |
---|
118 | { |
---|
119 | return _bound == b._bound && _inclusive == b._inclusive; |
---|
120 | } |
---|
121 | |
---|
122 | static const bool default_inc = true; |
---|
123 | }; |
---|
124 | |
---|
125 | /** @short Inclusive interval bound class |
---|
126 | @module {Interval set} |
---|
127 | @header dpp/interval_set |
---|
128 | |
---|
129 | @This may be used with the @ref interval and @ref interval_set |
---|
130 | classes to specify interval bounds inclusivity. |
---|
131 | |
---|
132 | When used this specify @b inclusive bounds and @ref interval bound values |
---|
133 | will always be considered as included in the interval. |
---|
134 | |
---|
135 | @see interval_bound |
---|
136 | @see interval_bound_exclusive |
---|
137 | */ |
---|
138 | |
---|
139 | template <typename X> |
---|
140 | class interval_bound_inclusive |
---|
141 | { |
---|
142 | template <typename, class> friend class interval; |
---|
143 | template <typename, class, class> friend class interval_set; |
---|
144 | |
---|
145 | X _bound; |
---|
146 | |
---|
147 | interval_bound_inclusive() |
---|
148 | { |
---|
149 | } |
---|
150 | |
---|
151 | interval_bound_inclusive(const X bound, bool inclusive) |
---|
152 | : _bound(bound) |
---|
153 | { |
---|
154 | } |
---|
155 | |
---|
156 | X bound() const |
---|
157 | { |
---|
158 | return _bound; |
---|
159 | } |
---|
160 | |
---|
161 | void set_bound(X b) |
---|
162 | { |
---|
163 | _bound = b; |
---|
164 | } |
---|
165 | |
---|
166 | bool inclusive() const |
---|
167 | { |
---|
168 | return true; |
---|
169 | } |
---|
170 | |
---|
171 | void set_inclusive(bool i) |
---|
172 | { |
---|
173 | assert(i); |
---|
174 | } |
---|
175 | |
---|
176 | bool operator==(const interval_bound_inclusive &b) const |
---|
177 | { |
---|
178 | return _bound == b._bound; |
---|
179 | } |
---|
180 | |
---|
181 | static const bool default_inc = true; |
---|
182 | }; |
---|
183 | |
---|
184 | /** @short Exclusive interval bound class |
---|
185 | @module {Interval set} |
---|
186 | @header dpp/interval_set |
---|
187 | |
---|
188 | @This may be used with the @ref interval and @ref interval_set |
---|
189 | classes to specify interval bounds inclusivity. |
---|
190 | |
---|
191 | When used this specify @b exclusive bounds and @ref interval bound values |
---|
192 | will always be considered as excluded from the interval. |
---|
193 | |
---|
194 | @see interval_bound |
---|
195 | @see interval_bound_inclusive |
---|
196 | */ |
---|
197 | |
---|
198 | template <typename X> |
---|
199 | class interval_bound_exclusive |
---|
200 | { |
---|
201 | template <typename, class> friend class interval; |
---|
202 | template <typename, class, class> friend class interval_set; |
---|
203 | |
---|
204 | X _bound; |
---|
205 | |
---|
206 | interval_bound_exclusive() |
---|
207 | { |
---|
208 | } |
---|
209 | |
---|
210 | interval_bound_exclusive(X bound, bool inclusive) |
---|
211 | : _bound(bound) |
---|
212 | { |
---|
213 | } |
---|
214 | |
---|
215 | X bound() const |
---|
216 | { |
---|
217 | return _bound; |
---|
218 | } |
---|
219 | |
---|
220 | void set_bound(X b) |
---|
221 | { |
---|
222 | _bound = b; |
---|
223 | } |
---|
224 | |
---|
225 | bool inclusive() const |
---|
226 | { |
---|
227 | return false; |
---|
228 | } |
---|
229 | |
---|
230 | void set_inclusive(bool i) |
---|
231 | { |
---|
232 | assert(!i); |
---|
233 | } |
---|
234 | |
---|
235 | bool operator==(const interval_bound_exclusive &b) const |
---|
236 | { |
---|
237 | return _bound == b._bound; |
---|
238 | } |
---|
239 | |
---|
240 | static const bool default_inc = false; |
---|
241 | }; |
---|
242 | |
---|
243 | ////////////////////////////////////////////////////////////////////// |
---|
244 | // interval bound limits |
---|
245 | ////////////////////////////////////////////////////////////////////// |
---|
246 | |
---|
247 | /** @short Interval limits class for standard scalar types |
---|
248 | @module {Interval set} |
---|
249 | @header dpp/interval_set |
---|
250 | |
---|
251 | This class specify upper and lower limits for scalar types and |
---|
252 | is the default limits definition class used by the @ref interval_set class. |
---|
253 | |
---|
254 | Similar classes must be defined when using the @ref interval_set |
---|
255 | class with user defined non scalar types. |
---|
256 | */ |
---|
257 | |
---|
258 | template <typename X> |
---|
259 | class interval_scalar_limits |
---|
260 | { |
---|
261 | public: |
---|
262 | /** @This returns interval maximum value */ |
---|
263 | static X upper() |
---|
264 | { |
---|
265 | if (!std::numeric_limits<X>::is_integer && std::numeric_limits<X>::has_infinity) |
---|
266 | return std::numeric_limits<X>::infinity(); |
---|
267 | else |
---|
268 | return std::numeric_limits<X>::max(); |
---|
269 | } |
---|
270 | |
---|
271 | /** @This returns interval minimum value */ |
---|
272 | static X lower() |
---|
273 | { |
---|
274 | if (std::numeric_limits<X>::is_integer) |
---|
275 | return std::numeric_limits<X>::min(); |
---|
276 | else |
---|
277 | return -upper(); |
---|
278 | } |
---|
279 | }; |
---|
280 | |
---|
281 | ////////////////////////////////////////////////////////////////////// |
---|
282 | // interval (bound pair) class |
---|
283 | ////////////////////////////////////////////////////////////////////// |
---|
284 | |
---|
285 | /** @short Interval class |
---|
286 | @module {Interval set} |
---|
287 | @header dpp/interval_set |
---|
288 | @main |
---|
289 | @showvalue |
---|
290 | |
---|
291 | @This defines an interval with its low and high bounds for a |
---|
292 | given type and bound inclusivity. |
---|
293 | |
---|
294 | @tt X can be a standard scalar type or an user defined type. |
---|
295 | |
---|
296 | Acceptable values for @tt Bound template parameter are |
---|
297 | @ref interval_bound (default), @ref interval_bound_inclusive and |
---|
298 | @ref interval_bound_exclusive |
---|
299 | |
---|
300 | This class is used as an @ref interval_set element. |
---|
301 | */ |
---|
302 | |
---|
303 | template <typename X, class Bound> |
---|
304 | class interval |
---|
305 | { |
---|
306 | template <typename, class, class> friend class interval_set; |
---|
307 | |
---|
308 | Bound _low; |
---|
309 | Bound _high; |
---|
310 | |
---|
311 | public: |
---|
312 | |
---|
313 | /** @This creates a non initialized interval object. */ |
---|
314 | interval() |
---|
315 | { |
---|
316 | } |
---|
317 | |
---|
318 | /** @This creates a new {@tt low, @tt high } interval. |
---|
319 | Bounds are inclusive by default when @ref interval_bound_exclusive is not used. |
---|
320 | @alias interval_1 |
---|
321 | */ |
---|
322 | interval(const X low, const X high) |
---|
323 | : _low(low, Bound::default_inc), |
---|
324 | _high(high, Bound::default_inc) |
---|
325 | { |
---|
326 | assert(low < high || low == high); |
---|
327 | } |
---|
328 | |
---|
329 | /** @This creates a new {@tt low, @tt high } interval with specified inclusivity. |
---|
330 | @alias interval_2 |
---|
331 | */ |
---|
332 | interval(const X low, bool low_inclusive, |
---|
333 | const X high, bool high_inclusive) |
---|
334 | : _low(low, low_inclusive), |
---|
335 | _high(high, high_inclusive) |
---|
336 | { |
---|
337 | assert(low < high || (low == high && low_inclusive && high_inclusive)); |
---|
338 | } |
---|
339 | |
---|
340 | /** @This returns the low bound value. */ |
---|
341 | X low_bound() const |
---|
342 | { |
---|
343 | return _low.bound(); |
---|
344 | } |
---|
345 | |
---|
346 | /** @This returns the high bound value. */ |
---|
347 | X high_bound() const |
---|
348 | { |
---|
349 | return _high.bound(); |
---|
350 | } |
---|
351 | |
---|
352 | /** @This tests if low bound is inclusive. */ |
---|
353 | bool low_inclusive() const |
---|
354 | { |
---|
355 | return _low.inclusive(); |
---|
356 | } |
---|
357 | |
---|
358 | /** @This tests if high bound is inclusive. */ |
---|
359 | bool high_inclusive() const |
---|
360 | { |
---|
361 | return _high.inclusive(); |
---|
362 | } |
---|
363 | |
---|
364 | /** @This tests if specified value is included in interval range. */ |
---|
365 | bool contains(const X a) const |
---|
366 | { |
---|
367 | if (a == _low.bound()) |
---|
368 | return _low.inclusive(); |
---|
369 | else if (a == _high.bound()) |
---|
370 | return _high.inclusive(); |
---|
371 | else |
---|
372 | return (!(a < _low.bound()) && a < _high.bound()); |
---|
373 | } |
---|
374 | |
---|
375 | /** @This tests if two intervals are equals. */ |
---|
376 | bool operator==(const interval &i) const |
---|
377 | { |
---|
378 | return _low == i._low && _high == i._high; |
---|
379 | } |
---|
380 | |
---|
381 | /** @This prints an interval to stream in the form "@tt {[low, high]}". |
---|
382 | Square brackets or parenthesis may be used depending on inclusivity. |
---|
383 | @alias print |
---|
384 | */ |
---|
385 | friend std::ostream & operator<<(std::ostream &o, const interval<X, Bound> &i) |
---|
386 | { |
---|
387 | o << (i.low_inclusive() ? "[" : "(") << i.low_bound() |
---|
388 | << ", " << i.high_bound() << (i.high_inclusive() ? "]" : ")"); |
---|
389 | return o; |
---|
390 | } |
---|
391 | }; |
---|
392 | |
---|
393 | |
---|
394 | ////////////////////////////////////////////////////////////////////// |
---|
395 | // interval set class |
---|
396 | ////////////////////////////////////////////////////////////////////// |
---|
397 | |
---|
398 | /** @short Interval set class |
---|
399 | @module {Interval set} |
---|
400 | @header dpp/interval_set |
---|
401 | @main |
---|
402 | @showvalue |
---|
403 | |
---|
404 | @This may contain several @ref interval objects to act as an |
---|
405 | interval set. |
---|
406 | |
---|
407 | It provides several common boolean set operations like union, |
---|
408 | intersection, complement and value inclusion test. |
---|
409 | |
---|
410 | No extra value can be attached to intervals in set; it wouldn't |
---|
411 | make sense because interval may be splited, joined, created or |
---|
412 | destroyed by boolean operations. |
---|
413 | |
---|
414 | @tt X can be a standard scalar type or an user defined type. |
---|
415 | When a user defined type is used, a custom @tt Limits |
---|
416 | class parameter must be provided to define upper and lower value |
---|
417 | limits. The @ref interval_scalar_limits is used by default. |
---|
418 | |
---|
419 | @tt Bound specify interval bounds inclusivity policy. |
---|
420 | Acceptable values for @tt Bound template parameter are |
---|
421 | @ref interval_bound (default), @ref interval_bound_inclusive and |
---|
422 | @ref interval_bound_exclusive. |
---|
423 | */ |
---|
424 | |
---|
425 | template <typename X, class Bound, class Limits> |
---|
426 | class interval_set |
---|
427 | { |
---|
428 | public: |
---|
429 | |
---|
430 | /** Associated @ref interval type */ |
---|
431 | typedef interval<X, Bound> interval_type; |
---|
432 | |
---|
433 | private: |
---|
434 | typedef std::vector<interval_type> set_container; |
---|
435 | |
---|
436 | public: |
---|
437 | /** Value type */ |
---|
438 | typedef X value_type; |
---|
439 | /** @ref interval iterator */ |
---|
440 | typedef typename set_container::iterator iterator; |
---|
441 | /** @ref interval const iterator */ |
---|
442 | typedef typename set_container::const_iterator const_iterator; |
---|
443 | /** @ref interval set limits class */ |
---|
444 | typedef Limits limits_type; |
---|
445 | |
---|
446 | private: |
---|
447 | |
---|
448 | static void union_glob(const set_container &a, unsigned int &i, |
---|
449 | const set_container &b, unsigned int &j, |
---|
450 | set_container &c, unsigned int &k) |
---|
451 | { |
---|
452 | // skip all included intervals |
---|
453 | while (j < b.size() && b[j]._high.bound() < c[k]._high.bound()) |
---|
454 | j++; |
---|
455 | |
---|
456 | if (j < b.size()) |
---|
457 | { |
---|
458 | // if interval end equal to next interval start |
---|
459 | if (((c[k]._high.bound() == b[j]._low.bound()) |
---|
460 | && (c[k]._high.inclusive() || b[j]._low.inclusive())) |
---|
461 | // or interval end greater than next interval start |
---|
462 | || (b[j]._low.bound() < c[k]._high.bound())) |
---|
463 | { |
---|
464 | // join intervals |
---|
465 | c[k]._high = b[j++]._high; |
---|
466 | // terminal recursion |
---|
467 | return union_glob(b, j, a, i, c, k); |
---|
468 | } |
---|
469 | } |
---|
470 | } |
---|
471 | |
---|
472 | static interval_set union_(const set_container &a, const set_container &b) |
---|
473 | { |
---|
474 | interval_set res; |
---|
475 | set_container &c = res._set; |
---|
476 | |
---|
477 | unsigned int i, j, k; |
---|
478 | |
---|
479 | c.resize(a.size() + b.size()); |
---|
480 | |
---|
481 | for (i = j = k = 0; i < a.size() && j < b.size(); k++) |
---|
482 | { |
---|
483 | if (a[i]._low.bound() == b[j]._low.bound()) |
---|
484 | { |
---|
485 | c[k] = a[i]; |
---|
486 | c[k]._low.set_inclusive(a[i]._low.inclusive() | b[j]._low.inclusive()); |
---|
487 | i++; |
---|
488 | union_glob(a, i, b, j, c, k); |
---|
489 | } |
---|
490 | else if (a[i]._low.bound() < b[j]._low.bound()) |
---|
491 | { |
---|
492 | c[k] = a[i++]; |
---|
493 | union_glob(a, i, b, j, c, k); |
---|
494 | } |
---|
495 | else // if (a[i]._low._bound > b[j]._low._bound) |
---|
496 | { |
---|
497 | c[k] = b[j++]; |
---|
498 | union_glob(b, j, a, i, c, k); |
---|
499 | } |
---|
500 | } |
---|
501 | |
---|
502 | for (; i < a.size(); i++, k++) |
---|
503 | c[k] = a[i]; |
---|
504 | |
---|
505 | for (; j < b.size(); j++, k++) |
---|
506 | c[k] = b[j]; |
---|
507 | |
---|
508 | res._set.resize(k); |
---|
509 | |
---|
510 | return res; |
---|
511 | } |
---|
512 | |
---|
513 | static bool pair_intersect(const interval_type &a, const interval_type &b, interval_type &r) |
---|
514 | { |
---|
515 | if (b._low.bound() < a._low.bound()) |
---|
516 | r._low = a._low; |
---|
517 | else // if (a._low.bound() <= b._low.bound()) |
---|
518 | { |
---|
519 | r._low = b._low; |
---|
520 | if (!a._low.inclusive() && a._low.bound() == b._low.bound()) |
---|
521 | r._low.set_inclusive(false); |
---|
522 | } |
---|
523 | |
---|
524 | if (a._high.bound() < b._high.bound()) |
---|
525 | r._high = a._high; |
---|
526 | else // if (b._high.bound() <= a._high.bound()) |
---|
527 | { |
---|
528 | r._high = b._high; |
---|
529 | if (!a._high.inclusive() && a._high.bound() == b._high.bound()) |
---|
530 | r._high.set_inclusive(false); |
---|
531 | } |
---|
532 | |
---|
533 | if (r._high.bound() == r._low.bound()) |
---|
534 | return r._low.inclusive() && r._high.inclusive(); |
---|
535 | else |
---|
536 | return(r._low.bound() < r._high.bound()); |
---|
537 | } |
---|
538 | |
---|
539 | static interval_set intersection(const set_container &a, const set_container &b) |
---|
540 | { |
---|
541 | interval_set res; |
---|
542 | set_container &c = res._set; |
---|
543 | |
---|
544 | unsigned int i, j, k; |
---|
545 | |
---|
546 | c.resize(a.size() + b.size()); |
---|
547 | |
---|
548 | for (i = j = k = 0; i < a.size() && j < b.size(); ) |
---|
549 | { |
---|
550 | if (b[j]._high.bound() < a[i]._low.bound()) |
---|
551 | while (j < b.size() && b[j]._high.bound() < a[i]._low.bound()) |
---|
552 | j++; |
---|
553 | else if (a[i]._high.bound() < b[j]._low.bound()) |
---|
554 | while (i < a.size() && a[i]._high.bound() < b[j]._low.bound()) |
---|
555 | i++; |
---|
556 | else |
---|
557 | { |
---|
558 | if (pair_intersect(a[i], b[j], c[k])) |
---|
559 | k++; |
---|
560 | |
---|
561 | if (a[i]._high.bound() == b[j]._high.bound()) |
---|
562 | j++, i++; |
---|
563 | else if (a[i]._high.bound() < b[j]._high.bound()) |
---|
564 | i++; |
---|
565 | else |
---|
566 | j++; |
---|
567 | } |
---|
568 | } |
---|
569 | |
---|
570 | res._set.resize(k); |
---|
571 | |
---|
572 | return res; |
---|
573 | } |
---|
574 | |
---|
575 | static interval_set complement(const set_container &a) |
---|
576 | { |
---|
577 | if (a.empty()) |
---|
578 | return interval_set(true); |
---|
579 | |
---|
580 | unsigned int i, j; |
---|
581 | interval_set res; |
---|
582 | set_container &r = res._set; |
---|
583 | |
---|
584 | if (a[0]._low.bound() == limits_type::lower() && a[0]._low.inclusive()) |
---|
585 | { |
---|
586 | r.resize(a.size()); |
---|
587 | r[0]._low.set_bound(a[0]._high.bound()); |
---|
588 | r[0]._low.set_inclusive(!a[0]._high.inclusive()); |
---|
589 | j = 1; |
---|
590 | } |
---|
591 | else |
---|
592 | { |
---|
593 | r.resize(a.size() + 1); |
---|
594 | r[0]._low.set_bound(limits_type::lower()); |
---|
595 | r[0]._low.set_inclusive(true); |
---|
596 | j = 0; |
---|
597 | } |
---|
598 | |
---|
599 | for (i = 0; i < r.size() - 1; i++, j++) |
---|
600 | { |
---|
601 | r[i]._high.set_bound(a[j]._low.bound()); |
---|
602 | r[i]._high.set_inclusive(!a[j]._low.inclusive()); |
---|
603 | r[i+1]._low.set_bound(a[j]._high.bound()); |
---|
604 | r[i+1]._low.set_inclusive(!a[j]._high.inclusive()); |
---|
605 | } |
---|
606 | |
---|
607 | assert(j >= 1); |
---|
608 | |
---|
609 | if (a[j-1]._high.bound() == limits_type::upper() && a[j-1]._high.inclusive()) |
---|
610 | { |
---|
611 | r.pop_back(); |
---|
612 | } |
---|
613 | else |
---|
614 | { |
---|
615 | r[i]._high.set_bound(limits_type::upper()); |
---|
616 | r[i]._high.set_inclusive(true); |
---|
617 | } |
---|
618 | |
---|
619 | return res; |
---|
620 | } |
---|
621 | |
---|
622 | unsigned int dicho(const X a) const |
---|
623 | { |
---|
624 | unsigned int min_idx = 0; |
---|
625 | unsigned int max_idx = _set.size(); |
---|
626 | |
---|
627 | assert(!_set.empty()); |
---|
628 | |
---|
629 | // dichotomic search |
---|
630 | while (max_idx - min_idx > 1) |
---|
631 | { |
---|
632 | unsigned int p = (max_idx + min_idx) / 2; |
---|
633 | |
---|
634 | if (a < _set[p]._low.bound()) |
---|
635 | max_idx = p; |
---|
636 | else |
---|
637 | min_idx = p; |
---|
638 | } |
---|
639 | |
---|
640 | return min_idx; |
---|
641 | } |
---|
642 | |
---|
643 | public: |
---|
644 | |
---|
645 | /** @This creates an empty interval set */ |
---|
646 | interval_set() |
---|
647 | { |
---|
648 | } |
---|
649 | |
---|
650 | /** @This creates an empty or whole interval set */ |
---|
651 | interval_set(bool whole) |
---|
652 | { |
---|
653 | if (whole) |
---|
654 | _set.push_back(interval_type(limits_type::lower(), |
---|
655 | limits_type::upper())); |
---|
656 | } |
---|
657 | |
---|
658 | /** @This creates an interval set including values in given @ref interval */ |
---|
659 | interval_set(const interval_type &i) |
---|
660 | { |
---|
661 | _set.push_back(i); |
---|
662 | } |
---|
663 | |
---|
664 | /** @This creates an interval set including values in [@tt low, @tt high] range. |
---|
665 | @see interval::__interval_1__ */ |
---|
666 | interval_set(const X low, const X high) |
---|
667 | { |
---|
668 | _set.push_back(interval_type(low, high)); |
---|
669 | } |
---|
670 | |
---|
671 | /** @This creates an interval set including values in range {@tt low, @tt high} with given inclusivity |
---|
672 | @see interval::__interval_2__ */ |
---|
673 | interval_set(const X low, bool low_inclusive, |
---|
674 | const X high, bool high_inclusive) |
---|
675 | { |
---|
676 | _set.push_back(interval_type(low, low_inclusive, high, high_inclusive)); |
---|
677 | } |
---|
678 | |
---|
679 | /** @This resets the interval set to empty state */ |
---|
680 | void clear() |
---|
681 | { |
---|
682 | _set.clear(); |
---|
683 | } |
---|
684 | |
---|
685 | /** @This tests if interval set is empty */ |
---|
686 | bool empty() |
---|
687 | { |
---|
688 | return _set.empty(); |
---|
689 | } |
---|
690 | |
---|
691 | /** @This tests if interval set is whole */ |
---|
692 | bool whole() |
---|
693 | { |
---|
694 | return (!_set.empty() |
---|
695 | && _set.back()._low.bound() == limits_type::lower() |
---|
696 | && _set.back()._high.bound() == limits_type::upper()); |
---|
697 | } |
---|
698 | |
---|
699 | /** @This returns a new interval set being the union of the two interval sets */ |
---|
700 | interval_set operator|(const interval_set &i) const |
---|
701 | { |
---|
702 | return union_(_set, i._set); |
---|
703 | } |
---|
704 | |
---|
705 | /** @This replaces the current interval set by the union with given interval set */ |
---|
706 | interval_set & operator|=(const interval_set &i) |
---|
707 | { |
---|
708 | return *this = *this | i; // FIXME write optimized version |
---|
709 | } |
---|
710 | |
---|
711 | /** @This replaces the current interval set by the union with given interval */ |
---|
712 | interval_set & operator|=(const interval_type &i) |
---|
713 | { |
---|
714 | return *this = *this | interval_set(i); // FIXME write optimized version |
---|
715 | } |
---|
716 | |
---|
717 | /** @This returns a new interval set being the intersection of the two interval sets */ |
---|
718 | interval_set operator&(const interval_set &i) const |
---|
719 | { |
---|
720 | return intersection(_set, i._set); |
---|
721 | } |
---|
722 | |
---|
723 | /** @This replaces the current interval set by the intersection with given interval set */ |
---|
724 | interval_set & operator&=(const interval_set &i) |
---|
725 | { |
---|
726 | return *this = *this & i; // FIXME write optimized version |
---|
727 | } |
---|
728 | |
---|
729 | /** @This replaces the current interval set by the intersection with given interval */ |
---|
730 | interval_set & operator&=(const interval_type &i) |
---|
731 | { |
---|
732 | return *this = *this & interval_set(i); // FIXME write optimized version |
---|
733 | } |
---|
734 | |
---|
735 | /** @This returns the complementary interval set */ |
---|
736 | interval_set operator~() const |
---|
737 | { |
---|
738 | return complement(_set); |
---|
739 | } |
---|
740 | |
---|
741 | /** @This returns a new interval set being the exclusive or of the two interval sets */ |
---|
742 | interval_set operator^(const interval_set &i) const |
---|
743 | { |
---|
744 | return (*this & ~i) | (~*this & i); |
---|
745 | } |
---|
746 | |
---|
747 | /** @This replaces the current interval set by the exclusive or with given interval set */ |
---|
748 | interval_set & operator^=(const interval_set &i) |
---|
749 | { |
---|
750 | return *this = *this ^ i; |
---|
751 | } |
---|
752 | |
---|
753 | /** @This replaces the current interval set by the exclusive or with given interval */ |
---|
754 | interval_set & operator^=(const interval_type &i) |
---|
755 | { |
---|
756 | return *this = *this ^ interval_set(i); |
---|
757 | } |
---|
758 | |
---|
759 | /** @This returns the interval which contains the given value. |
---|
760 | This throws a @ref std::out_of_range exception if no matching |
---|
761 | interval is available in set. */ |
---|
762 | interval_type get_interval(const X a) const throw (std::out_of_range) |
---|
763 | { |
---|
764 | if (_set.empty()) |
---|
765 | throw std::out_of_range("empty interval_set"); |
---|
766 | |
---|
767 | unsigned int p = dicho(a); |
---|
768 | |
---|
769 | if (!_set[p].contains(a)) |
---|
770 | throw std::out_of_range("no matching interval found"); |
---|
771 | |
---|
772 | return _set[p]; |
---|
773 | } |
---|
774 | |
---|
775 | /** @This tests if specified value is included in interval set |
---|
776 | @alias contains_1 |
---|
777 | */ |
---|
778 | bool contains(const X a) const |
---|
779 | { |
---|
780 | return !_set.empty() && _set[dicho(a)].contains(a); |
---|
781 | } |
---|
782 | |
---|
783 | /** @This tests if specified interval set is included in interval set */ |
---|
784 | bool contains(const interval_set &i) const |
---|
785 | { |
---|
786 | return (i & *this) == i; // FIXME write optimized version |
---|
787 | } |
---|
788 | |
---|
789 | /** @This is a shortcut for @ref __contains_1__ */ |
---|
790 | bool operator[](const X a) const |
---|
791 | { |
---|
792 | return contains(a); |
---|
793 | } |
---|
794 | |
---|
795 | /** @This tests if two interval sets are equals */ |
---|
796 | bool operator==(const interval_set &i) const |
---|
797 | { |
---|
798 | if (_set.size() != i._set.size()) |
---|
799 | return false; |
---|
800 | |
---|
801 | for (unsigned int j = 0; j < _set.size(); j++) |
---|
802 | if (!(_set[j] == i._set[j])) |
---|
803 | return false; |
---|
804 | |
---|
805 | return true; |
---|
806 | } |
---|
807 | |
---|
808 | /** @This returns an interval set iterator. It can be |
---|
809 | used to iterator over all @ref interval contained in the set. */ |
---|
810 | iterator begin() |
---|
811 | { |
---|
812 | return _set.begin(); |
---|
813 | } |
---|
814 | |
---|
815 | /** @This returns an interval set end iterator. */ |
---|
816 | iterator end() |
---|
817 | { |
---|
818 | return _set.end(); |
---|
819 | } |
---|
820 | |
---|
821 | /** @This returns an interval set const iterator. It can be |
---|
822 | used to iterator over all @ref interval contained in the set. */ |
---|
823 | const_iterator begin() const |
---|
824 | { |
---|
825 | return _set.begin(); |
---|
826 | } |
---|
827 | |
---|
828 | /** @This returns an interval set end iterator. */ |
---|
829 | const_iterator end() const |
---|
830 | { |
---|
831 | return _set.end(); |
---|
832 | } |
---|
833 | |
---|
834 | /** @This prints interval set to stream by iterating over all @ref interval |
---|
835 | present in the set using @ref interval::__print__ |
---|
836 | */ |
---|
837 | friend std::ostream & operator<<(std::ostream &o, const interval_set<X, Bound, Limits> &is) |
---|
838 | { |
---|
839 | for (typename interval_set<X, Bound, Limits>::const_iterator i = is.begin(); i != is.end(); i++) |
---|
840 | o << *i; |
---|
841 | return o; |
---|
842 | } |
---|
843 | |
---|
844 | private: |
---|
845 | |
---|
846 | set_container _set; |
---|
847 | }; |
---|
848 | |
---|
849 | } |
---|
850 | |
---|
851 | #endif |
---|
852 | |
---|