diff --git a/iguana/dynamic.hpp b/iguana/dynamic.hpp index 5bdc43be..14ff6ed5 100644 --- a/iguana/dynamic.hpp +++ b/iguana/dynamic.hpp @@ -113,20 +113,48 @@ struct base_impl : public base { return info; } - std::vector get_fields_name() override { + std::vector get_fields_name() const override { static constexpr auto map = iguana::get_members(); + std::vector vec; - for (auto [no, val] : map) { + + for (auto const& [no, val] : map) { std::visit( - [&](auto& field) { - vec.push_back(std::string_view(field.field_name.data(), - field.field_name.size())); + [&](auto const& field) { + std::string_view const current_name{field.field_name.data(), + field.field_name.size()}; + if (vec.empty() || (vec.back() != current_name)) { + vec.push_back(current_name); + } }, val); } return vec; } + std::any get_field_any(std::string_view name) const override { + static constexpr auto map = iguana::get_members(); + std::any result; + + for (auto [no, field] : map) { + if (result.has_value()) { + break; + } + std::visit( + [&](auto val) { + if (val.field_name == name) { + using value_type = typename decltype(val)::value_type; + auto const offset = member_offset((T*)this, val.member_ptr); + auto ptr = (((char*)this) + offset); + result = {*((value_type*)ptr)}; + } + }, + field); + } + + return result; + } + virtual ~base_impl() {} size_t cache_size = 0; diff --git a/iguana/reflection.hpp b/iguana/reflection.hpp index 9579ce8e..d5029d7b 100644 --- a/iguana/reflection.hpp +++ b/iguana/reflection.hpp @@ -4,6 +4,7 @@ #ifndef IGUANA_REFLECTION_HPP #define IGUANA_REFLECTION_HPP +#include #include #include #include @@ -569,7 +570,8 @@ struct base { virtual void from_json(std::string_view str) {} virtual void to_yaml(std::string &str) {} virtual void from_yaml(std::string_view str) {} - virtual std::vector get_fields_name() { return {}; } + virtual std::vector get_fields_name() const { return {}; } + virtual std::any get_field_any(std::string_view name) const { return {}; } virtual iguana::detail::field_info get_field_info(std::string_view name) { return {}; } diff --git a/test/test_pb.cpp b/test/test_pb.cpp index be29cfd5..bf784338 100644 --- a/test/test_pb.cpp +++ b/test/test_pb.cpp @@ -211,6 +211,9 @@ struct my_struct { int x; bool y; iguana::fixed64_t z; + bool operator==(const my_struct &other) const { + return x == other.x && y == other.y && z == other.z; + } }; REFLECTION(my_struct, x, y, z); @@ -221,8 +224,9 @@ struct nest1 PUBLIC(nest1) { std::string name; my_struct value; int var; + std::variant mv; }; -REFLECTION(nest1, name, value, var); +REFLECTION(nest1, name, value, var, mv); struct numer_st PUBLIC(numer_st) { numer_st() = default; @@ -237,7 +241,8 @@ TEST_CASE("test reflection") { { auto t = iguana::create_instance("nest1"); std::vector fields_name = t->get_fields_name(); - CHECK(fields_name == std::vector{"name", "value", "var"}); + CHECK(fields_name == + std::vector{"name", "value", "var", "mv"}); my_struct mt{2, true, {42}}; t->set_field_value("value", mt); @@ -259,6 +264,28 @@ TEST_CASE("test reflection") { CHECK_THROWS_AS(t->set_field_value("name", 42), std::invalid_argument); } + { + my_struct temp_my{1, false, {3}}; + nest1 t{"Hi", temp_my, 5}; + + auto const temp_variant = std::variant{1}; + t.set_field_value("mv", temp_variant); + + // dynamic any + auto const &any_name = t.get_field_any("name"); + assert(std::any_cast(any_name) == "Hi"); + + auto const &any_value = t.get_field_any("value"); + assert(std::any_cast(any_value) == temp_my); + + auto const &any_var = t.get_field_any("var"); + assert(std::any_cast(any_var) == 5); + + auto const &mvariant_any = t.get_field_any("mv"); + auto const &mvariant = + std::any_cast>(mvariant_any); + assert(mvariant == temp_variant); + } { auto t = iguana::create_instance("pair_t"); t->set_field_value("x", 12);