blob: fe3b083c695dff15bf76777119bcc92b66393a43 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2018 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_QUARTC_QUARTC_INTERVAL_COUNTER_H_
6#define QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_
7
8#include <stddef.h>
9#include <vector>
10
11#include "net/third_party/quiche/src/quic/core/quic_interval.h"
12#include "net/third_party/quiche/src/quic/core/quic_interval_set.h"
13
14namespace quic {
15
16// QuartcIntervalCounter counts the number of times each value appears within
17// a set of potentially overlapping intervals.
18//
19// QuartcIntervalCounter is not intended for widespread use. Consider replacing
20// it with a full interval-map if more use cases arise.
21//
22// QuartcIntervalCounter is only suitable for cases where the maximum count is
23// expected to remain low. (For example, counting the number of times the same
24// portions of stream data are lost.) It is inefficient when the maximum count
25// becomes high.
26template <typename T>
27class QuartcIntervalCounter {
28 public:
29 // Adds |interval| to the counter. The count associated with each value in
30 // |interval| is incremented by one. |interval| may overlap with previous
31 // intervals added to the counter.
32 //
33 // For each possible value:
34 // - If the value is present in both |interval| and the counter, the count
35 // associated with that value is incremented by one.
36 // - If the value is present in |interval| but not counter, the count
37 // associated with that value is set to one (incremented from zero).
38 // - If the value is absent from |interval|, the count is unchanged.
39 //
40 // Time complexity is O(|MaxCount| * the complexity of adding an interval to a
41 // QuicIntervalSet).
42 void AddInterval(QuicInterval<T> interval);
43
44 // Removes an interval from the counter. This method may be called to prune
45 // irrelevant intervals from the counter. This is useful to prevent unbounded
46 // growth.
47 //
48 // Time complexity is O(|MaxCount| * the complexity of removing an interval
49 // from a QuicIntervalSet).
50 void RemoveInterval(QuicInterval<T> interval);
51
52 // Returns the maximum number of times any single value has appeared in
53 // intervals added to the counter.
54 //
55 // Time complexity is constant.
56 size_t MaxCount() const { return intervals_by_count_.size(); }
57
58 // Returns the maximum number of times a particular value has appeared in
59 // intervals added to the counter.
60 //
61 // Time complexity is O(|MaxCount| * log(number of non-contiguous intervals)).
62 size_t Count(const T& value) const;
63
64 private:
65 // Each entry in this vector represents the intervals of values counted at
66 // least i + 1 times, where i is the index of the entry.
67 //
68 // Whenever an interval is added to the counter, each value in the interval is
69 // added to the first entry which does not already contain that value. If
70 // part of an interval is already present in the last entry, a new entry is
71 // added containing that part.
72 //
73 // Note that this means each value present in one of the interval sets will be
74 // present in all previous sets.
75 std::vector<QuicIntervalSet<T>> intervals_by_count_;
76};
77
78template <typename T>
79void QuartcIntervalCounter<T>::AddInterval(QuicInterval<T> interval) {
80 // After the Nth iteration, |leftover| contains the parts of |interval| that
81 // are already present in the first N entries. These parts of |interval| have
82 // been added to the counter more than N times.
83 QuicIntervalSet<T> leftover(interval);
84 for (auto& intervals : intervals_by_count_) {
85 QuicIntervalSet<T> tmp = leftover;
86 leftover.Intersection(intervals);
87 intervals.Union(tmp);
88 }
89
90 // Whatever ranges are still in |leftover| are already in all the entries
91 // Add a new entry containing |leftover|.
92 if (!leftover.Empty()) {
93 intervals_by_count_.push_back(leftover);
94 }
95}
96
97template <typename T>
98void QuartcIntervalCounter<T>::RemoveInterval(QuicInterval<T> interval) {
99 // Remove the interval from each entry in the vector, popping any entries that
100 // become empty.
101 for (size_t i = intervals_by_count_.size(); i > 0; --i) {
102 intervals_by_count_[i - 1].Difference(interval);
103 if (intervals_by_count_[i - 1].Empty()) {
104 intervals_by_count_.pop_back();
105 }
106 }
107}
108
109template <typename T>
110size_t QuartcIntervalCounter<T>::Count(const T& value) const {
111 // The index of the last entry containing |value| gives its count.
112 for (size_t i = intervals_by_count_.size(); i > 0; --i) {
113 if (intervals_by_count_[i - 1].Contains(value)) {
114 return i;
115 }
116 }
117 return 0;
118}
119
120} // namespace quic
121
122#endif // QUICHE_QUIC_QUARTC_QUARTC_INTERVAL_COUNTER_H_