Made user-defined attributes available in the reflection data.

Tested: on Linux.

Bug: 27923233
Change-Id: Ic16675650e4a8e138c163f1e2131a3aad7008ada
parent 9f2b05df
......@@ -18,7 +18,6 @@
#define FLATBUFFERS_IDL_H_
#include <map>
#include <set>
#include <stack>
#include <memory>
#include <functional>
......@@ -113,6 +112,7 @@ inline size_t SizeOf(BaseType t) {
struct StructDef;
struct EnumDef;
struct Parser;
// Represents any type in the IDL, which is a combination of the BaseType
// and additional information for vectors/structs_.
......@@ -184,10 +184,8 @@ template<typename T> class SymbolTable {
return it == dict.end() ? nullptr : it->second;
}
private:
std::map<std::string, T *> dict; // quick lookup
public:
std::map<std::string, T *> dict; // quick lookup
std::vector<T *> vec; // Used to iterate in order of insertion
};
......@@ -208,6 +206,11 @@ struct Definition {
Definition() : generated(false), defined_namespace(nullptr),
serialized_location(0), index(-1) {}
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
reflection::KeyValue>>>
SerializeAttributes(FlatBufferBuilder *builder,
const Parser &parser) const;
std::string name;
std::string file;
std::vector<std::string> doc_comment;
......@@ -223,8 +226,8 @@ struct Definition {
struct FieldDef : public Definition {
FieldDef() : deprecated(false), required(false), key(false), padding(0) {}
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id)
const;
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
const Parser &parser) const;
Value value;
bool deprecated; // Field is allowed to be present in old data, but can't be
......@@ -250,7 +253,8 @@ struct StructDef : public Definition {
if (fields.vec.size()) fields.vec.back()->padding = padding;
}
Offset<reflection::Object> Serialize(FlatBufferBuilder *builder) const;
Offset<reflection::Object> Serialize(FlatBufferBuilder *builder,
const Parser &parser) const;
SymbolTable<FieldDef> fields;
bool fixed; // If it's struct, not a table.
......@@ -299,7 +303,8 @@ struct EnumDef : public Definition {
return nullptr;
}
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder) const;
Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder,
const Parser &parser) const;
SymbolTable<EnumVal> vals;
bool is_union;
......@@ -406,18 +411,18 @@ class Parser {
anonymous_counter(0) {
// Just in case none are declared:
namespaces_.push_back(new Namespace());
known_attributes_.insert("deprecated");
known_attributes_.insert("required");
known_attributes_.insert("key");
known_attributes_.insert("hash");
known_attributes_.insert("id");
known_attributes_.insert("force_align");
known_attributes_.insert("bit_flags");
known_attributes_.insert("original_order");
known_attributes_.insert("nested_flatbuffer");
known_attributes_.insert("csharp_partial");
known_attributes_.insert("stream");
known_attributes_.insert("idempotent");
known_attributes_["deprecated"] = true;
known_attributes_["required"] = true;
known_attributes_["key"] = true;
known_attributes_["hash"] = true;
known_attributes_["id"] = true;
known_attributes_["force_align"] = true;
known_attributes_["bit_flags"] = true;
known_attributes_["original_order"] = true;
known_attributes_["nested_flatbuffer"] = true;
known_attributes_["csharp_partial"] = true;
known_attributes_["stream"] = true;
known_attributes_["idempotent"] = true;
}
~Parser() {
......@@ -528,6 +533,8 @@ private:
std::map<std::string, bool> included_files_;
std::map<std::string, std::set<std::string>> files_included_per_file_;
std::map<std::string, bool> known_attributes_;
IDLOptions opts;
private:
......@@ -541,8 +548,6 @@ private:
std::vector<std::pair<Value, FieldDef *>> field_stack_;
std::set<std::string> known_attributes_;
int anonymous_counter;
};
......
This diff is collapsed.
......@@ -34,6 +34,11 @@ table Type {
// from an enum, index into "enums" below.
}
table KeyValue {
key:string (required, key);
value:string;
}
table EnumVal {
name:string (required);
value:long (key);
......@@ -45,6 +50,7 @@ table Enum {
values:[EnumVal] (required); // In order of their values.
is_union:bool = false;
underlying_type:Type (required);
attributes:[KeyValue];
}
table Field {
......@@ -57,6 +63,7 @@ table Field {
deprecated:bool = false;
required:bool = false;
key:bool = false;
attributes:[KeyValue];
}
table Object { // Used for both tables and structs.
......@@ -65,6 +72,7 @@ table Object { // Used for both tables and structs.
is_struct:bool = false;
minalign:int;
bytesize:int; // For structs.
attributes:[KeyValue];
}
table Schema {
......
......@@ -1784,7 +1784,7 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
auto name = attribute_;
EXPECT(kTokenStringConstant);
EXPECT(';');
known_attributes_.insert(name);
known_attributes_[name] = false;
} else if (token_ == kTokenService) {
ECHECK(ParseService());
} else {
......@@ -1853,13 +1853,13 @@ void Parser::Serialize() {
AssignIndices(enums_.vec);
std::vector<Offset<reflection::Object>> object_offsets;
for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_);
auto offset = (*it)->Serialize(&builder_, *this);
object_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
}
std::vector<Offset<reflection::Enum>> enum_offsets;
for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
auto offset = (*it)->Serialize(&builder_);
auto offset = (*it)->Serialize(&builder_, *this);
enum_offsets.push_back(offset);
(*it)->serialized_location = offset.o;
}
......@@ -1875,13 +1875,13 @@ void Parser::Serialize() {
builder_.Finish(schema_offset, reflection::SchemaIdentifier());
}
Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder)
const {
Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
const Parser &parser) const {
std::vector<Offset<reflection::Field>> field_offsets;
for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
field_offsets.push_back(
(*it)->Serialize(builder,
static_cast<uint16_t>(it - fields.vec.begin())));
static_cast<uint16_t>(it - fields.vec.begin()), parser));
}
return reflection::CreateObject(*builder,
builder->CreateString(name),
......@@ -1889,11 +1889,13 @@ Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder)
&field_offsets),
fixed,
static_cast<int>(minalign),
static_cast<int>(bytesize));
static_cast<int>(bytesize),
SerializeAttributes(builder, parser));
}
Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
uint16_t id) const {
uint16_t id,
const Parser &parser) const {
return reflection::CreateField(*builder,
builder->CreateString(name),
value.type.Serialize(builder),
......@@ -1907,12 +1909,14 @@ Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
: 0.0,
deprecated,
required,
key);
key,
SerializeAttributes(builder, parser));
// TODO: value.constant is almost always "0", we could save quite a bit of
// space by sharing it. Same for common values of value.type.
}
Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder) const {
Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
const Parser &parser) const {
std::vector<Offset<reflection::EnumVal>> enumval_offsets;
for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
enumval_offsets.push_back((*it)->Serialize(builder));
......@@ -1921,7 +1925,8 @@ Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder) const {
builder->CreateString(name),
builder->CreateVector(enumval_offsets),
is_union,
underlying_type.Serialize(builder));
underlying_type.Serialize(builder),
SerializeAttributes(builder, parser));
}
Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
......@@ -1942,4 +1947,26 @@ Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
(enum_def ? enum_def->index : -1));
}
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
reflection::KeyValue>>>
Definition::SerializeAttributes(FlatBufferBuilder *builder,
const Parser &parser) const {
std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
for (auto kv : attributes.dict) {
auto it = parser.known_attributes_.find(kv.first);
assert(it != parser.known_attributes_.end());
if (!it->second) { // Custom attribute.
attrs.push_back(
reflection::CreateKeyValue(*builder, builder->CreateString(kv.first),
builder->CreateString(
kv.second->constant)));
}
}
if (attrs.size()) {
return builder->CreateVectorOfSortedTables(&attrs);
} else {
return 0;
}
}
} // namespace flatbuffers
No preview for this file type
......@@ -7,16 +7,6 @@
#include "namespace_test1_generated.h"
namespace NamespaceA {
namespace NamespaceB {
struct TableInNestedNS;
struct StructInNestedNS;
} // namespace NamespaceB
} // namespace NamespaceA
namespace NamespaceA {
struct TableInFirstNS;
......
......@@ -322,6 +322,10 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
TEST_EQ_STR(hp_field.name()->c_str(), "hp");
TEST_EQ(hp_field.id(), 2);
TEST_EQ(hp_field.type()->base_type(), reflection::Short);
auto friendly_field_ptr = fields->LookupByKey("friendly");
TEST_NOTNULL(friendly_field_ptr);
TEST_NOTNULL(friendly_field_ptr->attributes());
TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
// Now use it to dynamically access a buffer.
auto &root = *flatbuffers::GetAnyRoot(flatbuf);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment