Support native_type for tables when using the C++ object API. (#8668)

* Support native_type for tables when using the C++ object API.

If native_type is specified on a table:
- No object API struct type is generated.
- The object API refers to the table by its native_type.
- UnPack and Create<TableName> methods are declared but not defined; as they
  must be user-provided.

* Add tests for native_type on tables.

* Add documentation for native_type on tables.
This commit is contained in:
cosmith-nvidia
2025-11-05 07:50:10 -08:00
committed by GitHub
parent 4173b84d4b
commit 599847236c
7 changed files with 251 additions and 153 deletions

View File

@@ -242,6 +242,41 @@ provide the following functions to aide in the serialization process:
}
```
- `native_type("type")` (on a table): Tables can also be represented with
native types. For example, the following schema:
```cpp
table Matrix (native_type: "NativeMatrix") {
rows: int32;
columns: int32;
values: [float];
}
```
Would be represented by a user-defined C++ class:
```cpp
class NativeMatrix { ... }
```
In this case, the following function declarations are generated by the compiler.
The user must provide and link the matching function definitions:
```cpp
struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
// ...
static ::flatbuffers::Offset<Matrix> Pack(
::flatbuffers::FlatBufferBuilder& _fbb,
const NativeMatrix* _o,
const ::flatbuffers::rehasher_function_t* _rehasher = nullptr);
void UnPackTo(
NativeMatrix* _o,
const ::flatbuffers::resolver_function_t* _resolver = nullptr) const;
}
```
Finally, the following top-level attributes:
- `native_include("path")` (at file level): Because the `native_type` attribute

View File

@@ -501,7 +501,10 @@ class CppGenerator : public BaseGenerator {
}
}
if (!struct_def->fixed) {
// Don't declare a new object API struct type if the table is a
// native type.
const auto native_type = struct_def->attributes.Lookup("native_type");
if (!struct_def->fixed && !native_type) {
code_ += "struct " + nativeName + ";";
}
}
@@ -886,12 +889,23 @@ class CppGenerator : public BaseGenerator {
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.
const auto native_type = sd->attributes.Lookup("native_type");
if (native_type && !sd->fixed) {
return native_type->constant;
}
return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
: name;
}
std::string WrapNativeNameInNameSpace(const StructDef& struct_def,
const IDLOptions& opts) {
// If the table is a native_type, return the native_type name.
const auto native_type = struct_def.attributes.Lookup("native_type");
if (native_type && !struct_def.fixed) {
return native_type->constant;
}
return WrapInNameSpace(struct_def.defined_namespace,
NativeName(Name(struct_def), &struct_def, opts));
}
@@ -2883,7 +2897,9 @@ class CppGenerator : public BaseGenerator {
// Generate an accessor struct, builder structs & function for a table.
void GenTable(const StructDef& struct_def) {
if (opts_.generate_object_based_api) {
// Don't generate an object API struct for the table if it is a native type.
const auto native_type = struct_def.attributes.Lookup("native_type");
if (opts_.generate_object_based_api && !native_type) {
GenNativeTable(struct_def);
}
@@ -2891,6 +2907,8 @@ class CppGenerator : public BaseGenerator {
// type name() const { return GetField<type>(offset, defaultval); }
GenComment(struct_def.doc_comment);
const auto native_name = NativeName(Name(struct_def), &struct_def, opts_);
code_.SetValue("NATIVE_NAME", native_name);
code_.SetValue("STRUCT_NAME", Name(struct_def));
code_ +=
"struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
@@ -3766,7 +3784,9 @@ class CppGenerator : public BaseGenerator {
// Generate code for tables that needs to come after the regular definition.
void GenTablePost(const StructDef& struct_def) {
if (opts_.generate_object_based_api) {
// Don't generate an object API struct for the table if it is a native type.
const auto native_type = struct_def.attributes.Lookup("native_type");
if (opts_.generate_object_based_api && !native_type) {
GenNativeTablePost(struct_def);
}
@@ -3776,7 +3796,9 @@ class CppGenerator : public BaseGenerator {
if (opts_.generate_object_based_api) {
// Generate the >= C++11 copy ctor and assignment operator definitions.
GenCopyCtorAssignOpDefs(struct_def);
if (!native_type) {
GenCopyCtorAssignOpDefs(struct_def);
}
// Generate the X::UnPack() method.
code_ +=
@@ -3799,33 +3821,38 @@ class CppGenerator : public BaseGenerator {
code_ += " return _o.release();";
code_ += "}";
code_ += "";
code_ +=
"inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
code_ += " (void)_o;";
code_ += " (void)_resolver;";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto& field = **it;
if (field.deprecated) {
continue;
// Generate an Unpack method for the C++ object if that table does not
// have a native type.
if (!native_type) {
code_ +=
"inline " + TableUnPackToSignature(struct_def, false, opts_) + " {";
code_ += " (void)_o;";
code_ += " (void)_resolver;";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto& field = **it;
if (field.deprecated) {
continue;
}
// Assign a value from |this| to |_o|. Values from |this| are stored
// in a variable |_e| by calling this->field_type(). The value is
// then assigned to |_o| using the GenUnpackFieldStatement.
const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
const auto statement =
GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
code_.SetValue("FIELD_NAME", Name(field));
auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
auto postfix = " }";
code_ += std::string(prefix) + check + statement + postfix;
}
// Assign a value from |this| to |_o|. Values from |this| are stored
// in a variable |_e| by calling this->field_type(). The value is then
// assigned to |_o| using the GenUnpackFieldStatement.
const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
const auto statement =
GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
code_.SetValue("FIELD_NAME", Name(field));
auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
auto postfix = " }";
code_ += std::string(prefix) + check + statement + postfix;
code_ += "}";
code_ += "";
}
code_ += "}";
code_ += "";
// Generate the global CreateX function that simply calls the
// X::Pack member function.
@@ -3835,78 +3862,85 @@ class CppGenerator : public BaseGenerator {
code_ += "}";
code_ += "";
// Generate a CreateX method that works with an unpacked C++ object.
code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {";
code_ += " (void)_rehasher;";
code_ += " (void)_o;";
if (!native_type) {
// Generate a Pack method that works with an unpacked C++ object if it
// does not have a native type.
code_ +=
"inline " + TablePackSignature(struct_def, false, opts_) + " {";
code_ += " (void)_rehasher;";
code_ += " (void)_o;";
code_ +=
" struct _VectorArgs "
"{ " +
GetBuilder() +
" *__fbb; "
"const " +
NativeName(Name(struct_def), &struct_def, opts_) +
"* __o; "
"const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { "
"&_fbb, _o, _rehasher}; (void)_va;";
code_ +=
" struct _VectorArgs "
"{ " +
GetBuilder() +
" *__fbb; "
"const " +
NativeName(Name(struct_def), &struct_def, opts_) +
"* __o; "
"const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { "
"&_fbb, _o, _rehasher}; (void)_va;";
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto& field = **it;
if (field.deprecated) {
continue;
}
if (IsVector(field.value.type)) {
const std::string force_align_code =
GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
if (!force_align_code.empty()) {
code_ += " " + force_align_code;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto& field = **it;
if (field.deprecated) {
continue;
}
}
code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
}
// Need to call "Create" with the struct namespace.
const auto qualified_create_name =
struct_def.defined_namespace->GetFullyQualifiedName("Create");
code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
code_ += " _fbb\\";
for (const auto& field : struct_def.fields.vec) {
if (field->deprecated) {
continue;
}
bool pass_by_address = false;
bool check_ptr = false;
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");
auto native_inline = field->attributes.Lookup("native_inline");
if (native_type) {
pass_by_address = true;
}
if (native_type && !native_inline) {
check_ptr = true;
if (IsVector(field.value.type)) {
const std::string force_align_code =
GenVectorForceAlign(field, "_o->" + Name(field) + ".size()");
if (!force_align_code.empty()) {
code_ += " " + force_align_code;
}
}
code_ +=
" auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
}
// Need to call "Create" with the struct namespace.
const auto qualified_create_name =
struct_def.defined_namespace->GetFullyQualifiedName("Create");
code_.SetValue("CREATE_NAME",
TranslateNameSpace(qualified_create_name));
// Call the CreateX function using values from |_o|.
if (pass_by_address && check_ptr) {
code_ += ",\n _o->" + Name(*field) + " ? &_" + Name(*field) +
" : nullptr\\";
} else if (pass_by_address) {
code_ += ",\n &_" + Name(*field) + "\\";
} else {
code_ += ",\n _" + Name(*field) + "\\";
code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
code_ += " _fbb\\";
for (const auto& field : struct_def.fields.vec) {
if (field->deprecated) {
continue;
}
bool pass_by_address = false;
bool check_ptr = false;
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");
auto native_inline = field->attributes.Lookup("native_inline");
if (native_type) {
pass_by_address = true;
}
if (native_type && !native_inline) {
check_ptr = true;
}
}
}
// Call the CreateX function using values from |_o|.
if (pass_by_address && check_ptr) {
code_ += ",\n _o->" + Name(*field) + " ? &_" + Name(*field) +
" : nullptr\\";
} else if (pass_by_address) {
code_ += ",\n &_" + Name(*field) + "\\";
} else {
code_ += ",\n _" + Name(*field) + "\\";
}
}
code_ += ");";
code_ += "}";
code_ += "";
}
code_ += ");";
code_ += "}";
code_ += "";
}
}

View File

@@ -14,8 +14,7 @@ struct Vector3DAlt (native_type:"Native::Vector3D", native_type_pack_name:"Vecto
c:float;
}
// table Matrix (native_type:"Native::Matrix") {
table Matrix {
table Matrix (native_type:"Native::Matrix") {
rows:int32;
columns:int32;
values:[float];

View File

@@ -23,14 +23,11 @@ struct Vector3DAlt;
struct Matrix;
struct MatrixBuilder;
struct MatrixT;
struct ApplicationData;
struct ApplicationDataBuilder;
struct ApplicationDataT;
bool operator==(const MatrixT &lhs, const MatrixT &rhs);
bool operator!=(const MatrixT &lhs, const MatrixT &rhs);
bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs);
bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs);
@@ -124,15 +121,8 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
};
FLATBUFFERS_STRUCT_END(Vector3DAlt, 12);
struct MatrixT : public ::flatbuffers::NativeTable {
typedef Matrix TableType;
int32_t rows = 0;
int32_t columns = 0;
std::vector<float> values{};
};
struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef MatrixT NativeTableType;
typedef Native::Matrix NativeTableType;
typedef MatrixBuilder Builder;
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return MatrixTypeTable();
@@ -168,9 +158,9 @@ struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
verifier.VerifyVector(values()) &&
verifier.EndTable();
}
MatrixT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
void UnPackTo(MatrixT *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
static ::flatbuffers::Offset<Matrix> Pack(::flatbuffers::FlatBufferBuilder &_fbb, const MatrixT* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
Native::Matrix *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
void UnPackTo(Native::Matrix *_o, const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
static ::flatbuffers::Offset<Matrix> Pack(::flatbuffers::FlatBufferBuilder &_fbb, const Native::Matrix* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct MatrixBuilder {
@@ -222,7 +212,7 @@ inline ::flatbuffers::Offset<Matrix> CreateMatrixDirect(
values__);
}
::flatbuffers::Offset<Matrix> CreateMatrix(::flatbuffers::FlatBufferBuilder &_fbb, const MatrixT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
::flatbuffers::Offset<Matrix> CreateMatrix(::flatbuffers::FlatBufferBuilder &_fbb, const Native::Matrix *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
struct ApplicationDataT : public ::flatbuffers::NativeTable {
typedef ApplicationData TableType;
@@ -230,8 +220,8 @@ struct ApplicationDataT : public ::flatbuffers::NativeTable {
std::vector<Native::Vector3D> vectors_alt{};
std::unique_ptr<Native::Vector3D> position{};
Native::Vector3D position_inline{};
std::unique_ptr<Geometry::MatrixT> matrix{};
std::vector<std::unique_ptr<Geometry::MatrixT>> matrices{};
std::unique_ptr<Native::Matrix> matrix{};
std::vector<std::unique_ptr<Native::Matrix>> matrices{};
ApplicationDataT() = default;
ApplicationDataT(const ApplicationDataT &o);
ApplicationDataT(ApplicationDataT&&) FLATBUFFERS_NOEXCEPT = default;
@@ -382,51 +372,16 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
inline bool operator==(const MatrixT &lhs, const MatrixT &rhs) {
return
(lhs.rows == rhs.rows) &&
(lhs.columns == rhs.columns) &&
(lhs.values == rhs.values);
}
inline bool operator!=(const MatrixT &lhs, const MatrixT &rhs) {
return !(lhs == rhs);
}
inline MatrixT *Matrix::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const {
auto _o = std::unique_ptr<MatrixT>(new MatrixT());
inline Native::Matrix *Matrix::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const {
auto _o = std::unique_ptr<Native::Matrix>(new Native::Matrix());
UnPackTo(_o.get(), _resolver);
return _o.release();
}
inline void Matrix::UnPackTo(MatrixT *_o, const ::flatbuffers::resolver_function_t *_resolver) const {
(void)_o;
(void)_resolver;
{ auto _e = rows(); _o->rows = _e; }
{ auto _e = columns(); _o->columns = _e; }
{ auto _e = values(); if (_e) { _o->values.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->values[_i] = _e->Get(_i); } } else { _o->values.resize(0); } }
}
inline ::flatbuffers::Offset<Matrix> CreateMatrix(::flatbuffers::FlatBufferBuilder &_fbb, const MatrixT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
inline ::flatbuffers::Offset<Matrix> CreateMatrix(::flatbuffers::FlatBufferBuilder &_fbb, const Native::Matrix *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
return Matrix::Pack(_fbb, _o, _rehasher);
}
inline ::flatbuffers::Offset<Matrix> Matrix::Pack(::flatbuffers::FlatBufferBuilder &_fbb, const MatrixT* _o, const ::flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { ::flatbuffers::FlatBufferBuilder *__fbb; const MatrixT* __o; const ::flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _rows = _o->rows;
auto _columns = _o->columns;
auto _values = _o->values.size() ? _fbb.CreateVector(_o->values) : 0;
return Geometry::CreateMatrix(
_fbb,
_rows,
_columns,
_values);
}
inline bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs) {
return
@@ -435,7 +390,7 @@ 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<Geometry::MatrixT> const &a, std::unique_ptr<Geometry::MatrixT> 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); }));
}
inline bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs) {
@@ -448,9 +403,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 Geometry::MatrixT(*o.matrix) : nullptr) {
matrix((o.matrix) ? new Native::Matrix(*o.matrix) : nullptr) {
matrices.reserve(o.matrices.size());
for (const auto &matrices_ : o.matrices) { matrices.emplace_back((matrices_) ? new Geometry::MatrixT(*matrices_) : nullptr); }
for (const auto &matrices_ : o.matrices) { matrices.emplace_back((matrices_) ? new Native::Matrix(*matrices_) : nullptr); }
}
inline ApplicationDataT &ApplicationDataT::operator=(ApplicationDataT o) FLATBUFFERS_NOEXCEPT {
@@ -476,8 +431,8 @@ inline void ApplicationData::UnPackTo(ApplicationDataT *_o, const ::flatbuffers:
{ auto _e = vectors_alt(); if (_e) { _o->vectors_alt.resize(_e->size()); for (::flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vectors_alt[_i] = ::flatbuffers::UnPackVector3DAlt(*_e->Get(_i)); } } else { _o->vectors_alt.resize(0); } }
{ auto _e = position(); if (_e) _o->position = std::unique_ptr<Native::Vector3D>(new Native::Vector3D(::flatbuffers::UnPack(*_e))); }
{ 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<Geometry::MatrixT>(_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<Geometry::MatrixT>(_e->Get(_i)->UnPack(_resolver)); } } } else { _o->matrices.resize(0); } }
{ 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); } }
}
inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {

View File

@@ -19,3 +19,34 @@ const Native::Vector3D UnPackVector3DAlt(const Geometry::Vector3DAlt& obj) {
return Native::Vector3D(obj.a(), obj.b(), obj.c());
}
} // namespace flatbuffers
namespace Geometry {
void Matrix::UnPackTo(
Native::Matrix *_o,
const ::flatbuffers::resolver_function_t *_resolver) const {
(void)_resolver;
auto _rows = rows();
if (_rows) { _o->rows = _rows; }
auto _columns = columns();
if (_columns) { _o->columns = _columns; }
auto _values = values();
if (_values) {
_o->values.resize(_values->size());
for (::flatbuffers::uoffset_t i = 0; i < _values->size(); i++) {
_o->values[i] = _values->Get(i);
}
}
}
::flatbuffers::Offset<Matrix> Matrix::Pack(
::flatbuffers::FlatBufferBuilder &_fbb, const Native::Matrix *_o,
const ::flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
return CreateMatrix(_fbb, _o->rows, _o->columns,
_fbb.CreateVector<float>(_o->values));
}
} // namespace Geometry

View File

@@ -1,6 +1,8 @@
#ifndef NATIVE_TYPE_TEST_IMPL_H
#define NATIVE_TYPE_TEST_IMPL_H
#include <vector>
namespace Native {
struct Vector3D {
float x;
@@ -22,6 +24,25 @@ struct Vector3D {
return (x == other.x) && (y == other.y) && (z == other.z);
}
};
struct Matrix {
int rows;
int columns;
std::vector<float> values;
Matrix() : Matrix(0, 0) {}
Matrix(int _rows, int _columns) {
this->rows = _rows;
this->columns = _columns;
values.resize(_rows * _columns);
}
bool operator==(const Matrix &other) const {
return (rows == other.rows) && (columns == other.columns) &&
(values == other.values);
}
};
} // namespace Native
namespace Geometry {

View File

@@ -920,6 +920,15 @@ void NativeTypeTest() {
Native::Vector3D(20 * i + 0.1f, 20 * i + 0.2f, 20 * i + 0.3f));
}
src_data.matrix = std::make_unique<Native::Matrix>(1, 2);
src_data.matrix->values = {3, 4};
for (int i = 0; i < N; ++i) {
src_data.matrices.push_back(std::make_unique<Native::Matrix>(1, i));
std::fill(src_data.matrices[i]->values.begin(),
src_data.matrices[i]->values.end(), i + 0.5f);
}
flatbuffers::FlatBufferBuilder fbb;
fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
@@ -943,6 +952,20 @@ void NativeTypeTest() {
TEST_EQ(v2.y, 20 * i + 0.2f);
TEST_EQ(v2.z, 20 * i + 0.3f);
}
TEST_EQ(dstDataT->matrix->rows, 1);
TEST_EQ(dstDataT->matrix->columns, 2);
TEST_EQ(dstDataT->matrix->values[0], 3);
TEST_EQ(dstDataT->matrix->values[1], 4);
for (int i = 0; i < N; ++i) {
const Native::Matrix &m = *dstDataT->matrices[i];
TEST_EQ(m.rows, 1);
TEST_EQ(m.columns, i);
for (int j = 0; j < i; ++j) {
TEST_EQ(m.values[j], i + 0.5f);
}
}
}
// Guard against -Wunused-function on platforms without file tests.