/* * 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 https://mozilla.org/MPL/2.0/. */ #pragma once #include "Data/Containers/RingBuffer.hpp" #include #include namespace OpenVulkano::Math { template concept SupportsRunningAverage = requires(T a, T b, int64_t size) { { a += b } -> std::same_as; { a -= b } -> std::same_as; { a * size } -> std::convertible_to; { a / size } -> std::convertible_to; }; template, size_t RECALC_OP_COUNT = 100> requires SupportsRunningAverage class RunningAverage final { struct Empty {}; RingBuffer m_buffer; T m_value; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-attributes" [[no_unique_address]] [[msvc::no_unique_address]] std::conditional_t m_operations; #pragma clang diagnostic pop public: RunningAverage(size_t size) requires (std::is_default_constructible_v && SIZE == RING_BUFFER_DYNAMIC) : m_buffer(size), m_value(T() * static_cast(size)) { assert(size > 0); m_buffer.Fill(T()); if constexpr (RECALC) m_operations = 0; } RunningAverage(size_t size, const T& def) requires (SIZE == RING_BUFFER_DYNAMIC) : m_buffer(size), m_value(def * static_cast(size)) { assert(size > 0); m_buffer.Fill(def); if constexpr (RECALC) m_operations = 0; } RunningAverage() requires (std::is_default_constructible_v && SIZE != RING_BUFFER_DYNAMIC) : m_value(T() * static_cast(SIZE)) { static_assert(SIZE > 0); m_buffer.Fill(T()); if constexpr (RECALC) m_operations = 0; } RunningAverage(const T& def) requires (SIZE != RING_BUFFER_DYNAMIC) : m_value(def * static_cast(SIZE)) { static_assert(SIZE > 0); m_buffer.Fill(def); if constexpr (RECALC) m_operations = 0; } void Push(const T& value) { m_value -= m_buffer.PushAndOverwrite(value); m_value += value; if constexpr (RECALC) { if (++m_operations >= RECALC_OP_COUNT) { m_operations = 0; Recalculate(); } } } [[nodiscard]] T Get() const { return m_value / static_cast(m_buffer.Size()); } void Recalculate() { m_value = m_buffer[0]; auto it = m_buffer.cbegin(); it++; for(auto end = m_buffer.cend(); it != end; it++) { m_value += *it; } } }; }