Compare commits

...

4 Commits

Author SHA1 Message Date
rboullard 5b7f602ea8 bigfoot_ref 2026-07-31 02:43:43 +02:00
rboullard a06c41f2c7 Simplify templates 2026-07-29 23:11:48 +02:00
rboullard 4f6ad45b0e templated type 2026-07-29 22:57:58 +02:00
rboullard 81e5f093f9 vector-type 2026-07-29 14:38:13 +02:00
21 changed files with 967 additions and 182 deletions
+8
View File
@@ -238,8 +238,13 @@ set(FlatBuffers_Tests_SRCS
tests/util_test.cpp tests/util_test.cpp
tests/vector_table_naked_ptr_test.h tests/vector_table_naked_ptr_test.h
tests/vector_table_naked_ptr_test.cpp tests/vector_table_naked_ptr_test.cpp
tests/test_vector_type.h
tests/cpp_vector_type_test.h
tests/cpp_vector_type_test.cpp
tests/native_type_test_impl.h tests/native_type_test_impl.h
tests/native_type_test_impl.cpp tests/native_type_test_impl.cpp
tests/bigfoot_ref_test_impl.h
tests/bigfoot_ref_test_impl.cpp
tests/alignment_test.h tests/alignment_test.h
tests/alignment_test.cpp tests/alignment_test.cpp
tests/64bit/offset64_test.h tests/64bit/offset64_test.h
@@ -548,17 +553,20 @@ if(FLATBUFFERS_BUILD_TESTS)
# The flattest target needs some generated files # The flattest target needs some generated files
SET(FLATC_OPT_COMP --cpp --gen-compare --gen-mutable --gen-object-api --reflect-names) SET(FLATC_OPT_COMP --cpp --gen-compare --gen-mutable --gen-object-api --reflect-names)
SET(FLATC_OPT_SCOPED_ENUMS ${FLATC_OPT_COMP};--scoped-enums) SET(FLATC_OPT_SCOPED_ENUMS ${FLATC_OPT_COMP};--scoped-enums)
SET(FLATC_OPT_CPP_VECTOR_TYPE ${FLATC_OPT_COMP};--cpp-include;test_vector_type.h;--cpp-vector-type;::flatbuffers::tests::CustomVector)
compile_schema_for_test(tests/alignment_test.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/alignment_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test_fbsh(tests/default_vectors_strings_test.fbs "${FLATC_OPT_COMP}") compile_schema_for_test_fbsh(tests/default_vectors_strings_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/arrays_test.fbs "${FLATC_OPT_SCOPED_ENUMS}") compile_schema_for_test(tests/arrays_test.fbs "${FLATC_OPT_SCOPED_ENUMS}")
compile_schema_for_test(tests/native_inline_table_test.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/native_inline_table_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/native_type_test.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/native_type_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/bigfoot_ref_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/key_field/key_field_sample.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/key_field/key_field_sample.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/64bit/test_64bit.fbs "${FLATC_OPT_COMP};--bfbs-gen-embed") compile_schema_for_test(tests/64bit/test_64bit.fbs "${FLATC_OPT_COMP};--bfbs-gen-embed")
compile_schema_for_test(tests/64bit/evolution/v1.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/64bit/evolution/v1.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/64bit/evolution/v2.fbs "${FLATC_OPT_COMP}") compile_schema_for_test(tests/64bit/evolution/v2.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/union_underlying_type_test.fbs "${FLATC_OPT_SCOPED_ENUMS}") compile_schema_for_test(tests/union_underlying_type_test.fbs "${FLATC_OPT_SCOPED_ENUMS}")
compile_schema_for_test(tests/cpp_vector_type.fbs "${FLATC_OPT_CPP_VECTOR_TYPE}")
if(FLATBUFFERS_CODE_SANITIZE) if(FLATBUFFERS_CODE_SANITIZE)
add_fsanitize_to_target(flattests ${FLATBUFFERS_CODE_SANITIZE}) add_fsanitize_to_target(flattests ${FLATBUFFERS_CODE_SANITIZE})
+6
View File
@@ -168,6 +168,12 @@ list of `FILES...`.
std::string from Flatbuffers, but (char* + length). This allows efficient std::string from Flatbuffers, but (char* + length). This allows efficient
construction of custom string types, including zero-copy construction. construction of custom string types, including zero-copy construction.
- `--cpp-vector-type T` : Set object API vector type (default std::vector).
T must be a template taking a single element type argument and support
resize(), reserve(), size(), data(), operator[], emplace_back() and
begin()/end(), matching the subset of std::vector's interface generated
code relies on.
- `--no-cpp-direct-copy` : Don't generate direct copy methods for C++ - `--no-cpp-direct-copy` : Don't generate direct copy methods for C++
object-based API. object-based API.
+57
View File
@@ -242,6 +242,42 @@ provide the following functions to aide in the serialization process:
} }
``` ```
- `bigfoot_ref_wrapper("type")` (on a struct) together with `bigfoot_ref("type")`
(on a field of that struct type): Bigfoot-specific sugar for a
UUID-addressed reference to another native type. `bigfoot_ref_wrapper`
marks a struct as a reference-wrapper template (e.g. Bigfoot's
`HardReference`/`SoftReference`); `bigfoot_ref` on a field of that type
names the referenced native type, e.g. `bigfoot_ref: "::Bigfoot::AssetA"`
on a `HardReference`-typed field with `bigfoot_ref_wrapper:
"::Bigfoot::HardReference"` produces the field's native type
`::Bigfoot::HardReference<::Bigfoot::AssetA>` (auto-deriving a
`native_type_pack_name` of `HardReferenceAssetA`, same short-name
convention as `native_type_pack_name`). Unlike a hand-written
`native_type`, `bigfoot_ref` also emits, directly into the generated
header:
- a forward declaration of the referenced type (so the referencing
schema's generated header never needs that type's real definition -
only the wrapper template's constructor and a `GetUUID()` accessor
are used, and those don't require the referenced type to be
complete), and
- `inline` `Pack<Name>`/`UnPack<Name>` definitions for it (so no
hand-written implementation is required anywhere).
```cpp
struct HardReference (bigfoot_ref_wrapper: "::Bigfoot::HardReference") {
uuid: UUID;
}
table AssetB {
ref_a: HardReference (bigfoot_ref: "::Bigfoot::AssetA");
}
```
is enough on its own - no forward declaration of `::Bigfoot::AssetA` and
no `flatbuffers::Pack/UnPackHardReferenceAssetA` implementation need to
be written by hand. `bigfoot_ref` is only valid on fields whose type is a
struct (or vector of structs) that declares `bigfoot_ref_wrapper`.
- `native_type("type")` (on a table): Tables can also be represented with - `native_type("type")` (on a table): Tables can also be represented with
native types. For example, the following schema: native types. For example, the following schema:
@@ -337,6 +373,27 @@ constructor in the following format: `custom_str_class(const char *, size_t)`.
Please note that the character array is not guaranteed to be NULL terminated, Please note that the character array is not guaranteed to be NULL terminated,
you should always use the provided size to determine end of string. you should always use the provided size to determine end of string.
## Using different vector type
By default the object tree's vector fields are built out of `std::vector`,
but you can influence this either globally (using the `--cpp-vector-type`
argument to `flatc`) or per field using the `cpp_vector_type` attribute, to
use any other vector-like template type (e.g. `eastl::vector`).
The type must be a template taking a single element type argument
(`my_vector<T>`), and must support the following member functions:
`resize()`, `reserve()`, `size()`, `data()`, `operator[]`, `emplace_back()`,
and `begin()`/`end()`. This matches the subset of `std::vector`'s interface
that generated code relies on.
Note that unlike `std::vector<bool>`, the custom vector type must not use a
bit-packed specialization for `bool` elements, since generated code accesses
`data()` as a contiguous `bool` array.
As with custom string types, the header defining the custom vector type is
not automatically included; use `--cpp-include` to add the necessary
`#include`.
## Reflection (& Resizing) ## Reflection (& Resizing)
There is experimental support for reflection in FlatBuffers, allowing you to There is experimental support for reflection in FlatBuffers, allowing you to
+13
View File
@@ -142,6 +142,19 @@
#define FLATBUFFERS_VERSION_MAJOR 25 #define FLATBUFFERS_VERSION_MAJOR 25
#define FLATBUFFERS_VERSION_MINOR 12 #define FLATBUFFERS_VERSION_MINOR 12
#define FLATBUFFERS_VERSION_REVISION 19 #define FLATBUFFERS_VERSION_REVISION 19
// Identifies this header as Bigfoot's fork of flatbuffers, and versions the
// fork's own generated-code-affecting changes independently of the upstream
// FLATBUFFERS_VERSION_* triplet above (which just tracks the upstream
// version this fork is based on, and would still match an unforked, stock
// flatbuffers install of the same version). Generated headers assert on
// this - see GenFlatbuffersVersionCheck() in idl_gen_cpp.cpp - so building
// Bigfoot-generated code against stock flatbuffers, or a differently
// versioned Bigfoot fork, fails to compile immediately instead of silently
// miscompiling. Bump this whenever a change here affects what generated
// code assumes about this header (e.g. adding bigfoot_ref/bigfoot_ref_wrapper).
#define FLATBUFFERS_BIGFOOT_VERSION 1
#define FLATBUFFERS_STRING_EXPAND(X) #X #define FLATBUFFERS_STRING_EXPAND(X) #X
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X) #define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
namespace flatbuffers { namespace flatbuffers {
+4
View File
@@ -677,6 +677,7 @@ struct IDLOptions {
std::string cpp_object_api_pointer_type; std::string cpp_object_api_pointer_type;
std::string cpp_object_api_string_type; std::string cpp_object_api_string_type;
bool cpp_object_api_string_flexible_constructor; bool cpp_object_api_string_flexible_constructor;
std::string cpp_object_api_vector_type;
CaseStyle cpp_object_api_field_case_style; CaseStyle cpp_object_api_field_case_style;
bool cpp_direct_copy; bool cpp_direct_copy;
bool gen_nullable; bool gen_nullable;
@@ -1012,10 +1013,13 @@ class Parser : public ParserState {
known_attributes_["cpp_ptr_type_get"] = true; known_attributes_["cpp_ptr_type_get"] = true;
known_attributes_["cpp_str_type"] = true; known_attributes_["cpp_str_type"] = true;
known_attributes_["cpp_str_flex_ctor"] = true; known_attributes_["cpp_str_flex_ctor"] = true;
known_attributes_["cpp_vector_type"] = true;
known_attributes_["native_inline"] = true; known_attributes_["native_inline"] = true;
known_attributes_["native_custom_alloc"] = true; known_attributes_["native_custom_alloc"] = true;
known_attributes_["native_type"] = true; known_attributes_["native_type"] = true;
known_attributes_["native_type_pack_name"] = true; known_attributes_["native_type_pack_name"] = true;
known_attributes_["bigfoot_ref_wrapper"] = true;
known_attributes_["bigfoot_ref"] = true;
known_attributes_["native_default"] = true; known_attributes_["native_default"] = true;
known_attributes_["flexbuffer"] = true; known_attributes_["flexbuffer"] = true;
known_attributes_["private"] = true; known_attributes_["private"] = true;
+15
View File
@@ -251,6 +251,21 @@ flatc(
schema="vector_table_naked_ptr.fbs", schema="vector_table_naked_ptr.fbs",
) )
flatc(
[
"--cpp",
"--gen-compare",
"--gen-mutable",
"--gen-object-api",
"--reflect-names",
"--cpp-include",
"test_vector_type.h",
"--cpp-vector-type",
"::flatbuffers::tests::CustomVector",
],
schema="cpp_vector_type.fbs",
)
flatc( flatc(
BASE_OPTS + CPP_OPTS + CS_OPTS + JAVA_OPTS + KOTLIN_OPTS + PHP_OPTS, BASE_OPTS + CPP_OPTS + CS_OPTS + JAVA_OPTS + KOTLIN_OPTS + PHP_OPTS,
prefix="union_vector", prefix="union_vector",
+9
View File
@@ -145,6 +145,12 @@ const static FlatCOption flatc_options[] = {
{"", "cpp-str-flex-ctor", "", {"", "cpp-str-flex-ctor", "",
"Don't construct custom string types by passing std::string from " "Don't construct custom string types by passing std::string from "
"Flatbuffers, but (char* + length)."}, "Flatbuffers, but (char* + length)."},
{"", "cpp-vector-type", "T",
"Set object API vector type (default std::vector). T must be a "
"template taking a single element type argument and support "
"resize(), reserve(), size(), data(), operator[], emplace_back(), and "
"begin()/end(). The custom type also needs its own header to be "
"included via --cpp-include."},
{"", "cpp-field-case-style", "STYLE", {"", "cpp-field-case-style", "STYLE",
"Generate C++ fields using selected case style. Supported STYLE values: * " "Generate C++ fields using selected case style. Supported STYLE values: * "
"'unchanged' - leave unchanged (default) * 'upper' - schema snake_case " "'unchanged' - leave unchanged (default) * 'upper' - schema snake_case "
@@ -545,6 +551,9 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc,
opts.cpp_object_api_string_type = argv[argi]; opts.cpp_object_api_string_type = argv[argi];
} else if (arg == "--cpp-str-flex-ctor") { } else if (arg == "--cpp-str-flex-ctor") {
opts.cpp_object_api_string_flexible_constructor = true; opts.cpp_object_api_string_flexible_constructor = true;
} else if (arg == "--cpp-vector-type") {
if (++argi >= argc) Error("missing type following: " + arg, true);
opts.cpp_object_api_vector_type = argv[argi];
} else if (arg == "--no-cpp-direct-copy") { } else if (arg == "--no-cpp-direct-copy") {
opts.cpp_direct_copy = false; opts.cpp_direct_copy = false;
} else if (arg == "--cpp-field-case-style") { } else if (arg == "--cpp-field-case-style") {
+275 -25
View File
@@ -257,6 +257,19 @@ class CppGenerator : public BaseGenerator {
code_ += " FLATBUFFERS_VERSION_REVISION == " + code_ += " FLATBUFFERS_VERSION_REVISION == " +
std::to_string(FLATBUFFERS_VERSION_REVISION) + ","; std::to_string(FLATBUFFERS_VERSION_REVISION) + ",";
code_ += " \"Non-compatible flatbuffers version included\");"; code_ += " \"Non-compatible flatbuffers version included\");";
code_ += "// Ensure the included flatbuffers.h is Bigfoot's fork - stock";
code_ += "// flatbuffers (or a differently versioned Bigfoot fork) is not compatible.";
code_ += "#ifndef FLATBUFFERS_BIGFOOT_VERSION";
code_ +=
"#error \"This file requires Bigfoot's flatbuffers fork - stock "
"flatbuffers is not compatible\"";
code_ += "#endif";
code_ += "static_assert(FLATBUFFERS_BIGFOOT_VERSION == " +
std::to_string(FLATBUFFERS_BIGFOOT_VERSION) + ",";
code_ +=
" \"Non-compatible Bigfoot flatbuffers fork version "
"included\");";
} }
void GenIncludeDependencies() { void GenIncludeDependencies() {
@@ -529,6 +542,8 @@ class CppGenerator : public BaseGenerator {
code_ += ""; code_ += "";
} }
GenerateBigfootRefForwardDecls();
// Generate preablmle code for mini reflection. // Generate preablmle code for mini reflection.
if (opts_.mini_reflect != IDLOptions::kNone) { if (opts_.mini_reflect != IDLOptions::kNone) {
// To break cyclic dependencies, first pre-declare all tables/structs. // To break cyclic dependencies, first pre-declare all tables/structs.
@@ -758,6 +773,8 @@ class CppGenerator : public BaseGenerator {
if (cur_name_space_) SetNameSpace(nullptr); if (cur_name_space_) SetNameSpace(nullptr);
GenerateBigfootRefImpls();
// Close the include guard. // Close the include guard.
code_ += "#endif // " + include_guard; code_ += "#endif // " + include_guard;
@@ -892,6 +909,24 @@ class CppGenerator : public BaseGenerator {
return opts_.gen_nullable ? " _Nullable " : ""; return opts_.gen_nullable ? " _Nullable " : "";
} }
// A field's `native_type`/`native_type_pack_name` normally come from the
// referenced struct's own declaration. A field can override both (see
// `bigfoot_ref` in idl_parser.cpp, which synthesizes these two attributes
// directly on the field) to instantiate a templated native type
// differently per field.
static const Value* EffectiveNativeType(const FieldDef& field,
const StructDef& struct_def) {
if (const auto v = field.attributes.Lookup("native_type")) return v;
return struct_def.attributes.Lookup("native_type");
}
static const Value* EffectiveNativeTypePackName(const FieldDef& field,
const StructDef& struct_def) {
if (const auto v = field.attributes.Lookup("native_type_pack_name"))
return v;
return struct_def.attributes.Lookup("native_type_pack_name");
}
static std::string NativeName(const std::string& name, const StructDef* sd, static std::string NativeName(const std::string& name, const StructDef* sd,
const IDLOptions& opts) { const IDLOptions& opts) {
// If the table is a native_type, return the native_type name. // If the table is a native_type, return the native_type name.
@@ -937,6 +972,23 @@ class CppGenerator : public BaseGenerator {
"std::string"; // Only for custom string types. "std::string"; // Only for custom string types.
} }
const std::string NativeVectorType(const FieldDef* field) {
auto attr = field ? field->attributes.Lookup("cpp_vector_type") : nullptr;
auto& ret = attr ? attr->constant : opts_.cpp_object_api_vector_type;
if (ret.empty()) {
return "std::vector";
}
return ret;
}
// True if this field's native vector uses a custom (non-std::vector)
// container, meaning generated Pack() code can't rely on the std::vector
// specific CreateVector*() overloads and must fall back to data()/size()
// or per-element construction instead.
bool UsesCustomVectorType(const FieldDef* field) {
return NativeVectorType(field) != "std::vector";
}
std::string GenTypeNativePtr(const std::string& type, const FieldDef* field, std::string GenTypeNativePtr(const std::string& type, const FieldDef* field,
bool is_constructor) { bool is_constructor) {
auto& ptr_type = PtrType(field); auto& ptr_type = PtrType(field);
@@ -974,20 +1026,21 @@ class CppGenerator : public BaseGenerator {
case BASE_TYPE_VECTOR64: case BASE_TYPE_VECTOR64:
case BASE_TYPE_VECTOR: { case BASE_TYPE_VECTOR: {
const auto type_name = GenTypeNative(type.VectorType(), true, field); const auto type_name = GenTypeNative(type.VectorType(), true, field);
if (type.struct_def && const auto vector_type = NativeVectorType(&field);
if (vector_type == "std::vector" && type.struct_def &&
type.struct_def->attributes.Lookup("native_custom_alloc")) { type.struct_def->attributes.Lookup("native_custom_alloc")) {
auto native_custom_alloc = auto native_custom_alloc =
type.struct_def->attributes.Lookup("native_custom_alloc"); type.struct_def->attributes.Lookup("native_custom_alloc");
return "std::vector<" + type_name + "," + return "std::vector<" + type_name + "," +
native_custom_alloc->constant + "<" + type_name + ">>"; native_custom_alloc->constant + "<" + type_name + ">>";
} else { } else {
return "std::vector<" + type_name + ">"; return vector_type + "<" + type_name + ">";
} }
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
auto type_name = WrapInNameSpace(*type.struct_def); auto type_name = WrapInNameSpace(*type.struct_def);
if (IsStruct(type)) { if (IsStruct(type)) {
auto native_type = type.struct_def->attributes.Lookup("native_type"); auto native_type = EffectiveNativeType(field, *type.struct_def);
if (native_type) { if (native_type) {
type_name = native_type->constant; type_name = native_type->constant;
} }
@@ -1979,7 +2032,7 @@ class CppGenerator : public BaseGenerator {
const std::string& full_type = const std::string& full_type =
(cpp_type (cpp_type
? (IsVector(field.value.type) ? (IsVector(field.value.type)
? "std::vector<" + ? NativeVectorType(&field) + "<" +
GenTypeNativePtr(cpp_type->constant, &field, GenTypeNativePtr(cpp_type->constant, &field,
false) + false) +
"> " "> "
@@ -3515,11 +3568,11 @@ class CppGenerator : public BaseGenerator {
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
if (IsStruct(type)) { if (IsStruct(type)) {
const auto& struct_attrs = type.struct_def->attributes; const auto native_type = EffectiveNativeType(afield, *type.struct_def);
const auto native_type = struct_attrs.Lookup("native_type");
if (native_type) { if (native_type) {
std::string unpack_call = "::flatbuffers::UnPack"; std::string unpack_call = "::flatbuffers::UnPack";
const auto pack_name = struct_attrs.Lookup("native_type_pack_name"); const auto pack_name =
EffectiveNativeTypePackName(afield, *type.struct_def);
if (pack_name) { if (pack_name) {
unpack_call += pack_name->constant; unpack_call += pack_name->constant;
} }
@@ -3772,13 +3825,22 @@ class CppGenerator : public BaseGenerator {
case BASE_TYPE_VECTOR64: case BASE_TYPE_VECTOR64:
case BASE_TYPE_VECTOR: { case BASE_TYPE_VECTOR: {
auto vector_type = field.value.type.VectorType(); auto vector_type = field.value.type.VectorType();
// If the field's native container isn't std::vector, the
// std::vector-specific CreateVector*() overloads in
// flatbuffer_builder.h can't be used directly. Fall back to
// data()/size()-based overloads (which only require the container to
// support those, like std::vector does) or, where no such overload
// exists, to the same per-element lambda serialization already used
// above for custom string/table/union element types.
const bool custom_vector = UsesCustomVectorType(&field);
switch (vector_type.base_type) { switch (vector_type.base_type) {
case BASE_TYPE_STRING: { case BASE_TYPE_STRING: {
if (NativeString(&field) == "std::string") { if (!custom_vector && NativeString(&field) == "std::string") {
code += "_fbb.CreateVectorOfStrings(" + value + ")"; code += "_fbb.CreateVectorOfStrings(" + value + ")";
} else { } else {
// Use by-function serialization to emulate // Use by-function serialization to emulate
// CreateVectorOfStrings(); this works also with non-std strings. // CreateVectorOfStrings(); this works also with non-std strings
// and non-std::vector vector types.
code += code +=
"_fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::" "_fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::"
"String>>" "String>>"
@@ -3793,20 +3855,37 @@ class CppGenerator : public BaseGenerator {
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
if (IsStruct(vector_type)) { if (IsStruct(vector_type)) {
const auto& struct_attrs = const auto native_type =
field.value.type.struct_def->attributes; EffectiveNativeType(field, *field.value.type.struct_def);
const auto native_type = struct_attrs.Lookup("native_type");
if (native_type) { if (native_type) {
code += "_fbb.CreateVectorOfNativeStructs<"; code += "_fbb.CreateVectorOfNativeStructs<";
code += WrapInNameSpace(*vector_type.struct_def) + ", " + code += WrapInNameSpace(*vector_type.struct_def) + ", " +
native_type->constant + ">"; native_type->constant + ">";
code += "(" + value; if (custom_vector) {
const auto pack_name = code += "(" + value + ".data(), " + value + ".size()";
struct_attrs.Lookup("native_type_pack_name"); } else {
code += "(" + value;
}
const auto pack_name = EffectiveNativeTypePackName(
field, *field.value.type.struct_def);
if (pack_name) { if (pack_name) {
code += ", ::flatbuffers::Pack" + pack_name->constant; code += ", ::flatbuffers::Pack" + pack_name->constant;
} }
code += ")"; code += ")";
} else if (custom_vector &&
(field.value.type.base_type == BASE_TYPE_VECTOR64 ||
field.offset64)) {
// CreateVectorOfStructs64() (and CreateVectorOfStructs64<V>()
// for offset64) only accept a std::vector; use the
// equivalent explicit-template raw pointer overload instead.
const auto struct_type = WrapInNameSpace(*vector_type.struct_def);
const auto vector_t = field.value.type.base_type ==
BASE_TYPE_VECTOR64
? "::flatbuffers::Vector64"
: "::flatbuffers::Vector";
code += "_fbb.CreateVectorOfStructs<" + struct_type +
", ::flatbuffers::Offset64, " + vector_t + ">(" +
value + ".data(), " + value + ".size())";
} else { } else {
// If the field uses 64-bit addressing, create a 64-bit vector. // If the field uses 64-bit addressing, create a 64-bit vector.
if (field.value.type.base_type == BASE_TYPE_VECTOR64) { if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
@@ -3818,7 +3897,11 @@ class CppGenerator : public BaseGenerator {
code += "64<::flatbuffers::Vector>"; code += "64<::flatbuffers::Vector>";
} }
} }
code += "(" + value + ")"; if (custom_vector) {
code += "(" + value + ".data(), " + value + ".size())";
} else {
code += "(" + value + ")";
}
} }
} else { } else {
code += "_fbb.CreateVector<::flatbuffers::Offset<"; code += "_fbb.CreateVector<::flatbuffers::Offset<";
@@ -3837,7 +3920,17 @@ class CppGenerator : public BaseGenerator {
break; break;
} }
case BASE_TYPE_BOOL: { case BASE_TYPE_BOOL: {
code += "_fbb.CreateVector(" + value + ")"; if (custom_vector) {
// Vectors of bool are always stored on the wire as uint8_t
// (there is no Vector<bool>); CreateVectorScalarCast() does
// the per-element bool->uint8_t cast from a raw data()/size()
// pointer pair, avoiding any dependency on std::vector<bool>'s
// bit-packed specialization.
code += "_fbb.CreateVectorScalarCast<uint8_t>(" + value +
".data(), " + value + ".size())";
} else {
code += "_fbb.CreateVector(" + value + ")";
}
break; break;
} }
case BASE_TYPE_UNION: { case BASE_TYPE_UNION: {
@@ -3873,9 +3966,11 @@ class CppGenerator : public BaseGenerator {
// the underlying storage type (eg. uint8_t). // the underlying storage type (eg. uint8_t).
const auto basetype = GenTypeBasic( const auto basetype = GenTypeBasic(
field.value.type.enum_def->underlying_type, false); field.value.type.enum_def->underlying_type, false);
code += "_fbb.CreateVectorScalarCast<" + basetype + const std::string data_ptr =
">(::flatbuffers::data(" + value + "), " + value + custom_vector ? value + ".data()"
".size())"; : "::flatbuffers::data(" + value + ")";
code += "_fbb.CreateVectorScalarCast<" + basetype + ">(" +
data_ptr + ", " + value + ".size())";
} else if (field.attributes.Lookup("cpp_type")) { } else if (field.attributes.Lookup("cpp_type")) {
auto type = GenTypeBasic(vector_type, false); auto type = GenTypeBasic(vector_type, false);
code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), "; code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
@@ -3884,6 +3979,27 @@ class CppGenerator : public BaseGenerator {
code += "static_cast<" + type + ">((*__va->__rehasher)"; code += "static_cast<" + type + ">((*__va->__rehasher)";
code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0"; code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
code += "; }, &_va )"; code += "; }, &_va )";
} else if (custom_vector) {
// Explicitly specify the element type so it can be deduced
// from a raw data()/size() pointer pair instead of relying on
// the std::vector<T, Alloc>-specific CreateVector overloads.
// Use the user-facing type (matches what GenTypeNative()
// stores in the native vector, e.g. the enum type itself for
// scoped-enum fields) so it matches data()'s pointee type.
auto type = GenTypeBasic(vector_type, true);
if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
code += "_fbb.CreateVector<" + type +
", ::flatbuffers::Offset64, ::flatbuffers::Vector64>(" +
value + ".data(), " + value + ".size())";
} else if (field.offset64) {
// This is normal 32-bit vector, with 64-bit addressing.
code += "_fbb.CreateVector<" + type +
", ::flatbuffers::Offset64, ::flatbuffers::Vector>(" +
value + ".data(), " + value + ".size())";
} else {
code += "_fbb.CreateVector(" + value + ".data(), " + value +
".size())";
}
} else { } else {
// If the field uses 64-bit addressing, create a 64-bit vector. // If the field uses 64-bit addressing, create a 64-bit vector.
if (field.value.type.base_type == BASE_TYPE_VECTOR64) { if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
@@ -3917,12 +4033,12 @@ class CppGenerator : public BaseGenerator {
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
if (IsStruct(field.value.type)) { if (IsStruct(field.value.type)) {
const auto& struct_attribs = field.value.type.struct_def->attributes; const auto native_type =
const auto native_type = struct_attribs.Lookup("native_type"); EffectiveNativeType(field, *field.value.type.struct_def);
if (native_type && field.native_inline) { if (native_type && field.native_inline) {
code += "::flatbuffers::Pack"; code += "::flatbuffers::Pack";
const auto pack_name = const auto pack_name =
struct_attribs.Lookup("native_type_pack_name"); EffectiveNativeTypePackName(field, *field.value.type.struct_def);
if (pack_name) { if (pack_name) {
code += pack_name->constant; code += pack_name->constant;
} }
@@ -4087,8 +4203,7 @@ class CppGenerator : public BaseGenerator {
if (field->value.type.base_type == BASE_TYPE_STRUCT) { if (field->value.type.base_type == BASE_TYPE_STRUCT) {
if (IsStruct(field->value.type)) { if (IsStruct(field->value.type)) {
auto native_type = auto native_type =
field->value.type.struct_def->attributes.Lookup( EffectiveNativeType(*field, *field->value.type.struct_def);
"native_type");
auto native_inline = field->attributes.Lookup("native_inline"); auto native_inline = field->attributes.Lookup("native_inline");
if (native_type) { if (native_type) {
pass_by_address = true; pass_by_address = true;
@@ -4443,6 +4558,141 @@ class CppGenerator : public BaseGenerator {
} }
} }
// Split a "::"-qualified C++ name into namespace components + final name.
static std::vector<std::string> SplitQualifiedName(const std::string& qualified) {
std::vector<std::string> parts;
size_t start = qualified.compare(0, 2, "::") == 0 ? 2 : 0;
for (;;) {
const auto pos = qualified.find("::", start);
if (pos == std::string::npos) {
parts.push_back(qualified.substr(start));
break;
}
parts.push_back(qualified.substr(start, pos - start));
start = pos + 2;
}
return parts;
}
// Bigfoot: for every field annotated `bigfoot_ref: "::Ns::AssetX"` (see
// idl_parser.cpp), forward-declare AssetX plus prototype the Pack/UnPack
// functions for its reference wrapper. Called early (alongside the
// regular struct/table forward declarations), since these prototypes -
// unlike their definitions in GenerateBigfootRefImpls() - only need
// AssetX and the wrapper struct forward-declared, not complete.
void GenerateBigfootRefForwardDecls() {
std::unordered_set<std::string> declared_assets;
for (const auto& struct_def : parser_.structs_.vec) {
if (struct_def->generated) continue;
for (const auto& field : struct_def->fields.vec) {
const auto* bigfoot_ref = field->attributes.Lookup("bigfoot_ref");
if (!bigfoot_ref) continue;
if (!declared_assets.insert(bigfoot_ref->constant).second) continue;
auto parts = SplitQualifiedName(bigfoot_ref->constant);
const std::string class_name = parts.back();
parts.pop_back();
SetNameSpace(nullptr);
for (const auto& ns_part : parts) code_ += "namespace " + ns_part + " {";
code_ += "class " + class_name + ";";
for (auto it = parts.rbegin(); it != parts.rend(); ++it)
code_ += "} // namespace " + *it;
code_ += "";
}
}
std::unordered_set<std::string> declared_pairs;
bool opened_flatbuffers_ns = false;
for (const auto& struct_def : parser_.structs_.vec) {
if (struct_def->generated) continue;
for (const auto& field : struct_def->fields.vec) {
const auto* bigfoot_ref = field->attributes.Lookup("bigfoot_ref");
if (!bigfoot_ref) continue;
const auto* pack_name = field->attributes.Lookup("native_type_pack_name");
if (!declared_pairs.insert(pack_name->constant).second) continue;
if (!opened_flatbuffers_ns) {
SetNameSpace(nullptr);
code_ += "namespace flatbuffers {";
opened_flatbuffers_ns = true;
}
const auto* native_type = field->attributes.Lookup("native_type");
const std::string flat_wrapper =
WrapInNameSpace(*field->value.type.struct_def);
code_ += flat_wrapper + " Pack" + pack_name->constant +
"(const " + native_type->constant + "& p_asset);";
code_ += native_type->constant + " UnPack" + pack_name->constant +
"(const " + flat_wrapper + "& p_asset);";
}
}
if (opened_flatbuffers_ns) {
code_ += "} // namespace flatbuffers";
code_ += "";
}
}
// Bigfoot: defines the Pack/UnPack functions prototyped by
// GenerateBigfootRefForwardDecls(). Called late (after every struct/table
// in this file has been fully defined), since a wrapper struct (e.g.
// HardReference/SoftReference) may be defined in this same generated file
// rather than one it includes, and these definitions construct it by
// value - they need it complete, unlike the earlier prototypes.
void GenerateBigfootRefImpls() {
std::unordered_set<std::string> declared_pairs;
bool opened_flatbuffers_ns = false;
for (const auto& struct_def : parser_.structs_.vec) {
if (struct_def->generated) continue;
for (const auto& field : struct_def->fields.vec) {
const auto* bigfoot_ref = field->attributes.Lookup("bigfoot_ref");
if (!bigfoot_ref) continue;
const auto* pack_name = field->attributes.Lookup("native_type_pack_name");
if (!declared_pairs.insert(pack_name->constant).second) continue;
if (!opened_flatbuffers_ns) {
SetNameSpace(nullptr);
code_ += "namespace flatbuffers {";
opened_flatbuffers_ns = true;
}
const auto* native_type = field->attributes.Lookup("native_type");
const std::string flat_wrapper =
WrapInNameSpace(*field->value.type.struct_def);
// A single translation unit can end up including two different
// generated headers that both reference the same asset type (e.g.
// AssetB references AssetA, and some other TU includes both
// AssetA_generated.hpp and AssetB_generated.hpp directly) - each
// would otherwise emit an identical, independent definition of these
// functions. `inline` only allows identical definitions to repeat
// across *different* translation units, not twice within the same
// one, so guard against that with a plain macro guard.
std::string guard_name = pack_name->constant;
std::transform(guard_name.begin(), guard_name.end(), guard_name.begin(), CharToUpper);
const std::string guard = "FLATBUFFERS_BIGFOOT_REF_" + guard_name;
code_ += "#ifndef " + guard;
code_ += "#define " + guard;
code_ += "inline " + flat_wrapper + " Pack" + pack_name->constant +
"(const " + native_type->constant +
"& p_asset) { return {Pack(p_asset.GetUUID())}; }";
code_ += "inline " + native_type->constant + " UnPack" +
pack_name->constant + "(const " + flat_wrapper +
"& p_asset) { return {UnPack(p_asset.uuid())}; }";
code_ += "#endif // " + guard;
}
}
if (opened_flatbuffers_ns) {
code_ += "} // namespace flatbuffers";
code_ += "";
}
}
// Set up the correct namespace. Only open a namespace if the existing one is // Set up the correct namespace. Only open a namespace if the existing one is
// different (closing/opening only what is necessary). // different (closing/opening only what is necessary).
// //
+49
View File
@@ -1286,6 +1286,55 @@ CheckedError Parser::ParseField(StructDef& struct_def) {
"'native_inline' can only be defined on structs, vector of structs or " "'native_inline' can only be defined on structs, vector of structs or "
"vector of tables"); "vector of tables");
// `bigfoot_ref` is Bigfoot's single-purpose replacement for the old,
// general-purpose `native_type_template`/`native_type_template_arg` pair:
// a field typed as a `bigfoot_ref_wrapper`-tagged struct (HardReference or
// SoftReference) and annotated `bigfoot_ref: "::Bigfoot::AssetX"` gets its
// native type instantiated as `<wrapper><::Bigfoot::AssetX>`, plus (unlike
// the old mechanism) a forward declaration of AssetX and inline Pack/UnPack
// definitions are emitted directly into the generated header - see
// GenerateBigfootRefDecls in idl_gen_cpp.cpp.
auto bigfoot_ref = field->attributes.Lookup("bigfoot_ref");
if (bigfoot_ref) {
if (!IsStruct(field->value.type) && !IsVectorOfStruct(field->value.type))
return Error(
"'bigfoot_ref' can only be defined on struct-typed fields or "
"vectors of structs");
const auto* target_struct = field->value.type.struct_def;
const auto* wrapper = target_struct->attributes.Lookup("bigfoot_ref_wrapper");
if (!wrapper)
return Error(
"'bigfoot_ref' requires the field's type ('" + target_struct->name +
"') to declare a 'bigfoot_ref_wrapper' attribute");
if (field->attributes.Lookup("native_type"))
return Error(
"'bigfoot_ref' cannot be combined with an explicit 'native_type' "
"on the same field");
const auto b = bigfoot_ref->constant.find_first_not_of(" \t");
const auto e = bigfoot_ref->constant.find_last_not_of(" \t");
const std::string asset_type =
b == std::string::npos ? "" : bigfoot_ref->constant.substr(b, e - b + 1);
if (asset_type.empty())
return Error("'bigfoot_ref' cannot be empty");
auto native_type_val = new Value();
native_type_val->type = bigfoot_ref->type;
native_type_val->constant = wrapper->constant + "<" + asset_type + ">";
field->attributes.Add("native_type", native_type_val);
if (!field->attributes.Lookup("native_type_pack_name")) {
const auto last_colon = asset_type.find_last_of(':');
const std::string asset_short_name =
last_colon == std::string::npos ? asset_type
: asset_type.substr(last_colon + 1);
auto pack_name_val = new Value();
pack_name_val->type = bigfoot_ref->type;
pack_name_val->constant = target_struct->name + asset_short_name;
field->attributes.Add("native_type_pack_name", pack_name_val);
}
}
auto nested = field->attributes.Lookup("nested_flatbuffer"); auto nested = field->attributes.Lookup("nested_flatbuffer");
if (nested) { if (nested) {
if (nested->type.base_type != BASE_TYPE_STRING) if (nested->type.base_type != BASE_TYPE_STRING)
+17
View File
@@ -78,6 +78,9 @@ cc_test(
"vector_table_naked_ptr/vector_table_naked_ptr_generated.h", "vector_table_naked_ptr/vector_table_naked_ptr_generated.h",
"vector_table_naked_ptr_test.h", "vector_table_naked_ptr_test.h",
"vector_table_naked_ptr_test.cpp", "vector_table_naked_ptr_test.cpp",
"test_vector_type.h",
"cpp_vector_type_test.h",
"cpp_vector_type_test.cpp",
], ],
copts = [ copts = [
"-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE", "-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE",
@@ -136,6 +139,7 @@ cc_test(
deps = [ deps = [
":alignment_test_cc_fbs", ":alignment_test_cc_fbs",
":arrays_test_cc_fbs", ":arrays_test_cc_fbs",
":cpp_vector_type_cc_fbs",
":default_vectors_strings_test_cc_fbs", ":default_vectors_strings_test_cc_fbs",
":monster_extra_cc_fbs", ":monster_extra_cc_fbs",
":monster_test_cc_fbs", ":monster_test_cc_fbs",
@@ -271,6 +275,19 @@ flatbuffer_cc_library(
], ],
) )
flatbuffer_cc_library(
name = "cpp_vector_type_cc_fbs",
srcs = ["cpp_vector_type.fbs"],
flatc_args = [
"--gen-compare",
"--gen-mutable",
"--gen-object-api",
"--reflect-names",
"--cpp-include test_vector_type.h",
"--cpp-vector-type ::flatbuffers::tests::CustomVector",
],
)
flatbuffer_cc_library( flatbuffer_cc_library(
name = "alignment_test_cc_fbs", name = "alignment_test_cc_fbs",
srcs = ["alignment_test.fbs"], srcs = ["alignment_test.fbs"],
+31
View File
@@ -0,0 +1,31 @@
native_include "bigfoot_ref_test_impl.h";
namespace BigfootRefTestNS;
// Stands in for Bigfoot's real UUID - a `native_type` struct so RefId has a
// distinct native/flat representation, matching the shape `bigfoot_ref`
// requires of a wrapper's payload field.
struct RefId (native_type: "Native::RefId") {
value: uint64;
}
// The reference-wrapper template itself. `bigfoot_ref_wrapper` marks Ref as
// instantiable per referenced type via `bigfoot_ref` below.
struct Ref (bigfoot_ref_wrapper: "Native::Ref") {
uuid: RefId;
}
// RefHolder references two distinct C++ types (Thing, OtherThing) that are
// *never defined anywhere in this test* - only ever forward-declared, by
// flatc itself, directly into the generated header. This is the property
// `bigfoot_ref` exists to provide: a reference field never requires the
// referenced type to be complete. It also references `Thing` twice (once as
// a plain field, once in a vector), exercising the include-guard dedup for
// two fields that resolve to the identical Pack/UnPack pair.
table RefHolder {
ref_a: Ref (native_inline, bigfoot_ref: "Native::Thing");
ref_a_again: [Ref] (native_inline, bigfoot_ref: "Native::Thing");
ref_b: Ref (native_inline, bigfoot_ref: "Native::OtherThing");
}
root_type RefHolder;
+47
View File
@@ -0,0 +1,47 @@
#include "bigfoot_ref_test_impl.h"
#include "bigfoot_ref_test_generated.h"
#include "test_assert.h"
namespace flatbuffers {
BigfootRefTestNS::RefId Pack(const Native::RefId& obj) {
return BigfootRefTestNS::RefId(obj.value);
}
const Native::RefId UnPack(const BigfootRefTestNS::RefId& obj) {
return Native::RefId(obj.value());
}
} // namespace flatbuffers
namespace flatbuffers {
namespace tests {
// Exercises the --bigfoot_ref/--bigfoot_ref_wrapper flatc attributes (see
// tests/bigfoot_ref_test.fbs): a reference field never requires the
// referenced native type to be complete, and the generated header supplies
// its own forward declaration plus inline Pack/UnPack definitions, with no
// hand-written boilerplate anywhere in this file for `Thing`/`OtherThing`.
void BigfootRefTest() {
using BigfootRefTestNS::RefHolder;
using BigfootRefTestNS::RefHolderT;
RefHolderT src;
src.ref_a = Native::Ref<Native::Thing>(Native::RefId(1));
src.ref_a_again.push_back(Native::Ref<Native::Thing>(Native::RefId(2)));
src.ref_a_again.push_back(Native::Ref<Native::Thing>(Native::RefId(3)));
src.ref_b = Native::Ref<Native::OtherThing>(Native::RefId(4));
flatbuffers::FlatBufferBuilder fbb;
fbb.Finish(RefHolder::Pack(fbb, &src));
auto dst = BigfootRefTestNS::UnPackRefHolder(fbb.GetBufferPointer());
TEST_EQ(dst->ref_a.uuid.value, 1u);
TEST_EQ(dst->ref_a_again.size(), 2u);
TEST_EQ(dst->ref_a_again[0].uuid.value, 2u);
TEST_EQ(dst->ref_a_again[1].uuid.value, 3u);
TEST_EQ(dst->ref_b.uuid.value, 4u);
}
} // namespace tests
} // namespace flatbuffers
+55
View File
@@ -0,0 +1,55 @@
#ifndef BIGFOOT_REF_TEST_IMPL_H
#define BIGFOOT_REF_TEST_IMPL_H
#include <cstdint>
namespace Native {
// Stands in for Bigfoot's real UUID.
struct RefId {
uint64_t value;
RefId() : value(0) {}
explicit RefId(uint64_t _value) : value(_value) {}
bool operator==(const RefId& other) const { return value == other.value; }
};
// `Thing`/`OtherThing` are intentionally *never* defined anywhere in this
// test (see bigfoot_ref_test.fbs) - Ref<T> must compile and round-trip
// without T ever being a complete type, exactly like Bigfoot's
// HardReference<T>/SoftReference<T>. Their forward declarations are emitted
// automatically by flatc (GenerateBigfootRefForwardDecls in
// idl_gen_cpp.cpp) directly into bigfoot_ref_test_generated.h - no manual
// forward declaration belongs here.
// The reference-wrapper template `bigfoot_ref_wrapper`/`bigfoot_ref` (see
// idl_parser.cpp/idl_gen_cpp.cpp) instantiate per referenced type. Only
// needs a `GetUUID()` accessor and a constructor from RefId - never needs T
// complete.
template <typename T>
struct Ref {
RefId uuid;
Ref() : uuid() {}
Ref(const RefId& _uuid) : uuid(_uuid) {}
const RefId& GetUUID() const { return uuid; }
bool operator==(const Ref& other) const { return uuid == other.uuid; }
};
} // namespace Native
namespace BigfootRefTestNS {
struct RefId;
} // namespace BigfootRefTestNS
namespace flatbuffers {
BigfootRefTestNS::RefId Pack(const Native::RefId& obj);
const Native::RefId UnPack(const BigfootRefTestNS::RefId& obj);
namespace tests {
void BigfootRefTest();
} // namespace tests
} // namespace flatbuffers
#endif // BIGFOOT_REF_TEST_IMPL_H
+29
View File
@@ -0,0 +1,29 @@
// Schema used to test the --cpp-vector-type flatc option, which lets the
// generated Object API use a custom vector-like container (e.g.
// eastl::vector) instead of std::vector. See tests/test_vector_type.h for
// the stand-in container used by the test, and
// tests/cpp_vector_type_test.cpp for the test itself.
namespace CppVectorTypeNS;
enum CppVectorTypeColor : byte { Red = 0, Green, Blue }
struct CppVectorTypeVec2 {
x: float;
y: float;
}
table CppVectorTypeMonster {
id: int32;
}
table CppVectorTypeTest {
ints: [int32];
flags: [bool];
colors: [CppVectorTypeColor];
strings: [string];
positions: [CppVectorTypeVec2];
monsters: [CppVectorTypeMonster];
}
root_type CppVectorTypeTest;
+143
View File
@@ -0,0 +1,143 @@
#include "cpp_vector_type_test.h"
#include "cpp_vector_type_generated.h"
#include "test_assert.h"
namespace flatbuffers {
namespace tests {
// Exercises the --cpp-vector-type flatc option (see
// tests/cpp_vector_type.fbs and tests/test_vector_type.h), which replaces
// std::vector with a custom vector-like container in the generated Object
// API. This covers every CreateVector*-family code path in Pack(): plain
// scalars, bool, enum-cast, vector-of-string, vector-of-struct and
// vector-of-table, then round-trips everything back through UnPackTo().
void CppVectorTypeTest() {
using CppVectorTypeNS::CppVectorTypeColor_Blue;
using CppVectorTypeNS::CppVectorTypeColor_Green;
using CppVectorTypeNS::CppVectorTypeColor_Red;
using CppVectorTypeNS::CppVectorTypeMonsterT;
using CppVectorTypeNS::CppVectorTypeTest;
using CppVectorTypeNS::CppVectorTypeTestT;
using CppVectorTypeNS::CppVectorTypeVec2;
// ---------------------------------------
// 1) Build a native object using the custom vector container for every
// vector field (scalars, bools, enums, strings, structs and tables).
// ---------------------------------------
CppVectorTypeTestT src;
src.ints.push_back(1);
src.ints.push_back(2);
src.ints.push_back(3);
src.flags.push_back(true);
src.flags.push_back(false);
src.flags.push_back(true);
src.colors.push_back(CppVectorTypeColor_Red);
src.colors.push_back(CppVectorTypeColor_Green);
src.colors.push_back(CppVectorTypeColor_Blue);
src.strings.push_back("hello");
src.strings.push_back("world");
src.positions.push_back(CppVectorTypeVec2(1.0f, 2.0f));
src.positions.push_back(CppVectorTypeVec2(3.0f, 4.0f));
src.monsters.emplace_back(new CppVectorTypeMonsterT());
src.monsters[0]->id = 111;
src.monsters.emplace_back(new CppVectorTypeMonsterT());
src.monsters[1]->id = 222;
// ---------------------------------------
// 2) Exercise the copy constructor / copy assignment operator generated
// for object-API types (--gen-compare requires these too), which rely
// on the custom vector's own copy ctor plus reserve()/emplace_back()
// for the vector-of-pointer (table) field.
// ---------------------------------------
CppVectorTypeTestT copy_of_src(src);
TEST_EQ(copy_of_src == src, true);
TEST_ASSERT(copy_of_src.monsters[0].get() != src.monsters[0].get());
TEST_EQ(copy_of_src.monsters[0]->id, 111);
// ---------------------------------------
// 3) Pack into a FlatBuffer and verify the wire-format contents.
// ---------------------------------------
flatbuffers::FlatBufferBuilder fbb;
fbb.Finish(CppVectorTypeTest::Pack(fbb, &src));
const auto* fb =
flatbuffers::GetRoot<CppVectorTypeTest>(fbb.GetBufferPointer());
TEST_EQ(fb->ints()->size(), 3u);
TEST_EQ(fb->ints()->Get(0), 1);
TEST_EQ(fb->ints()->Get(1), 2);
TEST_EQ(fb->ints()->Get(2), 3);
TEST_EQ(fb->flags()->size(), 3u);
TEST_EQ(fb->flags()->Get(0) != 0, true);
TEST_EQ(fb->flags()->Get(1) != 0, false);
TEST_EQ(fb->flags()->Get(2) != 0, true);
TEST_EQ(fb->colors()->size(), 3u);
TEST_EQ(fb->colors()->Get(0), CppVectorTypeColor_Red);
TEST_EQ(fb->colors()->Get(1), CppVectorTypeColor_Green);
TEST_EQ(fb->colors()->Get(2), CppVectorTypeColor_Blue);
TEST_EQ(fb->strings()->size(), 2u);
TEST_EQ_STR(fb->strings()->Get(0)->c_str(), "hello");
TEST_EQ_STR(fb->strings()->Get(1)->c_str(), "world");
TEST_EQ(fb->positions()->size(), 2u);
TEST_EQ(fb->positions()->Get(0)->x(), 1.0f);
TEST_EQ(fb->positions()->Get(0)->y(), 2.0f);
TEST_EQ(fb->positions()->Get(1)->x(), 3.0f);
TEST_EQ(fb->positions()->Get(1)->y(), 4.0f);
TEST_EQ(fb->monsters()->size(), 2u);
TEST_EQ(fb->monsters()->Get(0)->id(), 111);
TEST_EQ(fb->monsters()->Get(1)->id(), 222);
// ---------------------------------------
// 4) Unpack back into a fresh native object and verify a full round-trip
// through the custom vector container.
// ---------------------------------------
CppVectorTypeTestT dst;
fb->UnPackTo(&dst);
TEST_EQ(dst == src, true);
TEST_EQ(dst.ints.size(), 3u);
TEST_EQ(dst.ints[0], 1);
TEST_EQ(dst.ints[1], 2);
TEST_EQ(dst.ints[2], 3);
TEST_EQ(dst.flags.size(), 3u);
TEST_EQ(dst.flags[0], true);
TEST_EQ(dst.flags[1], false);
TEST_EQ(dst.flags[2], true);
TEST_EQ(dst.colors.size(), 3u);
TEST_EQ(dst.colors[0], CppVectorTypeColor_Red);
TEST_EQ(dst.colors[1], CppVectorTypeColor_Green);
TEST_EQ(dst.colors[2], CppVectorTypeColor_Blue);
TEST_EQ(dst.strings.size(), 2u);
TEST_EQ_STR(dst.strings[0].c_str(), "hello");
TEST_EQ_STR(dst.strings[1].c_str(), "world");
TEST_EQ(dst.positions.size(), 2u);
TEST_EQ(dst.positions[0].x(), 1.0f);
TEST_EQ(dst.positions[0].y(), 2.0f);
TEST_EQ(dst.positions[1].x(), 3.0f);
TEST_EQ(dst.positions[1].y(), 4.0f);
TEST_EQ(dst.monsters.size(), 2u);
TEST_ASSERT(dst.monsters[0] != nullptr);
TEST_ASSERT(dst.monsters[1] != nullptr);
TEST_EQ(dst.monsters[0]->id, 111);
TEST_EQ(dst.monsters[1]->id, 222);
}
} // namespace tests
} // namespace flatbuffers
+12
View File
@@ -0,0 +1,12 @@
#ifndef TESTS_CPP_VECTOR_TYPE_TEST_H
#define TESTS_CPP_VECTOR_TYPE_TEST_H
namespace flatbuffers {
namespace tests {
void CppVectorTypeTest();
} // namespace tests
} // namespace flatbuffers
#endif // TESTS_CPP_VECTOR_TYPE_TEST_H
+28 -156
View File
@@ -31,14 +31,6 @@ struct ApplicationDataT;
bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs); bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs);
bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs); bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs);
inline const ::flatbuffers::TypeTable *Vector3DTypeTable();
inline const ::flatbuffers::TypeTable *Vector3DAltTypeTable();
inline const ::flatbuffers::TypeTable *MatrixTypeTable();
inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable();
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS { FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS {
private: private:
float x_; float x_;
@@ -46,9 +38,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS {
float z_; float z_;
public: public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { struct Traits;
return Vector3DTypeTable();
}
Vector3D() Vector3D()
: x_(0), : x_(0),
y_(0), y_(0),
@@ -62,24 +52,19 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS {
float x() const { float x() const {
return ::flatbuffers::EndianScalar(x_); return ::flatbuffers::EndianScalar(x_);
} }
void mutate_x(float _x) {
::flatbuffers::WriteScalar(&x_, _x);
}
float y() const { float y() const {
return ::flatbuffers::EndianScalar(y_); return ::flatbuffers::EndianScalar(y_);
} }
void mutate_y(float _y) {
::flatbuffers::WriteScalar(&y_, _y);
}
float z() const { float z() const {
return ::flatbuffers::EndianScalar(z_); return ::flatbuffers::EndianScalar(z_);
} }
void mutate_z(float _z) {
::flatbuffers::WriteScalar(&z_, _z);
}
}; };
FLATBUFFERS_STRUCT_END(Vector3D, 12); FLATBUFFERS_STRUCT_END(Vector3D, 12);
struct Vector3D::Traits {
using type = Vector3D;
};
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS { FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
private: private:
float a_; float a_;
@@ -87,9 +72,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
float c_; float c_;
public: public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { struct Traits;
return Vector3DAltTypeTable();
}
Vector3DAlt() Vector3DAlt()
: a_(0), : a_(0),
b_(0), b_(0),
@@ -103,30 +86,23 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
float a() const { float a() const {
return ::flatbuffers::EndianScalar(a_); return ::flatbuffers::EndianScalar(a_);
} }
void mutate_a(float _a) {
::flatbuffers::WriteScalar(&a_, _a);
}
float b() const { float b() const {
return ::flatbuffers::EndianScalar(b_); return ::flatbuffers::EndianScalar(b_);
} }
void mutate_b(float _b) {
::flatbuffers::WriteScalar(&b_, _b);
}
float c() const { float c() const {
return ::flatbuffers::EndianScalar(c_); return ::flatbuffers::EndianScalar(c_);
} }
void mutate_c(float _c) {
::flatbuffers::WriteScalar(&c_, _c);
}
}; };
FLATBUFFERS_STRUCT_END(Vector3DAlt, 12); FLATBUFFERS_STRUCT_END(Vector3DAlt, 12);
struct Vector3DAlt::Traits {
using type = Vector3DAlt;
};
struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef Native::Matrix NativeTableType; typedef Native::Matrix NativeTableType;
typedef MatrixBuilder Builder; typedef MatrixBuilder Builder;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { struct Traits;
return MatrixTypeTable();
}
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_ROWS = 4, VT_ROWS = 4,
VT_COLUMNS = 6, VT_COLUMNS = 6,
@@ -135,21 +111,12 @@ struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
int32_t rows() const { int32_t rows() const {
return GetField<int32_t>(VT_ROWS, 0); return GetField<int32_t>(VT_ROWS, 0);
} }
bool mutate_rows(int32_t _rows = 0) {
return SetField<int32_t>(VT_ROWS, _rows, 0);
}
int32_t columns() const { int32_t columns() const {
return GetField<int32_t>(VT_COLUMNS, 0); return GetField<int32_t>(VT_COLUMNS, 0);
} }
bool mutate_columns(int32_t _columns = 0) {
return SetField<int32_t>(VT_COLUMNS, _columns, 0);
}
const ::flatbuffers::Vector<float> *values() const { const ::flatbuffers::Vector<float> *values() const {
return GetPointer<const ::flatbuffers::Vector<float> *>(VT_VALUES); return GetPointer<const ::flatbuffers::Vector<float> *>(VT_VALUES);
} }
::flatbuffers::Vector<float> *mutable_values() {
return GetPointer<::flatbuffers::Vector<float> *>(VT_VALUES);
}
template <bool B = false> template <bool B = false>
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const { bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
@@ -200,6 +167,11 @@ inline ::flatbuffers::Offset<Matrix> CreateMatrix(
return builder_.Finish(); return builder_.Finish();
} }
struct Matrix::Traits {
using type = Matrix;
static auto constexpr Create = CreateMatrix;
};
inline ::flatbuffers::Offset<Matrix> CreateMatrixDirect( inline ::flatbuffers::Offset<Matrix> CreateMatrixDirect(
::flatbuffers::FlatBufferBuilder &_fbb, ::flatbuffers::FlatBufferBuilder &_fbb,
int32_t rows = 0, int32_t rows = 0,
@@ -232,9 +204,7 @@ struct ApplicationDataT : public ::flatbuffers::NativeTable {
struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef ApplicationDataT NativeTableType; typedef ApplicationDataT NativeTableType;
typedef ApplicationDataBuilder Builder; typedef ApplicationDataBuilder Builder;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() { struct Traits;
return ApplicationDataTypeTable();
}
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_VECTORS = 4, VT_VECTORS = 4,
VT_VECTORS_ALT = 6, VT_VECTORS_ALT = 6,
@@ -246,39 +216,21 @@ struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
const ::flatbuffers::Vector<const Geometry::Vector3D *> *vectors() const { const ::flatbuffers::Vector<const Geometry::Vector3D *> *vectors() const {
return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS); return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS);
} }
::flatbuffers::Vector<const Geometry::Vector3D *> *mutable_vectors() {
return GetPointer<::flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS);
}
const ::flatbuffers::Vector<const Geometry::Vector3DAlt *> *vectors_alt() const { const ::flatbuffers::Vector<const Geometry::Vector3DAlt *> *vectors_alt() const {
return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3DAlt *> *>(VT_VECTORS_ALT); return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3DAlt *> *>(VT_VECTORS_ALT);
} }
::flatbuffers::Vector<const Geometry::Vector3DAlt *> *mutable_vectors_alt() {
return GetPointer<::flatbuffers::Vector<const Geometry::Vector3DAlt *> *>(VT_VECTORS_ALT);
}
const Geometry::Vector3D *position() const { const Geometry::Vector3D *position() const {
return GetStruct<const Geometry::Vector3D *>(VT_POSITION); return GetStruct<const Geometry::Vector3D *>(VT_POSITION);
} }
Geometry::Vector3D *mutable_position() {
return GetStruct<Geometry::Vector3D *>(VT_POSITION);
}
const Geometry::Vector3D *position_inline() const { const Geometry::Vector3D *position_inline() const {
return GetStruct<const Geometry::Vector3D *>(VT_POSITION_INLINE); return GetStruct<const Geometry::Vector3D *>(VT_POSITION_INLINE);
} }
Geometry::Vector3D *mutable_position_inline() {
return GetStruct<Geometry::Vector3D *>(VT_POSITION_INLINE);
}
const Geometry::Matrix *matrix() const { const Geometry::Matrix *matrix() const {
return GetPointer<const Geometry::Matrix *>(VT_MATRIX); return GetPointer<const Geometry::Matrix *>(VT_MATRIX);
} }
Geometry::Matrix *mutable_matrix() {
return GetPointer<Geometry::Matrix *>(VT_MATRIX);
}
const ::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *matrices() const { const ::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *matrices() const {
return GetPointer<const ::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *>(VT_MATRICES); return GetPointer<const ::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *>(VT_MATRICES);
} }
::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *mutable_matrices() {
return GetPointer<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *>(VT_MATRICES);
}
template <bool B = false> template <bool B = false>
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const { bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
@@ -351,6 +303,11 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(
return builder_.Finish(); return builder_.Finish();
} }
struct ApplicationData::Traits {
using type = ApplicationData;
static auto constexpr Create = CreateApplicationData;
};
inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect( inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
::flatbuffers::FlatBufferBuilder &_fbb, ::flatbuffers::FlatBufferBuilder &_fbb,
const std::vector<Geometry::Vector3D> *vectors = nullptr, const std::vector<Geometry::Vector3D> *vectors = nullptr,
@@ -375,7 +332,7 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); ::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
inline Native::Matrix *Matrix::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { inline Native::Matrix *Matrix::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const {
auto _o = std::unique_ptr<Native::Matrix>(new Native::Matrix()); auto _o = std::make_unique<Native::Matrix>();
UnPackTo(_o.get(), _resolver); UnPackTo(_o.get(), _resolver);
return _o.release(); return _o.release();
} }
@@ -421,7 +378,7 @@ inline ApplicationDataT &ApplicationDataT::operator=(ApplicationDataT o) FLATBUF
} }
inline ApplicationDataT *ApplicationData::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { inline ApplicationDataT *ApplicationData::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const {
auto _o = std::unique_ptr<ApplicationDataT>(new ApplicationDataT()); auto _o = std::make_unique<ApplicationDataT>();
UnPackTo(_o.get(), _resolver); UnPackTo(_o.get(), _resolver);
return _o.release(); return _o.release();
} }
@@ -461,87 +418,6 @@ inline ::flatbuffers::Offset<ApplicationData> ApplicationData::Pack(::flatbuffer
_matrices); _matrices);
} }
inline const ::flatbuffers::TypeTable *Vector3DTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_FLOAT, 0, -1 },
{ ::flatbuffers::ET_FLOAT, 0, -1 },
{ ::flatbuffers::ET_FLOAT, 0, -1 }
};
static const int64_t values[] = { 0, 4, 8, 12 };
static const char * const names[] = {
"x",
"y",
"z"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 3, type_codes, nullptr, nullptr, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *Vector3DAltTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_FLOAT, 0, -1 },
{ ::flatbuffers::ET_FLOAT, 0, -1 },
{ ::flatbuffers::ET_FLOAT, 0, -1 }
};
static const int64_t values[] = { 0, 4, 8, 12 };
static const char * const names[] = {
"a",
"b",
"c"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 3, type_codes, nullptr, nullptr, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *MatrixTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_INT, 0, -1 },
{ ::flatbuffers::ET_INT, 0, -1 },
{ ::flatbuffers::ET_FLOAT, 1, -1 }
};
static const char * const names[] = {
"rows",
"columns",
"values"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_TABLE, 3, type_codes, nullptr, nullptr, nullptr, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_SEQUENCE, 1, 0 },
{ ::flatbuffers::ET_SEQUENCE, 1, 1 },
{ ::flatbuffers::ET_SEQUENCE, 0, 0 },
{ ::flatbuffers::ET_SEQUENCE, 0, 0 },
{ ::flatbuffers::ET_SEQUENCE, 0, 2 },
{ ::flatbuffers::ET_SEQUENCE, 1, 2 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
Geometry::Vector3DTypeTable,
Geometry::Vector3DAltTypeTable,
Geometry::MatrixTypeTable
};
static const char * const names[] = {
"vectors",
"vectors_alt",
"position",
"position_inline",
"matrix",
"matrices"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_TABLE, 6, type_codes, type_refs, nullptr, nullptr, names
};
return &tt;
}
inline const Geometry::ApplicationData *GetApplicationData(const void *buf) { inline const Geometry::ApplicationData *GetApplicationData(const void *buf) {
return ::flatbuffers::GetRoot<Geometry::ApplicationData>(buf); return ::flatbuffers::GetRoot<Geometry::ApplicationData>(buf);
} }
@@ -550,14 +426,6 @@ inline const Geometry::ApplicationData *GetSizePrefixedApplicationData(const voi
return ::flatbuffers::GetSizePrefixedRoot<Geometry::ApplicationData>(buf); return ::flatbuffers::GetSizePrefixedRoot<Geometry::ApplicationData>(buf);
} }
inline ApplicationData *GetMutableApplicationData(void *buf) {
return ::flatbuffers::GetMutableRoot<ApplicationData>(buf);
}
inline Geometry::ApplicationData *GetMutableSizePrefixedApplicationData(void *buf) {
return ::flatbuffers::GetMutableSizePrefixedRoot<Geometry::ApplicationData>(buf);
}
template <bool B = false> template <bool B = false>
inline bool VerifyApplicationDataBuffer( inline bool VerifyApplicationDataBuffer(
::flatbuffers::VerifierTemplate<B> &verifier) { ::flatbuffers::VerifierTemplate<B> &verifier) {
@@ -570,6 +438,10 @@ inline bool VerifySizePrefixedApplicationDataBuffer(
return verifier.template VerifySizePrefixedBuffer<Geometry::ApplicationData>(nullptr); return verifier.template VerifySizePrefixedBuffer<Geometry::ApplicationData>(nullptr);
} }
inline const char *ApplicationDataExtension() {
return "bfbs";
}
inline void FinishApplicationDataBuffer( inline void FinishApplicationDataBuffer(
::flatbuffers::FlatBufferBuilder &fbb, ::flatbuffers::FlatBufferBuilder &fbb,
::flatbuffers::Offset<Geometry::ApplicationData> root) { ::flatbuffers::Offset<Geometry::ApplicationData> root) {
+1
View File
@@ -43,6 +43,7 @@ struct Matrix {
(values == other.values); (values == other.values);
} }
}; };
} // namespace Native } // namespace Native
namespace Geometry { namespace Geometry {
+11
View File
@@ -97,6 +97,17 @@ void ErrorTest() {
"datatype already"); "datatype already");
TestError("struct X (force_align: 7) { Y:int; }", "force_align"); TestError("struct X (force_align: 7) { Y:int; }", "force_align");
TestError("struct X {}", "size 0"); TestError("struct X {}", "size 0");
TestError(
"struct X { Y:int; } table T { y:X (bigfoot_ref:\"::Foo::Bar\"); "
"}",
"'bigfoot_ref_wrapper' attribute");
TestError(
"table T { y:int (bigfoot_ref:\"::Foo::Bar\"); }",
"struct-typed fields");
TestError(
"struct X (bigfoot_ref_wrapper: \"Foo\") { Y:int; } "
"table T { y:X (bigfoot_ref:\"\"); }",
"cannot be empty");
TestError("{}", "no root"); TestError("{}", "no root");
TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file"); TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }", TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
+5 -1
View File
@@ -66,6 +66,8 @@
#include "native_type_test_generated.h" #include "native_type_test_generated.h"
#include "test_assert.h" #include "test_assert.h"
#include "util_test.h" #include "util_test.h"
#include "cpp_vector_type_test.h"
#include "bigfoot_ref_test_impl.h"
#include "vector_table_naked_ptr_test.h" #include "vector_table_naked_ptr_test.h"
void FlatBufferBuilderTest(); void FlatBufferBuilderTest();
@@ -950,7 +952,6 @@ void NativeTypeTest() {
TEST_EQ(dstDataT->position_inline.x, 4.0f); TEST_EQ(dstDataT->position_inline.x, 4.0f);
TEST_EQ(dstDataT->position_inline.y, 5.0f); TEST_EQ(dstDataT->position_inline.y, 5.0f);
TEST_EQ(dstDataT->position_inline.z, 6.0f); TEST_EQ(dstDataT->position_inline.z, 6.0f);
for (int i = 0; i < N; ++i) { for (int i = 0; i < N; ++i) {
const Native::Vector3D& v = dstDataT->vectors[i]; const Native::Vector3D& v = dstDataT->vectors[i];
TEST_EQ(v.x, 10 * i + 0.1f); TEST_EQ(v.x, 10 * i + 0.1f);
@@ -1744,6 +1745,8 @@ int FlatBufferTests(const std::string& tests_data_path) {
AlignmentTest(); AlignmentTest();
CppVectorTypeTest();
#ifndef FLATBUFFERS_NO_FILE_TESTS #ifndef FLATBUFFERS_NO_FILE_TESTS
ParseAndGenerateTextTest(tests_data_path, false); ParseAndGenerateTextTest(tests_data_path, false);
ParseAndGenerateTextTest(tests_data_path, true); ParseAndGenerateTextTest(tests_data_path, true);
@@ -1813,6 +1816,7 @@ int FlatBufferTests(const std::string& tests_data_path) {
InvalidFloatTest(); InvalidFloatTest();
FixedLengthArrayTest(); FixedLengthArrayTest();
NativeTypeTest(); NativeTypeTest();
flatbuffers::tests::BigfootRefTest();
OptionalScalarsTest(); OptionalScalarsTest();
ParseFlexbuffersFromJsonWithNullTest(); ParseFlexbuffersFromJsonWithNullTest();
FlatbuffersSpanTest(); FlatbuffersSpanTest();
+152
View File
@@ -0,0 +1,152 @@
#ifndef TESTS_TEST_VECTOR_TYPE_H_
#define TESTS_TEST_VECTOR_TYPE_H_
#include <cstddef>
#include <new>
#include <utility>
namespace flatbuffers {
namespace tests {
// A minimal stand-in for a custom vector-like container (e.g.
// eastl::vector), used to exercise the --cpp-vector-type flatc option.
//
// This is deliberately its own contiguous container rather than a wrapper
// around std::vector, so that:
// - generated code can't silently keep depending on any of the
// std::vector-specific overloads in flatbuffer_builder.h (e.g.
// CreateVector(const std::vector<T,Alloc>&)), and
// - CustomVector<bool> stores plain contiguous bools accessible via
// data(), unlike std::vector<bool>'s bit-packed specialization, matching
// how real alternative containers such as eastl::vector behave.
template<typename T>
class CustomVector {
public:
using value_type = T;
using iterator = T*;
using const_iterator = const T*;
CustomVector() = default;
CustomVector(const CustomVector& o) { assign_copy(o); }
CustomVector(CustomVector&& o) noexcept { steal(o); }
CustomVector& operator=(const CustomVector& o) {
if (this != &o) {
destroy_all();
deallocate();
assign_copy(o);
}
return *this;
}
CustomVector& operator=(CustomVector&& o) noexcept {
if (this != &o) {
destroy_all();
deallocate();
steal(o);
}
return *this;
}
~CustomVector() {
destroy_all();
deallocate();
}
void reserve(size_t n) {
if (n > capacity_) grow_to(n);
}
void resize(size_t n) {
if (n > capacity_) grow_to(n);
for (size_t i = n; i < size_; ++i) data_[i].~T();
for (size_t i = size_; i < n; ++i) new (&data_[i]) T();
size_ = n;
}
size_t size() const { return size_; }
bool empty() const { return size_ == 0; }
T* data() { return data_; }
const T* data() const { return data_; }
T& operator[](size_t i) { return data_[i]; }
const T& operator[](size_t i) const { return data_[i]; }
template<typename... Args>
void emplace_back(Args&&... args) {
if (size_ == capacity_) grow_to(capacity_ == 0 ? 1 : capacity_ * 2);
new (&data_[size_]) T(std::forward<Args>(args)...);
++size_;
}
void push_back(const T& v) { emplace_back(v); }
iterator begin() { return data_; }
iterator end() { return data_ + size_; }
const_iterator begin() const { return data_; }
const_iterator end() const { return data_ + size_; }
const_iterator cbegin() const { return data_; }
const_iterator cend() const { return data_ + size_; }
private:
void grow_to(size_t n) {
T* new_data = static_cast<T*>(::operator new(n * sizeof(T)));
for (size_t i = 0; i < size_; ++i) {
new (&new_data[i]) T(std::move(data_[i]));
data_[i].~T();
}
::operator delete(data_);
data_ = new_data;
capacity_ = n;
}
void assign_copy(const CustomVector& o) {
data_ = o.size_ ? static_cast<T*>(::operator new(o.size_ * sizeof(T)))
: nullptr;
capacity_ = o.size_;
for (size_t i = 0; i < o.size_; ++i) new (&data_[i]) T(o.data_[i]);
size_ = o.size_;
}
void steal(CustomVector& o) {
data_ = o.data_;
size_ = o.size_;
capacity_ = o.capacity_;
o.data_ = nullptr;
o.size_ = o.capacity_ = 0;
}
void destroy_all() {
for (size_t i = 0; i < size_; ++i) data_[i].~T();
size_ = 0;
}
void deallocate() {
::operator delete(data_);
data_ = nullptr;
capacity_ = 0;
}
T* data_ = nullptr;
size_t size_ = 0;
size_t capacity_ = 0;
};
template<typename T>
bool operator==(const CustomVector<T>& lhs, const CustomVector<T>& rhs) {
if (lhs.size() != rhs.size()) return false;
for (size_t i = 0; i < lhs.size(); ++i) {
if (!(lhs[i] == rhs[i])) return false;
}
return true;
}
template<typename T>
bool operator!=(const CustomVector<T>& lhs, const CustomVector<T>& rhs) {
return !(lhs == rhs);
}
} // namespace tests
} // namespace flatbuffers
#endif // TESTS_TEST_VECTOR_TYPE_H_