|  | // 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 QUICHE_QUIC_CORE_QUIC_SEEKER_H_ | 
|  | #define QUICHE_QUIC_CORE_QUIC_SEEKER_H_ | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/core/quic_circular_deque.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_interval.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_types.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_export.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" | 
|  | #include "net/third_party/quiche/src/common/platform/api/quiche_optional.h" | 
|  |  | 
|  | namespace quic { | 
|  |  | 
|  | namespace test { | 
|  | class QuicIntervalDequePeer; | 
|  | }  // namespace test | 
|  |  | 
|  | // QuicIntervalDeque<T, C> is a templated wrapper container, wrapping random | 
|  | // access data structures. The wrapper allows items to be added to the | 
|  | // underlying container with intervals associated with each item. The intervals | 
|  | // _should_ be added already sorted and represent searchable indices. The search | 
|  | // is optimized for sequential usage. | 
|  | // | 
|  | // As the intervals are to be searched sequentially the search for the next | 
|  | // interval can be achieved in O(1), by simply remembering the last interval | 
|  | // consumed. The structure also checks for an "off-by-one" use case wherein the | 
|  | // |cached_index_| is off by one index as the caller didn't call operator |++| | 
|  | // to increment the index. Other intervals can be found in O(log(n)) as they are | 
|  | // binary searchable. A use case for this structure is packet buffering: Packets | 
|  | // are sent sequentially but can sometimes needed for retransmission. The | 
|  | // packets and their payloads are added with associated intervals representing | 
|  | // data ranges they carry. When a user asks for a particular interval it's very | 
|  | // likely they are requesting the next sequential interval, receiving it in O(1) | 
|  | // time. Updating the sequential index is done automatically through the | 
|  | // |DataAt| method and its iterator operator |++|. | 
|  | // | 
|  | // The intervals are 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; and empty intervals are forbidden from being added to | 
|  | // this container as they would be unsearchable. | 
|  | // | 
|  | // The type T is required to be copy-constructable or move-constructable. The | 
|  | // type T is also expected to have an |interval()| method returning a | 
|  | // QuicInterval<std::size> for the particular value. The type C is required to | 
|  | // be a random access container supporting the methods |pop_front|, |push_back|, | 
|  | // |operator[]|, |size|, and iterator support for |std::lower_bound| eg. a | 
|  | // |deque| or |vector|. | 
|  | // | 
|  | // The QuicIntervalDeque<T, C>, like other C++ STL random access containers, | 
|  | // doesn't have any explicit support for any equality operators. | 
|  | // | 
|  | // | 
|  | // Examples with internal state: | 
|  | // | 
|  | //   // An example class to be stored inside the Interval Deque. | 
|  | //   struct IntervalVal { | 
|  | //     const int32_t val; | 
|  | //     const size_t interval_begin, interval_end; | 
|  | //     QuicInterval<size_t> interval(); | 
|  | //   }; | 
|  | //   typedef IntervalVal IV; | 
|  | //   QuicIntervialDeque<IntervalValue> deque; | 
|  | // | 
|  | //   // State: | 
|  | //   //   cached_index -> None | 
|  | //   //   container -> {} | 
|  | // | 
|  | //   // Add interval items | 
|  | //   deque.PushBack(IV(val: 0, interval_begin: 0, interval_end: 10)); | 
|  | //   deque.PushBack(IV(val: 1, interval_begin: 20, interval_end: 25)); | 
|  | //   deque.PushBack(IV(val: 2, interval_begin: 25, interval_end: 30)); | 
|  | // | 
|  | //   // State: | 
|  | //   //   cached_index -> 0 | 
|  | //   //   container -> {{0, [0, 10)}, {1, [20, 25)}, {2, [25, 30)}} | 
|  | // | 
|  | //   // Look for 0 and return [0, 10). Time: O(1) | 
|  | //   auto it = deque.DataAt(0); | 
|  | //   assert(it->val == 0); | 
|  | //   it++;  // Increment and move the |cached_index_| over [0, 10) to [20, 25). | 
|  | //   assert(it->val == 1); | 
|  | // | 
|  | //   // State: | 
|  | //   //   cached_index -> 1 | 
|  | //   //   container -> {{0, [0, 10)}, {1, [20, 25)}, {2, [25, 30)}} | 
|  | // | 
|  | //   // Look for 20 and return [20, 25). Time: O(1) | 
|  | //   auto it = deque.DataAt(20); // |cached_index_| remains unchanged. | 
|  | //   assert(it->val == 1); | 
|  | // | 
|  | //   // State: | 
|  | //   //   cached_index -> 1 | 
|  | //   //   container -> {{0, [0, 10)}, {1, [20, 25)}, {2, [25, 30)}} | 
|  | // | 
|  | //   // Look for 15 and return deque.DataEnd(). Time: O(log(n)) | 
|  | //   auto it = deque.DataAt(15); // |cached_index_| remains unchanged. | 
|  | //   assert(it == deque.DataEnd()); | 
|  | // | 
|  | //   // Look for 25 and return [25, 30). Time: O(1) with off-by-one. | 
|  | //   auto it = deque.DataAt(25); // |cached_index_| is updated to 2. | 
|  | //   assert(it->val == 2); | 
|  | //   it++; // |cached_index_| is set to |None| as all data has been iterated. | 
|  | // | 
|  | // | 
|  | //   // State: | 
|  | //   //   cached_index -> None | 
|  | //   //   container -> {{0, [0, 10)}, {1, [20, 25)}, {2, [25, 30)}} | 
|  | // | 
|  | //   // Look again for 0 and return [0, 10). Time: O(log(n)) | 
|  | //   auto it = deque.DataAt(0); | 
|  | // | 
|  | // | 
|  | //   deque.PopFront();  // Pop -> {0, [0, 10)} | 
|  | // | 
|  | //   // State: | 
|  | //   //   cached_index -> None | 
|  | //   //   container -> {{1, [20, 25)}, {2, [25, 30)}} | 
|  | // | 
|  | //   deque.PopFront();  // Pop -> {1, [20, 25)} | 
|  | // | 
|  | //   // State: | 
|  | //   //   cached_index -> None | 
|  | //   //   container -> {{2, [25, 30)}} | 
|  | // | 
|  | //   deque.PushBack(IV(val: 3, interval_begin: 35, interval_end: 50)); | 
|  | // | 
|  | //   // State: | 
|  | //   //   cached_index -> 1 | 
|  | //   //   container -> {{2, [25, 30)}, {3, [35, 50)}} | 
|  |  | 
|  | template <class T, class C = QUIC_NO_EXPORT QuicCircularDeque<T>> | 
|  | class QUIC_NO_EXPORT QuicIntervalDeque { | 
|  | public: | 
|  | class QUIC_NO_EXPORT Iterator { | 
|  | public: | 
|  | // Used by |std::lower_bound| | 
|  | using iterator_category = std::forward_iterator_tag; | 
|  | using value_type = T; | 
|  | using difference_type = std::ptrdiff_t; | 
|  | using pointer = T*; | 
|  | using reference = T&; | 
|  |  | 
|  | // Every increment of the iterator will increment the |cached_index_| if | 
|  | // |index_| is larger than the current |cached_index_|. |index_| is bounded | 
|  | // at |deque_.size()| and any attempt to increment above that will be | 
|  | // ignored. Once an iterator has iterated all elements the |cached_index_| | 
|  | // will be reset. | 
|  | Iterator(std::size_t index, QuicIntervalDeque* deque) | 
|  | : index_(index), deque_(deque) {} | 
|  | // Only the ++ operator attempts to update the cached index. Other operators | 
|  | // are used by |lower_bound| to binary search and are thus private. | 
|  | Iterator& operator++() { | 
|  | // Don't increment when we are at the end. | 
|  | const std::size_t container_size = deque_->container_.size(); | 
|  | if (index_ >= container_size) { | 
|  | QUIC_BUG << "Iterator out of bounds."; | 
|  | return *this; | 
|  | } | 
|  | index_++; | 
|  | if (deque_->cached_index_.has_value()) { | 
|  | const std::size_t cached_index = deque_->cached_index_.value(); | 
|  | // If all items are iterated then reset the |cached_index_| | 
|  | if (index_ == container_size) { | 
|  | deque_->cached_index_.reset(); | 
|  | } else { | 
|  | // Otherwise the new |cached_index_| is the max of itself and |index_| | 
|  | if (cached_index < index_) { | 
|  | deque_->cached_index_ = index_; | 
|  | } | 
|  | } | 
|  | } | 
|  | return *this; | 
|  | } | 
|  | Iterator operator++(int) { | 
|  | Iterator copy = *this; | 
|  | ++(*this); | 
|  | return copy; | 
|  | } | 
|  | reference operator*() { return deque_->container_[index_]; } | 
|  | pointer operator->() { return &deque_->container_[index_]; } | 
|  | bool operator==(const Iterator& rhs) const { | 
|  | return index_ == rhs.index_ && deque_ == rhs.deque_; | 
|  | } | 
|  | bool operator!=(const Iterator& rhs) const { return !(*this == rhs); } | 
|  |  | 
|  | private: | 
|  | // A set of private operators for |std::lower_bound| | 
|  | Iterator operator+(difference_type amount) const { | 
|  | Iterator copy = *this; | 
|  | copy.index_ += amount; | 
|  | DCHECK(copy.index_ < copy.deque_->size()); | 
|  | return copy; | 
|  | } | 
|  | Iterator& operator+=(difference_type amount) { | 
|  | index_ += amount; | 
|  | DCHECK(index_ < deque_->size()); | 
|  | return *this; | 
|  | } | 
|  | difference_type operator-(const Iterator& rhs) const { | 
|  | return static_cast<difference_type>(index_) - | 
|  | static_cast<difference_type>(rhs.index_); | 
|  | } | 
|  |  | 
|  | // |index_| is the index of the item in |*deque_|. | 
|  | std::size_t index_; | 
|  | // |deque_| is a pointer to the container the iterator came from. | 
|  | QuicIntervalDeque* deque_; | 
|  |  | 
|  | friend class QuicIntervalDeque; | 
|  | }; | 
|  |  | 
|  | QuicIntervalDeque(); | 
|  |  | 
|  | // Adds an item to the underlying container. The |item|'s interval _should_ be | 
|  | // strictly greater than the last interval added. | 
|  | void PushBack(T&& item); | 
|  | void PushBack(const T& item); | 
|  | // Removes the front/top of the underlying container and the associated | 
|  | // interval. | 
|  | void PopFront(); | 
|  | // Returns an iterator to the beginning of the data. The iterator will move | 
|  | // the |cached_index_| as the iterator moves. | 
|  | Iterator DataBegin(); | 
|  | // Returns an iterator to the end of the data. | 
|  | Iterator DataEnd(); | 
|  | // Returns an iterator pointing to the item in |interval_begin|. The iterator | 
|  | // will move the |cached_index_| as the iterator moves. | 
|  | Iterator DataAt(const std::size_t interval_begin); | 
|  |  | 
|  | // Returns the number of items contained inside the structure. | 
|  | std::size_t Size() const; | 
|  | // Returns whether the structure is empty. | 
|  | bool Empty() const; | 
|  |  | 
|  | private: | 
|  | struct QUIC_NO_EXPORT IntervalCompare { | 
|  | bool operator()(const T& item, std::size_t interval_begin) const { | 
|  | return item.interval().max() <= interval_begin; | 
|  | } | 
|  | }; | 
|  |  | 
|  | template <class U> | 
|  | void PushBackUniversal(U&& item); | 
|  |  | 
|  | Iterator Search(const std::size_t interval_begin, | 
|  | const std::size_t begin_index, | 
|  | const std::size_t end_index); | 
|  |  | 
|  | // For accessing the |cached_index_| | 
|  | friend class test::QuicIntervalDequePeer; | 
|  |  | 
|  | C container_; | 
|  | quiche::QuicheOptional<std::size_t> cached_index_; | 
|  | }; | 
|  |  | 
|  | template <class T, class C> | 
|  | QuicIntervalDeque<T, C>::QuicIntervalDeque() {} | 
|  |  | 
|  | template <class T, class C> | 
|  | void QuicIntervalDeque<T, C>::PushBack(T&& item) { | 
|  | PushBackUniversal(std::move(item)); | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | void QuicIntervalDeque<T, C>::PushBack(const T& item) { | 
|  | PushBackUniversal(item); | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | void QuicIntervalDeque<T, C>::PopFront() { | 
|  | if (container_.size() == 0) { | 
|  | QUIC_BUG << "Trying to pop from an empty container."; | 
|  | return; | 
|  | } | 
|  | container_.pop_front(); | 
|  | if (container_.size() == 0) { | 
|  | cached_index_.reset(); | 
|  | } | 
|  | if (cached_index_.value_or(0) > 0) { | 
|  | cached_index_ = cached_index_.value() - 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | typename QuicIntervalDeque<T, C>::Iterator | 
|  | QuicIntervalDeque<T, C>::DataBegin() { | 
|  | return Iterator(0, this); | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | typename QuicIntervalDeque<T, C>::Iterator QuicIntervalDeque<T, C>::DataEnd() { | 
|  | return Iterator(container_.size(), this); | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | typename QuicIntervalDeque<T, C>::Iterator QuicIntervalDeque<T, C>::DataAt( | 
|  | const std::size_t interval_begin) { | 
|  | // No |cached_index_| value means all items can be searched. | 
|  | if (!cached_index_.has_value()) { | 
|  | return Search(interval_begin, 0, container_.size()); | 
|  | } | 
|  |  | 
|  | const std::size_t cached_index = cached_index_.value(); | 
|  | DCHECK(cached_index < container_.size()); | 
|  |  | 
|  | const QuicInterval<size_t> cached_interval = | 
|  | container_[cached_index].interval(); | 
|  | // Does our cached index point directly to what we want? | 
|  | if (cached_interval.Contains(interval_begin)) { | 
|  | return Iterator(cached_index, this); | 
|  | } | 
|  |  | 
|  | // Are we off-by-one? | 
|  | const std::size_t next_index = cached_index + 1; | 
|  | if (next_index < container_.size()) { | 
|  | if (container_[next_index].interval().Contains(interval_begin)) { | 
|  | cached_index_ = next_index; | 
|  | return Iterator(next_index, this); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Small optimization: | 
|  | // Determine if we should binary search above or below the cached interval. | 
|  | const std::size_t cached_begin = cached_interval.min(); | 
|  | bool looking_below = interval_begin < cached_begin; | 
|  | const std::size_t lower = looking_below ? 0 : cached_index + 1; | 
|  | const std::size_t upper = looking_below ? cached_index : container_.size(); | 
|  | Iterator ret = Search(interval_begin, lower, upper); | 
|  | if (ret == DataEnd()) { | 
|  | return ret; | 
|  | } | 
|  | // Update the |cached_index_| to point to the higher index. | 
|  | if (!looking_below) { | 
|  | cached_index_ = ret.index_; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | std::size_t QuicIntervalDeque<T, C>::Size() const { | 
|  | return container_.size(); | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | bool QuicIntervalDeque<T, C>::Empty() const { | 
|  | return container_.size() == 0; | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | template <class U> | 
|  | void QuicIntervalDeque<T, C>::PushBackUniversal(U&& item) { | 
|  | QuicInterval<std::size_t> interval = item.interval(); | 
|  | // Adding an empty interval is a bug. | 
|  | if (interval.Empty()) { | 
|  | QUIC_BUG << "Trying to save empty interval to QuicCircularDeque."; | 
|  | return; | 
|  | } | 
|  | container_.push_back(std::forward<U>(item)); | 
|  | if (!cached_index_.has_value()) { | 
|  | cached_index_ = container_.size() - 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | template <class T, class C> | 
|  | typename QuicIntervalDeque<T, C>::Iterator QuicIntervalDeque<T, C>::Search( | 
|  | const std::size_t interval_begin, | 
|  | const std::size_t begin_index, | 
|  | const std::size_t end_index) { | 
|  | auto begin = container_.begin() + begin_index; | 
|  | auto end = container_.begin() + end_index; | 
|  | auto res = std::lower_bound(begin, end, interval_begin, IntervalCompare()); | 
|  | // Just because we run |lower_bound| and it didn't return |container_.end()| | 
|  | // doesn't mean we found our desired interval. | 
|  | if (res != end && res->interval().Contains(interval_begin)) { | 
|  | return Iterator(std::distance(begin, res) + begin_index, this); | 
|  | } | 
|  | return DataEnd(); | 
|  | } | 
|  |  | 
|  | }  // namespace quic | 
|  |  | 
|  | #endif  // QUICHE_QUIC_CORE_QUIC_SEEKER_H_ |