xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_interval.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_CORE_QUIC_INTERVAL_H_
6 #define QUICHE_QUIC_CORE_QUIC_INTERVAL_H_
7 
8 // An QuicInterval<T> is a data structure used to represent a contiguous,
9 // mutable range over an ordered type T. Supported operations include testing a
10 // value to see whether it is included in the QuicInterval, comparing two
11 // QuicIntervals, and performing their union, intersection, and difference. For
12 // the purposes of this library, an "ordered type" is any type that induces a
13 // total order on its values via its less-than operator (operator<()). Examples
14 // of such types are basic arithmetic types like int and double as well as class
15 // types like string.
16 //
17 // An QuicInterval<T> is represented using the usual C++ STL convention, namely
18 // as the half-open QuicInterval [min, max). A point p is considered to be
19 // contained in the QuicInterval iff p >= min && p < max. One consequence of
20 // this definition is that for any non-empty QuicInterval, min is contained in
21 // the QuicInterval but max is not. There is no canonical representation for the
22 // empty QuicInterval; rather, any QuicInterval where max <= min is regarded as
23 // empty. As a consequence, two empty QuicIntervals will still compare as equal
24 // despite possibly having different underlying min() or max() values. Also
25 // beware of the terminology used here: the library uses the terms "min" and
26 // "max" rather than "begin" and "end" as is conventional for the STL.
27 //
28 // T is required to be default- and copy-constructable, to have an assignment
29 // operator, and the full complement of comparison operators (<, <=, ==, !=, >=,
30 // >).  A difference operator (operator-()) is required if
31 // QuicInterval<T>::Length is used.
32 //
33 // QuicInterval supports operator==. Two QuicIntervals are considered equal if
34 // either they are both empty or if their corresponding min and max fields
35 // compare equal. QuicInterval also provides an operator<. Unfortunately,
36 // operator< is currently buggy because its behavior is inconsistent with
37 // operator==: two empty ranges with different representations may be regarded
38 // as equal by operator== but regarded as different by operator<. Bug 9240050
39 // has been created to address this.
40 //
41 //
42 // Examples:
43 //   QuicInterval<int> r1(0, 100);  // The QuicInterval [0, 100).
44 //   EXPECT_TRUE(r1.Contains(0));
45 //   EXPECT_TRUE(r1.Contains(50));
46 //   EXPECT_FALSE(r1.Contains(100));  // 100 is just outside the QuicInterval.
47 //
48 //   QuicInterval<int> r2(50, 150);  // The QuicInterval [50, 150).
49 //   EXPECT_TRUE(r1.Intersects(r2));
50 //   EXPECT_FALSE(r1.Contains(r2));
51 //   EXPECT_TRUE(r1.IntersectWith(r2));  // Mutates r1.
52 //   EXPECT_EQ(QuicInterval<int>(50, 100), r1);  // r1 is now [50, 100).
53 //
54 //   QuicInterval<int> r3(1000, 2000);  // The QuicInterval [1000, 2000).
55 //   EXPECT_TRUE(r1.IntersectWith(r3));  // Mutates r1.
56 //   EXPECT_TRUE(r1.Empty());  // Now r1 is empty.
57 //   EXPECT_FALSE(r1.Contains(r1.min()));  // e.g. doesn't contain its own min.
58 
59 #include <stddef.h>
60 
61 #include <algorithm>
62 #include <ostream>
63 #include <type_traits>
64 #include <utility>
65 #include <vector>
66 
67 #include "quiche/quic/platform/api/quic_export.h"
68 
69 namespace quic {
70 
71 template <typename T>
72 class QUICHE_NO_EXPORT QuicInterval {
73  private:
74   // Type trait for deriving the return type for QuicInterval::Length.  If
75   // operator-() is not defined for T, then the return type is void.  This makes
76   // the signature for Length compile so that the class can be used for such T,
77   // but code that calls Length would still generate a compilation error.
78   template <typename U>
79   class QUICHE_NO_EXPORT DiffTypeOrVoid {
80    private:
81     template <typename V>
82     static auto f(const V* v) -> decltype(*v - *v);
83     template <typename V>
84     static void f(...);
85 
86    public:
87     using type = typename std::decay<decltype(f<U>(nullptr))>::type;
88   };
89 
90  public:
91   // Construct an QuicInterval representing an empty QuicInterval.
QuicInterval()92   QuicInterval() : min_(), max_() {}
93 
94   // Construct an QuicInterval representing the QuicInterval [min, max). If min
95   // < max, the constructed object will represent the non-empty QuicInterval
96   // containing all values from min up to (but not including) max. On the other
97   // hand, if min >= max, the constructed object will represent the empty
98   // QuicInterval.
QuicInterval(const T & min,const T & max)99   QuicInterval(const T& min, const T& max) : min_(min), max_(max) {}
100 
101   template <typename U1, typename U2,
102             typename = typename std::enable_if<
103                 std::is_convertible<U1, T>::value &&
104                 std::is_convertible<U2, T>::value>::type>
QuicInterval(U1 && min,U2 && max)105   QuicInterval(U1&& min, U2&& max)
106       : min_(std::forward<U1>(min)), max_(std::forward<U2>(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 = {}; }
119 
Empty()120   bool Empty() const { return min() >= max(); }
121 
122   // Returns the length of this QuicInterval. The value returned is zero if
123   // Empty() is true; otherwise the value returned is max() - min().
Length()124   typename DiffTypeOrVoid<T>::type Length() const {
125     return (Empty() ? min() : max()) - min();
126   }
127 
128   // Returns true iff t >= min() && t < max().
Contains(const T & t)129   bool Contains(const T& t) const { return min() <= t && max() > t; }
130 
131   // Returns true iff *this and i are non-empty, and *this includes i. "*this
132   // includes i" means that for all t, if i.Contains(t) then this->Contains(t).
133   // Note the unintuitive consequence of this definition: this method always
134   // returns false when i is the empty QuicInterval.
Contains(const QuicInterval & i)135   bool Contains(const QuicInterval& i) const {
136     return !Empty() && !i.Empty() && min() <= i.min() && max() >= i.max();
137   }
138 
139   // Returns true iff there exists some point t for which this->Contains(t) &&
140   // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
Intersects(const QuicInterval & i)141   bool Intersects(const QuicInterval& i) const {
142     return !Empty() && !i.Empty() && min() < i.max() && max() > i.min();
143   }
144 
145   // Returns true iff there exists some point t for which this->Contains(t) &&
146   // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty.
147   // Furthermore, if the intersection is non-empty and the out pointer is not
148   // null, this method stores the calculated intersection in *out.
149   bool Intersects(const QuicInterval& i, QuicInterval* 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 QuicInterval& i);
154 
155   // Returns true iff this and other have disjoint closures.  For nonempty
156   // intervals, that means there is at least one point between this and other.
157   // Roughly speaking that means the intervals don't intersect, and they are not
158   // adjacent.   Empty intervals are always separated from any other interval.
Separated(const QuicInterval & other)159   bool Separated(const QuicInterval& other) const {
160     if (Empty() || other.Empty()) return true;
161     return other.max() < min() || max() < other.min();
162   }
163 
164   // Calculates the smallest QuicInterval containing both *this i, and updates
165   // *this to represent that QuicInterval, and returns true iff *this was
166   // modified.
167   bool SpanningUnion(const QuicInterval& i);
168 
169   // Determines the difference between two QuicIntervals by finding all points
170   // that are contained in *this but not in i, coalesces those points into the
171   // largest possible contiguous QuicIntervals, and appends those QuicIntervals
172   // to the *difference vector. Intuitively this can be thought of as "erasing"
173   // i from *this. This will either completely erase *this (leaving nothing
174   // behind), partially erase some of *this from the left or right side (leaving
175   // some residual behind), or erase a hole in the middle of *this (leaving
176   // behind an QuicInterval on either side). Therefore, 0, 1, or 2 QuicIntervals
177   // will be appended to *difference. The method returns true iff the
178   // intersection of *this and i is non-empty. The caller owns the vector and
179   // the QuicInterval* pointers inside it. The difference vector is required to
180   // be non-null.
181   bool Difference(const QuicInterval& i,
182                   std::vector<QuicInterval*>* difference) const;
183 
184   // Determines the difference between two QuicIntervals as in
185   // Difference(QuicInterval&, vector*), but stores the results directly in out
186   // parameters rather than dynamically allocating an QuicInterval* and
187   // appending it to a vector. If two results are generated, the one with the
188   // smaller value of min() will be stored in *lo and the other in *hi.
189   // Otherwise (if fewer than two results are generated), unused arguments will
190   // be set to the empty QuicInterval (it is possible that *lo will be empty and
191   // *hi non-empty). The method returns true iff the intersection of *this and i
192   // is non-empty.
193   bool Difference(const QuicInterval& i, QuicInterval* lo,
194                   QuicInterval* hi) const;
195 
196   friend bool operator==(const QuicInterval& a, const QuicInterval& b) {
197     bool ae = a.Empty();
198     bool be = b.Empty();
199     if (ae && be) return true;   // All empties are equal.
200     if (ae != be) return false;  // Empty cannot equal nonempty.
201     return a.min() == b.min() && a.max() == b.max();
202   }
203 
204   friend bool operator!=(const QuicInterval& a, const QuicInterval& b) {
205     return !(a == b);
206   }
207 
208   // Defines a comparator which can be used to induce an order on QuicIntervals,
209   // so that, for example, they can be stored in an ordered container such as
210   // std::set. The ordering is arbitrary, but does provide the guarantee that,
211   // for non-empty QuicIntervals X and Y, if X contains Y, then X <= Y.
212   // TODO(kosak): The current implementation of this comparator has a problem
213   // because the ordering it induces is inconsistent with that of Equals(). In
214   // particular, this comparator does not properly consider all empty
215   // QuicIntervals equivalent. Bug 9240050 has been created to track this.
216   friend bool operator<(const QuicInterval& a, const QuicInterval& b) {
217     return a.min() < b.min() || (!(b.min() < a.min()) && b.max() < a.max());
218   }
219 
220  private:
221   T min_;  // Inclusive lower bound.
222   T max_;  // Exclusive upper bound.
223 };
224 
225 // Constructs an QuicInterval by deducing the types from the function arguments.
226 template <typename T>
MakeQuicInterval(T && lhs,T && rhs)227 QuicInterval<T> MakeQuicInterval(T&& lhs, T&& rhs) {
228   return QuicInterval<T>(std::forward<T>(lhs), std::forward<T>(rhs));
229 }
230 
231 // Note: ideally we'd use
232 //   decltype(out << "[" << i.min() << ", " << i.max() << ")")
233 // as return type of the function, but as of July 2017 this triggers g++
234 // "sorry, unimplemented: string literal in function template signature" error.
235 template <typename T>
236 auto operator<<(std::ostream& out, const QuicInterval<T>& i)
237     -> decltype(out << i.min()) {
238   return out << "[" << i.min() << ", " << i.max() << ")";
239 }
240 
241 //==============================================================================
242 // Implementation details: Clients can stop reading here.
243 
244 template <typename T>
Intersects(const QuicInterval & i,QuicInterval * out)245 bool QuicInterval<T>::Intersects(const QuicInterval& i,
246                                  QuicInterval* out) const {
247   if (!Intersects(i)) return false;
248   if (out != nullptr) {
249     *out = QuicInterval(std::max(min(), i.min()), std::min(max(), i.max()));
250   }
251   return true;
252 }
253 
254 template <typename T>
IntersectWith(const QuicInterval & i)255 bool QuicInterval<T>::IntersectWith(const QuicInterval& i) {
256   if (Empty()) return false;
257   bool modified = false;
258   if (i.min() > min()) {
259     SetMin(i.min());
260     modified = true;
261   }
262   if (i.max() < max()) {
263     SetMax(i.max());
264     modified = true;
265   }
266   return modified;
267 }
268 
269 template <typename T>
SpanningUnion(const QuicInterval & i)270 bool QuicInterval<T>::SpanningUnion(const QuicInterval& i) {
271   if (i.Empty()) return false;
272   if (Empty()) {
273     *this = i;
274     return true;
275   }
276   bool modified = false;
277   if (i.min() < min()) {
278     SetMin(i.min());
279     modified = true;
280   }
281   if (i.max() > max()) {
282     SetMax(i.max());
283     modified = true;
284   }
285   return modified;
286 }
287 
288 template <typename T>
Difference(const QuicInterval & i,std::vector<QuicInterval * > * difference)289 bool QuicInterval<T>::Difference(const QuicInterval& i,
290                                  std::vector<QuicInterval*>* difference) const {
291   if (Empty()) {
292     // <empty> - <i> = <empty>
293     return false;
294   }
295   if (i.Empty()) {
296     // <this> - <empty> = <this>
297     difference->push_back(new QuicInterval(*this));
298     return false;
299   }
300   if (min() < i.max() && min() >= i.min() && max() > i.max()) {
301     //            [------ this ------)
302     // [------ i ------)
303     //                 [-- result ---)
304     difference->push_back(new QuicInterval(i.max(), max()));
305     return true;
306   }
307   if (max() > i.min() && max() <= i.max() && min() < i.min()) {
308     // [------ this ------)
309     //            [------ i ------)
310     // [- result -)
311     difference->push_back(new QuicInterval(min(), i.min()));
312     return true;
313   }
314   if (min() < i.min() && max() > i.max()) {
315     // [------- this --------)
316     //      [---- i ----)
317     // [ R1 )           [ R2 )
318     // There are two results: R1 and R2.
319     difference->push_back(new QuicInterval(min(), i.min()));
320     difference->push_back(new QuicInterval(i.max(), max()));
321     return true;
322   }
323   if (min() >= i.min() && max() <= i.max()) {
324     //   [--- this ---)
325     // [------ i --------)
326     // Intersection is <this>, so difference yields the empty QuicInterval.
327     // Nothing is appended to *difference.
328     return true;
329   }
330   // No intersection. Append <this>.
331   difference->push_back(new QuicInterval(*this));
332   return false;
333 }
334 
335 template <typename T>
Difference(const QuicInterval & i,QuicInterval * lo,QuicInterval * hi)336 bool QuicInterval<T>::Difference(const QuicInterval& i, QuicInterval* lo,
337                                  QuicInterval* hi) const {
338   // Initialize *lo and *hi to empty
339   *lo = {};
340   *hi = {};
341   if (Empty()) return false;
342   if (i.Empty()) {
343     *lo = *this;
344     return false;
345   }
346   if (min() < i.max() && min() >= i.min() && max() > i.max()) {
347     //            [------ this ------)
348     // [------ i ------)
349     //                 [-- result ---)
350     *hi = QuicInterval(i.max(), max());
351     return true;
352   }
353   if (max() > i.min() && max() <= i.max() && min() < i.min()) {
354     // [------ this ------)
355     //            [------ i ------)
356     // [- result -)
357     *lo = QuicInterval(min(), i.min());
358     return true;
359   }
360   if (min() < i.min() && max() > i.max()) {
361     // [------- this --------)
362     //      [---- i ----)
363     // [ R1 )           [ R2 )
364     // There are two results: R1 and R2.
365     *lo = QuicInterval(min(), i.min());
366     *hi = QuicInterval(i.max(), max());
367     return true;
368   }
369   if (min() >= i.min() && max() <= i.max()) {
370     //   [--- this ---)
371     // [------ i --------)
372     // Intersection is <this>, so difference yields the empty QuicInterval.
373     return true;
374   }
375   *lo = *this;  // No intersection.
376   return false;
377 }
378 
379 }  // namespace quic
380 
381 #endif  // QUICHE_QUIC_CORE_QUIC_INTERVAL_H_
382