[Toml,TomlTable] Replace macro implementations with template functions
All checks were successful
buildbot/IOCore-linux-builder Build done.
buildbot/IOCore-macos-builder Build done.
buildbot/IOCore-freebsd-builder Build done.

for better debugging, error messages, and development.

Templates provide better type deduction and safety anyway.
This commit is contained in:
S David 2024-08-04 18:07:45 -04:00
parent 3eba83e7a8
commit 5217f97acb
5 changed files with 94 additions and 48 deletions

View File

@ -22,22 +22,21 @@ struct TomlTable : public toml::table {
TomlTable(TomlTable&& tbl) noexcept : toml::table(std::move(tbl)) {}
template<typename T>
TomlTable(const T& obj)
TomlTable(const T& obj) : toml::table(to_toml_table(obj))
{
to_toml_table(*this, obj);
}
template<typename T>
auto operator=(const T& obj) -> TomlTable&
{
to_toml_table(*this, obj);
toml::table::operator=(to_toml_table(obj));
return *this;
}
template<typename T>
auto operator=(T&& obj) -> TomlTable&
{
to_toml_table(*this, obj);
toml::table::operator=(std::move(to_toml_table(obj)));
return *this;
}

View File

@ -12,6 +12,7 @@
#include <algorithm>
#include <initializer_list>
#include <string>
#include <type_traits>
#include <utility>
#include <toml++/toml.hpp>
@ -19,6 +20,31 @@
#include "../Exception.hpp"
#include "./macros.hpp"
/* NOLINTBEGIN */
// Primary template, defaults to false
template<typename T>
struct is_toml_type : std::false_type {};
// Specializations for TOML++ native types
template<>
struct is_toml_type<double> : std::true_type {};
template<>
struct is_toml_type<int64_t> : std::true_type {};
template<>
struct is_toml_type<bool> : std::true_type {};
template<>
struct is_toml_type<std::string> : std::true_type {};
template<>
struct is_toml_type<std::string_view> : std::true_type {};
template<typename T>
constexpr bool is_not_toml_native_t = is_toml_type<T>::value;
/* NOLINTEND */
namespace IOCore {
struct TomlException : public Exception {
@ -34,44 +60,80 @@ struct TomlException : public Exception {
}
template<typename T>
void add_to_toml_table(toml::table& tbl, const char* fieldName, const T& obj);
void insert_in_toml_table(toml::table& tbl, const char* fieldName, const T& obj);
template<typename T>
void extract_from_toml_table(
const toml::table& tbl, const char* fieldName, T& output
);
template<typename T>
auto to_toml_table(const T& obj) -> toml::table;
#define IOCORE_TOML_TO(field) add_to_toml_table(tbl, #field, obj.field);
#define IOCORE_TOML_FROM(field) extract_from_toml_table(tbl, #field, obj.field);
template<typename T>
void from_toml_table(const toml::table& tbl, T& result);
#define TOML_INIT_METADATA(T) \
auto metadata = toml::table(); \
metadata.insert_or_assign("type", #T); \
tbl.insert_or_assign("General", metadata);
#define IOCORE_TOML_TO(field) insert_in_toml_table(tbl, #field, obj.field);
#define IOCORE_TOML_FROM(field) \
extract_from_toml_table(tbl, #field, result.field);
#define IOCORE_TOML_SERIALIZABLE(T, ...) \
static constexpr const char* _class_name() \
#define IOCORE_TOML_SERIALIZABLE(CLASS, ...) \
static constexpr auto _class_name()->const char* \
{ \
return #T; \
return #CLASS; \
} \
friend void to_toml_table(toml::table& tbl, const T& obj) \
friend auto to_toml_table(const CLASS& obj)->toml::table \
{ \
toml::table tbl; \
FOREACH_PARAM(IOCORE_TOML_TO, __VA_ARGS__) \
return tbl; \
} \
\
friend void from_toml_table(const toml::table& tbl, T& obj) \
friend void from_toml_table(const toml::table& tbl, CLASS& result) \
{ \
FOREACH_PARAM(IOCORE_TOML_FROM, __VA_ARGS__) \
}
template<typename T>
inline void
insert_in_toml_table(toml::table& tbl, const char* fieldName, const T& obj)
{
using value_type = std::decay_t<T>;
if constexpr (is_not_toml_native_t<value_type>) {
auto subtable = to_toml_table<T>(obj);
tbl.insert_or_assign(fieldName, subtable);
} else {
tbl.insert_or_assign(fieldName, obj);
}
}
template<typename T>
inline void
extract_from_toml_table(const toml::table& tbl, const char* fieldName, T& output)
{
using value_type = std::decay_t<T>;
if (!tbl.contains(fieldName)) {
throw IOCore::TomlException(
"Missing field " + std::string(fieldName)
);
}
if constexpr (is_not_toml_native_t<value_type>) {
auto subtable = *(tbl[fieldName].as_table());
from_toml_table<T>(subtable, output);
} else {
output = tbl[fieldName].value<T>().value();
}
}
#define IOCORE_TOML_ENUM(ENUM_TYPE, ...) \
template<> \
inline void add_to_toml_table<ENUM_TYPE>( \
inline void insert_in_toml_table<ENUM_TYPE>( \
toml::table & tbl, const char* fieldName, const ENUM_TYPE& obj \
) \
{ \
static_assert( \
std::is_enum<ENUM_TYPE>::value, \
#ENUM_TYPE " must be an enum!" \
#ENUM_TYPE "must be an enum!" \
); \
using pair_t = std::pair<ENUM_TYPE, const char*>; \
static const pair_t _enum_to_string[] = { \
@ -109,23 +171,5 @@ void extract_from_toml_table(
} \
}
template<typename T>
inline void
add_to_toml_table(toml::table& tbl, const char* fieldName, const T& obj)
{
tbl.insert_or_assign(fieldName, obj);
}
template<typename T>
inline void
extract_from_toml_table(const toml::table& tbl, const char* fieldName, T& output)
{
if (!tbl.contains(fieldName)) {
throw IOCore::TomlException(
"Missing field " + std::string(fieldName)
);
}
output = tbl[fieldName].value<T>().value();
}
// clang-format off
// vim: set foldmethod=marker foldmarker=@{,@} foldminlines=10 textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :

View File

@ -1,11 +1,11 @@
# Define the executable 'test-runner'
add_executable(test-runner
runtime-tests.cpp
Util.macros.test.cpp
Util.toml.test.cpp
Application.test.cpp
FileResource.test.cpp
Exception.test.cpp
Util.macros.test.cpp
Util.toml.test.cpp
TomlTable.test.cpp
)

View File

@ -17,12 +17,10 @@
enum Colors { Red, Green, Blue };
IOCORE_TOML_ENUM(Colors, Red, Green, Blue);
// IOCORE_TOML_ENUM(Colors, { Red, "Red" }, { Green, "Green" }, { Blue, "Blue"
// });
using IOCore::TomlTable;
BEGIN_TEST_SUITE("IOCore.TomlTable")
BEGIN_TEST_SUITE("IOCore::TomlTable")
{
struct SimpleStruct {
int field1;
@ -41,7 +39,12 @@ BEGIN_TEST_SUITE("IOCore.TomlTable")
);
};
TEST_CASE("Toml::Table class construction and basic operators")
TEST_CASE("IOCore::TomlTable class construction")
{
TomlTable table;
}
TEST_CASE("IOCore::TomlTable core operators")
{
auto data = ComplexStruct{ 11, 22, Blue };
TomlTable table = data;

View File

@ -11,7 +11,6 @@
#include "test-utils/common.hpp"
#include "../include/TomlTable.hpp"
#include "../include/util/toml.hpp"
enum Colors { Red, Green, Blue };
@ -38,11 +37,12 @@ BEGIN_TEST_SUITE("Util.Toml")
TEST_CASE("IOCORE_TOML_TO Macro works")
{
toml::table table;
SimpleStruct data;
toml::table tbl;
SimpleStruct obj;
to_toml_table(table, data);
REQUIRE(table.size() == 2);
IOCORE_TOML_TO(field1);
IOCORE_TOML_TO(field2);
REQUIRE(tbl.size() == 2);
}
TEST_CASE("IOCORE_TOML_SERIALIZABLE Macro works")
{
@ -50,7 +50,7 @@ BEGIN_TEST_SUITE("Util.Toml")
ComplexStruct data = { 11, 22, Green };
ComplexStruct newdest;
to_toml_table(table, data);
table = to_toml_table(data);
from_toml_table(table, newdest);
CHECK(table.size() == 3);