From c9f715a9ea0c3d53998ffe8e98f9d984675d7fdd Mon Sep 17 00:00:00 2001 From: Roman Strakhov Date: Wed, 17 Apr 2024 13:47:38 +0400 Subject: [PATCH 1/3] do not indent empty lines --- messgen/cpp_generator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/messgen/cpp_generator.py b/messgen/cpp_generator.py index dbe7e01..13c614e 100644 --- a/messgen/cpp_generator.py +++ b/messgen/cpp_generator.py @@ -17,7 +17,7 @@ def _indent(c): elif type(c) is list: r = [] for i in c: - r.append(spaces + i) + r.append(spaces + i if i else "") return r else: raise RuntimeError("Unsupported type for indent: %s" % type(c)) @@ -328,7 +328,7 @@ def _generate_type_struct(self, type_name): "size_t serialized_size() const {", _indent("// %s" % ", ".join(fixed_fields)), _indent("size_t _size = %d;" % fixed_size), - _indent(""), + "", ] + _indent(code_ss) + [ "}"] code.extend(_indent(code_ss)) @@ -598,7 +598,7 @@ def _deserialize_field(self, field_name, field_type_def, level_n=0): "for (size_t _i%d = 0; _i%d < _map_size%d; ++_i%d) {" % (level_n, level_n, level_n, level_n))) c.append(_indent(_indent("%s _key%d;" % (key_c_type, level_n)))) c.append(_indent(_indent("%s _value%d;" % (value_c_type, level_n)))) - c.append(_indent(_indent(""))) + c.append("") c.extend(_indent( _indent( self._deserialize_field("_key%d" % level_n, key_type_def, level_n + 1)))) From 9a85f811fbbd9e69645981c1ab9a208a6e757328 Mon Sep 17 00:00:00 2001 From: Roman Strakhov Date: Wed, 17 Apr 2024 13:51:16 +0400 Subject: [PATCH 2/3] add struct name field --- messgen/cpp_generator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/messgen/cpp_generator.py b/messgen/cpp_generator.py index 13c614e..8a85cd2 100644 --- a/messgen/cpp_generator.py +++ b/messgen/cpp_generator.py @@ -232,6 +232,7 @@ def _generate_type_struct(self, type_name): code.append(_indent("static constexpr size_t FLAT_SIZE = %d;" % groups[0].size)) is_flat_str = "true" code.append(_indent("static constexpr bool IS_FLAT = %s;" % is_flat_str)) + code.append(_indent("static constexpr const char* NAME = \"%s\";" % type_name)) code.append("") for field in type_def["fields"]: From 5939659e7e91b21955fe19973669136263700148 Mon Sep 17 00:00:00 2001 From: Roman Strakhov Date: Wed, 17 Apr 2024 15:23:15 +0400 Subject: [PATCH 3/3] allow empty structs --- messgen/cpp_generator.py | 23 +++++++++++++------ messgen/protocols.py | 1 + tests/cpp_nostl/CppNostlTest.h | 9 ++++++++ tests/cpp_stl/CppTest.h | 6 +++++ .../test_proto/complex_struct_with_empty.yaml | 10 ++++++++ .../messgen/test_proto/empty_struct.yaml | 3 +++ 6 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 tests/messages/messgen/test_proto/complex_struct_with_empty.yaml create mode 100644 tests/messages/messgen/test_proto/empty_struct.yaml diff --git a/messgen/cpp_generator.py b/messgen/cpp_generator.py index dbe7e01..c4a061b 100644 --- a/messgen/cpp_generator.py +++ b/messgen/cpp_generator.py @@ -228,8 +228,9 @@ def _generate_type_struct(self, type_name): # IS_FLAT flag is_flat_str = "false" - if (len(groups) == 1 and groups[0].size is not None): - code.append(_indent("static constexpr size_t FLAT_SIZE = %d;" % groups[0].size)) + is_empty = len(groups) == 0 + if is_empty or (len(groups) == 1 and groups[0].size is not None): + code.append(_indent("static constexpr size_t FLAT_SIZE = %d;" % (0 if is_empty else groups[0].size))) is_flat_str = "true" code.append(_indent("static constexpr bool IS_FLAT = %s;" % is_flat_str)) code.append("") @@ -433,7 +434,7 @@ def _cpp_type(self, type_name: str) -> str: raise RuntimeError("Can't get c++ type for %s" % type_name) def _field_groups(self, fields): - groups = [FieldsGroup()] + groups = [FieldsGroup()] if len(fields) > 0 else [] for field in fields: type_def = self._protocols.get_type(self._ctx["proto_name"], field["type"]) align = self._get_alignment(type_def) @@ -478,7 +479,9 @@ def _serialize_field(self, field_name, field_type_def, level_n=0): el_type_def = self._protocols.get_type(self._ctx["proto_name"], field_type_def["element_type"]) el_size = el_type_def.get("size") el_align = self._get_alignment(el_type_def) - if el_size is not None and el_size % el_align == 0: + if el_size == 0: + pass + elif el_size is not None and el_size % el_align == 0: # Vector of fixed size elements, optimize with single memcpy c.append("_field_size = %d * %s.size();" % (el_size, field_name)) c.extend(self._memcpy_to_buf("%s[0]" % field_name, "_field_size")) @@ -540,7 +543,9 @@ def _deserialize_field(self, field_name, field_type_def, level_n=0): el_type_def = self._protocols.get_type(self._ctx["proto_name"], field_type_def["element_type"]) el_size = el_type_def.get("size") el_align = self._get_alignment(el_type_def) - if el_size is not None and el_size % el_align == 0: + if el_size == 0: + pass + elif el_size is not None and el_size % el_align == 0: # Vector or array of fixed size elements, optimize with single memcpy c.append("_field_size = %d * %s.size();" % (el_size, field_name)) c.extend(self._memcpy_from_buf("%s[0]" % field_name, "_field_size")) @@ -557,7 +562,9 @@ def _deserialize_field(self, field_name, field_type_def, level_n=0): el_align = self._get_alignment(el_type_def) c.append("%s.resize(*reinterpret_cast(&_buf[_size]));" % field_name) c.append("_size += sizeof(messgen::size_type);") - if el_size is not None and el_size % el_align == 0: + if el_size == 0: + pass + elif el_size is not None and el_size % el_align == 0: # Vector or array of fixed size elements, optimize with single memcpy c.append("_field_size = %d * %s.size();" % (el_size, field_name)) c.extend(self._memcpy_from_buf("%s[0]" % field_name, "_field_size")) @@ -574,7 +581,9 @@ def _deserialize_field(self, field_name, field_type_def, level_n=0): c.append("_field_size = *reinterpret_cast(&_buf[_size]);") c.append("%s = {_alloc.alloc<%s>(_field_size), _field_size};" % (field_name, el_c_type)) c.append("_size += sizeof(messgen::size_type);") - if el_size is not None and el_size % el_align == 0: + if el_size == 0: + pass + elif el_size is not None and el_size % el_align == 0: # Vector or array of fixed size elements, optimize with single memcpy if el_size != 1: c.append("_field_size *= %d;" % el_size) diff --git a/messgen/protocols.py b/messgen/protocols.py index d2c9eee..0320f9b 100644 --- a/messgen/protocols.py +++ b/messgen/protocols.py @@ -173,6 +173,7 @@ def get_type(self, curr_proto_name, type_name) -> dict: elif t["type_class"] == "struct": sz = 0 fixed_size = True + t["fields"] = t.get("fields") if isinstance(t.get("fields"), list) else [] for i in t["fields"]: it = self.get_type(curr_proto_name, i["type"]) isz = it.get("size") diff --git a/tests/cpp_nostl/CppNostlTest.h b/tests/cpp_nostl/CppNostlTest.h index 67ef514..175ae19 100644 --- a/tests/cpp_nostl/CppNostlTest.h +++ b/tests/cpp_nostl/CppNostlTest.h @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -96,3 +97,11 @@ TEST_F(CppNostlTest, ComplexStructNpstl) { test_serialization(msg); } + +TEST_F(CppNostlTest, EmptyStruct) { + messgen::test_proto::empty_struct e{}; + ASSERT_TRUE(e.IS_FLAT); + ASSERT_EQ(e.FLAT_SIZE, 0); + ASSERT_EQ(e.serialized_size(), 0); + test_serialization(e); +} diff --git a/tests/cpp_stl/CppTest.h b/tests/cpp_stl/CppTest.h index d3e0759..b73a306 100644 --- a/tests/cpp_stl/CppTest.h +++ b/tests/cpp_stl/CppTest.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -197,3 +198,8 @@ TEST_F(CppTest, TwoMsg) { EXPECT_EQ(msg1, msg1c); EXPECT_EQ(msg2, msg2c); } + +TEST_F(CppTest, ComplexStructWithEmpty) { + messgen::test_proto::complex_struct_with_empty e{}; + test_serialization(e); +} diff --git a/tests/messages/messgen/test_proto/complex_struct_with_empty.yaml b/tests/messages/messgen/test_proto/complex_struct_with_empty.yaml new file mode 100644 index 0000000..cc9c0fa --- /dev/null +++ b/tests/messages/messgen/test_proto/complex_struct_with_empty.yaml @@ -0,0 +1,10 @@ +type_class: struct +comment: "Struct with empty_struct in its fields" +fields: + - { name: "e", type: "empty_struct" } + - { name: "dynamic_array", type: "empty_struct[]" } + - { name: "static_array", type: "empty_struct[5]" } + - { name: "multi_array", type: "empty_struct[][5][]" } + - { name: "map_empty_by_int", type: "empty_struct{int32}" } + - { name: "map_vec_by_str", type: "empty_struct[]{string}" } + - { name: "array_of_size_zero", type: "int32[0]" } diff --git a/tests/messages/messgen/test_proto/empty_struct.yaml b/tests/messages/messgen/test_proto/empty_struct.yaml new file mode 100644 index 0000000..d6f053f --- /dev/null +++ b/tests/messages/messgen/test_proto/empty_struct.yaml @@ -0,0 +1,3 @@ +type_class: struct +comment: "Struct without data. May be used for heartbeat, command with no args, etc" +fields: