1414#ifndef OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_
1515#define OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_
1616
17+ #include < cstddef>
1718#include < cstdint>
1819#include < iterator>
1920#include < ostream>
@@ -32,21 +33,41 @@ namespace operations_research {
3233 * Represents a closed interval [start, end]. We must have start <= end.
3334 */
3435struct ClosedInterval {
36+ #if !defined(SWIG)
37+ /* *
38+ * An iterator over the values of a ClosedInterval object.
39+ *
40+ * To iterate over the values, you can use either a range for loop:
41+ *
42+ * ClosedInterval interval = {0, 100};
43+ * for (const int64_t value : interval) { Work(value); }
44+ *
45+ * or a classical for loop:
46+ * for (auto it = begin(interval); it != end(interval); ++it) { Work(*it); }
47+ *
48+ * The iterator is designed to be very efficient, using just a single counter.
49+ * It works correctly for any combination of `start` and `end` except the full
50+ * int64_t range (start == INT64_MIN && end == INT64_MAX).
51+ */
52+ class Iterator ;
53+ #endif // !defined(SWIG)
54+
3555 ClosedInterval () {}
56+ explicit ClosedInterval (int64_t v) : start(v), end(v) {}
3657 ClosedInterval (int64_t s, int64_t e) : start(s), end(e) {
3758 DLOG_IF (DFATAL , s > e) << " Invalid ClosedInterval(" << s << " , " << e
3859 << " )" ;
3960 }
4061
4162 std::string DebugString () const ;
42- bool operator ==(const ClosedInterval& other) const {
63+ constexpr bool operator ==(const ClosedInterval& other) const {
4364 return start == other.start && end == other.end ;
4465 }
4566
4667 // Because we mainly manipulate vector of disjoint intervals, we only need to
4768 // sort by the start. We do not care about the order in which interval with
4869 // the same start appear since they will always be merged into one interval.
49- bool operator <(const ClosedInterval& other) const {
70+ constexpr bool operator <(const ClosedInterval& other) const {
5071 return start < other.start ;
5172 }
5273
@@ -59,6 +80,11 @@ struct ClosedInterval {
5980 int64_t end = 0 ; // Inclusive.
6081};
6182
83+ #if !defined(SWIG)
84+ inline ClosedInterval::Iterator begin (ClosedInterval interval);
85+ inline ClosedInterval::Iterator end (ClosedInterval interval);
86+ #endif // !defined(SWIG)
87+
6288std::ostream& operator <<(std::ostream& out, const ClosedInterval& interval);
6389std::ostream& operator <<(std::ostream& out,
6490 const std::vector<ClosedInterval>& intervals);
@@ -648,6 +674,67 @@ class SortedDisjointIntervalList {
648674 IntervalSet intervals_;
649675};
650676
677+ // Implementation details.
678+
679+ #if !defined(SWIG)
680+ class ClosedInterval ::Iterator {
681+ public:
682+ using value_type = int64_t ;
683+ using difference_type = std::ptrdiff_t ;
684+
685+ Iterator (const Iterator&) = default ;
686+
687+ int64_t operator *() const { return static_cast <int64_t >(current_); }
688+
689+ Iterator& operator ++() {
690+ ++current_;
691+ return *this ;
692+ }
693+ void operator ++(int ) { ++current_; }
694+
695+ bool operator ==(Iterator other) const { return current_ == other.current_ ; }
696+ bool operator !=(Iterator other) const { return current_ != other.current_ ; }
697+
698+ Iterator& operator =(const Iterator&) = default ;
699+
700+ static Iterator Begin (ClosedInterval interval) {
701+ AssertNotFullInt64Range (interval);
702+ return Iterator (static_cast <uint64_t >(interval.start ));
703+ }
704+ static Iterator End (ClosedInterval interval) {
705+ AssertNotFullInt64Range (interval);
706+ return Iterator (static_cast <uint64_t >(interval.end ) + 1 );
707+ }
708+
709+ private:
710+ explicit Iterator (uint64_t current) : current_(current) {}
711+
712+ // Triggers a DCHECK-failure when `interval` represents the full int64_t
713+ // range.
714+ static void AssertNotFullInt64Range (ClosedInterval interval) {
715+ DCHECK_NE (static_cast <uint64_t >(interval.start ),
716+ static_cast <uint64_t >(interval.end ) + 1 )
717+ << " Iteration over the full int64_t range is not supported." ;
718+ }
719+
720+ // Implementation note: In C++, integer overflow is well-defined only for
721+ // unsigned integers. To avoid any compilation issues or UBSan failures, the
722+ // iterator uses uint64_t internally and relies on the fact that since C++20
723+ // unsigned->signed conversion is well-defined for all values using modulo
724+ // arithmetic.
725+ uint64_t current_;
726+ };
727+
728+ // begin()/end() are required for iteration over ClosedInterval in a range for
729+ // loop.
730+ inline ClosedInterval::Iterator begin (ClosedInterval interval) {
731+ return ClosedInterval::Iterator::Begin (interval);
732+ }
733+ inline ClosedInterval::Iterator end (ClosedInterval interval) {
734+ return ClosedInterval::Iterator::End (interval);
735+ }
736+ #endif // !defined(SWIG)
737+
651738} // namespace operations_research
652739
653740#endif // OR_TOOLS_UTIL_SORTED_INTERVAL_LIST_H_
0 commit comments