1*6777b538SAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_MOVING_WINDOW_H_ 6*6777b538SAndroid Build Coastguard Worker #define BASE_MOVING_WINDOW_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <math.h> 9*6777b538SAndroid Build Coastguard Worker #include <stddef.h> 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Worker #include <cmath> 12*6777b538SAndroid Build Coastguard Worker #include <functional> 13*6777b538SAndroid Build Coastguard Worker #include <limits> 14*6777b538SAndroid Build Coastguard Worker #include <vector> 15*6777b538SAndroid Build Coastguard Worker 16*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h" 17*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ref.h" 18*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h" 19*6777b538SAndroid Build Coastguard Worker 20*6777b538SAndroid Build Coastguard Worker namespace base { 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard Worker // Class to efficiently calculate statistics in a sliding window. 23*6777b538SAndroid Build Coastguard Worker // This class isn't thread safe. 24*6777b538SAndroid Build Coastguard Worker // Supported statistics are Min/Max/Mean/Deviation. 25*6777b538SAndroid Build Coastguard Worker // You can also iterate through the items in the window. 26*6777b538SAndroid Build Coastguard Worker // The class is modular: required features must be specified in the template 27*6777b538SAndroid Build Coastguard Worker // arguments. 28*6777b538SAndroid Build Coastguard Worker // Non listed features don't consume memory or runtime cycles at all. 29*6777b538SAndroid Build Coastguard Worker // 30*6777b538SAndroid Build Coastguard Worker // Usage: 31*6777b538SAndroid Build Coastguard Worker // base::MovingWindow<int, 32*6777b538SAndroid Build Coastguard Worker // base::MovingWindowFeatures::Min, 33*6777b538SAndroid Build Coastguard Worker // base::MovingWindowFeatures::Max> 34*6777b538SAndroid Build Coastguard Worker // moving_window(window_size); 35*6777b538SAndroid Build Coastguard Worker // 36*6777b538SAndroid Build Coastguard Worker // Following convenience shortcuts are provided with predefined sets of 37*6777b538SAndroid Build Coastguard Worker // features: 38*6777b538SAndroid Build Coastguard Worker // MovingMax/MovingMin/MovingAverage/MovingAverageDeviation/MovingMinMax. 39*6777b538SAndroid Build Coastguard Worker // 40*6777b538SAndroid Build Coastguard Worker // Methods: 41*6777b538SAndroid Build Coastguard Worker // Constructor: 42*6777b538SAndroid Build Coastguard Worker // MovingWindow(size_t window_size); 43*6777b538SAndroid Build Coastguard Worker // 44*6777b538SAndroid Build Coastguard Worker // Window update (available for all templates): 45*6777b538SAndroid Build Coastguard Worker // AddSample(T value) const; 46*6777b538SAndroid Build Coastguard Worker // size_t Count() const; 47*6777b538SAndroid Build Coastguard Worker // void Reset(); 48*6777b538SAndroid Build Coastguard Worker // 49*6777b538SAndroid Build Coastguard Worker // Available for MovingWindowFeatures::Min: 50*6777b538SAndroid Build Coastguard Worker // T Min() const; 51*6777b538SAndroid Build Coastguard Worker // 52*6777b538SAndroid Build Coastguard Worker // Available for MovingWindowFeatures::Max: 53*6777b538SAndroid Build Coastguard Worker // T Max() const; 54*6777b538SAndroid Build Coastguard Worker // 55*6777b538SAndroid Build Coastguard Worker // Available for MovingWindowFeatures::Mean: 56*6777b538SAndroid Build Coastguard Worker // U Mean<U>() const; 57*6777b538SAndroid Build Coastguard Worker // 58*6777b538SAndroid Build Coastguard Worker // Available for MovingWindowFeatures::Deviation: 59*6777b538SAndroid Build Coastguard Worker // U Deviation<U>() const; 60*6777b538SAndroid Build Coastguard Worker // 61*6777b538SAndroid Build Coastguard Worker // Available for MovingWindowFeatures::Iteration. Iterating through the window: 62*6777b538SAndroid Build Coastguard Worker // iterator begin() const; 63*6777b538SAndroid Build Coastguard Worker // iterator begin() const; 64*6777b538SAndroid Build Coastguard Worker // size_t size() const; 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Worker // Features supported by the class. 67*6777b538SAndroid Build Coastguard Worker struct MovingWindowFeatures { 68*6777b538SAndroid Build Coastguard Worker struct Min { 69*6777b538SAndroid Build Coastguard Worker static bool has_min; 70*6777b538SAndroid Build Coastguard Worker }; 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker struct Max { 73*6777b538SAndroid Build Coastguard Worker static bool has_max; 74*6777b538SAndroid Build Coastguard Worker }; 75*6777b538SAndroid Build Coastguard Worker 76*6777b538SAndroid Build Coastguard Worker // Need to specify a type capable of holding a sum of all elements in the 77*6777b538SAndroid Build Coastguard Worker // window. 78*6777b538SAndroid Build Coastguard Worker template <typename SumType> 79*6777b538SAndroid Build Coastguard Worker struct Mean { 80*6777b538SAndroid Build Coastguard Worker static SumType has_mean; 81*6777b538SAndroid Build Coastguard Worker }; 82*6777b538SAndroid Build Coastguard Worker 83*6777b538SAndroid Build Coastguard Worker // Need to specify a type capable of holding a sum of squares of all elements 84*6777b538SAndroid Build Coastguard Worker // in the window. 85*6777b538SAndroid Build Coastguard Worker template <typename SumType> 86*6777b538SAndroid Build Coastguard Worker struct Deviation { 87*6777b538SAndroid Build Coastguard Worker static SumType has_deviation; 88*6777b538SAndroid Build Coastguard Worker }; 89*6777b538SAndroid Build Coastguard Worker 90*6777b538SAndroid Build Coastguard Worker struct Iteration { 91*6777b538SAndroid Build Coastguard Worker static bool has_iteration; 92*6777b538SAndroid Build Coastguard Worker }; 93*6777b538SAndroid Build Coastguard Worker }; 94*6777b538SAndroid Build Coastguard Worker 95*6777b538SAndroid Build Coastguard Worker // Main template. 96*6777b538SAndroid Build Coastguard Worker template <typename T, typename... Features> 97*6777b538SAndroid Build Coastguard Worker class MovingWindow; 98*6777b538SAndroid Build Coastguard Worker 99*6777b538SAndroid Build Coastguard Worker // Convenience shortcuts. 100*6777b538SAndroid Build Coastguard Worker template <typename T> 101*6777b538SAndroid Build Coastguard Worker using MovingMax = MovingWindow<T, MovingWindowFeatures::Max>; 102*6777b538SAndroid Build Coastguard Worker 103*6777b538SAndroid Build Coastguard Worker template <typename T> 104*6777b538SAndroid Build Coastguard Worker using MovingMin = MovingWindow<T, MovingWindowFeatures::Min>; 105*6777b538SAndroid Build Coastguard Worker 106*6777b538SAndroid Build Coastguard Worker template <typename T> 107*6777b538SAndroid Build Coastguard Worker using MovingMinMax = 108*6777b538SAndroid Build Coastguard Worker MovingWindow<T, MovingWindowFeatures::Min, MovingWindowFeatures::Max>; 109*6777b538SAndroid Build Coastguard Worker 110*6777b538SAndroid Build Coastguard Worker template <typename T, typename SumType> 111*6777b538SAndroid Build Coastguard Worker using MovingAverage = MovingWindow<T, MovingWindowFeatures::Mean<SumType>>; 112*6777b538SAndroid Build Coastguard Worker 113*6777b538SAndroid Build Coastguard Worker template <typename T> 114*6777b538SAndroid Build Coastguard Worker using MovingAverageDeviation = 115*6777b538SAndroid Build Coastguard Worker MovingWindow<T, 116*6777b538SAndroid Build Coastguard Worker MovingWindowFeatures::Mean<T>, 117*6777b538SAndroid Build Coastguard Worker MovingWindowFeatures::Deviation<double>>; 118*6777b538SAndroid Build Coastguard Worker 119*6777b538SAndroid Build Coastguard Worker namespace internal { 120*6777b538SAndroid Build Coastguard Worker 121*6777b538SAndroid Build Coastguard Worker // Class responsible only for calculating maximum in the window. 122*6777b538SAndroid Build Coastguard Worker // It's reused to calculate both min and max via inverting the comparator. 123*6777b538SAndroid Build Coastguard Worker template <typename T, typename Comparator> 124*6777b538SAndroid Build Coastguard Worker class MovingExtremumBase { 125*6777b538SAndroid Build Coastguard Worker public: MovingExtremumBase(size_t window_size)126*6777b538SAndroid Build Coastguard Worker explicit MovingExtremumBase(size_t window_size) 127*6777b538SAndroid Build Coastguard Worker : window_size_(window_size), 128*6777b538SAndroid Build Coastguard Worker values_(window_size), 129*6777b538SAndroid Build Coastguard Worker added_at_(window_size), 130*6777b538SAndroid Build Coastguard Worker last_idx_(window_size - 1), 131*6777b538SAndroid Build Coastguard Worker compare_(Comparator()) {} 132*6777b538SAndroid Build Coastguard Worker ~MovingExtremumBase() = default; 133*6777b538SAndroid Build Coastguard Worker 134*6777b538SAndroid Build Coastguard Worker // Add new sample to the stream. AddSample(const T & value,size_t total_added)135*6777b538SAndroid Build Coastguard Worker void AddSample(const T& value, size_t total_added) { 136*6777b538SAndroid Build Coastguard Worker // Remove old elements from the back of the window; 137*6777b538SAndroid Build Coastguard Worker while (size_ > 0 && added_at_[begin_idx_] + window_size_ <= total_added) { 138*6777b538SAndroid Build Coastguard Worker ++begin_idx_; 139*6777b538SAndroid Build Coastguard Worker if (begin_idx_ == window_size_) { 140*6777b538SAndroid Build Coastguard Worker begin_idx_ = 0; 141*6777b538SAndroid Build Coastguard Worker } 142*6777b538SAndroid Build Coastguard Worker --size_; 143*6777b538SAndroid Build Coastguard Worker } 144*6777b538SAndroid Build Coastguard Worker // Remove small elements from the front of the window because they can never 145*6777b538SAndroid Build Coastguard Worker // become the maximum in the window since the currently added element is 146*6777b538SAndroid Build Coastguard Worker // bigger than them and will leave the window later. 147*6777b538SAndroid Build Coastguard Worker while (size_ > 0 && compare_(values_[last_idx_], value)) { 148*6777b538SAndroid Build Coastguard Worker if (last_idx_ == 0) { 149*6777b538SAndroid Build Coastguard Worker last_idx_ = window_size_; 150*6777b538SAndroid Build Coastguard Worker } 151*6777b538SAndroid Build Coastguard Worker --last_idx_; 152*6777b538SAndroid Build Coastguard Worker --size_; 153*6777b538SAndroid Build Coastguard Worker } 154*6777b538SAndroid Build Coastguard Worker DCHECK_LT(size_, window_size_); 155*6777b538SAndroid Build Coastguard Worker ++last_idx_; 156*6777b538SAndroid Build Coastguard Worker if (last_idx_ == window_size_) { 157*6777b538SAndroid Build Coastguard Worker last_idx_ = 0; 158*6777b538SAndroid Build Coastguard Worker } 159*6777b538SAndroid Build Coastguard Worker values_[last_idx_] = value; 160*6777b538SAndroid Build Coastguard Worker added_at_[last_idx_] = total_added; 161*6777b538SAndroid Build Coastguard Worker ++size_; 162*6777b538SAndroid Build Coastguard Worker } 163*6777b538SAndroid Build Coastguard Worker 164*6777b538SAndroid Build Coastguard Worker // Get the maximum of the last `window_size` elements. Value()165*6777b538SAndroid Build Coastguard Worker T Value() const { 166*6777b538SAndroid Build Coastguard Worker DCHECK_GT(size_, 0u); 167*6777b538SAndroid Build Coastguard Worker return values_[begin_idx_]; 168*6777b538SAndroid Build Coastguard Worker } 169*6777b538SAndroid Build Coastguard Worker 170*6777b538SAndroid Build Coastguard Worker // Clear all samples. Reset()171*6777b538SAndroid Build Coastguard Worker void Reset() { 172*6777b538SAndroid Build Coastguard Worker size_ = 0; 173*6777b538SAndroid Build Coastguard Worker begin_idx_ = 0; 174*6777b538SAndroid Build Coastguard Worker last_idx_ = window_size_ - 1; 175*6777b538SAndroid Build Coastguard Worker } 176*6777b538SAndroid Build Coastguard Worker 177*6777b538SAndroid Build Coastguard Worker private: 178*6777b538SAndroid Build Coastguard Worker const size_t window_size_; 179*6777b538SAndroid Build Coastguard Worker // Circular buffer with some values in the window. 180*6777b538SAndroid Build Coastguard Worker // Only possible candidates for maximum are stored: 181*6777b538SAndroid Build Coastguard Worker // values form a non-increasing sequence. 182*6777b538SAndroid Build Coastguard Worker std::vector<T> values_; 183*6777b538SAndroid Build Coastguard Worker // Circular buffer storing when numbers in `values_` were added. 184*6777b538SAndroid Build Coastguard Worker std::vector<size_t> added_at_; 185*6777b538SAndroid Build Coastguard Worker // Begin of the circular buffers above. 186*6777b538SAndroid Build Coastguard Worker size_t begin_idx_ = 0; 187*6777b538SAndroid Build Coastguard Worker // Last occupied position. 188*6777b538SAndroid Build Coastguard Worker size_t last_idx_; 189*6777b538SAndroid Build Coastguard Worker // How many elements are stored in the circular buffers above. 190*6777b538SAndroid Build Coastguard Worker size_t size_ = 0; 191*6777b538SAndroid Build Coastguard Worker // Template parameter comparator. 192*6777b538SAndroid Build Coastguard Worker const Comparator compare_; 193*6777b538SAndroid Build Coastguard Worker }; 194*6777b538SAndroid Build Coastguard Worker 195*6777b538SAndroid Build Coastguard Worker // Null implementation of the above class to be used when feature is disabled. 196*6777b538SAndroid Build Coastguard Worker template <typename T> 197*6777b538SAndroid Build Coastguard Worker struct NullExtremumImpl { NullExtremumImplNullExtremumImpl198*6777b538SAndroid Build Coastguard Worker explicit NullExtremumImpl(size_t) {} 199*6777b538SAndroid Build Coastguard Worker ~NullExtremumImpl() = default; AddSampleNullExtremumImpl200*6777b538SAndroid Build Coastguard Worker void AddSample(const T&, size_t) {} ResetNullExtremumImpl201*6777b538SAndroid Build Coastguard Worker void Reset() {} 202*6777b538SAndroid Build Coastguard Worker }; 203*6777b538SAndroid Build Coastguard Worker 204*6777b538SAndroid Build Coastguard Worker // Class to hold the moving window. 205*6777b538SAndroid Build Coastguard Worker // It's used to calculate replaced element for Mean/Deviation calculations. 206*6777b538SAndroid Build Coastguard Worker template <typename T> 207*6777b538SAndroid Build Coastguard Worker class MovingWindowBase { 208*6777b538SAndroid Build Coastguard Worker public: MovingWindowBase(size_t window_size)209*6777b538SAndroid Build Coastguard Worker explicit MovingWindowBase(size_t window_size) : values_(window_size) {} 210*6777b538SAndroid Build Coastguard Worker 211*6777b538SAndroid Build Coastguard Worker ~MovingWindowBase() = default; 212*6777b538SAndroid Build Coastguard Worker AddSample(const T & sample)213*6777b538SAndroid Build Coastguard Worker void AddSample(const T& sample) { 214*6777b538SAndroid Build Coastguard Worker values_[cur_idx_] = sample; 215*6777b538SAndroid Build Coastguard Worker ++cur_idx_; 216*6777b538SAndroid Build Coastguard Worker if (cur_idx_ == values_.size()) { 217*6777b538SAndroid Build Coastguard Worker cur_idx_ = 0; 218*6777b538SAndroid Build Coastguard Worker } 219*6777b538SAndroid Build Coastguard Worker } 220*6777b538SAndroid Build Coastguard Worker 221*6777b538SAndroid Build Coastguard Worker // Is the window filled integer amount of times. IsLastIdx()222*6777b538SAndroid Build Coastguard Worker bool IsLastIdx() const { return cur_idx_ + 1 == values_.size(); } 223*6777b538SAndroid Build Coastguard Worker Reset()224*6777b538SAndroid Build Coastguard Worker void Reset() { 225*6777b538SAndroid Build Coastguard Worker cur_idx_ = 0; 226*6777b538SAndroid Build Coastguard Worker std::fill(values_.begin(), values_.end(), T()); 227*6777b538SAndroid Build Coastguard Worker } 228*6777b538SAndroid Build Coastguard Worker GetValue()229*6777b538SAndroid Build Coastguard Worker T GetValue() const { return values_[cur_idx_]; } 230*6777b538SAndroid Build Coastguard Worker 231*6777b538SAndroid Build Coastguard Worker T operator[](size_t idx) const { return values_[idx]; } 232*6777b538SAndroid Build Coastguard Worker Size()233*6777b538SAndroid Build Coastguard Worker size_t Size() const { return values_.size(); } 234*6777b538SAndroid Build Coastguard Worker 235*6777b538SAndroid Build Coastguard Worker // What index will be overwritten by a new element; CurIdx()236*6777b538SAndroid Build Coastguard Worker size_t CurIdx() const { return cur_idx_; } 237*6777b538SAndroid Build Coastguard Worker 238*6777b538SAndroid Build Coastguard Worker private: 239*6777b538SAndroid Build Coastguard Worker // Circular buffer. 240*6777b538SAndroid Build Coastguard Worker std::vector<T> values_; 241*6777b538SAndroid Build Coastguard Worker // Where the buffer begins. 242*6777b538SAndroid Build Coastguard Worker size_t cur_idx_ = 0; 243*6777b538SAndroid Build Coastguard Worker }; 244*6777b538SAndroid Build Coastguard Worker 245*6777b538SAndroid Build Coastguard Worker // Null implementation of the above class to be used when feature is disabled. 246*6777b538SAndroid Build Coastguard Worker template <typename T> 247*6777b538SAndroid Build Coastguard Worker struct NullWindowImpl { NullWindowImplNullWindowImpl248*6777b538SAndroid Build Coastguard Worker explicit NullWindowImpl(size_t) {} 249*6777b538SAndroid Build Coastguard Worker ~NullWindowImpl() = default; AddSampleNullWindowImpl250*6777b538SAndroid Build Coastguard Worker void AddSample(const T& sample) {} IsLastIdxNullWindowImpl251*6777b538SAndroid Build Coastguard Worker bool IsLastIdx() const { return false; } ResetNullWindowImpl252*6777b538SAndroid Build Coastguard Worker void Reset() {} GetValueNullWindowImpl253*6777b538SAndroid Build Coastguard Worker T GetValue() const { return T(); } 254*6777b538SAndroid Build Coastguard Worker }; 255*6777b538SAndroid Build Coastguard Worker 256*6777b538SAndroid Build Coastguard Worker // Performs division allowing the class to work with more types. 257*6777b538SAndroid Build Coastguard Worker // General template. 258*6777b538SAndroid Build Coastguard Worker template <typename SumType, typename ReturnType> 259*6777b538SAndroid Build Coastguard Worker struct DivideInternal { ComputeDivideInternal260*6777b538SAndroid Build Coastguard Worker static ReturnType Compute(const SumType& sum, const size_t count) { 261*6777b538SAndroid Build Coastguard Worker return static_cast<ReturnType>(sum) / static_cast<ReturnType>(count); 262*6777b538SAndroid Build Coastguard Worker } 263*6777b538SAndroid Build Coastguard Worker }; 264*6777b538SAndroid Build Coastguard Worker 265*6777b538SAndroid Build Coastguard Worker // Class to calculate moving mean. 266*6777b538SAndroid Build Coastguard Worker template <typename T, typename SumType, bool IsFloating> 267*6777b538SAndroid Build Coastguard Worker class MovingMeanBase { 268*6777b538SAndroid Build Coastguard Worker public: MovingMeanBase(size_t window_size)269*6777b538SAndroid Build Coastguard Worker explicit MovingMeanBase(size_t window_size) : sum_() {} 270*6777b538SAndroid Build Coastguard Worker 271*6777b538SAndroid Build Coastguard Worker ~MovingMeanBase() = default; 272*6777b538SAndroid Build Coastguard Worker AddSample(const T & sample,const T & replaced_value,bool is_last_idx)273*6777b538SAndroid Build Coastguard Worker void AddSample(const T& sample, const T& replaced_value, bool is_last_idx) { 274*6777b538SAndroid Build Coastguard Worker sum_ += sample - replaced_value; 275*6777b538SAndroid Build Coastguard Worker } 276*6777b538SAndroid Build Coastguard Worker 277*6777b538SAndroid Build Coastguard Worker template <typename ReturnType = SumType> Mean(const size_t count)278*6777b538SAndroid Build Coastguard Worker ReturnType Mean(const size_t count) const { 279*6777b538SAndroid Build Coastguard Worker if (count == 0) { 280*6777b538SAndroid Build Coastguard Worker return ReturnType(); 281*6777b538SAndroid Build Coastguard Worker } 282*6777b538SAndroid Build Coastguard Worker return DivideInternal<SumType, ReturnType>::Compute(sum_, count); 283*6777b538SAndroid Build Coastguard Worker } Reset()284*6777b538SAndroid Build Coastguard Worker void Reset() { sum_ = SumType(); } 285*6777b538SAndroid Build Coastguard Worker Sum()286*6777b538SAndroid Build Coastguard Worker SumType Sum() const { return sum_; } 287*6777b538SAndroid Build Coastguard Worker 288*6777b538SAndroid Build Coastguard Worker private: 289*6777b538SAndroid Build Coastguard Worker SumType sum_; 290*6777b538SAndroid Build Coastguard Worker }; 291*6777b538SAndroid Build Coastguard Worker 292*6777b538SAndroid Build Coastguard Worker // Class to calculate moving mean. 293*6777b538SAndroid Build Coastguard Worker // Variant for float types with running sum to avoid rounding errors 294*6777b538SAndroid Build Coastguard Worker // accumulation. 295*6777b538SAndroid Build Coastguard Worker template <typename T, typename SumType> 296*6777b538SAndroid Build Coastguard Worker class MovingMeanBase<T, SumType, true> { 297*6777b538SAndroid Build Coastguard Worker public: MovingMeanBase(size_t window_size)298*6777b538SAndroid Build Coastguard Worker explicit MovingMeanBase(size_t window_size) : sum_(), running_sum_() {} 299*6777b538SAndroid Build Coastguard Worker 300*6777b538SAndroid Build Coastguard Worker ~MovingMeanBase() = default; 301*6777b538SAndroid Build Coastguard Worker AddSample(const T & sample,const T & replaced_value,bool is_last_idx)302*6777b538SAndroid Build Coastguard Worker void AddSample(const T& sample, const T& replaced_value, bool is_last_idx) { 303*6777b538SAndroid Build Coastguard Worker running_sum_ += sample; 304*6777b538SAndroid Build Coastguard Worker if (is_last_idx) { 305*6777b538SAndroid Build Coastguard Worker // Replace sum with running sum to avoid rounding errors accumulation. 306*6777b538SAndroid Build Coastguard Worker sum_ = running_sum_; 307*6777b538SAndroid Build Coastguard Worker running_sum_ = SumType(); 308*6777b538SAndroid Build Coastguard Worker } else { 309*6777b538SAndroid Build Coastguard Worker sum_ += sample - replaced_value; 310*6777b538SAndroid Build Coastguard Worker } 311*6777b538SAndroid Build Coastguard Worker } 312*6777b538SAndroid Build Coastguard Worker 313*6777b538SAndroid Build Coastguard Worker template <typename ReturnType = SumType> Mean(const size_t count)314*6777b538SAndroid Build Coastguard Worker ReturnType Mean(const size_t count) const { 315*6777b538SAndroid Build Coastguard Worker if (count == 0) { 316*6777b538SAndroid Build Coastguard Worker return ReturnType(); 317*6777b538SAndroid Build Coastguard Worker } 318*6777b538SAndroid Build Coastguard Worker return DivideInternal<SumType, ReturnType>::Compute(sum_, count); 319*6777b538SAndroid Build Coastguard Worker } 320*6777b538SAndroid Build Coastguard Worker Reset()321*6777b538SAndroid Build Coastguard Worker void Reset() { sum_ = running_sum_ = SumType(); } 322*6777b538SAndroid Build Coastguard Worker Sum()323*6777b538SAndroid Build Coastguard Worker SumType Sum() const { return sum_; } 324*6777b538SAndroid Build Coastguard Worker 325*6777b538SAndroid Build Coastguard Worker private: 326*6777b538SAndroid Build Coastguard Worker SumType sum_; 327*6777b538SAndroid Build Coastguard Worker SumType running_sum_; 328*6777b538SAndroid Build Coastguard Worker }; 329*6777b538SAndroid Build Coastguard Worker 330*6777b538SAndroid Build Coastguard Worker // Null implementation of the above class to be used when feature is disabled. 331*6777b538SAndroid Build Coastguard Worker template <typename T> 332*6777b538SAndroid Build Coastguard Worker struct NullMeanImpl { NullMeanImplNullMeanImpl333*6777b538SAndroid Build Coastguard Worker explicit NullMeanImpl(size_t window_size) {} 334*6777b538SAndroid Build Coastguard Worker ~NullMeanImpl() = default; 335*6777b538SAndroid Build Coastguard Worker AddSampleNullMeanImpl336*6777b538SAndroid Build Coastguard Worker void AddSample(const T& sample, const T&, bool) {} 337*6777b538SAndroid Build Coastguard Worker ResetNullMeanImpl338*6777b538SAndroid Build Coastguard Worker void Reset() {} 339*6777b538SAndroid Build Coastguard Worker }; 340*6777b538SAndroid Build Coastguard Worker 341*6777b538SAndroid Build Coastguard Worker // Computs main Deviation fromula, allowing the class to work with more types. 342*6777b538SAndroid Build Coastguard Worker // Deviation is equal to mean of squared values minus squared mean value. 343*6777b538SAndroid Build Coastguard Worker // General template. 344*6777b538SAndroid Build Coastguard Worker template <typename SumType, typename ReturnType> 345*6777b538SAndroid Build Coastguard Worker struct DeivationInternal { ComputeDeivationInternal346*6777b538SAndroid Build Coastguard Worker static ReturnType Compute(const SumType& sum_squares, 347*6777b538SAndroid Build Coastguard Worker const SumType& square_of_sum, 348*6777b538SAndroid Build Coastguard Worker const size_t count) { 349*6777b538SAndroid Build Coastguard Worker return static_cast<ReturnType>( 350*6777b538SAndroid Build Coastguard Worker std::sqrt((static_cast<double>(sum_squares) - 351*6777b538SAndroid Build Coastguard Worker static_cast<double>(square_of_sum) / count) / 352*6777b538SAndroid Build Coastguard Worker count)); 353*6777b538SAndroid Build Coastguard Worker } 354*6777b538SAndroid Build Coastguard Worker }; 355*6777b538SAndroid Build Coastguard Worker 356*6777b538SAndroid Build Coastguard Worker // Class to compute square of the number. 357*6777b538SAndroid Build Coastguard Worker // General template 358*6777b538SAndroid Build Coastguard Worker template <typename T, typename SquareType> 359*6777b538SAndroid Build Coastguard Worker struct SquareInternal { ComputeSquareInternal360*6777b538SAndroid Build Coastguard Worker static SquareType Compute(const T& sample) { 361*6777b538SAndroid Build Coastguard Worker return static_cast<SquareType>(sample) * sample; 362*6777b538SAndroid Build Coastguard Worker } 363*6777b538SAndroid Build Coastguard Worker }; 364*6777b538SAndroid Build Coastguard Worker 365*6777b538SAndroid Build Coastguard Worker // Class to calculate moving deviation. 366*6777b538SAndroid Build Coastguard Worker template <typename T, typename SumType, bool IsFloating> 367*6777b538SAndroid Build Coastguard Worker class MovingDeviationBase { 368*6777b538SAndroid Build Coastguard Worker public: MovingDeviationBase(size_t window_size)369*6777b538SAndroid Build Coastguard Worker explicit MovingDeviationBase(size_t window_size) : sum_sq_() {} 370*6777b538SAndroid Build Coastguard Worker ~MovingDeviationBase() = default; AddSample(const T & sample,const T & replaced_value,bool is_last_idx)371*6777b538SAndroid Build Coastguard Worker void AddSample(const T& sample, const T& replaced_value, bool is_last_idx) { 372*6777b538SAndroid Build Coastguard Worker sum_sq_ += SquareInternal<T, SumType>::Compute(sample) - 373*6777b538SAndroid Build Coastguard Worker SquareInternal<T, SumType>::Compute(replaced_value); 374*6777b538SAndroid Build Coastguard Worker } 375*6777b538SAndroid Build Coastguard Worker 376*6777b538SAndroid Build Coastguard Worker template <typename ReturnType, typename U> Deviation(const size_t count,const U & sum)377*6777b538SAndroid Build Coastguard Worker ReturnType Deviation(const size_t count, const U& sum) const { 378*6777b538SAndroid Build Coastguard Worker if (count == 0) { 379*6777b538SAndroid Build Coastguard Worker return ReturnType(); 380*6777b538SAndroid Build Coastguard Worker } 381*6777b538SAndroid Build Coastguard Worker return DeivationInternal<SumType, ReturnType>::Compute( 382*6777b538SAndroid Build Coastguard Worker sum_sq_, SquareInternal<U, SumType>::Compute(sum), count); 383*6777b538SAndroid Build Coastguard Worker } Reset()384*6777b538SAndroid Build Coastguard Worker void Reset() { sum_sq_ = SumType(); } 385*6777b538SAndroid Build Coastguard Worker 386*6777b538SAndroid Build Coastguard Worker private: 387*6777b538SAndroid Build Coastguard Worker SumType sum_sq_; 388*6777b538SAndroid Build Coastguard Worker }; 389*6777b538SAndroid Build Coastguard Worker 390*6777b538SAndroid Build Coastguard Worker // Class to calculate moving deviation. 391*6777b538SAndroid Build Coastguard Worker // Variant for float types with running sum to avoid rounding errors 392*6777b538SAndroid Build Coastguard Worker // accumulation. 393*6777b538SAndroid Build Coastguard Worker template <typename T, typename SumType> 394*6777b538SAndroid Build Coastguard Worker class MovingDeviationBase<T, SumType, true> { 395*6777b538SAndroid Build Coastguard Worker public: MovingDeviationBase(size_t window_size)396*6777b538SAndroid Build Coastguard Worker explicit MovingDeviationBase(size_t window_size) 397*6777b538SAndroid Build Coastguard Worker : sum_sq_(), running_sum_() {} 398*6777b538SAndroid Build Coastguard Worker ~MovingDeviationBase() = default; AddSample(const T & sample,const T & replaced_value,bool is_last_idx)399*6777b538SAndroid Build Coastguard Worker void AddSample(const T& sample, const T& replaced_value, bool is_last_idx) { 400*6777b538SAndroid Build Coastguard Worker SumType square = SquareInternal<T, SumType>::Compute(sample); 401*6777b538SAndroid Build Coastguard Worker running_sum_ += square; 402*6777b538SAndroid Build Coastguard Worker if (is_last_idx) { 403*6777b538SAndroid Build Coastguard Worker // Replace sum with running sum to avoid rounding errors accumulation. 404*6777b538SAndroid Build Coastguard Worker sum_sq_ = running_sum_; 405*6777b538SAndroid Build Coastguard Worker running_sum_ = SumType(); 406*6777b538SAndroid Build Coastguard Worker } else { 407*6777b538SAndroid Build Coastguard Worker sum_sq_ += square - SquareInternal<T, SumType>::Compute(replaced_value); 408*6777b538SAndroid Build Coastguard Worker } 409*6777b538SAndroid Build Coastguard Worker } 410*6777b538SAndroid Build Coastguard Worker 411*6777b538SAndroid Build Coastguard Worker template <typename ReturnType, typename U> Deviation(const size_t count,const U & sum)412*6777b538SAndroid Build Coastguard Worker ReturnType Deviation(const size_t count, const U& sum) const { 413*6777b538SAndroid Build Coastguard Worker if (count == 0) { 414*6777b538SAndroid Build Coastguard Worker return ReturnType(); 415*6777b538SAndroid Build Coastguard Worker } 416*6777b538SAndroid Build Coastguard Worker return DeivationInternal<SumType, ReturnType>::Compute( 417*6777b538SAndroid Build Coastguard Worker sum_sq_, SquareInternal<U, SumType>::Compute(sum), count); 418*6777b538SAndroid Build Coastguard Worker } Reset()419*6777b538SAndroid Build Coastguard Worker void Reset() { running_sum_ = sum_sq_ = SumType(); } 420*6777b538SAndroid Build Coastguard Worker 421*6777b538SAndroid Build Coastguard Worker private: 422*6777b538SAndroid Build Coastguard Worker SumType sum_sq_; 423*6777b538SAndroid Build Coastguard Worker SumType running_sum_; 424*6777b538SAndroid Build Coastguard Worker }; 425*6777b538SAndroid Build Coastguard Worker 426*6777b538SAndroid Build Coastguard Worker // Null implementation of the above class to be used when feature is disabled. 427*6777b538SAndroid Build Coastguard Worker template <typename T> 428*6777b538SAndroid Build Coastguard Worker struct NullDeviationImpl { 429*6777b538SAndroid Build Coastguard Worker public: NullDeviationImplNullDeviationImpl430*6777b538SAndroid Build Coastguard Worker explicit NullDeviationImpl(size_t window_size) {} 431*6777b538SAndroid Build Coastguard Worker ~NullDeviationImpl() = default; AddSampleNullDeviationImpl432*6777b538SAndroid Build Coastguard Worker void AddSample(const T&, const T&, bool) {} ResetNullDeviationImpl433*6777b538SAndroid Build Coastguard Worker void Reset() {} 434*6777b538SAndroid Build Coastguard Worker }; 435*6777b538SAndroid Build Coastguard Worker 436*6777b538SAndroid Build Coastguard Worker // Template helpers. 437*6777b538SAndroid Build Coastguard Worker 438*6777b538SAndroid Build Coastguard Worker // Gets all enabled features in one struct. 439*6777b538SAndroid Build Coastguard Worker template <typename... Features> 440*6777b538SAndroid Build Coastguard Worker struct EnabledFeatures : public Features... {}; 441*6777b538SAndroid Build Coastguard Worker 442*6777b538SAndroid Build Coastguard Worker template <typename T> 443*6777b538SAndroid Build Coastguard Worker concept has_member_min = requires { T::has_min; }; 444*6777b538SAndroid Build Coastguard Worker 445*6777b538SAndroid Build Coastguard Worker template <typename T> 446*6777b538SAndroid Build Coastguard Worker concept has_member_max = requires { T::has_max; }; 447*6777b538SAndroid Build Coastguard Worker 448*6777b538SAndroid Build Coastguard Worker template <typename T> 449*6777b538SAndroid Build Coastguard Worker concept has_member_mean = requires { T::has_mean; }; 450*6777b538SAndroid Build Coastguard Worker 451*6777b538SAndroid Build Coastguard Worker template <typename T> 452*6777b538SAndroid Build Coastguard Worker concept has_member_deviation = requires { T::has_deviation; }; 453*6777b538SAndroid Build Coastguard Worker 454*6777b538SAndroid Build Coastguard Worker template <typename T> 455*6777b538SAndroid Build Coastguard Worker concept has_member_iteration = requires { T::has_iteration; }; 456*6777b538SAndroid Build Coastguard Worker 457*6777b538SAndroid Build Coastguard Worker // Gets the type of the member if present. 458*6777b538SAndroid Build Coastguard Worker // Can't just use decltype, because the member might be absent. 459*6777b538SAndroid Build Coastguard Worker template <typename T> 460*6777b538SAndroid Build Coastguard Worker struct get_type_mean { 461*6777b538SAndroid Build Coastguard Worker using type = void; 462*6777b538SAndroid Build Coastguard Worker }; 463*6777b538SAndroid Build Coastguard Worker template <typename T> 464*6777b538SAndroid Build Coastguard Worker requires has_member_mean<T> 465*6777b538SAndroid Build Coastguard Worker struct get_type_mean<T> { 466*6777b538SAndroid Build Coastguard Worker using type = decltype(T::has_mean); 467*6777b538SAndroid Build Coastguard Worker }; 468*6777b538SAndroid Build Coastguard Worker template <typename T> 469*6777b538SAndroid Build Coastguard Worker using mean_t = typename get_type_mean<T>::type; 470*6777b538SAndroid Build Coastguard Worker 471*6777b538SAndroid Build Coastguard Worker template <typename T> 472*6777b538SAndroid Build Coastguard Worker struct get_type_deviation { 473*6777b538SAndroid Build Coastguard Worker using type = void; 474*6777b538SAndroid Build Coastguard Worker }; 475*6777b538SAndroid Build Coastguard Worker template <typename T> 476*6777b538SAndroid Build Coastguard Worker requires has_member_deviation<T> 477*6777b538SAndroid Build Coastguard Worker struct get_type_deviation<T> { 478*6777b538SAndroid Build Coastguard Worker using type = decltype(T::has_deviation); 479*6777b538SAndroid Build Coastguard Worker }; 480*6777b538SAndroid Build Coastguard Worker template <typename T> 481*6777b538SAndroid Build Coastguard Worker using deviation_t = typename get_type_deviation<T>::type; 482*6777b538SAndroid Build Coastguard Worker 483*6777b538SAndroid Build Coastguard Worker // Performs division allowing the class to work with more types. 484*6777b538SAndroid Build Coastguard Worker // Specific template for TimeDelta. 485*6777b538SAndroid Build Coastguard Worker template <> 486*6777b538SAndroid Build Coastguard Worker struct DivideInternal<TimeDelta, TimeDelta> { 487*6777b538SAndroid Build Coastguard Worker static TimeDelta Compute(const TimeDelta& sum, const size_t count) { 488*6777b538SAndroid Build Coastguard Worker return sum / count; 489*6777b538SAndroid Build Coastguard Worker } 490*6777b538SAndroid Build Coastguard Worker }; 491*6777b538SAndroid Build Coastguard Worker 492*6777b538SAndroid Build Coastguard Worker // Computs main Deviation fromula, allowing the class to work with more types. 493*6777b538SAndroid Build Coastguard Worker // Deviation is equal to mean of squared values minus squared mean value. 494*6777b538SAndroid Build Coastguard Worker // Specific template for TimeDelta. 495*6777b538SAndroid Build Coastguard Worker template <> 496*6777b538SAndroid Build Coastguard Worker struct DeivationInternal<double, TimeDelta> { 497*6777b538SAndroid Build Coastguard Worker static TimeDelta Compute(const double sum_squares, 498*6777b538SAndroid Build Coastguard Worker const double square_of_sum, 499*6777b538SAndroid Build Coastguard Worker const size_t count) { 500*6777b538SAndroid Build Coastguard Worker return Seconds(std::sqrt((sum_squares - square_of_sum / count) / count)); 501*6777b538SAndroid Build Coastguard Worker } 502*6777b538SAndroid Build Coastguard Worker }; 503*6777b538SAndroid Build Coastguard Worker 504*6777b538SAndroid Build Coastguard Worker // Class to compute square of the number. 505*6777b538SAndroid Build Coastguard Worker // Specific template for TimeDelta. 506*6777b538SAndroid Build Coastguard Worker template <> 507*6777b538SAndroid Build Coastguard Worker struct SquareInternal<TimeDelta, double> { 508*6777b538SAndroid Build Coastguard Worker static double Compute(const TimeDelta& sample) { 509*6777b538SAndroid Build Coastguard Worker return sample.InSecondsF() * sample.InSecondsF(); 510*6777b538SAndroid Build Coastguard Worker } 511*6777b538SAndroid Build Coastguard Worker }; 512*6777b538SAndroid Build Coastguard Worker 513*6777b538SAndroid Build Coastguard Worker } // namespace internal 514*6777b538SAndroid Build Coastguard Worker 515*6777b538SAndroid Build Coastguard Worker // Implementation of the main class. 516*6777b538SAndroid Build Coastguard Worker template <typename T, typename... Features> 517*6777b538SAndroid Build Coastguard Worker class MovingWindow { 518*6777b538SAndroid Build Coastguard Worker public: 519*6777b538SAndroid Build Coastguard Worker // List of all requested features. 520*6777b538SAndroid Build Coastguard Worker using EnabledFeatures = internal::EnabledFeatures<Features...>; 521*6777b538SAndroid Build Coastguard Worker 522*6777b538SAndroid Build Coastguard Worker explicit MovingWindow(size_t window_size) 523*6777b538SAndroid Build Coastguard Worker : min_impl_(window_size), 524*6777b538SAndroid Build Coastguard Worker max_impl_(window_size), 525*6777b538SAndroid Build Coastguard Worker mean_impl_(window_size), 526*6777b538SAndroid Build Coastguard Worker deviation_impl_(window_size), 527*6777b538SAndroid Build Coastguard Worker window_impl_(window_size) {} 528*6777b538SAndroid Build Coastguard Worker 529*6777b538SAndroid Build Coastguard Worker // Adds sample to the window. 530*6777b538SAndroid Build Coastguard Worker void AddSample(const T& sample) { 531*6777b538SAndroid Build Coastguard Worker ++total_added_; 532*6777b538SAndroid Build Coastguard Worker min_impl_.AddSample(sample, total_added_); 533*6777b538SAndroid Build Coastguard Worker max_impl_.AddSample(sample, total_added_); 534*6777b538SAndroid Build Coastguard Worker mean_impl_.AddSample(sample, window_impl_.GetValue(), 535*6777b538SAndroid Build Coastguard Worker window_impl_.IsLastIdx()); 536*6777b538SAndroid Build Coastguard Worker deviation_impl_.AddSample(sample, window_impl_.GetValue(), 537*6777b538SAndroid Build Coastguard Worker window_impl_.IsLastIdx()); 538*6777b538SAndroid Build Coastguard Worker window_impl_.AddSample(sample); 539*6777b538SAndroid Build Coastguard Worker } 540*6777b538SAndroid Build Coastguard Worker 541*6777b538SAndroid Build Coastguard Worker // Returns amount of elementes so far in the stream (might be bigger than the 542*6777b538SAndroid Build Coastguard Worker // window size). 543*6777b538SAndroid Build Coastguard Worker size_t Count() const { return total_added_; } 544*6777b538SAndroid Build Coastguard Worker 545*6777b538SAndroid Build Coastguard Worker // Calculates min in the window. 546*6777b538SAndroid Build Coastguard Worker T Min() const 547*6777b538SAndroid Build Coastguard Worker requires internal::has_member_min<EnabledFeatures> 548*6777b538SAndroid Build Coastguard Worker { 549*6777b538SAndroid Build Coastguard Worker return min_impl_.Value(); 550*6777b538SAndroid Build Coastguard Worker } 551*6777b538SAndroid Build Coastguard Worker 552*6777b538SAndroid Build Coastguard Worker // Calculates max in the window. 553*6777b538SAndroid Build Coastguard Worker T Max() const 554*6777b538SAndroid Build Coastguard Worker requires internal::has_member_max<EnabledFeatures> 555*6777b538SAndroid Build Coastguard Worker { 556*6777b538SAndroid Build Coastguard Worker return max_impl_.Value(); 557*6777b538SAndroid Build Coastguard Worker } 558*6777b538SAndroid Build Coastguard Worker 559*6777b538SAndroid Build Coastguard Worker // Calculates mean in the window. 560*6777b538SAndroid Build Coastguard Worker // `ReturnType` can be used to adjust the type of the calculated mean value; 561*6777b538SAndroid Build Coastguard Worker // if not specified, uses `T` by default. 562*6777b538SAndroid Build Coastguard Worker template <typename ReturnType = T> 563*6777b538SAndroid Build Coastguard Worker requires internal::has_member_mean<EnabledFeatures> 564*6777b538SAndroid Build Coastguard Worker ReturnType Mean() const { 565*6777b538SAndroid Build Coastguard Worker return mean_impl_.template Mean<ReturnType>( 566*6777b538SAndroid Build Coastguard Worker std::min(total_added_, window_impl_.Size())); 567*6777b538SAndroid Build Coastguard Worker } 568*6777b538SAndroid Build Coastguard Worker 569*6777b538SAndroid Build Coastguard Worker // Calculates deviation in the window. 570*6777b538SAndroid Build Coastguard Worker // `ReturnType` can be used to adjust the type of the calculated deviation 571*6777b538SAndroid Build Coastguard Worker // value; if not specified, uses `T` by default. 572*6777b538SAndroid Build Coastguard Worker template <typename ReturnType = T> 573*6777b538SAndroid Build Coastguard Worker requires internal::has_member_deviation<EnabledFeatures> 574*6777b538SAndroid Build Coastguard Worker ReturnType Deviation() const { 575*6777b538SAndroid Build Coastguard Worker const size_t count = std::min(total_added_, window_impl_.Size()); 576*6777b538SAndroid Build Coastguard Worker return deviation_impl_.template Deviation<ReturnType>(count, 577*6777b538SAndroid Build Coastguard Worker mean_impl_.Sum()); 578*6777b538SAndroid Build Coastguard Worker } 579*6777b538SAndroid Build Coastguard Worker 580*6777b538SAndroid Build Coastguard Worker // Resets the state to an empty window. 581*6777b538SAndroid Build Coastguard Worker void Reset() { 582*6777b538SAndroid Build Coastguard Worker min_impl_.Reset(); 583*6777b538SAndroid Build Coastguard Worker max_impl_.Reset(); 584*6777b538SAndroid Build Coastguard Worker mean_impl_.Reset(); 585*6777b538SAndroid Build Coastguard Worker deviation_impl_.Reset(); 586*6777b538SAndroid Build Coastguard Worker window_impl_.Reset(); 587*6777b538SAndroid Build Coastguard Worker total_added_ = 0; 588*6777b538SAndroid Build Coastguard Worker } 589*6777b538SAndroid Build Coastguard Worker 590*6777b538SAndroid Build Coastguard Worker // iterator implementation. 591*6777b538SAndroid Build Coastguard Worker class iterator { 592*6777b538SAndroid Build Coastguard Worker public: 593*6777b538SAndroid Build Coastguard Worker ~iterator() = default; 594*6777b538SAndroid Build Coastguard Worker 595*6777b538SAndroid Build Coastguard Worker const T operator*() { 596*6777b538SAndroid Build Coastguard Worker DCHECK_LT(idx_, window_impl_->Size()); 597*6777b538SAndroid Build Coastguard Worker return (*window_impl_)[idx_]; 598*6777b538SAndroid Build Coastguard Worker } 599*6777b538SAndroid Build Coastguard Worker 600*6777b538SAndroid Build Coastguard Worker iterator& operator++() { 601*6777b538SAndroid Build Coastguard Worker ++idx_; 602*6777b538SAndroid Build Coastguard Worker // Wrap around the circular buffer. 603*6777b538SAndroid Build Coastguard Worker if (idx_ == window_impl_->Size()) { 604*6777b538SAndroid Build Coastguard Worker idx_ = 0; 605*6777b538SAndroid Build Coastguard Worker } 606*6777b538SAndroid Build Coastguard Worker // The only way to arrive to the current element is to 607*6777b538SAndroid Build Coastguard Worker // come around after iterating through the whole window. 608*6777b538SAndroid Build Coastguard Worker if (idx_ == window_impl_->CurIdx()) { 609*6777b538SAndroid Build Coastguard Worker idx_ = kInvalidIndex; 610*6777b538SAndroid Build Coastguard Worker } 611*6777b538SAndroid Build Coastguard Worker return *this; 612*6777b538SAndroid Build Coastguard Worker } 613*6777b538SAndroid Build Coastguard Worker 614*6777b538SAndroid Build Coastguard Worker bool operator==(const iterator& other) const { return idx_ == other.idx_; } 615*6777b538SAndroid Build Coastguard Worker 616*6777b538SAndroid Build Coastguard Worker private: 617*6777b538SAndroid Build Coastguard Worker iterator(const internal::MovingWindowBase<T>& window, size_t idx) 618*6777b538SAndroid Build Coastguard Worker : window_impl_(window), idx_(idx) {} 619*6777b538SAndroid Build Coastguard Worker 620*6777b538SAndroid Build Coastguard Worker static const size_t kInvalidIndex = std::numeric_limits<size_t>::max(); 621*6777b538SAndroid Build Coastguard Worker 622*6777b538SAndroid Build Coastguard Worker raw_ref<const internal::MovingWindowBase<T>> window_impl_; 623*6777b538SAndroid Build Coastguard Worker size_t idx_; 624*6777b538SAndroid Build Coastguard Worker 625*6777b538SAndroid Build Coastguard Worker friend class MovingWindow<T, Features...>; 626*6777b538SAndroid Build Coastguard Worker }; 627*6777b538SAndroid Build Coastguard Worker 628*6777b538SAndroid Build Coastguard Worker // Begin iterator. Template to enable only if iteration feature is requested. 629*6777b538SAndroid Build Coastguard Worker iterator begin() const 630*6777b538SAndroid Build Coastguard Worker requires internal::has_member_iteration<EnabledFeatures> 631*6777b538SAndroid Build Coastguard Worker { 632*6777b538SAndroid Build Coastguard Worker if (total_added_ == 0) { 633*6777b538SAndroid Build Coastguard Worker return end(); 634*6777b538SAndroid Build Coastguard Worker } 635*6777b538SAndroid Build Coastguard Worker // Before window is fully filled, the oldest element is at the index 0. 636*6777b538SAndroid Build Coastguard Worker size_t idx = 637*6777b538SAndroid Build Coastguard Worker (total_added_ < window_impl_.Size()) ? 0 : window_impl_.CurIdx(); 638*6777b538SAndroid Build Coastguard Worker 639*6777b538SAndroid Build Coastguard Worker return iterator(window_impl_, idx); 640*6777b538SAndroid Build Coastguard Worker } 641*6777b538SAndroid Build Coastguard Worker 642*6777b538SAndroid Build Coastguard Worker // End iterator. Template to enable only if iteration feature is requested. 643*6777b538SAndroid Build Coastguard Worker iterator end() const 644*6777b538SAndroid Build Coastguard Worker requires internal::has_member_iteration<EnabledFeatures> 645*6777b538SAndroid Build Coastguard Worker { 646*6777b538SAndroid Build Coastguard Worker return iterator(window_impl_, iterator::kInvalidIndex); 647*6777b538SAndroid Build Coastguard Worker } 648*6777b538SAndroid Build Coastguard Worker 649*6777b538SAndroid Build Coastguard Worker // Size of the collection. Template to enable only if iteration feature is 650*6777b538SAndroid Build Coastguard Worker // requested. 651*6777b538SAndroid Build Coastguard Worker size_t size() const 652*6777b538SAndroid Build Coastguard Worker requires internal::has_member_iteration<EnabledFeatures> 653*6777b538SAndroid Build Coastguard Worker { 654*6777b538SAndroid Build Coastguard Worker return std::min(total_added_, window_impl_.Size()); 655*6777b538SAndroid Build Coastguard Worker } 656*6777b538SAndroid Build Coastguard Worker 657*6777b538SAndroid Build Coastguard Worker private: 658*6777b538SAndroid Build Coastguard Worker // Member for calculating min. 659*6777b538SAndroid Build Coastguard Worker // Conditionally enabled on Min feature. 660*6777b538SAndroid Build Coastguard Worker std::conditional_t<internal::has_member_min<EnabledFeatures>, 661*6777b538SAndroid Build Coastguard Worker internal::MovingExtremumBase<T, std::greater<>>, 662*6777b538SAndroid Build Coastguard Worker internal::NullExtremumImpl<T>> 663*6777b538SAndroid Build Coastguard Worker min_impl_; 664*6777b538SAndroid Build Coastguard Worker 665*6777b538SAndroid Build Coastguard Worker // Member for calculating min. 666*6777b538SAndroid Build Coastguard Worker // Conditionally enabled on Min feature. 667*6777b538SAndroid Build Coastguard Worker std::conditional_t<internal::has_member_max<EnabledFeatures>, 668*6777b538SAndroid Build Coastguard Worker internal::MovingExtremumBase<T, std::less<>>, 669*6777b538SAndroid Build Coastguard Worker internal::NullExtremumImpl<T>> 670*6777b538SAndroid Build Coastguard Worker max_impl_; 671*6777b538SAndroid Build Coastguard Worker 672*6777b538SAndroid Build Coastguard Worker // Type for sum value in Mean implementation. Might need to reuse deviation 673*6777b538SAndroid Build Coastguard Worker // sum type, because enabling only deviation feature will also enable mean 674*6777b538SAndroid Build Coastguard Worker // member (because deviation calculation depends on mean calculation). 675*6777b538SAndroid Build Coastguard Worker using MeanSumType = 676*6777b538SAndroid Build Coastguard Worker std::conditional_t<internal::has_member_mean<EnabledFeatures>, 677*6777b538SAndroid Build Coastguard Worker internal::mean_t<EnabledFeatures>, 678*6777b538SAndroid Build Coastguard Worker internal::deviation_t<EnabledFeatures>>; 679*6777b538SAndroid Build Coastguard Worker // Member for calculating mean. 680*6777b538SAndroid Build Coastguard Worker // Conditionally enabled on Mean or Deviation feature (because deviation 681*6777b538SAndroid Build Coastguard Worker // calculation depends on mean calculation). 682*6777b538SAndroid Build Coastguard Worker std::conditional_t< 683*6777b538SAndroid Build Coastguard Worker internal::has_member_mean<EnabledFeatures> || 684*6777b538SAndroid Build Coastguard Worker internal::has_member_deviation<EnabledFeatures>, 685*6777b538SAndroid Build Coastguard Worker internal:: 686*6777b538SAndroid Build Coastguard Worker MovingMeanBase<T, MeanSumType, std::is_floating_point_v<MeanSumType>>, 687*6777b538SAndroid Build Coastguard Worker internal::NullMeanImpl<T>> 688*6777b538SAndroid Build Coastguard Worker mean_impl_; 689*6777b538SAndroid Build Coastguard Worker 690*6777b538SAndroid Build Coastguard Worker // Member for calculating deviation. 691*6777b538SAndroid Build Coastguard Worker // Conditionally enabled on Deviation feature. 692*6777b538SAndroid Build Coastguard Worker std::conditional_t< 693*6777b538SAndroid Build Coastguard Worker internal::has_member_deviation<EnabledFeatures>, 694*6777b538SAndroid Build Coastguard Worker internal::MovingDeviationBase< 695*6777b538SAndroid Build Coastguard Worker T, 696*6777b538SAndroid Build Coastguard Worker internal::deviation_t<EnabledFeatures>, 697*6777b538SAndroid Build Coastguard Worker std::is_floating_point_v<internal::deviation_t<EnabledFeatures>>>, 698*6777b538SAndroid Build Coastguard Worker internal::NullDeviationImpl<T>> 699*6777b538SAndroid Build Coastguard Worker deviation_impl_; 700*6777b538SAndroid Build Coastguard Worker 701*6777b538SAndroid Build Coastguard Worker // Member for storing the moving window. 702*6777b538SAndroid Build Coastguard Worker // Conditionally enabled on Mean, Deviation or Iteration feature since 703*6777b538SAndroid Build Coastguard Worker // they need the elements in the window. 704*6777b538SAndroid Build Coastguard Worker // Min and Max features store elements internally so they don't need this. 705*6777b538SAndroid Build Coastguard Worker std::conditional_t<internal::has_member_mean<EnabledFeatures> || 706*6777b538SAndroid Build Coastguard Worker internal::has_member_deviation<EnabledFeatures> || 707*6777b538SAndroid Build Coastguard Worker internal::has_member_iteration<EnabledFeatures>, 708*6777b538SAndroid Build Coastguard Worker internal::MovingWindowBase<T>, 709*6777b538SAndroid Build Coastguard Worker internal::NullWindowImpl<T>> 710*6777b538SAndroid Build Coastguard Worker window_impl_; 711*6777b538SAndroid Build Coastguard Worker // Total number of added elements. 712*6777b538SAndroid Build Coastguard Worker size_t total_added_ = 0; 713*6777b538SAndroid Build Coastguard Worker }; 714*6777b538SAndroid Build Coastguard Worker 715*6777b538SAndroid Build Coastguard Worker } // namespace base 716*6777b538SAndroid Build Coastguard Worker 717*6777b538SAndroid Build Coastguard Worker #endif // BASE_MOVING_WINDOW_H_ 718