Archived
240 lines
6.5 KiB
C++
240 lines
6.5 KiB
C++
#pragma once
|
|
#if !defined(__cplusplus) || __cplusplus < 202002L
|
|
#error "This code requires C++20 or later"
|
|
#endif
|
|
|
|
#include "tomlc17.h"
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace toml {
|
|
|
|
class Datum : public toml_datum_t {
|
|
public:
|
|
using datetime = std::chrono::sys_time<std::chrono::microseconds>;
|
|
using time = std::chrono::hh_mm_ss<std::chrono::microseconds>;
|
|
using date = std::chrono::year_month_day;
|
|
|
|
Datum(toml_datum_t dat = toml_datum_t{}) : toml_datum_t(dat) {}
|
|
bool is_table() const { return type == TOML_TABLE; }
|
|
bool is_array() const { return type == TOML_ARRAY; }
|
|
|
|
// Retrieve a string.
|
|
std::optional<std::string_view> as_str() const {
|
|
if (type != TOML_STRING)
|
|
return std::nullopt;
|
|
else
|
|
return std::string_view{u.str.ptr, (size_t)u.str.len};
|
|
}
|
|
|
|
// Retrieve an int.
|
|
std::optional<std::int64_t> as_int() const {
|
|
if (type != TOML_INT64)
|
|
return std::nullopt;
|
|
else
|
|
return u.int64;
|
|
}
|
|
|
|
// Retrieve a float.
|
|
std::optional<double> as_real() const {
|
|
if (type != TOML_FP64)
|
|
return std::nullopt;
|
|
else
|
|
return u.fp64;
|
|
}
|
|
|
|
// Retrieve a boolean.
|
|
std::optional<bool> as_bool() const {
|
|
if (type != TOML_BOOLEAN)
|
|
return std::nullopt;
|
|
else
|
|
return !!u.boolean;
|
|
}
|
|
|
|
// Retrieve a date.
|
|
std::optional<date> as_date() const {
|
|
using namespace std::chrono;
|
|
if (type != TOML_DATE)
|
|
return std::nullopt;
|
|
else
|
|
return date{year(u.ts.year), month(u.ts.month), day(u.ts.day)};
|
|
}
|
|
|
|
// Retrieve a time.
|
|
std::optional<time> as_time() const {
|
|
using namespace std::chrono;
|
|
if (type != TOML_TIME)
|
|
return std::nullopt;
|
|
else
|
|
return time{hours(u.ts.hour) + minutes(u.ts.minute) +
|
|
seconds(u.ts.second) + microseconds(u.ts.usec)};
|
|
}
|
|
|
|
// Retrieve a datetime.
|
|
std::optional<datetime> as_datetime() const {
|
|
using namespace std::chrono;
|
|
if (type != TOML_DATETIME) {
|
|
return std::nullopt;
|
|
}
|
|
year_month_day ymd{year{u.ts.year}, month{(unsigned)u.ts.month},
|
|
day{(unsigned)u.ts.day}};
|
|
auto tod = hours{u.ts.hour} + minutes{u.ts.minute} + seconds{u.ts.second} +
|
|
microseconds{u.ts.usec};
|
|
return datetime{sys_days{ymd} + tod};
|
|
}
|
|
|
|
// Retrieve a datetime and minute offset from UTC.
|
|
std::optional<std::pair<datetime, int>> as_datetimetz() const {
|
|
using namespace std::chrono;
|
|
|
|
if (type != TOML_DATETIMETZ) {
|
|
return std::nullopt;
|
|
}
|
|
year_month_day ymd{year{u.ts.year}, month{(unsigned)u.ts.month},
|
|
day{(unsigned)u.ts.day}};
|
|
auto tod = hours{u.ts.hour} + minutes{u.ts.minute} + seconds{u.ts.second} +
|
|
microseconds{u.ts.usec};
|
|
return std::pair{datetime{sys_days{ymd} + tod}, u.ts.tz};
|
|
}
|
|
|
|
// Retrieve an array of Datum from this datum.
|
|
std::optional<std::vector<Datum>> as_vector() const {
|
|
if (type != TOML_ARRAY) {
|
|
return std::nullopt;
|
|
}
|
|
std::vector<Datum> ret;
|
|
ret.assign(u.arr.elem, u.arr.elem + u.arr.size);
|
|
return ret;
|
|
}
|
|
|
|
// Retrieve an array of strings from this datum.
|
|
std::optional<std::vector<std::string_view>> as_strvec() const {
|
|
try {
|
|
auto vec = as_vector().value();
|
|
std::vector<std::string_view> ret;
|
|
ret.resize(vec.size());
|
|
for (size_t i = 0; i < vec.size(); i++) {
|
|
ret[i] = vec[i].as_str().value();
|
|
}
|
|
return ret;
|
|
} catch (const std::bad_optional_access &ex) {
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
|
|
// Retrieve an array of ints from this datum
|
|
std::optional<std::vector<int64_t>> as_intvec() const {
|
|
try {
|
|
auto vec = as_vector().value();
|
|
std::vector<int64_t> ret;
|
|
ret.resize(vec.size());
|
|
for (size_t i = 0; i < vec.size(); i++) {
|
|
ret[i] = vec[i].as_int().value();
|
|
}
|
|
return ret;
|
|
} catch (const std::bad_optional_access &ex) {
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
|
|
// Retrieve an array of doubles from this datum
|
|
std::optional<std::vector<double>> as_realvec() const {
|
|
try {
|
|
auto vec = as_vector().value();
|
|
std::vector<double> ret;
|
|
ret.resize(vec.size());
|
|
for (size_t i = 0; i < vec.size(); i++) {
|
|
ret[i] = vec[i].as_real().value();
|
|
}
|
|
return ret;
|
|
} catch (const std::bad_optional_access &ex) {
|
|
return std::nullopt;
|
|
}
|
|
}
|
|
|
|
// For tables. Retrieve the value of a composite key from this datum
|
|
// (which is a table).
|
|
std::optional<Datum> get(std::initializer_list<std::string_view> keys) const {
|
|
Datum tab = *this;
|
|
Datum value;
|
|
for (auto key : keys) {
|
|
value = {};
|
|
if (tab.type != TOML_TABLE) {
|
|
return std::nullopt;
|
|
}
|
|
for (int i = 0; i < tab.u.tab.size; i++) {
|
|
if (key ==
|
|
std::string_view{tab.u.tab.key[i], (size_t)tab.u.tab.len[i]}) {
|
|
value = tab.u.tab.value[i];
|
|
break;
|
|
}
|
|
}
|
|
tab = value;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
// Retrieve the value of a key
|
|
std::optional<Datum> get(std::string_view key) const { return get({key}); }
|
|
|
|
// Retrieve the value of a multi-part key
|
|
std::optional<Datum> seek(const char *multipart_key) const {
|
|
auto ret = toml_seek(*this, multipart_key);
|
|
if (!ret.type) {
|
|
return std::nullopt;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
}; // class Datum
|
|
|
|
class Result : private toml_result_t {
|
|
public:
|
|
Result(const toml_result_t &result) : toml_result_t(result) {}
|
|
~Result() noexcept { toml_free(*this); }
|
|
|
|
// Disallow copying
|
|
Result(const Result &) = delete;
|
|
Result &operator=(const Result &) = delete;
|
|
|
|
// Allow moving
|
|
Result(Result &&other) noexcept : toml_result_t() { swap(*this, other); }
|
|
Result &operator=(Result &&other) noexcept {
|
|
swap(*this, other);
|
|
return *this;
|
|
}
|
|
|
|
// Access methods
|
|
bool ok() const { return toml_result_t::ok; }
|
|
Datum toptab() const { return toml_result_t::toptab; }
|
|
const char *errmsg() const { return toml_result_t::errmsg; }
|
|
|
|
// Shortcuts
|
|
std::optional<Datum> get(std::initializer_list<std::string_view> keys) const {
|
|
return toptab().get(keys);
|
|
}
|
|
std::optional<Datum> seek(const char *multipart_key) const {
|
|
return toptab().seek(multipart_key);
|
|
}
|
|
|
|
private:
|
|
friend void swap(Result &a, Result &b) noexcept {
|
|
std::swap(static_cast<toml_result_t &>(a), static_cast<toml_result_t &>(b));
|
|
}
|
|
};
|
|
|
|
static inline Result parse_file(FILE *fp) { return toml_parse_file(fp); }
|
|
|
|
static inline Result parse_file_ex(const char *fname) {
|
|
return toml_parse_file_ex(fname);
|
|
}
|
|
|
|
static inline Result parse(const std::string &s) {
|
|
return toml_parse(s.data(), s.size());
|
|
}
|
|
|
|
}; // namespace toml
|