OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #ifndef WEBRTC_RTC_BASE_MOVING_MAX_COUNTER_H_ |
| 12 #define WEBRTC_RTC_BASE_MOVING_MAX_COUNTER_H_ |
| 13 |
| 14 #include <stdint.h> |
| 15 |
| 16 #include <deque> |
| 17 #include <limits> |
| 18 #include <utility> |
| 19 |
| 20 #include "webrtc/rtc_base/checks.h" |
| 21 #include "webrtc/rtc_base/constructormagic.h" |
| 22 #include "webrtc/rtc_base/optional.h" |
| 23 |
| 24 namespace rtc { |
| 25 |
| 26 // Implements moving max: can add samples to it and calculate maximum over some |
| 27 // fixed moving window. |
| 28 // |
| 29 // Window size is configured at constructor. |
| 30 // Samples can be added with |Add()| and max over current window is returned by |
| 31 // |MovingMax|. |current_time_ms| in successive calls to Add and MovingMax |
| 32 // should never decrease as if it's a wallclock time. |
| 33 // Not thread-safe even if you only call const methods. |
| 34 template <class T> |
| 35 class MovingMaxCounter { |
| 36 public: |
| 37 explicit MovingMaxCounter(int64_t window_length_ms); |
| 38 // Advances the current time, and adds a new sample. The new current time must |
| 39 // be at least as large as the old current time. |
| 40 void Add(const T& sample, int64_t current_time_ms); |
| 41 // Advances the current time, and returns the maximum sample in the time |
| 42 // window ending at the current time. The new current time must be at least as |
| 43 // large as the old current time. |
| 44 rtc::Optional<T> Max(int64_t current_time_ms) const; |
| 45 void Reset(); |
| 46 |
| 47 private: |
| 48 // Throws out obsolete samples. Is |const| because it is always safe to throw |
| 49 // out old elements as long as |current_time_ms| parameters to public methods |
| 50 // are always increasing. |
| 51 void RollWindow(int64_t new_time_ms) const; |
| 52 const int64_t window_length_ms_; |
| 53 // Samples in the window are stored as pairs <time, sample> in this deque in |
| 54 // chronological order. Samples what can't be maximum in any window are |
| 55 // thrown out - deque always contains non-increasing sequence of samples. |
| 56 // Is |mutable| because |MovingMax()| may be called on const instances yet it |
| 57 // will remove obsolete samples to speed up consecutive calls. |
| 58 mutable std::deque<std::pair<int64_t, T>> samples_; |
| 59 #if RTC_DCHECK_IS_ON |
| 60 mutable int64_t last_call_time_ms_; |
| 61 #endif |
| 62 RTC_DISALLOW_COPY_AND_ASSIGN(MovingMaxCounter); |
| 63 }; |
| 64 |
| 65 template <class T> |
| 66 MovingMaxCounter<T>::MovingMaxCounter(int64_t window_length_ms) |
| 67 : window_length_ms_(window_length_ms) |
| 68 #if RTC_DCHECK_IS_ON |
| 69 , last_call_time_ms_(std::numeric_limits<int64_t>::min()) |
| 70 #endif |
| 71 {} |
| 72 |
| 73 template <class T> |
| 74 void MovingMaxCounter<T>::Add(const T& sample, int64_t current_time_ms) { |
| 75 #if RTC_DCHECK_IS_ON |
| 76 RTC_DCHECK_GE(current_time_ms, last_call_time_ms_); |
| 77 last_call_time_ms_ = current_time_ms; |
| 78 #endif |
| 79 RollWindow(current_time_ms); |
| 80 // Remove samples what will never be maximum in any window: newly added sample |
| 81 // will always be in all windows the previous samples are. Thus, smaller |
| 82 // samples could be removed. This will maintain the invariant - deque contains |
| 83 // non-increasing sequence of values. |
| 84 while (!samples_.empty() && samples_.back().second < sample) { |
| 85 samples_.pop_back(); |
| 86 } |
| 87 // Add the new sample but only if there's no existing sample at the same time. |
| 88 // Due to checks above, already existing element will be larger and new sample |
| 89 // will never be a maximum in any window. |
| 90 if (samples_.empty() || samples_.back().first < current_time_ms) { |
| 91 samples_.emplace_back(std::make_pair(current_time_ms, sample)); |
| 92 } |
| 93 } |
| 94 |
| 95 template <class T> |
| 96 rtc::Optional<T> MovingMaxCounter<T>::Max(int64_t current_time_ms) const { |
| 97 #if RTC_DCHECK_IS_ON |
| 98 RTC_DCHECK_GE(current_time_ms, last_call_time_ms_); |
| 99 last_call_time_ms_ = current_time_ms; |
| 100 #endif |
| 101 RollWindow(current_time_ms); |
| 102 rtc::Optional<T> res; |
| 103 if (!samples_.empty()) { |
| 104 res.emplace(samples_.front().second); |
| 105 } |
| 106 return res; |
| 107 } |
| 108 |
| 109 template <class T> |
| 110 void MovingMaxCounter<T>::Reset() { |
| 111 samples_.clear(); |
| 112 } |
| 113 |
| 114 template <class T> |
| 115 void MovingMaxCounter<T>::RollWindow(int64_t new_time_ms) const { |
| 116 const int64_t window_begin_ms = new_time_ms - window_length_ms_; |
| 117 auto it = samples_.begin(); |
| 118 while (it != samples_.end() && it->first < window_begin_ms) { |
| 119 ++it; |
| 120 } |
| 121 samples_.erase(samples_.begin(), it); |
| 122 } |
| 123 |
| 124 } // namespace rtc |
| 125 |
| 126 #endif // WEBRTC_RTC_BASE_MOVING_MAX_COUNTER_H_ |
OLD | NEW |