Compare commits

...

5 Commits

Author SHA1 Message Date
505ec2fb6a Fix CreateVector/CreateVectorOfStructs for non-std vector types (cpp_vec_type)
When cpp_vec_type is set to a non-std container, Pack methods for scalar,
bool, and plain-struct vectors now use the pointer+size overloads of
CreateVector/CreateVectorOfStructs instead of the std::vector-only overloads.
Extends the combined cpp_vec_type+native_type test to also cover scalar
(ubyte) vectors with a custom container type.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 20:48:32 +02:00
19aa2ce420 Fix CreateVectorOfNativeStructs for non-std vector types (cpp_vec_type + native_type)
When a field combines cpp_vec_type (e.g. eastl::vector) with native_type on a
struct, the generated Pack method now uses the pointer+size overload of
CreateVectorOfNativeStructs instead of the std::vector overload, which only
accepts std::vector. Adds a dedicated test covering the combined attribute case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 20:35:36 +02:00
35665b5ae7 Add cpp_vec_type attribute for object API vector customization
Mirrors cpp_str_type and cpp_ptr_type: a per-field cpp_vec_type attribute
lets users substitute any std::vector-compatible container in generated
T-structs, and --cpp-vec-type sets the global default.

NativeVector() resolves the attribute (falling back to the global option,
then std::vector). Changes applied to GenTypeNative, GenMember, GenParam
(CreateDirect), and the CreateVectorOfStrings fast-path guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 19:55:26 +02:00
9e9f5bbfcf Fix field-level native_type for vector pack and CreateTable args
Complete field-level native_type/native_type_pack_name support in C++
codegen by fixing two remaining locations that only checked struct-level
attributes: vector-of-structs packing and CreateTable argument passing.
Add tests with a struct lacking struct-level native_type to verify
field-level attributes work end-to-end.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-09 15:47:07 +02:00
4edfa03ffc native_type and native_inline on fields 2026-05-09 12:23:35 +02:00
15 changed files with 480 additions and 33 deletions

View File

@@ -240,6 +240,9 @@ set(FlatBuffers_Tests_SRCS
tests/vector_table_naked_ptr_test.cpp
tests/native_type_test_impl.h
tests/native_type_test_impl.cpp
tests/cpp_vec_type_test_impl.h
tests/cpp_vec_type_native_type_test_impl.h
tests/cpp_vec_type_native_type_test_impl.cpp
tests/alignment_test.h
tests/alignment_test.cpp
tests/64bit/offset64_test.h
@@ -554,6 +557,8 @@ if(FLATBUFFERS_BUILD_TESTS)
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/cpp_vec_type_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/cpp_vec_type_native_type_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}")

View File

