Skip to content

Commit

Permalink
P16-1075 Add formating hints to MIBs
Browse files Browse the repository at this point in the history
  • Loading branch information
Chris Johns authored and kiwichris committed Apr 19, 2024
1 parent 6452b8e commit f1f7304
Show file tree
Hide file tree
Showing 3 changed files with 249 additions and 16 deletions.
44 changes: 41 additions & 3 deletions sdk/include/pixie/mib.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ enum struct type {
timestamp /**< Time stamp in nanoseconds */
};

/**
* String formating hints
*/
enum struct hint {
fmt_defaults, /**< Use the default format for the MIB type */
fmt_no_quotes, /**< If string do not wrap in quoutes, default is quotes */
fmt_boolnum, /**< If boolean use 0 or 1, default is boolalpha */
fmt_dec, /**< If integer or uinteger use decimal, default is decimal */
fmt_oct, /**< If integer or uinteger use octal */
fmt_hex, /**< If integer or uinteger use hexadecimal */
fmt_fixed, /**< If real use fixed point, default is fixed point */
fmt_iso8601 /**< If timestamp use ISO8601 format */
};

/**
* The type of the types for a MIB
*/
Expand Down Expand Up @@ -441,6 +455,22 @@ struct node_base {
using lock_type = std::mutex;
using lock_guard = std::lock_guard<lock_type>;

using hint_flag_type = uint64_t;

static constexpr hint_flag_type fmt_mask = 0x1f;
static constexpr hint_flag_type fmt_base = 0;
static constexpr hint_flag_type fixed_mask = 0x1f;
static constexpr hint_flag_type fixed_base = 5;
static constexpr hint_flag_type fmt_defaults = 0;
static constexpr hint_flag_type fmt_no_quotes = 1;
static constexpr hint_flag_type fmt_boolnum = 2;
static constexpr hint_flag_type fmt_dec = 3;
static constexpr hint_flag_type fmt_oct = 4;
static constexpr hint_flag_type fmt_hex = 5;
static constexpr hint_flag_type fmt_fixed = 6;
static constexpr hint_flag_type fmt_iso8601 = 7;

lock_type lock;
const name_type name;
const type type_;
const bool read_only;
Expand All @@ -451,7 +481,7 @@ struct node_base {
event_func set_event;
event_func timer_event;
bool in_event_call;
lock_type lock;
hint_flag_type hints;

node_base(const name_type& name, const type type_, const bool enabled);
/*
Expand Down Expand Up @@ -486,6 +516,8 @@ struct node_base {
void call_timer_event_func();

std::string str(bool attributes);
void set_hint(hint hint_);
bool get_hint(hint hint_);
};

/**
Expand Down Expand Up @@ -556,6 +588,8 @@ struct node {
template<typename T> bool operator<=(const T& val) const;
template<typename T> bool operator>=(const T& val) const;

node& operator=(hint hint_);

operator string();
operator boolean();
operator integer();
Expand All @@ -573,6 +607,8 @@ struct node {
void set_value(const char* val);

std::string str(bool attributes = false);
void set_hint(hint hint_);
bool get_hint(hint hint_) const;

bool valid() const { if (base) return true; return false; }

Expand Down Expand Up @@ -685,10 +721,12 @@ template<typename T> node_base::node_base(
template<typename T> void node_base::set(const T& val) {
lock_guard guard(lock);
if (read_only) {
throw error(error::code::read_only, "mib::node::set: MIB is read-only");
throw error(
error::code::read_only, "mib::node::set: MIB is read-only: " + name);
}
if (write_lock) {
throw error(error::code::read_only, "mib::node::set: MIB is write locked");
throw error(
error::code::read_only, "mib::node::set: MIB is write locked: " + name);
}
if (std::is_same_v<T, string> ||
std::is_same_v<T, stringp> ||
Expand Down
173 changes: 164 additions & 9 deletions sdk/src/pixie/mib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <pixie/log.hpp>
#include <pixie/mib.hpp>
#include <pixie/utils/string.hpp>
#include <pixie/utils/time.hpp>

namespace xia {
namespace mib {
Expand Down Expand Up @@ -205,7 +206,7 @@ data_type::~data_type() {

node_base::node_base(const name_type& name_, const type type__, const bool enabled_)
: name(name_), type_(type__), read_only(false), write_lock(false),
enabled(enabled_), in_event_call(false) {
enabled(enabled_), in_event_call(false), hints(0) {
/*
* A mib can only ever be one type. The union has classes and they
* could contain references to resources such as memory. The
Expand Down Expand Up @@ -488,15 +489,48 @@ void node_base::call_timer_event_func() {
}

std::string node_base::str(bool attributes) {
std::ostringstream oss;
lock_guard guard(lock);
call_get_event_func();
std::ostringstream oss;
oss << std::boolalpha
<< std::dec
<< std::showbase
<< std::fixed;
bool s_fmt_no_quotes = false;
bool ts_fmt_iso8601 = false;
switch (hints & (fmt_mask << fmt_base)) {
case fmt_no_quotes:
s_fmt_no_quotes = true;
break;
case fmt_boolnum:
oss << std::noboolalpha;
break;
case fmt_dec:
break;
case fmt_oct:
oss << std::oct;
break;
case fmt_hex:
oss << std::hex;
break;
case fmt_fixed:
break;
case fmt_iso8601:
ts_fmt_iso8601 = true;
break;
default:
break;
}
switch (type_) {
case type::string:
oss << '"' << v.s << '"';
if (s_fmt_no_quotes) {
oss << v.s;
} else {
oss << '"' << v.s << '"';
}
break;
case type::boolean:
oss << std::boolalpha << v.b;
oss << v.b;
break;
case type::integer:
oss << static_cast<integer>(v.u);
Expand All @@ -505,12 +539,27 @@ std::string node_base::str(bool attributes) {
oss << v.u;
break;
case type::real:
oss << std::fixed << std::setprecision(9) << v.r;
oss << std::setprecision(9) << v.r;
break;
case type::timestamp:
oss << v.t.nsecs / 1000000000UL
<< '.' << std::setw(9) << std::setfill('0')
<< v.t.nsecs % 1000000000UL;
if (ts_fmt_iso8601) {
/*
* Stage the conversion of nanoseconds to a system clock
* time point to cater for different clock precisions on
* different host platforms. Use a temporary system clock
* time point to add the duration to to deal with possible
* differences in the clock types.
*/
std::chrono::duration td = std::chrono::nanoseconds{v.t.nsecs};
util::time::datetime_timepoint temp_dtp;
auto dp =
std::chrono::time_point_cast<std::chrono::system_clock::duration>(temp_dtp + td);
oss << util::time::datetime_iso8601(dp);
} else {
oss << v.t.nsecs / 1000000000UL
<< '.' << std::setw(9) << std::setfill('0')
<< v.t.nsecs % 1000000000UL;
}
break;
}
if (attributes) {
Expand All @@ -530,6 +579,101 @@ std::string node_base::str(bool attributes) {
return oss.str();
}

void node_base::set_hint(hint hint_) {
lock_guard guard(lock);
switch (hint_) {
case hint::fmt_defaults:
hints &= ~(fmt_mask << fmt_base);
hints |= fmt_defaults;
break;
case hint::fmt_no_quotes:
hints &= ~(fmt_mask << fmt_base);
hints |= fmt_no_quotes;
break;
case hint::fmt_boolnum:
hints &= ~(fmt_mask << fmt_base);
hints |= fmt_boolnum;
break;
case hint::fmt_dec:
hints &= ~(fmt_mask << fmt_base);
hints |= fmt_dec;
break;
case hint::fmt_oct:
hints &= ~(fmt_mask << fmt_base);
hints |= fmt_oct;
break;
case hint::fmt_hex:
hints &= ~(fmt_mask << fmt_base);
hints |= fmt_hex;
break;
case hint::fmt_fixed:
hints &= ~(fmt_mask << fmt_base);
hints |= fmt_fixed;
break;
case hint::fmt_iso8601:
hints &= ~(fmt_mask << fmt_base);
hints |= fmt_iso8601;
break;
default:
break;
}
}

bool node_base::get_hint(hint hint_) {
lock_guard guard(lock);
bool result = false;
switch (hint_) {
case hint::fmt_defaults:
if ((hints & fmt_defaults) != 0) {
result = true;
}
break;
case hint::fmt_no_quotes:
if ((hints & fmt_no_quotes) != 0) {
result = true;
}
break;
case hint::fmt_boolnum:
if ((hints & fmt_boolnum) != 0) {
result = true;
}
break;
case hint::fmt_dec:
if ((hints & fmt_dec) != 0) {
result = true;
}
break;
case hint::fmt_oct:
if ((hints & fmt_oct) != 0) {
result = true;
}
break;
case hint::fmt_hex:
if ((hints & fmt_hex) != 0) {
result = true;
}
break;
case hint::fmt_fixed:
if ((hints & fmt_fixed) != 0) {
result = true;
}
break;
case hint::fmt_iso8601:
if ((hints & fmt_iso8601) != 0) {
result = true;
}
break;
default:
break;
}
return result;
}

node& node::operator=(hint hint_) {
set_hint(hint_);
return *this;
}

void node::check_base() const {
if (!valid()) {
throw error(error::code::read_only, "mib::node::check: not a valid node");
Expand Down Expand Up @@ -605,7 +749,8 @@ void node::lock_writes() {
node_base::lock_guard guard(base->lock);
if (base->read_only) {
throw error(
error::code::read_only, "mib::node::lock-write: MIB is read-only");
error::code::read_only,
"mib::node::lock-write: MIB is read-only: " + base->name);
}
base->write_lock = true;
}
Expand Down Expand Up @@ -690,6 +835,16 @@ std::string node::str(bool attributes) {
return base->str(attributes);
}

void node::set_hint(hint hint_) {
check_base();
base->set_hint(hint_);
}

bool node::get_hint(hint hint_) const {
check_base();
return base->get_hint(hint_);
}

void add(const name_type& name, const type type_, const bool enabled) {
mib.add(name, type_, enabled);
}
Expand Down
48 changes: 44 additions & 4 deletions tests/unit/sdk/test_pixie_mib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ TEST_SUITE("xia::pixie::mib") {
CHECK_NOTHROW(s1.lock_writes());
CHECK(s1.write_locked() == true);
CHECK_THROWS_WITH_AS(s1 = "write while locked",
"mib::node::set: MIB is write locked", xia::mib::error);
"mib::node::set: MIB is write locked: s.1", xia::mib::error);
CHECK_NOTHROW(s1.unlock_writes());
CHECK(s1.write_locked() == false);
CHECK_NOTHROW(s1 = "write while locked");
Expand Down Expand Up @@ -286,8 +286,8 @@ TEST_SUITE("xia::pixie::mib") {
CHECK_NOTHROW(xia::mib::add_ro_real("r.2.ro", 3.33333));
CHECK_NOTHROW(xia::mib::add_ro_timestamp("t.2.ro", xia::mib::timestamp(987654321)));
auto s = xia::mib::node("s.2.ro");
CHECK_THROWS_WITH_AS(s = "abc", "mib::node::set: MIB is read-only", xia::mib::error);
CHECK_THROWS_WITH_AS(s.lock_writes(), "mib::node::lock-write: MIB is read-only", xia::mib::error);
CHECK_THROWS_WITH_AS(s = "abc", "mib::node::set: MIB is read-only: s.2.ro", xia::mib::error);
CHECK_THROWS_WITH_AS(s.lock_writes(), "mib::node::lock-write: MIB is read-only: s.2.ro", xia::mib::error);
}
TEST_CASE("MIB: events") {
auto s1 = xia::mib::node("s.1");
Expand Down Expand Up @@ -509,7 +509,8 @@ TEST_SUITE("xia::pixie::mib") {
std::mutex lock;
std::string s = "locked ro mib read";
auto ro1 = xia::mib::read_write_lock("rw.2", s, lock);
CHECK_THROWS_WITH_AS(ro1.nod = "write locked set", "mib::node::set: MIB is write locked", xia::mib::error);
CHECK_THROWS_WITH_AS(ro1.nod = "write locked set",
"mib::node::set: MIB is write locked: rw.2", xia::mib::error);
CHECK(*ro1 == "locked ro mib read");
std::atomic_int as1 = 100;
auto rw3 = xia::mib::read_write("rw.3", as1, xia::mib::rw_mode::rw);
Expand Down Expand Up @@ -635,4 +636,43 @@ TEST_SUITE("xia::pixie::mib") {
xia::mib::timestamp t(1712711064001386000);
CHECK(n == t);
}
TEST_CASE("MIB: hints") {
xia::mib::node n;
CHECK_NOTHROW(n = xia::mib::find("s.1"));
CHECK(n.str() == "\"string string\"");
CHECK_NOTHROW(n = xia::mib::hint::fmt_no_quotes);
CHECK(n.str() == "string string");
CHECK_NOTHROW(n = xia::mib::find("b.1"));
CHECK_NOTHROW(n = true);
CHECK(n.str() == "true");
CHECK_NOTHROW(n = xia::mib::hint::fmt_boolnum);
CHECK(n.str() == "1");
CHECK_NOTHROW(n = xia::mib::find("i.1"));
CHECK_NOTHROW(n = 128);
CHECK(n.str() == "128");
CHECK_NOTHROW(n = xia::mib::hint::fmt_dec);
CHECK(n.str() == "128");
CHECK_NOTHROW(n = xia::mib::hint::fmt_oct);
CHECK(n.str() == "0200");
CHECK_NOTHROW(n = xia::mib::hint::fmt_hex);
CHECK(n.str() == "0x80");
CHECK_NOTHROW(n = xia::mib::hint::fmt_hex);
CHECK_NOTHROW(n = xia::mib::find("u.1"));
CHECK_NOTHROW(n = 256);
CHECK(n.str() == "256");
CHECK_NOTHROW(n = xia::mib::hint::fmt_oct);
CHECK(n.str() == "0400");
CHECK_NOTHROW(n = xia::mib::hint::fmt_hex);
CHECK(n.str() == "0x100");
CHECK_NOTHROW(n = xia::mib::find("r.1"));
CHECK_NOTHROW(n = 1.123456789);
CHECK(n.str() == "1.123456789");
CHECK_NOTHROW(n = xia::mib::hint::fmt_fixed);
CHECK(n.str() == "1.123456789");
CHECK_NOTHROW(n = xia::mib::find("t.1"));
CHECK_NOTHROW(n.set_value("2024-04-10T01:04:24.123456"));
CHECK(n.str() == "1712711064.123456000");
CHECK_NOTHROW(n = xia::mib::hint::fmt_iso8601);
CHECK(n.str() == "2024-04-10T01:04:24.123Z");
}
}

0 comments on commit f1f7304

Please sign in to comment.