summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rwxr-xr-xdocs/source/Compiler.md3
-rwxr-xr-xdocs/source/CppUsage.md24
-rw-r--r--include/flatbuffers/flatbuffers.h67
-rw-r--r--include/flatbuffers/idl.h5
-rw-r--r--include/flatbuffers/minireflect.h352
-rw-r--r--samples/monster_generated.h114
-rw-r--r--src/flatc.cpp6
-rw-r--r--src/idl_gen_cpp.cpp165
-rw-r--r--tests/generate_code.bat6
-rwxr-xr-xtests/generate_code.sh8
-rw-r--r--tests/monster_test.bfbsbin4480 -> 5400 bytes
-rw-r--r--tests/monster_test_generated.h312
-rw-r--r--tests/namespace_test/namespace_test1_generated.h53
-rw-r--r--tests/namespace_test/namespace_test2_generated.h79
-rw-r--r--tests/test.cpp70
-rw-r--r--tests/union_vector/union_vector_generated.h101
17 files changed, 1340 insertions, 27 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e8353252..e9ba5288 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md
index 80f81e8f..aaa274c3 100755
--- a/docs/source/Compiler.md
+++ b/docs/source/Compiler.md
@@ -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.
diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md
index cff3071b..2ded6110 100755
--- a/docs/source/CppUsage.md
+++ b/docs/source/CppUsage.md
@@ -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
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index b7bad539..3b56ba49 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -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
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index a6f2c4d2..3ba5e0d5 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -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) {}
};
diff --git a/include/flatbuffers/minireflect.h b/include/flatbuffers/minireflect.h
new file mode 100644
index 00000000..cb3f4038
--- /dev/null
+++ b/include/flatbuffers/minireflect.h
@@ -0,0 +1,352 @@
+/*
+ * 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_
diff --git a/samples/monster_generated.h b/samples/monster_generated.h
index 523a136b..0560d46a 100644
--- a/samples/monster_generated.h
+++ b/samples/monster_generated.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);
}
diff --git a/src/flatc.cpp b/src/flatc.cpp
index 405cc6d5..abc948c2 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -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 ||
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index 29f93d3c..93941b80 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -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
diff --git a/tests/generate_code.bat b/tests/generate_code.bat
index f594542b..1437c7c2 100644
--- a/tests/generate_code.bat
+++ b/tests/generate_code.bat
@@ -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
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
index 31f4dee5..4b6db29b 100755
--- a/tests/generate_code.sh
+++ b/tests/generate_code.sh
@@ -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
diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs
index 15d39986..843e308c 100644
--- a/tests/monster_test.bfbs
+++ b/tests/monster_test.bfbs
Binary files differ
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
index 3423a108..f02a4dbd 100644
--- a/tests/monster_test_generated.h
+++ b/tests/monster_test_generated.h
@@ -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);
}
diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h
index 6fc6df7a..0beea4cc 100644
--- a/tests/namespace_test/namespace_test1_generated.h
+++ b/tests/namespace_test/namespace_test1_generated.h
@@ -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
diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h
index 7e650f43..a88d40ea 100644
--- a/tests/namespace_test/namespace_test2_generated.h
+++ b/tests/namespace_test/namespace_test2_generated.h
@@ -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_
diff --git a/tests/test.cpp b/tests/test.cpp
index 63a73c73..a698b128 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -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
diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h
index a21cb000..3975ec8e 100644
--- a/tests/union_vector/union_vector_generated.h
+++ b/tests/union_vector/union_vector_generated.h
@@ -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);
}