mirror of
https://github.com/google/flatbuffers.git
synced 2026-08-03 20:11:55 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b7f602ea8 | |||
| a06c41f2c7 | |||
| 4f6ad45b0e | |||
| 81e5f093f9 |
@@ -238,8 +238,13 @@ set(FlatBuffers_Tests_SRCS
|
||||
tests/util_test.cpp
|
||||
tests/vector_table_naked_ptr_test.h
|
||||
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.cpp
|
||||
tests/bigfoot_ref_test_impl.h
|
||||
tests/bigfoot_ref_test_impl.cpp
|
||||
tests/alignment_test.h
|
||||
tests/alignment_test.cpp
|
||||
tests/64bit/offset64_test.h
|
||||
@@ -548,17 +553,20 @@ if(FLATBUFFERS_BUILD_TESTS)
|
||||
# The flattest target needs some generated files
|
||||
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_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_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/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/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/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/v2.fbs "${FLATC_OPT_COMP}")
|
||||
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)
|
||||
add_fsanitize_to_target(flattests ${FLATBUFFERS_CODE_SANITIZE})
|
||||
|
||||
@@ -168,6 +168,12 @@ list of `FILES...`.
|
||||
std::string from Flatbuffers, but (char* + length). This allows efficient
|
||||
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++
|
||||
object-based API.
|
||||
|
||||
|
||||
@@ -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 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,
|
||||
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)
|
||||
|
||||
There is experimental support for reflection in FlatBuffers, allowing you to
|
||||
|
||||
@@ -142,6 +142,19 @@
|
||||
#define FLATBUFFERS_VERSION_MAJOR 25
|
||||
#define FLATBUFFERS_VERSION_MINOR 12
|
||||
#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(X) FLATBUFFERS_STRING_EXPAND(X)
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -677,6 +677,7 @@ struct IDLOptions {
|
||||
std::string cpp_object_api_pointer_type;
|
||||
std::string cpp_object_api_string_type;
|
||||
bool cpp_object_api_string_flexible_constructor;
|
||||
std::string cpp_object_api_vector_type;
|
||||
CaseStyle cpp_object_api_field_case_style;
|
||||
bool cpp_direct_copy;
|
||||
bool gen_nullable;
|
||||
@@ -1012,10 +1013,13 @@ class Parser : public ParserState {
|
||||
known_attributes_["cpp_ptr_type_get"] = true;
|
||||
known_attributes_["cpp_str_type"] = true;
|
||||
known_attributes_["cpp_str_flex_ctor"] = true;
|
||||
known_attributes_["cpp_vector_type"] = true;
|
||||
known_attributes_["native_inline"] = true;
|
||||
known_attributes_["native_custom_alloc"] = true;
|
||||
known_attributes_["native_type"] = 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_["flexbuffer"] = true;
|
||||
known_attributes_["private"] = true;
|
||||
|
||||
@@ -251,6 +251,21 @@ flatc(
|
||||
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(
|
||||
BASE_OPTS + CPP_OPTS + CS_OPTS + JAVA_OPTS + KOTLIN_OPTS + PHP_OPTS,
|
||||
prefix="union_vector",
|
||||
|
||||
@@ -145,6 +145,12 @@ const static FlatCOption flatc_options[] = {
|
||||
{"", "cpp-str-flex-ctor", "",
|
||||
"Don't construct custom string types by passing std::string from "
|
||||
"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",
|
||||
"Generate C++ fields using selected case style. Supported STYLE values: * "
|
||||
"'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];
|
||||
} else if (arg == "--cpp-str-flex-ctor") {
|
||||
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") {
|
||||
opts.cpp_direct_copy = false;
|
||||
} else if (arg == "--cpp-field-case-style") {
|
||||
|
||||
+275
-25
@@ -257,6 +257,19 @@ class CppGenerator : public BaseGenerator {
|
||||
code_ += " FLATBUFFERS_VERSION_REVISION == " +
|
||||
std::to_string(FLATBUFFERS_VERSION_REVISION) + ",";
|
||||
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() {
|
||||
@@ -529,6 +542,8 @@ class CppGenerator : public BaseGenerator {
|
||||
code_ += "";
|
||||
}
|
||||
|
||||
GenerateBigfootRefForwardDecls();
|
||||
|
||||
// Generate preablmle code for mini reflection.
|
||||
if (opts_.mini_reflect != IDLOptions::kNone) {
|
||||
// To break cyclic dependencies, first pre-declare all tables/structs.
|
||||
@@ -758,6 +773,8 @@ class CppGenerator : public BaseGenerator {
|
||||
|
||||
if (cur_name_space_) SetNameSpace(nullptr);
|
||||
|
||||
GenerateBigfootRefImpls();
|
||||
|
||||
// Close the include guard.
|
||||
code_ += "#endif // " + include_guard;
|
||||
|
||||
@@ -892,6 +909,24 @@ class CppGenerator : public BaseGenerator {
|
||||
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,
|
||||
const IDLOptions& opts) {
|
||||
// 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.
|
||||
}
|
||||
|
||||
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,
|
||||
bool is_constructor) {
|
||||
auto& ptr_type = PtrType(field);
|
||||
@@ -974,20 +1026,21 @@ class CppGenerator : public BaseGenerator {
|
||||
case BASE_TYPE_VECTOR64:
|
||||
case BASE_TYPE_VECTOR: {
|
||||
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")) {
|
||||
auto native_custom_alloc =
|
||||
type.struct_def->attributes.Lookup("native_custom_alloc");
|
||||
return "std::vector<" + type_name + "," +
|
||||
native_custom_alloc->constant + "<" + type_name + ">>";
|
||||
} else {
|
||||
return "std::vector<" + type_name + ">";
|
||||
return vector_type + "<" + type_name + ">";
|
||||
}
|
||||
}
|
||||
case BASE_TYPE_STRUCT: {
|
||||
auto type_name = WrapInNameSpace(*type.struct_def);
|
||||
if (IsStruct(type)) {
|
||||
auto native_type = type.struct_def->attributes.Lookup("native_type");
|
||||
auto native_type = EffectiveNativeType(field, *type.struct_def);
|
||||
if (native_type) {
|
||||
type_name = native_type->constant;
|
||||
}
|
||||
@@ -1979,7 +2032,7 @@ class CppGenerator : public BaseGenerator {
|
||||
const std::string& full_type =
|
||||
(cpp_type
|
||||
? (IsVector(field.value.type)
|
||||
? "std::vector<" +
|
||||
? NativeVectorType(&field) + "<" +
|
||||
GenTypeNativePtr(cpp_type->constant, &field,
|
||||
false) +
|
||||
"> "
|
||||
@@ -3515,11 +3568,11 @@ class CppGenerator : public BaseGenerator {
|
||||
}
|
||||
case BASE_TYPE_STRUCT: {
|
||||
if (IsStruct(type)) {
|
||||
const auto& struct_attrs = type.struct_def->attributes;
|
||||
const auto native_type = struct_attrs.Lookup("native_type");
|
||||
const auto native_type = EffectiveNativeType(afield, *type.struct_def);
|
||||
if (native_type) {
|
||||
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) {
|
||||
unpack_call += pack_name->constant;
|
||||
}
|
||||
@@ -3772,13 +3825,22 @@ class CppGenerator : public BaseGenerator {
|
||||
case BASE_TYPE_VECTOR64:
|
||||
case BASE_TYPE_VECTOR: {
|
||||
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) {
|
||||
case BASE_TYPE_STRING: {
|
||||
if (NativeString(&field) == "std::string") {
|
||||
if (!custom_vector && NativeString(&field) == "std::string") {
|
||||
code += "_fbb.CreateVectorOfStrings(" + value + ")";
|
||||
} else {
|
||||
// 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 +=
|
||||
"_fbb.CreateVector<::flatbuffers::Offset<::flatbuffers::"
|
||||
"String>>"
|
||||
@@ -3793,20 +3855,37 @@ class CppGenerator : public BaseGenerator {
|
||||
}
|
||||
case BASE_TYPE_STRUCT: {
|
||||
if (IsStruct(vector_type)) {
|
||||
const auto& struct_attrs =
|
||||
field.value.type.struct_def->attributes;
|
||||
const auto native_type = struct_attrs.Lookup("native_type");
|
||||
const auto native_type =
|
||||
EffectiveNativeType(field, *field.value.type.struct_def);
|
||||
if (native_type) {
|
||||
code += "_fbb.CreateVectorOfNativeStructs<";
|
||||
code += WrapInNameSpace(*vector_type.struct_def) + ", " +
|
||||
native_type->constant + ">";
|
||||
code += "(" + value;
|
||||
const auto pack_name =
|
||||
struct_attrs.Lookup("native_type_pack_name");
|
||||
if (custom_vector) {
|
||||
code += "(" + value + ".data(), " + value + ".size()";
|
||||
} else {
|
||||
code += "(" + value;
|
||||
}
|
||||
const auto pack_name = EffectiveNativeTypePackName(
|
||||
field, *field.value.type.struct_def);
|
||||
if (pack_name) {
|
||||
code += ", ::flatbuffers::Pack" + pack_name->constant;
|
||||
}
|
||||
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 {
|
||||
// If the field uses 64-bit addressing, create a 64-bit vector.
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
|
||||
@@ -3818,7 +3897,11 @@ class CppGenerator : public BaseGenerator {
|
||||
code += "64<::flatbuffers::Vector>";
|
||||
}
|
||||
}
|
||||
code += "(" + value + ")";
|
||||
if (custom_vector) {
|
||||
code += "(" + value + ".data(), " + value + ".size())";
|
||||
} else {
|
||||
code += "(" + value + ")";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
code += "_fbb.CreateVector<::flatbuffers::Offset<";
|
||||
@@ -3837,7 +3920,17 @@ class CppGenerator : public BaseGenerator {
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
case BASE_TYPE_UNION: {
|
||||
@@ -3873,9 +3966,11 @@ class CppGenerator : public BaseGenerator {
|
||||
// the underlying storage type (eg. uint8_t).
|
||||
const auto basetype = GenTypeBasic(
|
||||
field.value.type.enum_def->underlying_type, false);
|
||||
code += "_fbb.CreateVectorScalarCast<" + basetype +
|
||||
">(::flatbuffers::data(" + value + "), " + value +
|
||||
".size())";
|
||||
const std::string data_ptr =
|
||||
custom_vector ? value + ".data()"
|
||||
: "::flatbuffers::data(" + value + ")";
|
||||
code += "_fbb.CreateVectorScalarCast<" + basetype + ">(" +
|
||||
data_ptr + ", " + value + ".size())";
|
||||
} else if (field.attributes.Lookup("cpp_type")) {
|
||||
auto type = GenTypeBasic(vector_type, false);
|
||||
code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
|
||||
@@ -3884,6 +3979,27 @@ class CppGenerator : public BaseGenerator {
|
||||
code += "static_cast<" + type + ">((*__va->__rehasher)";
|
||||
code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
|
||||
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 {
|
||||
// If the field uses 64-bit addressing, create a 64-bit vector.
|
||||
if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
|
||||
@@ -3917,12 +4033,12 @@ class CppGenerator : public BaseGenerator {
|
||||
}
|
||||
case BASE_TYPE_STRUCT: {
|
||||
if (IsStruct(field.value.type)) {
|
||||
const auto& struct_attribs = field.value.type.struct_def->attributes;
|
||||
const auto native_type = struct_attribs.Lookup("native_type");
|
||||
const auto native_type =
|
||||
EffectiveNativeType(field, *field.value.type.struct_def);
|
||||
if (native_type && field.native_inline) {
|
||||
code += "::flatbuffers::Pack";
|
||||
const auto pack_name =
|
||||
struct_attribs.Lookup("native_type_pack_name");
|
||||
EffectiveNativeTypePackName(field, *field.value.type.struct_def);
|
||||
if (pack_name) {
|
||||
code += pack_name->constant;
|
||||
}
|
||||
@@ -4087,8 +4203,7 @@ class CppGenerator : public BaseGenerator {
|
||||
if (field->value.type.base_type == BASE_TYPE_STRUCT) {
|
||||
if (IsStruct(field->value.type)) {
|
||||
auto native_type =
|
||||
field->value.type.struct_def->attributes.Lookup(
|
||||
"native_type");
|
||||
EffectiveNativeType(*field, *field->value.type.struct_def);
|
||||
auto native_inline = field->attributes.Lookup("native_inline");
|
||||
if (native_type) {
|
||||
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
|
||||
// different (closing/opening only what is necessary).
|
||||
//
|
||||
|
||||
@@ -1286,6 +1286,55 @@ CheckedError Parser::ParseField(StructDef& struct_def) {
|
||||
"'native_inline' can only be defined on structs, vector of structs or "
|
||||
"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");
|
||||
if (nested) {
|
||||
if (nested->type.base_type != BASE_TYPE_STRING)
|
||||
|
||||
@@ -78,6 +78,9 @@ cc_test(
|
||||
"vector_table_naked_ptr/vector_table_naked_ptr_generated.h",
|
||||
"vector_table_naked_ptr_test.h",
|
||||
"vector_table_naked_ptr_test.cpp",
|
||||
"test_vector_type.h",
|
||||
"cpp_vector_type_test.h",
|
||||
"cpp_vector_type_test.cpp",
|
||||
],
|
||||
copts = [
|
||||
"-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE",
|
||||
@@ -136,6 +139,7 @@ cc_test(
|
||||
deps = [
|
||||
":alignment_test_cc_fbs",
|
||||
":arrays_test_cc_fbs",
|
||||
":cpp_vector_type_cc_fbs",
|
||||
":default_vectors_strings_test_cc_fbs",
|
||||
":monster_extra_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(
|
||||
name = "alignment_test_cc_fbs",
|
||||
srcs = ["alignment_test.fbs"],
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -31,14 +31,6 @@ struct ApplicationDataT;
|
||||
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 {
|
||||
private:
|
||||
float x_;
|
||||
@@ -46,9 +38,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS {
|
||||
float z_;
|
||||
|
||||
public:
|
||||
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
|
||||
return Vector3DTypeTable();
|
||||
}
|
||||
struct Traits;
|
||||
Vector3D()
|
||||
: x_(0),
|
||||
y_(0),
|
||||
@@ -62,24 +52,19 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS {
|
||||
float x() const {
|
||||
return ::flatbuffers::EndianScalar(x_);
|
||||
}
|
||||
void mutate_x(float _x) {
|
||||
::flatbuffers::WriteScalar(&x_, _x);
|
||||
}
|
||||
float y() const {
|
||||
return ::flatbuffers::EndianScalar(y_);
|
||||
}
|
||||
void mutate_y(float _y) {
|
||||
::flatbuffers::WriteScalar(&y_, _y);
|
||||
}
|
||||
float z() const {
|
||||
return ::flatbuffers::EndianScalar(z_);
|
||||
}
|
||||
void mutate_z(float _z) {
|
||||
::flatbuffers::WriteScalar(&z_, _z);
|
||||
}
|
||||
};
|
||||
FLATBUFFERS_STRUCT_END(Vector3D, 12);
|
||||
|
||||
struct Vector3D::Traits {
|
||||
using type = Vector3D;
|
||||
};
|
||||
|
||||
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
|
||||
private:
|
||||
float a_;
|
||||
@@ -87,9 +72,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
|
||||
float c_;
|
||||
|
||||
public:
|
||||
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
|
||||
return Vector3DAltTypeTable();
|
||||
}
|
||||
struct Traits;
|
||||
Vector3DAlt()
|
||||
: a_(0),
|
||||
b_(0),
|
||||
@@ -103,30 +86,23 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
|
||||
float a() const {
|
||||
return ::flatbuffers::EndianScalar(a_);
|
||||
}
|
||||
void mutate_a(float _a) {
|
||||
::flatbuffers::WriteScalar(&a_, _a);
|
||||
}
|
||||
float b() const {
|
||||
return ::flatbuffers::EndianScalar(b_);
|
||||
}
|
||||
void mutate_b(float _b) {
|
||||
::flatbuffers::WriteScalar(&b_, _b);
|
||||
}
|
||||
float c() const {
|
||||
return ::flatbuffers::EndianScalar(c_);
|
||||
}
|
||||
void mutate_c(float _c) {
|
||||
::flatbuffers::WriteScalar(&c_, _c);
|
||||
}
|
||||
};
|
||||
FLATBUFFERS_STRUCT_END(Vector3DAlt, 12);
|
||||
|
||||
struct Vector3DAlt::Traits {
|
||||
using type = Vector3DAlt;
|
||||
};
|
||||
|
||||
struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
typedef Native::Matrix NativeTableType;
|
||||
typedef MatrixBuilder Builder;
|
||||
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
|
||||
return MatrixTypeTable();
|
||||
}
|
||||
struct Traits;
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_ROWS = 4,
|
||||
VT_COLUMNS = 6,
|
||||
@@ -135,21 +111,12 @@ struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
int32_t rows() const {
|
||||
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 {
|
||||
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 {
|
||||
return GetPointer<const ::flatbuffers::Vector<float> *>(VT_VALUES);
|
||||
}
|
||||
::flatbuffers::Vector<float> *mutable_values() {
|
||||
return GetPointer<::flatbuffers::Vector<float> *>(VT_VALUES);
|
||||
}
|
||||
template <bool B = false>
|
||||
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
@@ -200,6 +167,11 @@ inline ::flatbuffers::Offset<Matrix> CreateMatrix(
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct Matrix::Traits {
|
||||
using type = Matrix;
|
||||
static auto constexpr Create = CreateMatrix;
|
||||
};
|
||||
|
||||
inline ::flatbuffers::Offset<Matrix> CreateMatrixDirect(
|
||||
::flatbuffers::FlatBufferBuilder &_fbb,
|
||||
int32_t rows = 0,
|
||||
@@ -232,9 +204,7 @@ struct ApplicationDataT : public ::flatbuffers::NativeTable {
|
||||
struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
typedef ApplicationDataT NativeTableType;
|
||||
typedef ApplicationDataBuilder Builder;
|
||||
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
|
||||
return ApplicationDataTypeTable();
|
||||
}
|
||||
struct Traits;
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_VECTORS = 4,
|
||||
VT_VECTORS_ALT = 6,
|
||||
@@ -246,39 +216,21 @@ struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
|
||||
const ::flatbuffers::Vector<const Geometry::Vector3D *> *vectors() const {
|
||||
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 {
|
||||
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 {
|
||||
return GetStruct<const Geometry::Vector3D *>(VT_POSITION);
|
||||
}
|
||||
Geometry::Vector3D *mutable_position() {
|
||||
return GetStruct<Geometry::Vector3D *>(VT_POSITION);
|
||||
}
|
||||
const Geometry::Vector3D *position_inline() const {
|
||||
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 {
|
||||
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 {
|
||||
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>
|
||||
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
@@ -351,6 +303,11 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
struct ApplicationData::Traits {
|
||||
using type = ApplicationData;
|
||||
static auto constexpr Create = CreateApplicationData;
|
||||
};
|
||||
|
||||
inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
|
||||
::flatbuffers::FlatBufferBuilder &_fbb,
|
||||
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);
|
||||
|
||||
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);
|
||||
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 {
|
||||
auto _o = std::unique_ptr<ApplicationDataT>(new ApplicationDataT());
|
||||
auto _o = std::make_unique<ApplicationDataT>();
|
||||
UnPackTo(_o.get(), _resolver);
|
||||
return _o.release();
|
||||
}
|
||||
@@ -461,87 +418,6 @@ inline ::flatbuffers::Offset<ApplicationData> ApplicationData::Pack(::flatbuffer
|
||||
_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) {
|
||||
return ::flatbuffers::GetRoot<Geometry::ApplicationData>(buf);
|
||||
}
|
||||
@@ -550,14 +426,6 @@ inline const Geometry::ApplicationData *GetSizePrefixedApplicationData(const voi
|
||||
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>
|
||||
inline bool VerifyApplicationDataBuffer(
|
||||
::flatbuffers::VerifierTemplate<B> &verifier) {
|
||||
@@ -570,6 +438,10 @@ inline bool VerifySizePrefixedApplicationDataBuffer(
|
||||
return verifier.template VerifySizePrefixedBuffer<Geometry::ApplicationData>(nullptr);
|
||||
}
|
||||
|
||||
inline const char *ApplicationDataExtension() {
|
||||
return "bfbs";
|
||||
}
|
||||
|
||||
inline void FinishApplicationDataBuffer(
|
||||
::flatbuffers::FlatBufferBuilder &fbb,
|
||||
::flatbuffers::Offset<Geometry::ApplicationData> root) {
|
||||
|
||||
@@ -43,6 +43,7 @@ struct Matrix {
|
||||
(values == other.values);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Native
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
@@ -97,6 +97,17 @@ void ErrorTest() {
|
||||
"datatype already");
|
||||
TestError("struct X (force_align: 7) { Y:int; }", "force_align");
|
||||
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("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 }",
|
||||
|
||||
+5
-1
@@ -66,6 +66,8 @@
|
||||
#include "native_type_test_generated.h"
|
||||
#include "test_assert.h"
|
||||
#include "util_test.h"
|
||||
#include "cpp_vector_type_test.h"
|
||||
#include "bigfoot_ref_test_impl.h"
|
||||
#include "vector_table_naked_ptr_test.h"
|
||||
|
||||
void FlatBufferBuilderTest();
|
||||
@@ -950,7 +952,6 @@ void NativeTypeTest() {
|
||||
TEST_EQ(dstDataT->position_inline.x, 4.0f);
|
||||
TEST_EQ(dstDataT->position_inline.y, 5.0f);
|
||||
TEST_EQ(dstDataT->position_inline.z, 6.0f);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
const Native::Vector3D& v = dstDataT->vectors[i];
|
||||
TEST_EQ(v.x, 10 * i + 0.1f);
|
||||
@@ -1744,6 +1745,8 @@ int FlatBufferTests(const std::string& tests_data_path) {
|
||||
|
||||
AlignmentTest();
|
||||
|
||||
CppVectorTypeTest();
|
||||
|
||||
#ifndef FLATBUFFERS_NO_FILE_TESTS
|
||||
ParseAndGenerateTextTest(tests_data_path, false);
|
||||
ParseAndGenerateTextTest(tests_data_path, true);
|
||||
@@ -1813,6 +1816,7 @@ int FlatBufferTests(const std::string& tests_data_path) {
|
||||
InvalidFloatTest();
|
||||
FixedLengthArrayTest();
|
||||
NativeTypeTest();
|
||||
flatbuffers::tests::BigfootRefTest();
|
||||
OptionalScalarsTest();
|
||||
ParseFlexbuffersFromJsonWithNullTest();
|
||||
FlatbuffersSpanTest();
|
||||
|
||||
@@ -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_
|
||||
Reference in New Issue
Block a user