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) {}
};
......
/*
* Copyright 2017 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_MINIREFLECT_H_
#define FLATBUFFERS_MINIREFLECT_H_
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/util.h"
namespace flatbuffers {
// Utilities that can be used with the "mini reflection" tables present
// in generated code with --reflect-types (only types) or --reflect-names
// (also names).
// This allows basic reflection functionality such as pretty-printing
// that does not require the use of the schema parser or loading of binary
// schema files at runtime (reflection.h).
// For any of the functions below that take `const TypeTable *`, you pass
// `FooTypeTable()` if the type of the root is `Foo`.
// First, a generic iterator that can be used by multiple algorithms.
struct IterationVisitor {
// These mark the scope of a table or struct.
virtual void StartSequence() {}
virtual void EndSequence() {}
// Called for each field regardless of wether it is present or not.
// If not present, val == nullptr. set_idx is the index of all set fields.
virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/,
ElementaryType /*type*/, bool /*is_vector*/,
const TypeTable * /*type_table*/, const char * /*name*/,
const uint8_t * /*val*/) {}
// Called for a value that is actually present, after a field, or as part
// of a vector.
virtual void UType(uint8_t, const char *) {}
virtual void Bool(bool) {}
virtual void Char(int8_t, const char *) {}
virtual void UChar(uint8_t, const char *) {}
virtual void Short(int16_t, const char *) {}
virtual void UShort(uint16_t, const char *) {}
virtual void Int(int32_t, const char *) {}
virtual void UInt(uint32_t, const char *) {}
virtual void Long(int64_t) {}
virtual void ULong(uint64_t) {}
virtual void Float(float) {}
virtual void Double(double) {}
virtual void String(const String *) {}
virtual void Unknown(const uint8_t *) {} // From a future version.
// These mark the scope of a vector.
virtual void StartVector() {}
virtual void EndVector() {}
virtual void Element(size_t /*i*/, ElementaryType /*type*/,
const TypeTable * /*type_table*/,
const uint8_t * /*val*/)
{}
virtual ~IterationVisitor() {}
};
inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
switch (type) {
case ET_UTYPE:
case ET_BOOL:
case ET_CHAR:
case ET_UCHAR:
return 1;
case ET_SHORT:
case ET_USHORT:
return 2;
case ET_INT:
case ET_UINT:
case ET_FLOAT:
case ET_STRING:
return 4;
case ET_LONG:
case ET_ULONG:
case ET_DOUBLE:
return 8;
case ET_SEQUENCE:
switch (type_table->st) {
case ST_TABLE:
case ST_UNION:
return 4;
case ST_STRUCT:
return type_table->values[type_table->num_elems];
default:
assert(false);
return 1;
}
default:
assert(false);
return 1;
}
}
inline int32_t LookupEnum(int32_t enum_val, const int32_t *values,
size_t num_values) {
if (!values) return enum_val;
for (size_t i = 0; i < num_values; i++) {
if (enum_val == values[i]) return static_cast<int32_t>(i);
}
return -1; // Unknown enum value.
}
template<typename T> const char *EnumName(T tval, const TypeTable *type_table) {
if (!type_table || !type_table->names) return nullptr;
auto i = LookupEnum(static_cast<int32_t>(tval), type_table->values,
type_table->num_elems);
if (i >= 0 && i < static_cast<int32_t>(type_table->num_elems)) {
return type_table->names[i];
}
return nullptr;
}
void IterateObject(const uint8_t *obj, const TypeTable *type_table,
IterationVisitor *visitor);
inline void IterateValue(ElementaryType type, const uint8_t *val,
const TypeTable *type_table,
const uint8_t *prev_val,
soffset_t vector_index,
IterationVisitor *visitor) {
switch (type) {
case ET_UTYPE: {
auto tval = *reinterpret_cast<const uint8_t *>(val);
visitor->UType(tval, EnumName(tval, type_table));
break;
}
case ET_BOOL: {
visitor->Bool(*reinterpret_cast<const uint8_t *>(val) != 0);
break;
}
case ET_CHAR: {
auto tval = *reinterpret_cast<const int8_t *>(val);
visitor->Char(tval, EnumName(tval, type_table));
break;
}
case ET_UCHAR: {
auto tval = *reinterpret_cast<const uint8_t *>(val);
visitor->UChar(tval, EnumName(tval, type_table));
break;
}
case ET_SHORT: {
auto tval = *reinterpret_cast<const int16_t *>(val);
visitor->Short(tval, EnumName(tval, type_table));
break;
}
case ET_USHORT: {
auto tval = *reinterpret_cast<const uint16_t *>(val);
visitor->UShort(tval, EnumName(tval, type_table));
break;
}
case ET_INT: {
auto tval = *reinterpret_cast<const int32_t *>(val);
visitor->Int(tval, EnumName(tval, type_table));
break;
}
case ET_UINT: {
auto tval = *reinterpret_cast<const uint32_t *>(val);
visitor->UInt(tval, EnumName(tval, type_table));
break;
}
case ET_LONG: {
visitor->Long(*reinterpret_cast<const int64_t *>(val));
break;
}
case ET_ULONG: {
visitor->ULong(*reinterpret_cast<const uint64_t *>(val));
break;
}
case ET_FLOAT: {
visitor->Float(*reinterpret_cast<const float *>(val));
break;
}
case ET_DOUBLE: {
visitor->Double(*reinterpret_cast<const double *>(val));
break;
}
case ET_STRING: {
val += ReadScalar<uoffset_t>(val);
visitor->String(reinterpret_cast<const String *>(val));
break;
}
case ET_SEQUENCE: {
switch (type_table->st) {
case ST_TABLE:
val += ReadScalar<uoffset_t>(val);
IterateObject(val, type_table, visitor);
break;
case ST_STRUCT:
IterateObject(val, type_table, visitor);
break;
case ST_UNION: {
val += ReadScalar<uoffset_t>(val);
assert(prev_val);
auto union_type = *prev_val; // Always a uint8_t.
if (vector_index >= 0) {
auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val);
union_type = type_vec->Get(static_cast<uoffset_t>(vector_index));
}
auto type_code_idx = LookupEnum(union_type, type_table->values,
type_table->num_elems);
if (type_code_idx >= 0 && type_code_idx <
static_cast<int32_t>(type_table->num_elems)) {
auto type_code = type_table->type_codes[type_code_idx];
switch (type_code.base_type) {
case ET_SEQUENCE: {
auto ref = type_table->type_refs[type_code.sequence_ref]();
IterateObject(val, ref, visitor);
break;
}
case ET_STRING:
visitor->String(reinterpret_cast<const String *>(val));
break;
default:
visitor->Unknown(val);
}
} else {
visitor->Unknown(val);
}
break;
}
case ST_ENUM:
assert(false);
break;
}
break;
}
default: {
visitor->Unknown(val);
break;
}
}
}
inline void IterateObject(const uint8_t *obj, const TypeTable *type_table,
IterationVisitor *visitor) {
visitor->StartSequence();
const uint8_t *prev_val = nullptr;
size_t set_idx = 0;
for (size_t i = 0; i < type_table->num_elems; i++) {
auto type_code = type_table->type_codes[i];
auto type = static_cast<ElementaryType>(type_code.base_type);
auto is_vector = type_code.is_vector != 0;
auto ref_idx = type_code.sequence_ref;
const TypeTable *ref = nullptr;
if (ref_idx >= 0) {
ref = type_table->type_refs[ref_idx]();
}
auto name = type_table->names ? type_table->names[i] : nullptr;
const uint8_t *val = nullptr;
if (type_table->st == ST_TABLE) {
val = reinterpret_cast<const Table *>(obj)->GetAddressOf(
FieldIndexToOffset(static_cast<voffset_t>(i)));
} else {
val = obj + type_table->values[i];
}
visitor->Field(i, set_idx, type, is_vector, ref, name, val);
if (val) {
set_idx++;
if (is_vector) {
val += ReadScalar<uoffset_t>(val);
auto vec = reinterpret_cast<const Vector<uint8_t> *>(val);
visitor->StartVector();
auto elem_ptr = vec->Data();
for (size_t j = 0; j < vec->size(); j++) {
visitor->Element(j, type, ref, elem_ptr);
IterateValue(type, elem_ptr, ref, prev_val, static_cast<soffset_t>(j),
visitor);
elem_ptr += InlineSize(type, ref);
}
visitor->EndVector();
} else {
IterateValue(type, val, ref, prev_val, -1, visitor);
}
}
prev_val = val;
}
visitor->EndSequence();
}
inline void IterateFlatBuffer(const uint8_t *buffer,
const TypeTable *type_table,
IterationVisitor *callback) {
IterateObject(GetRoot<uint8_t>(buffer), type_table, callback);
}
// Outputting a Flatbuffer to a string. Tries to conform as close to JSON /
// the output generated by idl_gen_text.cpp.
struct ToStringVisitor : public IterationVisitor {
std::string s;
void StartSequence() { s += "{ "; }
void EndSequence() { s += " }"; }
void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
bool /*is_vector*/, const TypeTable * /*type_table*/,
const char *name, const uint8_t *val) {
if (!val) return;
if (set_idx) s += ", ";
if (name) { s += name; s += ": "; }
}
template<typename T> void Named(T x, const char *name) {
if (name) s+= name;
else s+= NumToString(x);
}
void UType(uint8_t x, const char *name) { Named(x, name); }
void Bool(bool x) { s+= x ? "true" : "false"; }
void Char(int8_t x, const char *name) { Named(x, name); }
void UChar(uint8_t x, const char *name) { Named(x, name); }
void Short(int16_t x, const char *name) { Named(x, name); }
void UShort(uint16_t x, const char *name) { Named(x, name); }
void Int(int32_t x, const char *name) { Named(x, name); }
void UInt(uint32_t x, const char *name) { Named(x, name); }
void Long(int64_t x) { s+= NumToString(x); }
void ULong(uint64_t x) { s+= NumToString(x); }
void Float(float x) { s+= NumToString(x); }
void Double(double x) { s+= NumToString(x); }
void String(const struct String *str) {
EscapeString(str->c_str(), str->size(), &s, true);
}
void Unknown(const uint8_t *) { s += "(?)"; }
void StartVector() { s += "[ "; }
void EndVector() { s += " ]"; }
void Element(size_t i, ElementaryType /*type*/,
const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
if (i) s += ", ";
}
};
inline std::string FlatBufferToString(const uint8_t *buffer,
const TypeTable *type_table) {
ToStringVisitor tostring_visitor;
IterateFlatBuffer(buffer, type_table, &tostring_visitor);
return tostring_visitor.s;
}
} // namespace flatbuffers
#endif // FLATBUFFERS_MINIREFLECT_H_
......@@ -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