mfbt/RollingMean.h

changeset 0
6474c204b198
     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_

mercurial