2026-07-18 14:31:15 +02:00
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "common.hpp"
|
|
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stores history of a property for data analysis
|
|
|
|
|
*/
|
|
|
|
|
template<typename TKey, typename TValue>
|
|
|
|
|
class HistoryBuffer {
|
|
|
|
|
private:
|
|
|
|
|
size_t m_head, m_tail;
|
|
|
|
|
std::vector<std::pair<TKey, TValue>> 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<const TValue*> get(TKey key) const {
|
2026-07-22 17:34:44 +02:00
|
|
|
for(size_t i = m_tail; i != m_head; i = (i + 1) % max_size()) {
|
2026-07-18 14:31:15 +02:00
|
|
|
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) {
|
2026-07-22 17:34:44 +02:00
|
|
|
// 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) {
|
2026-07-18 14:31:15 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-22 17:34:44 +02:00
|
|
|
size_t i = (m_tail + 1) % max_size();
|
2026-07-18 14:31:15 +02:00
|
|
|
if(m_tail != m_head) {
|
2026-07-22 17:34:44 +02:00
|
|
|
for(i = (m_tail + 1) % max_size(); i != m_head; i = (i + 1) % max_size()) {
|
2026-07-18 14:31:15 +02:00
|
|
|
if(m_buffer.at(i).first > key) {
|
2026-07-22 17:34:44 +02:00
|
|
|
m_buffer[(i - 1 + max_size()) % max_size()] = std::make_pair(key, value);
|
|
|
|
|
m_head = (m_head + 1) % max_size();
|
2026-07-18 14:31:15 +02:00
|
|
|
return true;
|
|
|
|
|
} else {
|
2026-07-22 17:34:44 +02:00
|
|
|
m_buffer[(i - 1 + max_size()) % max_size()] = m_buffer[i];
|
2026-07-18 14:31:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-22 17:34:44 +02:00
|
|
|
m_buffer[(i - 1 + max_size()) % max_size()] = std::make_pair(key, value);
|
2026-07-18 14:31:15 +02:00
|
|
|
m_head = (m_head + 1) % max_size();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
};
|