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