diff options
author | Vladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com> | 2020-10-13 02:24:18 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-12 12:24:18 -0700 |
commit | 04bec23a37e11a80b9c6dc56657654305d658691 (patch) | |
tree | 18a54ef5f7339339c077f5d67a3a733c30d566b3 /src | |
parent | 77d57fd07560e1bfeccd34d1e4088cd36d3bf4be (diff) | |
download | flatbuffers-04bec23a37e11a80b9c6dc56657654305d658691.tar.gz flatbuffers-04bec23a37e11a80b9c6dc56657654305d658691.tar.bz2 flatbuffers-04bec23a37e11a80b9c6dc56657654305d658691.zip |
Add Array initialization from struct constructor (#5865) (#6147)
- add flatbuffers::span
- add new constructor for `struct` with `array`
- add some test for flatbuffers::span and 'arrays_test.fbs'
Diffstat (limited to 'src')
-rw-r--r-- | src/idl_gen_cpp.cpp | 203 |
1 files changed, 136 insertions, 67 deletions
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index f6535f0c..5b5d978d 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -72,6 +72,12 @@ namespace cpp { enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 }; +// Define a style of 'struct' constructor if it has 'Array' fields. +enum GenArrayArgMode { + kArrayArgModeNone, // don't generate initialization args + kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N> +}; + // Extension of IDLOptions for cpp-generator. struct IDLOptionsCpp : public IDLOptions { // All fields start with 'g_' prefix to distinguish from the base IDLOptions. @@ -820,6 +826,38 @@ class CppGenerator : public BaseGenerator { } } + std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) { + // Generate "flatbuffers::span<const U, extent>". + FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type"); + auto element_type = type.VectorType(); + std::string text = "flatbuffers::span<"; + text += immutable ? "const " : ""; + if (IsScalar(element_type.base_type)) { + text += GenTypeBasic(element_type, IsEnum(element_type)); + } else { + switch (element_type.base_type) { + case BASE_TYPE_STRING: { + text += "char"; + break; + } + case BASE_TYPE_STRUCT: { + FLATBUFFERS_ASSERT(type.struct_def); + text += WrapInNameSpace(*type.struct_def); + break; + } + default: + FLATBUFFERS_ASSERT(false && "unexpected element's type"); + break; + } + } + if (extent != flatbuffers::dynamic_extent) { + text += ", "; + text += NumToString(extent); + } + text += "> "; + return text; + } + std::string GenEnumValDecl(const EnumDef &enum_def, const std::string &enum_val) const { return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val; @@ -2938,13 +2976,14 @@ class CppGenerator : public BaseGenerator { static void PaddingInitializer(int bits, std::string *code_ptr, int *id) { (void)bits; - if (*code_ptr != "") *code_ptr += ",\n "; + if (!code_ptr->empty()) *code_ptr += ",\n "; *code_ptr += "padding" + NumToString((*id)++) + "__(0)"; } static void PaddingNoop(int bits, std::string *code_ptr, int *id) { (void)bits; - *code_ptr += " (void)padding" + NumToString((*id)++) + "__;\n"; + if (!code_ptr->empty()) *code_ptr += '\n'; + *code_ptr += " (void)padding" + NumToString((*id)++) + "__;"; } void GenStructDefaultConstructor(const StructDef &struct_def) { @@ -2989,58 +3028,50 @@ class CppGenerator : public BaseGenerator { code_ += " {}"; } else { code_.SetValue("INIT_LIST", init_list); - code_.SetValue("DEFAULT_CONSTRUCTOR_BODY", body); code_ += " {{STRUCT_NAME}}()"; code_ += " : {{INIT_LIST}} {"; - code_ += "{{DEFAULT_CONSTRUCTOR_BODY}} }"; + if (!body.empty()) { code_ += body; } + code_ += " }"; } } - void GenStructConstructor(const StructDef &struct_def) { + void GenStructConstructor(const StructDef &struct_def, + GenArrayArgMode array_mode) { std::string arg_list; std::string init_list; int padding_id = 0; - bool first_arg = true; - bool first_init = true; + auto first = struct_def.fields.vec.begin(); + // skip arrays if generate ctor without array assignment + const auto init_arrays = (array_mode != kArrayArgModeNone); for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; - const auto &field_type = field.value.type; - const auto member_name = Name(field) + "_"; + const auto &type = field.value.type; + const auto is_array = IsArray(type); const auto arg_name = "_" + Name(field); - const auto arg_type = GenTypeGet(field_type, " ", "const ", " &", true); - - if (!IsArray(field_type)) { - if (first_arg) { - first_arg = false; - } else { - arg_list += ", "; - } - arg_list += arg_type; + if (!is_array || init_arrays) { + if (it != first && !arg_list.empty()) { arg_list += ", "; } + arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true) + : GenTypeSpan(type, true, type.fixed_length); arg_list += arg_name; } - if (first_init) { - first_init = false; - } else { - init_list += ","; - init_list += "\n "; - } - init_list += member_name; - if (IsScalar(field_type.base_type)) { - auto type = GenUnderlyingCast(field, false, arg_name); - init_list += "(flatbuffers::EndianScalar(" + type + "))"; - } else if (IsArray(field_type)) { - // implicit initialization of array - // for each object in array it: - // * sets it as zeros for POD types (integral, floating point, etc) - // * calls default constructor for classes/structs - init_list += "()"; - } else { - init_list += "(" + arg_name + ")"; + // skip an array with initialization from span + if (false == (is_array && init_arrays)) { + if (it != first && !init_list.empty()) { init_list += ",\n "; } + init_list += Name(field) + "_"; + if (IsScalar(type.base_type)) { + auto scalar_type = GenUnderlyingCast(field, false, arg_name); + init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))"; + } else { + FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type)); + if (!is_array) + init_list += "(" + arg_name + ")"; + else + init_list += "()"; + } } - if (field.padding) { + if (field.padding) GenPadding(field, &init_list, &padding_id, PaddingInitializer); - } } if (!arg_list.empty()) { @@ -3052,10 +3083,55 @@ class CppGenerator : public BaseGenerator { } else { code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {"; } + padding_id = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + const auto &type = field.value.type; + if (IsArray(type) && init_arrays) { + const auto &element_type = type.VectorType(); + const auto is_enum = IsEnum(element_type); + FLATBUFFERS_ASSERT( + (IsScalar(element_type.base_type) || IsStruct(element_type)) && + "invalid declaration"); + const auto face_type = GenTypeGet(type, " ", "", "", is_enum); + std::string get_array = + is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray"; + const auto field_name = Name(field) + "_"; + const auto arg_name = "_" + Name(field); + code_ += " flatbuffers::" + get_array + "(" + field_name + + ").CopyFromSpan(" + arg_name + ");"; + } + if (field.padding) { + std::string padding; + GenPadding(field, &padding, &padding_id, PaddingNoop); + code_ += padding; + } + } code_ += " }"; } } + void GenArrayAccessor(const Type &type, bool mutable_accessor) { + FLATBUFFERS_ASSERT(IsArray(type)); + const auto is_enum = IsEnum(type.VectorType()); + // The Array<bool,N> is a tricky case, like std::vector<bool>. + // It requires a specialization of Array class. + // Generate Array<uint8_t> for Array<bool>. + const auto face_type = GenTypeGet(type, " ", "", "", is_enum); + std::string ret_type = "flatbuffers::Array<" + face_type + ", " + + NumToString(type.fixed_length) + ">"; + if (mutable_accessor) + code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {"; + else + code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {"; + + std::string get_array = + is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray"; + code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});"; + code_ += " }"; + } + // Generate an accessor struct with constructor for a flatbuffers struct. void GenStruct(const StructDef &struct_def) { // Generate an accessor struct, with private variables of the form: @@ -3110,19 +3186,29 @@ class CppGenerator : public BaseGenerator { GenStructDefaultConstructor(struct_def); // Generate a constructor that takes all fields as arguments, - // excluding arrays - GenStructConstructor(struct_def); + // excluding arrays. + GenStructConstructor(struct_def, kArrayArgModeNone); + + auto arrays_num = std::count_if(struct_def.fields.vec.begin(), + struct_def.fields.vec.end(), + [](const flatbuffers::FieldDef *fd) { + return IsArray(fd->value.type); + }); + if (arrays_num > 0) { + GenStructConstructor(struct_def, kArrayArgModeSpanStatic); + } // Generate accessor methods of the form: // type name() const { return flatbuffers::EndianScalar(name_); } for (auto it = struct_def.fields.vec.begin(); it != struct_def.fields.vec.end(); ++it) { const auto &field = **it; + const auto &type = field.value.type; + const auto is_scalar = IsScalar(type.base_type); + const auto is_array = IsArray(type); - auto field_type = GenTypeGet(field.value.type, " ", - IsArray(field.value.type) ? "" : "const ", - IsArray(field.value.type) ? "" : " &", true); - auto is_scalar = IsScalar(field.value.type.base_type); + const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ", + is_array ? "" : " &", true); auto member = Name(field) + "_"; auto value = is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member; @@ -3134,16 +3220,8 @@ class CppGenerator : public BaseGenerator { GenComment(field.doc_comment, " "); // Generate a const accessor function. - if (IsArray(field.value.type)) { - auto underlying = GenTypeGet(field.value.type, "", "", "", false); - code_ += " const flatbuffers::Array<" + field_type + ", " + - NumToString(field.value.type.fixed_length) + "> *" + - "{{FIELD_NAME}}() const {"; - code_ += " return reinterpret_cast<const flatbuffers::Array<" + - field_type + ", " + - NumToString(field.value.type.fixed_length) + - "> *>({{FIELD_VALUE}});"; - code_ += " }"; + if (is_array) { + GenArrayAccessor(type, false); } else { code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {"; code_ += " return {{FIELD_VALUE}};"; @@ -3153,11 +3231,10 @@ class CppGenerator : public BaseGenerator { // Generate a mutable accessor function. if (opts_.mutable_buffer) { auto mut_field_type = - GenTypeGet(field.value.type, " ", "", - IsArray(field.value.type) ? "" : " &", true); + GenTypeGet(type, " ", "", is_array ? "" : " &", true); code_.SetValue("FIELD_TYPE", mut_field_type); if (is_scalar) { - code_.SetValue("ARG", GenTypeBasic(field.value.type, true)); + code_.SetValue("ARG", GenTypeBasic(type, true)); code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, false, "_" + Name(field))); @@ -3166,16 +3243,8 @@ class CppGenerator : public BaseGenerator { " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, " "{{FIELD_VALUE}});"; code_ += " }"; - } else if (IsArray(field.value.type)) { - auto underlying = GenTypeGet(field.value.type, "", "", "", false); - code_ += " flatbuffers::Array<" + mut_field_type + ", " + - NumToString(field.value.type.fixed_length) + "> *" + - "mutable_{{FIELD_NAME}}() {"; - code_ += " return reinterpret_cast<flatbuffers::Array<" + - mut_field_type + ", " + - NumToString(field.value.type.fixed_length) + - "> *>({{FIELD_VALUE}});"; - code_ += " }"; + } else if (is_array) { + GenArrayAccessor(type, true); } else { code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {"; code_ += " return {{FIELD_VALUE}};"; |