xref: /aosp_15_r20/external/cronet/base/moving_window.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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