#pragma once #include "common.hpp" #include #include #include /** * Stores history of a property for data analysis */ template class HistoryBuffer { private: size_t m_head, m_tail; std::vector> m_buffer; public: size_t size() const { if(m_tail > m_head) { return max_size() - m_tail + m_head; } return (m_head - m_tail) % max_size(); } size_t max_size() const { return m_buffer.size(); } bool is_full(float percentage) { return size() / (float)max_size() > percentage; } void clear() { m_tail = m_head = 0; } GET_REF(m_buffer, buffer); HistoryBuffer(TKey default_key, TValue&& default_value, size_t size) : m_head(0), m_tail(0), m_buffer(size) { } std::optional get(TKey key) const { for(size_t i = m_tail; i != m_head; i = (i + 1) % max_size()) { if(m_buffer[i].first > key) { return {}; } if(m_buffer[i].first == key) { return &m_buffer[i].second; } } return {}; } bool set(TKey key, const TValue& value) { // If buffer has entries and key is older than the oldest, reject it if(m_tail != m_head && key < m_buffer.at(m_tail).first) { return false; } size_t i = (m_tail + 1) % max_size(); if(m_tail != m_head) { for(i = (m_tail + 1) % max_size(); i != m_head; i = (i + 1) % max_size()) { if(m_buffer.at(i).first > key) { m_buffer[(i - 1 + max_size()) % max_size()] = std::make_pair(key, value); m_head = (m_head + 1) % max_size(); return true; } else { m_buffer[(i - 1 + max_size()) % max_size()] = m_buffer[i]; } } } m_buffer[(i - 1 + max_size()) % max_size()] = std::make_pair(key, value); m_head = (m_head + 1) % max_size(); return true; } };