mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-06 05:27:24 +00:00
Added functionality to assign field ids manually in a schema
New attribute:
- `id: n` (on a table field): manually set the field identifier to `n`.
If you use this attribute, you must use it on ALL fields of this table,
and the numbers must be a contiguous range from 0 onwards.
Additionally, since a union type effectively adds two fields, its
id must be that of the second field (the first field is the type
field and not explicitly declared in the schema).
For example, if the last field before the union field had id 6,
the union field should have id 8, and the unions type field will
implicitly be 7.
IDs allow the fields to be placed in any order in the schema.
When a new field is added to the schema is must use the next available ID.
Change-Id: I8690f105f3a2d31fdcb75a4fab4130692b12c62f
Tested: on Windows
This commit is contained in:
@@ -306,10 +306,12 @@ void Parser::ParseField(StructDef &struct_def) {
|
||||
if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type))
|
||||
Error("structs_ may contain only scalar or struct fields");
|
||||
|
||||
FieldDef *typefield = nullptr;
|
||||
if (type.base_type == BASE_TYPE_UNION) {
|
||||
// For union fields, add a second auto-generated field to hold the type,
|
||||
// with _type appended as the name.
|
||||
AddField(struct_def, name + "_type", type.enum_def->underlying_type);
|
||||
typefield = &AddField(struct_def, name + "_type",
|
||||
type.enum_def->underlying_type);
|
||||
}
|
||||
|
||||
auto &field = AddField(struct_def, name, type);
|
||||
@@ -325,6 +327,19 @@ void Parser::ParseField(StructDef &struct_def) {
|
||||
if (field.deprecated && struct_def.fixed)
|
||||
Error("can't deprecate fields in a struct");
|
||||
|
||||
if (typefield) {
|
||||
// If this field is a union, and it has a manually assigned id,
|
||||
// the automatically added type field should have an id as well (of N - 1).
|
||||
auto attr = field.attributes.Lookup("id");
|
||||
if (attr) {
|
||||
auto id = atoi(attr->constant.c_str());
|
||||
auto val = new Value();
|
||||
val->type = attr->type;
|
||||
val->constant = NumToString(id - 1);
|
||||
typefield->attributes.Add("id", val);
|
||||
}
|
||||
}
|
||||
|
||||
Expect(';');
|
||||
}
|
||||
|
||||
@@ -651,6 +666,35 @@ void Parser::ParseDecl() {
|
||||
struct_def.minalign = align;
|
||||
}
|
||||
struct_def.PadLastField(struct_def.minalign);
|
||||
// Check if this is a table that has manual id assignments
|
||||
auto &fields = struct_def.fields.vec;
|
||||
if (!struct_def.fixed && fields.size()) {
|
||||
int num_id_fields = 0;
|
||||
for (auto it = fields.begin(); it != fields.end(); ++it) {
|
||||
if ((*it)->attributes.Lookup("id")) num_id_fields++;
|
||||
}
|
||||
// If any fields have ids..
|
||||
if (num_id_fields) {
|
||||
// Then all fields must have them.
|
||||
if (num_id_fields != fields.size())
|
||||
Error("either all fields or no fields must have an 'id' attribute");
|
||||
// Simply sort by id, then the fields are the same as if no ids had
|
||||
// been specified.
|
||||
std::sort(fields.begin(), fields.end(),
|
||||
[](const FieldDef *a, const FieldDef *b) -> bool {
|
||||
auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
|
||||
auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
|
||||
return a_id < b_id;
|
||||
});
|
||||
// Verify we have a contiguous set, and reassign vtable offsets.
|
||||
for (int i = 0; i < static_cast<int>(fields.size()); i++) {
|
||||
if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
|
||||
Error("field id\'s must be consecutive from 0, id " +
|
||||
NumToString(i) + " missing or set twice");
|
||||
fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
Expect('}');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user