diff options
author | Anton Samokhvalov <pg83@yandex.ru> | 2022-02-10 16:45:17 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:17 +0300 |
commit | d3a398281c6fd1d3672036cb2d63f842d2cb28c5 (patch) | |
tree | dd4bd3ca0f36b817e96812825ffaf10d645803f2 /library/cpp/sliding_window | |
parent | 72cb13b4aff9bc9cf22e49251bc8fd143f82538f (diff) | |
download | ydb-d3a398281c6fd1d3672036cb2d63f842d2cb28c5.tar.gz |
Restoring authorship annotation for Anton Samokhvalov <pg83@yandex.ru>. Commit 2 of 2.
Diffstat (limited to 'library/cpp/sliding_window')
-rw-r--r-- | library/cpp/sliding_window/sliding_window.h | 390 | ||||
-rw-r--r-- | library/cpp/sliding_window/sliding_window_ut.cpp | 126 |
2 files changed, 258 insertions, 258 deletions
diff --git a/library/cpp/sliding_window/sliding_window.h b/library/cpp/sliding_window/sliding_window.h index 2613fd46ea..180bdf93d0 100644 --- a/library/cpp/sliding_window/sliding_window.h +++ b/library/cpp/sliding_window/sliding_window.h @@ -11,214 +11,214 @@ #include <limits> namespace NSlidingWindow { - namespace NPrivate { - template <class TValueType_, class TCmp, TValueType_ initialValue> // std::less for max, std::greater for min - struct TMinMaxOperationImpl { - using TValueType = TValueType_; - using TValueVector = TVector<TValueType>; - - static constexpr TValueType InitialValue() { - return initialValue; - } - - // Updates value in current bucket and returns window value - static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) { - Y_ASSERT(index < buckets.size()); - TCmp cmp; - TValueType& curVal = buckets[index]; - if (cmp(curVal, newVal)) { - curVal = newVal; - if (cmp(windowValue, newVal)) { - windowValue = newVal; - } - } - return windowValue; + namespace NPrivate { + template <class TValueType_, class TCmp, TValueType_ initialValue> // std::less for max, std::greater for min + struct TMinMaxOperationImpl { + using TValueType = TValueType_; + using TValueVector = TVector<TValueType>; + + static constexpr TValueType InitialValue() { + return initialValue; } - static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, const size_t firstElemIndex, const size_t bucketsToClear) { - Y_ASSERT(!buckets.empty()); - Y_ASSERT(firstElemIndex < buckets.size()); - Y_ASSERT(bucketsToClear <= buckets.size()); - TCmp cmp; - - bool needRecalc = false; - size_t current = firstElemIndex; - const size_t arraySize = buckets.size(); - for (size_t i = 0; i < bucketsToClear; ++i) { - TValueType& curVal = buckets[current]; - if (!needRecalc && windowValue == curVal) { - needRecalc = true; - } - curVal = InitialValue(); - current = (current + 1) % arraySize; + // Updates value in current bucket and returns window value + static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) { + Y_ASSERT(index < buckets.size()); + TCmp cmp; + TValueType& curVal = buckets[index]; + if (cmp(curVal, newVal)) { + curVal = newVal; + if (cmp(windowValue, newVal)) { + windowValue = newVal; + } } - if (needRecalc) { - windowValue = InitialValue(); - for (size_t i = 0; i < firstElemIndex; ++i) { - const TValueType val = buckets[i]; - if (cmp(windowValue, val)) { - windowValue = val; - } - } - for (size_t i = current, size = buckets.size(); i < size; ++i) { - const TValueType val = buckets[i]; - if (cmp(windowValue, val)) { - windowValue = val; - } - } + return windowValue; + } + + static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, const size_t firstElemIndex, const size_t bucketsToClear) { + Y_ASSERT(!buckets.empty()); + Y_ASSERT(firstElemIndex < buckets.size()); + Y_ASSERT(bucketsToClear <= buckets.size()); + TCmp cmp; + + bool needRecalc = false; + size_t current = firstElemIndex; + const size_t arraySize = buckets.size(); + for (size_t i = 0; i < bucketsToClear; ++i) { + TValueType& curVal = buckets[current]; + if (!needRecalc && windowValue == curVal) { + needRecalc = true; + } + curVal = InitialValue(); + current = (current + 1) % arraySize; + } + if (needRecalc) { + windowValue = InitialValue(); + for (size_t i = 0; i < firstElemIndex; ++i) { + const TValueType val = buckets[i]; + if (cmp(windowValue, val)) { + windowValue = val; + } + } + for (size_t i = current, size = buckets.size(); i < size; ++i) { + const TValueType val = buckets[i]; + if (cmp(windowValue, val)) { + windowValue = val; + } + } } - return windowValue; + return windowValue; } - }; - + }; + } - template <class TValueType> - using TMaxOperation = NPrivate::TMinMaxOperationImpl<TValueType, std::less<TValueType>, std::numeric_limits<TValueType>::min()>; - - template <class TValueType> - using TMinOperation = NPrivate::TMinMaxOperationImpl<TValueType, std::greater<TValueType>, std::numeric_limits<TValueType>::max()>; - - template <class TValueType_> - struct TSumOperation { - using TValueType = TValueType_; - using TValueVector = TVector<TValueType>; - - static constexpr TValueType InitialValue() { - return TValueType(); // zero - } - - // Updates value in current bucket and returns window value - static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) { - Y_ASSERT(index < buckets.size()); - buckets[index] += newVal; - windowValue += newVal; - return windowValue; - } - - static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, size_t firstElemIndex, size_t bucketsToClear) { - Y_ASSERT(!buckets.empty()); - Y_ASSERT(firstElemIndex < buckets.size()); - Y_ASSERT(bucketsToClear <= buckets.size()); - - const size_t arraySize = buckets.size(); - for (size_t i = 0; i < bucketsToClear; ++i) { - TValueType& curVal = buckets[firstElemIndex]; - windowValue -= curVal; - curVal = InitialValue(); - firstElemIndex = (firstElemIndex + 1) % arraySize; - } - return windowValue; + template <class TValueType> + using TMaxOperation = NPrivate::TMinMaxOperationImpl<TValueType, std::less<TValueType>, std::numeric_limits<TValueType>::min()>; + + template <class TValueType> + using TMinOperation = NPrivate::TMinMaxOperationImpl<TValueType, std::greater<TValueType>, std::numeric_limits<TValueType>::max()>; + + template <class TValueType_> + struct TSumOperation { + using TValueType = TValueType_; + using TValueVector = TVector<TValueType>; + + static constexpr TValueType InitialValue() { + return TValueType(); // zero } - }; - - ///////////////////////////////////////////////////////////////////////////////////////// - // TSlidingWindow - ///////////////////////////////////////////////////////////////////////////////////////// - template <class TOperation, class TMutexImpl = TFakeMutex> - class TSlidingWindow { - public: - using TValueType = typename TOperation::TValueType; + + // Updates value in current bucket and returns window value + static TValueType UpdateBucket(TValueType windowValue, TValueVector& buckets, size_t index, TValueType newVal) { + Y_ASSERT(index < buckets.size()); + buckets[index] += newVal; + windowValue += newVal; + return windowValue; + } + + static TValueType ClearBuckets(TValueType windowValue, TValueVector& buckets, size_t firstElemIndex, size_t bucketsToClear) { + Y_ASSERT(!buckets.empty()); + Y_ASSERT(firstElemIndex < buckets.size()); + Y_ASSERT(bucketsToClear <= buckets.size()); + + const size_t arraySize = buckets.size(); + for (size_t i = 0; i < bucketsToClear; ++i) { + TValueType& curVal = buckets[firstElemIndex]; + windowValue -= curVal; + curVal = InitialValue(); + firstElemIndex = (firstElemIndex + 1) % arraySize; + } + return windowValue; + } + }; + + ///////////////////////////////////////////////////////////////////////////////////////// + // TSlidingWindow + ///////////////////////////////////////////////////////////////////////////////////////// + template <class TOperation, class TMutexImpl = TFakeMutex> + class TSlidingWindow { + public: + using TValueType = typename TOperation::TValueType; using TValueVector = TVector<TValueType>; using TSizeType = typename TValueVector::size_type; - public: + public: TSlidingWindow(const TDuration& length, TSizeType partsNum) - : Mutex() - , Buckets(partsNum, TOperation::InitialValue()) // vector of size partsNum initialized with initial value - , WindowValue(TOperation::InitialValue()) - , FirstElem(0) - , PeriodStart() - , Length(length) - , MicroSecondsPerBucket(length.MicroSeconds() / partsNum) - { - } - - TSlidingWindow(const TSlidingWindow& w) - : Mutex() - { - TGuard<TMutexImpl> guard(&w.Mutex); - Buckets = w.Buckets; - WindowValue = w.WindowValue; - FirstElem = w.FirstElem; - PeriodStart = w.PeriodStart; - Length = w.Length; - MicroSecondsPerBucket = w.MicroSecondsPerBucket; - } - - TSlidingWindow(TSlidingWindow&&) = default; - - TSlidingWindow& operator=(TSlidingWindow&&) = default; - TSlidingWindow& operator=(const TSlidingWindow&) = delete; - - // Period of time - const TDuration& GetDuration() const { - return Length; - } - - // Update window with new value and time - TValueType Update(TValueType val, TInstant t) { - TGuard<TMutexImpl> guard(&Mutex); - AdvanceTime(t); - UpdateCurrentBucket(val); - return WindowValue; - } - - // Update just time, without new values - TValueType Update(TInstant t) { - TGuard<TMutexImpl> guard(&Mutex); - AdvanceTime(t); - return WindowValue; - } - - // Get current window value (without updating current time) - TValueType GetValue() const { - TGuard<TMutexImpl> guard(&Mutex); - return WindowValue; + : Mutex() + , Buckets(partsNum, TOperation::InitialValue()) // vector of size partsNum initialized with initial value + , WindowValue(TOperation::InitialValue()) + , FirstElem(0) + , PeriodStart() + , Length(length) + , MicroSecondsPerBucket(length.MicroSeconds() / partsNum) + { } - private: - void UpdateCurrentBucket(TValueType val) { - const TSizeType arraySize = Buckets.size(); - const TSizeType pos = (FirstElem + arraySize - 1) % arraySize; - WindowValue = TOperation::UpdateBucket(WindowValue, Buckets, pos, val); + TSlidingWindow(const TSlidingWindow& w) + : Mutex() + { + TGuard<TMutexImpl> guard(&w.Mutex); + Buckets = w.Buckets; + WindowValue = w.WindowValue; + FirstElem = w.FirstElem; + PeriodStart = w.PeriodStart; + Length = w.Length; + MicroSecondsPerBucket = w.MicroSecondsPerBucket; + } + + TSlidingWindow(TSlidingWindow&&) = default; + + TSlidingWindow& operator=(TSlidingWindow&&) = default; + TSlidingWindow& operator=(const TSlidingWindow&) = delete; + + // Period of time + const TDuration& GetDuration() const { + return Length; } - void AdvanceTime(const TInstant& time) { - if (time < PeriodStart + Length) { - return; - } - - if (PeriodStart.MicroSeconds() == 0) { - PeriodStart = time - Length; - return; - } - - const TInstant& newPeriodStart = time - Length; - const ui64 tmDiff = (newPeriodStart - PeriodStart).MicroSeconds(); - const TSizeType bucketsDiff = tmDiff / MicroSecondsPerBucket; - const TSizeType arraySize = Buckets.size(); - const TSizeType buckets = Min(bucketsDiff, arraySize); - - WindowValue = TOperation::ClearBuckets(WindowValue, Buckets, FirstElem, buckets); - FirstElem = (FirstElem + buckets) % arraySize; - PeriodStart += TDuration::MicroSeconds(bucketsDiff * MicroSecondsPerBucket); - - // Check that PeriodStart lags behind newPeriodStart - // (which is actual, uptodate, precise and equal to time - Length) not more - // then MicroSecondsPerBucket - Y_ASSERT(newPeriodStart >= PeriodStart); - Y_ASSERT((newPeriodStart - PeriodStart).MicroSeconds() <= MicroSecondsPerBucket); - } - - - mutable TMutexImpl Mutex; - TValueVector Buckets; - TValueType WindowValue; - TSizeType FirstElem; - TInstant PeriodStart; - TDuration Length; - ui64 MicroSecondsPerBucket; - }; - -} + // Update window with new value and time + TValueType Update(TValueType val, TInstant t) { + TGuard<TMutexImpl> guard(&Mutex); + AdvanceTime(t); + UpdateCurrentBucket(val); + return WindowValue; + } + + // Update just time, without new values + TValueType Update(TInstant t) { + TGuard<TMutexImpl> guard(&Mutex); + AdvanceTime(t); + return WindowValue; + } + + // Get current window value (without updating current time) + TValueType GetValue() const { + TGuard<TMutexImpl> guard(&Mutex); + return WindowValue; + } + + private: + void UpdateCurrentBucket(TValueType val) { + const TSizeType arraySize = Buckets.size(); + const TSizeType pos = (FirstElem + arraySize - 1) % arraySize; + WindowValue = TOperation::UpdateBucket(WindowValue, Buckets, pos, val); + } + + void AdvanceTime(const TInstant& time) { + if (time < PeriodStart + Length) { + return; + } + + if (PeriodStart.MicroSeconds() == 0) { + PeriodStart = time - Length; + return; + } + + const TInstant& newPeriodStart = time - Length; + const ui64 tmDiff = (newPeriodStart - PeriodStart).MicroSeconds(); + const TSizeType bucketsDiff = tmDiff / MicroSecondsPerBucket; + const TSizeType arraySize = Buckets.size(); + const TSizeType buckets = Min(bucketsDiff, arraySize); + + WindowValue = TOperation::ClearBuckets(WindowValue, Buckets, FirstElem, buckets); + FirstElem = (FirstElem + buckets) % arraySize; + PeriodStart += TDuration::MicroSeconds(bucketsDiff * MicroSecondsPerBucket); + + // Check that PeriodStart lags behind newPeriodStart + // (which is actual, uptodate, precise and equal to time - Length) not more + // then MicroSecondsPerBucket + Y_ASSERT(newPeriodStart >= PeriodStart); + Y_ASSERT((newPeriodStart - PeriodStart).MicroSeconds() <= MicroSecondsPerBucket); + } + + + mutable TMutexImpl Mutex; + TValueVector Buckets; + TValueType WindowValue; + TSizeType FirstElem; + TInstant PeriodStart; + TDuration Length; + ui64 MicroSecondsPerBucket; + }; + +} diff --git a/library/cpp/sliding_window/sliding_window_ut.cpp b/library/cpp/sliding_window/sliding_window_ut.cpp index 35f04b21b2..1e7343a8d3 100644 --- a/library/cpp/sliding_window/sliding_window_ut.cpp +++ b/library/cpp/sliding_window/sliding_window_ut.cpp @@ -9,40 +9,40 @@ Y_UNIT_TEST_SUITE(TSlidingWindowTest) { TSlidingWindow<TMaxOperation<unsigned>> w(TDuration::Minutes(5), 5); TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds()); TInstant now = start; - w.Update(5, start); // ~ ~ ~ ~ 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(5, start); // ~ ~ ~ ~ 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(1) + TDuration::Seconds(1); - w.Update(5, now); // 5 ~ ~ ~ 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(5, now); // 5 ~ ~ ~ 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(1); - w.Update(3, now); // 5 3 ~ ~ 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(3, now); // 5 3 ~ ~ 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(3); - w.Update(2, now); // 5 3 ~ ~ 2 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(2, now); // 5 3 ~ ~ 2 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(1); - w.Update(2, now); // 2 3 ~ ~ 2 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 3); // ^ + w.Update(2, now); // 2 3 ~ ~ 2 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 3); // ^ now += TDuration::Minutes(1); - w.Update(2, now); // 2 2 ~ ~ 2 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ + w.Update(2, now); // 2 2 ~ ~ 2 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ now += TDuration::Minutes(5); - w.Update(1, now); // ~ 1 ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 1); // ^ + w.Update(1, now); // ~ 1 ~ ~ ~ + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 1); // ^ // update current bucket - w.Update(2, now); // ~ 2 ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ + w.Update(2, now); // ~ 2 ~ ~ ~ + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ - w.Update(1, now + TDuration::Seconds(30)); // ~ 2 ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ + w.Update(1, now + TDuration::Seconds(30)); // ~ 2 ~ ~ ~ + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ // test idle now += TDuration::Minutes(1); - w.Update(now); // ~ 2 ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ + w.Update(now); // ~ 2 ~ ~ ~ + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 2); // ^ - now += TDuration::Minutes(5); // ~ ~ ~ ~ ~ + now += TDuration::Minutes(5); // ~ ~ ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.Update(now), 0); } @@ -50,40 +50,40 @@ Y_UNIT_TEST_SUITE(TSlidingWindowTest) { TSlidingWindow<TMinOperation<unsigned>> w(TDuration::Minutes(5), 5); TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds()); TInstant now = start; - w.Update(5, start); // ~ ~ ~ ~ 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(5, start); // ~ ~ ~ ~ 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(1) + TDuration::Seconds(1); - w.Update(5, now); // 5 ~ ~ ~ 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(5, now); // 5 ~ ~ ~ 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(1); - w.Update(7, now); // 5 7 ~ ~ 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(7, now); // 5 7 ~ ~ 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(3); - w.Update(8, now); // 5 7 ~ ~ 8 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(8, now); // 5 7 ~ ~ 8 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(1); - w.Update(8, now); // 8 7 ~ ~ 8 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 7); // ^ + w.Update(8, now); // 8 7 ~ ~ 8 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 7); // ^ now += TDuration::Minutes(1); - w.Update(8, now); // 8 8 ~ ~ 8 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 8); // ^ + w.Update(8, now); // 8 8 ~ ~ 8 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 8); // ^ now += TDuration::Minutes(5); - w.Update(6, now); // ~ 6 ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 6); // ^ + w.Update(6, now); // ~ 6 ~ ~ ~ + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 6); // ^ // update current bucket - w.Update(5, now); // ~ 5 ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(5, now); // ~ 5 ~ ~ ~ + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - w.Update(6, now + TDuration::Seconds(30)); // ~ 5 ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(6, now + TDuration::Seconds(30)); // ~ 5 ~ ~ ~ + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ // test idle now += TDuration::Minutes(1); - w.Update(now); // ~ 5 ~ ~ ~ - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(now); // ~ 5 ~ ~ ~ + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ - now += TDuration::Minutes(5); // ~ ~ ~ ~ ~ + now += TDuration::Minutes(5); // ~ ~ ~ ~ ~ UNIT_ASSERT_VALUES_EQUAL(w.Update(now), std::numeric_limits<unsigned>::max()); } @@ -93,40 +93,40 @@ Y_UNIT_TEST_SUITE(TSlidingWindowTest) { TInstant start = TInstant::MicroSeconds(TDuration::Hours(1).MicroSeconds()); TInstant now = start; - w.Update(5, start); // 0 0 0 0 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ + w.Update(5, start); // 0 0 0 0 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 5); // ^ now += TDuration::Minutes(1) + TDuration::Seconds(1); - w.Update(5, now); // 5 0 0 0 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 10); // ^ + w.Update(5, now); // 5 0 0 0 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 10); // ^ now += TDuration::Minutes(1); - w.Update(3, now); // 5 3 0 0 5 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 13); // ^ + w.Update(3, now); // 5 3 0 0 5 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 13); // ^ now += TDuration::Minutes(3); - w.Update(2, now); // 5 3 0 0 2 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 10); // ^ + w.Update(2, now); // 5 3 0 0 2 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 10); // ^ now += TDuration::Minutes(1); - w.Update(2, now); // 2 3 0 0 2 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 7); // ^ + w.Update(2, now); // 2 3 0 0 2 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 7); // ^ now += TDuration::Minutes(1); - w.Update(2, now); // 2 2 0 0 2 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 6); // ^ + w.Update(2, now); // 2 2 0 0 2 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 6); // ^ now += TDuration::Minutes(5); - w.Update(1, now); // 0 1 0 0 0 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 1); // ^ + w.Update(1, now); // 0 1 0 0 0 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 1); // ^ // update current bucket - w.Update(2, now); // 0 3 0 0 0 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 3); // ^ + w.Update(2, now); // 0 3 0 0 0 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 3); // ^ - w.Update(1, now + TDuration::Seconds(30)); // 0 4 0 0 0 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 4); // ^ + w.Update(1, now + TDuration::Seconds(30)); // 0 4 0 0 0 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 4); // ^ // test idle now += TDuration::Minutes(1); - w.Update(now); // 0 4 0 0 0 - UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 4); // ^ + w.Update(now); // 0 4 0 0 0 + UNIT_ASSERT_VALUES_EQUAL(w.GetValue(), 4); // ^ - now += TDuration::Minutes(5); // 0 0 0 0 0 + now += TDuration::Minutes(5); // 0 0 0 0 0 UNIT_ASSERT_VALUES_EQUAL(w.Update(now), 0); } } |