| // Copyright (c) 2018 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_QUARTC_QUARTC_INTERVAL_COUNTER_H_ | |
| #define QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_ | |
| #include <stddef.h> | |
| #include <vector> | |
| #include "net/third_party/quiche/src/quic/core/quic_interval.h" | |
| #include "net/third_party/quiche/src/quic/core/quic_interval_set.h" | |
| namespace quic { | |
| // QuartcIntervalCounter counts the number of times each value appears within | |
| // a set of potentially overlapping intervals. | |
| // | |
| // QuartcIntervalCounter is not intended for widespread use. Consider replacing | |
| // it with a full interval-map if more use cases arise. | |
| // | |
| // QuartcIntervalCounter is only suitable for cases where the maximum count is | |
| // expected to remain low. (For example, counting the number of times the same | |
| // portions of stream data are lost.) It is inefficient when the maximum count | |
| // becomes high. | |
| template <typename T> | |
| class QuartcIntervalCounter { | |
| public: | |
| // Adds |interval| to the counter. The count associated with each value in | |
| // |interval| is incremented by one. |interval| may overlap with previous | |
| // intervals added to the counter. | |
| // | |
| // For each possible value: | |
| // - If the value is present in both |interval| and the counter, the count | |
| // associated with that value is incremented by one. | |
| // - If the value is present in |interval| but not counter, the count | |
| // associated with that value is set to one (incremented from zero). | |
| // - If the value is absent from |interval|, the count is unchanged. | |
| // | |
| // Time complexity is O(|MaxCount| * the complexity of adding an interval to a | |
| // QuicIntervalSet). | |
| void AddInterval(QuicInterval<T> interval); | |
| // Removes an interval from the counter. This method may be called to prune | |
| // irrelevant intervals from the counter. This is useful to prevent unbounded | |
| // growth. | |
| // | |
| // Time complexity is O(|MaxCount| * the complexity of removing an interval | |
| // from a QuicIntervalSet). | |
| void RemoveInterval(QuicInterval<T> interval); | |
| // Returns the maximum number of times any single value has appeared in | |
| // intervals added to the counter. | |
| // | |
| // Time complexity is constant. | |
| size_t MaxCount() const { return intervals_by_count_.size(); } | |
| // Returns the maximum number of times a particular value has appeared in | |
| // intervals added to the counter. | |
| // | |
| // Time complexity is O(|MaxCount| * log(number of non-contiguous intervals)). | |
| size_t Count(const T& value) const; | |
| private: | |
| // Each entry in this vector represents the intervals of values counted at | |
| // least i + 1 times, where i is the index of the entry. | |
| // | |
| // Whenever an interval is added to the counter, each value in the interval is | |
| // added to the first entry which does not already contain that value. If | |
| // part of an interval is already present in the last entry, a new entry is | |
| // added containing that part. | |
| // | |
| // Note that this means each value present in one of the interval sets will be | |
| // present in all previous sets. | |
| std::vector<QuicIntervalSet<T>> intervals_by_count_; | |
| }; | |
| template <typename T> | |
| void QuartcIntervalCounter<T>::AddInterval(QuicInterval<T> interval) { | |
| // After the Nth iteration, |leftover| contains the parts of |interval| that | |
| // are already present in the first N entries. These parts of |interval| have | |
| // been added to the counter more than N times. | |
| QuicIntervalSet<T> leftover(interval); | |
| for (auto& intervals : intervals_by_count_) { | |
| QuicIntervalSet<T> tmp = leftover; | |
| leftover.Intersection(intervals); | |
| intervals.Union(tmp); | |
| } | |
| // Whatever ranges are still in |leftover| are already in all the entries | |
| // Add a new entry containing |leftover|. | |
| if (!leftover.Empty()) { | |
| intervals_by_count_.push_back(leftover); | |
| } | |
| } | |
| template <typename T> | |
| void QuartcIntervalCounter<T>::RemoveInterval(QuicInterval<T> interval) { | |
| // Remove the interval from each entry in the vector, popping any entries that | |
| // become empty. | |
| for (size_t i = intervals_by_count_.size(); i > 0; --i) { | |
| intervals_by_count_[i - 1].Difference(interval); | |
| if (intervals_by_count_[i - 1].Empty()) { | |
| intervals_by_count_.pop_back(); | |
| } | |
| } | |
| } | |
| template <typename T> | |
| size_t QuartcIntervalCounter<T>::Count(const T& value) const { | |
| // The index of the last entry containing |value| gives its count. | |
| for (size_t i = intervals_by_count_.size(); i > 0; --i) { | |
| if (intervals_by_count_[i - 1].Contains(value)) { | |
| return i; | |
| } | |
| } | |
| return 0; | |
| } | |
| } // namespace quic | |
| #endif // QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_ |