mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-03 12:21:23 +00:00
Add support for fixed-size arrays (#5313)
This commit is contained in:
committed by
Wouter van Oortmerssen
parent
0d2cebccfe
commit
e635141d5b
@@ -601,12 +601,35 @@ CheckedError Parser::ParseType(Type &type) {
|
||||
NEXT();
|
||||
Type subtype;
|
||||
ECHECK(Recurse([&]() { return ParseType(subtype); }));
|
||||
if (subtype.base_type == BASE_TYPE_VECTOR) {
|
||||
if (IsSeries(subtype)) {
|
||||
// We could support this, but it will complicate things, and it's
|
||||
// easier to work around with a struct around the inner vector.
|
||||
return Error("nested vector types not supported (wrap in table first).");
|
||||
return Error("nested vector types not supported (wrap in table first)");
|
||||
}
|
||||
if (token_ == ':') {
|
||||
NEXT();
|
||||
if (token_ != kTokenIntegerConstant) {
|
||||
return Error("length of fixed-length array must be an integer value");
|
||||
}
|
||||
uint16_t fixed_length = 0;
|
||||
bool check = StringToNumber(attribute_.c_str(), &fixed_length);
|
||||
if (!check || fixed_length < 1) {
|
||||
return Error(
|
||||
"length of fixed-length array must be positive and fit to "
|
||||
"uint16_t type");
|
||||
}
|
||||
// Check if enum arrays are used in C++ without specifying --scoped-enums
|
||||
if ((opts.lang_to_generate & IDLOptions::kCpp) && !opts.scoped_enums &&
|
||||
IsEnum(subtype)) {
|
||||
return Error(
|
||||
"--scoped-enums must be enabled to use enum arrays in C++\n");
|
||||
}
|
||||
type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def,
|
||||
fixed_length);
|
||||
NEXT();
|
||||
} else {
|
||||
type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
|
||||
}
|
||||
type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
|
||||
type.element = subtype.base_type;
|
||||
EXPECT(']');
|
||||
} else {
|
||||
@@ -651,9 +674,19 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
Type type;
|
||||
ECHECK(ParseType(type));
|
||||
|
||||
if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
|
||||
if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type) &&
|
||||
!IsArray(type))
|
||||
return Error("structs_ may contain only scalar or struct fields");
|
||||
|
||||
if (!struct_def.fixed && IsArray(type))
|
||||
return Error("fixed-length array in table must be wrapped in struct");
|
||||
|
||||
if (IsArray(type) && !SupportsAdvancedArrayFeatures()) {
|
||||
return Error(
|
||||
"Arrays are not yet supported in all "
|
||||
"the specified programming languages.");
|
||||
}
|
||||
|
||||
FieldDef *typefield = nullptr;
|
||||
if (type.base_type == BASE_TYPE_UNION) {
|
||||
// For union fields, add a second auto-generated field to hold the type,
|
||||
@@ -703,12 +736,13 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
}
|
||||
}
|
||||
if (type.enum_def) {
|
||||
// The type.base_type can only be scalar, union or vector.
|
||||
// The type.base_type can only be scalar, union, array or vector.
|
||||
// Table, struct or string can't have enum_def.
|
||||
// Default value of union and vector in NONE, NULL translated to "0".
|
||||
FLATBUFFERS_ASSERT(IsInteger(type.base_type) ||
|
||||
(type.base_type == BASE_TYPE_UNION) ||
|
||||
(type.base_type == BASE_TYPE_VECTOR));
|
||||
(type.base_type == BASE_TYPE_VECTOR) ||
|
||||
(type.base_type == BASE_TYPE_ARRAY));
|
||||
if (type.base_type == BASE_TYPE_VECTOR) {
|
||||
// Vector can't use initialization list.
|
||||
FLATBUFFERS_ASSERT(field->value.constant == "0");
|
||||
@@ -963,6 +997,10 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
val.constant = NumToString(off);
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_ARRAY: {
|
||||
ECHECK(ParseArray(val));
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_INT:
|
||||
case BASE_TYPE_UINT:
|
||||
case BASE_TYPE_LONG:
|
||||
@@ -983,11 +1021,16 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
}
|
||||
|
||||
void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
|
||||
SerializeStruct(builder_, struct_def, val);
|
||||
}
|
||||
|
||||
void Parser::SerializeStruct(FlatBufferBuilder &builder,
|
||||
const StructDef &struct_def, const Value &val) {
|
||||
FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize);
|
||||
builder_.Align(struct_def.minalign);
|
||||
builder_.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
|
||||
struct_def.bytesize);
|
||||
builder_.AddStructOffset(val.offset, builder_.GetSize());
|
||||
builder.Align(struct_def.minalign);
|
||||
builder.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
|
||||
struct_def.bytesize);
|
||||
builder.AddStructOffset(val.offset, builder.GetSize());
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
@@ -1161,7 +1204,13 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
|
||||
break;
|
||||
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
|
||||
#undef FLATBUFFERS_TD
|
||||
// clang-format on
|
||||
case BASE_TYPE_ARRAY:
|
||||
builder_.Pad(field->padding);
|
||||
builder_.PushBytes(
|
||||
reinterpret_cast<const uint8_t*>(field_value.constant.c_str()),
|
||||
InlineSize(field_value.type));
|
||||
break;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1244,6 +1293,54 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue,
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseArray(Value &array) {
|
||||
std::vector<Value> stack;
|
||||
FlatBufferBuilder builder;
|
||||
const auto &type = array.type.VectorType();
|
||||
auto length = array.type.fixed_length;
|
||||
uoffset_t count = 0;
|
||||
auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
|
||||
vector_emplace_back(&stack, Value());
|
||||
auto &val = stack.back();
|
||||
val.type = type;
|
||||
if (IsStruct(type)) {
|
||||
ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
|
||||
} else {
|
||||
ECHECK(ParseSingleValue(nullptr, val, false));
|
||||
}
|
||||
return NoError();
|
||||
});
|
||||
ECHECK(err);
|
||||
if (length != count) return Error("Fixed-length array size is incorrect.");
|
||||
|
||||
for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
|
||||
auto &val = *it;
|
||||
// clang-format off
|
||||
switch (val.type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
|
||||
CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \
|
||||
case BASE_TYPE_ ## ENUM: \
|
||||
if (IsStruct(val.type)) { \
|
||||
SerializeStruct(builder, *val.type.struct_def, val); \
|
||||
} else { \
|
||||
CTYPE elem; \
|
||||
ECHECK(atot(val.constant.c_str(), *this, &elem)); \
|
||||
builder.PushElement(elem); \
|
||||
} \
|
||||
break;
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
default: FLATBUFFERS_ASSERT(0);
|
||||
}
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
array.constant.assign(
|
||||
reinterpret_cast<const char *>(builder.GetCurrentBufferPointer()),
|
||||
InlineSize(array.type));
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
|
||||
size_t fieldn,
|
||||
const StructDef *parent_struct_def) {
|
||||
@@ -1989,6 +2086,13 @@ bool Parser::SupportsAdvancedUnionFeatures() const {
|
||||
IDLOptions::kBinary)) == 0;
|
||||
}
|
||||
|
||||
bool Parser::SupportsAdvancedArrayFeatures() const {
|
||||
return (opts.lang_to_generate &
|
||||
~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
|
||||
IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
|
||||
IDLOptions::kBinary)) == 0;
|
||||
}
|
||||
|
||||
Namespace *Parser::UniqueNamespace(Namespace *ns) {
|
||||
for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
|
||||
if (ns->components == (*it)->components) {
|
||||
@@ -3171,19 +3275,22 @@ bool EnumVal::Deserialize(const Parser &parser,
|
||||
|
||||
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
|
||||
return reflection::CreateType(
|
||||
*builder,
|
||||
static_cast<reflection::BaseType>(base_type),
|
||||
*builder, static_cast<reflection::BaseType>(base_type),
|
||||
static_cast<reflection::BaseType>(element),
|
||||
struct_def ? struct_def->index : (enum_def ? enum_def->index : -1));
|
||||
struct_def ? struct_def->index : (enum_def ? enum_def->index : -1),
|
||||
fixed_length);
|
||||
}
|
||||
|
||||
bool Type::Deserialize(const Parser &parser, const reflection::Type *type) {
|
||||
if (type == nullptr) return true;
|
||||
base_type = static_cast<BaseType>(type->base_type());
|
||||
element = static_cast<BaseType>(type->element());
|
||||
fixed_length = type->fixed_length();
|
||||
if (type->index() >= 0) {
|
||||
bool is_series = type->base_type() == reflection::Vector ||
|
||||
type->base_type() == reflection::Array;
|
||||
if (type->base_type() == reflection::Obj ||
|
||||
(type->base_type() == reflection::Vector &&
|
||||
(is_series &&
|
||||
type->element() == reflection::Obj)) {
|
||||
if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
|
||||
struct_def = parser.structs_.vec[type->index()];
|
||||
|
||||
Reference in New Issue
Block a user