DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (b6057e17f856)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
/* -*- Mode: C++; tab-w idth: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 / 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_