Skip to content

Commit ee628a1

Browse files
authored
Merge pull request #13 from bartman/cli
blot cli fixes and improvements
2 parents d721457 + 97e1f15 commit ee628a1

File tree

4 files changed

+117
-19
lines changed

4 files changed

+117
-19
lines changed

cli/config.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ Config::Config(int argc, char *argv[])
2222
bool show_help{}, show_version{};
2323
auto cli_head = (
2424
clipp::option("-h", "--help").set(show_help).doc("This help"),
25-
clipp::option("-V", "--version").set(show_version).doc("Version"),
25+
clipp::option("-V", "--version").set(show_version).doc("Version")
26+
);
27+
auto cli_mod = "Run modifiers:" % (
2628
clipp::option("-v", "--verbose").call([]{
2729
spdlog::set_level(spdlog::level::debug);
2830
}).doc("Enable verbose output"),
@@ -35,9 +37,9 @@ Config::Config(int argc, char *argv[])
3537
.doc("Display interval in seconds")
3638
);
3739

38-
auto cli_output = "Output:" % (
39-
clipp::option("-A", "--ascii").set(m_output_type,ASCII).doc("ASCII output") |
40-
clipp::option("-U", "--unicode").set(m_output_type,UNICODE).doc("Unicode output") |
40+
auto cli_output = "Output:" % one_of (
41+
clipp::option("-A", "--ascii").set(m_output_type,ASCII).doc("ASCII output"),
42+
clipp::option("-U", "--unicode").set(m_output_type,UNICODE).doc("Unicode output"),
4143
clipp::option("-B", "--braille").set(m_output_type,BRAILLE).doc("Braille output")
4244
);
4345

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

5456
auto cli = (
5557
cli_head | (
58+
cli_mod,
5659
cli_output,
5760
clipp::repeatable(
5861
/* select a plot type */
@@ -98,8 +101,10 @@ Config::Config(int argc, char *argv[])
98101
.doc("Find numbers in input line, pick 1 or 2 positions for X and Y values"),
99102
(clipp::option("-r", "--regex") & clipp::value("regex")
100103
.call([&](const char *txt) { m_inputs.back().set_regex(txt); }))
101-
.doc("Regex to match numbers from input line")
102-
104+
.doc("Regex to match numbers from input line"),
105+
(clipp::option("-l", "--limit") & clipp::value("count")
106+
.call([&](const char *txt) { m_inputs.back().set_data_limit(txt); }))
107+
.doc("How many historical values to retain for plotting")
103108
),
104109

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

170175
bool with_interval{}, no_interval{};
171176
double prev_interval = 1;
177+
size_t prev_data_limit = Input::g_default_data_limit;
172178
for (auto &input : m_inputs) {
173179
if (input.needs_interval()) {
174180
if (!input.interval()) {
@@ -177,6 +183,11 @@ Config::Config(int argc, char *argv[])
177183
prev_interval = input.interval();
178184
}
179185
}
186+
if (!input.data_limit()) {
187+
input.set_data_limit(prev_data_limit);
188+
} else {
189+
prev_data_limit = input.data_limit();
190+
}
180191
if (!input) {
181192
spdlog::error("incomplete plot definition");
182193
std::exit(1);
@@ -316,6 +327,19 @@ void Input::set_interval (const std::string &txt)
316327
std::exit(1);
317328
}
318329
}
330+
void Input::set_data_limit (size_t value)
331+
{
332+
m_data_limit = value;
333+
}
334+
void Input::set_data_limit (const std::string &txt)
335+
{
336+
auto [_,ec] = std::from_chars(txt.data(), txt.data()+txt.size(), m_data_limit);
337+
if (ec != std::errc{}) {
338+
spdlog::error("failed to parse data limit from '{}': {}",
339+
txt, std::make_error_code(ec).message());
340+
std::exit(1);
341+
}
342+
}
319343

320344
Input::operator bool() const
321345
{

cli/config.hpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ class Input final {
2020
WATCH // run program repetitively at interval, each run is one entry
2121
};
2222

23+
static constexpr const size_t g_default_data_limit = 1000000;
24+
2325
protected:
2426
blot_plot_type m_plot_type{BLOT_LINE};
2527
Source m_source{NONE};
2628
std::string m_details{};
2729
Extract m_extract;
2830
blot_color m_plot_color;
2931
double m_interval{0};
32+
size_t m_data_limit{g_default_data_limit};
3033

3134
public:
3235
explicit Input(blot_plot_type plot_type, blot_color color)
@@ -63,6 +66,7 @@ class Input final {
6366
const Extract& extract() const { return m_extract; }
6467
blot_color plot_color() const { return m_plot_color; }
6568
double interval() const { return m_interval; }
69+
size_t data_limit() const { return m_data_limit; }
6670

6771
/* validate if the configuration looks sane */
6872
operator bool() const;
@@ -73,14 +77,19 @@ class Input final {
7377
void set_color (const std::string &txt);
7478
void set_interval (double interval);
7579
void set_interval (const std::string &txt);
80+
void set_data_limit (size_t);
81+
void set_data_limit (const std::string &txt);
7682

7783

7884
};
7985

8086
class Config final {
87+
public:
88+
using OutputType = enum output_type { ASCII, UNICODE, BRAILLE };
89+
8190
protected:
8291
const char *m_self{};
83-
enum output_type { ASCII, UNICODE, BRAILLE } m_output_type;
92+
OutputType m_output_type;
8493
const static blot_color m_first_color{9};
8594
std::vector<Input> m_inputs;
8695
bool m_display_interval{1};
@@ -100,8 +109,9 @@ class Config final {
100109
}
101110
}
102111

103-
size_t inputs() const { return m_inputs.size(); }
112+
OutputType output_type() const { return m_output_type; }
104113

114+
size_t inputs() const { return m_inputs.size(); }
105115
const Input& input(size_t n) const { return m_inputs.at(n); }
106116
Input& input(size_t n) { return m_inputs.at(n); }
107117

cli/plotter.hpp

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,49 @@
99
template <typename X, typename Y>
1010
class Plotter final {
1111
protected:
12+
template <typename T>
13+
class Storage {
14+
protected:
15+
std::vector<T> m_data;
16+
size_t m_offset{};
17+
18+
void relocation_check() {
19+
bool full = m_data.size() == m_data.capacity();
20+
if (full && m_offset && m_offset > (m_data.capacity()/2)) {
21+
// full but most is empty, so we should relocate the data
22+
m_data.erase(m_data.begin(), m_data.begin() + m_offset);
23+
m_offset = 0;
24+
}
25+
}
26+
27+
public:
28+
void push_back(const T &v) {
29+
relocation_check();
30+
m_data.push_back(v);
31+
}
32+
33+
void erase_front(size_t count = 1) {
34+
if (count > size())
35+
BLOT_THROW(ERANGE, "count=%zu exceeds size=%zu", count, size());
36+
m_offset += count;
37+
}
38+
39+
T* data() noexcept { return m_data.data() + m_offset; }
40+
const T* data() const noexcept { return m_data.data() + m_offset; }
41+
size_t size() const { return m_data.size() - m_offset; }
42+
43+
std::span<T> span() {
44+
return std::span<const T>(data(), size());
45+
}
46+
std::span<const T> span() const {
47+
return std::span<const T>(data(), size());
48+
}
49+
50+
};
51+
1252
struct Data {
13-
std::vector<X> m_xs;
14-
std::vector<Y> m_ys;
53+
Storage<X> m_xs;
54+
Storage<Y> m_ys;
1555
};
1656
std::vector<Data> m_data;
1757
size_t m_count{};
@@ -41,6 +81,11 @@ class Plotter final {
4181
m_data[layer].m_xs.push_back(x);
4282
m_data[layer].m_ys.push_back(y);
4383
m_count ++;
84+
85+
if (m_data[layer].m_xs.size() > m_config.input(layer).data_limit()) {
86+
m_data[layer].m_xs.erase_front();
87+
m_data[layer].m_ys.erase_front();
88+
}
4489
}
4590

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

70-
fig.plot(input.plot_type(), data.m_xs, data.m_ys,
115+
fig.plot(input.plot_type(), data.m_xs.span(), data.m_ys.span(),
71116
input.plot_color(), input.details());
72117
}
73118

74119
double t_add = timing ? blot_double_time() : 0;
75120

76121
blot_render_flags flags
77-
= BLOT_RENDER_BRAILLE
78-
| BLOT_RENDER_LEGEND_BELOW
122+
= BLOT_RENDER_LEGEND_BELOW
79123
| BLOT_RENDER_CLEAR;
80124

125+
switch (m_config.output_type()) {
126+
case Config::ASCII:
127+
flags = flags | BLOT_RENDER_NO_UNICODE;
128+
break;
129+
case Config::BRAILLE:
130+
flags = flags | BLOT_RENDER_BRAILLE;
131+
break;
132+
default: // UNICODE
133+
break;
134+
}
135+
81136
if (timing)
82137
flags = flags | BLOT_RENDER_LEGEND_DETAILS;
83138

include/blot.hpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <cassert>
77
#include <iostream>
8+
#include <span>
89
#include <stdexcept>
910
#include <algorithm>
1011
#include <utility>
@@ -86,15 +87,15 @@ class Exception final : public std::exception {
8687

8788
template <typename T>
8889
constexpr blot_data_type data_type() {
89-
if constexpr (std::is_same_v<T, int16_t>)
90+
if constexpr (std::is_same_v<std::remove_const_t<T>, int16_t>)
9091
return BLOT_DATA_INT16;
91-
else if constexpr (std::is_same_v<T, int32_t>)
92+
else if constexpr (std::is_same_v<std::remove_const_t<T>, int32_t>)
9293
return BLOT_DATA_INT32;
93-
else if constexpr (std::is_same_v<T, int64_t>)
94+
else if constexpr (std::is_same_v<std::remove_const_t<T>, int64_t>)
9495
return BLOT_DATA_INT64;
95-
else if constexpr (std::is_same_v<T, float>)
96+
else if constexpr (std::is_same_v<std::remove_const_t<T>, float>)
9697
return BLOT_DATA_FLOAT;
97-
else if constexpr (std::is_same_v<T, double>)
98+
else if constexpr (std::is_same_v<std::remove_const_t<T>, double>)
9899
return BLOT_DATA_DOUBLE;
99100
else
100101
BLOT_THROW(EINVAL, "unsupported type");
@@ -184,7 +185,7 @@ struct Figure final : public blot_figure {
184185
/* add layers */
185186

186187
template <typename T, typename U>
187-
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) {
188+
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) {
188189
GError *error = nullptr;
189190
size_t data_count = data_ys.size();
190191

@@ -206,6 +207,14 @@ struct Figure final : public blot_figure {
206207
}
207208
}
208209

210+
template <typename T, typename U>
211+
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) {
212+
plot(plot_type,
213+
std::span<const T>(data_xs.data(), data_xs.size()),
214+
std::span<const U>(data_ys.data(), data_ys.size()),
215+
data_color, data_label);
216+
}
217+
209218
template <typename T, typename U>
210219
void scatter(const std::vector<T> &data_xs, const std::vector<U>& data_ys, blot_color data_color, const char *data_label) {
211220
plot(BLOT_SCATTER, data_xs, data_ys, data_color, data_label);

0 commit comments

Comments
 (0)