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>
This commit is contained in:
2026-05-09 15:47:07 +02:00
parent 4edfa03ffc
commit 9e9f5bbfcf
6 changed files with 197 additions and 15 deletions

View File

@@ -3812,14 +3812,25 @@ 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");
if (pack_name) {
code += ", ::flatbuffers::Pack" + pack_name->constant;
}
@@ -4114,9 +4125,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

@@ -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

@@ -929,6 +929,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 +969,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);