mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-01 19:58:15 +00:00
Added optional object based API for C++.
Change-Id: If927f3ea3fb3723088fa287f24bdd1ad43c8d1d1 Tested: on Linux.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -40,6 +40,8 @@ flatsamplebinary
|
||||
flatsamplebinary.exe
|
||||
flatsampletext
|
||||
flatsampletext.exe
|
||||
grpctest
|
||||
grpctest.exe
|
||||
snapshot.sh
|
||||
tests/go_gen
|
||||
tests/monsterdata_java_wire.mon
|
||||
|
||||
@@ -6,8 +6,10 @@ project(FlatBuffers)
|
||||
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_INSTALL "Enable the installation of targets." ON)
|
||||
option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library" ON)
|
||||
option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" ON)
|
||||
option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library"
|
||||
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_GRPCTEST "Enable the build of grpctest" OFF)
|
||||
|
||||
@@ -95,7 +97,8 @@ set(FlatBuffers_GRPCTest_SRCS
|
||||
|
||||
if(APPLE)
|
||||
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)
|
||||
if(CYGWIN)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
@@ -118,7 +121,8 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||
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")
|
||||
set(CMAKE_EXE_LINKER_FLAGS
|
||||
"${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
|
||||
@@ -165,7 +169,9 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
|
||||
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
|
||||
add_custom_command(
|
||||
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)
|
||||
endfunction()
|
||||
|
||||
@@ -174,7 +180,8 @@ function(compile_flatbuffers_schema_to_binary SRC_FBS)
|
||||
string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS})
|
||||
add_custom_command(
|
||||
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)
|
||||
endfunction()
|
||||
|
||||
|
||||
@@ -81,6 +81,11 @@ Additional options:
|
||||
- `--gen-mutable` : Generate additional non-const accessors for mutating
|
||||
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-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:
|
||||
|
||||
*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)
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -984,6 +984,17 @@ FLATBUFFERS_FINAL_CLASS
|
||||
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`.
|
||||
/// This is a convenience function that takes care of iteration for you.
|
||||
/// @tparam T The data type of the `std::vector` elements.
|
||||
@@ -1523,6 +1534,12 @@ class Table {
|
||||
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
|
||||
// enums in the generated code.
|
||||
// `table` must be a generated table type. Since this is a template parameter,
|
||||
|
||||
@@ -338,7 +338,8 @@ struct IDLOptions {
|
||||
bool skip_unexpected_fields_in_json;
|
||||
bool generate_name_strings;
|
||||
bool escape_proto_identifiers;
|
||||
|
||||
bool generate_object_based_api;
|
||||
|
||||
// Possible options for the more general generator below.
|
||||
enum Language { kJava, kCSharp, kGo, kMAX };
|
||||
|
||||
@@ -358,6 +359,7 @@ struct IDLOptions {
|
||||
skip_unexpected_fields_in_json(false),
|
||||
generate_name_strings(false),
|
||||
escape_proto_identifiers(false),
|
||||
generate_object_based_api(false),
|
||||
lang(IDLOptions::kJava) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,8 +11,10 @@ namespace Sample {
|
||||
struct Vec3;
|
||||
|
||||
struct Monster;
|
||||
struct MonsterT;
|
||||
|
||||
struct Weapon;
|
||||
struct WeaponT;
|
||||
|
||||
enum Color {
|
||||
Color_Red = 0,
|
||||
@@ -36,6 +38,21 @@ enum Equipment {
|
||||
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() {
|
||||
static const char *names[] = { "NONE", "Weapon", nullptr };
|
||||
return names;
|
||||
@@ -52,6 +69,8 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
float z_;
|
||||
|
||||
public:
|
||||
Vec3() { memset(this, 0, sizeof(Vec3)); }
|
||||
Vec3(const Vec3 &_o) { memcpy(this, &_o, sizeof(Vec3)); }
|
||||
Vec3(float _x, float _y, float _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 {
|
||||
};
|
||||
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 {
|
||||
enum {
|
||||
VT_POS = 4,
|
||||
@@ -112,6 +142,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VerifyEquipment(verifier, equipped(), equipped_type()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
std::unique_ptr<MonsterT> UnPack() const;
|
||||
};
|
||||
|
||||
struct MonsterBuilder {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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 {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
@@ -186,6 +224,7 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VerifyField<int16_t>(verifier, VT_DAMAGE) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
std::unique_ptr<WeaponT> UnPack() const;
|
||||
};
|
||||
|
||||
struct WeaponBuilder {
|
||||
@@ -216,6 +255,48 @@ inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &
|
||||
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) {
|
||||
switch (type) {
|
||||
case Equipment_NONE: return true;
|
||||
@@ -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 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) {
|
||||
" --gen-onefile Generate single output file for C#.\n"
|
||||
" --gen-name-strings Generate type name functions for C++.\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"
|
||||
" This may crash flatc given a mismatched schema.\n"
|
||||
" --proto Input is a .proto, translate to .fbs.\n"
|
||||
@@ -179,6 +180,8 @@ int main(int argc, const char *argv[]) {
|
||||
opts.mutable_buffer = true;
|
||||
} else if(arg == "--gen-name-strings") {
|
||||
opts.generate_name_strings = true;
|
||||
} else if(arg == "--gen-object-api") {
|
||||
opts.generate_object_based_api = true;
|
||||
} else if(arg == "--gen-all") {
|
||||
opts.generate_all = true;
|
||||
opts.include_dependence_headers = false;
|
||||
|
||||
@@ -96,7 +96,11 @@ class CppGenerator : public BaseGenerator {
|
||||
auto &struct_def = **it;
|
||||
if (!struct_def.generated) {
|
||||
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 {
|
||||
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.
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
@@ -134,7 +146,7 @@ class CppGenerator : public BaseGenerator {
|
||||
auto &enum_def = **it;
|
||||
if (enum_def.is_union && !enum_def.generated) {
|
||||
SetNameSpace(enum_def.defined_namespace, &code);
|
||||
GenEnumPost(enum_def, &code);
|
||||
GenUnionPost(enum_def, &code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,9 +244,10 @@ class CppGenerator : public BaseGenerator {
|
||||
// Return a C++ type from the table in idl.h
|
||||
std::string GenTypeBasic(const Type &type, bool user_facing_type) {
|
||||
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)
|
||||
#undef FLATBUFFERS_TD
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
if (user_facing_type) {
|
||||
if (type.enum_def) return WrapInNameSpace(*type.enum_def);
|
||||
@@ -252,9 +265,8 @@ class CppGenerator : public BaseGenerator {
|
||||
case BASE_TYPE_VECTOR:
|
||||
return "flatbuffers::Vector<" +
|
||||
GenTypeWire(type.VectorType(), "", false) + ">";
|
||||
case BASE_TYPE_STRUCT: {
|
||||
case BASE_TYPE_STRUCT:
|
||||
return WrapInNameSpace(*type.struct_def);
|
||||
}
|
||||
case BASE_TYPE_UNION:
|
||||
// fall through
|
||||
default:
|
||||
@@ -283,6 +295,34 @@ class CppGenerator : public BaseGenerator {
|
||||
: "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
|
||||
// using a flatbuffer.
|
||||
std::string GenTypeGet(const Type &type,
|
||||
@@ -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 +
|
||||
"(flatbuffers::Verifier &verifier, " + "const void *union_obj, " +
|
||||
"(flatbuffers::Verifier &verifier, const void *union_obj, " +
|
||||
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.
|
||||
void GenEnum(EnumDef &enum_def, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
@@ -363,6 +428,36 @@ class CppGenerator : public BaseGenerator {
|
||||
GenTypeBasic(enum_def.underlying_type, false) + ")\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.
|
||||
// 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
|
||||
@@ -395,31 +490,82 @@ class CppGenerator : public BaseGenerator {
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
// has been corrupted, since the verifiers will simply fail when called
|
||||
// on the wrong type.
|
||||
std::string &code_post = *code_ptr_post;
|
||||
code_post += EnumSignature(enum_def) + " {\n switch (type) {\n";
|
||||
std::string &code = *code_ptr;
|
||||
code += UnionVerifySignature(enum_def) + " {\n switch (type) {\n";
|
||||
for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
|
||||
++it) {
|
||||
auto &ev = **it;
|
||||
code_post += " case " + GetEnumVal(enum_def, ev, parser_.opts);
|
||||
code += " case " + GetEnumVal(enum_def, ev, parser_.opts);
|
||||
if (!ev.value) {
|
||||
code_post += ": return true;\n"; // "NONE" enum value.
|
||||
code += ": return true;\n"; // "NONE" enum value.
|
||||
} else {
|
||||
code_post += ": return verifier.VerifyTable(reinterpret_cast<const ";
|
||||
code_post += WrapInNameSpace(*ev.struct_def);
|
||||
code_post += " *>(union_obj));\n";
|
||||
code += ": return verifier.VerifyTable(reinterpret_cast<const ";
|
||||
code += WrapInNameSpace(*ev.struct_def);
|
||||
code += " *>(union_obj));\n";
|
||||
}
|
||||
}
|
||||
code_post += " default: return false;\n }\n}\n\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";
|
||||
}
|
||||
}
|
||||
|
||||
// Generates a value with optionally a cast applied if the field has a
|
||||
@@ -491,6 +637,24 @@ class CppGenerator : public BaseGenerator {
|
||||
// Generate an accessor struct, builder structs & function for a table.
|
||||
void GenTable(StructDef &struct_def, std::string *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:
|
||||
// type name() const { return GetField<type>(offset, defaultval); }
|
||||
GenComment(struct_def.doc_comment, code_ptr, nullptr);
|
||||
@@ -658,7 +822,13 @@ class CppGenerator : public BaseGenerator {
|
||||
}
|
||||
code += prefix + "verifier.EndTable()";
|
||||
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:
|
||||
// void add_name(type name) { fbb_.AddElement<type>(offset, name, default);
|
||||
@@ -782,6 +952,163 @@ class CppGenerator : public BaseGenerator {
|
||||
}
|
||||
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,
|
||||
@@ -838,6 +1165,15 @@ class CppGenerator : public BaseGenerator {
|
||||
code += "\n public:\n";
|
||||
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.
|
||||
code += " " + struct_def.name + "(";
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
@@ -941,6 +1277,7 @@ class CppGenerator : public BaseGenerator {
|
||||
cur_name_space_ = ns;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cpp
|
||||
|
||||
bool GenerateCPP(const Parser &parser, const std::string &path,
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
:: See the License for the specific language governing permissions and
|
||||
:: 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 --binary --schema monster_test.fbs
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# 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 --binary --schema monster_test.fbs
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace MyGame {
|
||||
namespace Example2 {
|
||||
|
||||
struct Monster;
|
||||
struct MonsterT;
|
||||
|
||||
} // namespace Example2
|
||||
|
||||
@@ -17,12 +18,15 @@ namespace Example {
|
||||
struct Test;
|
||||
|
||||
struct TestSimpleTableWithEnum;
|
||||
struct TestSimpleTableWithEnumT;
|
||||
|
||||
struct Vec3;
|
||||
|
||||
struct Stat;
|
||||
struct StatT;
|
||||
|
||||
struct Monster;
|
||||
struct MonsterT;
|
||||
|
||||
enum Color {
|
||||
Color_Red = 1,
|
||||
@@ -48,6 +52,23 @@ enum Any {
|
||||
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() {
|
||||
static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", nullptr };
|
||||
return names;
|
||||
@@ -64,6 +85,8 @@ MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
|
||||
int8_t __padding0;
|
||||
|
||||
public:
|
||||
Test() { memset(this, 0, sizeof(Test)); }
|
||||
Test(const Test &_o) { memcpy(this, &_o, sizeof(Test)); }
|
||||
Test(int16_t _a, int8_t _b)
|
||||
: a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)), __padding0(0) { (void)__padding0; }
|
||||
|
||||
@@ -87,6 +110,8 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
int16_t __padding2;
|
||||
|
||||
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)
|
||||
: 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);
|
||||
|
||||
namespace Example2 {
|
||||
|
||||
struct MonsterT : public flatbuffers::NativeTable {
|
||||
};
|
||||
|
||||
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
std::unique_ptr<MonsterT> UnPack() const;
|
||||
};
|
||||
|
||||
struct MonsterBuilder {
|
||||
@@ -132,10 +161,16 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o);
|
||||
|
||||
} // namespace Example2
|
||||
|
||||
namespace Example {
|
||||
|
||||
struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable {
|
||||
Color color;
|
||||
};
|
||||
|
||||
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_COLOR = 4
|
||||
@@ -147,6 +182,7 @@ struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Ta
|
||||
VerifyField<int8_t>(verifier, VT_COLOR) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
std::unique_ptr<TestSimpleTableWithEnumT> UnPack() const;
|
||||
};
|
||||
|
||||
struct TestSimpleTableWithEnumBuilder {
|
||||
@@ -168,6 +204,14 @@ inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnu
|
||||
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 {
|
||||
enum {
|
||||
VT_ID = 4,
|
||||
@@ -188,6 +232,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VerifyField<uint16_t>(verifier, VT_COUNT) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
std::unique_ptr<StatT> UnPack() const;
|
||||
};
|
||||
|
||||
struct StatBuilder {
|
||||
@@ -222,6 +267,38 @@ inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb
|
||||
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
|
||||
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
@@ -361,6 +438,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
std::unique_ptr<MonsterT> UnPack() const;
|
||||
};
|
||||
|
||||
struct MonsterBuilder {
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
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) {
|
||||
switch (type) {
|
||||
case Any_NONE: return true;
|
||||
@@ -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 Monster *GetMutableMonster(void *buf) { return flatbuffers::GetMutableRoot<Monster>(buf); }
|
||||
|
||||
@@ -33,6 +33,8 @@ MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS {
|
||||
int32_t b_;
|
||||
|
||||
public:
|
||||
StructInNestedNS() { memset(this, 0, sizeof(StructInNestedNS)); }
|
||||
StructInNestedNS(const StructInNestedNS &_o) { memcpy(this, &_o, sizeof(StructInNestedNS)); }
|
||||
StructInNestedNS(int32_t _a, int32_t _b)
|
||||
: a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)) { }
|
||||
|
||||
|
||||
@@ -154,4 +154,12 @@ inline flatbuffers::Offset<SecondTableInA> CreateSecondTableInA(flatbuffers::Fla
|
||||
|
||||
} // namespace NamespaceA
|
||||
|
||||
namespace NamespaceC {
|
||||
|
||||
} // namespace NamespaceC
|
||||
|
||||
namespace NamespaceA {
|
||||
|
||||
} // namespace NamespaceA
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
|
||||
|
||||
@@ -155,7 +155,8 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
|
||||
}
|
||||
|
||||
// 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)
|
||||
flatbuffers::Verifier verifier(flatbuf, length);
|
||||
@@ -218,9 +219,11 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) {
|
||||
TEST_EQ(vecofstrings->Length(), 4U);
|
||||
TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
|
||||
TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
|
||||
// These should have pointer equality because of string pooling.
|
||||
TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
|
||||
TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
|
||||
if (pooled) {
|
||||
// These should have pointer equality because of string pooling.
|
||||
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();
|
||||
if (vecofstrings2) {
|
||||
@@ -305,6 +308,77 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t 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
|
||||
// text back from it:
|
||||
void ParseAndGenerateTextTest() {
|
||||
@@ -855,7 +929,7 @@ void ValueTest() {
|
||||
|
||||
// Test conversion functions.
|
||||
TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }","float"), -1), true);
|
||||
|
||||
|
||||
// Test negative hex constant.
|
||||
TEST_EQ(TestValue<int>("{ Y:-0x80 }","int") == -128, true);
|
||||
}
|
||||
@@ -993,6 +1067,8 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
|
||||
MutateFlatBuffersTest(flatbuf.get(), rawbuf.length());
|
||||
|
||||
ObjectFlatBuffersTest(flatbuf.get(), rawbuf.length());
|
||||
|
||||
#ifndef FLATBUFFERS_NO_FILE_TESTS
|
||||
ParseAndGenerateTextTest();
|
||||
ReflectionTest(flatbuf.get(), rawbuf.length());
|
||||
|
||||
Reference in New Issue
Block a user