blob: 9e87ecd051f40b6ce31522a0154738440034b1de [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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#include <algorithm>
61#include <ostream>
62#include <type_traits>
63#include <utility>
64#include <vector>
65
dschinazif25169a2019-10-23 08:12:18 -070066#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
67
QUICHE teama6ef0a62019-03-07 20:34:33 -050068namespace quic {
69
70template <typename T>
dschinazie2116422019-10-29 11:54:26 -070071class QUIC_NO_EXPORT QuicInterval {
QUICHE teama6ef0a62019-03-07 20:34:33 -050072 private:
73 // Type trait for deriving the return type for QuicInterval::Length. If
74 // operator-() is not defined for T, then the return type is void. This makes
75 // the signature for Length compile so that the class can be used for such T,
76 // but code that calls Length would still generate a compilation error.
77 template <typename U>
dschinazie2116422019-10-29 11:54:26 -070078 class QUIC_NO_EXPORT DiffTypeOrVoid {
QUICHE teama6ef0a62019-03-07 20:34:33 -050079 private:
80 template <typename V>
81 static auto f(const V* v) -> decltype(*v - *v);
82 template <typename V>
83 static void f(...);
84
85 public:
86 using type = typename std::decay<decltype(f<U>(nullptr))>::type;
87 };
88
89 public:
90 // Construct an QuicInterval representing an empty QuicInterval.
91 QuicInterval() : min_(), max_() {}
92
93 // Construct an QuicInterval representing the QuicInterval [min, max). If min
94 // < max, the constructed object will represent the non-empty QuicInterval
95 // containing all values from min up to (but not including) max. On the other
96 // hand, if min >= max, the constructed object will represent the empty
97 // QuicInterval.
98 QuicInterval(const T& min, const T& max) : min_(min), max_(max) {}
99
100 template <typename U1,
101 typename U2,
102 typename = typename std::enable_if<
103 std::is_convertible<U1, T>::value &&
104 std::is_convertible<U2, T>::value>::type>
105 QuicInterval(U1&& min, U2&& max)
106 : min_(std::forward<U1>(min)), max_(std::forward<U2>(max)) {}
107
108 const T& min() const { return min_; }
109 const T& max() const { return max_; }
110 void SetMin(const T& t) { min_ = t; }
111 void SetMax(const T& t) { max_ = t; }
112
113 void Set(const T& min, const T& max) {
114 SetMin(min);
115 SetMax(max);
116 }
117
118 void Clear() { *this = {}; }
119
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().
124 typename DiffTypeOrVoid<T>::type Length() const {
125 return (Empty() ? min() : max()) - min();
126 }
127
128 // Returns true iff t >= min() && t < max().
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.
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.
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 // Calculates the smallest QuicInterval containing both *this i, and updates
156 // *this to represent that QuicInterval, and returns true iff *this was
157 // modified.
158 bool SpanningUnion(const QuicInterval& i);
159
160 // Determines the difference between two QuicIntervals by finding all points
161 // that are contained in *this but not in i, coalesces those points into the
162 // largest possible contiguous QuicIntervals, and appends those QuicIntervals
163 // to the *difference vector. Intuitively this can be thought of as "erasing"
164 // i from *this. This will either completely erase *this (leaving nothing
165 // behind), partially erase some of *this from the left or right side (leaving
166 // some residual behind), or erase a hole in the middle of *this (leaving
167 // behind an QuicInterval on either side). Therefore, 0, 1, or 2 QuicIntervals
168 // will be appended to *difference. The method returns true iff the
169 // intersection of *this and i is non-empty. The caller owns the vector and
170 // the QuicInterval* pointers inside it. The difference vector is required to
171 // be non-null.
172 bool Difference(const QuicInterval& i,
173 std::vector<QuicInterval*>* difference) const;
174
175 // Determines the difference between two QuicIntervals as in
176 // Difference(QuicInterval&, vector*), but stores the results directly in out
177 // parameters rather than dynamically allocating an QuicInterval* and
178 // appending it to a vector. If two results are generated, the one with the
179 // smaller value of min() will be stored in *lo and the other in *hi.
180 // Otherwise (if fewer than two results are generated), unused arguments will
181 // be set to the empty QuicInterval (it is possible that *lo will be empty and
182 // *hi non-empty). The method returns true iff the intersection of *this and i
183 // is non-empty.
184 bool Difference(const QuicInterval& i,
185 QuicInterval* lo,
186 QuicInterval* hi) const;
187
188 friend bool operator==(const QuicInterval& a, const QuicInterval& b) {
189 bool ae = a.Empty();
190 bool be = b.Empty();
191 if (ae && be)
192 return true; // All empties are equal.
193 if (ae != be)
194 return false; // Empty cannot equal nonempty.
195 return a.min() == b.min() && a.max() == b.max();
196 }
197
198 friend bool operator!=(const QuicInterval& a, const QuicInterval& b) {
199 return !(a == b);
200 }
201
202 // Defines a comparator which can be used to induce an order on QuicIntervals,
203 // so that, for example, they can be stored in an ordered container such as
204 // std::set. The ordering is arbitrary, but does provide the guarantee that,
205 // for non-empty QuicIntervals X and Y, if X contains Y, then X <= Y.
206 // TODO(kosak): The current implementation of this comparator has a problem
207 // because the ordering it induces is inconsistent with that of Equals(). In
208 // particular, this comparator does not properly consider all empty
209 // QuicIntervals equivalent. Bug 9240050 has been created to track this.
210 friend bool operator<(const QuicInterval& a, const QuicInterval& b) {
211 return a.min() < b.min() || (!(b.min() < a.min()) && b.max() < a.max());
212 }
213
214 private:
215 T min_; // Inclusive lower bound.
216 T max_; // Exclusive upper bound.
217};
218
219// Constructs an QuicInterval by deducing the types from the function arguments.
220template <typename T>
221QuicInterval<T> MakeQuicInterval(T&& lhs, T&& rhs) {
222 return QuicInterval<T>(std::forward<T>(lhs), std::forward<T>(rhs));
223}
224
225// Note: ideally we'd use
226// decltype(out << "[" << i.min() << ", " << i.max() << ")")
227// as return type of the function, but as of July 2017 this triggers g++
228// "sorry, unimplemented: string literal in function template signature" error.
229template <typename T>
230auto operator<<(std::ostream& out, const QuicInterval<T>& i)
231 -> decltype(out << i.min()) {
232 return out << "[" << i.min() << ", " << i.max() << ")";
233}
234
235//==============================================================================
236// Implementation details: Clients can stop reading here.
237
238template <typename T>
239bool QuicInterval<T>::Intersects(const QuicInterval& i,
240 QuicInterval* out) const {
241 if (!Intersects(i))
242 return false;
243 if (out != nullptr) {
244 *out = QuicInterval(std::max(min(), i.min()), std::min(max(), i.max()));
245 }
246 return true;
247}
248
249template <typename T>
250bool QuicInterval<T>::IntersectWith(const QuicInterval& i) {
251 if (Empty())
252 return false;
253 bool modified = false;
254 if (i.min() > min()) {
255 SetMin(i.min());
256 modified = true;
257 }
258 if (i.max() < max()) {
259 SetMax(i.max());
260 modified = true;
261 }
262 return modified;
263}
264
265template <typename T>
266bool QuicInterval<T>::SpanningUnion(const QuicInterval& i) {
267 if (i.Empty())
268 return false;
269 if (Empty()) {
270 *this = i;
271 return true;
272 }
273 bool modified = false;
274 if (i.min() < min()) {
275 SetMin(i.min());
276 modified = true;
277 }
278 if (i.max() > max()) {
279 SetMax(i.max());
280 modified = true;
281 }
282 return modified;
283}
284
285template <typename T>
286bool QuicInterval<T>::Difference(const QuicInterval& i,
287 std::vector<QuicInterval*>* difference) const {
288 if (Empty()) {
289 // <empty> - <i> = <empty>
290 return false;
291 }
292 if (i.Empty()) {
293 // <this> - <empty> = <this>
294 difference->push_back(new QuicInterval(*this));
295 return false;
296 }
297 if (min() < i.max() && min() >= i.min() && max() > i.max()) {
298 // [------ this ------)
299 // [------ i ------)
300 // [-- result ---)
301 difference->push_back(new QuicInterval(i.max(), max()));
302 return true;
303 }
304 if (max() > i.min() && max() <= i.max() && min() < i.min()) {
305 // [------ this ------)
306 // [------ i ------)
307 // [- result -)
308 difference->push_back(new QuicInterval(min(), i.min()));
309 return true;
310 }
311 if (min() < i.min() && max() > i.max()) {
312 // [------- this --------)
313 // [---- i ----)
314 // [ R1 ) [ R2 )
315 // There are two results: R1 and R2.
316 difference->push_back(new QuicInterval(min(), i.min()));
317 difference->push_back(new QuicInterval(i.max(), max()));
318 return true;
319 }
320 if (min() >= i.min() && max() <= i.max()) {
321 // [--- this ---)
322 // [------ i --------)
323 // Intersection is <this>, so difference yields the empty QuicInterval.
324 // Nothing is appended to *difference.
325 return true;
326 }
327 // No intersection. Append <this>.
328 difference->push_back(new QuicInterval(*this));
329 return false;
330}
331
332template <typename T>
333bool QuicInterval<T>::Difference(const QuicInterval& i,
334 QuicInterval* lo,
335 QuicInterval* hi) const {
336 // Initialize *lo and *hi to empty
337 *lo = {};
338 *hi = {};
339 if (Empty())
340 return false;
341 if (i.Empty()) {
342 *lo = *this;
343 return false;
344 }
345 if (min() < i.max() && min() >= i.min() && max() > i.max()) {
346 // [------ this ------)
347 // [------ i ------)
348 // [-- result ---)
349 *hi = QuicInterval(i.max(), max());
350 return true;
351 }
352 if (max() > i.min() && max() <= i.max() && min() < i.min()) {
353 // [------ this ------)
354 // [------ i ------)
355 // [- result -)
356 *lo = QuicInterval(min(), i.min());
357 return true;
358 }
359 if (min() < i.min() && max() > i.max()) {
360 // [------- this --------)
361 // [---- i ----)
362 // [ R1 ) [ R2 )
363 // There are two results: R1 and R2.
364 *lo = QuicInterval(min(), i.min());
365 *hi = QuicInterval(i.max(), max());
366 return true;
367 }
368 if (min() >= i.min() && max() <= i.max()) {
369 // [--- this ---)
370 // [------ i --------)
371 // Intersection is <this>, so difference yields the empty QuicInterval.
372 return true;
373 }
374 *lo = *this; // No intersection.
375 return false;
376}
377
378} // namespace quic
379
380#endif // QUICHE_QUIC_CORE_QUIC_INTERVAL_H_