From 9954e09ab7c19509a39703c572241af62a7c0499 Mon Sep 17 00:00:00 2001 From: Myrice Date: Thu, 12 Mar 2020 08:32:29 -0700 Subject: [PATCH] [C++] Generate code for vector force_align attribute. (#5796) * [Flatbuffer] Generate code for force_align with CreateXDirect and Pack functions. * Fixed Visual Studio 10.0 compile error for std::to_string. * Fixed Visual Studio 10.0 compile error for std::to_string. --- docs/source/Schemas.md | 3 +++ src/idl_gen_cpp.cpp | 29 +++++++++++++++++++++++++++++ src/idl_parser.cpp | 11 +++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md index bd37f418d..bd119b0b8 100644 --- a/docs/source/Schemas.md +++ b/docs/source/Schemas.md @@ -345,6 +345,9 @@ Current understood attributes: Note: currently not guaranteed to have an effect when used with `--object-api`, since that may allocate objects at alignments less than what you specify with `force_align`. +- `force_align: size` (on a vector): force the alignment of this vector to be + something different than what the element size would normally dictate. + Note: Now only work for generated C++ code. - `bit_flags` (on an unsigned enum): the values of this field indicate bits, meaning that any unsigned value N specified in the schema will end up representing 1<constant.c_str()) : 1; + // Generate code to do force_align for the vector. + if (align > 1) { + const auto vtype = field.value.type.VectorType(); + const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def) + : GenTypeWire(vtype, "", false); + return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type + + "), " + std::to_string(static_cast(align)) + ");"; + } + return ""; + } + void GenBuilders(const StructDef &struct_def) { code_.SetValue("STRUCT_NAME", Name(struct_def)); @@ -2307,6 +2326,11 @@ class CppGenerator : public BaseGenerator { " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? " "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;"; } else if (field.value.type.base_type == BASE_TYPE_VECTOR) { + const std::string force_align_code = + GenVectorForceAlign(field, Name(field) + "->size()"); + if (!force_align_code.empty()) { + code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }"; + } code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\"; const auto vtype = field.value.type.VectorType(); const auto has_key = TypeHasKey(vtype); @@ -2766,6 +2790,11 @@ class CppGenerator : public BaseGenerator { it != struct_def.fields.vec.end(); ++it) { auto &field = **it; if (field.deprecated) { continue; } + if (field.value.type.base_type == BASE_TYPE_VECTOR) { + const std::string force_align_code = + GenVectorForceAlign(field, "_o->" + Name(field) + ".size()"); + if (!force_align_code.empty()) { code_ += " " + force_align_code; } + } code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";"; } // Need to call "Create" with the struct namespace. diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index eda3604a9..bdda28ec4 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -1293,8 +1293,15 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue, }); ECHECK(err); - builder_.StartVector(count * InlineSize(type) / InlineAlignment(type), - InlineAlignment(type)); + const auto *force_align = field->attributes.Lookup("force_align"); + const size_t align = + force_align ? static_cast(atoi(force_align->constant.c_str())) + : 1; + const size_t len = count * InlineSize(type) / InlineAlignment(type); + const size_t elemsize = InlineAlignment(type); + if (align > 1) { builder_.ForceVectorAlignment(len, elemsize, align); } + + builder_.StartVector(len, elemsize); for (uoffset_t i = 0; i < count; i++) { // start at the back, since we're building the data backwards. auto &val = field_stack_.back().first;