xref: /aosp_15_r20/external/cronet/net/base/interval.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // An Interval<T> is a data structure used to represent a contiguous, mutable
6 // range over an ordered type T. Supported operations include testing a value to
7 // see whether it is included in the interval, comparing two intervals, and
8 // performing their union, intersection, and difference. For the purposes of
9 // this library, an "ordered type" is any type that induces a total order on its
10 // values via its less-than operator (operator<()). Examples of such types are
11 // basic arithmetic types like int and double as well as class types like
12 // string.
13 //
14 // An Interval<T> is represented using the usual C++ STL convention, namely as
15 // the half-open interval [min, max). A point p is considered to be contained in
16 // the interval iff p >= min && p < max. One consequence of this definition is
17 // that for any non-empty interval, min is contained in the interval but max is
18 // not. There is no canonical representation for the empty interval; rather, any
19 // interval where max <= min is regarded as empty. As a consequence, two empty
20 // intervals will still compare as equal despite possibly having different
21 // underlying min() or max() values. Also beware of the terminology used here:
22 // the library uses the terms "min" and "max" rather than "begin" and "end" as
23 // is conventional for the STL.
24 //
25 // T is required to be default- and copy-constructable, to have an assignment
26 // operator, and the full complement of comparison operators (<, <=, ==, !=, >=,
27 // >).  A difference operator (operator-()) is required if Interval<T>::Length
28 // is used.
29 //
30 // For equality comparisons, Interval<T> supports an Equals() method and an
31 // operator==() which delegates to it. Two intervals are considered equal if
32 // either they are both empty or if their corresponding min and max fields
33 // compare equal. For ordered comparisons, Interval<T> also provides the
34 // comparator Interval<T>::Less and an operator<() which delegates to it.
35 // Unfortunately this comparator is currently buggy because its behavior is
36 // inconsistent with Equals(): two empty ranges with different representations
37 // may be regarded as equivalent by Equals() but regarded as different by
38 // the comparator. Bug 9240050 has been created to address this.
39 //
40 // This class is thread-compatible if T is thread-compatible. (See
41 // go/thread-compatible).
42 //
43 // Examples:
44 //   Interval<int> r1(0, 100);  // The interval [0, 100).
45 //   EXPECT_TRUE(r1.Contains(0));
46 //   EXPECT_TRUE(r1.Contains(50));
47 //   EXPECT_FALSE(r1.Contains(100));  // 100 is just outside the interval.
48 //
49 //   Interval<int> r2(50, 150);  // The interval [50, 150).
50 //   EXPECT_TRUE(r1.Intersects(r2));
51 //   EXPECT_FALSE(r1.Contains(r2));
52 //   EXPECT_TRUE(r1.IntersectWith(r2));  // Mutates r1.
53 //   EXPECT_EQ(Interval<int>(50, 100), r1);  // r1 is now [50, 100).
54 //
55 //   Interval<int> r3(1000, 2000);  // The interval [1000, 2000).
56 //   EXPECT_TRUE(r1.IntersectWith(r3));  // Mutates r1.
57 //   EXPECT_TRUE(r1.Empty());  // Now r1 is empty.
58 //   EXPECT_FALSE(r1.Contains(r1.min()));  // e.g. doesn't contain its own min.
59 
60 #ifndef NET_BASE_INTERVAL_H_
61 #define NET_BASE_INTERVAL_H_
62 
63 #include <stddef.h>
64 
65 #include <algorithm>
66 #include <functional>
67 #include <ostream>
68 #include <utility>
69 #include <vector>
70 
71 namespace net {
72 
73 template <typename T>
74 class Interval {
75  private:
76 // TODO(rtenneti): Implement after suupport for std::decay.
77 #if 0
78   // Type trait for deriving the return type for Interval::Length.  If
79   // operator-() is not defined for T, then the return type is void.  This makes
80   // the signature for Length compile so that the class can be used for such T,
81   // but code that calls Length would still generate a compilation error.
82   template <typename U>
83   class DiffTypeOrVoid {
84    private:
85     template <typename V>
86     static auto f(const V* v) -> decltype(*v - *v);
87     template <typename V>
88     static void f(...);
89 
90    public:
91     using type = typename std::decay<decltype(f<U>(0))>::type;
92   };
93 #endif
94 
95  public:
96   // Compatibility alias.
97   using Less = std::less<Interval>;
98 
99   // Construct an Interval representing an empty interval.
Interval()100   Interval() : min_(), max_() {}
101 
102   // Construct an Interval representing the interval [min, max). If min < max,
103   // the constructed object will represent the non-empty interval containing all
104   // values from min up to (but not including) max. On the other hand, if min >=
105   // max, the constructed object will represent the empty interval.
Interval(const T & min,const T & max)106   Interval(const T& min, const T& max) : min_(min), max_(max) {}
107 
min()108   const T& min() const { return min_; }
max()109   const T& max() const { return max_; }
SetMin(const T & t)110   void SetMin(const T& t) { min_ = t; }
SetMax(const T & t)111   void SetMax(const T& t) { max_ = t; }
112 
Set(const T & min,const T & max)113   void Set(const T& min, const T& max) {
114     SetMin(min);
115     SetMax(max);
116   }
117 
Clear()118   void Clear() { *this = {}; }
CopyFrom(const Interval & i)119   void CopyFrom(const Interval& i) { *this = i; }
Equals(const Interval & i)120   bool Equals(const Interval& i) const { return *this == i; }
Empty()121   bool Empty() const { return min() >= max(); }
122 
123   // Returns the length of this interval. The value returned is zero if
124   // IsEmpty() is true; otherwise the value returned is max() - min().
Length()125   const T Length() const { return (min_ >= max_ ? min_ : max_) - min_; }
126 
127   // Returns true iff t >= min() && t < max().
Contains(const T & t)128   bool Contains(const T& t) const { return min() <= t && max() > t; }
129 
130   // Returns true iff *this and i are non-empty, and *this includes i. "*this
131   // includes i" means that for all t, if i.Contains(t) then this->Contains(t).
132   // Note the unintuitive consequence of this definition: this method always
133   // returns false when i is the empty interval.
Contains(const Interval & i)134   bool Contains(const Interval& i) const {
135     return !Empty() && !i.Empty() && min() <= i.min() && max() >= i.max();
136   }
137 
138   // Returns true iff there exists some point t for which this->Contains(t) &&
139   // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
Intersects(const Interval & i)140   bool Intersects(const Interval& i) const {
141     return !Empty() && !i.Empty() && min() < i.max() && max() > i.min();
142   }
143 
144   // Returns true iff there exists some point t for which this->Contains(t) &&
145   // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
146   // Furthermore, if the intersection is non-empty and the intersection pointer
147   // is not null, this method stores the calculated intersection in
148   // *intersection.
149   bool Intersects(const Interval& i, Interval* out) const;
150 
151   // Sets *this to be the intersection of itself with i. Returns true iff
152   // *this was modified.
153   bool IntersectWith(const Interval& i);
154 
155   // Calculates the smallest interval containing both *this i, and updates *this
156   // to represent that interval, and returns true iff *this was modified.
157   bool SpanningUnion(const Interval& i);
158 
159   // Determines the difference between two intervals as in
160   // Difference(Interval&, vector*), but stores the results directly in out
161   // parameters rather than dynamically allocating an Interval* and appending
162   // it to a vector. If two results are generated, the one with the smaller
163   // value of min() will be stored in *lo and the other in *hi. Otherwise (if
164   // fewer than two results are generated), unused arguments will be set to the
165   // empty interval (it is possible that *lo will be empty and *hi non-empty).
166   // The method returns true iff the intersection of *this and i is non-empty.
167   bool Difference(const Interval& i, Interval* lo, Interval* hi) const;
168 
169   friend bool operator==(const Interval& a, const Interval& b) {
170     bool ae = a.Empty();
171     bool be = b.Empty();
172     if (ae && be)
173       return true;  // All empties are equal.
174     if (ae != be)
175       return false;  // Empty cannot equal nonempty.
176     return a.min() == b.min() && a.max() == b.max();
177   }
178 
179   friend bool operator!=(const Interval& a, const Interval& b) {
180     return !(a == b);
181   }
182 
183   // Defines a comparator which can be used to induce an order on Intervals, so
184   // that, for example, they can be stored in an ordered container such as
185   // std::set. The ordering is arbitrary, but does provide the guarantee that,
186   // for non-empty intervals X and Y, if X contains Y, then X <= Y.
187   // TODO(kosak): The current implementation of this comparator has a problem
188   // because the ordering it induces is inconsistent with that of Equals(). In
189   // particular, this comparator does not properly consider all empty intervals
190   // equivalent. Bug b/9240050 has been created to track this.
191   friend bool operator<(const Interval& a, const Interval& b) {
192     return a.min() < b.min() || (a.min() == b.min() && a.max() > b.max());
193   }
194 
195   friend std::ostream& operator<<(std::ostream& out, const Interval& i) {
196     return out << "[" << i.min() << ", " << i.max() << ")";
197   }
198 
199  private:
200   T min_;  // Inclusive lower bound.
201   T max_;  // Exclusive upper bound.
202 };
203 
204 //==============================================================================
205 // Implementation details: Clients can stop reading here.
206 
207 template <typename T>
Intersects(const Interval & i,Interval * out)208 bool Interval<T>::Intersects(const Interval& i, Interval* out) const {
209   if (!Intersects(i))
210     return false;
211   if (out != nullptr) {
212     *out = Interval(std::max(min(), i.min()), std::min(max(), i.max()));
213   }
214   return true;
215 }
216 
217 template <typename T>
IntersectWith(const Interval & i)218 bool Interval<T>::IntersectWith(const Interval& i) {
219   if (Empty())
220     return false;
221   bool modified = false;
222   if (i.min() > min()) {
223     SetMin(i.min());
224     modified = true;
225   }
226   if (i.max() < max()) {
227     SetMax(i.max());
228     modified = true;
229   }
230   return modified;
231 }
232 
233 template <typename T>
SpanningUnion(const Interval & i)234 bool Interval<T>::SpanningUnion(const Interval& i) {
235   if (i.Empty())
236     return false;
237   if (Empty()) {
238     *this = i;
239     return true;
240   }
241   bool modified = false;
242   if (i.min() < min()) {
243     SetMin(i.min());
244     modified = true;
245   }
246   if (i.max() > max()) {
247     SetMax(i.max());
248     modified = true;
249   }
250   return modified;
251 }
252 
253 template <typename T>
Difference(const Interval & i,Interval * lo,Interval * hi)254 bool Interval<T>::Difference(const Interval& i,
255                              Interval* lo,
256                              Interval* hi) const {
257   // Initialize *lo and *hi to empty
258   *lo = {};
259   *hi = {};
260   if (Empty())
261     return false;
262   if (i.Empty()) {
263     *lo = *this;
264     return false;
265   }
266   if (min() < i.max() && min() >= i.min() && max() > i.max()) {
267     //            [------ this ------)
268     // [------ i ------)
269     //                 [-- result ---)
270     *hi = Interval(i.max(), max());
271     return true;
272   }
273   if (max() > i.min() && max() <= i.max() && min() < i.min()) {
274     // [------ this ------)
275     //            [------ i ------)
276     // [- result -)
277     *lo = Interval(min(), i.min());
278     return true;
279   }
280   if (min() < i.min() && max() > i.max()) {
281     // [------- this --------)
282     //      [---- i ----)
283     // [ R1 )           [ R2 )
284     // There are two results: R1 and R2.
285     *lo = Interval(min(), i.min());
286     *hi = Interval(i.max(), max());
287     return true;
288   }
289   if (min() >= i.min() && max() <= i.max()) {
290     //   [--- this ---)
291     // [------ i --------)
292     // Intersection is <this>, so difference yields the empty interval.
293     return true;
294   }
295   *lo = *this;  // No intersection.
296   return false;
297 }
298 
299 }  // namespace net
300 
301 #endif  // NET_BASE_INTERVAL_H_
302