Skip to content

Commit

Permalink
Make RRDFetchHeader a dumb struct
Browse files Browse the repository at this point in the history
This improves the consistency between both classes defined in the file.
I like to have some consistency at the file level at least.  :)

CMK-18929

Change-Id: I67bfc465019cb18639fa9f5b0d2aac4248bc4ec1
  • Loading branch information
Synss committed Jan 22, 2025
1 parent a9910d4 commit 10c8757
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 56 deletions.
53 changes: 10 additions & 43 deletions packages/livestatus/include/livestatus/RRDFetch.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,32 @@
#ifndef RRDFetch_h
#define RRDFetch_h

#include <cassert>
#include <charconv>
#include <chrono>
#include <cstddef>
#include <ios>
#include <string>
#include <system_error>
#include <vector>

class RRDFetchHeader {
struct RRDFetchHeader {
/*
* FlushVersion: 1
* Start: ...
* End: ...
* Step: ...
* DSCount: 7
*/
[[nodiscard]] RRDFetchHeader static parse(
const std::vector<std::string> &h);
[[nodiscard]] std::vector<std::string> unparse() const;
enum Field { FlushVersion, Start, End, Step, Dscount };
using C = std::chrono::system_clock;

public:
using time_point = C::time_point;
explicit RRDFetchHeader(const std::vector<std::string> &h) : _h{h} {
assert(h.size() == size());
}
using time_point = std::chrono::system_clock::time_point;
static std::size_t size() { return Field::Dscount + 1; }
[[nodiscard]] unsigned long flush_version() const {
return parse(_h[Field::FlushVersion]);
}
[[nodiscard]] time_point start() const {
return time_point{std::chrono::seconds{parse(_h[Field::Start])}};
}
[[nodiscard]] time_point end() const {
return time_point{std::chrono::seconds{parse(_h[Field::End])}};
}
[[nodiscard]] unsigned long step() const { return parse(_h[Field::Step]); }
[[nodiscard]] unsigned long dscount() const {
return parse(_h[Field::Dscount]);
}

private:
std::vector<std::string> _h;
[[nodiscard]] static unsigned long parse(const std::string &line) {
const auto idx = line.find(": ");
if (idx == std::string::npos) {
return {};
}
unsigned long number = 0;
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
auto [ptr, ec] =
std::from_chars(line.data() + static_cast<std::size_t>(idx) + 2,
line.data() + line.size(), number);
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return ec == std::errc{} ? number : 0;
}
unsigned long flush_version{};
time_point start;
time_point end;
unsigned long step{};
unsigned long dscount{};
};

std::ostream &operator<<(std::ostream &os, const RRDFetchHeader &h);

struct RRDFetchBinPayloadHeader {
// DSName-[DSNAME]: BinaryData [VALUE_COUNT] [VALUE_SIZE] [ENDIANNESS]
static RRDFetchBinPayloadHeader parse(const std::string &line);
Expand Down
48 changes: 40 additions & 8 deletions packages/livestatus/src/RRDFetch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,53 @@

#include "livestatus/RRDFetch.h"

#include <cassert>
#include <charconv>
#include <sstream>
#include <stdexcept>
#include <string_view>
#include <system_error>

#include "livestatus/StringUtils.h"

std::ostream &operator<<(std::ostream &os, const RRDFetchHeader &h) {
return os << "FlushVersion: " << h.flush_version() << "\n"
<< "Start: " << std::chrono::system_clock::to_time_t(h.start())
<< "\n"
<< "End: " << std::chrono::system_clock::to_time_t(h.end())
<< "\n"
<< "Step: " << h.step() << "\n"
<< "DSCount: " << h.dscount() << "\n";
using namespace std::string_literals;

namespace {
[[nodiscard]] unsigned long get_header_value(std::string_view line) {
// "KEY: VALUE" -> VALUE
const std::size_t idx = line.find(": ");
if (idx == std::string::npos) {
return {};
}
unsigned long number = 0;
auto [ptr, ec] =
std::from_chars(line.begin() + idx + 2, line.end(), number);
return ec == std::errc{} ? number : 0;
}
} // namespace

RRDFetchHeader RRDFetchHeader::parse(const std::vector<std::string> &h) {
assert(h.size() == size());
return RRDFetchHeader{
.flush_version = get_header_value(h[Field::FlushVersion]),
.start = RRDFetchHeader::time_point{std::chrono::seconds{
get_header_value(h[Field::Start])}},
.end = RRDFetchHeader::time_point{std::chrono::seconds{
get_header_value(h[Field::End])}},
.step = get_header_value(h[Field::Step]),
.dscount = get_header_value(h[Field::Dscount]),
};
}

std::vector<std::string> RRDFetchHeader::unparse() const {
return std::vector<std::string>{
"FlushVersion: "s + std::to_string(flush_version),
"Start: "s +
std::to_string(std::chrono::system_clock::to_time_t(start)),
"End: "s + std::to_string(std::chrono::system_clock::to_time_t(end)),
"Step: "s + std::to_string(step),
"DSCount: "s + std::to_string(dscount),
};
}

namespace {
Expand Down
7 changes: 2 additions & 5 deletions packages/livestatus/test/test_RRDFetch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// terms and conditions defined in the file COPYING, which is part of this
// source code package.

#include <sstream>
#include <string>

#include "gtest/gtest.h"
Expand All @@ -17,10 +16,8 @@ TEST(TestRRDFetchHeader, Header) {
"End: 1736245800\n"
"Step: 1800\n"
"DSCount: 2\n";
auto header = RRDFetchHeader{mk::split(raw, '\n')};
auto ss = std::ostringstream{};
ss << header;
EXPECT_EQ(ss.str(), raw);
auto header = mk::split(raw, '\n');
EXPECT_EQ(header, RRDFetchHeader::parse(header).unparse());
}

TEST(TestRRDFetchBinPayloadHeader, Header) {
Expand Down

0 comments on commit 10c8757

Please sign in to comment.