| // Copyright (c) 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef NET_THIRD_PARTY_QUIC_CORE_QUIC_INTERVAL_H_ |
| #define NET_THIRD_PARTY_QUIC_CORE_QUIC_INTERVAL_H_ |
| |
| // An QuicInterval<T> is a data structure used to represent a contiguous, |
| // mutable range over an ordered type T. Supported operations include testing a |
| // value to see whether it is included in the QuicInterval, comparing two |
| // QuicIntervals, and performing their union, intersection, and difference. For |
| // the purposes of this library, an "ordered type" is any type that induces a |
| // total order on its values via its less-than operator (operator<()). Examples |
| // of such types are basic arithmetic types like int and double as well as class |
| // types like string. |
| // |
| // An QuicInterval<T> is represented using the usual C++ STL convention, namely |
| // as the half-open QuicInterval [min, max). A point p is considered to be |
| // contained in the QuicInterval iff p >= min && p < max. One consequence of |
| // this definition is that for any non-empty QuicInterval, min is contained in |
| // the QuicInterval but max is not. There is no canonical representation for the |
| // empty QuicInterval; rather, any QuicInterval where max <= min is regarded as |
| // empty. As a consequence, two empty QuicIntervals will still compare as equal |
| // despite possibly having different underlying min() or max() values. Also |
| // beware of the terminology used here: the library uses the terms "min" and |
| // "max" rather than "begin" and "end" as is conventional for the STL. |
| // |
| // T is required to be default- and copy-constructable, to have an assignment |
| // operator, and the full complement of comparison operators (<, <=, ==, !=, >=, |
| // >). A difference operator (operator-()) is required if |
| // QuicInterval<T>::Length is used. |
| // |
| // QuicInterval supports operator==. Two QuicIntervals are considered equal if |
| // either they are both empty or if their corresponding min and max fields |
| // compare equal. QuicInterval also provides an operator<. Unfortunately, |
| // operator< is currently buggy because its behavior is inconsistent with |
| // operator==: two empty ranges with different representations may be regarded |
| // as equal by operator== but regarded as different by operator<. Bug 9240050 |
| // has been created to address this. |
| // |
| // |
| // Examples: |
| // QuicInterval<int> r1(0, 100); // The QuicInterval [0, 100). |
| // EXPECT_TRUE(r1.Contains(0)); |
| // EXPECT_TRUE(r1.Contains(50)); |
| // EXPECT_FALSE(r1.Contains(100)); // 100 is just outside the QuicInterval. |
| // |
| // QuicInterval<int> r2(50, 150); // The QuicInterval [50, 150). |
| // EXPECT_TRUE(r1.Intersects(r2)); |
| // EXPECT_FALSE(r1.Contains(r2)); |
| // EXPECT_TRUE(r1.IntersectWith(r2)); // Mutates r1. |
| // EXPECT_EQ(QuicInterval<int>(50, 100), r1); // r1 is now [50, 100). |
| // |
| // QuicInterval<int> r3(1000, 2000); // The QuicInterval [1000, 2000). |
| // EXPECT_TRUE(r1.IntersectWith(r3)); // Mutates r1. |
| // EXPECT_TRUE(r1.Empty()); // Now r1 is empty. |
| // EXPECT_FALSE(r1.Contains(r1.min())); // e.g. doesn't contain its own min. |
| |
| #include <algorithm> |
| #include <ostream> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include "starboard/types.h" |
| |
| namespace quic { |
| |
| template <typename T> |
| class QuicInterval { |
| private: |
| // Type trait for deriving the return type for QuicInterval::Length. If |
| // operator-() is not defined for T, then the return type is void. This makes |
| // the signature for Length compile so that the class can be used for such T, |
| // but code that calls Length would still generate a compilation error. |
| template <typename U> |
| class DiffTypeOrVoid { |
| private: |
| template <typename V> |
| static auto f(const V* v) -> decltype(*v - *v); |
| template <typename V> |
| static void f(...); |
| |
| public: |
| using type = typename std::decay<decltype(f<U>(nullptr))>::type; |
| }; |
| |
| public: |
| // Construct an QuicInterval representing an empty QuicInterval. |
| QuicInterval() : min_(), max_() {} |
| |
| // Construct an QuicInterval representing the QuicInterval [min, max). If min |
| // < max, the constructed object will represent the non-empty QuicInterval |
| // containing all values from min up to (but not including) max. On the other |
| // hand, if min >= max, the constructed object will represent the empty |
| // QuicInterval. |
| QuicInterval(const T& min, const T& max) : min_(min), max_(max) {} |
| |
| template <typename U1, |
| typename U2, |
| typename = typename std::enable_if< |
| std::is_convertible<U1, T>::value && |
| std::is_convertible<U2, T>::value>::type> |
| QuicInterval(U1&& min, U2&& max) |
| : min_(std::forward<U1>(min)), max_(std::forward<U2>(max)) {} |
| |
| const T& min() const { return min_; } |
| const T& max() const { return max_; } |
| void SetMin(const T& t) { min_ = t; } |
| void SetMax(const T& t) { max_ = t; } |
| |
| void Set(const T& min, const T& max) { |
| SetMin(min); |
| SetMax(max); |
| } |
| |
| void Clear() { *this = {}; } |
| |
| bool Empty() const { return min() >= max(); } |
| |
| // Returns the length of this QuicInterval. The value returned is zero if |
| // Empty() is true; otherwise the value returned is max() - min(). |
| typename DiffTypeOrVoid<T>::type Length() const { |
| return (Empty() ? min() : max()) - min(); |
| } |
| |
| // Returns true iff t >= min() && t < max(). |
| bool Contains(const T& t) const { return min() <= t && max() > t; } |
| |
| // Returns true iff *this and i are non-empty, and *this includes i. "*this |
| // includes i" means that for all t, if i.Contains(t) then this->Contains(t). |
| // Note the unintuitive consequence of this definition: this method always |
| // returns false when i is the empty QuicInterval. |
| bool Contains(const QuicInterval& i) const { |
| return !Empty() && !i.Empty() && min() <= i.min() && max() >= i.max(); |
| } |
| |
| // Returns true iff there exists some point t for which this->Contains(t) && |
| // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty. |
| bool Intersects(const QuicInterval& i) const { |
| return !Empty() && !i.Empty() && min() < i.max() && max() > i.min(); |
| } |
| |
| // Returns true iff there exists some point t for which this->Contains(t) && |
| // i.Contains(t) evaluates to true, i.e. if the intersection is non-empty. |
| // Furthermore, if the intersection is non-empty and the out pointer is not |
| // null, this method stores the calculated intersection in *out. |
| bool Intersects(const QuicInterval& i, QuicInterval* out) const; |
| |
| // Sets *this to be the intersection of itself with i. Returns true iff |
| // *this was modified. |
| bool IntersectWith(const QuicInterval& i); |
| |
| // Calculates the smallest QuicInterval containing both *this i, and updates |
| // *this to represent that QuicInterval, and returns true iff *this was |
| // modified. |
| bool SpanningUnion(const QuicInterval& i); |
| |
| // Determines the difference between two QuicIntervals by finding all points |
| // that are contained in *this but not in i, coalesces those points into the |
| // largest possible contiguous QuicIntervals, and appends those QuicIntervals |
| // to the *difference vector. Intuitively this can be thought of as "erasing" |
| // i from *this. This will either completely erase *this (leaving nothing |
| // behind), partially erase some of *this from the left or right side (leaving |
| // some residual behind), or erase a hole in the middle of *this (leaving |
| // behind an QuicInterval on either side). Therefore, 0, 1, or 2 QuicIntervals |
| // will be appended to *difference. The method returns true iff the |
| // intersection of *this and i is non-empty. The caller owns the vector and |
| // the QuicInterval* pointers inside it. The difference vector is required to |
| // be non-null. |
| bool Difference(const QuicInterval& i, |
| std::vector<QuicInterval*>* difference) const; |
| |
| // Determines the difference between two QuicIntervals as in |
| // Difference(QuicInterval&, vector*), but stores the results directly in out |
| // parameters rather than dynamically allocating an QuicInterval* and |
| // appending it to a vector. If two results are generated, the one with the |
| // smaller value of min() will be stored in *lo and the other in *hi. |
| // Otherwise (if fewer than two results are generated), unused arguments will |
| // be set to the empty QuicInterval (it is possible that *lo will be empty and |
| // *hi non-empty). The method returns true iff the intersection of *this and i |
| // is non-empty. |
| bool Difference(const QuicInterval& i, |
| QuicInterval* lo, |
| QuicInterval* hi) const; |
| |
| friend bool operator==(const QuicInterval& a, const QuicInterval& b) { |
| bool ae = a.Empty(); |
| bool be = b.Empty(); |
| if (ae && be) |
| return true; // All empties are equal. |
| if (ae != be) |
| return false; // Empty cannot equal nonempty. |
| return a.min() == b.min() && a.max() == b.max(); |
| } |
| |
| friend bool operator!=(const QuicInterval& a, const QuicInterval& b) { |
| return !(a == b); |
| } |
| |
| // Defines a comparator which can be used to induce an order on QuicIntervals, |
| // so that, for example, they can be stored in an ordered container such as |
| // std::set. The ordering is arbitrary, but does provide the guarantee that, |
| // for non-empty QuicIntervals X and Y, if X contains Y, then X <= Y. |
| // TODO(kosak): The current implementation of this comparator has a problem |
| // because the ordering it induces is inconsistent with that of Equals(). In |
| // particular, this comparator does not properly consider all empty |
| // QuicIntervals equivalent. Bug 9240050 has been created to track this. |
| friend bool operator<(const QuicInterval& a, const QuicInterval& b) { |
| return a.min() < b.min() || (!(b.min() < a.min()) && b.max() < a.max()); |
| } |
| |
| private: |
| T min_; // Inclusive lower bound. |
| T max_; // Exclusive upper bound. |
| }; |
| |
| // Constructs an QuicInterval by deducing the types from the function arguments. |
| template <typename T> |
| QuicInterval<T> MakeQuicInterval(T&& lhs, T&& rhs) { |
| return QuicInterval<T>(std::forward<T>(lhs), std::forward<T>(rhs)); |
| } |
| |
| // Note: ideally we'd use |
| // decltype(out << "[" << i.min() << ", " << i.max() << ")") |
| // as return type of the function, but as of July 2017 this triggers g++ |
| // "sorry, unimplemented: string literal in function template signature" error. |
| template <typename T> |
| auto operator<<(std::ostream& out, const QuicInterval<T>& i) |
| -> decltype(out << i.min()) { |
| return out << "[" << i.min() << ", " << i.max() << ")"; |
| } |
| |
| //============================================================================== |
| // Implementation details: Clients can stop reading here. |
| |
| template <typename T> |
| bool QuicInterval<T>::Intersects(const QuicInterval& i, |
| QuicInterval* out) const { |
| if (!Intersects(i)) |
| return false; |
| if (out != nullptr) { |
| *out = QuicInterval(std::max(min(), i.min()), std::min(max(), i.max())); |
| } |
| return true; |
| } |
| |
| template <typename T> |
| bool QuicInterval<T>::IntersectWith(const QuicInterval& i) { |
| if (Empty()) |
| return false; |
| bool modified = false; |
| if (i.min() > min()) { |
| SetMin(i.min()); |
| modified = true; |
| } |
| if (i.max() < max()) { |
| SetMax(i.max()); |
| modified = true; |
| } |
| return modified; |
| } |
| |
| template <typename T> |
| bool QuicInterval<T>::SpanningUnion(const QuicInterval& i) { |
| if (i.Empty()) |
| return false; |
| if (Empty()) { |
| *this = i; |
| return true; |
| } |
| bool modified = false; |
| if (i.min() < min()) { |
| SetMin(i.min()); |
| modified = true; |
| } |
| if (i.max() > max()) { |
| SetMax(i.max()); |
| modified = true; |
| } |
| return modified; |
| } |
| |
| template <typename T> |
| bool QuicInterval<T>::Difference(const QuicInterval& i, |
| std::vector<QuicInterval*>* difference) const { |
| if (Empty()) { |
| // <empty> - <i> = <empty> |
| return false; |
| } |
| if (i.Empty()) { |
| // <this> - <empty> = <this> |
| difference->push_back(new QuicInterval(*this)); |
| return false; |
| } |
| if (min() < i.max() && min() >= i.min() && max() > i.max()) { |
| // [------ this ------) |
| // [------ i ------) |
| // [-- result ---) |
| difference->push_back(new QuicInterval(i.max(), max())); |
| return true; |
| } |
| if (max() > i.min() && max() <= i.max() && min() < i.min()) { |
| // [------ this ------) |
| // [------ i ------) |
| // [- result -) |
| difference->push_back(new QuicInterval(min(), i.min())); |
| return true; |
| } |
| if (min() < i.min() && max() > i.max()) { |
| // [------- this --------) |
| // [---- i ----) |
| // [ R1 ) [ R2 ) |
| // There are two results: R1 and R2. |
| difference->push_back(new QuicInterval(min(), i.min())); |
| difference->push_back(new QuicInterval(i.max(), max())); |
| return true; |
| } |
| if (min() >= i.min() && max() <= i.max()) { |
| // [--- this ---) |
| // [------ i --------) |
| // Intersection is <this>, so difference yields the empty QuicInterval. |
| // Nothing is appended to *difference. |
| return true; |
| } |
| // No intersection. Append <this>. |
| difference->push_back(new QuicInterval(*this)); |
| return false; |
| } |
| |
| template <typename T> |
| bool QuicInterval<T>::Difference(const QuicInterval& i, |
| QuicInterval* lo, |
| QuicInterval* hi) const { |
| // Initialize *lo and *hi to empty |
| *lo = {}; |
| *hi = {}; |
| if (Empty()) |
| return false; |
| if (i.Empty()) { |
| *lo = *this; |
| return false; |
| } |
| if (min() < i.max() && min() >= i.min() && max() > i.max()) { |
| // [------ this ------) |
| // [------ i ------) |
| // [-- result ---) |
| *hi = QuicInterval(i.max(), max()); |
| return true; |
| } |
| if (max() > i.min() && max() <= i.max() && min() < i.min()) { |
| // [------ this ------) |
| // [------ i ------) |
| // [- result -) |
| *lo = QuicInterval(min(), i.min()); |
| return true; |
| } |
| if (min() < i.min() && max() > i.max()) { |
| // [------- this --------) |
| // [---- i ----) |
| // [ R1 ) [ R2 ) |
| // There are two results: R1 and R2. |
| *lo = QuicInterval(min(), i.min()); |
| *hi = QuicInterval(i.max(), max()); |
| return true; |
| } |
| if (min() >= i.min() && max() <= i.max()) { |
| // [--- this ---) |
| // [------ i --------) |
| // Intersection is <this>, so difference yields the empty QuicInterval. |
| return true; |
| } |
| *lo = *this; // No intersection. |
| return false; |
| } |
| |
| } // namespace quic |
| |
| #endif // NET_THIRD_PARTY_QUIC_CORE_QUIC_INTERVAL_H_ |