From 599847236c35fa3802ea4e46e20e93a55d3a4a94 Mon Sep 17 00:00:00 2001 From: cosmith-nvidia <141183495+cosmith-nvidia@users.noreply.github.com> Date: Wed, 5 Nov 2025 07:50:10 -0800 Subject: [PATCH] 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 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. --- docs/source/languages/cpp.md | 35 +++++ src/idl_gen_cpp.cpp | 216 +++++++++++++++++------------ tests/native_type_test.fbs | 3 +- tests/native_type_test_generated.h | 75 ++-------- tests/native_type_test_impl.cpp | 31 +++++ tests/native_type_test_impl.h | 21 +++ tests/test.cpp | 23 +++ 7 files changed, 251 insertions(+), 153 deletions(-) diff --git a/docs/source/languages/cpp.md b/docs/source/languages/cpp.md index 7e99d4efd..445ca7301 100644 --- a/docs/source/languages/cpp.md +++ b/docs/source/languages/cpp.md @@ -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 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 diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp index 34fec99f5..ddf9395ae 100644 --- a/src/idl_gen_cpp.cpp +++ b/src/idl_gen_cpp.cpp @@ -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(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_ += ""; } } diff --git a/tests/native_type_test.fbs b/tests/native_type_test.fbs index 37dcc4e18..1e73d3330 100644 --- a/tests/native_type_test.fbs +++ b/tests/native_type_test.fbs @@ -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]; diff --git a/tests/native_type_test_generated.h b/tests/native_type_test_generated.h index d6849f9a8..bdbf633e1 100644 --- a/tests/native_type_test_generated.h +++ b/tests/native_type_test_generated.h @@ -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 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 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 Pack(::flatbuffers::FlatBufferBuilder &_fbb, const Native::Matrix* _o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); }; struct MatrixBuilder { @@ -222,7 +212,7 @@ inline ::flatbuffers::Offset CreateMatrixDirect( values__); } -::flatbuffers::Offset CreateMatrix(::flatbuffers::FlatBufferBuilder &_fbb, const MatrixT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); +::flatbuffers::Offset 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 vectors_alt{}; std::unique_ptr position{}; Native::Vector3D position_inline{}; - std::unique_ptr matrix{}; - std::vector> matrices{}; + std::unique_ptr matrix{}; + std::vector> matrices{}; ApplicationDataT() = default; ApplicationDataT(const ApplicationDataT &o); ApplicationDataT(ApplicationDataT&&) FLATBUFFERS_NOEXCEPT = default; @@ -382,51 +372,16 @@ inline ::flatbuffers::Offset CreateApplicationDataDirect( ::flatbuffers::Offset 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(new MatrixT()); +inline Native::Matrix *Matrix::UnPack(const ::flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(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 CreateMatrix(::flatbuffers::FlatBufferBuilder &_fbb, const MatrixT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { +inline ::flatbuffers::Offset CreateMatrix(::flatbuffers::FlatBufferBuilder &_fbb, const Native::Matrix *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { return Matrix::Pack(_fbb, _o, _rehasher); } -inline ::flatbuffers::Offset 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 const &a, std::unique_ptr 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 const &a, std::unique_ptr 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(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(_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(_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(_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(_e->Get(_i)->UnPack(_resolver)); } } } else { _o->matrices.resize(0); } } } inline ::flatbuffers::Offset CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { diff --git a/tests/native_type_test_impl.cpp b/tests/native_type_test_impl.cpp index 5c54025c3..aaed71268 100644 --- a/tests/native_type_test_impl.cpp +++ b/tests/native_type_test_impl.cpp @@ -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::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(_o->values)); +} +} // namespace Geometry diff --git a/tests/native_type_test_impl.h b/tests/native_type_test_impl.h index ce2e061b5..15085a3b2 100644 --- a/tests/native_type_test_impl.h +++ b/tests/native_type_test_impl.h @@ -1,6 +1,8 @@ #ifndef NATIVE_TYPE_TEST_IMPL_H #define NATIVE_TYPE_TEST_IMPL_H +#include + 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 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 { diff --git a/tests/test.cpp b/tests/test.cpp index 581fc6743..fb0c7504e 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -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(1, 2); + src_data.matrix->values = {3, 4}; + + for (int i = 0; i < N; ++i) { + src_data.matrices.push_back(std::make_unique(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.