Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions cli/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ Config::Config(int argc, char *argv[])
bool show_help{}, show_version{};
auto cli_head = (
clipp::option("-h", "--help").set(show_help).doc("This help"),
clipp::option("-V", "--version").set(show_version).doc("Version"),
clipp::option("-V", "--version").set(show_version).doc("Version")
);
auto cli_mod = "Run modifiers:" % (
clipp::option("-v", "--verbose").call([]{
spdlog::set_level(spdlog::level::debug);
}).doc("Enable verbose output"),
Expand All @@ -35,9 +37,9 @@ Config::Config(int argc, char *argv[])
.doc("Display interval in seconds")
);

auto cli_output = "Output:" % (
clipp::option("-A", "--ascii").set(m_output_type,ASCII).doc("ASCII output") |
clipp::option("-U", "--unicode").set(m_output_type,UNICODE).doc("Unicode output") |
auto cli_output = "Output:" % one_of (
clipp::option("-A", "--ascii").set(m_output_type,ASCII).doc("ASCII output"),
clipp::option("-U", "--unicode").set(m_output_type,UNICODE).doc("Unicode output"),
clipp::option("-B", "--braille").set(m_output_type,BRAILLE).doc("Braille output")
);

Expand All @@ -53,6 +55,7 @@ Config::Config(int argc, char *argv[])

auto cli = (
cli_head | (
cli_mod,
cli_output,
clipp::repeatable(
/* select a plot type */
Expand Down Expand Up @@ -98,8 +101,10 @@ Config::Config(int argc, char *argv[])
.doc("Find numbers in input line, pick 1 or 2 positions for X and Y values"),
(clipp::option("-r", "--regex") & clipp::value("regex")
.call([&](const char *txt) { m_inputs.back().set_regex(txt); }))
.doc("Regex to match numbers from input line")

.doc("Regex to match numbers from input line"),
(clipp::option("-l", "--limit") & clipp::value("count")
.call([&](const char *txt) { m_inputs.back().set_data_limit(txt); }))
.doc("How many historical values to retain for plotting")
),

"Plot modifiers:" % (
Expand Down Expand Up @@ -169,6 +174,7 @@ Config::Config(int argc, char *argv[])

bool with_interval{}, no_interval{};
double prev_interval = 1;
size_t prev_data_limit = Input::g_default_data_limit;
for (auto &input : m_inputs) {
if (input.needs_interval()) {
if (!input.interval()) {
Expand All @@ -177,6 +183,11 @@ Config::Config(int argc, char *argv[])
prev_interval = input.interval();
}
}
if (!input.data_limit()) {
input.set_data_limit(prev_data_limit);
} else {
prev_data_limit = input.data_limit();
}
if (!input) {
spdlog::error("incomplete plot definition");
std::exit(1);
Expand Down Expand Up @@ -316,6 +327,19 @@ void Input::set_interval (const std::string &txt)
std::exit(1);
}
}
void Input::set_data_limit (size_t value)
{
m_data_limit = value;
}
void Input::set_data_limit (const std::string &txt)
{
auto [_,ec] = std::from_chars(txt.data(), txt.data()+txt.size(), m_data_limit);
if (ec != std::errc{}) {
spdlog::error("failed to parse data limit from '{}': {}",
txt, std::make_error_code(ec).message());
std::exit(1);
}
}

Input::operator bool() const
{
Expand Down
14 changes: 12 additions & 2 deletions cli/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ class Input final {
WATCH // run program repetitively at interval, each run is one entry
};

static constexpr const size_t g_default_data_limit = 1000000;

protected:
blot_plot_type m_plot_type{BLOT_LINE};
Source m_source{NONE};
std::string m_details{};
Extract m_extract;
blot_color m_plot_color;
double m_interval{0};
size_t m_data_limit{g_default_data_limit};

public:
explicit Input(blot_plot_type plot_type, blot_color color)
Expand Down Expand Up @@ -63,6 +66,7 @@ class Input final {
const Extract& extract() const { return m_extract; }
blot_color plot_color() const { return m_plot_color; }
double interval() const { return m_interval; }
size_t data_limit() const { return m_data_limit; }

/* validate if the configuration looks sane */
operator bool() const;
Expand All @@ -73,14 +77,19 @@ class Input final {
void set_color (const std::string &txt);
void set_interval (double interval);
void set_interval (const std::string &txt);
void set_data_limit (size_t);
void set_data_limit (const std::string &txt);


};

class Config final {
public:
using OutputType = enum output_type { ASCII, UNICODE, BRAILLE };

protected:
const char *m_self{};
enum output_type { ASCII, UNICODE, BRAILLE } m_output_type;
OutputType m_output_type;
const static blot_color m_first_color{9};
std::vector<Input> m_inputs;
bool m_display_interval{1};
Expand All @@ -100,8 +109,9 @@ class Config final {
}
}

size_t inputs() const { return m_inputs.size(); }
OutputType output_type() const { return m_output_type; }

size_t inputs() const { return m_inputs.size(); }
const Input& input(size_t n) const { return m_inputs.at(n); }
Input& input(size_t n) { return m_inputs.at(n); }

Expand Down
65 changes: 60 additions & 5 deletions cli/plotter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,49 @@
template <typename X, typename Y>
class Plotter final {
protected:
template <typename T>
class Storage {
protected:
std::vector<T> m_data;
size_t m_offset{};

void relocation_check() {
bool full = m_data.size() == m_data.capacity();
if (full && m_offset && m_offset > (m_data.capacity()/2)) {
// full but most is empty, so we should relocate the data
m_data.erase(m_data.begin(), m_data.begin() + m_offset);
m_offset = 0;
}
}

public:
void push_back(const T &v) {
relocation_check();
m_data.push_back(v);
}

void erase_front(size_t count = 1) {
if (count > size())
BLOT_THROW(ERANGE, "count=%zu exceeds size=%zu", count, size());
m_offset += count;
}

T* data() noexcept { return m_data.data() + m_offset; }
const T* data() const noexcept { return m_data.data() + m_offset; }
size_t size() const { return m_data.size() - m_offset; }

std::span<T> span() {
return std::span<const T>(data(), size());
}
std::span<const T> span() const {
return std::span<const T>(data(), size());
}

};

struct Data {
std::vector<X> m_xs;
std::vector<Y> m_ys;
Storage<X> m_xs;
Storage<Y> m_ys;
};
std::vector<Data> m_data;
size_t m_count{};
Expand Down Expand Up @@ -41,6 +81,11 @@ class Plotter final {
m_data[layer].m_xs.push_back(x);
m_data[layer].m_ys.push_back(y);
m_count ++;

if (m_data[layer].m_xs.size() > m_config.input(layer).data_limit()) {
m_data[layer].m_xs.erase_front();
m_data[layer].m_ys.erase_front();
}
}

bool have_data() const { return m_count > 0; }
Expand All @@ -67,17 +112,27 @@ class Plotter final {
const auto &data = m_data[i];
const auto &input = m_config.input(i);

fig.plot(input.plot_type(), data.m_xs, data.m_ys,
fig.plot(input.plot_type(), data.m_xs.span(), data.m_ys.span(),
input.plot_color(), input.details());
}

double t_add = timing ? blot_double_time() : 0;

blot_render_flags flags
= BLOT_RENDER_BRAILLE
| BLOT_RENDER_LEGEND_BELOW
= BLOT_RENDER_LEGEND_BELOW
| BLOT_RENDER_CLEAR;

switch (m_config.output_type()) {
case Config::ASCII:
flags = flags | BLOT_RENDER_NO_UNICODE;
break;
case Config::BRAILLE:
flags = flags | BLOT_RENDER_BRAILLE;
break;
default: // UNICODE
break;
}

if (timing)
flags = flags | BLOT_RENDER_LEGEND_DETAILS;

Expand Down
21 changes: 15 additions & 6 deletions include/blot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <cassert>
#include <iostream>
#include <span>
#include <stdexcept>
#include <algorithm>
#include <utility>
Expand Down Expand Up @@ -86,15 +87,15 @@ class Exception final : public std::exception {

template <typename T>
constexpr blot_data_type data_type() {
if constexpr (std::is_same_v<T, int16_t>)
if constexpr (std::is_same_v<std::remove_const_t<T>, int16_t>)
return BLOT_DATA_INT16;
else if constexpr (std::is_same_v<T, int32_t>)
else if constexpr (std::is_same_v<std::remove_const_t<T>, int32_t>)
return BLOT_DATA_INT32;
else if constexpr (std::is_same_v<T, int64_t>)
else if constexpr (std::is_same_v<std::remove_const_t<T>, int64_t>)
return BLOT_DATA_INT64;
else if constexpr (std::is_same_v<T, float>)
else if constexpr (std::is_same_v<std::remove_const_t<T>, float>)
return BLOT_DATA_FLOAT;
else if constexpr (std::is_same_v<T, double>)
else if constexpr (std::is_same_v<std::remove_const_t<T>, double>)
return BLOT_DATA_DOUBLE;
else
BLOT_THROW(EINVAL, "unsupported type");
Expand Down Expand Up @@ -184,7 +185,7 @@ struct Figure final : public blot_figure {
/* add layers */

template <typename T, typename U>
void plot(blot_plot_type plot_type, const std::vector<T> &data_xs, const std::vector<U> &data_ys, blot_color data_color, const char *data_label) {
void plot(blot_plot_type plot_type, const std::span<T> &data_xs, const std::span<U> &data_ys, blot_color data_color, const char *data_label) {
GError *error = nullptr;
size_t data_count = data_ys.size();

Expand All @@ -206,6 +207,14 @@ struct Figure final : public blot_figure {
}
}

template <typename T, typename U>
void plot(blot_plot_type plot_type, const std::vector<T> &data_xs, const std::vector<U> &data_ys, blot_color data_color, const char *data_label) {
plot(plot_type,
std::span<const T>(data_xs.data(), data_xs.size()),
std::span<const U>(data_ys.data(), data_ys.size()),
data_color, data_label);
}

template <typename T, typename U>
void scatter(const std::vector<T> &data_xs, const std::vector<U>& data_ys, blot_color data_color, const char *data_label) {
plot(BLOT_SCATTER, data_xs, data_ys, data_color, data_label);
Expand Down