General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

140 lines
4.1 KiB

#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>
#include <string>
#include <sstream>
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&){}, gp::nullopt};
~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(data.size() == data.capacity()) {
wrap_around = 0;
}
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(prio >= override_prio) {
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);
auto seg = get_segment(prepared.name.as_buffer());
if(seg.has_value()) {
seg.value().get() = prepared;
return;
}
push_segment(prepared.name.as_buffer(), prepared.text.as_buffer(), prepared.priority);
}
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{
};*/