Added optional object based API for C++.

Change-Id: If927f3ea3fb3723088fa287f24bdd1ad43c8d1d1
Tested: on Linux.
parent b22db6e8
...@@ -40,6 +40,8 @@ flatsamplebinary ...@@ -40,6 +40,8 @@ flatsamplebinary
flatsamplebinary.exe flatsamplebinary.exe
flatsampletext flatsampletext
flatsampletext.exe flatsampletext.exe
grpctest
grpctest.exe
snapshot.sh snapshot.sh
tests/go_gen tests/go_gen
tests/monsterdata_java_wire.mon tests/monsterdata_java_wire.mon
......
...@@ -6,8 +6,10 @@ project(FlatBuffers) ...@@ -6,8 +6,10 @@ project(FlatBuffers)
option(FLATBUFFERS_CODE_COVERAGE "Enable the code coverage build option." OFF) option(FLATBUFFERS_CODE_COVERAGE "Enable the code coverage build option." OFF)
option(FLATBUFFERS_BUILD_TESTS "Enable the build of tests and samples." ON) option(FLATBUFFERS_BUILD_TESTS "Enable the build of tests and samples." ON)
option(FLATBUFFERS_INSTALL "Enable the installation of targets." ON) option(FLATBUFFERS_INSTALL "Enable the installation of targets." ON)
option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library" ON) option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library"
option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" ON) ON)
option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler"
ON)
option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON) option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON)
option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF) option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF)
...@@ -95,7 +97,8 @@ set(FlatBuffers_GRPCTest_SRCS ...@@ -95,7 +97,8 @@ set(FlatBuffers_GRPCTest_SRCS
if(APPLE) if(APPLE)
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror -Wextra") "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++ -Wall -pedantic -Werror
-Wextra")
elseif(CMAKE_COMPILER_IS_GNUCXX) elseif(CMAKE_COMPILER_IS_GNUCXX)
if(CYGWIN) if(CYGWIN)
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS
...@@ -118,7 +121,8 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) ...@@ -118,7 +121,8 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror -Wextra") "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror
-Wextra")
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD") if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
set(CMAKE_EXE_LINKER_FLAGS set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi") "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
...@@ -165,7 +169,9 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS) ...@@ -165,7 +169,9 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS}) string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
add_custom_command( add_custom_command(
OUTPUT ${GEN_HEADER} OUTPUT ${GEN_HEADER}
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
--gen-object-api -o "${SRC_FBS_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc) DEPENDS flatc)
endfunction() endfunction()
...@@ -174,7 +180,8 @@ function(compile_flatbuffers_schema_to_binary SRC_FBS) ...@@ -174,7 +180,8 @@ function(compile_flatbuffers_schema_to_binary SRC_FBS)
string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS}) string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS})
add_custom_command( add_custom_command(
OUTPUT ${GEN_BINARY_SCHEMA} OUTPUT ${GEN_BINARY_SCHEMA}
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -b --schema -o "${SRC_FBS_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}" COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -b --schema -o "${SRC_FBS_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc) DEPENDS flatc)
endfunction() endfunction()
......
...@@ -81,6 +81,11 @@ Additional options: ...@@ -81,6 +81,11 @@ Additional options:
- `--gen-mutable` : Generate additional non-const accessors for mutating - `--gen-mutable` : Generate additional non-const accessors for mutating
FlatBuffers in-place. FlatBuffers in-place.
`--gen-object-api` : Generate an additional object-based API. This API is
more convenient for object construction and mutation than the base API,
at the cost of efficiency (object allocation). Recommended only to be used
if other options are insufficient.
- `--gen-onefile` : Generate single output file (useful for C#) - `--gen-onefile` : Generate single output file (useful for C#)
- `--gen-all`: Generate not just code for the current schema files, but - `--gen-all`: Generate not just code for the current schema files, but
......
...@@ -85,6 +85,27 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc: ...@@ -85,6 +85,27 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
*Note: That we never stored a `mana` value, so it will return the default.* *Note: That we never stored a `mana` value, so it will return the default.*
## Object based API.
FlatBuffers is all about memory efficiency, which is why its base API is written
around using as little as possible of it. This does make the API clumsier
(requiring pre-order construction of all data, and making mutation harder).
For times when efficiency is less important a more convenient object based API
can be used (through `--gen-object-api`) that is able to unpack & pack a
FlatBuffer into objects and standard STL containers, allowing for convenient
construction, access and mutation.
To use:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
auto monsterobj = GetMonster(buffer)->UnPack();
cout << monsterobj->name; // This is now a std::string!
monsterobj->name = "Bob"; // Change the name.
FlatBufferBuilder fbb;
monsterobj->Pack(fbb); // Serialize into new buffer.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Reflection (& Resizing) ## Reflection (& Resizing)
There is experimental support for reflection in FlatBuffers, allowing you to There is experimental support for reflection in FlatBuffers, allowing you to
......
...@@ -1881,6 +1881,9 @@ One way to solve this is to call `ForceDefaults` on a FlatBufferBuilder to ...@@ -1881,6 +1881,9 @@ One way to solve this is to call `ForceDefaults` on a FlatBufferBuilder to
force all fields you set to actually be written. This, of course, increases the force all fields you set to actually be written. This, of course, increases the
size of the buffer somewhat, but this may be acceptable for a mutable buffer. size of the buffer somewhat, but this may be acceptable for a mutable buffer.
If this is not sufficient, other ways of mutating FlatBuffers may be supported
in your language through an object based API (`--gen-object-api`) or reflection.
See the individual language documents for support.
## JSON with FlatBuffers ## JSON with FlatBuffers
......
...@@ -984,6 +984,17 @@ FLATBUFFERS_FINAL_CLASS ...@@ -984,6 +984,17 @@ FLATBUFFERS_FINAL_CLASS
return CreateVector(v.data(), v.size()); return CreateVector(v.data(), v.size());
} }
// vector<bool> may be implemented using a bit-set, so we can't access it as
// an array. Instead, read elements manually.
// Background: https://isocpp.org/blog/2012/11/on-vectorbool
Offset<Vector<uint8_t>> CreateVector(const std::vector<bool> &v) {
StartVector(v.size(), sizeof(uint8_t));
for (auto i = v.size(); i > 0; ) {
PushElement(static_cast<uint8_t>(v[--i]));
}
return Offset<Vector<uint8_t>>(EndVector(v.size()));
}
/// @brief Serialize values returned by a function into a FlatBuffer `vector`. /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
/// This is a convenience function that takes care of iteration for you. /// This is a convenience function that takes care of iteration for you.
/// @tparam T The data type of the `std::vector` elements. /// @tparam T The data type of the `std::vector` elements.
...@@ -1523,6 +1534,12 @@ class Table { ...@@ -1523,6 +1534,12 @@ class Table {
uint8_t data_[1]; uint8_t data_[1];
}; };
// Base class for native objects (FlatBuffer data de-serialized into native
// C++ data structures).
// Contains no functionality, purely documentative.
struct NativeTable {
};
// Helper function to test if a field is present, using any of the field // Helper function to test if a field is present, using any of the field
// enums in the generated code. // enums in the generated code.
// `table` must be a generated table type. Since this is a template parameter, // `table` must be a generated table type. Since this is a template parameter,
......
...@@ -338,7 +338,8 @@ struct IDLOptions { ...@@ -338,7 +338,8 @@ struct IDLOptions {
bool skip_unexpected_fields_in_json; bool skip_unexpected_fields_in_json;
bool generate_name_strings; bool generate_name_strings;
bool escape_proto_identifiers; bool escape_proto_identifiers;
bool generate_object_based_api;
// Possible options for the more general generator below. // Possible options for the more general generator below.
enum Language { kJava, kCSharp, kGo, kMAX }; enum Language { kJava, kCSharp, kGo, kMAX };
...@@ -358,6 +359,7 @@ struct IDLOptions { ...@@ -358,6 +359,7 @@ struct IDLOptions {
skip_unexpected_fields_in_json(false), skip_unexpected_fields_in_json(false),
generate_name_strings(false), generate_name_strings(false),
escape_proto_identifiers(false), escape_proto_identifiers(false),
generate_object_based_api(false),
lang(IDLOptions::kJava) {} lang(IDLOptions::kJava) {}
}; };
......
...@@ -11,8 +11,10 @@ namespace Sample { ...@@ -11,8 +11,10 @@ namespace Sample {
struct Vec3; struct Vec3;
struct Monster; struct Monster;
struct MonsterT;
struct Weapon; struct Weapon;
struct WeaponT;
enum Color { enum Color {
Color_Red = 0, Color_Red = 0,
...@@ -36,6 +38,21 @@ enum Equipment { ...@@ -36,6 +38,21 @@ enum Equipment {
Equipment_MAX = Equipment_Weapon Equipment_MAX = Equipment_Weapon
}; };
struct EquipmentUnion {
Equipment type;
flatbuffers::NativeTable *table;
EquipmentUnion() : type(Equipment_NONE), table(nullptr) {}
EquipmentUnion(const EquipmentUnion &);
EquipmentUnion &operator=(const EquipmentUnion &);
~EquipmentUnion();
static flatbuffers::NativeTable *UnPack(const void *union_obj, Equipment type);
flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb) const;
WeaponT *AsWeapon() { return type == Equipment_Weapon ? reinterpret_cast<WeaponT *>(table) : nullptr; }
};
inline const char **EnumNamesEquipment() { inline const char **EnumNamesEquipment() {
static const char *names[] = { "NONE", "Weapon", nullptr }; static const char *names[] = { "NONE", "Weapon", nullptr };
return names; return names;
...@@ -52,6 +69,8 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { ...@@ -52,6 +69,8 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
float z_; float z_;
public: public:
Vec3() { memset(this, 0, sizeof(Vec3)); }
Vec3(const Vec3 &_o) { memcpy(this, &_o, sizeof(Vec3)); }
Vec3(float _x, float _y, float _z) Vec3(float _x, float _y, float _z)
: x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)) { } : x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)) { }
...@@ -64,6 +83,17 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS { ...@@ -64,6 +83,17 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
}; };
STRUCT_END(Vec3, 12); STRUCT_END(Vec3, 12);
struct MonsterT : public flatbuffers::NativeTable {
std::unique_ptr<Vec3> pos;
int16_t mana;
int16_t hp;
std::string name;
std::vector<uint8_t> inventory;
Color color;
std::vector<std::unique_ptr<WeaponT>> weapons;
EquipmentUnion equipped;
};
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum { enum {
VT_POS = 4, VT_POS = 4,
...@@ -112,6 +142,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { ...@@ -112,6 +142,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyEquipment(verifier, equipped(), equipped_type()) && VerifyEquipment(verifier, equipped(), equipped_type()) &&
verifier.EndTable(); verifier.EndTable();
} }
std::unique_ptr<MonsterT> UnPack() const;
}; };
struct MonsterBuilder { struct MonsterBuilder {
...@@ -170,6 +201,13 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder ...@@ -170,6 +201,13 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector<uint8_t>(*inventory), color, weapons ? 0 : _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons), equipped_type, equipped); return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector<uint8_t>(*inventory), color, weapons ? 0 : _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons), equipped_type, equipped);
} }
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
struct WeaponT : public flatbuffers::NativeTable {
std::string name;
int16_t damage;
};
struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum { enum {
VT_NAME = 4, VT_NAME = 4,
...@@ -186,6 +224,7 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { ...@@ -186,6 +224,7 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<int16_t>(verifier, VT_DAMAGE) && VerifyField<int16_t>(verifier, VT_DAMAGE) &&
verifier.EndTable(); verifier.EndTable();
} }
std::unique_ptr<WeaponT> UnPack() const;
}; };
struct WeaponBuilder { struct WeaponBuilder {
...@@ -216,6 +255,48 @@ inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder & ...@@ -216,6 +255,48 @@ inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &
return CreateWeapon(_fbb, name ? 0 : _fbb.CreateString(name), damage); return CreateWeapon(_fbb, name ? 0 : _fbb.CreateString(name), damage);
} }
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o);
inline std::unique_ptr<MonsterT> Monster::UnPack() const {
auto _o = new MonsterT();
{ auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(new Vec3(*_e)); };
{ auto _e = mana(); _o->mana = _e; };
{ auto _e = hp(); _o->hp = _e; };
{ auto _e = name(); if (_e) _o->name = _e->str(); };
{ auto _e = inventory(); if (_e) { for (size_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 (size_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(_e->Get(_i)->UnPack()); } } };
{ auto _e = equipped_type(); _o->equipped.type = _e; };
{ auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type()); };
return std::unique_ptr<MonsterT>(_o);
}
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
return CreateMonster(_fbb,
_o->pos ? _o->pos.get() : 0,
_o->mana,
_o->hp,
_o->name.size() ? _fbb.CreateString(_o->name) : 0,
_o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0,
_o->color,
_o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get()); }) : 0,
_o->equipped.type,
_o->equipped.Pack(_fbb));
}
inline std::unique_ptr<WeaponT> Weapon::UnPack() const {
auto _o = new WeaponT();
{ auto _e = name(); if (_e) _o->name = _e->str(); };
{ auto _e = damage(); _o->damage = _e; };
return std::unique_ptr<WeaponT>(_o);
}
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o) {
return CreateWeapon(_fbb,
_o->name.size() ? _fbb.CreateString(_o->name) : 0,
_o->damage);
}
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type) { inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type) {
switch (type) { switch (type) {
case Equipment_NONE: return true; case Equipment_NONE: return true;
...@@ -224,6 +305,29 @@ inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_o ...@@ -224,6 +305,29 @@ inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_o
} }
} }
inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type) {
switch (type) {
case Equipment_NONE: return nullptr;
case Equipment_Weapon: return reinterpret_cast<const Weapon *>(union_obj)->UnPack().release();
default: return nullptr;
}
}
inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
switch (type) {
case Equipment_NONE: return 0;
case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast<const WeaponT *>(table)).Union();
default: return 0;
}
}
inline EquipmentUnion::~EquipmentUnion() {
switch (type) {
case Equipment_Weapon: delete reinterpret_cast<WeaponT *>(table); break;
default:;
}
}
inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf); } inline const MyGame::Sample::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf); }
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); } inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
......
...@@ -123,6 +123,7 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) { ...@@ -123,6 +123,7 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
" --gen-onefile Generate single output file for C#.\n" " --gen-onefile Generate single output file for C#.\n"
" --gen-name-strings Generate type name functions for C++.\n" " --gen-name-strings Generate type name functions for C++.\n"
" --escape-proto-ids Disable appending '_' in namespaces names.\n" " --escape-proto-ids Disable appending '_' in namespaces names.\n"
" --gen-object-api Generate an additional object-based API\n"
" --raw-binary Allow binaries without file_indentifier to be read.\n" " --raw-binary Allow binaries without file_indentifier to be read.\n"
" This may crash flatc given a mismatched schema.\n" " This may crash flatc given a mismatched schema.\n"
" --proto Input is a .proto, translate to .fbs.\n" " --proto Input is a .proto, translate to .fbs.\n"
...@@ -179,6 +180,8 @@ int main(int argc, const char *argv[]) { ...@@ -179,6 +180,8 @@ int main(int argc, const char *argv[]) {
opts.mutable_buffer = true; opts.mutable_buffer = true;
} else if(arg == "--gen-name-strings") { } else if(arg == "--gen-name-strings") {
opts.generate_name_strings = true; opts.generate_name_strings = true;
} else if(arg == "--gen-object-api") {
opts.generate_object_based_api = true;
} else if(arg == "--gen-all") { } else if(arg == "--gen-all") {
opts.generate_all = true; opts.generate_all = true;
opts.include_dependence_headers = false; opts.include_dependence_headers = false;
......
...@@ -96,7 +96,11 @@ class CppGenerator : public BaseGenerator { ...@@ -96,7 +96,11 @@ class CppGenerator : public BaseGenerator {
auto &struct_def = **it; auto &struct_def = **it;
if (!struct_def.generated) { if (!struct_def.generated) {
SetNameSpace(struct_def.defined_namespace, &code); SetNameSpace(struct_def.defined_namespace, &code);
code += "struct " + struct_def.name + ";\n\n"; code += "struct " + struct_def.name + ";\n";
if (parser_.opts.generate_object_based_api && !struct_def.fixed) {
code += "struct " + NativeName(struct_def.name) + ";\n";
}
code += "\n";
} }
} }
...@@ -127,6 +131,14 @@ class CppGenerator : public BaseGenerator { ...@@ -127,6 +131,14 @@ class CppGenerator : public BaseGenerator {
GenTable(struct_def, &code); GenTable(struct_def, &code);
} }
} }
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
auto &struct_def = **it;
if (!struct_def.fixed && !struct_def.generated) {
SetNameSpace(struct_def.defined_namespace, &code);
GenTablePost(struct_def, &code);
}
}
// Generate code for union verifiers. // Generate code for union verifiers.
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
...@@ -134,7 +146,7 @@ class CppGenerator : public BaseGenerator { ...@@ -134,7 +146,7 @@ class CppGenerator : public BaseGenerator {
auto &enum_def = **it; auto &enum_def = **it;
if (enum_def.is_union && !enum_def.generated) { if (enum_def.is_union && !enum_def.generated) {
SetNameSpace(enum_def.defined_namespace, &code); SetNameSpace(enum_def.defined_namespace, &code);
GenEnumPost(enum_def, &code); GenUnionPost(enum_def, &code);
} }
} }
...@@ -232,9 +244,10 @@ class CppGenerator : public BaseGenerator { ...@@ -232,9 +244,10 @@ class CppGenerator : public BaseGenerator {
// Return a C++ type from the table in idl.h // Return a C++ type from the table in idl.h
std::string GenTypeBasic(const Type &type, bool user_facing_type) { std::string GenTypeBasic(const Type &type, bool user_facing_type) {
static const char *ctypename[] = { static const char *ctypename[] = {
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) #CTYPE, #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
#CTYPE,
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
#undef FLATBUFFERS_TD #undef FLATBUFFERS_TD
}; };
if (user_facing_type) { if (user_facing_type) {
if (type.enum_def) return WrapInNameSpace(*type.enum_def); if (type.enum_def) return WrapInNameSpace(*type.enum_def);
...@@ -252,9 +265,8 @@ class CppGenerator : public BaseGenerator { ...@@ -252,9 +265,8 @@ class CppGenerator : public BaseGenerator {
case BASE_TYPE_VECTOR: case BASE_TYPE_VECTOR:
return "flatbuffers::Vector<" + return "flatbuffers::Vector<" +
GenTypeWire(type.VectorType(), "", false) + ">"; GenTypeWire(type.VectorType(), "", false) + ">";
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT:
return WrapInNameSpace(*type.struct_def); return WrapInNameSpace(*type.struct_def);
}
case BASE_TYPE_UNION: case BASE_TYPE_UNION:
// fall through // fall through
default: default:
...@@ -283,6 +295,34 @@ class CppGenerator : public BaseGenerator { ...@@ -283,6 +295,34 @@ class CppGenerator : public BaseGenerator {
: "flatbuffers::uoffset_t"; : "flatbuffers::uoffset_t";
} }
// TODO(wvo): make this configurable.
std::string NativeName(const std::string &name) { return name + "T"; }
std::string GenTypeNative(const Type &type, bool invector) {
switch (type.base_type) {
case BASE_TYPE_STRING:
return "std::string";
case BASE_TYPE_VECTOR:
return "std::vector<" + GenTypeNative(type.VectorType(), true) + ">";
case BASE_TYPE_STRUCT:
if (IsStruct(type)) {
if (invector) {
return WrapInNameSpace(*type.struct_def);
} else {
return "std::unique_ptr<" +
WrapInNameSpace(*type.struct_def) + ">";
}
} else {
return "std::unique_ptr<" +
NativeName(WrapInNameSpace(*type.struct_def)) + ">";
}
case BASE_TYPE_UNION:
return type.enum_def->name + "Union";
default:
return GenTypeBasic(type, true);
}
}
// Return a C++ type for any type (scalar/pointer) specifically for // Return a C++ type for any type (scalar/pointer) specifically for
// using a flatbuffer. // using a flatbuffer.
std::string GenTypeGet(const Type &type, std::string GenTypeGet(const Type &type,
...@@ -316,12 +356,37 @@ class CppGenerator : public BaseGenerator { ...@@ -316,12 +356,37 @@ class CppGenerator : public BaseGenerator {
} }
} }
std::string EnumSignature(EnumDef &enum_def) { std::string UnionVerifySignature(EnumDef &enum_def) {
return "inline bool Verify" + enum_def.name + return "inline bool Verify" + enum_def.name +
"(flatbuffers::Verifier &verifier, " + "const void *union_obj, " + "(flatbuffers::Verifier &verifier, const void *union_obj, " +
enum_def.name + " type)"; enum_def.name + " type)";
} }
std::string UnionUnPackSignature(EnumDef &enum_def, bool inclass) {
return (inclass ? "static " : "") +
std::string("flatbuffers::NativeTable *") +
(inclass ? "" : enum_def.name + "Union::") +
"UnPack(const void *union_obj, " + enum_def.name + " type)";
}
std::string UnionPackSignature(EnumDef &enum_def, bool inclass) {
return "flatbuffers::Offset<void> " +
(inclass ? "" : enum_def.name + "Union::") +
"Pack(flatbuffers::FlatBufferBuilder &_fbb) const";
}
std::string TableCreateSignature(StructDef &struct_def) {
return "inline flatbuffers::Offset<" + struct_def.name + "> Create" +
struct_def.name +
"(flatbuffers::FlatBufferBuilder &_fbb, const " +
NativeName(struct_def.name) + " *_o)";
}
std::string TableUnPackSignature(StructDef &struct_def, bool inclass) {
return "std::unique_ptr<" + NativeName(struct_def.name) + "> " +
(inclass ? "" : struct_def.name + "::") + "UnPack() const";
}
// Generate an enum declaration and an enum string lookup table. // Generate an enum declaration and an enum string lookup table.
void GenEnum(EnumDef &enum_def, std::string *code_ptr) { void GenEnum(EnumDef &enum_def, std::string *code_ptr) {
std::string &code = *code_ptr; std::string &code = *code_ptr;
...@@ -363,6 +428,36 @@ class CppGenerator : public BaseGenerator { ...@@ -363,6 +428,36 @@ class CppGenerator : public BaseGenerator {
GenTypeBasic(enum_def.underlying_type, false) + ")\n"; GenTypeBasic(enum_def.underlying_type, false) + ")\n";
code += "\n"; code += "\n";
if (parser_.opts.generate_object_based_api && enum_def.is_union) {
// Generate a union type
code += "struct " + enum_def.name + "Union {\n";
code += " " + enum_def.name + " type;\n\n";
code += " flatbuffers::NativeTable *table;\n";
code += " " + enum_def.name + "Union() : type(";
code += GenEnumVal(enum_def, "NONE", parser_.opts);
code += "), table(nullptr) {}\n";
code += " " + enum_def.name + "Union(const ";
code += enum_def.name + "Union &);\n";
code += " " + enum_def.name + "Union &operator=(const ";
code += enum_def.name + "Union &);\n";
code += " ~" + enum_def.name + "Union();\n\n";
code += " " + UnionUnPackSignature(enum_def, true) + ";\n";
code += " " + UnionPackSignature(enum_def, true) + ";\n\n";
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
if (ev.value) {
auto native_name = NativeName(WrapInNameSpace(*ev.struct_def));
code += " " + native_name + " *As";
code += ev.name + "() { return type == ";
code += GetEnumVal(enum_def, ev, parser_.opts);
code += " ? reinterpret_cast<" + native_name;
code += " *>(table) : nullptr; }\n";
}
}
code += "};\n\n";
}
// Generate a generate string table for enum values. // Generate a generate string table for enum values.
// Problem is, if values are very sparse that could generate really big // Problem is, if values are very sparse that could generate really big
// tables. Ideally in that case we generate a map lookup instead, but for // tables. Ideally in that case we generate a map lookup instead, but for
...@@ -395,31 +490,82 @@ class CppGenerator : public BaseGenerator { ...@@ -395,31 +490,82 @@ class CppGenerator : public BaseGenerator {
} }
if (enum_def.is_union) { if (enum_def.is_union) {
code += EnumSignature(enum_def) + ";\n\n"; code += UnionVerifySignature(enum_def) + ";\n\n";
} }
} }
void GenEnumPost(EnumDef &enum_def, std::string *code_ptr_post) { void GenUnionPost(EnumDef &enum_def, std::string *code_ptr) {
// Generate a verifier function for this union that can be called by the // Generate a verifier function for this union that can be called by the
// table verifier functions. It uses a switch case to select a specific // table verifier functions. It uses a switch case to select a specific
// verifier function to call, this should be safe even if the union type // verifier function to call, this should be safe even if the union type
// has been corrupted, since the verifiers will simply fail when called // has been corrupted, since the verifiers will simply fail when called
// on the wrong type. // on the wrong type.
std::string &code_post = *code_ptr_post; std::string &code = *code_ptr;
code_post += EnumSignature(enum_def) + " {\n switch (type) {\n"; code += UnionVerifySignature(enum_def) + " {\n switch (type) {\n";
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end(); for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) { ++it) {
auto &ev = **it; auto &ev = **it;
code_post += " case " + GetEnumVal(enum_def, ev, parser_.opts); code += " case " + GetEnumVal(enum_def, ev, parser_.opts);
if (!ev.value) { if (!ev.value) {
code_post += ": return true;\n"; // "NONE" enum value. code += ": return true;\n"; // "NONE" enum value.
} else { } else {
code_post += ": return verifier.VerifyTable(reinterpret_cast<const "; code += ": return verifier.VerifyTable(reinterpret_cast<const ";
code_post += WrapInNameSpace(*ev.struct_def); code += WrapInNameSpace(*ev.struct_def);
code_post += " *>(union_obj));\n"; code += " *>(union_obj));\n";
}
}
code += " default: return false;\n }\n}\n\n";
if (parser_.opts.generate_object_based_api) {
// Generate a union pack & unpack function.
code += "inline " + UnionUnPackSignature(enum_def, false);
code += " {\n switch (type) {\n";
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
code += " case " + GetEnumVal(enum_def, ev, parser_.opts);
if (!ev.value) {
code += ": return nullptr;\n"; // "NONE" enum value.
} else {
code += ": return reinterpret_cast<const ";
code += WrapInNameSpace(*ev.struct_def);
code += " *>(union_obj)->UnPack().release();\n";
}
}
code += " default: return nullptr;\n }\n}\n\n";
code += "inline " + UnionPackSignature(enum_def, false);
code += " {\n switch (type) {\n";
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
code += " case " + GetEnumVal(enum_def, ev, parser_.opts);
if (!ev.value) {
code += ": return 0;\n"; // "NONE" enum value.
} else {
code += ": return Create" + ev.struct_def->name;
code += "(_fbb, reinterpret_cast<const ";
code += NativeName(WrapInNameSpace(*ev.struct_def));
code += " *>(table)).Union();\n";
}
}
code += " default: return 0;\n }\n}\n\n";
// Generate a union destructor.
code += "inline " + enum_def.name + "Union::~";
code += enum_def.name + "Union() {\n";
code += " switch (type) {\n";
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
++it) {
auto &ev = **it;
if (ev.value) {
code += " case " + GenEnumVal(enum_def, ev.name, parser_.opts);
code += ": delete reinterpret_cast<";
code += NativeName(WrapInNameSpace(*ev.struct_def));
code += " *>(table); break;\n";
}
} }
code += " default:;\n }\n}\n\n";
} }
code_post += " default: return false;\n }\n}\n\n";
} }
// Generates a value with optionally a cast applied if the field has a // Generates a value with optionally a cast applied if the field has a
...@@ -491,6 +637,24 @@ class CppGenerator : public BaseGenerator { ...@@ -491,6 +637,24 @@ class CppGenerator : public BaseGenerator {
// Generate an accessor struct, builder structs & function for a table. // Generate an accessor struct, builder structs & function for a table.
void GenTable(StructDef &struct_def, std::string *code_ptr) { void GenTable(StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr; std::string &code = *code_ptr;
if (parser_.opts.generate_object_based_api) {
// Generate a C++ object that can hold an unpacked version of this
// table.
code += "struct " + NativeName(struct_def.name);
code += " : public flatbuffers::NativeTable {\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (!field.deprecated && // Deprecated fields won't be accessible.
field.value.type.base_type != BASE_TYPE_UTYPE) {
code += " " + GenTypeNative(field.value.type, false) + " ";
code += field.name + ";\n";
}
}
code += "};\n\n";
}
// Generate an accessor struct, with methods of the form: // Generate an accessor struct, with methods of the form:
// type name() const { return GetField<type>(offset, defaultval); } // type name() const { return GetField<type>(offset, defaultval); }
GenComment(struct_def.doc_comment, code_ptr, nullptr); GenComment(struct_def.doc_comment, code_ptr, nullptr);
...@@ -658,7 +822,13 @@ class CppGenerator : public BaseGenerator { ...@@ -658,7 +822,13 @@ class CppGenerator : public BaseGenerator {
} }
code += prefix + "verifier.EndTable()"; code += prefix + "verifier.EndTable()";
code += ";\n }\n"; code += ";\n }\n";
code += "};\n\n";
if (parser_.opts.generate_object_based_api) {
// Generate the UnPack() pre declaration.
code += " " + TableUnPackSignature(struct_def, true) + ";\n";
}
code += "};\n\n"; // End of table.
// Generate a builder struct, with methods of the form: // Generate a builder struct, with methods of the form:
// void add_name(type name) { fbb_.AddElement<type>(offset, name, default); // void add_name(type name) { fbb_.AddElement<type>(offset, name, default);
...@@ -782,6 +952,163 @@ class CppGenerator : public BaseGenerator { ...@@ -782,6 +952,163 @@ class CppGenerator : public BaseGenerator {
} }
code += ");\n}\n\n"; code += ");\n}\n\n";
} }
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";
}
}
// Generate code for tables that needs to come after the regular definition.
void GenTablePost(StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
if (parser_.opts.generate_object_based_api) {
// Generate the UnPack() method.
code += "inline " + TableUnPackSignature(struct_def, false) + " {\n";
code += " auto _o = new " + NativeName(struct_def.name) + "();\n";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (!field.deprecated) {
auto prefix = " { auto _e = " + field.name + "(); ";
if (!IsScalar(field.value.type.base_type)) prefix += "if (_e) ";
auto deref = "_o->";
auto dest = deref + field.name;
auto assign = prefix + dest + " = ";
auto gen_unpack_val = [&](const Type &type, const std::string &val,
bool invector) {
switch (type.base_type) {
case BASE_TYPE_STRING:
return val + "->str()";
case BASE_TYPE_STRUCT:
if (IsStruct(type)) {
if (invector) {
return "*" + val;
} else {
return "std::unique_ptr<" + type.struct_def->name +
">(new " + type.struct_def->name + "(*" + val + "))";
}
} else {
return val + "->UnPack()";
}
default:
return val;
break;
}
};
switch (field.value.type.base_type) {
case BASE_TYPE_VECTOR:
code += prefix;
code += "{ for (size_t _i = 0; _i < _e->size(); _i++) { ";
code += dest + ".push_back(";
code += gen_unpack_val(field.value.type.VectorType(),
"_e->Get(_i)", true);
code += "); } }";
break;
case BASE_TYPE_UTYPE: {
auto &union_field = **(it + 1);
assert(union_field.value.type.base_type == BASE_TYPE_UNION);
code += prefix + deref + union_field.name + ".type = _e;";
break;
}
case BASE_TYPE_UNION:
code += prefix + dest + ".table = ";
code += field.value.type.enum_def->name;
code += "Union::UnPack(_e, ";
code += field.name + UnionTypeFieldSuffix() + "());";
break;
default:
code += assign + gen_unpack_val(field.value.type, "_e", false);
code += ";";
break;
}
code += " };\n";
}
}
code += " return std::unique_ptr<" + NativeName(struct_def.name);
code += ">(_o);\n}\n\n";
// Generate a CreateX method that works with an unpacked C++ object.
code += TableCreateSignature(struct_def) + " {\n";
auto before_return_statement = code.size();
code += " return Create";
code += struct_def.name + "(_fbb";
bool any_fields = false;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto &field = **it;
if (!field.deprecated) {
any_fields = true;
auto field_name = field.name;
if (field.value.type.base_type == BASE_TYPE_UTYPE) {
field_name = field_name.substr(0, field_name.size() -
strlen(UnionTypeFieldSuffix()));
field_name += ".type";
}
auto accessor = "_o->" + field_name;
auto ptrprefix = accessor + " ? ";
auto stlprefix = accessor + ".size() ? ";
auto postfix = " : 0";
if (field.required &&
(field.value.type.base_type == BASE_TYPE_STRING ||
field.value.type.base_type == BASE_TYPE_VECTOR)) {
stlprefix = "";
postfix = "";
}
code += ",\n ";
switch (field.value.type.base_type) {
case BASE_TYPE_STRING:
code += stlprefix + "_fbb.CreateString(" + accessor + ")";
code += postfix;
break;
case BASE_TYPE_VECTOR: {
auto vector_type = field.value.type.VectorType();
code += stlprefix;
switch (vector_type.base_type) {
case BASE_TYPE_STRING:
code += "_fbb.CreateVectorOfStrings(" + accessor + ")";
break;
case BASE_TYPE_STRUCT:
if (IsStruct(vector_type)) {
code += "_fbb.CreateVectorOfStructs(" + accessor + ")";
} else {
code += "_fbb.CreateVector<flatbuffers::Offset<";
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()); })";
}
break;
default:
code += "_fbb.CreateVector(" + accessor + ")";
break;
}
code += postfix;
break;
}
case BASE_TYPE_UNION:
code += accessor + ".Pack(_fbb)";
break;
case BASE_TYPE_STRUCT:
if (IsStruct(field.value.type)) {
code += ptrprefix + accessor + ".get()" + postfix;
} else {
code += ptrprefix + "Create";
code += field.value.type.struct_def->name;
code += "(_fbb, " + accessor + ".get())" + postfix;
}
break;
default:
code += accessor;
break;
}
}
}
code += ");\n}\n\n";
if (!any_fields) code.insert(before_return_statement, " (void)_o;\n");
}
} }
static void GenPadding(const FieldDef &field, std::string &code, static void GenPadding(const FieldDef &field, std::string &code,
...@@ -838,6 +1165,15 @@ class CppGenerator : public BaseGenerator { ...@@ -838,6 +1165,15 @@ class CppGenerator : public BaseGenerator {
code += "\n public:\n"; code += "\n public:\n";
GenFullyQualifiedNameGetter(struct_def.name, code); GenFullyQualifiedNameGetter(struct_def.name, code);
// Generate a default constructor.
code += " " + struct_def.name + "() { memset(this, 0, sizeof(";
code += struct_def.name + ")); }\n";
// Generate a copy constructor.
code += " " + struct_def.name + "(const " + struct_def.name;
code += " &_o) { memcpy(this, &_o, sizeof(";
code += struct_def.name + ")); }\n";
// Generate a constructor that takes all fields as arguments. // Generate a constructor that takes all fields as arguments.
code += " " + struct_def.name + "("; code += " " + struct_def.name + "(";
for (auto it = struct_def.fields.vec.begin(); for (auto it = struct_def.fields.vec.begin();
...@@ -941,6 +1277,7 @@ class CppGenerator : public BaseGenerator { ...@@ -941,6 +1277,7 @@ class CppGenerator : public BaseGenerator {
cur_name_space_ = ns; cur_name_space_ = ns;
} }
}; };
} // namespace cpp } // namespace cpp
bool GenerateCPP(const Parser &parser, const std::string &path, bool GenerateCPP(const Parser &parser, const std::string &path,
......
...@@ -12,6 +12,6 @@ ...@@ -12,6 +12,6 @@
:: See the License for the specific language governing permissions and :: See the License for the specific language governing permissions and
:: limitations under the License. :: limitations under the License.
..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --no-includes monster_test.fbs monsterdata_test.json ..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs ..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs
..\flatc.exe --binary --schema monster_test.fbs ..\flatc.exe --binary --schema monster_test.fbs
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --no-includes monster_test.fbs monsterdata_test.json ../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs ../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --binary --schema monster_test.fbs ../flatc --binary --schema monster_test.fbs
...@@ -9,6 +9,7 @@ namespace MyGame { ...@@ -9,6 +9,7 @@ namespace MyGame {
namespace Example2 { namespace Example2 {
struct Monster; struct Monster;
struct MonsterT;
} // namespace Example2 } // namespace Example2
...@@ -17,12 +18,15 @@ namespace Example { ...@@ -17,12 +18,15 @@ namespace Example {
struct Test; struct Test;
struct TestSimpleTableWithEnum; struct TestSimpleTableWithEnum;
struct TestSimpleTableWithEnumT;
struct Vec3; struct Vec3;
struct Stat; struct Stat;
struct StatT;
struct Monster; struct Monster;
struct MonsterT;
enum Color { enum Color {
Color_Red = 1, Color_Red = 1,
...@@ -48,6 +52,23 @@ enum Any { ...@@ -48,6 +52,23 @@ enum Any {
Any_MAX = Any_MyGame_Example2_Monster Any_MAX = Any_MyGame_Example2_Monster
}; };
struct AnyUnion {
Any type;
flatbuffers::NativeTable *table;
AnyUnion() : type(Any_NONE), table(nullptr) {}
AnyUnion(const AnyUnion &);
AnyUnion &operator=(const AnyUnion &);
~AnyUnion();
static flatbuffers::NativeTable *UnPack(const void *union_obj, Any type);
flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb) const;
MonsterT *AsMonster() { return type == Any_Monster ? reinterpret_cast<MonsterT *>(table) : nullptr; }
TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() { return type == Any_TestSimpleTableWithEnum ? reinterpret_cast<TestSimpleTableWithEnumT *>(table) : nullptr; }
MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() { return type == Any_MyGame_Example2_Monster ? reinterpret_cast<MyGame::Example2::MonsterT *>(table) : nullptr; }
};
inline const char **EnumNamesAny() { inline const char **EnumNamesAny() {
static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", nullptr }; static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", nullptr };
return names; return names;
...@@ -64,6 +85,8 @@ MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS { ...@@ -64,6 +85,8 @@ MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
int8_t __padding0; int8_t __padding0;
public: public:
Test() { memset(this, 0, sizeof(Test)); }
Test(const Test &_o) { memcpy(this, &_o, sizeof(Test)); }
Test(int16_t _a, int8_t _b) Test(int16_t _a, int8_t _b)
: a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)), __padding0(0) { (void)__padding0; } : a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)), __padding0(0) { (void)__padding0; }
...@@ -87,6 +110,8 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS { ...@@ -87,6 +110,8 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS {
int16_t __padding2; int16_t __padding2;
public: public:
Vec3() { memset(this, 0, sizeof(Vec3)); }
Vec3(const Vec3 &_o) { memcpy(this, &_o, sizeof(Vec3)); }
Vec3(float _x, float _y, float _z, double _test1, Color _test2, const Test &_test3) Vec3(float _x, float _y, float _z, double _test1, Color _test2, const Test &_test3)
: x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)), __padding0(0), test1_(flatbuffers::EndianScalar(_test1)), test2_(flatbuffers::EndianScalar(static_cast<int8_t>(_test2))), __padding1(0), test3_(_test3), __padding2(0) { (void)__padding0; (void)__padding1; (void)__padding2; } : x_(flatbuffers::EndianScalar(_x)), y_(flatbuffers::EndianScalar(_y)), z_(flatbuffers::EndianScalar(_z)), __padding0(0), test1_(flatbuffers::EndianScalar(_test1)), test2_(flatbuffers::EndianScalar(static_cast<int8_t>(_test2))), __padding1(0), test3_(_test3), __padding2(0) { (void)__padding0; (void)__padding1; (void)__padding2; }
...@@ -109,11 +134,15 @@ STRUCT_END(Vec3, 32); ...@@ -109,11 +134,15 @@ STRUCT_END(Vec3, 32);
namespace Example2 { namespace Example2 {
struct MonsterT : public flatbuffers::NativeTable {
};
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool Verify(flatbuffers::Verifier &verifier) const { bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
verifier.EndTable(); verifier.EndTable();
} }
std::unique_ptr<MonsterT> UnPack() const;
}; };
struct MonsterBuilder { struct MonsterBuilder {
...@@ -132,10 +161,16 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder ...@@ -132,10 +161,16 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
return builder_.Finish(); return builder_.Finish();
} }
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
} // namespace Example2 } // namespace Example2
namespace Example { namespace Example {
struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable {
Color color;
};
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum { enum {
VT_COLOR = 4 VT_COLOR = 4
...@@ -147,6 +182,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta ...@@ -147,6 +182,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta
VerifyField<int8_t>(verifier, VT_COLOR) && VerifyField<int8_t>(verifier, VT_COLOR) &&
verifier.EndTable(); verifier.EndTable();
} }
std::unique_ptr<TestSimpleTableWithEnumT> UnPack() const;
}; };
struct TestSimpleTableWithEnumBuilder { struct TestSimpleTableWithEnumBuilder {
...@@ -168,6 +204,14 @@ inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnu ...@@ -168,6 +204,14 @@ inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnu
return builder_.Finish(); return builder_.Finish();
} }
inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o);
struct StatT : public flatbuffers::NativeTable {
std::string id;
int64_t val;
uint16_t count;
};
struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum { enum {
VT_ID = 4, VT_ID = 4,
...@@ -188,6 +232,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { ...@@ -188,6 +232,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<uint16_t>(verifier, VT_COUNT) && VerifyField<uint16_t>(verifier, VT_COUNT) &&
verifier.EndTable(); verifier.EndTable();
} }
std::unique_ptr<StatT> UnPack() const;
}; };
struct StatBuilder { struct StatBuilder {
...@@ -222,6 +267,38 @@ inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb ...@@ -222,6 +267,38 @@ inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb
return CreateStat(_fbb, id ? 0 : _fbb.CreateString(id), val, count); return CreateStat(_fbb, id ? 0 : _fbb.CreateString(id), val, count);
} }
inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o);
struct MonsterT : public flatbuffers::NativeTable {
std::unique_ptr<Vec3> pos;
int16_t mana;
int16_t hp;
std::string name;
std::vector<uint8_t> inventory;
Color color;
AnyUnion test;
std::vector<Test> test4;
std::vector<std::string> testarrayofstring;
std::vector<std::unique_ptr<MonsterT>> testarrayoftables;
std::unique_ptr<MonsterT> enemy;
std::vector<uint8_t> testnestedflatbuffer;
std::unique_ptr<StatT> testempty;
bool testbool;
int32_t testhashs32_fnv1;
uint32_t testhashu32_fnv1;
int64_t testhashs64_fnv1;
uint64_t testhashu64_fnv1;
int32_t testhashs32_fnv1a;
uint32_t testhashu32_fnv1a;
int64_t testhashs64_fnv1a;
uint64_t testhashu64_fnv1a;
std::vector<bool> testarrayofbools;
float testf;
float testf2;
float testf3;
std::vector<std::string> testarrayofstring2;
};
/// an example documentation comment: monster object /// an example documentation comment: monster object
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum { enum {
...@@ -361,6 +438,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { ...@@ -361,6 +438,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
verifier.VerifyVectorOfStrings(testarrayofstring2()) && verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
verifier.EndTable(); verifier.EndTable();
} }
std::unique_ptr<MonsterT> UnPack() const;
}; };
struct MonsterBuilder { struct MonsterBuilder {
...@@ -496,6 +574,117 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder ...@@ -496,6 +574,117 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector<uint8_t>(*inventory), color, test_type, test, test4 ? 0 : _fbb.CreateVector<const Test *>(*test4), testarrayofstring ? 0 : _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring), testarrayoftables ? 0 : _fbb.CreateVector<flatbuffers::Offset<Monster>>(*testarrayoftables), enemy, testnestedflatbuffer ? 0 : _fbb.CreateVector<uint8_t>(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? 0 : _fbb.CreateVector<uint8_t>(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 ? 0 : _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2)); return CreateMonster(_fbb, pos, mana, hp, name ? 0 : _fbb.CreateString(name), inventory ? 0 : _fbb.CreateVector<uint8_t>(*inventory), color, test_type, test, test4 ? 0 : _fbb.CreateVector<const Test *>(*test4), testarrayofstring ? 0 : _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring), testarrayoftables ? 0 : _fbb.CreateVector<flatbuffers::Offset<Monster>>(*testarrayoftables), enemy, testnestedflatbuffer ? 0 : _fbb.CreateVector<uint8_t>(*testnestedflatbuffer), testempty, testbool, testhashs32_fnv1, testhashu32_fnv1, testhashs64_fnv1, testhashu64_fnv1, testhashs32_fnv1a, testhashu32_fnv1a, testhashs64_fnv1a, testhashu64_fnv1a, testarrayofbools ? 0 : _fbb.CreateVector<uint8_t>(*testarrayofbools), testf, testf2, testf3, testarrayofstring2 ? 0 : _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2));
} }
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
} // namespace Example
namespace Example2 {
inline std::unique_ptr<MonsterT> Monster::UnPack() const {
auto _o = new MonsterT();
return std::unique_ptr<MonsterT>(_o);
}
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
(void)_o;
return CreateMonster(_fbb);
}
} // namespace Example2
namespace Example {
inline std::unique_ptr<TestSimpleTableWithEnumT> TestSimpleTableWithEnum::UnPack() const {
auto _o = new TestSimpleTableWithEnumT();
{ auto _e = color(); _o->color = _e; };
return std::unique_ptr<TestSimpleTableWithEnumT>(_o);
}
inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o) {
return CreateTestSimpleTableWithEnum(_fbb,
_o->color);
}
inline std::unique_ptr<StatT> Stat::UnPack() const {
auto _o = new StatT();
{ auto _e = id(); if (_e) _o->id = _e->str(); };
{ auto _e = val(); _o->val = _e; };
{ auto _e = count(); _o->count = _e; };
return std::unique_ptr<StatT>(_o);
}
inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o) {
return CreateStat(_fbb,
_o->id.size() ? _fbb.CreateString(_o->id) : 0,
_o->val,
_o->count);
}
inline std::unique_ptr<MonsterT> Monster::UnPack() const {
auto _o = new MonsterT();
{ auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(new Vec3(*_e)); };
{ auto _e = mana(); _o->mana = _e; };
{ auto _e = hp(); _o->hp = _e; };
{ auto _e = name(); if (_e) _o->name = _e->str(); };
{ auto _e = inventory(); if (_e) { for (size_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 = test4(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->test4.push_back(*_e->Get(_i)); } } };
{ auto _e = testarrayofstring(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring.push_back(_e->Get(_i)->str()); } } };
{ auto _e = testarrayoftables(); if (_e) { for (size_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 = testnestedflatbuffer(); if (_e) { for (size_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 = 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 = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; };
{ auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; };
{ auto _e = testarrayofbools(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i)); } } };
{ auto _e = testf(); _o->testf = _e; };
{ auto _e = testf2(); _o->testf2 = _e; };
{ auto _e = testf3(); _o->testf3 = _e; };
{ auto _e = testarrayofstring2(); if (_e) { for (size_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2.push_back(_e->Get(_i)->str()); } } };
return std::unique_ptr<MonsterT>(_o);
}
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o) {
return CreateMonster(_fbb,
_o->pos ? _o->pos.get() : 0,
_o->mana,
_o->hp,
_fbb.CreateString(_o->name),
_o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0,
_o->color,
_o->test.type,
_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<flatbuffers::Offset<Monster>>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get()); }) : 0,
_o->enemy ? CreateMonster(_fbb, _o->enemy.get()) : 0,
_o->testnestedflatbuffer.size() ? _fbb.CreateVector(_o->testnestedflatbuffer) : 0,
_o->testempty ? CreateStat(_fbb, _o->testempty.get()) : 0,
_o->testbool,
_o->testhashs32_fnv1,
_o->testhashu32_fnv1,
_o->testhashs64_fnv1,
_o->testhashu64_fnv1,
_o->testhashs32_fnv1a,
_o->testhashu32_fnv1a,
_o->testhashs64_fnv1a,
_o->testhashu64_fnv1a,
_o->testarrayofbools.size() ? _fbb.CreateVector(_o->testarrayofbools) : 0,
_o->testf,
_o->testf2,
_o->testf3,
_o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0);
}
inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type) { inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, Any type) {
switch (type) { switch (type) {
case Any_NONE: return true; case Any_NONE: return true;
...@@ -506,6 +695,35 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An ...@@ -506,6 +695,35 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An
} }
} }
inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *union_obj, Any type) {
switch (type) {
case Any_NONE: return nullptr;
case Any_Monster: return reinterpret_cast<const Monster *>(union_obj)->UnPack().release();
case Any_TestSimpleTableWithEnum: return reinterpret_cast<const TestSimpleTableWithEnum *>(union_obj)->UnPack().release();
case Any_MyGame_Example2_Monster: return reinterpret_cast<const MyGame::Example2::Monster *>(union_obj)->UnPack().release();
default: return nullptr;
}
}
inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb) const {
switch (type) {
case Any_NONE: return 0;
case Any_Monster: return CreateMonster(_fbb, reinterpret_cast<const MonsterT *>(table)).Union();
case Any_TestSimpleTableWithEnum: return CreateTestSimpleTableWithEnum(_fbb, reinterpret_cast<const TestSimpleTableWithEnumT *>(table)).Union();
case Any_MyGame_Example2_Monster: return CreateMonster(_fbb, reinterpret_cast<const MyGame::Example2::MonsterT *>(table)).Union();
default: return 0;
}
}
inline AnyUnion::~AnyUnion() {
switch (type) {
case Any_Monster: delete reinterpret_cast<MonsterT *>(table); break;
case Any_TestSimpleTableWithEnum: delete reinterpret_cast<TestSimpleTableWithEnumT *>(table); break;
case Any_MyGame_Example2_Monster: delete reinterpret_cast<MyGame::Example2::MonsterT *>(table); break;
default:;
}
}
inline const MyGame::Example::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Example::Monster>(buf); } inline const MyGame::Example::Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<MyGame::Example::Monster>(buf); }
inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); } inline Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
......
...@@ -33,6 +33,8 @@ MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS { ...@@ -33,6 +33,8 @@ MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS {
int32_t b_; int32_t b_;
public: public:
StructInNestedNS() { memset(this, 0, sizeof(StructInNestedNS)); }
StructInNestedNS(const StructInNestedNS &_o) { memcpy(this, &_o, sizeof(StructInNestedNS)); }
StructInNestedNS(int32_t _a, int32_t _b) StructInNestedNS(int32_t _a, int32_t _b)
: a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)) { } : a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)) { }
......
...@@ -154,4 +154,12 @@ inline flatbuffers::Offset<SecondTableInA> CreateSecondTableInA(flatbuffers::Fla ...@@ -154,4 +154,12 @@ inline flatbuffers::Offset<SecondTableInA> CreateSecondTableInA(flatbuffers::Fla
} // namespace NamespaceA } // namespace NamespaceA
namespace NamespaceC {
} // namespace NamespaceC
namespace NamespaceA {
} // namespace NamespaceA
#endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_ #endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
...@@ -155,7 +155,8 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) { ...@@ -155,7 +155,8 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
} }
// example of accessing a buffer loaded in memory: // example of accessing a buffer loaded in memory:
void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) { void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
bool pooled = true) {
// First, verify the buffers integrity (optional) // First, verify the buffers integrity (optional)
flatbuffers::Verifier verifier(flatbuf, length); flatbuffers::Verifier verifier(flatbuf, length);
...@@ -218,9 +219,11 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) { ...@@ -218,9 +219,11 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) {
TEST_EQ(vecofstrings->Length(), 4U); TEST_EQ(vecofstrings->Length(), 4U);
TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob"); TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred"); TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
// These should have pointer equality because of string pooling. if (pooled) {
TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str()); // These should have pointer equality because of string pooling.
TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str()); TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
}
auto vecofstrings2 = monster->testarrayofstring2(); auto vecofstrings2 = monster->testarrayofstring2();
if (vecofstrings2) { if (vecofstrings2) {
...@@ -305,6 +308,77 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) { ...@@ -305,6 +308,77 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
AccessFlatBufferTest(flatbuf, length); AccessFlatBufferTest(flatbuf, length);
} }
// Unpack a FlatBuffer into objects.
void ObjectFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
// Turn a buffer into C++ objects.
auto monster1 = GetMonster(flatbuf)->UnPack();
// Re-serialize the data.
flatbuffers::FlatBufferBuilder fbb1;
fbb1.Finish(CreateMonster(fbb1, monster1.get()), MonsterIdentifier());
// Unpack again, and re-serialize again.
auto monster2 = GetMonster(fbb1.GetBufferPointer())->UnPack();
flatbuffers::FlatBufferBuilder fbb2;
fbb2.Finish(CreateMonster(fbb2, monster2.get()), MonsterIdentifier());
// Now we've gone full round-trip, the two buffers should match.
auto len1 = fbb1.GetSize();
auto len2 = fbb2.GetSize();
TEST_EQ(len1, len2);
TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(),
len1), 0);
// Test it with the original buffer test to make sure all data survived.
AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
// Test accessing fields, similar to AccessFlatBufferTest above.
TEST_EQ(monster2->hp, 80);
TEST_EQ(monster2->mana, 150); // default
TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
auto &pos = monster2->pos;
TEST_NOTNULL(pos);
TEST_EQ(pos->z(), 3);
TEST_EQ(pos->test3().a(), 10);
TEST_EQ(pos->test3().b(), 20);
auto &inventory = monster2->inventory;
TEST_EQ(inventory.size(), 10UL);
unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (auto it = inventory.begin(); it != inventory.end(); ++it)
TEST_EQ(*it, inv_data[it - inventory.begin()]);
TEST_EQ(monster2->color, Color_Blue);
auto monster3 = monster2->test.AsMonster();
TEST_NOTNULL(monster3);
TEST_EQ_STR(monster3->name.c_str(), "Fred");
auto &vecofstrings = monster2->testarrayofstring;
TEST_EQ(vecofstrings.size(), 4U);
TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
auto &vecofstrings2 = monster2->testarrayofstring2;
TEST_EQ(vecofstrings2.size(), 2U);
TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
auto &vecoftables = monster2->testarrayoftables;
TEST_EQ(vecoftables.size(), 3U);
TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
TEST_EQ(vecoftables[0]->hp, 1000);
TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
auto &tests = monster2->test4;
TEST_EQ(tests[0].a(), 10);
TEST_EQ(tests[0].b(), 20);
TEST_EQ(tests[1].a(), 30);
TEST_EQ(tests[1].b(), 40);
}
// example of parsing text straight into a buffer, and generating // example of parsing text straight into a buffer, and generating
// text back from it: // text back from it:
void ParseAndGenerateTextTest() { void ParseAndGenerateTextTest() {
...@@ -855,7 +929,7 @@ void ValueTest() { ...@@ -855,7 +929,7 @@ void ValueTest() {
// Test conversion functions. // Test conversion functions.
TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }","float"), -1), true); TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }","float"), -1), true);
// Test negative hex constant. // Test negative hex constant.
TEST_EQ(TestValue<int>("{ Y:-0x80 }","int") == -128, true); TEST_EQ(TestValue<int>("{ Y:-0x80 }","int") == -128, true);
} }
...@@ -993,6 +1067,8 @@ int main(int /*argc*/, const char * /*argv*/[]) { ...@@ -993,6 +1067,8 @@ int main(int /*argc*/, const char * /*argv*/[]) {
MutateFlatBuffersTest(flatbuf.get(), rawbuf.length()); MutateFlatBuffersTest(flatbuf.get(), rawbuf.length());
ObjectFlatBuffersTest(flatbuf.get(), rawbuf.length());
#ifndef FLATBUFFERS_NO_FILE_TESTS #ifndef FLATBUFFERS_NO_FILE_TESTS
ParseAndGenerateTextTest(); ParseAndGenerateTextTest();
ReflectionTest(flatbuf.get(), rawbuf.length()); ReflectionTest(flatbuf.get(), rawbuf.length());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment