// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/power_monitor/moving_average.h"

#include <algorithm>
#include <limits>

#include "base/check_op.h"
#include "base/numerics/clamped_math.h"

namespace {
constexpr int kIntMax = std::numeric_limits<int>::max();
constexpr int64_t kInt64Max = std::numeric_limits<int64_t>::max();
}  // namespace

namespace base {

MovingAverage::MovingAverage(uint8_t window_size)
    : window_size_(window_size), buffer_(window_size, 0) {
  DCHECK_LE(kIntMax * window_size, kInt64Max);
}

MovingAverage::~MovingAverage() = default;

void MovingAverage::AddSample(int sample) {
  sum_ -= buffer_[index_];
  buffer_[index_++] = sample;
  sum_ += sample;
  if (index_ == window_size_) {
    full_ = true;
    index_ = 0;
  }
}

int MovingAverage::GetAverageRoundedDown() const {
  if (Size() == 0 || uint64_t{Size()} > static_cast<uint64_t>(kInt64Max)) {
    return 0;
  }
  return static_cast<int>(sum_ / static_cast<int64_t>(Size()));
}

int MovingAverage::GetAverageRoundedToClosest() const {
  if (Size() == 0 || uint64_t{Size()} > static_cast<uint64_t>(kInt64Max))
    return 0;
  return static_cast<int>((base::ClampedNumeric<int64_t>(sum_) + Size() / 2) /
                          static_cast<int64_t>(Size()));
}

double MovingAverage::GetUnroundedAverage() const {
  if (Size() == 0)
    return 0;
  return sum_ / static_cast<double>(Size());
}

void MovingAverage::Reset() {
  std::fill(buffer_.begin(), buffer_.end(), 0);
  sum_ = 0;
  index_ = 0;
  full_ = false;
}

size_t MovingAverage::Size() const {
  return full_ ? window_size_ : index_;
}
}  // namespace base