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