From 5154d5464669ca9d4c43cd9697ce0b3ec3307041 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 28 May 2024 10:19:38 +0800 Subject: [PATCH] rename and update doc --- iguana/pb_util.hpp | 22 +++++++----- iguana/reflection.hpp | 8 ++--- lang/struct_pb_intro.md | 70 ++++++++++++++++++++++++++++++++---- test/proto/unittest_proto3.h | 2 +- test/test_pb.cpp | 51 +++++++++++++------------- 5 files changed, 106 insertions(+), 47 deletions(-) diff --git a/iguana/pb_util.hpp b/iguana/pb_util.hpp index e16c909a..b2e46772 100644 --- a/iguana/pb_util.hpp +++ b/iguana/pb_util.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,7 @@ IGUANA_INLINE void to_pb(T& t, Stream& out); template IGUANA_INLINE void from_pb(T& t, std::string_view pb_str); -using pb_base = detail::pb_base; +using base = detail::base; template IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { @@ -42,7 +43,7 @@ IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { } template -struct pb_base_impl : public pb_base { +struct base_impl : public base { void to_pb(std::string& str) override { iguana::to_pb(*(static_cast(this)), str); } @@ -89,17 +90,20 @@ struct pb_base_impl : public pb_base { return vec; } - virtual ~pb_base_impl() {} + virtual ~base_impl() {} size_t cache_size = 0; }; template -constexpr bool inherits_from_pb_base_v = std::is_base_of_v; +constexpr bool inherits_from_base_v = std::is_base_of_v; -IGUANA_INLINE std::shared_ptr create_instance(std::string_view name) { +IGUANA_INLINE std::shared_ptr create_instance(std::string_view name) { auto it = iguana::detail::g_pb_map.find(name); - assert(it != iguana::detail::g_pb_map.end()); + if (it == iguana::detail::g_pb_map.end()) { + throw std::invalid_argument(std::string(name) + + "not inheried from iguana::base_impl"); + } return it->second(); } @@ -514,7 +518,7 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr) { static constexpr auto tuple = get_members_tuple(); constexpr size_t SIZE = std::tuple_size_v>; size_t pre_index = -1; - if constexpr (!inherits_from_pb_base_v && key_size != 0) { + if constexpr (!inherits_from_base_v && key_size != 0) { pre_index = size_arr.size(); size_arr.push_back(0); // placeholder } @@ -543,7 +547,7 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr) { } }, std::make_index_sequence{}); - if constexpr (inherits_from_pb_base_v) { + if constexpr (inherits_from_base_v) { t.cache_size = len; } else if constexpr (key_size != 0) { @@ -612,7 +616,7 @@ template IGUANA_INLINE size_t pb_value_size(Type&& t, uint32_t*& sz_ptr) { using T = std::remove_const_t>; if constexpr (is_reflection_v || is_custom_reflection_v) { - if constexpr (inherits_from_pb_base_v) { + if constexpr (inherits_from_base_v) { return t.cache_size; } else { diff --git a/iguana/reflection.hpp b/iguana/reflection.hpp index df38b02a..cb0ff86a 100644 --- a/iguana/reflection.hpp +++ b/iguana/reflection.hpp @@ -560,7 +560,7 @@ struct field_info { std::string_view type_name; }; -struct pb_base { +struct base { virtual void to_pb(std::string &str) {} virtual void from_pb(std::string_view str) {} virtual std::vector get_fields_name() { return {}; } @@ -585,7 +585,7 @@ struct pb_base { *((T *)ptr) = std::move(val); } - virtual ~pb_base() {} + virtual ~base() {} private: template @@ -608,14 +608,14 @@ struct pb_base { }; inline std::unordered_map()>> + std::function()>> g_pb_map; template inline bool register_type() { #if defined(__clang__) || defined(_MSC_VER) || \ (defined(__GNUC__) && __GNUC__ > 8) - if constexpr (std::is_base_of_v) { + if constexpr (std::is_base_of_v) { auto it = g_pb_map.emplace(type_string(), [] { return std::make_shared(); }); diff --git a/lang/struct_pb_intro.md b/lang/struct_pb_intro.md index 2e61bdc8..6da92ac6 100644 --- a/lang/struct_pb_intro.md +++ b/lang/struct_pb_intro.md @@ -11,14 +11,14 @@ struct_pb 是基于C++17 开发的高性能、易用、header only的protobuf格 ```cpp #include -struct my_struct : struct_pb::pb_base_impl { +struct my_struct { int x; bool y; struct_pb::fixed64_t z; }; REFLECTION(my_struct, x, y, z); -struct nest : struct_pb::pb_base_impl { +struct nest { std::string name; my_struct value; int var; @@ -29,10 +29,10 @@ REFLECTION(nest, name, value, var); ### 序列化 ```cpp int main() { - nest v{0, "Hi", {0, 1, false, 3}, 5}, v2{}; + nest v{"Hi", {1, false, {3}}, 5}, v2{}; std::string s; - struct_pb::to_pb(v, s); - struct_pb::from_pb(v2, s); + iguana::to_pb(v, s); + iguana::from_pb(v2, s); assert(v.var == v2.var); assert(v.value.y == v2.value.y); assert(v.value.z == v2.value.z); @@ -53,6 +53,62 @@ message nest { } ``` +## 动态反射 +特性: +- 根据对象名称创建实例; +- 获取对象的所有字段名; +- 根据对象实例和字段名获取或设置字段的值 + +### 根据名称创建对象 +```cpp +struct my_struct { + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest1 : public iguana::base_imple { + nest1() = default; + nest1(std::string s, my_struct t, int d) + : name(std::move(s)), value(t), var(d) {} + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest1, name, value, var); +``` + +```cpp +std::shared_ptr t = iguana::create_instance("nest1"); +``` +根据对象nest1创建了实例,返回的是基类指针。 + +“根据对象名称创建实例” 要求对象必须从iguana::base_impl 派生,如果没有派生则创建实例会抛异常。 + +### 根据名称设置字段的值 +```cpp + auto t = iguana::create_instance("nest1"); + + std::vector fields_name = t->get_fields_name(); + CHECK(fields_name == std::vector{"name", "value", "var"}); + + my_struct mt{2, true, {42}}; + t->set_field_value("value", mt); + t->set_field_value("name", std::string("test")); + t->set_field_value("var", 41); + nest1 *st = dynamic_cast(t.get()); + auto p = *st; + std::cout << p.name << "\n"; + auto &r0 = t->get_field_value("name"); + CHECK(r0 == "test"); + auto &r = t->get_field_value("var"); + CHECK(r == 41); + auto &r1 = t->get_field_value("value"); + CHECK(r1.x == 2); +``` +“根据对象实例和字段名获取或设置字段的值” 如果字段名不存在则会抛异常;如果设置的值类型和结构体字段类型不相同则会抛异常;需要类型完全一样,不允许隐式转换。比如字段类型是double,但是设置字段的值类型是int也会抛异常,必须显式传double;如果字段类型是std::string, 设置值类型是const char * 同样会报错;如果字段类型是int32_t, 设置值类型是uint_8也会抛异常,因为类型不相同。 + ## benchmark 在benchmark monster场景下,struct_pb 性能比protobuf 更好,序列化速度是protobuf的2.4倍,反序列化是protobuf的3.4倍。详情可以自行运行struct_pack 中的benchmark复现结果。 @@ -96,10 +152,10 @@ oneof -> `std::variant <...>` - 目前还只支持proto3,不支持proto2; - 目前还没支持反射; - 还没支持unkonwn字段; -- struct_pb 结构体必须派生于pb_base_impl +- struct_pb 结构体必须派生于base_impl ## roadmap - 支持proto2; - 支持反射; - 支持unkonwn字段; -- 去除struct_pb 结构体必须派生于pb_base_impl的约束; +- 去除struct_pb 结构体必须派生于base_impl的约束; diff --git a/test/proto/unittest_proto3.h b/test/proto/unittest_proto3.h index 594bd563..c1123b7f 100644 --- a/test/proto/unittest_proto3.h +++ b/test/proto/unittest_proto3.h @@ -7,7 +7,7 @@ #endif #define PB_CHECK assert -#define PUBLIC(T) : public iguana::pb_base_impl +#define PUBLIC(T) : public iguana::base_impl // define the struct as msg in proto namespace stpb { diff --git a/test/test_pb.cpp b/test/test_pb.cpp index 63804333..5b151672 100644 --- a/test/test_pb.cpp +++ b/test/test_pb.cpp @@ -17,10 +17,9 @@ void print_hex_str(const std::string &str) { std::cout << oss.str() << std::endl; } -#define BASE(T) -#define PUBLIC(T) : public iguana::pb_base_impl +#define PUBLIC(T) : public iguana::base_impl -struct point_t BASE(point_t) { +struct point_t { point_t() = default; point_t(int a, double b) : x(a), y(b) {} int x; @@ -29,7 +28,7 @@ struct point_t BASE(point_t) { REFLECTION(point_t, x, y); namespace my_space { -struct inner_struct BASE(inner_struct) { +struct inner_struct { inner_struct() = default; inner_struct(int a, int b, int c) : x(a), y(b), z(c) {} int x; @@ -44,7 +43,7 @@ constexpr inline auto get_members_impl(inner_struct *) { } } // namespace my_space -struct test_pb_st1 BASE(test_pb_st1) { +struct test_pb_st1 { test_pb_st1() = default; test_pb_st1(int a, iguana::sint32_t b, iguana::sint64_t c) : x(a), y(b), z(c) {} @@ -61,7 +60,7 @@ struct test_pb_sts PUBLIC(test_pb_sts) { }; REFLECTION(test_pb_sts, list); -struct test_pb_st2 BASE(test_pb_st2) { +struct test_pb_st2 { test_pb_st2() = default; test_pb_st2(int a, iguana::fixed32_t b, iguana::fixed64_t c) : x(a), y(b), z(c) {} @@ -71,7 +70,7 @@ struct test_pb_st2 BASE(test_pb_st2) { }; REFLECTION(test_pb_st2, x, y, z); -struct test_pb_st3 BASE(test_pb_st3) { +struct test_pb_st3 { test_pb_st3() = default; test_pb_st3(int a, iguana::sfixed32_t b, iguana::sfixed64_t c) : x(a), y(b), z(c) {} @@ -81,7 +80,7 @@ struct test_pb_st3 BASE(test_pb_st3) { }; REFLECTION(test_pb_st3, x, y, z); -struct test_pb_st4 BASE(test_pb_st3) { +struct test_pb_st4 { test_pb_st4() = default; test_pb_st4(int a, std::string b) : x(a), y(std::move(b)) {} int x; @@ -89,7 +88,7 @@ struct test_pb_st4 BASE(test_pb_st3) { }; REFLECTION(test_pb_st4, x, y); -struct test_pb_st5 BASE(test_pb_st5) { +struct test_pb_st5 { test_pb_st5() = default; test_pb_st5(int a, std::string_view b) : x(a), y(b) {} int x; @@ -97,7 +96,7 @@ struct test_pb_st5 BASE(test_pb_st5) { }; REFLECTION(test_pb_st5, x, y); -struct test_pb_st6 BASE(test_pb_st6) { +struct test_pb_st6 { test_pb_st6() = default; test_pb_st6(std::optional a, std::optional b) : x(std::move(a)), y(std::move(b)) {} @@ -106,7 +105,7 @@ struct test_pb_st6 BASE(test_pb_st6) { }; REFLECTION(test_pb_st6, x, y); -struct pair_t BASE(pair_t) { +struct pair_t PUBLIC(pair_t) { pair_t() = default; pair_t(int a, int b) : x(a), y(b) {} int x; @@ -122,7 +121,7 @@ struct message_t PUBLIC(message_t) { }; REFLECTION(message_t, id, t); -struct test_pb_st8 BASE(test_pb_st8) { +struct test_pb_st8 { test_pb_st8() = default; test_pb_st8(int a, pair_t b, message_t c) : x(a), y(b), z(c) {} @@ -132,7 +131,7 @@ struct test_pb_st8 BASE(test_pb_st8) { }; REFLECTION(test_pb_st8, x, y, z); -struct test_pb_st9 BASE(test_pb_st9) { +struct test_pb_st9 { test_pb_st9() = default; test_pb_st9(int a, std::vector b, std::string c) : x(a), y(std::move(b)), z(std::move(c)) {} @@ -142,7 +141,7 @@ struct test_pb_st9 BASE(test_pb_st9) { }; REFLECTION(test_pb_st9, x, y, z); -struct test_pb_st10 BASE(test_pb_st10) { +struct test_pb_st10 { test_pb_st10() = default; test_pb_st10(int a, std::vector b, std::string c) : x(a), y(std::move(b)), z(std::move(c)) {} @@ -163,7 +162,7 @@ struct test_pb_st11 PUBLIC(test_pb_st11) { }; REFLECTION(test_pb_st11, x, y, z); -struct test_pb_st12 BASE(test_pb_st12) { +struct test_pb_st12 { test_pb_st12() = default; test_pb_st12(int a, std::map b, std::map c) @@ -175,7 +174,7 @@ struct test_pb_st12 BASE(test_pb_st12) { }; REFLECTION(test_pb_st12, x, y, z); -struct test_pb_st13 BASE(test_pb_st13) { +struct test_pb_st13 { test_pb_st13() = default; test_pb_st13(int a, std::map b, std::string c) : x(a), y(std::move(b)), z(std::move(c)) {} @@ -190,7 +189,7 @@ enum class colors_t { red, black }; enum level_t { debug, info }; -struct test_pb_st14 BASE(test_pb_st14) { +struct test_pb_st14 { test_pb_st14() = default; test_pb_st14(int a, colors_t b, level_t c) : x(a), y(b), z(c) {} int x; @@ -200,7 +199,7 @@ struct test_pb_st14 BASE(test_pb_st14) { REFLECTION(test_pb_st14, x, y, z); namespace client { -struct person BASE(person) { +struct person { person() = default; person(std::string s, int d) : name(s), age(d) {} std::string name; @@ -210,16 +209,14 @@ struct person BASE(person) { REFLECTION(person, name, age); } // namespace client -struct my_struct BASE(my_struct) { - my_struct() = default; - my_struct(int a, bool b, iguana::fixed64_t c) : x(a), y(b), z(c) {} +struct my_struct { int x; bool y; iguana::fixed64_t z; }; REFLECTION(my_struct, x, y, z); -struct nest1 BASE(nest1) { +struct nest1 PUBLIC(nest1) { nest1() = default; nest1(std::string s, my_struct t, int d) : name(std::move(s)), value(t), var(d) {} @@ -227,10 +224,9 @@ struct nest1 BASE(nest1) { my_struct value; int var; }; - REFLECTION(nest1, name, value, var); -struct numer_st BASE(numer_st) { +struct numer_st PUBLIC(numer_st) { numer_st() = default; numer_st(bool x, double y, float z) : a(x), b(y), c(z) {} bool a; @@ -242,6 +238,9 @@ REFLECTION(numer_st, a, b, c); 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"}); + my_struct mt{2, true, {42}}; t->set_field_value("value", mt); t->set_field_value("name", std::string("test")); @@ -442,7 +441,7 @@ TEST_CASE("test struct_pb") { std::string s; m->to_pb(s); - std::shared_ptr base = m; + std::shared_ptr base = m; std::string str; base->to_pb(str); @@ -575,7 +574,7 @@ TEST_CASE("test members") { val); } -struct test_variant BASE(test_variant) { +struct test_variant { test_variant() = default; test_variant(int a, std::variant b, double c) : x(a), y(std::move(b)), z(c) {}