1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/RollingMean.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,109 @@ 1.4 +/* -*- Mode: C++; tab-w idth: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* A set abstraction for enumeration values. */ 1.10 + 1.11 +#ifndef mozilla_RollingMean_h_ 1.12 +#define mozilla_RollingMean_h_ 1.13 + 1.14 +#include "mozilla/Assertions.h" 1.15 +#include "mozilla/TypeTraits.h" 1.16 +#include "mozilla/Vector.h" 1.17 + 1.18 +#include <algorithm> 1.19 +#include <stddef.h> 1.20 +#include <stdint.h> 1.21 + 1.22 +namespace mozilla { 1.23 + 1.24 +/** 1.25 + * RollingMean<T> calculates a rolling mean of the values it is given. It 1.26 + * accumulates the total as values are added and removed. The second type 1.27 + * argument S specifies the type of the total. This may need to be a bigger 1.28 + * type in order to maintain that the sum of all values in the average doesn't 1.29 + * exceed the maximum input value. 1.30 + * 1.31 + * WARNING: Float types are not supported due to rounding errors. 1.32 + */ 1.33 +template<typename T, typename S> 1.34 +class RollingMean 1.35 +{ 1.36 + private: 1.37 + size_t mInsertIndex; 1.38 + size_t mMaxValues; 1.39 + Vector<T> mValues; 1.40 + S mTotal; 1.41 + 1.42 + public: 1.43 + static_assert(!IsFloatingPoint<T>::value, 1.44 + "floating-point types are unsupported due to rounding " 1.45 + "errors"); 1.46 + 1.47 + RollingMean(size_t aMaxValues) 1.48 + : mInsertIndex(0), 1.49 + mMaxValues(aMaxValues), 1.50 + mTotal(0) 1.51 + { 1.52 + MOZ_ASSERT(aMaxValues > 0); 1.53 + } 1.54 + 1.55 + RollingMean& operator=(RollingMean&& aOther) { 1.56 + MOZ_ASSERT(this != &aOther, "self-assignment is forbidden"); 1.57 + this->~RollingMean(); 1.58 + new(this) RollingMean(aOther.mMaxValues); 1.59 + mInsertIndex = aOther.mInsertIndex; 1.60 + mTotal = aOther.mTotal; 1.61 + mValues.swap(aOther.mValues); 1.62 + return *this; 1.63 + } 1.64 + 1.65 + /** 1.66 + * Insert a value into the rolling mean. 1.67 + */ 1.68 + bool insert(T aValue) { 1.69 + MOZ_ASSERT(mValues.length() <= mMaxValues); 1.70 + 1.71 + if (mValues.length() == mMaxValues) { 1.72 + mTotal = mTotal - mValues[mInsertIndex] + aValue; 1.73 + mValues[mInsertIndex] = aValue; 1.74 + } else { 1.75 + if (!mValues.append(aValue)) 1.76 + return false; 1.77 + mTotal = mTotal + aValue; 1.78 + } 1.79 + 1.80 + mInsertIndex = (mInsertIndex + 1) % mMaxValues; 1.81 + return true; 1.82 + } 1.83 + 1.84 + /** 1.85 + * Calculate the rolling mean. 1.86 + */ 1.87 + T mean() { 1.88 + MOZ_ASSERT(!empty()); 1.89 + return T(mTotal / mValues.length()); 1.90 + } 1.91 + 1.92 + bool empty() { 1.93 + return mValues.empty(); 1.94 + } 1.95 + 1.96 + /** 1.97 + * Remove all values from the rolling mean. 1.98 + */ 1.99 + void clear() { 1.100 + mValues.clear(); 1.101 + mInsertIndex = 0; 1.102 + mTotal = T(0); 1.103 + } 1.104 + 1.105 + size_t maxValues() { 1.106 + return mMaxValues; 1.107 + } 1.108 +}; 1.109 + 1.110 +} // namespace mozilla 1.111 + 1.112 +#endif // mozilla_RollingMean_h_