diff --git a/docs/source/FlexBuffers.md b/docs/source/FlexBuffers.md index 5d592fea9..afe3c93a5 100644 --- a/docs/source/FlexBuffers.md +++ b/docs/source/FlexBuffers.md @@ -128,6 +128,16 @@ A description of how FlexBuffers are encoded is in the [internals](Internals.md#flexbuffers) document. +# Nesting inside a FlatBuffer + +You can mark a field as containing a FlexBuffer, e.g. + + a:[ubyte] (flexbuffer); + +A special accessor will be generated that allows you to access the root value +directly, e.g. `a_flexbuffer_root().AsInt64()`. + + # Efficiency tips * Vectors generally are a lot more efficient than maps, so prefer them over maps diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md index c4a942166..1a3228078 100755 --- a/docs/source/Schemas.md +++ b/docs/source/Schemas.md @@ -302,6 +302,9 @@ Current understood attributes: (which must be a vector of ubyte) contains flatbuffer data, for which the root type is given by `table_name`. The generated code will then produce a convenient accessor for the nested FlatBuffer. +- `flexbuffer` (on a field): this indicates that the field + (which must be a vector of ubyte) contains flexbuffer data. The generated + code will then produce a convenient accessor for the FlexBuffer root. - `key` (on a field): this field is meant to be used as a key when sorting a vector of the type of table it sits in. Can be used for in-place binary search. diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 00cec0306..4e3a24a67 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -471,6 +471,7 @@ class Parser : public ParserState { explicit Parser(const IDLOptions &options = IDLOptions()) : root_struct_def_(nullptr), opts(options), + uses_flexbuffers_(false), source_(nullptr), anonymous_counter(0) { // Just in case none are declared: @@ -493,6 +494,7 @@ class Parser : public ParserState { known_attributes_["native_inline"] = true; known_attributes_["native_type"] = true; known_attributes_["native_default"] = true; + known_attributes_["flexbuffer"] = true; } ~Parser() { @@ -617,6 +619,7 @@ private: std::map known_attributes_; IDLOptions opts; + bool uses_flexbuffers_; private: const char *source_; diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index ce5932b8d..d5c8b03f5 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -97,6 +97,9 @@ class CppGenerator : public BaseGenerator { code_ += ""; code_ += "#include \"flatbuffers/flatbuffers.h\""; + if (parser_.uses_flexbuffers_) { + code_ += "#include \"flatbuffers/flexbuffers.h\""; + } code_ += ""; if (parser_.opts.include_dependence_headers) { @@ -1335,11 +1338,19 @@ class CppGenerator : public BaseGenerator { code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name)); code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {"; - code_ += " const uint8_t* data = {{FIELD_NAME}}()->Data();"; + code_ += " auto data = {{FIELD_NAME}}()->Data();"; code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(data);"; code_ += " }"; } + if (field.attributes.Lookup("flexbuffer")) { + code_ += " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()" + " const {"; + code_ += " auto v = {{FIELD_NAME}}();"; + code_ += " return flexbuffers::GetRoot(v->Data(), v->size());"; + code_ += " }"; + } + // Generate a comparison function for this field if it is a key. if (field.key) { const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING); diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 1631e9151..c238bee0c 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -725,6 +725,14 @@ CheckedError Parser::ParseField(StructDef &struct_def) { LookupCreateStruct(nested->constant); } + if (field->attributes.Lookup("flexbuffer")) { + uses_flexbuffers_ = true; + if (field->value.type.base_type != BASE_TYPE_VECTOR || + field->value.type.element != BASE_TYPE_UCHAR) + return Error( + "flexbuffer attribute may only apply to a vector of ubyte"); + } + 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). diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index ab4cdfe8a..6828701bd 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -83,8 +83,12 @@ public struct Monster : IFlatbufferObject public int Testarrayofstring2Length { get { int o = __p.__offset(60); return o != 0 ? __p.__vector_len(o) : 0; } } public Ability? Testarrayofsortedstruct(int j) { int o = __p.__offset(62); return o != 0 ? (Ability?)(new Ability()).__assign(__p.__vector(o) + j * 8, __p.bb) : null; } public int TestarrayofsortedstructLength { get { int o = __p.__offset(62); return o != 0 ? __p.__vector_len(o) : 0; } } + public byte Flex(int j) { int o = __p.__offset(64); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; } + public int FlexLength { get { int o = __p.__offset(64); return o != 0 ? __p.__vector_len(o) : 0; } } + public ArraySegment? GetFlexBytes() { return __p.__vector_as_arraysegment(64); } + public bool MutateFlex(int j, byte flex) { int o = __p.__offset(64); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, flex); return true; } else { return false; } } - public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(30); } + public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(31); } public static void AddPos(FlatBufferBuilder builder, Offset posOffset) { builder.AddStruct(0, posOffset.Value, 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); } @@ -128,6 +132,9 @@ public struct Monster : IFlatbufferObject public static void StartTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); } public static void AddTestarrayofsortedstruct(FlatBufferBuilder builder, VectorOffset testarrayofsortedstructOffset) { builder.AddOffset(29, testarrayofsortedstructOffset.Value, 0); } public static void StartTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 4); } + public static void AddFlex(FlatBufferBuilder builder, VectorOffset flexOffset) { builder.AddOffset(30, flexOffset.Value, 0); } + public static VectorOffset CreateFlexVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); } + public static void StartFlexVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); } public static Offset EndMonster(FlatBufferBuilder builder) { int o = builder.EndObject(); builder.Required(o, 10); // name diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go index ba2e60d11..8b3ffa530 100644 --- a/tests/MyGame/Example/Monster.go +++ b/tests/MyGame/Example/Monster.go @@ -438,8 +438,33 @@ func (rcv *Monster) TestarrayofsortedstructLength() int { return 0 } +func (rcv *Monster) Flex(j int) byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(64)) + if o != 0 { + a := rcv._tab.Vector(o) + return rcv._tab.GetByte(a + flatbuffers.UOffsetT(j*1)) + } + return 0 +} + +func (rcv *Monster) FlexLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(64)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func (rcv *Monster) FlexBytes() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(64)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + func MonsterStart(builder *flatbuffers.Builder) { - builder.StartObject(30) + builder.StartObject(31) } func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) { builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0) @@ -552,6 +577,12 @@ func MonsterAddTestarrayofsortedstruct(builder *flatbuffers.Builder, testarrayof func MonsterStartTestarrayofsortedstructVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(8, numElems, 4) } +func MonsterAddFlex(builder *flatbuffers.Builder, flex flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(30, flatbuffers.UOffsetT(flex), 0) +} +func MonsterStartFlexVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(1, numElems, 1) +} 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 8ccbe3daf..58ac75cfe 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -91,8 +91,12 @@ public final class Monster extends Table { public Ability testarrayofsortedstruct(int j) { return testarrayofsortedstruct(new Ability(), j); } public Ability testarrayofsortedstruct(Ability obj, int j) { int o = __offset(62); return o != 0 ? obj.__assign(__vector(o) + j * 8, bb) : null; } public int testarrayofsortedstructLength() { int o = __offset(62); return o != 0 ? __vector_len(o) : 0; } + public int flex(int j) { int o = __offset(64); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; } + public int flexLength() { int o = __offset(64); return o != 0 ? __vector_len(o) : 0; } + public ByteBuffer flexAsByteBuffer() { return __vector_as_bytebuffer(64, 1); } + public boolean mutateFlex(int j, int flex) { int o = __offset(64); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)flex); return true; } else { return false; } } - public static void startMonster(FlatBufferBuilder builder) { builder.startObject(30); } + public static void startMonster(FlatBufferBuilder builder) { builder.startObject(31); } 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); } @@ -136,6 +140,9 @@ public final class Monster extends Table { public static void startTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); } public static void addTestarrayofsortedstruct(FlatBufferBuilder builder, int testarrayofsortedstructOffset) { builder.addOffset(29, testarrayofsortedstructOffset, 0); } public static void startTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 4); } + public static void addFlex(FlatBufferBuilder builder, int flexOffset) { builder.addOffset(30, flexOffset, 0); } + public static int createFlexVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); } + public static void startFlexVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); } public static int endMonster(FlatBufferBuilder builder) { int o = builder.endObject(); builder.required(o, 10); // name diff --git a/tests/MyGame/Example/Monster.php b/tests/MyGame/Example/Monster.php index a86687063..f2185ed4e 100644 --- a/tests/MyGame/Example/Monster.php +++ b/tests/MyGame/Example/Monster.php @@ -398,22 +398,49 @@ class Monster extends Table return $o != 0 ? $this->__vector_len($o) : 0; } + /** + * @param int offset + * @return byte + */ + public function getFlex($j) + { + $o = $this->__offset(64); + return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0; + } + + /** + * @return int + */ + public function getFlexLength() + { + $o = $this->__offset(64); + return $o != 0 ? $this->__vector_len($o) : 0; + } + + /** + * @return string + */ + public function getFlexBytes() + { + return $this->__vector_as_bytes(64); + } + /** * @param FlatBufferBuilder $builder * @return void */ public static function startMonster(FlatBufferBuilder $builder) { - $builder->StartObject(30); + $builder->StartObject(31); } /** * @param FlatBufferBuilder $builder * @return Monster */ - public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2, $testarrayofsortedstruct) + public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2, $testarrayofsortedstruct, $flex) { - $builder->startObject(30); + $builder->startObject(31); self::addPos($builder, $pos); self::addMana($builder, $mana); self::addHp($builder, $hp); @@ -443,6 +470,7 @@ class Monster extends Table self::addTestf3($builder, $testf3); self::addTestarrayofstring2($builder, $testarrayofstring2); self::addTestarrayofsortedstruct($builder, $testarrayofsortedstruct); + self::addFlex($builder, $flex); $o = $builder->endObject(); $builder->required($o, 10); // name return $o; @@ -925,6 +953,40 @@ class Monster extends Table $builder->startVector(8, $numElems, 4); } + /** + * @param FlatBufferBuilder $builder + * @param VectorOffset + * @return void + */ + public static function addFlex(FlatBufferBuilder $builder, $flex) + { + $builder->addOffsetX(30, $flex, 0); + } + + /** + * @param FlatBufferBuilder $builder + * @param array offset array + * @return int vector offset + */ + public static function createFlexVector(FlatBufferBuilder $builder, array $data) + { + $builder->startVector(1, count($data), 1); + for ($i = count($data) - 1; $i >= 0; $i--) { + $builder->addByte($data[$i]); + } + return $builder->endVector(); + } + + /** + * @param FlatBufferBuilder $builder + * @param int $numElems + * @return void + */ + public static function startFlexVector(FlatBufferBuilder $builder, $numElems) + { + $builder->startVector(1, $numElems, 1); + } + /** * @param FlatBufferBuilder $builder * @return int table offset diff --git a/tests/MyGame/Example/Monster.py b/tests/MyGame/Example/Monster.py index 75e54a1fd..ff7e7da51 100644 --- a/tests/MyGame/Example/Monster.py +++ b/tests/MyGame/Example/Monster.py @@ -316,7 +316,22 @@ class Monster(object): return self._tab.VectorLen(o) return 0 -def MonsterStart(builder): builder.StartObject(30) + # Monster + def Flex(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64)) + if o != 0: + a = self._tab.Vector(o) + return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1)) + return 0 + + # Monster + def FlexLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + +def MonsterStart(builder): builder.StartObject(31) def MonsterAddPos(builder, pos): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(pos), 0) def MonsterAddMana(builder, mana): builder.PrependInt16Slot(1, mana, 150) def MonsterAddHp(builder, hp): builder.PrependInt16Slot(2, hp, 100) @@ -354,4 +369,6 @@ def MonsterAddTestarrayofstring2(builder, testarrayofstring2): builder.PrependUO def MonsterStartTestarrayofstring2Vector(builder, numElems): return builder.StartVector(4, numElems, 4) def MonsterAddTestarrayofsortedstruct(builder, testarrayofsortedstruct): builder.PrependUOffsetTRelativeSlot(29, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofsortedstruct), 0) def MonsterStartTestarrayofsortedstructVector(builder, numElems): return builder.StartVector(8, numElems, 4) +def MonsterAddFlex(builder, flex): builder.PrependUOffsetTRelativeSlot(30, flatbuffers.number_types.UOffsetTFlags.py_type(flex), 0) +def MonsterStartFlexVector(builder, numElems): return builder.StartVector(1, numElems, 1) def MonsterEnd(builder): return builder.EndObject() diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs index 81ec993e5..c12390903 100755 --- a/tests/monster_test.fbs +++ b/tests/monster_test.fbs @@ -73,6 +73,7 @@ table Monster { testf:float = 3.14159 (id:25); testf2:float = 3 (id:26); testf3:float (id:27); + flex:[ubyte] (id:30, flexbuffer); } rpc_service MonsterStorage { diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index 6d6868f32..580ed57b4 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -5,6 +5,7 @@ #define FLATBUFFERS_GENERATED_MONSTERTEST_MYGAME_EXAMPLE_H_ #include "flatbuffers/flatbuffers.h" +#include "flatbuffers/flexbuffers.h" namespace MyGame { namespace Example2 { @@ -543,6 +544,7 @@ struct MonsterT : public flatbuffers::NativeTable { float testf3; std::vector testarrayofstring2; std::vector testarrayofsortedstruct; + std::vector flex; MonsterT() : mana(150), hp(100), @@ -594,7 +596,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_TESTF2 = 56, VT_TESTF3 = 58, VT_TESTARRAYOFSTRING2 = 60, - VT_TESTARRAYOFSORTEDSTRUCT = 62 + VT_TESTARRAYOFSORTEDSTRUCT = 62, + VT_FLEX = 64 }; const Vec3 *pos() const { return GetStruct(VT_POS); @@ -693,7 +696,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { return GetPointer *>(VT_TESTNESTEDFLATBUFFER); } const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const { - const uint8_t* data = testnestedflatbuffer()->Data(); + auto data = testnestedflatbuffer()->Data(); return flatbuffers::GetRoot(data); } const Stat *testempty() const { @@ -792,6 +795,16 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { flatbuffers::Vector *mutable_testarrayofsortedstruct() { return GetPointer *>(VT_TESTARRAYOFSORTEDSTRUCT); } + const flatbuffers::Vector *flex() const { + return GetPointer *>(VT_FLEX); + } + flatbuffers::Vector *mutable_flex() { + return GetPointer *>(VT_FLEX); + } + flexbuffers::Reference flex_flexbuffer_root() const { + auto v = flex(); + return flexbuffers::GetRoot(v->Data(), v->size()); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_POS) && @@ -838,6 +851,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { verifier.VerifyVectorOfStrings(testarrayofstring2()) && VerifyOffset(verifier, VT_TESTARRAYOFSORTEDSTRUCT) && verifier.Verify(testarrayofsortedstruct()) && + VerifyOffset(verifier, VT_FLEX) && + verifier.Verify(flex()) && verifier.EndTable(); } MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; @@ -947,13 +962,16 @@ struct MonsterBuilder { void add_testarrayofsortedstruct(flatbuffers::Offset> testarrayofsortedstruct) { fbb_.AddOffset(Monster::VT_TESTARRAYOFSORTEDSTRUCT, testarrayofsortedstruct); } + void add_flex(flatbuffers::Offset> flex) { + fbb_.AddOffset(Monster::VT_FLEX, flex); + } MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } MonsterBuilder &operator=(const MonsterBuilder &); flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_, 30); + const auto end = fbb_.EndTable(start_, 31); auto o = flatbuffers::Offset(end); fbb_.Required(o, Monster::VT_NAME); return o; @@ -990,12 +1008,14 @@ inline flatbuffers::Offset CreateMonster( float testf2 = 3.0f, float testf3 = 0.0f, flatbuffers::Offset>> testarrayofstring2 = 0, - flatbuffers::Offset> testarrayofsortedstruct = 0) { + flatbuffers::Offset> testarrayofsortedstruct = 0, + flatbuffers::Offset> flex = 0) { MonsterBuilder builder_(_fbb); builder_.add_testhashu64_fnv1a(testhashu64_fnv1a); builder_.add_testhashs64_fnv1a(testhashs64_fnv1a); builder_.add_testhashu64_fnv1(testhashu64_fnv1); builder_.add_testhashs64_fnv1(testhashs64_fnv1); + builder_.add_flex(flex); builder_.add_testarrayofsortedstruct(testarrayofsortedstruct); builder_.add_testarrayofstring2(testarrayofstring2); builder_.add_testf3(testf3); @@ -1054,7 +1074,8 @@ inline flatbuffers::Offset CreateMonsterDirect( float testf2 = 3.0f, float testf3 = 0.0f, const std::vector> *testarrayofstring2 = nullptr, - const std::vector *testarrayofsortedstruct = nullptr) { + const std::vector *testarrayofsortedstruct = nullptr, + const std::vector *flex = nullptr) { return MyGame::Example::CreateMonster( _fbb, pos, @@ -1085,7 +1106,8 @@ inline flatbuffers::Offset CreateMonsterDirect( testf2, testf3, testarrayofstring2 ? _fbb.CreateVector>(*testarrayofstring2) : 0, - testarrayofsortedstruct ? _fbb.CreateVector(*testarrayofsortedstruct) : 0); + testarrayofsortedstruct ? _fbb.CreateVector(*testarrayofsortedstruct) : 0, + flex ? _fbb.CreateVector(*flex) : 0); } flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); @@ -1214,6 +1236,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function { auto _e = testf3(); _o->testf3 = _e; }; { auto _e = testarrayofstring2(); if (_e) { _o->testarrayofstring2.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2[_i] = _e->Get(_i)->str(); } } }; { auto _e = testarrayofsortedstruct(); if (_e) { _o->testarrayofsortedstruct.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofsortedstruct[_i] = *_e->Get(_i); } } }; + { auto _e = flex(); if (_e) { _o->flex.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->flex[_i] = _e->Get(_i); } } }; } inline flatbuffers::Offset Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) { @@ -1252,6 +1275,7 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder auto _testf3 = _o->testf3; auto _testarrayofstring2 = _o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0; auto _testarrayofsortedstruct = _o->testarrayofsortedstruct.size() ? _fbb.CreateVectorOfStructs(_o->testarrayofsortedstruct) : 0; + auto _flex = _o->flex.size() ? _fbb.CreateVector(_o->flex) : 0; return MyGame::Example::CreateMonster( _fbb, _pos, @@ -1282,7 +1306,8 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder _testf2, _testf3, _testarrayofstring2, - _testarrayofsortedstruct); + _testarrayofsortedstruct, + _flex); } inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type) { diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js index 1d317ceb1..a647ea8fa 100644 --- a/tests/monster_test_generated.js +++ b/tests/monster_test_generated.js @@ -1271,11 +1271,36 @@ MyGame.Example.Monster.prototype.testarrayofsortedstructLength = function() { return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; }; +/** + * @param {number} index + * @returns {number} + */ +MyGame.Example.Monster.prototype.flex = function(index) { + var offset = this.bb.__offset(this.bb_pos, 64); + return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0; +}; + +/** + * @returns {number} + */ +MyGame.Example.Monster.prototype.flexLength = function() { + var offset = this.bb.__offset(this.bb_pos, 64); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint8Array} + */ +MyGame.Example.Monster.prototype.flexArray = function() { + var offset = this.bb.__offset(this.bb_pos, 64); + return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + /** * @param {flatbuffers.Builder} builder */ MyGame.Example.Monster.startMonster = function(builder) { - builder.startObject(30); + builder.startObject(31); }; /** @@ -1652,6 +1677,35 @@ MyGame.Example.Monster.startTestarrayofsortedstructVector = function(builder, nu builder.startVector(8, numElems, 4); }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} flexOffset + */ +MyGame.Example.Monster.addFlex = function(builder, flexOffset) { + builder.addFieldOffset(30, flexOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +MyGame.Example.Monster.createFlexVector = function(builder, data) { + builder.startVector(1, data.length, 1); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt8(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +MyGame.Example.Monster.startFlexVector = function(builder, numElems) { + builder.startVector(1, numElems, 1); +}; + /** * @param {flatbuffers.Builder} builder * @returns {flatbuffers.Offset} diff --git a/tests/monster_test_generated.ts b/tests/monster_test_generated.ts index aeee6fc90..a05e586c9 100644 --- a/tests/monster_test_generated.ts +++ b/tests/monster_test_generated.ts @@ -1262,11 +1262,36 @@ testarrayofsortedstructLength():number { return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; }; +/** + * @param {number} index + * @returns {number} + */ +flex(index: number):number|null { + var offset = this.bb.__offset(this.bb_pos, 64); + return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0; +}; + +/** + * @returns {number} + */ +flexLength():number { + var offset = this.bb.__offset(this.bb_pos, 64); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + +/** + * @returns {Uint8Array} + */ +flexArray():Uint8Array|null { + var offset = this.bb.__offset(this.bb_pos, 64); + return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null; +}; + /** * @param {flatbuffers.Builder} builder */ static startMonster(builder:flatbuffers.Builder) { - builder.startObject(30); + builder.startObject(31); }; /** @@ -1643,6 +1668,35 @@ static startTestarrayofsortedstructVector(builder:flatbuffers.Builder, numElems: builder.startVector(8, numElems, 4); }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} flexOffset + */ +static addFlex(builder:flatbuffers.Builder, flexOffset:flatbuffers.Offset) { + builder.addFieldOffset(30, flexOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {Array.} data + * @returns {flatbuffers.Offset} + */ +static createFlexVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset { + builder.startVector(1, data.length, 1); + for (var i = data.length - 1; i >= 0; i--) { + builder.addInt8(data[i]); + } + return builder.endVector(); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +static startFlexVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(1, numElems, 1); +}; + /** * @param {flatbuffers.Builder} builder * @returns {flatbuffers.Offset} diff --git a/tests/monsterdata_test.mon b/tests/monsterdata_test.mon index 21c42166a..e5606e398 100644 Binary files a/tests/monsterdata_test.mon and b/tests/monsterdata_test.mon differ diff --git a/tests/test.cpp b/tests/test.cpp index 1be9fec69..5ebeb4d90 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -167,13 +167,19 @@ flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) { builder.CreateVector(nested_builder.GetBufferPointer(), nested_builder.GetSize()); + // Test a nested FlexBuffer: + flexbuffers::Builder flexbuild; + flexbuild.Int(1234); + flexbuild.Finish(); + auto flex = builder.CreateVector(flexbuild.GetBuffer()); + // shortcut for creating monster with all fields set: auto mloc = CreateMonster(builder, &vec, 150, 80, name, inventory, Color_Blue, Any_Monster, mlocs[1].Union(), // Store a union. testv, vecofstrings, vecoftables, 0, nested_flatbuffer_vector, 0, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, - vecofstrings2, vecofstructs); + vecofstrings2, vecofstructs, flex); FinishMonsterBuffer(builder, mloc); @@ -205,10 +211,6 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length, std::memcpy(&test_buff[0], flatbuf , length); std::memcpy(&test_buff[length], flatbuf , length); - flatbuffers::Verifier verifierl(&test_buff[0], length - 1); - TEST_EQ(VerifyMonsterBuffer(verifierl), false); - TEST_EQ(verifierl.GetComputedSize(), 0); - flatbuffers::Verifier verifier1(&test_buff[0], length); TEST_EQ(VerifyMonsterBuffer(verifier1), true); TEST_EQ(verifier1.GetComputedSize(), length); @@ -305,6 +307,15 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length, TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster"); } + // Test flexbuffer if available: + auto flex = monster->flex(); + if (flex) { + // flex is a vector of bytes you can memcpy. However, if you + // actually want to access the nested data, this is a convenient + // accessor that directly gives you the root value: + TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234); + } + // Since Flatbuffers uses explicit mechanisms to override the default // compiler alignment, double check that the compiler indeed obeys them: // (Test consists of a short and byte):