#pragma once
|
|
|
|
#include "gp/algorithms/min_of.hpp"
|
|
#include "gp/containers/dynarray.hpp"
|
|
#include "gp/containers/vector.hpp"
|
|
#include "gp/functional/optional.hpp"
|
|
|
|
#include <stdint.h>
|
|
|
|
struct segment{
|
|
int16_t priority = 0;
|
|
gp::dynarray<char, 32> name;
|
|
gp::dynarray<char, gp_config::limits::loggers_segment_size> text;
|
|
};
|
|
|
|
struct virtual_logging_segment{
|
|
virtual size_t push_segment(gp::buffer<char> name, gp::buffer<char> text, int16_t prio = 0) = 0;
|
|
virtual void set_segment(gp::buffer<char> name, gp::buffer<char> text, int16_t prio = 0) = 0;
|
|
virtual gp::optional<gp::reference_wrapper<segment>> get_segment(gp::buffer<char> name) = 0;
|
|
virtual size_t size() = 0;
|
|
virtual segment& get_segment_by_idx(size_t) = 0;
|
|
virtual void clear() = 0;
|
|
};
|
|
|
|
|
|
template<size_t capacity>
|
|
struct static_logging_segment : virtual_logging_segment{
|
|
gp::dynarray<segment, capacity> data;
|
|
gp::optional<size_t> wrap_around;
|
|
gp::function<void(virtual_logging_segment&)> on_destruct = +[](virtual_logging_segment&){};
|
|
|
|
~static_logging_segment() {
|
|
on_destruct(*this);
|
|
}
|
|
|
|
segment prepare_segment(gp::buffer<char> name, gp::buffer<char> text, int prio = 0) {
|
|
segment prepared;
|
|
prepared.priority = prio;
|
|
{
|
|
auto it = name.begin();
|
|
auto end = name.begin()+gp::min(name.size(), prepared.name.capacity());
|
|
while(it != end) {
|
|
prepared.name.push_back(*it);
|
|
++it;
|
|
}
|
|
}
|
|
{
|
|
auto it = text.begin();
|
|
auto end = text.begin()+gp::min(text.size(), prepared.text.capacity());
|
|
while(it != end) {
|
|
prepared.text.push_back(*it);
|
|
++it;
|
|
}
|
|
if(text.size()>prepared.text.capacity()) {
|
|
auto it = prepared.text.rbegin();
|
|
*it = '.'; ++it;
|
|
*it = '.'; ++it;
|
|
*it = '.';
|
|
}
|
|
}
|
|
|
|
return prepared;
|
|
}
|
|
|
|
virtual size_t push_segment(gp::buffer<char> name, gp::buffer<char> text, int16_t prio = 0) {
|
|
auto prepared = prepare_segment(name, text, prio);
|
|
|
|
if(wrap_around.has_value()) {
|
|
size_t idx = wrap_around.value();
|
|
size_t override_prio = gp::min_of(data.begin(), data.end(), [](auto v){ return v.priority; });
|
|
while(true) {
|
|
if(data[idx].priority == override_prio) {
|
|
data[idx] = prepared;
|
|
break;
|
|
}
|
|
idx = (++idx) % data.size();
|
|
}
|
|
idx = (++idx) % data.size();
|
|
wrap_around = idx;
|
|
return idx-1;
|
|
} else {
|
|
data.push_back(prepared);
|
|
return data.size()-1;
|
|
}
|
|
}
|
|
virtual void set_segment(gp::buffer<char> name, gp::buffer<char> text, int16_t prio = 0) {
|
|
auto prepared = prepare_segment(name, text, prio);
|
|
|
|
if(auto seg = get_segment(name); seg.has_value()) {
|
|
seg.value() = prepared;
|
|
} else {
|
|
data.push_back(prepared);
|
|
}
|
|
}
|
|
virtual gp::optional<gp::reference_wrapper<segment>> get_segment(gp::buffer<char> name) {
|
|
decltype(segment{}.name) tname;
|
|
auto it = name.begin();
|
|
auto end = name.begin()+gp::min(name.size(), tname.capacity());
|
|
while(it != end) {
|
|
tname.push_back(*it);
|
|
++it;
|
|
}
|
|
|
|
for(auto& elem : data) {
|
|
if(elem.name == tname) {
|
|
return gp::reference_wrapper<segment>(elem);
|
|
}
|
|
}
|
|
return gp::nullopt;
|
|
}
|
|
virtual size_t size() {
|
|
return data.size();
|
|
}
|
|
virtual segment& get_segment_by_idx(size_t idx) {
|
|
return data[idx];
|
|
}
|
|
|
|
virtual void clear() {
|
|
data.~dynarray();
|
|
new(&data) decltype(data){};
|
|
}
|
|
};
|
|
|
|
/*struct dynamic_logging_segment{
|
|
|
|
};*/
|