Reflection: generically copy (parts of) FlatBuffers.

Change-Id: Ief3f1507c003079eac90c2bb6c2abd64a80a0a34
Tested: on Linux.
parent 1c152cc7
...@@ -713,6 +713,10 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS { ...@@ -713,6 +713,10 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
return CreateString(str.c_str(), str.length()); return CreateString(str.c_str(), str.length());
} }
Offset<String> CreateString(const String *str) {
return CreateString(str->c_str(), str->Length());
}
uoffset_t EndVector(size_t len) { uoffset_t EndVector(size_t len) {
return PushElement(static_cast<uoffset_t>(len)); return PushElement(static_cast<uoffset_t>(len));
} }
......
This diff is collapsed.
...@@ -255,6 +255,8 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { ...@@ -255,6 +255,8 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); } int KeyCompareWithValue(const char *val) const { return strcmp(name()->c_str(), val); }
const flatbuffers::Vector<flatbuffers::Offset<Field>> *fields() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Field>> *>(6); } const flatbuffers::Vector<flatbuffers::Offset<Field>> *fields() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Field>> *>(6); }
uint8_t is_struct() const { return GetField<uint8_t>(8, 0); } uint8_t is_struct() const { return GetField<uint8_t>(8, 0); }
int32_t minalign() const { return GetField<int32_t>(10, 0); }
int32_t bytesize() const { return GetField<int32_t>(12, 0); }
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) && VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, 4 /* name */) &&
...@@ -263,6 +265,8 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { ...@@ -263,6 +265,8 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
verifier.Verify(fields()) && verifier.Verify(fields()) &&
verifier.VerifyVectorOfTables(fields()) && verifier.VerifyVectorOfTables(fields()) &&
VerifyField<uint8_t>(verifier, 8 /* is_struct */) && VerifyField<uint8_t>(verifier, 8 /* is_struct */) &&
VerifyField<int32_t>(verifier, 10 /* minalign */) &&
VerifyField<int32_t>(verifier, 12 /* bytesize */) &&
verifier.EndTable(); verifier.EndTable();
} }
}; };
...@@ -273,10 +277,12 @@ struct ObjectBuilder { ...@@ -273,10 +277,12 @@ struct ObjectBuilder {
void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); } void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(4, name); }
void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields) { fbb_.AddOffset(6, fields); } void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields) { fbb_.AddOffset(6, fields); }
void add_is_struct(uint8_t is_struct) { fbb_.AddElement<uint8_t>(8, is_struct, 0); } void add_is_struct(uint8_t is_struct) { fbb_.AddElement<uint8_t>(8, is_struct, 0); }
void add_minalign(int32_t minalign) { fbb_.AddElement<int32_t>(10, minalign, 0); }
void add_bytesize(int32_t bytesize) { fbb_.AddElement<int32_t>(12, bytesize, 0); }
ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
ObjectBuilder &operator=(const ObjectBuilder &); ObjectBuilder &operator=(const ObjectBuilder &);
flatbuffers::Offset<Object> Finish() { flatbuffers::Offset<Object> Finish() {
auto o = flatbuffers::Offset<Object>(fbb_.EndTable(start_, 3)); auto o = flatbuffers::Offset<Object>(fbb_.EndTable(start_, 5));
fbb_.Required(o, 4); // name fbb_.Required(o, 4); // name
fbb_.Required(o, 6); // fields fbb_.Required(o, 6); // fields
return o; return o;
...@@ -286,8 +292,12 @@ struct ObjectBuilder { ...@@ -286,8 +292,12 @@ struct ObjectBuilder {
inline flatbuffers::Offset<Object> CreateObject(flatbuffers::FlatBufferBuilder &_fbb, inline flatbuffers::Offset<Object> CreateObject(flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> name = 0, flatbuffers::Offset<flatbuffers::String> name = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields = 0, flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields = 0,
uint8_t is_struct = 0) { uint8_t is_struct = 0,
int32_t minalign = 0,
int32_t bytesize = 0) {
ObjectBuilder builder_(_fbb); ObjectBuilder builder_(_fbb);
builder_.add_bytesize(bytesize);
builder_.add_minalign(minalign);
builder_.add_fields(fields); builder_.add_fields(fields);
builder_.add_name(name); builder_.add_name(name);
builder_.add_is_struct(is_struct); builder_.add_is_struct(is_struct);
......
...@@ -23,7 +23,7 @@ enum BaseType : byte { ...@@ -23,7 +23,7 @@ enum BaseType : byte {
String, String,
Vector, Vector,
Obj, // Used for tables & structs. Obj, // Used for tables & structs.
Union // Union
} }
table Type { table Type {
...@@ -63,6 +63,8 @@ table Object { // Used for both tables and structs. ...@@ -63,6 +63,8 @@ table Object { // Used for both tables and structs.
name:string (required, key); name:string (required, key);
fields:[Field] (required); // Sorted. fields:[Field] (required); // Sorted.
is_struct:bool = false; is_struct:bool = false;
minalign:int;
bytesize:int; // For structs.
} }
table Schema { table Schema {
......
...@@ -1354,7 +1354,9 @@ Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder) ...@@ -1354,7 +1354,9 @@ Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder)
builder->CreateString(name), builder->CreateString(name),
builder->CreateVectorOfSortedTables( builder->CreateVectorOfSortedTables(
&field_offsets), &field_offsets),
fixed); fixed,
static_cast<int>(minalign),
static_cast<int>(bytesize));
} }
Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder, Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
......
../flatc -c -j -n -g -b --gen-mutable monster_test.fbs monsterdata_test.json ../flatc -c -j -n -g -b --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
../flatc -b --schema monster_test.fbs ../flatc -b --schema monster_test.fbs
No preview for this file type
...@@ -302,18 +302,19 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) { ...@@ -302,18 +302,19 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
TEST_EQ(reflection::VerifySchemaBuffer(verifier), true); TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
// Make sure the schema is what we expect it to be. // Make sure the schema is what we expect it to be.
auto schema = reflection::GetSchema(bfbsfile.c_str()); auto &schema = *reflection::GetSchema(bfbsfile.c_str());
auto root_table = schema->root_table(); auto root_table = schema.root_table();
TEST_EQ_STR(root_table->name()->c_str(), "Monster"); TEST_EQ_STR(root_table->name()->c_str(), "Monster");
auto fields = root_table->fields(); auto fields = root_table->fields();
auto hp_field = fields->LookupByKey("hp"); auto hp_field_ptr = fields->LookupByKey("hp");
TEST_NOTNULL(hp_field); TEST_NOTNULL(hp_field_ptr);
TEST_EQ_STR(hp_field->name()->c_str(), "hp"); auto &hp_field = *hp_field_ptr;
TEST_EQ(hp_field->id(), 2); TEST_EQ_STR(hp_field.name()->c_str(), "hp");
TEST_EQ(hp_field->type()->base_type(), reflection::Short); TEST_EQ(hp_field.id(), 2);
TEST_EQ(hp_field.type()->base_type(), reflection::Short);
// Now use it to dynamically access a buffer. // Now use it to dynamically access a buffer.
auto root = flatbuffers::GetAnyRoot(flatbuf); auto &root = *flatbuffers::GetAnyRoot(flatbuf);
auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field); auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
TEST_EQ(hp, 80); TEST_EQ(hp, 80);
...@@ -323,51 +324,60 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) { ...@@ -323,51 +324,60 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
TEST_EQ(hp_int64, 80); TEST_EQ(hp_int64, 80);
auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field); auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
TEST_EQ(hp_double, 80.0); TEST_EQ(hp_double, 80.0);
auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field); auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, schema);
TEST_EQ_STR(hp_string.c_str(), "80"); TEST_EQ_STR(hp_string.c_str(), "80");
// We can also modify it. // We can also modify it.
flatbuffers::SetField<uint16_t>(root, hp_field, 200); flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field); hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
TEST_EQ(hp, 200); TEST_EQ(hp, 200);
// We can also set fields generically: // We can also set fields generically:
flatbuffers::SetAnyFieldI(root, hp_field, 300); flatbuffers::SetAnyFieldI(&root, hp_field, 300);
hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field); hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
TEST_EQ(hp_int64, 300); TEST_EQ(hp_int64, 300);
flatbuffers::SetAnyFieldF(root, hp_field, 300.5); flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field); hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
TEST_EQ(hp_int64, 300); TEST_EQ(hp_int64, 300);
flatbuffers::SetAnyFieldS(root, hp_field, "300"); flatbuffers::SetAnyFieldS(&root, hp_field, "300");
hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field); hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
TEST_EQ(hp_int64, 300); TEST_EQ(hp_int64, 300);
// Reset it, for further tests. // Reset it, for further tests.
flatbuffers::SetField<uint16_t>(root, hp_field, 80); flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
// More advanced functionality: changing the size of items in-line! // More advanced functionality: changing the size of items in-line!
// First we put the FlatBuffer inside an std::vector. // First we put the FlatBuffer inside an std::vector.
std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length); std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
// Find the field we want to modify. // Find the field we want to modify.
auto name_field = fields->LookupByKey("name"); auto &name_field = *fields->LookupByKey("name");
// Get the root. // Get the root.
// This time we wrap the result from GetAnyRoot in a smartpointer that // This time we wrap the result from GetAnyRoot in a smartpointer that
// will keep rroot valid as resizingbuf resizes. // will keep rroot valid as resizingbuf resizes.
auto rroot = flatbuffers::piv(flatbuffers::GetAnyRoot(resizingbuf.data()), auto rroot = flatbuffers::piv(flatbuffers::GetAnyRoot(resizingbuf.data()),
resizingbuf); resizingbuf);
SetString(*schema, "totally new string", GetFieldS(*rroot, name_field), SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
&resizingbuf); &resizingbuf);
// Here resizingbuf has changed, but rroot is still valid. // Here resizingbuf has changed, but rroot is still valid.
TEST_EQ_STR(GetFieldS(*rroot, name_field)->c_str(), "totally new string"); TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
// Now lets extend a vector by 100 elements (10 -> 110). // Now lets extend a vector by 100 elements (10 -> 110).
auto inventory_field = fields->LookupByKey("inventory"); auto &inventory_field = *fields->LookupByKey("inventory");
auto rinventory = flatbuffers::piv( auto rinventory = flatbuffers::piv(
flatbuffers::GetFieldV<uint8_t>(*rroot, inventory_field), flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field),
resizingbuf); resizingbuf);
flatbuffers::ResizeVector<uint8_t>(*schema, 110, 50, *rinventory, flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
&resizingbuf); &resizingbuf);
// rinventory still valid, so lets read from it. // rinventory still valid, so lets read from it.
TEST_EQ(rinventory->Get(10), 50); TEST_EQ(rinventory->Get(10), 50);
// Using reflection, we can also copy tables and other things out of
// other FlatBuffers into a new one, either part or whole.
flatbuffers::FlatBufferBuilder fbb;
auto root_offset = flatbuffers::CopyTable(fbb, schema, *root_table,
*flatbuffers::GetAnyRoot(flatbuf));
fbb.Finish(root_offset, MonsterIdentifier());
// Test that it was copied correctly:
AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
} }
// Parse a .proto schema, output as .fbs // Parse a .proto schema, output as .fbs
......
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