michael@0: /* -*- Mode: C++; tab-w idth: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* A set abstraction for enumeration values. */ michael@0: michael@0: #ifndef mozilla_RollingMean_h_ michael@0: #define mozilla_RollingMean_h_ michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/TypeTraits.h" michael@0: #include "mozilla/Vector.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * RollingMean calculates a rolling mean of the values it is given. It michael@0: * accumulates the total as values are added and removed. The second type michael@0: * argument S specifies the type of the total. This may need to be a bigger michael@0: * type in order to maintain that the sum of all values in the average doesn't michael@0: * exceed the maximum input value. michael@0: * michael@0: * WARNING: Float types are not supported due to rounding errors. michael@0: */ michael@0: template michael@0: class RollingMean michael@0: { michael@0: private: michael@0: size_t mInsertIndex; michael@0: size_t mMaxValues; michael@0: Vector mValues; michael@0: S mTotal; michael@0: michael@0: public: michael@0: static_assert(!IsFloatingPoint::value, michael@0: "floating-point types are unsupported due to rounding " michael@0: "errors"); michael@0: michael@0: RollingMean(size_t aMaxValues) michael@0: : mInsertIndex(0), michael@0: mMaxValues(aMaxValues), michael@0: mTotal(0) michael@0: { michael@0: MOZ_ASSERT(aMaxValues > 0); michael@0: } michael@0: michael@0: RollingMean& operator=(RollingMean&& aOther) { michael@0: MOZ_ASSERT(this != &aOther, "self-assignment is forbidden"); michael@0: this->~RollingMean(); michael@0: new(this) RollingMean(aOther.mMaxValues); michael@0: mInsertIndex = aOther.mInsertIndex; michael@0: mTotal = aOther.mTotal; michael@0: mValues.swap(aOther.mValues); michael@0: return *this; michael@0: } michael@0: michael@0: /** michael@0: * Insert a value into the rolling mean. michael@0: */ michael@0: bool insert(T aValue) { michael@0: MOZ_ASSERT(mValues.length() <= mMaxValues); michael@0: michael@0: if (mValues.length() == mMaxValues) { michael@0: mTotal = mTotal - mValues[mInsertIndex] + aValue; michael@0: mValues[mInsertIndex] = aValue; michael@0: } else { michael@0: if (!mValues.append(aValue)) michael@0: return false; michael@0: mTotal = mTotal + aValue; michael@0: } michael@0: michael@0: mInsertIndex = (mInsertIndex + 1) % mMaxValues; michael@0: return true; michael@0: } michael@0: michael@0: /** michael@0: * Calculate the rolling mean. michael@0: */ michael@0: T mean() { michael@0: MOZ_ASSERT(!empty()); michael@0: return T(mTotal / mValues.length()); michael@0: } michael@0: michael@0: bool empty() { michael@0: return mValues.empty(); michael@0: } michael@0: michael@0: /** michael@0: * Remove all values from the rolling mean. michael@0: */ michael@0: void clear() { michael@0: mValues.clear(); michael@0: mInsertIndex = 0; michael@0: mTotal = T(0); michael@0: } michael@0: michael@0: size_t maxValues() { michael@0: return mMaxValues; michael@0: } michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_RollingMean_h_