@@ -676,6 +676,7 @@ struct IDLOptions {
bool gen_absl_hash;
std::string cpp_object_api_pointer_type;
std::string cpp_object_api_string_type;
std::string cpp_object_api_vector_type;
bool cpp_object_api_string_flexible_constructor;
CaseStyle cpp_object_api_field_case_style;
bool cpp_direct_copy;
@@ -1012,6 +1013,7 @@ 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_vec_type"] = true;
known_attributes_["native_inline"] = true;
known_attributes_["native_custom_alloc"] = true;
known_attributes_["native_type"] = true;

View File

@@ -383,6 +383,11 @@ flatc(
schema="native_type_test.fbs",
)
flatc(
["--cpp", "--gen-compare", "--gen-mutable", "--gen-object-api", "--reflect-names"],
schema="cpp_vec_type_test.fbs",
)
flatc(
[
"--cpp",

View File

@@ -142,6 +142,10 @@ const static FlatCOption flatc_options[] = {
"and T::empty() must be supported. The custom type also needs to be "
"constructible from std::string (see the --cpp-str-flex-ctor option to "
"change this behavior)"},
{"", "cpp-vec-type", "T",
"Set object API vector type (default std::vector). T must support the "
"same interface as std::vector: size(), resize(), reserve(), "
"emplace_back(), operator[], begin(), end(), and data()."},
{"", "cpp-str-flex-ctor", "",
"Don't construct custom string types by passing std::string from "
"Flatbuffers, but (char* + length)."},
@@ -543,6 +547,9 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc,
} else if (arg == "--cpp-str-type") {
if (++argi >= argc) Error("missing type following: " + arg, true);
opts.cpp_object_api_string_type = argv[argi];
} else if (arg == "--cpp-vec-type") {
if (++argi >= argc) Error("missing type following: " + arg, true);
opts.cpp_object_api_vector_type = argv[argi];
} else if (arg == "--cpp-str-flex-ctor") {
opts.cpp_object_api_string_flexible_constructor = true;
} else if (arg == "--no-cpp-direct-copy") {

View File

@@ -929,6 +929,15 @@ class CppGenerator : public BaseGenerator {
return ret;
}
const std::string NativeVector(const FieldDef* field) {
auto attr = field ? field->attributes.Lookup("cpp_vec_type") : nullptr;
auto& ret = attr ? attr->constant : opts_.cpp_object_api_vector_type;
if (ret.empty()) {
return "std::vector";
}
return ret;
}
bool FlexibleStringConstructor(const FieldDef* field) {
auto attr = field != nullptr &&
(field->attributes.Lookup("cpp_str_flex_ctor") != nullptr);
@@ -974,20 +983,26 @@ 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 vec_type = NativeVector(&field);
if (vec_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 vec_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");
// Field-level native_type takes priority over struct-level
// native_type
auto field_native_type = field.attributes.Lookup("native_type");
auto native_type =
field_native_type
? field_native_type
: type.struct_def->attributes.Lookup("native_type");
if (native_type) {
type_name = native_type->constant;
}
@@ -1951,9 +1966,10 @@ class CppGenerator : public BaseGenerator {
field.offset64);
}
if (TypeHasKey(vtype)) {
code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *");
code_.SetValue("PARAM_TYPE", NativeVector(&field) + "<" + type + "> *");
} else {
code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
code_.SetValue("PARAM_TYPE",
"const " + NativeVector(&field) + "<" + type + "> *");
}
code_.SetValue("PARAM_VALUE", "nullptr");
} else {
@@ -1979,7 +1995,7 @@ class CppGenerator : public BaseGenerator {
const std::string& full_type =
(cpp_type
? (IsVector(field.value.type)
? "std::vector<" +
? NativeVector(&field) + "<" +
GenTypeNativePtr(cpp_type->constant, &field,
false) +
"> "
@@ -3516,10 +3532,21 @@ 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");
// Field-level native_type takes priority over struct-level
// native_type
auto field_native_type = afield.attributes.Lookup("native_type");
const auto native_type = field_native_type
? field_native_type
: struct_attrs.Lookup("native_type");
if (native_type) {
std::string unpack_call = "::flatbuffers::UnPack";
const auto pack_name = struct_attrs.Lookup("native_type_pack_name");
// Field-level native_type_pack_name takes priority over
// struct-level
auto field_pack_name =
afield.attributes.Lookup("native_type_pack_name");
const auto pack_name =
field_pack_name ? field_pack_name
: struct_attrs.Lookup("native_type_pack_name");
if (pack_name) {
unpack_call += pack_name->constant;
}
@@ -3774,7 +3801,8 @@ class CppGenerator : public BaseGenerator {
auto vector_type = field.value.type.VectorType();
switch (vector_type.base_type) {
case BASE_TYPE_STRING: {
if (NativeString(&field) == "std::string") {
if (NativeString(&field) == "std::string" &&
NativeVector(&field) == "std::vector") {
code += "_fbb.CreateVectorOfStrings(" + value + ")";
} else {
// Use by-function serialization to emulate
@@ -3795,30 +3823,52 @@ class CppGenerator : public BaseGenerator {
if (IsStruct(vector_type)) {
const auto& struct_attrs =
field.value.type.struct_def->attributes;
const auto native_type = struct_attrs.Lookup("native_type");
// Field-level native_type takes priority over struct-level
// native_type
auto field_native_type = field.attributes.Lookup("native_type");
const auto native_type = field_native_type
? field_native_type
: struct_attrs.Lookup("native_type");
if (native_type) {
code += "_fbb.CreateVectorOfNativeStructs<";
code += WrapInNameSpace(*vector_type.struct_def) + ", " +
native_type->constant + ">";
code += "(" + value;
// Field-level native_type_pack_name takes priority over
// struct-level
auto field_pack_name =
field.attributes.Lookup("native_type_pack_name");
const auto pack_name =
struct_attrs.Lookup("native_type_pack_name");
field_pack_name
? field_pack_name
: struct_attrs.Lookup("native_type_pack_name");
// Non-std vectors (e.g. eastl::vector) don't match the
// std::vector overload, so use the pointer+size overload.
const bool is_std_vec = NativeVector(&field) == "std::vector";
if (is_std_vec) {
code += "(" + value;
} else {
code += "(" + value + ".data(), " + value + ".size()";
}
if (pack_name) {
code += ", ::flatbuffers::Pack" + pack_name->constant;
}
code += ")";
} else {
// If the field uses 64-bit addressing, create a 64-bit vector.
const bool is_std_vec = NativeVector(&field) == "std::vector";
const std::string vec_args =
is_std_vec ? ("(" + value + ")")
: ("(" + value + ".data(), " + value + ".size())");
if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
code += "_fbb.CreateVectorOfStructs64";
code += "_fbb.CreateVectorOfStructs64" + vec_args;
} else {
code += "_fbb.CreateVectorOfStructs";
if (field.offset64) {
// This is normal 32-bit vector, with 64-bit addressing.
code += "64<::flatbuffers::Vector>";
}
code += vec_args;
}
code += "(" + value + ")";
}
} else {
code += "_fbb.CreateVector<::flatbuffers::Offset<";
@@ -3837,7 +3887,12 @@ class CppGenerator : public BaseGenerator {
break;
}
case BASE_TYPE_BOOL: {
code += "_fbb.CreateVector(" + value + ")";
if (NativeVector(&field) == "std::vector") {
code += "_fbb.CreateVector(" + value + ")";
} else {
code += "_fbb.CreateVector(" + value + ".data(), " + value +
".size())";
}
break;
}
case BASE_TYPE_UNION: {
@@ -3886,15 +3941,19 @@ class CppGenerator : public BaseGenerator {
code += "; }, &_va )";
} else {
// If the field uses 64-bit addressing, create a 64-bit vector.
const bool is_std_vec = NativeVector(&field) == "std::vector";
const std::string vec_args =
is_std_vec ? ("(" + value + ")")
: ("(" + value + ".data(), " + value + ".size())");
if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
code += "_fbb.CreateVector64(" + value + ")";
code += "_fbb.CreateVector64" + vec_args;
} else {
code += "_fbb.CreateVector";
if (field.offset64) {
// This is normal 32-bit vector, with 64-bit addressing.
code += "64<::flatbuffers::Vector>";
}
code += "(" + value + ")";
code += vec_args;
}
}
break;
@@ -3918,11 +3977,22 @@ 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");
// Field-level native_type takes priority over struct-level
// native_type
auto field_native_type = field.attributes.Lookup("native_type");
const auto native_type = field_native_type
? field_native_type
: struct_attribs.Lookup("native_type");
if (native_type && field.native_inline) {
code += "::flatbuffers::Pack";
// Field-level native_type_pack_name takes priority over
// struct-level
auto field_pack_name =
field.attributes.Lookup("native_type_pack_name");
const auto pack_name =
struct_attribs.Lookup("native_type_pack_name");
field_pack_name
? field_pack_name
: struct_attribs.Lookup("native_type_pack_name");
if (pack_name) {
code += pack_name->constant;
}
@@ -4086,9 +4156,15 @@ class CppGenerator : public BaseGenerator {
bool check_ptr = false;
if (field->value.type.base_type == BASE_TYPE_STRUCT) {
if (IsStruct(field->value.type)) {
// Field-level native_type takes priority over struct-level
// native_type
auto field_native_type =
field->attributes.Lookup("native_type");
auto native_type =
field->value.type.struct_def->attributes.Lookup(
"native_type");
field_native_type
? field_native_type
: field->value.type.struct_def->attributes.Lookup(
"native_type");
auto native_inline = field->attributes.Lookup("native_inline");
if (native_type) {
pass_by_address = true;

View File

@@ -0,0 +1,16 @@
native_include "cpp_vec_type_native_type_test_impl.h";
namespace CppVecNativeTypeTest;
struct Vec3 (native_type: "CppVecNativeTypeTest::Native::Vec3") {
x: float;
y: float;
z: float;
}
table Container {
points: [Vec3] (cpp_vec_type: "CppVecNativeTypeTest::CustomVec");
bytes: [ubyte] (cpp_vec_type: "CppVecNativeTypeTest::CustomVec");
}
root_type Container;

View File

@@ -0,0 +1,15 @@
#include "cpp_vec_type_native_type_test_impl.h"
#include "cpp_vec_type_native_type_test_generated.h"
namespace flatbuffers {
CppVecNativeTypeTest::Vec3 Pack(
const CppVecNativeTypeTest::Native::Vec3& obj) {
return CppVecNativeTypeTest::Vec3(obj.x, obj.y, obj.z);
}
const CppVecNativeTypeTest::Native::Vec3 UnPack(
const CppVecNativeTypeTest::Vec3& obj) {
return CppVecNativeTypeTest::Native::Vec3(obj.x(), obj.y(), obj.z());
}
} // namespace flatbuffers

View File

@@ -0,0 +1,34 @@
#ifndef CPP_VEC_TYPE_NATIVE_TYPE_TEST_IMPL_H
#define CPP_VEC_TYPE_NATIVE_TYPE_TEST_IMPL_H
#include <vector>
namespace CppVecNativeTypeTest {
namespace Native {
struct Vec3 {
float x, y, z;
Vec3() : x(0), y(0), z(0) {}
Vec3(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
bool operator==(const Vec3& o) const {
return x == o.x && y == o.y && z == o.z;
}
};
} // namespace Native
template <typename T>
struct CustomVec : public std::vector<T> {
using std::vector<T>::vector;
};
struct Vec3; // flatbuffers-generated struct
} // namespace CppVecNativeTypeTest
namespace flatbuffers {
CppVecNativeTypeTest::Vec3 Pack(const CppVecNativeTypeTest::Native::Vec3& obj);
const CppVecNativeTypeTest::Native::Vec3 UnPack(
const CppVecNativeTypeTest::Vec3& obj);
} // namespace flatbuffers
#endif // CPP_VEC_TYPE_NATIVE_TYPE_TEST_IMPL_H

View File

@@ -0,0 +1,17 @@
native_include "cpp_vec_type_test_impl.h";
namespace CppVecTest;
table Item {
id: int;
value: float;
}
table Data {
values: [int] (cpp_vec_type: "CppVecTest::CustomVec");
items: [Item] (cpp_vec_type: "CppVecTest::CustomVec");
strs: [string] (cpp_vec_type: "CppVecTest::CustomVec");
regular: [int];
}
root_type Data;

View File

@@ -0,0 +1,15 @@
#ifndef CPP_VEC_TYPE_TEST_IMPL_H
#define CPP_VEC_TYPE_TEST_IMPL_H
#include <vector>
namespace CppVecTest {
template<typename T>
struct CustomVec : public std::vector<T> {
using std::vector<T>::vector;
};
} // namespace CppVecTest
#endif // CPP_VEC_TYPE_TEST_IMPL_H

View File

@@ -14,6 +14,12 @@ struct Vector3DAlt (native_type:"Native::Vector3D", native_type_pack_name:"Vecto
c:float;
}
struct Vector3DSimple {
x:float;
y:float;
z:float;
}
table Matrix (native_type:"Native::Matrix") {
rows:int32;
columns:int32;
@@ -27,6 +33,8 @@ table ApplicationData {
position_inline:Vector3D (native_inline);
matrix:Matrix;
matrices:[Matrix];
simple_position:Vector3DSimple (native_type: "Native::Vector3D", native_inline, native_type_pack_name: "Vector3DSimple");
simple_vectors:[Vector3DSimple] (native_type: "Native::Vector3D", native_type_pack_name: "Vector3DSimple");
}
root_type ApplicationData;

View File

@@ -21,6 +21,8 @@ struct Vector3D;
struct Vector3DAlt;
struct Vector3DSimple;
struct Matrix;
struct MatrixBuilder;
@@ -28,6 +30,8 @@ struct ApplicationData;
struct ApplicationDataBuilder;
struct ApplicationDataT;
bool operator==(const Vector3DSimple &lhs, const Vector3DSimple &rhs);
bool operator!=(const Vector3DSimple &lhs, const Vector3DSimple &rhs);
bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs);
bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs);
@@ -35,6 +39,8 @@ inline const ::flatbuffers::TypeTable *Vector3DTypeTable();
inline const ::flatbuffers::TypeTable *Vector3DAltTypeTable();
inline const ::flatbuffers::TypeTable *Vector3DSimpleTypeTable();
inline const ::flatbuffers::TypeTable *MatrixTypeTable();
inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable();
@@ -121,6 +127,59 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
};
FLATBUFFERS_STRUCT_END(Vector3DAlt, 12);
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DSimple FLATBUFFERS_FINAL_CLASS {
private:
float x_;
float y_;
float z_;
public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return Vector3DSimpleTypeTable();
}
Vector3DSimple()
: x_(0),
y_(0),
z_(0) {
}
Vector3DSimple(float _x, float _y, float _z)
: x_(::flatbuffers::EndianScalar(_x)),
y_(::flatbuffers::EndianScalar(_y)),
z_(::flatbuffers::EndianScalar(_z)) {
}
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(Vector3DSimple, 12);
inline bool operator==(const Vector3DSimple &lhs, const Vector3DSimple &rhs) {
return
(lhs.x() == rhs.x()) &&
(lhs.y() == rhs.y()) &&
(lhs.z() == rhs.z());
}
inline bool operator!=(const Vector3DSimple &lhs, const Vector3DSimple &rhs) {
return !(lhs == rhs);
}
struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef Native::Matrix NativeTableType;
typedef MatrixBuilder Builder;
@@ -223,6 +282,8 @@ struct ApplicationDataT : public ::flatbuffers::NativeTable {
Native::Vector3D position_inline{};
std::unique_ptr<Native::Matrix> matrix{};
std::vector<std::unique_ptr<Native::Matrix>> matrices{};
Native::Vector3D simple_position{};
std::vector<Native::Vector3D> simple_vectors{};
ApplicationDataT() = default;
ApplicationDataT(const ApplicationDataT &o);
ApplicationDataT(ApplicationDataT&&) FLATBUFFERS_NOEXCEPT = default;
@@ -241,7 +302,9 @@ struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
VT_POSITION = 8,
VT_POSITION_INLINE = 10,
VT_MATRIX = 12,
VT_MATRICES = 14
VT_MATRICES = 14,
VT_SIMPLE_POSITION = 16,
VT_SIMPLE_VECTORS = 18
};
const ::flatbuffers::Vector<const Geometry::Vector3D *> *vectors() const {
return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS);
@@ -279,6 +342,18 @@ struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *mutable_matrices() {
return GetPointer<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *>(VT_MATRICES);
}
const Geometry::Vector3DSimple *simple_position() const {
return GetStruct<const Geometry::Vector3DSimple *>(VT_SIMPLE_POSITION);
}
Geometry::Vector3DSimple *mutable_simple_position() {
return GetStruct<Geometry::Vector3DSimple *>(VT_SIMPLE_POSITION);
}
const ::flatbuffers::Vector<const Geometry::Vector3DSimple *> *simple_vectors() const {
return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3DSimple *> *>(VT_SIMPLE_VECTORS);
}
::flatbuffers::Vector<const Geometry::Vector3DSimple *> *mutable_simple_vectors() {
return GetPointer<::flatbuffers::Vector<const Geometry::Vector3DSimple *> *>(VT_SIMPLE_VECTORS);
}
template <bool B = false>
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
return VerifyTableStart(verifier) &&
@@ -293,6 +368,9 @@ struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
VerifyOffset(verifier, VT_MATRICES) &&
verifier.VerifyVector(matrices()) &&
verifier.VerifyVectorOfTables(matrices()) &&
VerifyField<Geometry::Vector3DSimple>(verifier, VT_SIMPLE_POSITION, 4) &&
VerifyOffset(verifier, VT_SIMPLE_VECTORS) &&
verifier.VerifyVector(simple_vectors()) &&
verifier.EndTable();
}
ApplicationDataT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -322,6 +400,12 @@ struct ApplicationDataBuilder {
void add_matrices(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>>> matrices) {
fbb_.AddOffset(ApplicationData::VT_MATRICES, matrices);
}
void add_simple_position(const Geometry::Vector3DSimple *simple_position) {
fbb_.AddStruct(ApplicationData::VT_SIMPLE_POSITION, simple_position);
}
void add_simple_vectors(::flatbuffers::Offset<::flatbuffers::Vector<const Geometry::Vector3DSimple *>> simple_vectors) {
fbb_.AddOffset(ApplicationData::VT_SIMPLE_VECTORS, simple_vectors);
}
explicit ApplicationDataBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -340,8 +424,12 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(
const Geometry::Vector3D *position = nullptr,
const Geometry::Vector3D *position_inline = nullptr,
::flatbuffers::Offset<Geometry::Matrix> matrix = 0,
::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>>> matrices = 0) {
::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>>> matrices = 0,
const Geometry::Vector3DSimple *simple_position = nullptr,
::flatbuffers::Offset<::flatbuffers::Vector<const Geometry::Vector3DSimple *>> simple_vectors = 0) {
ApplicationDataBuilder builder_(_fbb);
builder_.add_simple_vectors(simple_vectors);
builder_.add_simple_position(simple_position);
builder_.add_matrices(matrices);
builder_.add_matrix(matrix);
builder_.add_position_inline(position_inline);
@@ -358,10 +446,13 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
const Geometry::Vector3D *position = nullptr,
const Geometry::Vector3D *position_inline = nullptr,
::flatbuffers::Offset<Geometry::Matrix> matrix = 0,
const std::vector<::flatbuffers::Offset<Geometry::Matrix>> *matrices = nullptr) {
const std::vector<::flatbuffers::Offset<Geometry::Matrix>> *matrices = nullptr,
const Geometry::Vector3DSimple *simple_position = nullptr,
const std::vector<Geometry::Vector3DSimple> *simple_vectors = nullptr) {
auto vectors__ = vectors ? _fbb.CreateVectorOfStructs<Geometry::Vector3D>(*vectors) : 0;
auto vectors_alt__ = vectors_alt ? _fbb.CreateVectorOfStructs<Geometry::Vector3DAlt>(*vectors_alt) : 0;
auto matrices__ = matrices ? _fbb.CreateVector<::flatbuffers::Offset<Geometry::Matrix>>(*matrices) : 0;
auto simple_vectors__ = simple_vectors ? _fbb.CreateVectorOfStructs<Geometry::Vector3DSimple>(*simple_vectors) : 0;
return Geometry::CreateApplicationData(
_fbb,
vectors__,
@@ -369,7 +460,9 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
position,
position_inline,
matrix,
matrices__);
matrices__,
simple_position,
simple_vectors__);
}
::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
@@ -392,7 +485,9 @@ inline bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs)
((lhs.position == rhs.position) || (lhs.position && rhs.position && *lhs.position == *rhs.position)) &&
(lhs.position_inline == rhs.position_inline) &&
((lhs.matrix == rhs.matrix) || (lhs.matrix && rhs.matrix && *lhs.matrix == *rhs.matrix)) &&
(lhs.matrices.size() == rhs.matrices.size() && std::equal(lhs.matrices.cbegin(), lhs.matrices.cend(), rhs.matrices.cbegin(), [](std::unique_ptr<Native::Matrix> const &a, std::unique_ptr<Native::Matrix> const &b) { return (a == b) || (a && b && *a == *b); }));
(lhs.matrices.size() == rhs.matrices.size() && std::equal(lhs.matrices.cbegin(), lhs.matrices.cend(), rhs.matrices.cbegin(), [](std::unique_ptr<Native::Matrix> const &a, std::unique_ptr<Native::Matrix> const &b) { return (a == b) || (a && b && *a == *b); })) &&
(lhs.simple_position == rhs.simple_position) &&
(lhs.simple_vectors == rhs.simple_vectors);
}
inline bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs) {
@@ -405,7 +500,9 @@ inline ApplicationDataT::ApplicationDataT(const ApplicationDataT &o)
vectors_alt(o.vectors_alt),
position((o.position) ? new Native::Vector3D(*o.position) : nullptr),
position_inline(o.position_inline),
matrix((o.matrix) ? new Native::Matrix(*o.matrix) : nullptr) {
matrix((o.matrix) ? new Native::Matrix(*o.matrix) : nullptr),
simple_position(o.simple_position),
simple_vectors(o.simple_vectors) {
matrices.reserve(o.matrices.size());
for (const auto &matrices_ : o.matrices) { matrices.emplace_back((matrices_) ? new Native::Matrix(*matrices_) : nullptr); }
}
@@ -417,6 +514,8 @@ inline ApplicationDataT &ApplicationDataT::operator=(ApplicationDataT o) FLATBUF
std::swap(position_inline, o.position_inline);
std::swap(matrix, o.matrix);
std::swap(matrices, o.matrices);
std::swap(simple_position, o.simple_position);
std::swap(simple_vectors, o.simple_vectors);
return *this;
}
@@ -435,6 +534,8 @@ inline void ApplicationData::UnPackTo(ApplicationDataT *_o, const ::flatbuffers:
{ auto _e = position_inline(); if (_e) _o->position_inline = ::flatbuffers::UnPack(*_e); }
{ auto _e = matrix(); if (_e) { if(_o->matrix) { _e->UnPackTo(_o->matrix.get(), _resolver); } else { _o->matrix = std::unique_ptr<Native::Matrix>(_e->UnPack(_resolver)); } } else if (_o->matrix) { _o->matrix.reset(); } }
{ auto _e = matrices(); if (_e) { _o->matrices.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->matrices[_i]) { _e->Get(_i)->UnPackTo(_o->matrices[_i].get(), _resolver); } else { _o->matrices[_i] = std::unique_ptr<Native::Matrix>(_e->Get(_i)->UnPack(_resolver)); } } } else { _o->matrices.resize(0); } }
{ auto _e = simple_position(); if (_e) _o->simple_position = ::flatbuffers::UnPackVector3DSimple(*_e); }
{ auto _e = simple_vectors(); if (_e) { _o->simple_vectors.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->simple_vectors[_i] = ::flatbuffers::UnPackVector3DSimple(*_e->Get(_i)); } } else { _o->simple_vectors.resize(0); } }
}
inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
@@ -451,6 +552,8 @@ inline ::flatbuffers::Offset<ApplicationData> ApplicationData::Pack(::flatbuffer
auto _position_inline = ::flatbuffers::Pack(_o->position_inline);
auto _matrix = _o->matrix ? CreateMatrix(_fbb, _o->matrix.get(), _rehasher) : 0;
auto _matrices = _o->matrices.size() ? _fbb.CreateVector<::flatbuffers::Offset<Geometry::Matrix>> (_o->matrices.size(), [](size_t i, _VectorArgs *__va) { return CreateMatrix(*__va->__fbb, __va->__o->matrices[i].get(), __va->__rehasher); }, &_va ) : 0;
auto _simple_position = ::flatbuffers::PackVector3DSimple(_o->simple_position);
auto _simple_vectors = _o->simple_vectors.size() ? _fbb.CreateVectorOfNativeStructs<Geometry::Vector3DSimple, Native::Vector3D>(_o->simple_vectors, ::flatbuffers::PackVector3DSimple) : 0;
return Geometry::CreateApplicationData(
_fbb,
_vectors,
@@ -458,7 +561,9 @@ inline ::flatbuffers::Offset<ApplicationData> ApplicationData::Pack(::flatbuffer
_o->position ? &_position : nullptr,
&_position_inline,
_matrix,
_matrices);
_matrices,
&_simple_position,
_simple_vectors);
}
inline const ::flatbuffers::TypeTable *Vector3DTypeTable() {
@@ -497,6 +602,24 @@ inline const ::flatbuffers::TypeTable *Vector3DAltTypeTable() {
return &tt;
}
inline const ::flatbuffers::TypeTable *Vector3DSimpleTypeTable() {
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 *MatrixTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_INT, 0, -1 },
@@ -521,12 +644,15 @@ inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable() {
{ ::flatbuffers::ET_SEQUENCE, 0, 0 },
{ ::flatbuffers::ET_SEQUENCE, 0, 0 },
{ ::flatbuffers::ET_SEQUENCE, 0, 2 },
{ ::flatbuffers::ET_SEQUENCE, 1, 2 }
{ ::flatbuffers::ET_SEQUENCE, 1, 2 },
{ ::flatbuffers::ET_SEQUENCE, 0, 3 },
{ ::flatbuffers::ET_SEQUENCE, 1, 3 }
};
static const ::flatbuffers::TypeFunction type_refs[] = {
Geometry::Vector3DTypeTable,
Geometry::Vector3DAltTypeTable,
Geometry::MatrixTypeTable
Geometry::MatrixTypeTable,
Geometry::Vector3DSimpleTypeTable
};
static const char * const names[] = {
"vectors",
@@ -534,10 +660,12 @@ inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable() {
"position",
"position_inline",
"matrix",
"matrices"
"matrices",
"simple_position",
"simple_vectors"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_TABLE, 6, type_codes, type_refs, nullptr, nullptr, names
::flatbuffers::ST_TABLE, 8, type_codes, type_refs, nullptr, nullptr, names
};
return &tt;
}

View File

@@ -18,6 +18,15 @@ Geometry::Vector3DAlt PackVector3DAlt(const Native::Vector3D& obj) {
const Native::Vector3D UnPackVector3DAlt(const Geometry::Vector3DAlt& obj) {
return Native::Vector3D(obj.a(), obj.b(), obj.c());
}
Geometry::Vector3DSimple PackVector3DSimple(const Native::Vector3D& obj) {
return Geometry::Vector3DSimple(obj.x, obj.y, obj.z);
}
const Native::Vector3D UnPackVector3DSimple(
const Geometry::Vector3DSimple& obj) {
return Native::Vector3D(obj.x(), obj.y(), obj.z());
}
} // namespace flatbuffers
namespace Geometry {

View File

@@ -48,6 +48,7 @@ struct Matrix {
namespace Geometry {
struct Vector3D;
struct Vector3DAlt;
struct Vector3DSimple;
} // namespace Geometry
namespace flatbuffers {
@@ -55,6 +56,8 @@ Geometry::Vector3D Pack(const Native::Vector3D& obj);
const Native::Vector3D UnPack(const Geometry::Vector3D& obj);
Geometry::Vector3DAlt PackVector3DAlt(const Native::Vector3D& obj);
const Native::Vector3D UnPackVector3DAlt(const Geometry::Vector3DAlt& obj);
Geometry::Vector3DSimple PackVector3DSimple(const Native::Vector3D& obj);
const Native::Vector3D UnPackVector3DSimple(const Geometry::Vector3DSimple& obj);
} // namespace flatbuffers
#endif // VECTOR3D_PACK_H

View File

@@ -63,7 +63,9 @@
#include "flexbuffers_test.h"
#include "is_quiet_nan.h"
#include "monster_test_bfbs_generated.h" // Generated using --bfbs-comments --bfbs-builtins --cpp --bfbs-gen-embed
#include "cpp_vec_type_test_generated.h"
#include "native_type_test_generated.h"
#include "cpp_vec_type_native_type_test_generated.h"
#include "test_assert.h"
#include "util_test.h"
#include "vector_table_naked_ptr_test.h"
@@ -929,6 +931,12 @@ void NativeTypeTest() {
Native::Vector3D(20 * i + 0.1f, 20 * i + 0.2f, 20 * i + 0.3f));
}
src_data.simple_position = Native::Vector3D(7.0f, 8.0f, 9.0f);
for (int i = 0; i < N; ++i) {
src_data.simple_vectors.push_back(
Native::Vector3D(30 * i + 0.1f, 30 * i + 0.2f, 30 * i + 0.3f));
}
src_data.matrix = std::unique_ptr<Native::Matrix>(new Native::Matrix(1, 2));
src_data.matrix->values = {3, 4};
@@ -963,6 +971,17 @@ void NativeTypeTest() {
TEST_EQ(v2.z, 20 * i + 0.3f);
}
TEST_EQ(dstDataT->simple_position.x, 7.0f);
TEST_EQ(dstDataT->simple_position.y, 8.0f);
TEST_EQ(dstDataT->simple_position.z, 9.0f);
for (int i = 0; i < N; ++i) {
const Native::Vector3D& sv = dstDataT->simple_vectors[i];
TEST_EQ(sv.x, 30 * i + 0.1f);
TEST_EQ(sv.y, 30 * i + 0.2f);
TEST_EQ(sv.z, 30 * i + 0.3f);
}
TEST_EQ(dstDataT->matrix->rows, 1);
TEST_EQ(dstDataT->matrix->columns, 2);
TEST_EQ(dstDataT->matrix->values[0], 3);
@@ -978,6 +997,92 @@ void NativeTypeTest() {
}
}
void CppVecTypeTest() {
static_assert(
std::is_same<decltype(CppVecTest::DataT{}.values),
CppVecTest::CustomVec<int32_t>>::value,
"values should be CustomVec<int32_t>");
static_assert(
std::is_same<decltype(CppVecTest::DataT{}.regular),
std::vector<int32_t>>::value,
"regular should be std::vector<int32_t>");
CppVecTest::DataT src;
src.values.push_back(10);
src.values.push_back(20);
src.values.push_back(30);
auto item = flatbuffers::unique_ptr<CppVecTest::ItemT>(new CppVecTest::ItemT());
item->id = 42;
item->value = 1.5f;
src.items.push_back(std::move(item));
src.strs.push_back("hello");
src.strs.push_back("world");
flatbuffers::FlatBufferBuilder fbb;
fbb.Finish(CppVecTest::Data::Pack(fbb, &src));
auto dst = CppVecTest::UnPackData(fbb.GetBufferPointer());
TEST_EQ(dst->values.size(), 3U);
TEST_EQ(dst->values[0], 10);
TEST_EQ(dst->values[1], 20);
TEST_EQ(dst->values[2], 30);
TEST_EQ(dst->items.size(), 1U);
TEST_EQ(dst->items[0]->id, 42);
TEST_EQ(dst->items[0]->value, 1.5f);
TEST_EQ(dst->strs.size(), 2U);
TEST_EQ(dst->strs[0], std::string("hello"));
TEST_EQ(dst->strs[1], std::string("world"));
TEST_EQ(dst->regular.size(), 0U);
TEST_ASSERT(*dst == *dst);
}
void CppVecTypeNativeTypeTest() {
// Verify that combining cpp_vec_type + native_type on a vector of structs
// produces the correct container type in the NativeTable.
static_assert(
std::is_same<
decltype(CppVecNativeTypeTest::ContainerT{}.points),
CppVecNativeTypeTest::CustomVec<
CppVecNativeTypeTest::Native::Vec3>>::value,
"points should be CustomVec<Native::Vec3>");
static_assert(
std::is_same<decltype(CppVecNativeTypeTest::ContainerT{}.bytes),
CppVecNativeTypeTest::CustomVec<uint8_t>>::value,
"bytes should be CustomVec<uint8_t>");
const int N = 3;
CppVecNativeTypeTest::ContainerT src;
for (int i = 0; i < N; ++i) {
src.points.push_back(
CppVecNativeTypeTest::Native::Vec3(1.0f * i, 2.0f * i, 3.0f * i));
src.bytes.push_back(static_cast<uint8_t>(i * 10));
}
flatbuffers::FlatBufferBuilder fbb;
fbb.Finish(CppVecNativeTypeTest::Container::Pack(fbb, &src));
auto dst =
CppVecNativeTypeTest::UnPackContainer(fbb.GetBufferPointer());
TEST_EQ(dst->points.size(), static_cast<size_t>(N));
for (int i = 0; i < N; ++i) {
TEST_EQ(dst->points[i].x, 1.0f * i);
TEST_EQ(dst->points[i].y, 2.0f * i);
TEST_EQ(dst->points[i].z, 3.0f * i);
}
TEST_EQ(dst->bytes.size(), static_cast<size_t>(N));
for (int i = 0; i < N; ++i) {
TEST_EQ(dst->bytes[i], static_cast<uint8_t>(i * 10));
}
}
// Guard against -Wunused-function on platforms without file tests.
#ifndef FLATBUFFERS_NO_FILE_TESTS
// VS10 does not support typed enums, exclude from tests
@@ -1813,6 +1918,8 @@ int FlatBufferTests(const std::string& tests_data_path) {
InvalidFloatTest();
FixedLengthArrayTest();
NativeTypeTest();
CppVecTypeTest();
CppVecTypeNativeTypeTest();
OptionalScalarsTest();
ParseFlexbuffersFromJsonWithNullTest();
FlatbuffersSpanTest();