Added support for mini-reflection tables.

Change-Id: I83453d074685fa57bbf1c7c87b1d9392ce972085
Tested: on Linux.
parent 21a81219
......@@ -34,6 +34,7 @@ set(FlatBuffers_Library_SRCS
include/flatbuffers/stl_emulation.h
include/flatbuffers/flexbuffers.h
include/flatbuffers/registry.h
include/flatbuffers/minireflect.h
src/code_generators.cpp
src/idl_parser.cpp
src/idl_gen_text.cpp
......@@ -200,6 +201,7 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
--gen-object-api -o "${SRC_FBS_DIR}"
--cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs
--reflect-names
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
DEPENDS flatc)
......
......@@ -125,5 +125,8 @@ Additional options:
- `--keep-prefix` : Keep original prefix of schema include statement.
- `--reflect-types` : Add minimal type reflection to code generation.
- `--reflect-names` : Add minimal type/name reflection.
NOTE: short-form options for generators are deprecated, use the long form
whenever possible.
......@@ -231,6 +231,30 @@ schema, as well as a lot of helper functions.
And example of usage, for the time being, can be found in
`test.cpp/ReflectionTest()`.
## Mini Reflection
A more limited form of reflection is available for direct inclusion in
generated code, which doesn't any (binary) schema access at all. It was designed
to keep the overhead of reflection as low as possible (on the order of 2-6
bytes per field added to your executable), but doesn't contain all the
information the (binary) schema contains.
You add this information to your generated code by specifying `--reflect-types`
(or instead `--reflect-names` if you also want field / enum names).
You can now use this information, for example to print a FlatBuffer to text:
auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable());
`MonsterTypeTable()` is declared in the generated code for each type. The
string produced is very similar to the JSON produced by the `Parser` based
text generator.
You'll need `flatbuffers/minireflect.h` for this functionality. In there is also
a convenient visitor/iterator so you can write your own output / functionality
based on the mini reflection tables without having to know the FlatBuffers or
reflection encoding.
## Storing maps / dictionaries in a FlatBuffer
FlatBuffers doesn't support maps natively, but there is support to
......
......@@ -2066,6 +2066,73 @@ inline int LookupEnum(const char **names, const char *name) {
#error Unknown compiler, please define structure alignment macros
#endif
// Minimal reflection via code generation.
// Besides full-fat reflection (see reflection.h) and parsing/printing by
// loading schemas (see idl.h), we can also have code generation for mimimal
// reflection data which allows pretty-printing and other uses without needing
// a schema or a parser.
// Generate code with --reflect-types (types only) or --reflect-names (names
// also) to enable.
// See minireflect.h for utilities using this functionality.
// These types are organized slightly differently as the ones in idl.h.
enum SequenceType { ST_TABLE, ST_STRUCT, ST_UNION, ST_ENUM };
// Scalars have the same order as in idl.h
#define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \
ET(ET_UTYPE) \
ET(ET_BOOL) \
ET(ET_CHAR) \
ET(ET_UCHAR) \
ET(ET_SHORT) \
ET(ET_USHORT) \
ET(ET_INT) \
ET(ET_UINT) \
ET(ET_LONG) \
ET(ET_ULONG) \
ET(ET_FLOAT) \
ET(ET_DOUBLE) \
ET(ET_STRING) \
ET(ET_SEQUENCE) // See SequenceType.
enum ElementaryType {
#define FLATBUFFERS_ET(E) E,
FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET)
#undef FLATBUFFERS_ET
};
inline const char **ElementaryTypeNames() {
static const char *names[] = {
#define FLATBUFFERS_ET(E) #E,
FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET)
#undef FLATBUFFERS_ET
};
return names;
}
// Basic type info cost just 16bits per field!
struct TypeCode {
uint16_t base_type : 4; // ElementaryType
uint16_t is_vector : 1;
int16_t sequence_ref : 11; // Index into type_refs below, or -1 for none.
};
static_assert(sizeof(TypeCode) == 2, "TypeCode");
struct TypeTable;
// Signature of the static method present in each type.
typedef TypeTable *(*TypeFunction)();
struct TypeTable {
SequenceType st;
size_t num_elems; // of each of the arrays below.
const TypeCode *type_codes;
const TypeFunction *type_refs;
const int32_t *values; // Only set for non-consecutive enum/union or structs.
const char **names; // Only set if compiled with --reflect-names.
};
// String which identifies the current version of FlatBuffers.
// flatbuffer_version_string is used by Google developers to identify which
// applications uploaded to Google Play are using this library. This allows
......
......@@ -396,6 +396,10 @@ struct IDLOptions {
Language lang;
enum MiniReflect { kNone, kTypes, kTypesAndNames };
MiniReflect mini_reflect;
// The corresponding language bit will be set if a language is included
// for code generation.
unsigned long lang_to_generate;
......@@ -426,6 +430,7 @@ struct IDLOptions {
reexport_ts_modules(true),
protobuf_ascii_alike(false),
lang(IDLOptions::kJava),
mini_reflect(IDLOptions::kNone),
lang_to_generate(0) {}
};
......
This diff is collapsed.
......@@ -605,6 +605,120 @@ inline void EquipmentUnion::Reset() {
type = Equipment_NONE;
}
flatbuffers::TypeTable *Vec3TypeTable();
flatbuffers::TypeTable *MonsterTypeTable();
flatbuffers::TypeTable *WeaponTypeTable();
flatbuffers::TypeTable *ColorTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_CHAR, 0, 0 },
{ flatbuffers::ET_CHAR, 0, 0 },
{ flatbuffers::ET_CHAR, 0, 0 }
};
static flatbuffers::TypeFunction type_refs[] = {
ColorTypeTable
};
static const char *names[] = {
"Red",
"Green",
"Blue"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_ENUM, 3, type_codes, type_refs, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *EquipmentTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 0, -1 },
{ flatbuffers::ET_SEQUENCE, 0, 0 }
};
static flatbuffers::TypeFunction type_refs[] = {
WeaponTypeTable
};
static const char *names[] = {
"NONE",
"Weapon"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_UNION, 2, type_codes, type_refs, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *Vec3TypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_FLOAT, 0, -1 }
};
static const int32_t values[] = { 0, 4, 8, 12 };
static const char *names[] = {
"x",
"y",
"z"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_STRUCT, 3, type_codes, nullptr, values, names
};
return &tt;
}
flatbuffers::TypeTable *MonsterTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 0, 0 },
{ flatbuffers::ET_SHORT, 0, -1 },
{ flatbuffers::ET_SHORT, 0, -1 },
{ flatbuffers::ET_STRING, 0, -1 },
{ flatbuffers::ET_BOOL, 0, -1 },
{ flatbuffers::ET_UCHAR, 1, -1 },
{ flatbuffers::ET_CHAR, 0, 1 },
{ flatbuffers::ET_SEQUENCE, 1, 2 },
{ flatbuffers::ET_UTYPE, 0, 3 },
{ flatbuffers::ET_SEQUENCE, 0, 3 }
};
static flatbuffers::TypeFunction type_refs[] = {
Vec3TypeTable,
ColorTypeTable,
WeaponTypeTable,
EquipmentTypeTable
};
static const char *names[] = {
"pos",
"mana",
"hp",
"name",
"friendly",
"inventory",
"color",
"weapons",
"equipped_type",
"equipped"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 10, type_codes, type_refs, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *WeaponTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_STRING, 0, -1 },
{ flatbuffers::ET_SHORT, 0, -1 }
};
static const char *names[] = {
"name",
"damage"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 2, type_codes, nullptr, nullptr, names
};
return &tt;
}
inline const MyGame::Sample::Monster *GetMonster(const void *buf) {
return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf);
}
......
......@@ -111,6 +111,8 @@ std::string FlatCompiler::GetUsageString(const char* program_name) const {
" --keep-prefix Keep original prefix of schema include statement.\n"
" --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
" --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
" --reflect-types Add minimal type reflection to code generation.\n"
" --reflect-names Add minimal type/name reflection.\n"
"FILEs may be schemas (must end in .fbs), or JSON files (conforming to preceding\n"
"schema). FILEs after the -- must be binary flatbuffer format files.\n"
"Output files are named using the base file name of the input,\n"
......@@ -243,6 +245,10 @@ int FlatCompiler::Compile(int argc, const char** argv) {
opts.skip_flatbuffers_import = true;
} else if(arg == "--no-ts-reexport") {
opts.reexport_ts_modules = false;
} else if(arg == "--reflect-types") {
opts.mini_reflect = IDLOptions::kTypes;
} else if(arg == "--reflect-names") {
opts.mini_reflect = IDLOptions::kTypesAndNames;
} else {
for (size_t i = 0; i < params_.num_generators; ++i) {
if (arg == params_.generators[i].generator_opt_long ||
......
......@@ -169,6 +169,37 @@ class CppGenerator : public BaseGenerator {
}
}
// Generate code for mini reflection.
if (parser_.opts.mini_reflect != IDLOptions::kNone) {
// To break cyclic dependencies, first pre-declare all tables/structs.
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
if (!struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
GenMiniReflectPre(&struct_def);
}
}
// Then the unions/enums that may refer to them.
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
const auto &enum_def = **it;
if (!enum_def.generated) {
SetNameSpace(enum_def.defined_namespace);
GenMiniReflect(nullptr, &enum_def);
}
}
// Then the full tables/structs.
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
const auto &struct_def = **it;
if (!struct_def.generated) {
SetNameSpace(struct_def.defined_namespace);
GenMiniReflect(&struct_def, nullptr);
}
}
}
// Generate convenient global helper functions:
if (parser_.root_struct_def_) {
auto &struct_def = *parser_.root_struct_def_;
......@@ -559,6 +590,140 @@ class CppGenerator : public BaseGenerator {
(inclass ? " = nullptr" : "") + ") const";
}
void GenMiniReflectPre(const StructDef *struct_def) {
code_.SetValue("NAME", struct_def->name);
code_ += "flatbuffers::TypeTable *{{NAME}}TypeTable();";
code_ += "";
}
void GenMiniReflect(const StructDef *struct_def,
const EnumDef *enum_def) {
code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
code_.SetValue("SEQ_TYPE", struct_def
? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
: (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
auto num_fields = struct_def
? struct_def->fields.vec.size()
: enum_def->vals.vec.size();
code_.SetValue("NUM_FIELDS", NumToString(num_fields));
std::vector<std::string> names;
std::vector<Type> types;
bool consecutive_enum_from_zero = true;
if (struct_def) {
for (auto it = struct_def->fields.vec.begin();
it != struct_def->fields.vec.end(); ++it) {
const auto &field = **it;
names.push_back(field.name);
types.push_back(field.value.type);
}
} else {
for (auto it = enum_def->vals.vec.begin(); it != enum_def->vals.vec.end();
++it) {
const auto &ev = **it;
names.push_back(ev.name);
types.push_back(enum_def->is_union ? ev.union_type
: Type(enum_def->underlying_type));
if (static_cast<int64_t>(it - enum_def->vals.vec.begin()) != ev.value) {
consecutive_enum_from_zero = false;
}
}
}
std::string ts;
std::vector<std::string> type_refs;
for (auto it = types.begin(); it != types.end(); ++it) {
auto &type = *it;
if (!ts.empty()) ts += ",\n ";
auto is_vector = type.base_type == BASE_TYPE_VECTOR;
auto bt = is_vector ? type.element : type.base_type;
auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
? bt - BASE_TYPE_UTYPE + ET_UTYPE
: ET_SEQUENCE;
int ref_idx = -1;
std::string ref_name = type.struct_def
? WrapInNameSpace(*type.struct_def)
: type.enum_def
? WrapInNameSpace(*type.enum_def)
: "";
if (!ref_name.empty()) {
auto rit = type_refs.begin();
for (; rit != type_refs.end(); ++rit) {
if (*rit == ref_name) {
ref_idx = static_cast<int>(rit - type_refs.begin());
break;
}
}
if (rit == type_refs.end()) {
ref_idx = static_cast<int>(type_refs.size());
type_refs.push_back(ref_name);
}
}
ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
NumToString(is_vector) + ", " + NumToString(ref_idx) + " }";
}
std::string rs;
for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
if (!rs.empty()) rs += ",\n ";
rs += *it + "TypeTable";
}
std::string ns;
for (auto it = names.begin(); it != names.end(); ++it) {
if (!ns.empty()) ns += ",\n ";
ns += "\"" + *it + "\"";
}
std::string vs;
if (enum_def && !consecutive_enum_from_zero) {
for (auto it = enum_def->vals.vec.begin(); it != enum_def->vals.vec.end();
++it) {
const auto &ev = **it;
if (!vs.empty()) vs += ", ";
vs += NumToString(ev.value);
}
} else if (struct_def && struct_def->fixed) {
for (auto it = struct_def->fields.vec.begin();
it != struct_def->fields.vec.end(); ++it) {
const auto &field = **it;
vs += NumToString(field.value.offset);
vs += ", ";
}
vs += NumToString(struct_def->bytesize);
}
code_.SetValue("TYPES", ts);
code_.SetValue("REFS", rs);
code_.SetValue("NAMES", ns);
code_.SetValue("VALUES", vs);
code_ += "flatbuffers::TypeTable *{{NAME}}TypeTable() {";
if (num_fields) {
code_ += " static flatbuffers::TypeCode type_codes[] = {";
code_ += " {{TYPES}}";
code_ += " };";
}
if (!type_refs.empty()) {
code_ += " static flatbuffers::TypeFunction type_refs[] = {";
code_ += " {{REFS}}";
code_ += " };";
}
if (!vs.empty()) {
code_ += " static const int32_t values[] = { {{VALUES}} };";
}
auto has_names = num_fields &&
parser_.opts.mini_reflect == IDLOptions::kTypesAndNames;
if (has_names) {
code_ += " static const char *names[] = {";
code_ += " {{NAMES}}";
code_ += " };";
}
code_ += " static flatbuffers::TypeTable tt = {";
code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
(num_fields ? "type_codes, " : "nullptr, ") +
(!type_refs.empty() ? "type_refs, ": "nullptr, " ) +
(!vs.empty() ? "values, " : "nullptr, ") +
(has_names ? "names" : "nullptr");
code_ += " };";
code_ += " return &tt;";
code_ += "}";
code_ += "";
}
// Generate an enum declaration,
// an enum string lookup table,
// and an enum array of values
......
......@@ -15,9 +15,9 @@
set buildtype=Release
if "%1"=="-b" set buildtype=%2
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
..\%buildtype%\flatc.exe --cpp --js --ts --php --gen-mutable --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
..\%buildtype%\flatc.exe --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
..\%buildtype%\flatc.exe -b --schema --bfbs-comments -I include_test monster_test.fbs
..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs
cd ../samples
......
......@@ -14,11 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --cpp --js --ts --php --gen-mutable --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
../flatc -b --schema --bfbs-comments -I include_test monster_test.fbs
../flatc --jsonschema --schema -I include_test monster_test.fbs
cd ../samples
../flatc --cpp --gen-mutable --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
../flatc --cpp --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
cd ../reflection
No preview for this file type
......@@ -1899,6 +1899,318 @@ inline void AnyUnion::Reset() {
type = Any_NONE;
}
} // namespace Example
flatbuffers::TypeTable *InParentNamespaceTypeTable();
namespace Example2 {
flatbuffers::TypeTable *MonsterTypeTable();
} // namespace Example2
namespace Example {
flatbuffers::TypeTable *TestTypeTable();
flatbuffers::TypeTable *TestSimpleTableWithEnumTypeTable();
flatbuffers::TypeTable *Vec3TypeTable();
flatbuffers::TypeTable *AbilityTypeTable();
flatbuffers::TypeTable *StatTypeTable();
flatbuffers::TypeTable *MonsterTypeTable();
flatbuffers::TypeTable *TypeAliasesTypeTable();
flatbuffers::TypeTable *ColorTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_CHAR, 0, 0 },
{ flatbuffers::ET_CHAR, 0, 0 },
{ flatbuffers::ET_CHAR, 0, 0 }
};
static flatbuffers::TypeFunction type_refs[] = {
ColorTypeTable
};
static const int32_t values[] = { 1, 2, 8 };
static const char *names[] = {
"Red",
"Green",
"Blue"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_ENUM, 3, type_codes, type_refs, values, names
};
return &tt;
}
flatbuffers::TypeTable *AnyTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 0, -1 },
{ flatbuffers::ET_SEQUENCE, 0, 0 },
{ flatbuffers::ET_SEQUENCE, 0, 1 },
{ flatbuffers::ET_SEQUENCE, 0, 2 }
};
static flatbuffers::TypeFunction type_refs[] = {
MonsterTypeTable,
TestSimpleTableWithEnumTypeTable,
MyGame::Example2::MonsterTypeTable
};
static const char *names[] = {
"NONE",
"Monster",
"TestSimpleTableWithEnum",
"MyGame_Example2_Monster"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_UNION, 4, type_codes, type_refs, nullptr, names
};
return &tt;
}
} // namespace Example
flatbuffers::TypeTable *InParentNamespaceTypeTable() {
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 0, nullptr, nullptr, nullptr, nullptr
};
return &tt;
}
namespace Example2 {
flatbuffers::TypeTable *MonsterTypeTable() {
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 0, nullptr, nullptr, nullptr, nullptr
};
return &tt;
}
} // namespace Example2
namespace Example {
flatbuffers::TypeTable *TestTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SHORT, 0, -1 },
{ flatbuffers::ET_CHAR, 0, -1 }
};
static const int32_t values[] = { 0, 2, 4 };
static const char *names[] = {
"a",
"b"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
};
return &tt;
}
flatbuffers::TypeTable *TestSimpleTableWithEnumTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_CHAR, 0, 0 }
};
static flatbuffers::TypeFunction type_refs[] = {
ColorTypeTable
};
static const char *names[] = {
"color"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *Vec3TypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_DOUBLE, 0, -1 },
{ flatbuffers::ET_CHAR, 0, 0 },
{ flatbuffers::ET_SEQUENCE, 0, 1 }
};
static flatbuffers::TypeFunction type_refs[] = {
ColorTypeTable,
TestTypeTable
};
static const int32_t values[] = { 0, 4, 8, 16, 24, 26, 32 };
static const char *names[] = {
"x",
"y",
"z",
"test1",
"test2",
"test3"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_STRUCT, 6, type_codes, type_refs, values, names
};
return &tt;
}
flatbuffers::TypeTable *AbilityTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_UINT, 0, -1 },
{ flatbuffers::ET_UINT, 0, -1 }
};
static const int32_t values[] = { 0, 4, 8 };
static const char *names[] = {
"id",
"distance"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
};
return &tt;
}
flatbuffers::TypeTable *StatTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_STRING, 0, -1 },
{ flatbuffers::ET_LONG, 0, -1 },
{ flatbuffers::ET_USHORT, 0, -1 }
};
static const char *names[] = {
"id",
"val",
"count"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 3, type_codes, nullptr, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *MonsterTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 0, 0 },
{ flatbuffers::ET_SHORT, 0, -1 },
{ flatbuffers::ET_SHORT, 0, -1 },
{ flatbuffers::ET_STRING, 0, -1 },
{ flatbuffers::ET_BOOL, 0, -1 },
{ flatbuffers::ET_UCHAR, 1, -1 },
{ flatbuffers::ET_CHAR, 0, 1 },
{ flatbuffers::ET_UTYPE, 0, 2 },
{ flatbuffers::ET_SEQUENCE, 0, 2 },
{ flatbuffers::ET_SEQUENCE, 1, 3 },
{ flatbuffers::ET_STRING, 1, -1 },
{ flatbuffers::ET_SEQUENCE, 1, 4 },
{ flatbuffers::ET_SEQUENCE, 0, 4 },
{ flatbuffers::ET_UCHAR, 1, -1 },
{ flatbuffers::ET_SEQUENCE, 0, 5 },
{ flatbuffers::ET_BOOL, 0, -1 },
{ flatbuffers::ET_INT, 0, -1 },
{ flatbuffers::ET_UINT, 0, -1 },
{ flatbuffers::ET_LONG, 0, -1 },
{ flatbuffers::ET_ULONG, 0, -1 },
{ flatbuffers::ET_INT, 0, -1 },
{ flatbuffers::ET_UINT, 0, -1 },
{ flatbuffers::ET_LONG, 0, -1 },
{ flatbuffers::ET_ULONG, 0, -1 },
{ flatbuffers::ET_BOOL, 1, -1 },
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_STRING, 1, -1 },
{ flatbuffers::ET_SEQUENCE, 1, 6 },
{ flatbuffers::ET_UCHAR, 1, -1 },
{ flatbuffers::ET_SEQUENCE, 1, 3 },
{ flatbuffers::ET_LONG, 1, -1 },
{ flatbuffers::ET_DOUBLE, 1, -1 },
{ flatbuffers::ET_SEQUENCE, 0, 7 }
};
static flatbuffers::TypeFunction type_refs[] = {
Vec3TypeTable,
ColorTypeTable,
AnyTypeTable,
TestTypeTable,
MonsterTypeTable,
StatTypeTable,
AbilityTypeTable,
MyGame::InParentNamespaceTypeTable
};
static const char *names[] = {
"pos",
"mana",
"hp",
"name",
"friendly",
"inventory",
"color",
"test_type",
"test",
"test4",
"testarrayofstring",
"testarrayoftables",
"enemy",
"testnestedflatbuffer",
"testempty",
"testbool",
"testhashs32_fnv1",
"testhashu32_fnv1",
"testhashs64_fnv1",
"testhashu64_fnv1",
"testhashs32_fnv1a",
"testhashu32_fnv1a",
"testhashs64_fnv1a",
"testhashu64_fnv1a",
"testarrayofbools",
"testf",
"testf2",
"testf3",
"testarrayofstring2",
"testarrayofsortedstruct",
"flex",
"test5",
"vector_of_longs",
"vector_of_doubles",
"parent_namespace_test"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 35, type_codes, type_refs, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *TypeAliasesTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_CHAR, 0, -1 },
{ flatbuffers::ET_UCHAR, 0, -1 },
{ flatbuffers::ET_SHORT, 0, -1 },
{ flatbuffers::ET_USHORT, 0, -1 },
{ flatbuffers::ET_INT, 0, -1 },
{ flatbuffers::ET_UINT, 0, -1 },
{ flatbuffers::ET_LONG, 0, -1 },
{ flatbuffers::ET_ULONG, 0, -1 },
{ flatbuffers::ET_FLOAT, 0, -1 },
{ flatbuffers::ET_DOUBLE, 0, -1 },
{ flatbuffers::ET_CHAR, 1, -1 },
{ flatbuffers::ET_DOUBLE, 1, -1 }
};
static const char *names[] = {
"i8",
"u8",
"i16",
"u16",
"i32",
"u32",
"i64",
"u64",
"f32",
"f64",
"v8",
"vf64"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 12, type_codes, nullptr, nullptr, names
};
return &tt;
}
inline const MyGame::Example::Monster *GetMonster(const void *buf) {
return flatbuffers::GetRoot<MyGame::Example::Monster>(buf);
}
......
......@@ -119,6 +119,59 @@ inline flatbuffers::Offset<TableInNestedNS> CreateTableInNestedNS(
return builder_.Finish();
}
flatbuffers::TypeTable *TableInNestedNSTypeTable();
flatbuffers::TypeTable *StructInNestedNSTypeTable();
flatbuffers::TypeTable *EnumInNestedNSTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_CHAR, 0, 0 },
{ flatbuffers::ET_CHAR, 0, 0 },
{ flatbuffers::ET_CHAR, 0, 0 }
};
static flatbuffers::TypeFunction type_refs[] = {
EnumInNestedNSTypeTable
};
static const char *names[] = {
"A",
"B",
"C"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_ENUM, 3, type_codes, type_refs, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *TableInNestedNSTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_INT, 0, -1 }
};
static const char *names[] = {
"foo"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *StructInNestedNSTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_INT, 0, -1 },
{ flatbuffers::ET_INT, 0, -1 }
};
static const int32_t values[] = { 0, 4, 8 };
static const char *names[] = {
"a",
"b"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
};
return &tt;
}
} // namespace NamespaceB
} // namespace NamespaceA
......
......@@ -212,6 +212,85 @@ namespace NamespaceC {
namespace NamespaceA {
flatbuffers::TypeTable *TableInFirstNSTypeTable();
} // namespace NamespaceA
namespace NamespaceC {
flatbuffers::TypeTable *TableInCTypeTable();
} // namespace NamespaceC
namespace NamespaceA {
flatbuffers::TypeTable *SecondTableInATypeTable();
flatbuffers::TypeTable *TableInFirstNSTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 0, 0 },
{ flatbuffers::ET_CHAR, 0, 1 },
{ flatbuffers::ET_SEQUENCE, 0, 2 }
};
static flatbuffers::TypeFunction type_refs[] = {
NamespaceA::NamespaceB::TableInNestedNSTypeTable,
NamespaceA::NamespaceB::EnumInNestedNSTypeTable,
NamespaceA::NamespaceB::StructInNestedNSTypeTable
};
static const char *names[] = {
"foo_table",
"foo_enum",
"foo_struct"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 3, type_codes, type_refs, nullptr, names
};
return &tt;
}
} // namespace NamespaceA
namespace NamespaceC {
flatbuffers::TypeTable *TableInCTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 0, 0 },
{ flatbuffers::ET_SEQUENCE, 0, 1 }
};
static flatbuffers::TypeFunction type_refs[] = {
NamespaceA::TableInFirstNSTypeTable,
NamespaceA::SecondTableInATypeTable
};
static const char *names[] = {
"refer_to_a1",
"refer_to_a2"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, names
};
return &tt;
}
} // namespace NamespaceC
namespace NamespaceA {
flatbuffers::TypeTable *SecondTableInATypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 0, 0 }
};
static flatbuffers::TypeFunction type_refs[] = {
NamespaceC::TableInCTypeTable
};
static const char *names[] = {
"refer_to_c"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, names
};
return &tt;
}
} // namespace NamespaceA
#endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
......@@ -18,6 +18,7 @@
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
#include "flatbuffers/registry.h"
#include "flatbuffers/minireflect.h"
#include "monster_test_generated.h"
#include "namespace_test/namespace_test1_generated.h"
......@@ -46,8 +47,9 @@ int testing_fails = 0;
void TestFail(const char *expval, const char *val, const char *exp,
const char *file, int line) {
TEST_OUTPUT_LINE("TEST FAILED: %s:%d, %s (%s) != %s", file, line,
exp, expval, val);
TEST_OUTPUT_LINE("VALUE: \"%s\"", expval);
TEST_OUTPUT_LINE("EXPECTED: \"%s\"", val);
TEST_OUTPUT_LINE("TEST FAILED: %s:%d, %s", file, line, exp);
assert(0);
testing_fails++;
}
......@@ -561,11 +563,7 @@ void ParseAndGenerateTextTest() {
std::string jsongen;
auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
TEST_EQ(result, true);
if (jsongen != jsonfile) {
TEST_OUTPUT_LINE("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
TEST_NOTNULL(NULL);
}
TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
// We can also do the above using the convenient Registry that knows about
// a set of file_identifiers mapped to schemas.
......@@ -772,6 +770,34 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
fbb.GetBufferPointer(), fbb.GetSize()), true);
}
void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable());
TEST_EQ_STR(s.c_str(),
"{ "
"pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
"{ a: 10, b: 20 } }, "
"hp: 80, "
"name: \"MyMonster\", "
"inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
"test_type: Monster, "
"test: { name: \"Fred\" }, "
"test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
"testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
"testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" }, "
"{ name: \"Wilma\" } ], "
// TODO(wvo): should really print this nested buffer correctly.
"testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, 0, "
"4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
"101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
"testarrayofstring2: [ \"jane\", \"mary\" ], "
"testarrayofsortedstruct: [ { id: 1, distance: 10 }, "
"{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
"{ id: 4, distance: 40 } ], "
"flex: [ 210, 4, 5, 2 ], "
"test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ] "
"}");
}
// Parse a .proto schema, output as .fbs
void ParseProtoTest() {
// load the .proto and the golden file from disk
......@@ -800,11 +826,7 @@ void ParseProtoTest() {
// Ensure generated file is parsable.
flatbuffers::Parser parser2;
TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
if (fbs != goldenfile) {
TEST_OUTPUT_LINE("%s----------------\n%s", fbs.c_str(), goldenfile.c_str());
TEST_NOTNULL(NULL);
}
TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
}
template<typename T> void CompareTableFieldValue(flatbuffers::Table *table,
......@@ -1248,10 +1270,9 @@ void UnicodeTest() {
parser.opts.indent_step = -1;
auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
TEST_EQ(result, true);
TEST_EQ(jsongen,
std::string(
TEST_EQ_STR(jsongen.c_str(),
"{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
"\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}"));
"\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
}
void UnicodeTestAllowNonUTF8() {
......@@ -1265,10 +1286,9 @@ void UnicodeTestAllowNonUTF8() {
parser.opts.indent_step = -1;
auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
TEST_EQ(result, true);
TEST_EQ(jsongen,
std::string(
TEST_EQ_STR(jsongen.c_str(),
"{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
"\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}"));
"\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
}
void UnicodeTestGenerateTextFailsOnNonUTF8() {
......@@ -1300,7 +1320,7 @@ void UnicodeSurrogatesTest() {
parser.builder_.GetBufferPointer());
auto string = root->GetPointer<flatbuffers::String *>(
flatbuffers::FieldIndexToOffset(0));
TEST_EQ(strcmp(string->c_str(), "\xF0\x9F\x92\xA9"), 0);
TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
}
void UnicodeInvalidSurrogatesTest() {
......@@ -1437,7 +1457,7 @@ void UnknownFieldsTest() {
parser.opts.indent_step = -1;
auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
TEST_EQ(result, true);
TEST_EQ(jsongen == "{str: \"test\",i: 10}", true);
TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
}
void ParseUnionTest() {
......@@ -1548,6 +1568,14 @@ void UnionVectorTest() {
auto repacked_movie = GetMovie(fbb.GetBufferPointer());
TestMovie(repacked_movie);
auto s = flatbuffers::FlatBufferToString(fbb.GetBufferPointer(),
MovieTypeTable());
TEST_EQ_STR(s.c_str(),
"{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
"characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
"characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
"{ books_read: 2 }, \"Other\", \"Unused\" ] }");
}
void ConformTest() {
......@@ -1774,6 +1802,8 @@ int main(int /*argc*/, const char * /*argv*/[]) {
ObjectFlatBuffersTest(flatbuf.data());
MiniReflectFlatBuffersTest(flatbuf.data());
SizePrefixedTest();
#ifndef FLATBUFFERS_NO_FILE_TESTS
......
......@@ -600,6 +600,107 @@ inline void CharacterUnion::Reset() {
type = Character_NONE;
}
flatbuffers::TypeTable *AttackerTypeTable();
flatbuffers::TypeTable *RapunzelTypeTable();
flatbuffers::TypeTable *BookReaderTypeTable();
flatbuffers::TypeTable *MovieTypeTable();
flatbuffers::TypeTable *CharacterTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 0, -1 },
{ flatbuffers::ET_SEQUENCE, 0, 0 },
{ flatbuffers::ET_SEQUENCE, 0, 1 },
{ flatbuffers::ET_SEQUENCE, 0, 2 },
{ flatbuffers::ET_SEQUENCE, 0, 2 },
{ flatbuffers::ET_STRING, 0, -1 },
{ flatbuffers::ET_STRING, 0, -1 }
};
static flatbuffers::TypeFunction type_refs[] = {
AttackerTypeTable,
RapunzelTypeTable,
BookReaderTypeTable
};
static const char *names[] = {
"NONE",
"MuLan",
"Rapunzel",
"Belle",
"BookFan",
"Other",
"Unused"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_UNION, 7, type_codes, type_refs, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *AttackerTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_INT, 0, -1 }
};
static const char *names[] = {
"sword_attack_damage"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, names
};
return &tt;
}
flatbuffers::TypeTable *RapunzelTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_INT, 0, -1 }
};
static const int32_t values[] = { 0, 4 };
static const char *names[] = {
"hair_length"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_STRUCT, 1, type_codes, nullptr, values, names
};
return &tt;
}
flatbuffers::TypeTable *BookReaderTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_INT, 0, -1 }
};
static const int32_t values[] = { 0, 4 };
static const char *names[] = {
"books_read"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_STRUCT, 1, type_codes, nullptr, values, names
};
return &tt;
}
flatbuffers::TypeTable *MovieTypeTable() {
static flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_UTYPE, 0, 0 },
{ flatbuffers::ET_SEQUENCE, 0, 0 },
{ flatbuffers::ET_UTYPE, 1, 0 },
{ flatbuffers::ET_SEQUENCE, 1, 0 }
};
static flatbuffers::TypeFunction type_refs[] = {
CharacterTypeTable
};
static const char *names[] = {
"main_character_type",
"main_character",
"characters_type",
"characters"
};
static flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 4, type_codes, type_refs, nullptr, names
};
return &tt;
}
inline const Movie *GetMovie(const void *buf) {
return flatbuffers::GetRoot<Movie>(buf);
}
......
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