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