#pragma once #include "gp/algorithms/min_of.hpp" #include "gp/containers/dynarray.hpp" #include "gp/containers/vector.hpp" #include "gp/functional/optional.hpp" #include struct segment{ int16_t priority = 0; gp::dynarray name; gp::dynarray text; }; struct virtual_logging_segment{ virtual size_t push_segment(gp::buffer name, gp::buffer text, int16_t prio = 0) = 0; virtual void set_segment(gp::buffer name, gp::buffer text, int16_t prio = 0) = 0; virtual gp::optional> get_segment(gp::buffer name) = 0; virtual size_t size() = 0; virtual segment& get_segment_by_idx(size_t) = 0; virtual void clear() = 0; }; template struct static_logging_segment : virtual_logging_segment{ gp::dynarray data; gp::optional wrap_around; gp::function on_destruct = +[](virtual_logging_segment&){}; ~static_logging_segment() { on_destruct(*this); } segment prepare_segment(gp::buffer name, gp::buffer 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 name, gp::buffer 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 name, gp::buffer 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> get_segment(gp::buffer 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(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{ };*/