From dc2fa215b854b31aa9a7f8c959ce08297ec79e23 Mon Sep 17 00:00:00 2001 From: Wouter van Oortmerssen Date: Wed, 5 Oct 2016 16:59:15 -0700 Subject: [PATCH] External references for the object API thru a resolver function. This allows hashed string fields to be used for lookup of any C++ objects, a pointer to which are then stored in the object besides the original hash for easy access. Change-Id: I2247a13c349b905f1c54660becde2c818ad23e97 Tested: on Linux. Bug: 30204449 --- docs/source/CppUsage.md | 19 ++++++++ docs/source/Schemas.md | 4 ++ include/flatbuffers/flatbuffers.h | 18 ++++++++ include/flatbuffers/idl.h | 1 + samples/monster_generated.h | 34 +++++++-------- src/idl_gen_cpp.cpp | 61 ++++++++++++++++++-------- src/idl_parser.cpp | 5 +++ tests/monster_test.fbs | 2 +- tests/monster_test_generated.h | 72 +++++++++++++++---------------- tests/test.cpp | 21 +++++++-- 10 files changed, 161 insertions(+), 76 deletions(-) diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md index 87a11c8bd..88b6e4557 100755 --- a/docs/source/CppUsage.md +++ b/docs/source/CppUsage.md @@ -106,6 +106,25 @@ To use: CreateMonster(fbb, monsterobj.get()); // Serialize into new buffer. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# External references. + +An additional feature of the object API is the ability to allow you to load +multiple independent FlatBuffers, and have them refer to eachothers objects +using hashes which are then represented as typed pointers in the object API. + +To make this work have a field in the objects you want to referred to which is +using the string hashing feature (see `hash` attribute in the +[schema](@ref flatbuffers_guide_writing_schema) documentation). Then you have +a similar hash in the field referring to it, along with a `cpp_type` +attribute specifying the C++ type this will refer to (this can be any C++ +type, and will get a `*` added). + +Then, in JSON or however you create these buffers, make sure they use the +same string (or hash). + +When you call `UnPack` (or `Create`), you'll need a function that maps from +hash to the object (see `resolver_function_t` for details). + ## Reflection (& Resizing) There is experimental support for reflection in FlatBuffers, allowing you to diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md index 5bcaccb37..f9fe4867b 100755 --- a/docs/source/Schemas.md +++ b/docs/source/Schemas.md @@ -304,6 +304,10 @@ Current understood attributes: - `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. +- `hash` (on a field). This is an (un)signed 32/64 bit integer field, whose + value during JSON parsing is allowed to be a string, which will then be + stored as its hash. The value of attribute is the hashing algorithm to + use, one of `fnv1_32` `fnv1_64` `fnv1a_32` `fnv1a_64`. ## JSON Parsing diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index b193b1791..8c1c7f0ee 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -1560,6 +1560,24 @@ class Table { struct NativeTable { }; +/// @brief Function types to be used with resolving hashes into objects and +/// back again. The resolver gets a pointer to a field inside an object API +/// object that is of the type specified in the schema using the attribute +/// `cpp_type` (it is thus important whatever you write to this address +/// matches that type). The value of this field is initially null, so you +/// may choose to implement a delayed binding lookup using this function +/// if you wish. The resolver does the opposite lookup, for when the object +/// is being serialized again. +typedef uint64_t hash_value_t; +#ifdef FLATBUFFERS_CPP98_STL + typedef void (*resolver_function_t)(void **pointer_adr, hash_value_t hash); + typedef hash_value_t (*rehasher_function_t)(void *pointer); +#else + typedef std::function + resolver_function_t; + typedef std::function rehasher_function_t; +#endif + // Helper function to test if a field is present, using any of the field // enums in the generated code. // `table` must be a generated table type. Since this is a template parameter, diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index 1c1e63494..63788b743 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -450,6 +450,7 @@ class Parser : public ParserState { known_attributes_["csharp_partial"] = true; known_attributes_["streaming"] = true; known_attributes_["idempotent"] = true; + known_attributes_["cpp_type"] = true; } ~Parser() { diff --git a/samples/monster_generated.h b/samples/monster_generated.h index 84e56224f..1efa5e058 100644 --- a/samples/monster_generated.h +++ b/samples/monster_generated.h @@ -47,8 +47,8 @@ struct EquipmentUnion { EquipmentUnion &operator=(const EquipmentUnion &); ~EquipmentUnion(); - static flatbuffers::NativeTable *UnPack(const void *union_obj, Equipment type); - flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb) const; + static flatbuffers::NativeTable *UnPack(const void *union_obj, Equipment type, const flatbuffers::resolver_function_t *resolver); + flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher = nullptr) const; WeaponT *AsWeapon() { return type == Equipment_Weapon ? reinterpret_cast(table) : nullptr; } }; @@ -142,7 +142,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyEquipment(verifier, equipped(), equipped_type()) && verifier.EndTable(); } - std::unique_ptr UnPack() const; + std::unique_ptr UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const; }; struct MonsterBuilder { @@ -201,7 +201,7 @@ inline flatbuffers::Offset CreateMonsterDirect(flatbuffers::FlatBufferB return CreateMonster(_fbb, pos, mana, hp, name ? _fbb.CreateString(name) : 0, inventory ? _fbb.CreateVector(*inventory) : 0, color, weapons ? _fbb.CreateVector>(*weapons) : 0, equipped_type, equipped); } -inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o); +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr); struct WeaponT : public flatbuffers::NativeTable { std::string name; @@ -224,7 +224,7 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_DAMAGE) && verifier.EndTable(); } - std::unique_ptr UnPack() const; + std::unique_ptr UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const; }; struct WeaponBuilder { @@ -255,9 +255,9 @@ inline flatbuffers::Offset CreateWeaponDirect(flatbuffers::FlatBufferBui return CreateWeapon(_fbb, name ? _fbb.CreateString(name) : 0, damage); } -inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o); +inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr); -inline std::unique_ptr Monster::UnPack() const { +inline std::unique_ptr Monster::UnPack(const flatbuffers::resolver_function_t *resolver) const { auto _o = new MonsterT(); { auto _e = pos(); if (_e) _o->pos = std::unique_ptr(new Vec3(*_e)); }; { auto _e = mana(); _o->mana = _e; }; @@ -265,13 +265,13 @@ inline std::unique_ptr Monster::UnPack() const { { auto _e = name(); if (_e) _o->name = _e->str(); }; { auto _e = inventory(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } } }; { auto _e = color(); _o->color = _e; }; - { auto _e = weapons(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(_e->Get(_i)->UnPack()); } } }; + { auto _e = weapons(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(_e->Get(_i)->UnPack(resolver)); } } }; { auto _e = equipped_type(); _o->equipped.type = _e; }; - { auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type()); }; + { auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type(), resolver); }; return std::unique_ptr(_o); } -inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) { +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher) { return CreateMonster(_fbb, _o->pos ? _o->pos.get() : 0, _o->mana, @@ -279,19 +279,19 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder _o->name.size() ? _fbb.CreateString(_o->name) : 0, _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0, _o->color, - _o->weapons.size() ? _fbb.CreateVector>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get()); }) : 0, + _o->weapons.size() ? _fbb.CreateVector>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get(), rehasher); }) : 0, _o->equipped.type, _o->equipped.Pack(_fbb)); } -inline std::unique_ptr Weapon::UnPack() const { +inline std::unique_ptr Weapon::UnPack(const flatbuffers::resolver_function_t *resolver) const { auto _o = new WeaponT(); { auto _e = name(); if (_e) _o->name = _e->str(); }; { auto _e = damage(); _o->damage = _e; }; return std::unique_ptr(_o); } -inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o) { +inline flatbuffers::Offset CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *rehasher) { return CreateWeapon(_fbb, _o->name.size() ? _fbb.CreateString(_o->name) : 0, _o->damage); @@ -305,18 +305,18 @@ inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_o } } -inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type) { +inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type, const flatbuffers::resolver_function_t *resolver) { switch (type) { case Equipment_NONE: return nullptr; - case Equipment_Weapon: return reinterpret_cast(union_obj)->UnPack().release(); + case Equipment_Weapon: return reinterpret_cast(union_obj)->UnPack(resolver).release(); default: return nullptr; } } -inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const { +inline flatbuffers::Offset EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher) const { switch (type) { case Equipment_NONE: return 0; - case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast(table)).Union(); + case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast(table), rehasher).Union(); default: return 0; } } diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 74a6bf9a0..23bcab7cf 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -361,25 +361,32 @@ class CppGenerator : public BaseGenerator { return (inclass ? "static " : "") + std::string("flatbuffers::NativeTable *") + (inclass ? "" : enum_def.name + "Union::") + - "UnPack(const void *union_obj, " + enum_def.name + " type)"; + "UnPack(const void *union_obj, " + enum_def.name + + " type, const flatbuffers::resolver_function_t *resolver)"; } std::string UnionPackSignature(EnumDef &enum_def, bool inclass) { return "flatbuffers::Offset " + (inclass ? "" : enum_def.name + "Union::") + - "Pack(flatbuffers::FlatBufferBuilder &_fbb) const"; + "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + + "const flatbuffers::rehasher_function_t *rehasher" + + (inclass ? " = nullptr" : "") + ") const"; } - std::string TableCreateSignature(StructDef &struct_def) { + std::string TableCreateSignature(StructDef &struct_def, bool predecl) { return "inline flatbuffers::Offset<" + struct_def.name + "> Create" + struct_def.name + "(flatbuffers::FlatBufferBuilder &_fbb, const " + - NativeName(struct_def.name) + " *_o)"; + NativeName(struct_def.name) + + " *_o, const flatbuffers::rehasher_function_t *rehasher" + + (predecl ? " = nullptr" : "") + ")"; } std::string TableUnPackSignature(StructDef &struct_def, bool inclass) { return "std::unique_ptr<" + NativeName(struct_def.name) + "> " + - (inclass ? "" : struct_def.name + "::") + "UnPack() const"; + (inclass ? "" : struct_def.name + "::") + + "UnPack(const flatbuffers::resolver_function_t *resolver" + + (inclass ? " = nullptr" : "") + ") const"; } // Generate an enum declaration and an enum string lookup table. @@ -524,7 +531,7 @@ class CppGenerator : public BaseGenerator { } else { code += ": return reinterpret_castname; code += "(_fbb, reinterpret_castconstant + " *" : type+ " ") + + field.name + ";\n"; } } code += "};\n\n"; @@ -945,7 +954,7 @@ class CppGenerator : public BaseGenerator { if (parser_.opts.generate_object_based_api) { // Generate a pre-declaration for a CreateX method that works with an // unpacked C++ object. - code += TableCreateSignature(struct_def) + ";\n\n"; + code += TableCreateSignature(struct_def, true) + ";\n\n"; } } @@ -982,7 +991,7 @@ class CppGenerator : public BaseGenerator { WrapInNameSpace (*type.struct_def) + "(*" + val + "))"; } } else { - return val + "->UnPack()"; + return val + "->UnPack(resolver)"; } default: return val; @@ -1009,16 +1018,28 @@ class CppGenerator : public BaseGenerator { code += prefix + deref + union_field.name + ".type = _e;"; break; } - case BASE_TYPE_UNION: + case BASE_TYPE_UNION: { code += prefix + dest + ".table = "; code += field.value.type.enum_def->name; code += "Union::UnPack(_e, "; - code += field.name + UnionTypeFieldSuffix() + "());"; + code += field.name + UnionTypeFieldSuffix() + "(), resolver);"; break; - default: - code += assign + gen_unpack_val(field.value.type, "_e", false); + } + default: { + auto cpp_type = field.attributes.Lookup("cpp_type"); + if (cpp_type) { + code += prefix; + code += "if (resolver) (*resolver)(reinterpret_cast(&"; + code += dest; + code += "), static_cast(_e)); else "; + code += dest + " = nullptr"; + } else { + code += assign; + code += gen_unpack_val(field.value.type, "_e", false); + } code += ";"; break; + } } code += " };\n"; } @@ -1027,7 +1048,7 @@ class CppGenerator : public BaseGenerator { code += ">(_o);\n}\n\n"; // Generate a CreateX method that works with an unpacked C++ object. - code += TableCreateSignature(struct_def) + " {\n"; + code += TableCreateSignature(struct_def, false) + " {\n"; auto before_return_statement = code.size(); code += " return Create"; code += struct_def.name + "(_fbb"; @@ -1044,6 +1065,10 @@ class CppGenerator : public BaseGenerator { field_name += ".type"; } auto accessor = "_o->" + field_name; + if (field.attributes.Lookup("cpp_type")) + accessor = "rehasher ? static_cast<" + + GenTypeBasic(field.value.type, false) + + ">((*rehasher)(" + accessor + ")) : 0"; auto ptrprefix = accessor + " ? "; auto stlprefix = accessor + ".size() ? "; auto postfix = " : 0"; @@ -1074,7 +1099,7 @@ class CppGenerator : public BaseGenerator { code += vector_type.struct_def->name + ">>(" + accessor; code += ".size(), [&](size_t i) { return Create"; code += vector_type.struct_def->name + "(_fbb, " + accessor; - code += "[i].get()); })"; + code += "[i].get(), rehasher); })"; } break; default: @@ -1093,7 +1118,7 @@ class CppGenerator : public BaseGenerator { } else { code += ptrprefix + "Create"; code += field.value.type.struct_def->name; - code += "(_fbb, " + accessor + ".get())" + postfix; + code += "(_fbb, " + accessor + ".get(), rehasher)" + postfix; } break; default: diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 21cbed3f5..06948bce4 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -657,6 +657,11 @@ CheckedError Parser::ParseField(StructDef &struct_def) { "only int, uint, long and ulong data types support hashing."); } } + auto cpp_type = field->attributes.Lookup("cpp_type"); + if (cpp_type) { + if (!hash_name) + return Error("cpp_type can only be used with a hashed field"); + } if (field->deprecated && struct_def.fixed) return Error("can't deprecate fields in a struct"); field->required = field->attributes.Lookup("required") != nullptr; diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs index 3fecd33cf..d1946a39a 100755 --- a/tests/monster_test.fbs +++ b/tests/monster_test.fbs @@ -61,7 +61,7 @@ table Monster { testhashs64_fnv1:long (id:18, hash:"fnv1_64"); testhashu64_fnv1:ulong (id:19, hash:"fnv1_64"); testhashs32_fnv1a:int (id:20, hash:"fnv1a_32"); - testhashu32_fnv1a:uint (id:21, hash:"fnv1a_32"); + testhashu32_fnv1a:uint (id:21, hash:"fnv1a_32", cpp_type:"Stat"); testhashs64_fnv1a:long (id:22, hash:"fnv1a_64"); testhashu64_fnv1a:ulong (id:23, hash:"fnv1a_64"); testf:float = 3.14159 (id:25); diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h index bb37b9536..eda76bd0e 100644 --- a/tests/monster_test_generated.h +++ b/tests/monster_test_generated.h @@ -61,8 +61,8 @@ struct AnyUnion { AnyUnion &operator=(const AnyUnion &); ~AnyUnion(); - static flatbuffers::NativeTable *UnPack(const void *union_obj, Any type); - flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb) const; + static flatbuffers::NativeTable *UnPack(const void *union_obj, Any type, const flatbuffers::resolver_function_t *resolver); + flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher = nullptr) const; MonsterT *AsMonster() { return type == Any_Monster ? reinterpret_cast(table) : nullptr; } TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() { return type == Any_TestSimpleTableWithEnum ? reinterpret_cast(table) : nullptr; } @@ -142,7 +142,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { return VerifyTableStart(verifier) && verifier.EndTable(); } - std::unique_ptr UnPack() const; + std::unique_ptr UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const; }; struct MonsterBuilder { @@ -161,7 +161,7 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder return builder_.Finish(); } -inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o); +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr); } // namespace Example2 @@ -182,7 +182,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta VerifyField(verifier, VT_COLOR) && verifier.EndTable(); } - std::unique_ptr UnPack() const; + std::unique_ptr UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const; }; struct TestSimpleTableWithEnumBuilder { @@ -204,7 +204,7 @@ inline flatbuffers::Offset CreateTestSimpleTableWithEnu return builder_.Finish(); } -inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o); +inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr); struct StatT : public flatbuffers::NativeTable { std::string id; @@ -232,7 +232,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_COUNT) && verifier.EndTable(); } - std::unique_ptr UnPack() const; + std::unique_ptr UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const; }; struct StatBuilder { @@ -267,7 +267,7 @@ inline flatbuffers::Offset CreateStatDirect(flatbuffers::FlatBufferBuilder return CreateStat(_fbb, id ? _fbb.CreateString(id) : 0, val, count); } -inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o); +inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr); struct MonsterT : public flatbuffers::NativeTable { std::unique_ptr pos; @@ -289,7 +289,7 @@ struct MonsterT : public flatbuffers::NativeTable { int64_t testhashs64_fnv1; uint64_t testhashu64_fnv1; int32_t testhashs32_fnv1a; - uint32_t testhashu32_fnv1a; + Stat *testhashu32_fnv1a; int64_t testhashs64_fnv1a; uint64_t testhashu64_fnv1a; std::vector testarrayofbools; @@ -438,7 +438,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { verifier.VerifyVectorOfStrings(testarrayofstring2()) && verifier.EndTable(); } - std::unique_ptr UnPack() const; + std::unique_ptr UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const; }; struct MonsterBuilder { @@ -574,18 +574,18 @@ inline flatbuffers::Offset CreateMonsterDirect(flatbuffers::FlatBufferB return CreateMonster(_fbb, pos, mana, hp, name ? _fbb.CreateString(name) : 0, inventory ? _fbb.CreateVector(*inventory) : 0, color, test_type, test, test4 ? _fbb.CreateVector(*test4) : 0, testarrayofstring ? _fbb.CreateVector>(*testarrayofstring) : 0, testarrayoftables ? _fbb.CreateVector>(*testarrayoftables) : 0, enemy, testnestedflatbuffer ? _fbb.CreateVector(*testnestedflatbuffer) : 0, testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? _fbb.CreateVector(*testarrayofbools) : 0, testf, testf2, testf3, testarrayofstring2 ? _fbb.CreateVector>(*testarrayofstring2) : 0); } -inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o); +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr); } // namespace Example namespace Example2 { -inline std::unique_ptr Monster::UnPack() const { +inline std::unique_ptr Monster::UnPack(const flatbuffers::resolver_function_t *resolver) const { auto _o = new MonsterT(); return std::unique_ptr(_o); } -inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) { +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher) { (void)_o; return CreateMonster(_fbb); } @@ -594,18 +594,18 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder namespace Example { -inline std::unique_ptr TestSimpleTableWithEnum::UnPack() const { +inline std::unique_ptr TestSimpleTableWithEnum::UnPack(const flatbuffers::resolver_function_t *resolver) const { auto _o = new TestSimpleTableWithEnumT(); { auto _e = color(); _o->color = _e; }; return std::unique_ptr(_o); } -inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o) { +inline flatbuffers::Offset CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *rehasher) { return CreateTestSimpleTableWithEnum(_fbb, _o->color); } -inline std::unique_ptr Stat::UnPack() const { +inline std::unique_ptr Stat::UnPack(const flatbuffers::resolver_function_t *resolver) const { auto _o = new StatT(); { auto _e = id(); if (_e) _o->id = _e->str(); }; { auto _e = val(); _o->val = _e; }; @@ -613,14 +613,14 @@ inline std::unique_ptr Stat::UnPack() const { return std::unique_ptr(_o); } -inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o) { +inline flatbuffers::Offset CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o, const flatbuffers::rehasher_function_t *rehasher) { return CreateStat(_fbb, _o->id.size() ? _fbb.CreateString(_o->id) : 0, _o->val, _o->count); } -inline std::unique_ptr Monster::UnPack() const { +inline std::unique_ptr Monster::UnPack(const flatbuffers::resolver_function_t *resolver) const { auto _o = new MonsterT(); { auto _e = pos(); if (_e) _o->pos = std::unique_ptr(new Vec3(*_e)); }; { auto _e = mana(); _o->mana = _e; }; @@ -629,20 +629,20 @@ inline std::unique_ptr Monster::UnPack() const { { auto _e = inventory(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } } }; { auto _e = color(); _o->color = _e; }; { auto _e = test_type(); _o->test.type = _e; }; - { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type()); }; + { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type(), resolver); }; { auto _e = test4(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4.push_back(*_e->Get(_i)); } } }; { auto _e = testarrayofstring(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring.push_back(_e->Get(_i)->str()); } } }; - { auto _e = testarrayoftables(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables.push_back(_e->Get(_i)->UnPack()); } } }; - { auto _e = enemy(); if (_e) _o->enemy = _e->UnPack(); }; + { auto _e = testarrayoftables(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables.push_back(_e->Get(_i)->UnPack(resolver)); } } }; + { auto _e = enemy(); if (_e) _o->enemy = _e->UnPack(resolver); }; { auto _e = testnestedflatbuffer(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer.push_back(_e->Get(_i)); } } }; - { auto _e = testempty(); if (_e) _o->testempty = _e->UnPack(); }; + { auto _e = testempty(); if (_e) _o->testempty = _e->UnPack(resolver); }; { auto _e = testbool(); _o->testbool = _e; }; { auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; }; { auto _e = testhashu32_fnv1(); _o->testhashu32_fnv1 = _e; }; { auto _e = testhashs64_fnv1(); _o->testhashs64_fnv1 = _e; }; { auto _e = testhashu64_fnv1(); _o->testhashu64_fnv1 = _e; }; { auto _e = testhashs32_fnv1a(); _o->testhashs32_fnv1a = _e; }; - { auto _e = testhashu32_fnv1a(); _o->testhashu32_fnv1a = _e; }; + { auto _e = testhashu32_fnv1a(); if (resolver) (*resolver)(reinterpret_cast(&_o->testhashu32_fnv1a), static_cast(_e)); else _o->testhashu32_fnv1a = nullptr; }; { auto _e = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; }; { auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; }; { auto _e = testarrayofbools(); if (_e) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i)!=0); } } }; @@ -653,7 +653,7 @@ inline std::unique_ptr Monster::UnPack() const { return std::unique_ptr(_o); } -inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) { +inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher) { return CreateMonster(_fbb, _o->pos ? _o->pos.get() : 0, _o->mana, @@ -665,17 +665,17 @@ inline flatbuffers::Offset CreateMonster(flatbuffers::FlatBufferBuilder _o->test.Pack(_fbb), _o->test4.size() ? _fbb.CreateVectorOfStructs(_o->test4) : 0, _o->testarrayofstring.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring) : 0, - _o->testarrayoftables.size() ? _fbb.CreateVector>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get()); }) : 0, - _o->enemy ? CreateMonster(_fbb, _o->enemy.get()) : 0, + _o->testarrayoftables.size() ? _fbb.CreateVector>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get(), rehasher); }) : 0, + _o->enemy ? CreateMonster(_fbb, _o->enemy.get(), rehasher) : 0, _o->testnestedflatbuffer.size() ? _fbb.CreateVector(_o->testnestedflatbuffer) : 0, - _o->testempty ? CreateStat(_fbb, _o->testempty.get()) : 0, + _o->testempty ? CreateStat(_fbb, _o->testempty.get(), rehasher) : 0, _o->testbool, _o->testhashs32_fnv1, _o->testhashu32_fnv1, _o->testhashs64_fnv1, _o->testhashu64_fnv1, _o->testhashs32_fnv1a, - _o->testhashu32_fnv1a, + rehasher ? static_cast((*rehasher)(_o->testhashu32_fnv1a)) : 0, _o->testhashs64_fnv1a, _o->testhashu64_fnv1a, _o->testarrayofbools.size() ? _fbb.CreateVector(_o->testarrayofbools) : 0, @@ -695,22 +695,22 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An } } -inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *union_obj, Any type) { +inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *union_obj, Any type, const flatbuffers::resolver_function_t *resolver) { switch (type) { case Any_NONE: return nullptr; - case Any_Monster: return reinterpret_cast(union_obj)->UnPack().release(); - case Any_TestSimpleTableWithEnum: return reinterpret_cast(union_obj)->UnPack().release(); - case Any_MyGame_Example2_Monster: return reinterpret_cast(union_obj)->UnPack().release(); + case Any_Monster: return reinterpret_cast(union_obj)->UnPack(resolver).release(); + case Any_TestSimpleTableWithEnum: return reinterpret_cast(union_obj)->UnPack(resolver).release(); + case Any_MyGame_Example2_Monster: return reinterpret_cast(union_obj)->UnPack(resolver).release(); default: return nullptr; } } -inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const { +inline flatbuffers::Offset AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher) const { switch (type) { case Any_NONE: return 0; - case Any_Monster: return CreateMonster(_fbb, reinterpret_cast(table)).Union(); - case Any_TestSimpleTableWithEnum: return CreateTestSimpleTableWithEnum(_fbb, reinterpret_cast(table)).Union(); - case Any_MyGame_Example2_Monster: return CreateMonster(_fbb, reinterpret_cast(table)).Union(); + case Any_Monster: return CreateMonster(_fbb, reinterpret_cast(table), rehasher).Union(); + case Any_TestSimpleTableWithEnum: return CreateTestSimpleTableWithEnum(_fbb, reinterpret_cast(table), rehasher).Union(); + case Any_MyGame_Example2_Monster: return CreateMonster(_fbb, reinterpret_cast(table), rehasher).Union(); default: return 0; } } diff --git a/tests/test.cpp b/tests/test.cpp index 45eb1fe25..6567b9139 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -314,17 +314,30 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) { // Unpack a FlatBuffer into objects. void ObjectFlatBuffersTest(uint8_t *flatbuf) { + // Optional: we can specify resolver and rehasher functions to turn hashed + // strings into object pointers and back, to implement remote references + // and such. + auto resolver = flatbuffers::resolver_function_t([](void **pointer_adr, + flatbuffers::hash_value_t hash) { + return nullptr; // Fail the lookup. + }); + auto rehasher = flatbuffers::rehasher_function_t([](void *pointer) { + return 0; + }); + // Turn a buffer into C++ objects. - auto monster1 = GetMonster(flatbuf)->UnPack(); + auto monster1 = GetMonster(flatbuf)->UnPack(&resolver); // Re-serialize the data. flatbuffers::FlatBufferBuilder fbb1; - fbb1.Finish(CreateMonster(fbb1, monster1.get()), MonsterIdentifier()); + fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher), + MonsterIdentifier()); // Unpack again, and re-serialize again. - auto monster2 = GetMonster(fbb1.GetBufferPointer())->UnPack(); + auto monster2 = GetMonster(fbb1.GetBufferPointer())->UnPack(&resolver); flatbuffers::FlatBufferBuilder fbb2; - fbb2.Finish(CreateMonster(fbb2, monster2.get()), MonsterIdentifier()); + fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher), + MonsterIdentifier()); // Now we've gone full round-trip, the two buffers should match. auto len1 = fbb1.GetSize();