1 /*
2 * Copyright (c) 2018 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 #include "rtc_base/numerics/sample_counter.h"
12
13 #include <limits>
14
15 #include "rtc_base/checks.h"
16 #include "rtc_base/numerics/safe_conversions.h"
17
18 namespace rtc {
19
20 SampleCounter::SampleCounter() = default;
21 SampleCounter::~SampleCounter() = default;
22
Add(int sample)23 void SampleCounter::Add(int sample) {
24 if (sum_ > 0) {
25 RTC_DCHECK_LE(sample, std::numeric_limits<int64_t>::max() - sum_);
26 } else {
27 RTC_DCHECK_GE(sample, std::numeric_limits<int64_t>::min() - sum_);
28 }
29 sum_ += sample;
30 ++num_samples_;
31 if (!max_ || sample > *max_) {
32 max_ = sample;
33 }
34 }
35
Add(const SampleCounter & other)36 void SampleCounter::Add(const SampleCounter& other) {
37 if (sum_ > 0) {
38 RTC_DCHECK_LE(other.sum_, std::numeric_limits<int64_t>::max() - sum_);
39 } else {
40 RTC_DCHECK_GE(other.sum_, std::numeric_limits<int64_t>::min() - sum_);
41 }
42 sum_ += other.sum_;
43 RTC_DCHECK_LE(other.num_samples_,
44 std::numeric_limits<int64_t>::max() - num_samples_);
45 num_samples_ += other.num_samples_;
46 if (other.max_ && (!max_ || *max_ < *other.max_))
47 max_ = other.max_;
48 }
49
Avg(int64_t min_required_samples) const50 absl::optional<int> SampleCounter::Avg(int64_t min_required_samples) const {
51 RTC_DCHECK_GT(min_required_samples, 0);
52 if (num_samples_ < min_required_samples)
53 return absl::nullopt;
54 return rtc::dchecked_cast<int>(sum_ / num_samples_);
55 }
56
Max() const57 absl::optional<int> SampleCounter::Max() const {
58 return max_;
59 }
60
Sum(int64_t min_required_samples) const61 absl::optional<int64_t> SampleCounter::Sum(int64_t min_required_samples) const {
62 RTC_DCHECK_GT(min_required_samples, 0);
63 if (num_samples_ < min_required_samples)
64 return absl::nullopt;
65 return sum_;
66 }
67
NumSamples() const68 int64_t SampleCounter::NumSamples() const {
69 return num_samples_;
70 }
71
Reset()72 void SampleCounter::Reset() {
73 *this = {};
74 }
75
76 SampleCounterWithVariance::SampleCounterWithVariance() = default;
77 SampleCounterWithVariance::~SampleCounterWithVariance() = default;
78
Variance(int64_t min_required_samples) const79 absl::optional<int64_t> SampleCounterWithVariance::Variance(
80 int64_t min_required_samples) const {
81 RTC_DCHECK_GT(min_required_samples, 0);
82 if (num_samples_ < min_required_samples)
83 return absl::nullopt;
84 // E[(x-mean)^2] = E[x^2] - mean^2
85 int64_t mean = sum_ / num_samples_;
86 return sum_squared_ / num_samples_ - mean * mean;
87 }
88
Add(int sample)89 void SampleCounterWithVariance::Add(int sample) {
90 SampleCounter::Add(sample);
91 // Prevent overflow in squaring.
92 RTC_DCHECK_GT(sample, std::numeric_limits<int32_t>::min());
93 RTC_DCHECK_LE(int64_t{sample} * sample,
94 std::numeric_limits<int64_t>::max() - sum_squared_);
95 sum_squared_ += int64_t{sample} * sample;
96 }
97
Add(const SampleCounterWithVariance & other)98 void SampleCounterWithVariance::Add(const SampleCounterWithVariance& other) {
99 SampleCounter::Add(other);
100 RTC_DCHECK_LE(other.sum_squared_,
101 std::numeric_limits<int64_t>::max() - sum_squared_);
102 sum_squared_ += other.sum_squared_;
103 }
104
Reset()105 void SampleCounterWithVariance::Reset() {
106 *this = {};
107 }
108
109 } // namespace rtc
110