diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 140e176aa..8ea80c893 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -478,7 +478,7 @@ protected: VectorOfAny(); uoffset_t length_; - + private: VectorOfAny(const VectorOfAny&); }; @@ -1204,6 +1204,44 @@ FLATBUFFERS_FINAL_CLASS return CreateVectorOfStructs(data(v), v.size()); } + /// @cond FLATBUFFERS_INTERNAL + template + struct StructKeyComparator { + bool operator()(const T &a, const T &b) const { + return a.KeyCompareLessThan(&b); + } + + private: + StructKeyComparator& operator= (const StructKeyComparator&); + }; + /// @endcond + + /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector` + /// in sorted order. + /// @tparam T The data type of the `std::vector` struct elements. + /// @param[in]] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template Offset> CreateVectorOfSortedStructs( + std::vector *v) { + return CreateVectorOfSortedStructs(data(*v), v->size()); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted + /// order. + /// @tparam T The data type of the struct array elements. + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template Offset> CreateVectorOfSortedStructs( + T *v, size_t len) { + std::sort(v, v + len, StructKeyComparator()); + return CreateVectorOfStructs(v, len); + } + /// @cond FLATBUFFERS_INTERNAL template struct TableKeyComparator { diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 857287596..0e8bb28de 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -1943,6 +1943,24 @@ class CppGenerator : public BaseGenerator { code_ += " }"; } } + + // Generate a comparison function for this field if it is a key. + if (field.key) { + code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {"; + code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();"; + code_ += " }"; + auto type = GenTypeBasic(field.value.type, false); + if (parser_.opts.scoped_enums && field.value.type.enum_def && + IsScalar(field.value.type.base_type)) { + type = GenTypeGet(field.value.type, " ", "const ", " *", true); + } + + code_.SetValue("KEY_TYPE", type); + code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {"; + code_ += " const auto key = {{FIELD_NAME}}();"; + code_ += " return static_cast(key > val) - static_cast(key < val);"; + code_ += " }"; + } } code_ += "};"; diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp index b7bc2f6fe..8ca39f0f7 100644 --- a/src/idl_gen_general.cpp +++ b/src/idl_gen_general.cpp @@ -1291,7 +1291,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) { code += "); }\n"; } } - if (struct_def.has_key) { + // Only generate key compare function for table, + // because `key_field` is not set for struct + if (struct_def.has_key && !struct_def.fixed) { if (lang_.language == IDLOptions::kJava) { code += "\n @Override\n protected int keysCompare("; code += "Integer o1, Integer o2, ByteBuffer _bb) {"; diff --git a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj index 6e76b07f1..eda44c757 100644 --- a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj +++ b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj @@ -80,6 +80,9 @@ MyGame\Example\Vec3.cs + + MyGame\Example\Ability.cs + NamespaceA\NamespaceB\EnumInNestedNS.cs diff --git a/tests/MyGame/Example/Ability.cs b/tests/MyGame/Example/Ability.cs new file mode 100644 index 000000000..d049f8b60 --- /dev/null +++ b/tests/MyGame/Example/Ability.cs @@ -0,0 +1,30 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +namespace MyGame.Example +{ + +using System; +using FlatBuffers; + +public struct Ability : IFlatbufferObject +{ + private Struct __p; + public ByteBuffer ByteBuffer { get { return __p.bb; } } + public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; } + public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public uint Id { get { return __p.bb.GetUint(__p.bb_pos + 0); } } + public void MutateId(uint id) { __p.bb.PutUint(__p.bb_pos + 0, id); } + public uint Distance { get { return __p.bb.GetUint(__p.bb_pos + 4); } } + public void MutateDistance(uint distance) { __p.bb.PutUint(__p.bb_pos + 4, distance); } + + public static Offset CreateAbility(FlatBufferBuilder builder, uint Id, uint Distance) { + builder.Prep(4, 8); + builder.PutUint(Distance); + builder.PutUint(Id); + return new Offset(builder.Offset); + } +}; + + +} diff --git a/tests/MyGame/Example/Ability.go b/tests/MyGame/Example/Ability.go new file mode 100644 index 000000000..2ea866538 --- /dev/null +++ b/tests/MyGame/Example/Ability.go @@ -0,0 +1,41 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package Example + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type Ability struct { + _tab flatbuffers.Struct +} + +func (rcv *Ability) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *Ability) Table() flatbuffers.Table { + return rcv._tab.Table +} + +func (rcv *Ability) Id() uint32 { + return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(0)) +} +func (rcv *Ability) MutateId(n uint32) bool { + return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n) +} + +func (rcv *Ability) Distance() uint32 { + return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(4)) +} +func (rcv *Ability) MutateDistance(n uint32) bool { + return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n) +} + +func CreateAbility(builder *flatbuffers.Builder, id uint32, distance uint32) flatbuffers.UOffsetT { + builder.Prep(4, 8) + builder.PrependUint32(distance) + builder.PrependUint32(id) + return builder.Offset() +} diff --git a/tests/MyGame/Example/Ability.java b/tests/MyGame/Example/Ability.java new file mode 100644 index 000000000..5e1c90e03 --- /dev/null +++ b/tests/MyGame/Example/Ability.java @@ -0,0 +1,27 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package MyGame.Example; + +import java.nio.*; +import java.lang.*; +import java.util.*; +import com.google.flatbuffers.*; + +@SuppressWarnings("unused") +public final class Ability extends Struct { + public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; } + public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public long id() { return (long)bb.getInt(bb_pos + 0) & 0xFFFFFFFFL; } + public void mutateId(long id) { bb.putInt(bb_pos + 0, (int)id); } + public long distance() { return (long)bb.getInt(bb_pos + 4) & 0xFFFFFFFFL; } + public void mutateDistance(long distance) { bb.putInt(bb_pos + 4, (int)distance); } + + public static int createAbility(FlatBufferBuilder builder, long id, long distance) { + builder.prep(4, 8); + builder.putInt((int)distance); + builder.putInt((int)id); + return builder.offset(); + } +} + diff --git a/tests/MyGame/Example/Ability.php b/tests/MyGame/Example/Ability.php new file mode 100644 index 000000000..c09eca318 --- /dev/null +++ b/tests/MyGame/Example/Ability.php @@ -0,0 +1,52 @@ +bb_pos = $_i; + $this->bb = $_bb; + return $this; + } + + /** + * @return uint + */ + public function GetId() + { + return $this->bb->getUint($this->bb_pos + 0); + } + + /** + * @return uint + */ + public function GetDistance() + { + return $this->bb->getUint($this->bb_pos + 4); + } + + + /** + * @return int offset + */ + public static function createAbility(FlatBufferBuilder $builder, $id, $distance) + { + $builder->prep(4, 8); + $builder->putUint($distance); + $builder->putUint($id); + return $builder->offset(); + } +} diff --git a/tests/MyGame/Example/Ability.py b/tests/MyGame/Example/Ability.py new file mode 100644 index 000000000..3c4776ef8 --- /dev/null +++ b/tests/MyGame/Example/Ability.py @@ -0,0 +1,23 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: Example + +import flatbuffers + +class Ability(object): + __slots__ = ['_tab'] + + # Ability + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # Ability + def Id(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0)) + # Ability + def Distance(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4)) + +def CreateAbility(builder, id, distance): + builder.Prep(4, 8) + builder.PrependUint32(distance) + builder.PrependUint32(id) + return builder.Offset() diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs index 30f49221e..1c473f309 100644 --- a/tests/MyGame/Example/Monster.cs +++ b/tests/MyGame/Example/Monster.cs @@ -78,8 +78,10 @@ public struct Monster : IFlatbufferObject public bool MutateTestf3(float testf3) { int o = __p.__offset(58); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf3); return true; } else { return false; } } public string Testarrayofstring2(int j) { int o = __p.__offset(60); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; } 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 static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(29); } + public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(30); } 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); } @@ -121,6 +123,8 @@ public struct Monster : IFlatbufferObject public static void AddTestarrayofstring2(FlatBufferBuilder builder, VectorOffset testarrayofstring2Offset) { builder.AddOffset(28, testarrayofstring2Offset.Value, 0); } public static VectorOffset CreateTestarrayofstring2Vector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); } 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 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 ba3ae0f4c..ba2e60d11 100644 --- a/tests/MyGame/Example/Monster.go +++ b/tests/MyGame/Example/Monster.go @@ -419,8 +419,27 @@ func (rcv *Monster) Testarrayofstring2Length() int { return 0 } +func (rcv *Monster) Testarrayofsortedstruct(obj *Ability, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(62)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 8 + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *Monster) TestarrayofsortedstructLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(62)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + func MonsterStart(builder *flatbuffers.Builder) { - builder.StartObject(29) + builder.StartObject(30) } func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) { builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0) @@ -527,6 +546,12 @@ func MonsterAddTestarrayofstring2(builder *flatbuffers.Builder, testarrayofstrin func MonsterStartTestarrayofstring2Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(4, numElems, 4) } +func MonsterAddTestarrayofsortedstruct(builder *flatbuffers.Builder, testarrayofsortedstruct flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(29, flatbuffers.UOffsetT(testarrayofsortedstruct), 0) +} +func MonsterStartTestarrayofsortedstructVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(8, numElems, 4) +} 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 10a9aa4d4..5bde80a3f 100644 --- a/tests/MyGame/Example/Monster.java +++ b/tests/MyGame/Example/Monster.java @@ -87,8 +87,11 @@ public final class Monster extends Table { public boolean mutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.putFloat(o + bb_pos, testf3); return true; } else { return false; } } public String testarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; } public int testarrayofstring2Length() { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; } + 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 static void startMonster(FlatBufferBuilder builder) { builder.startObject(29); } + public static void startMonster(FlatBufferBuilder builder) { builder.startObject(30); } 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); } @@ -130,6 +133,8 @@ public final class Monster extends Table { public static void addTestarrayofstring2(FlatBufferBuilder builder, int testarrayofstring2Offset) { builder.addOffset(28, testarrayofstring2Offset, 0); } public static int createTestarrayofstring2Vector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); } 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 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 c06cffbc6..a86687063 100644 --- a/tests/MyGame/Example/Monster.php +++ b/tests/MyGame/Example/Monster.php @@ -379,22 +379,41 @@ class Monster extends Table return $o != 0 ? $this->__vector_len($o) : 0; } + /** + * @returnVectorOffset + */ + public function getTestarrayofsortedstruct($j) + { + $o = $this->__offset(62); + $obj = new Ability(); + return $o != 0 ? $obj->init($this->__vector($o) + $j *8, $this->bb) : null; + } + + /** + * @return int + */ + public function getTestarrayofsortedstructLength() + { + $o = $this->__offset(62); + return $o != 0 ? $this->__vector_len($o) : 0; + } + /** * @param FlatBufferBuilder $builder * @return void */ public static function startMonster(FlatBufferBuilder $builder) { - $builder->StartObject(29); + $builder->StartObject(30); } /** * @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) + 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) { - $builder->startObject(29); + $builder->startObject(30); self::addPos($builder, $pos); self::addMana($builder, $mana); self::addHp($builder, $hp); @@ -423,6 +442,7 @@ class Monster extends Table self::addTestf2($builder, $testf2); self::addTestf3($builder, $testf3); self::addTestarrayofstring2($builder, $testarrayofstring2); + self::addTestarrayofsortedstruct($builder, $testarrayofsortedstruct); $o = $builder->endObject(); $builder->required($o, 10); // name return $o; @@ -871,6 +891,40 @@ class Monster extends Table $builder->startVector(4, $numElems, 4); } + /** + * @param FlatBufferBuilder $builder + * @param VectorOffset + * @return void + */ + public static function addTestarrayofsortedstruct(FlatBufferBuilder $builder, $testarrayofsortedstruct) + { + $builder->addOffsetX(29, $testarrayofsortedstruct, 0); + } + + /** + * @param FlatBufferBuilder $builder + * @param array offset array + * @return int vector offset + */ + public static function createTestarrayofsortedstructVector(FlatBufferBuilder $builder, array $data) + { + $builder->startVector(8, count($data), 4); + for ($i = count($data) - 1; $i >= 0; $i--) { + $builder->addOffset($data[$i]); + } + return $builder->endVector(); + } + + /** + * @param FlatBufferBuilder $builder + * @param int $numElems + * @return void + */ + public static function startTestarrayofsortedstructVector(FlatBufferBuilder $builder, $numElems) + { + $builder->startVector(8, $numElems, 4); + } + /** * @param FlatBufferBuilder $builder * @return int table offset diff --git a/tests/MyGame/Example/Monster.py b/tests/MyGame/Example/Monster.py index a7a783633..75e54a1fd 100644 --- a/tests/MyGame/Example/Monster.py +++ b/tests/MyGame/Example/Monster.py @@ -297,7 +297,26 @@ class Monster(object): return self._tab.VectorLen(o) return 0 -def MonsterStart(builder): builder.StartObject(29) + # Monster + def Testarrayofsortedstruct(self, j): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(62)) + if o != 0: + x = self._tab.Vector(o) + x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 8 + from .Ability import Ability + obj = Ability() + obj.Init(self._tab.Bytes, x) + return obj + return None + + # Monster + def TestarrayofsortedstructLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(62)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + +def MonsterStart(builder): builder.StartObject(30) 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) @@ -333,4 +352,6 @@ def MonsterAddTestf2(builder, testf2): builder.PrependFloat32Slot(26, testf2, 3. def MonsterAddTestf3(builder, testf3): builder.PrependFloat32Slot(27, testf3, 0.0) def MonsterAddTestarrayofstring2(builder, testarrayofstring2): builder.PrependUOffsetTRelativeSlot(28, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofstring2), 0) 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 MonsterEnd(builder): return builder.EndObject() diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs index 21f3c0008..a27bafc61 100644 Binary files a/tests/monster_test.bfbs and b/tests/monster_test.bfbs differ diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs index 050bcea57..81ec993e5 100755 --- a/tests/monster_test.fbs +++ b/tests/monster_test.fbs @@ -29,6 +29,11 @@ struct Vec3 (force_align: 16) { test3:Test; } +struct Ability { + id:uint(key); + distance:uint; +} + table Stat { id:string; val:long; @@ -50,6 +55,7 @@ table Monster { testarrayofstring:[string] (id: 10); testarrayofstring2:[string] (id: 28); testarrayofbools:[bool] (id: 24); + testarrayofsortedstruct:[Ability] (id: 29); enemy:MyGame.Example.Monster (id:12); // Test referring by full namespace. test:Any (id: 8); test4:[Test] (id: 9); diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index ea7f4c3bd..b1fac7463 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -23,6 +23,8 @@ struct TestSimpleTableWithEnumT; struct Vec3; +struct Ability; + struct Stat; struct StatT; @@ -247,6 +249,44 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS { }; STRUCT_END(Vec3, 32); +MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS { + private: + uint32_t id_; + uint32_t distance_; + + public: + Ability() { + memset(this, 0, sizeof(Ability)); + } + Ability(const Ability &_o) { + memcpy(this, &_o, sizeof(Ability)); + } + Ability(uint32_t _id, uint32_t _distance) + : id_(flatbuffers::EndianScalar(_id)), + distance_(flatbuffers::EndianScalar(_distance)) { + } + uint32_t id() const { + return flatbuffers::EndianScalar(id_); + } + void mutate_id(uint32_t _id) { + flatbuffers::WriteScalar(&id_, _id); + } + bool KeyCompareLessThan(const Ability *o) const { + return id() < o->id(); + } + int KeyCompareWithValue(uint32_t val) const { + const auto key = id(); + return static_cast(key > val) - static_cast(key < val); + } + uint32_t distance() const { + return flatbuffers::EndianScalar(distance_); + } + void mutate_distance(uint32_t _distance) { + flatbuffers::WriteScalar(&distance_, _distance); + } +}; +STRUCT_END(Ability, 8); + } // namespace Example namespace Example2 { @@ -480,6 +520,7 @@ struct MonsterT : public flatbuffers::NativeTable { float testf2; float testf3; std::vector testarrayofstring2; + std::vector testarrayofsortedstruct; MonsterT() : mana(150), hp(100), @@ -530,7 +571,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_TESTF = 54, VT_TESTF2 = 56, VT_TESTF3 = 58, - VT_TESTARRAYOFSTRING2 = 60 + VT_TESTARRAYOFSTRING2 = 60, + VT_TESTARRAYOFSORTEDSTRUCT = 62 }; const Vec3 *pos() const { return GetStruct(VT_POS); @@ -722,6 +764,12 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { flatbuffers::Vector> *mutable_testarrayofstring2() { return GetPointer> *>(VT_TESTARRAYOFSTRING2); } + const flatbuffers::Vector *testarrayofsortedstruct() const { + return GetPointer *>(VT_TESTARRAYOFSORTEDSTRUCT); + } + flatbuffers::Vector *mutable_testarrayofsortedstruct() { + return GetPointer *>(VT_TESTARRAYOFSORTEDSTRUCT); + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_POS) && @@ -766,6 +814,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_TESTARRAYOFSTRING2) && verifier.Verify(testarrayofstring2()) && verifier.VerifyVectorOfStrings(testarrayofstring2()) && + VerifyField(verifier, VT_TESTARRAYOFSORTEDSTRUCT) && + verifier.Verify(testarrayofsortedstruct()) && verifier.EndTable(); } MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; @@ -872,13 +922,16 @@ struct MonsterBuilder { void add_testarrayofstring2(flatbuffers::Offset>> testarrayofstring2) { fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING2, testarrayofstring2); } + void add_testarrayofsortedstruct(flatbuffers::Offset> testarrayofsortedstruct) { + fbb_.AddOffset(Monster::VT_TESTARRAYOFSORTEDSTRUCT, testarrayofsortedstruct); + } MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); } MonsterBuilder &operator=(const MonsterBuilder &); flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_, 29); + const auto end = fbb_.EndTable(start_, 30); auto o = flatbuffers::Offset(end); fbb_.Required(o, Monster::VT_NAME); return o; @@ -914,12 +967,14 @@ inline flatbuffers::Offset CreateMonster( float testf = 3.14159f, float testf2 = 3.0f, float testf3 = 0.0f, - flatbuffers::Offset>> testarrayofstring2 = 0) { + flatbuffers::Offset>> testarrayofstring2 = 0, + flatbuffers::Offset> testarrayofsortedstruct = 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_testarrayofsortedstruct(testarrayofsortedstruct); builder_.add_testarrayofstring2(testarrayofstring2); builder_.add_testf3(testf3); builder_.add_testf2(testf2); @@ -976,7 +1031,8 @@ inline flatbuffers::Offset CreateMonsterDirect( float testf = 3.14159f, float testf2 = 3.0f, float testf3 = 0.0f, - const std::vector> *testarrayofstring2 = nullptr) { + const std::vector> *testarrayofstring2 = nullptr, + const std::vector *testarrayofsortedstruct = nullptr) { return MyGame::Example::CreateMonster( _fbb, pos, @@ -1006,7 +1062,8 @@ inline flatbuffers::Offset CreateMonsterDirect( testf, testf2, testf3, - testarrayofstring2 ? _fbb.CreateVector>(*testarrayofstring2) : 0); + testarrayofstring2 ? _fbb.CreateVector>(*testarrayofstring2) : 0, + testarrayofsortedstruct ? _fbb.CreateVector(*testarrayofsortedstruct) : 0); } flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); @@ -1134,6 +1191,7 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function { auto _e = testf2(); _o->testf2 = _e; }; { 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); } } }; } inline flatbuffers::Offset Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) { @@ -1171,6 +1229,7 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder auto _testf2 = _o->testf2; auto _testf3 = _o->testf3; auto _testarrayofstring2 = _o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0; + auto _testarrayofsortedstruct = _o->testarrayofsortedstruct.size() ? _fbb.CreateVectorOfStructs(_o->testarrayofsortedstruct) : 0; return MyGame::Example::CreateMonster( _fbb, _pos, @@ -1200,7 +1259,8 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder _testf, _testf2, _testf3, - _testarrayofstring2); + _testarrayofstring2, + _testarrayofsortedstruct); } 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 dbb5ba635..7b0165c55 100644 --- a/tests/monster_test_generated.js +++ b/tests/monster_test_generated.js @@ -432,6 +432,89 @@ MyGame.Example.Vec3.createVec3 = function(builder, x, y, z, test1, test2, test3_ return builder.offset(); }; +/** + * @constructor + */ +MyGame.Example.Ability = function() { + /** + * @type {flatbuffers.ByteBuffer} + */ + this.bb = null; + + /** + * @type {number} + */ + this.bb_pos = 0; +}; + +/** + * @param {number} i + * @param {flatbuffers.ByteBuffer} bb + * @returns {MyGame.Example.Ability} + */ +MyGame.Example.Ability.prototype.__init = function(i, bb) { + this.bb_pos = i; + this.bb = bb; + return this; +}; + +/** + * @returns {number} + */ +MyGame.Example.Ability.prototype.id = function() { + return this.bb.readUint32(this.bb_pos); +}; + +/** + * @param {number} value + * @returns {boolean} + */ +MyGame.Example.Ability.prototype.mutate_id = function(value) { + var offset = this.bb.__offset(this.bb_pos, 0); + + if (offset === 0) { + return false; + } + + this.bb.writeUint32(this.bb_pos + offset, value); + return true; +}; + +/** + * @returns {number} + */ +MyGame.Example.Ability.prototype.distance = function() { + return this.bb.readUint32(this.bb_pos + 4); +}; + +/** + * @param {number} value + * @returns {boolean} + */ +MyGame.Example.Ability.prototype.mutate_distance = function(value) { + var offset = this.bb.__offset(this.bb_pos, 4); + + if (offset === 0) { + return false; + } + + this.bb.writeUint32(this.bb_pos + offset, value); + return true; +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} id + * @param {number} distance + * @returns {flatbuffers.Offset} + */ +MyGame.Example.Ability.createAbility = function(builder, id, distance) { + builder.prep(4, 8); + builder.writeInt32(distance); + builder.writeInt32(id); + return builder.offset(); +}; + /** * @constructor */ @@ -1170,11 +1253,29 @@ MyGame.Example.Monster.prototype.testarrayofstring2Length = function() { return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; }; +/** + * @param {number} index + * @param {MyGame.Example.Ability=} obj + * @returns {MyGame.Example.Ability} + */ +MyGame.Example.Monster.prototype.testarrayofsortedstruct = function(index, obj) { + var offset = this.bb.__offset(this.bb_pos, 62); + return offset ? (obj || new MyGame.Example.Ability).__init(this.bb.__vector(this.bb_pos + offset) + index * 8, this.bb) : null; +}; + +/** + * @returns {number} + */ +MyGame.Example.Monster.prototype.testarrayofsortedstructLength = function() { + var offset = this.bb.__offset(this.bb_pos, 62); + return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0; +}; + /** * @param {flatbuffers.Builder} builder */ MyGame.Example.Monster.startMonster = function(builder) { - builder.startObject(29); + builder.startObject(30); }; /** @@ -1535,6 +1636,22 @@ MyGame.Example.Monster.startTestarrayofstring2Vector = function(builder, numElem builder.startVector(4, numElems, 4); }; +/** + * @param {flatbuffers.Builder} builder + * @param {flatbuffers.Offset} testarrayofsortedstructOffset + */ +MyGame.Example.Monster.addTestarrayofsortedstruct = function(builder, testarrayofsortedstructOffset) { + builder.addFieldOffset(29, testarrayofsortedstructOffset, 0); +}; + +/** + * @param {flatbuffers.Builder} builder + * @param {number} numElems + */ +MyGame.Example.Monster.startTestarrayofsortedstructVector = function(builder, numElems) { + builder.startVector(8, numElems, 4); +}; + /** * @param {flatbuffers.Builder} builder * @returns {flatbuffers.Offset} diff --git a/tests/monsterdata_test.mon b/tests/monsterdata_test.mon index 01bd52794..21c42166a 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 4e031b6dd..8011a11a8 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -134,12 +134,21 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) { // Create an array of sorted tables, can be used with binary search when read: auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3); + // Create an array of sorted structs, + // can be used with binary search when read: + std::vector abilities; + abilities.push_back(Ability(4, 40)); + abilities.push_back(Ability(3, 30)); + abilities.push_back(Ability(2, 20)); + abilities.push_back(Ability(1, 10)); + auto vecofstructs = builder.CreateVectorOfSortedStructs(&abilities); + // 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, 0, 0, false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, - vecofstrings2); + vecofstrings2, vecofstructs); FinishMonsterBuffer(builder, mloc); @@ -249,6 +258,18 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length, TEST_NOTNULL(vecoftables->LookupByKey("Fred")); TEST_NOTNULL(vecoftables->LookupByKey("Wilma")); + // Test accessing a vector of sorted structs + auto vecofstructs = monster->testarrayofsortedstruct(); + if (vecofstructs) { // not filled in monster_test.bfbs + for (size_t i = 0; i < vecofstructs->size()-1; i++) { + auto left = vecofstructs->Get(i); + auto right = vecofstructs->Get(i+1); + TEST_EQ(true, (left->KeyCompareLessThan(right))); + } + TEST_NOTNULL(vecofstructs->LookupByKey(3)); + TEST_EQ(static_cast(nullptr), vecofstructs->LookupByKey(5)); + } + // 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):