diff --git a/iguana/dynamic.hpp b/iguana/dynamic.hpp index cfb5b116..4b479b0c 100644 --- a/iguana/dynamic.hpp +++ b/iguana/dynamic.hpp @@ -17,9 +17,9 @@ constexpr inline uint8_t ENABLE_ALL = 0x0F; template struct base_impl : public base { - void to_pb(std::string& str) override { + void to_pb(std::string& str) const override { if constexpr ((ENABLE_FLAG & ENABLE_PB) != 0) { - to_pb_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + to_pb_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); } else { throw std::runtime_error("Protobuf Disabled"); @@ -35,9 +35,9 @@ struct base_impl : public base { } } - void to_json(std::string& str) override { + void to_json(std::string& str) const override { if constexpr ((ENABLE_FLAG & ENABLE_JSON) != 0) { - to_json_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + to_json_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); } else { throw std::runtime_error("Json Disabled"); @@ -53,9 +53,9 @@ struct base_impl : public base { } } - void to_xml(std::string& str) override { + void to_xml(std::string& str) const override { if constexpr ((ENABLE_FLAG & ENABLE_XML) != 0) { - to_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + to_xml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); } else { throw std::runtime_error("Xml Disabled"); @@ -71,9 +71,9 @@ struct base_impl : public base { } } - void to_yaml(std::string& str) override { + void to_yaml(std::string& str) const override { if constexpr ((ENABLE_FLAG & ENABLE_YAML) != 0) { - to_yaml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); + to_yaml_adl((iguana_adl_t*)nullptr, *(static_cast(this)), str); } else { throw std::runtime_error("Yaml Disabled"); @@ -89,18 +89,20 @@ struct base_impl : public base { } } - iguana::detail::field_info get_field_info(std::string_view name) override { + iguana::detail::field_info get_field_info( + std::string_view name) const override { static constexpr auto map = iguana::get_members(); iguana::detail::field_info info{}; - for (auto& [no, field] : map) { + for (auto const& [no, field] : map) { if (info.offset > 0) { break; } std::visit( - [&](auto val) { + [&](auto const& val) { if (val.field_name == name) { info.offset = member_offset((T*)this, val.member_ptr); - using value_type = typename decltype(val)::value_type; + using value_type = + typename std::remove_reference_t::value_type; #if defined(__clang__) || defined(_MSC_VER) || \ (defined(__GNUC__) && __GNUC__ > 8) info.type_name = type_string(); @@ -136,17 +138,18 @@ struct base_impl : public base { static constexpr auto map = iguana::get_members(); std::any result; - for (auto [no, field] : map) { + for (auto const& [no, field] : map) { if (result.has_value()) { break; } std::visit( - [&](auto val) { + [&](auto const& val) { if (val.field_name == name) { - using value_type = typename decltype(val)::value_type; + using value_type = + typename std::remove_reference_t::value_type; auto const offset = member_offset((T*)this, val.member_ptr); - auto ptr = (((char*)this) + offset); - result = {*((value_type*)ptr)}; + auto ptr = (char*)this + offset; + result = *((value_type*)ptr); } }, field); @@ -157,7 +160,7 @@ struct base_impl : public base { virtual ~base_impl() {} - size_t cache_size = 0; + mutable size_t cache_size = 0; }; IGUANA_INLINE std::shared_ptr create_instance(std::string_view name) { diff --git a/iguana/pb_util.hpp b/iguana/pb_util.hpp index 5fa7365c..27bc9a89 100644 --- a/iguana/pb_util.hpp +++ b/iguana/pb_util.hpp @@ -419,6 +419,7 @@ IGUANA_INLINE size_t pb_oneof_size(Type&& t, Arr& size_arr) { int len = 0; std::visit( [&len, &size_arr](auto&& value) IGUANA__INLINE_LAMBDA { + using raw_value_type = decltype(value); using value_type = std::remove_const_t>; constexpr auto offset = @@ -427,7 +428,7 @@ IGUANA_INLINE size_t pb_oneof_size(Type&& t, Arr& size_arr) { ((field_no + offset) << 3) | static_cast(get_wire_type()); len = pb_key_value_size( - std::forward(value), size_arr); + std::forward(value), size_arr); }, std::forward(t)); return len; @@ -454,7 +455,7 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr) { std::decay_t>; constexpr auto value = std::get(tuple); using U = typename field_type::value_type; - auto& val = value.value(t); + auto const& val = value.value(t); if constexpr (variant_v) { constexpr auto offset = get_variant_index; std::visit( [&it, &sz_ptr](auto&& value) IGUANA__INLINE_LAMBDA { + using raw_value_type = decltype(value); using value_type = std::remove_const_t>; constexpr auto offset = @@ -90,7 +91,7 @@ IGUANA_INLINE void to_pb_oneof(Type&& t, It&& it, uint32_t*& sz_ptr) { constexpr uint32_t key = ((field_no + offset) << 3) | static_cast(get_wire_type()); - to_pb_impl(std::forward(value), it, sz_ptr); + to_pb_impl(std::forward(value), it, sz_ptr); }, std::forward(t)); } @@ -449,7 +450,7 @@ IGUANA_INLINE void build_sub_proto(Map& map, std::string_view str_type, } // namespace detail template -IGUANA_INLINE void to_pb(T& t, Stream& out) { +IGUANA_INLINE void to_pb(T const& t, Stream& out) { std::vector size_arr; auto byte_len = detail::pb_key_value_size<0>(t, size_arr); detail::resize(out, byte_len); @@ -491,7 +492,7 @@ IGUANA_INLINE void to_proto_file(Stream& stream, std::string_view ns = "") { #endif template -IGUANA_INLINE void to_pb_adl(iguana_adl_t* p, T& t, Stream& out) { +IGUANA_INLINE void to_pb_adl(iguana_adl_t* p, T const& t, Stream& out) { to_pb(t, out); } diff --git a/iguana/reflection.hpp b/iguana/reflection.hpp index ceb605a4..6bad499c 100644 --- a/iguana/reflection.hpp +++ b/iguana/reflection.hpp @@ -562,17 +562,18 @@ struct field_info { }; struct base { - virtual void to_pb(std::string &str) {} + virtual void to_pb(std::string &str) const {} virtual void from_pb(std::string_view str) {} - virtual void to_xml(std::string &str) {} + virtual void to_xml(std::string &str) const {} virtual void from_xml(std::string_view str) {} - virtual void to_json(std::string &str) {} + virtual void to_json(std::string &str) const {} virtual void from_json(std::string_view str) {} - virtual void to_yaml(std::string &str) {} + virtual void to_yaml(std::string &str) const {} virtual void from_yaml(std::string_view str) {} 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) { + virtual iguana::detail::field_info get_field_info( + std::string_view name) const { return {}; } @@ -802,6 +803,7 @@ struct field_t { uint32_t field_no; auto &value(owner_type &value) const { return value.*member_ptr; } + auto const &value(owner_type const &value) const { return value.*member_ptr; } }; template diff --git a/test/test_pb.cpp b/test/test_pb.cpp index 85e27988..7e85aa1b 100644 --- a/test/test_pb.cpp +++ b/test/test_pb.cpp @@ -242,6 +242,17 @@ struct numer_st PUBLIC(numer_st) { }; REFLECTION(numer_st, a, b, c); +struct MyPerson : public iguana::base_impl { + MyPerson() = default; + MyPerson(std::string s, int d) : name(s), age(d) {} + std::string name; + int64_t age; + bool operator==(const MyPerson &other) const { + return name == other.name && age == other.age; + } +}; + +REFLECTION(MyPerson, name, age); struct person PUBLIC(person) { person() = default; person(int32_t a, std::string b, int c, double d) @@ -386,6 +397,19 @@ TEST_CASE("test reflection") { std::any_cast>(mvariant_any); assert(mvariant == temp_variant); } + { + // to_json is an const member_function now + MyPerson const p1{"xiaoming", 10}; + std::string str; + p1.to_json(str); + + // p1.to_pb(str); // compile failed + + MyPerson p2; + p2.from_json(str); + + assert(p1 == p2); + } { auto t = iguana::create_instance("pair_t"); t->set_field_value("x", 12);