From 3e201a99b2f23c8c8475e43803d122b105db9a68 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Tue, 15 Jul 2014 17:50:22 -0700 Subject: [PATCH] A feature that officially supports nested FlatBuffers. Generates convenient accessors for the nested root. Change-Id: Ic0b1531de7ace475ff2a7b1f430d27f41c838430 Tested: on Windows. --- include/flatbuffers/flatbuffers.h | 9 +++++---- src/idl_gen_cpp.cpp | 13 +++++++++++-- src/idl_parser.cpp | 11 +++++++++++ tests/MyGame/Example/Monster.go | 21 ++++++++++++++++++++- tests/MyGame/Example/Monster.java | 6 +++++- tests/monster_test.fbs | 1 + tests/monster_test_generated.h | 13 ++++++++++--- tests/monsterdata_test.bin | Bin 176 -> 176 bytes 8 files changed, 63 insertions(+), 11 deletions(-) diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index ab473b0..02f29e9 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -262,15 +262,16 @@ public: iterator end() { return iterator(Data(), length_); } const_iterator end() const { return const_iterator(Data(), length_); } + // The raw data in little endian format. Use with care. + const uint8_t *Data() const { + return reinterpret_cast(&length_ + 1); + } + protected: // This class is only used to access pre-existing data. Don't ever // try to construct these manually. Vector(); - const uint8_t *Data() const { - return reinterpret_cast(&length_ + 1); - } - uoffset_t length_; }; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index cd560c5..8bb7551 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -164,7 +164,8 @@ static void GenComment(const std::string &dc, } // Generate an accessor struct, builder structs & function for a table. -static void GenTable(StructDef &struct_def, std::string *code_ptr) { +static void GenTable(const Parser &parser, StructDef &struct_def, + std::string *code_ptr) { if (struct_def.generated) return; std::string &code = *code_ptr; @@ -191,6 +192,14 @@ static void GenTable(StructDef &struct_def, std::string *code_ptr) { if (IsScalar(field.value.type.base_type)) code += ", " + field.value.constant; code += "); }\n"; + auto nested = field.attributes.Lookup("nested_flatbuffer"); + if (nested) { + auto nested_root = parser.structs_.Lookup(nested->constant); + assert(nested_root); // Guaranteed to exist by parser. + code += " const " + nested_root->name + " *" + field.name; + code += "_nested_root() { return flatbuffers::GetRoot<"; + code += nested_root->name + ">(" + field.name + "()->Data()); }\n"; + } } } // Generate a verifier function that can check a buffer from an untrusted @@ -418,7 +427,7 @@ std::string GenerateCPP(const Parser &parser, const std::string &include_guard_i } for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); ++it) { - if (!(**it).fixed) GenTable(**it, &decl_code); + if (!(**it).fixed) GenTable(parser, **it, &decl_code); } // Only output file-level code if there were any declarations. diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 8be0591..436d0bc 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -333,6 +333,17 @@ void Parser::ParseField(StructDef &struct_def) { field.deprecated = field.attributes.Lookup("deprecated") != nullptr; if (field.deprecated && struct_def.fixed) Error("can't deprecate fields in a struct"); + auto nested = field.attributes.Lookup("nested_flatbuffer"); + if (nested) { + if (nested->type.base_type != BASE_TYPE_STRING) + Error("nested_flatbuffer attribute must be a string (the root type)"); + if (field.value.type.base_type != BASE_TYPE_VECTOR || + field.value.type.element != BASE_TYPE_UCHAR) + Error("nested_flatbuffer attribute may only apply to a vector of ubyte"); + // This will cause an error if the root type of the nested flatbuffer + // wasn't defined elsewhere. + LookupCreateStruct(nested->constant); + } if (typefield) { // If this field is a union, and it has a manually assigned id, diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go index 2bceae5..16894f1 100644 --- a/tests/MyGame/Example/Monster.go +++ b/tests/MyGame/Example/Monster.go @@ -176,7 +176,24 @@ func (rcv *Monster) Enemy(obj *Monster) *Monster { return nil } -func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(13) } +func (rcv *Monster) Testnestedflatbuffer(j int) byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(30)) + if o != 0 { + a := rcv._tab.Vector(o) + return rcv._tab.GetByte(a + flatbuffers.UOffsetT(j * 1)) + } + return 0 +} + +func (rcv *Monster) TestnestedflatbufferLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(30)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(14) } func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) { builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0) } func MonsterAddMana(builder *flatbuffers.Builder, mana int16) { builder.PrependInt16Slot(1, mana, 150) } func MonsterAddHp(builder *flatbuffers.Builder, hp int16) { builder.PrependInt16Slot(2, hp, 100) } @@ -193,4 +210,6 @@ func MonsterStartTestarrayofstringVector(builder *flatbuffers.Builder, numElems func MonsterAddTestarrayoftables(builder *flatbuffers.Builder, testarrayoftables flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(11, flatbuffers.UOffsetT(testarrayoftables), 0) } func MonsterStartTestarrayoftablesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(4, numElems) } func MonsterAddEnemy(builder *flatbuffers.Builder, enemy flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(12, flatbuffers.UOffsetT(enemy), 0) } +func MonsterAddTestnestedflatbuffer(builder *flatbuffers.Builder, testnestedflatbuffer flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(13, flatbuffers.UOffsetT(testnestedflatbuffer), 0) } +func MonsterStartTestnestedflatbufferVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(1, numElems) } func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java index 439dd7a..dcb7699 100755 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -31,8 +31,10 @@ public class Monster extends Table { public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; } public Monster enemy() { return enemy(new Monster()); } public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; } + public byte testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; } + public int testnestedflatbufferLength() { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; } - public static void startMonster(FlatBufferBuilder builder) { builder.startObject(13); } + public static void startMonster(FlatBufferBuilder builder) { builder.startObject(14); } public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); } public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); } public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); } @@ -49,6 +51,8 @@ public class Monster extends Table { public static void addTestarrayoftables(FlatBufferBuilder builder, int testarrayoftablesOffset) { builder.addOffset(11, testarrayoftablesOffset, 0); } public static void startTestarrayoftablesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems); } public static void addEnemy(FlatBufferBuilder builder, int enemyOffset) { builder.addOffset(12, enemyOffset, 0); } + public static void addTestnestedflatbuffer(FlatBufferBuilder builder, int testnestedflatbufferOffset) { builder.addOffset(13, testnestedflatbufferOffset, 0); } + public static void startTestnestedflatbufferVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems); } public static int endMonster(FlatBufferBuilder builder) { return builder.endObject(); } }; diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs index cf191c4..9e6d444 100755 --- a/tests/monster_test.fbs +++ b/tests/monster_test.fbs @@ -32,6 +32,7 @@ table Monster { enemy:Monster (id:12); test:Any (id: 8); test4:[Test] (id: 9); + testnestedflatbuffer:[ubyte] (id:13, nested_flatbuffer: "Monster"); } root_type Monster; diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index b8ad91c..e6beb77 100755 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -93,6 +93,8 @@ struct Monster : private flatbuffers::Table { /// an example documentation comment: this will end up in the generated code multiline too const flatbuffers::Vector> *testarrayoftables() const { return GetPointer> *>(26); } const Monster *enemy() const { return GetPointer(28); } + const flatbuffers::Vector *testnestedflatbuffer() const { return GetPointer *>(30); } + const Monster *testnestedflatbuffer_nested_root() { return flatbuffers::GetRoot(testnestedflatbuffer()->Data()); } bool Verify(const flatbuffers::Verifier &verifier) const { return VerifyTable(verifier) && VerifyField(verifier, 4 /* pos */) && @@ -115,7 +117,9 @@ struct Monster : private flatbuffers::Table { verifier.Verify(testarrayoftables()) && verifier.VerifyVectorOfTables(testarrayoftables()) && VerifyField(verifier, 28 /* enemy */) && - verifier.VerifyTable(enemy()); + verifier.VerifyTable(enemy()) && + VerifyField(verifier, 30 /* testnestedflatbuffer */) && + verifier.Verify(testnestedflatbuffer()); } }; @@ -134,9 +138,10 @@ struct MonsterBuilder { void add_testarrayofstring(flatbuffers::Offset>> testarrayofstring) { fbb_.AddOffset(24, testarrayofstring); } void add_testarrayoftables(flatbuffers::Offset>> testarrayoftables) { fbb_.AddOffset(26, testarrayoftables); } void add_enemy(flatbuffers::Offset enemy) { fbb_.AddOffset(28, enemy); } + void add_testnestedflatbuffer(flatbuffers::Offset> testnestedflatbuffer) { fbb_.AddOffset(30, testnestedflatbuffer); } MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } MonsterBuilder &operator=(const MonsterBuilder &); - flatbuffers::Offset Finish() { return flatbuffers::Offset(fbb_.EndTable(start_, 13)); } + flatbuffers::Offset Finish() { return flatbuffers::Offset(fbb_.EndTable(start_, 14)); } }; inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, @@ -151,8 +156,10 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder flatbuffers::Offset> test4 = 0, flatbuffers::Offset>> testarrayofstring = 0, flatbuffers::Offset>> testarrayoftables = 0, - flatbuffers::Offset enemy = 0) { + flatbuffers::Offset enemy = 0, + flatbuffers::Offset> testnestedflatbuffer = 0) { MonsterBuilder builder_(_fbb); + builder_.add_testnestedflatbuffer(testnestedflatbuffer); builder_.add_enemy(enemy); builder_.add_testarrayoftables(testarrayoftables); builder_.add_testarrayofstring(testarrayofstring); diff --git a/tests/monsterdata_test.bin b/tests/monsterdata_test.bin index f09bf5081d63b77ddffcabf7b9f11d553356e1e9..631374560aaacf61b3a7b0f3b821236f09100627 100644 GIT binary patch delta 36 jcmdnMxPg&Vg8>2*CUVO%GcYJj)O2Q4n3xY?_bLMbXvhXH delta 36 jcmdnMxPg&dg8>HQCUVL$%1zXCW@ccJo0tn?_bLMbWF!V7 -- 2.7.4