summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com>2020-10-13 02:24:18 +0700
committerGitHub <noreply@github.com>2020-10-12 12:24:18 -0700
commit04bec23a37e11a80b9c6dc56657654305d658691 (patch)
tree18a54ef5f7339339c077f5d67a3a733c30d566b3 /src
parent77d57fd07560e1bfeccd34d1e4088cd36d3bf4be (diff)
downloadflatbuffers-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.cpp203
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}};";