[C++] support native_inline attribute for vector of tables (#7479)

This commit is contained in:
sssooonnnggg 2022-08-30 03:48:10 +08:00 committed by GitHub
parent 694add668b
commit 6a87427540
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 347 additions and 24 deletions

View File

@ -249,6 +249,8 @@ set(FlatBuffers_Tests_SRCS
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_bfbs_generated.h
# file generate by running compiler on tests/optional_scalars.fbs
${CMAKE_CURRENT_BINARY_DIR}/tests/optional_scalars_generated.h
# file generate by running compiler on tests/native_inline_table_test.fbs
${CMAKE_CURRENT_BINARY_DIR}/tests/native_inline_table_test_generated.h
)
set(FlatBuffers_Tests_CPP17_SRCS
@ -620,6 +622,7 @@ if(FLATBUFFERS_BUILD_TESTS)
compile_flatbuffers_schema_to_cpp_opt(tests/arrays_test.fbs "--scoped-enums;--gen-compare")
compile_flatbuffers_schema_to_binary(tests/arrays_test.fbs)
compile_flatbuffers_schema_to_embedded_binary(tests/monster_test.fbs "--no-includes;--gen-compare")
compile_flatbuffers_schema_to_cpp(tests/native_inline_table_test.fbs "--gen-compare")
if(NOT (MSVC AND (MSVC_VERSION LESS 1900)))
compile_flatbuffers_schema_to_cpp(tests/monster_extra.fbs) # Test floating-point NAN/INF.
endif()

View File

@ -464,6 +464,10 @@ inline bool IsStruct(const Type &type) {
return type.base_type == BASE_TYPE_STRUCT && type.struct_def->fixed;
}
inline bool IsTable(const Type &type) {
return type.base_type == BASE_TYPE_STRUCT && !type.struct_def->fixed;
}
inline bool IsUnion(const Type &type) {
return type.enum_def != nullptr && type.enum_def->is_union;
}
@ -476,6 +480,14 @@ inline bool IsVector(const Type &type) {
return type.base_type == BASE_TYPE_VECTOR;
}
inline bool IsVectorOfStruct(const Type& type) {
return IsVector(type) && IsStruct(type.VectorType());
}
inline bool IsVectorOfTable(const Type& type) {
return IsVector(type) && IsTable(type.VectorType());
}
inline bool IsArray(const Type &type) {
return type.base_type == BASE_TYPE_ARRAY;
}

View File

@ -74,6 +74,15 @@ static std::string GenIncludeGuard(const std::string &file_name,
return guard;
}
static bool IsVectorOfPointers(const FieldDef& field) {
const auto& type = field.value.type;
const auto& vector_type = type.VectorType();
return type.base_type == BASE_TYPE_VECTOR &&
vector_type.base_type == BASE_TYPE_STRUCT &&
!vector_type.struct_def->fixed &&
!field.native_inline;
}
namespace cpp {
enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
@ -885,7 +894,9 @@ class CppGenerator : public BaseGenerator {
}
} else {
const auto nn = WrapNativeNameInNameSpace(*type.struct_def, opts_);
return forcopy ? nn : GenTypeNativePtr(nn, &field, false);
return (forcopy || field.native_inline)
? nn
: GenTypeNativePtr(nn, &field, false);
}
}
case BASE_TYPE_UNION: {
@ -1871,9 +1882,7 @@ class CppGenerator : public BaseGenerator {
if (vec_type.base_type == BASE_TYPE_UTYPE) continue;
const auto cpp_type = field.attributes.Lookup("cpp_type");
const auto cpp_ptr_type = field.attributes.Lookup("cpp_ptr_type");
const bool is_ptr =
(vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
(cpp_type && cpp_ptr_type->constant != "naked");
const bool is_ptr = IsVectorOfPointers(field) || (cpp_type && cpp_ptr_type->constant != "naked");
if (is_ptr) { return true; }
}
}
@ -1997,9 +2006,7 @@ class CppGenerator : public BaseGenerator {
? cpp_type->constant
: GenTypeNative(vec_type, /*invector*/ true,
field, /*forcopy*/ true);
const bool is_ptr =
(vec_type.base_type == BASE_TYPE_STRUCT && !IsStruct(vec_type)) ||
(cpp_type && cpp_ptr_type->constant != "naked");
const bool is_ptr = IsVectorOfPointers(field) || (cpp_type && cpp_ptr_type->constant != "naked");
CodeWriter cw(" ");
cw.SetValue("FIELD", Name(field));
cw.SetValue("TYPE", type_name);
@ -2078,9 +2085,7 @@ class CppGenerator : public BaseGenerator {
// If the field is a vector of tables, the table need to be compared
// by value, instead of by the default unique_ptr == operator which
// compares by address.
if (field.value.type.base_type == BASE_TYPE_VECTOR &&
field.value.type.element == BASE_TYPE_STRUCT &&
!field.value.type.struct_def->fixed) {
if (IsVectorOfPointers(field)) {
const auto type =
GenTypeNative(field.value.type.VectorType(), true, field);
const auto equal_length =
@ -2979,7 +2984,8 @@ class CppGenerator : public BaseGenerator {
return ptype + "(new " + name + "(*" + val + "))";
}
} else {
const auto ptype = GenTypeNativePtr(
std::string ptype = afield.native_inline ? "*" : "";
ptype += GenTypeNativePtr(
WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield,
true);
return ptype + "(" + val + "->UnPack(_resolver))";
@ -3066,9 +3072,7 @@ class CppGenerator : public BaseGenerator {
} else {
// clang-format off
#if FLATBUFFERS_CPP_OBJECT_UNPACKTO
const bool is_pointer =
field.value.type.VectorType().base_type == BASE_TYPE_STRUCT &&
!IsStruct(field.value.type.VectorType());
const bool is_pointer = IsVectorOfPointers(field);
if (is_pointer) {
code += "if(_o->" + name + "[_i]" + ") { ";
code += indexing + "->UnPackTo(_o->" + name +
@ -3131,9 +3135,7 @@ class CppGenerator : public BaseGenerator {
// _o->field = value;
// clang-format off
#if FLATBUFFERS_CPP_OBJECT_UNPACKTO
const bool is_pointer =
field.value.type.base_type == BASE_TYPE_STRUCT &&
!IsStruct(field.value.type);
const bool is_pointer = IsVectorOfPointers(field);
if (is_pointer) {
code += "{ if(_o->" + Name(field) + ") { ";
code += "_e->UnPackTo(_o->" + Name(field) + ".get(), _resolver);";
@ -3251,9 +3253,13 @@ class CppGenerator : public BaseGenerator {
code += "(" + value + ".size(), ";
code += "[](size_t i, _VectorArgs *__va) { ";
code += "return Create" + vector_type.struct_def->name;
code += "(*__va->__fbb, __va->_" + value + "[i]" +
GenPtrGet(field) + ", ";
code += "__va->__rehasher); }, &_va )";
code += "(*__va->__fbb, ";
if (field.native_inline) {
code += "&(__va->_" + value + "[i])";
} else {
code += "__va->_" + value + "[i]" + GenPtrGet(field);
}
code += ", __va->__rehasher); }, &_va )";
}
break;
}
@ -3342,8 +3348,9 @@ class CppGenerator : public BaseGenerator {
// _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
const auto type = field.value.type.struct_def->name;
code += value + " ? Create" + type;
code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
code += " : 0";
code += "(_fbb, " + value;
if (!field.native_inline) code += GenPtrGet(field);
code += ", _rehasher) : 0";
}
break;
}

View File

@ -1153,8 +1153,12 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
"definition");
field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
if (field->native_inline && !IsStruct(field->value.type))
return Error("native_inline can only be defined on structs");
if (field->native_inline && !IsStruct(field->value.type) &&
!IsVectorOfStruct(field->value.type) &&
!IsVectorOfTable(field->value.type))
return Error(
"'native_inline' can only be defined on structs, vector of structs or "
"vector of tables");
auto nested = field->attributes.Lookup("nested_flatbuffer");
if (nested) {

View File

@ -25,6 +25,7 @@ cc_test(
"monster_test_bfbs_generated.h",
"namespace_test/namespace_test1_generated.h",
"namespace_test/namespace_test2_generated.h",
"native_inline_table_test_generated.h",
"native_type_test_impl.cpp",
"native_type_test_impl.h",
"optional_scalars_generated.h",

View File

@ -0,0 +1,7 @@
table NativeInlineTable {
a: int;
}
table TestNativeInlineTable {
t: [NativeInlineTable] (native_inline);
}

View File

@ -0,0 +1,263 @@
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_NATIVEINLINETABLETEST_H_
#define FLATBUFFERS_GENERATED_NATIVEINLINETABLETEST_H_
#include "flatbuffers/flatbuffers.h"
// Ensure the included flatbuffers.h is the same version as when this file was
// generated, otherwise it may not be compatible.
static_assert(FLATBUFFERS_VERSION_MAJOR == 2 &&
FLATBUFFERS_VERSION_MINOR == 0 &&
FLATBUFFERS_VERSION_REVISION == 7,
"Non-compatible flatbuffers version included");
struct NativeInlineTable;
struct NativeInlineTableBuilder;
struct NativeInlineTableT;
struct TestNativeInlineTable;
struct TestNativeInlineTableBuilder;
struct TestNativeInlineTableT;
bool operator==(const NativeInlineTableT &lhs, const NativeInlineTableT &rhs);
bool operator!=(const NativeInlineTableT &lhs, const NativeInlineTableT &rhs);
bool operator==(const TestNativeInlineTableT &lhs, const TestNativeInlineTableT &rhs);
bool operator!=(const TestNativeInlineTableT &lhs, const TestNativeInlineTableT &rhs);
inline const flatbuffers::TypeTable *NativeInlineTableTypeTable();
inline const flatbuffers::TypeTable *TestNativeInlineTableTypeTable();
struct NativeInlineTableT : public flatbuffers::NativeTable {
typedef NativeInlineTable TableType;
int32_t a = 0;
};
struct NativeInlineTable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef NativeInlineTableT NativeTableType;
typedef NativeInlineTableBuilder Builder;
static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return NativeInlineTableTypeTable();
}
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_A = 4
};
int32_t a() const {
return GetField<int32_t>(VT_A, 0);
}
bool mutate_a(int32_t _a = 0) {
return SetField<int32_t>(VT_A, _a, 0);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int32_t>(verifier, VT_A, 4) &&
verifier.EndTable();
}
NativeInlineTableT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
void UnPackTo(NativeInlineTableT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
static flatbuffers::Offset<NativeInlineTable> Pack(flatbuffers::FlatBufferBuilder &_fbb, const NativeInlineTableT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct NativeInlineTableBuilder {
typedef NativeInlineTable Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_a(int32_t a) {
fbb_.AddElement<int32_t>(NativeInlineTable::VT_A, a, 0);
}
explicit NativeInlineTableBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<NativeInlineTable> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<NativeInlineTable>(end);
return o;
}
};
inline flatbuffers::Offset<NativeInlineTable> CreateNativeInlineTable(
flatbuffers::FlatBufferBuilder &_fbb,
int32_t a = 0) {
NativeInlineTableBuilder builder_(_fbb);
builder_.add_a(a);
return builder_.Finish();
}
flatbuffers::Offset<NativeInlineTable> CreateNativeInlineTable(flatbuffers::FlatBufferBuilder &_fbb, const NativeInlineTableT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
struct TestNativeInlineTableT : public flatbuffers::NativeTable {
typedef TestNativeInlineTable TableType;
std::vector<NativeInlineTableT> t{};
};
struct TestNativeInlineTable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef TestNativeInlineTableT NativeTableType;
typedef TestNativeInlineTableBuilder Builder;
static const flatbuffers::TypeTable *MiniReflectTypeTable() {
return TestNativeInlineTableTypeTable();
}
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_T = 4
};
const flatbuffers::Vector<flatbuffers::Offset<NativeInlineTable>> *t() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<NativeInlineTable>> *>(VT_T);
}
flatbuffers::Vector<flatbuffers::Offset<NativeInlineTable>> *mutable_t() {
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<NativeInlineTable>> *>(VT_T);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_T) &&
verifier.VerifyVector(t()) &&
verifier.VerifyVectorOfTables(t()) &&
verifier.EndTable();
}
TestNativeInlineTableT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
void UnPackTo(TestNativeInlineTableT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
static flatbuffers::Offset<TestNativeInlineTable> Pack(flatbuffers::FlatBufferBuilder &_fbb, const TestNativeInlineTableT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct TestNativeInlineTableBuilder {
typedef TestNativeInlineTable Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_t(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<NativeInlineTable>>> t) {
fbb_.AddOffset(TestNativeInlineTable::VT_T, t);
}
explicit TestNativeInlineTableBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<TestNativeInlineTable> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<TestNativeInlineTable>(end);
return o;
}
};
inline flatbuffers::Offset<TestNativeInlineTable> CreateTestNativeInlineTable(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<NativeInlineTable>>> t = 0) {
TestNativeInlineTableBuilder builder_(_fbb);
builder_.add_t(t);
return builder_.Finish();
}
inline flatbuffers::Offset<TestNativeInlineTable> CreateTestNativeInlineTableDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const std::vector<flatbuffers::Offset<NativeInlineTable>> *t = nullptr) {
auto t__ = t ? _fbb.CreateVector<flatbuffers::Offset<NativeInlineTable>>(*t) : 0;
return CreateTestNativeInlineTable(
_fbb,
t__);
}
flatbuffers::Offset<TestNativeInlineTable> CreateTestNativeInlineTable(flatbuffers::FlatBufferBuilder &_fbb, const TestNativeInlineTableT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
inline bool operator==(const NativeInlineTableT &lhs, const NativeInlineTableT &rhs) {
return
(lhs.a == rhs.a);
}
inline bool operator!=(const NativeInlineTableT &lhs, const NativeInlineTableT &rhs) {
return !(lhs == rhs);
}
inline NativeInlineTableT *NativeInlineTable::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
auto _o = std::unique_ptr<NativeInlineTableT>(new NativeInlineTableT());
UnPackTo(_o.get(), _resolver);
return _o.release();
}
inline void NativeInlineTable::UnPackTo(NativeInlineTableT *_o, const flatbuffers::resolver_function_t *_resolver) const {
(void)_o;
(void)_resolver;
{ auto _e = a(); _o->a = _e; }
}
inline flatbuffers::Offset<NativeInlineTable> NativeInlineTable::Pack(flatbuffers::FlatBufferBuilder &_fbb, const NativeInlineTableT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
return CreateNativeInlineTable(_fbb, _o, _rehasher);
}
inline flatbuffers::Offset<NativeInlineTable> CreateNativeInlineTable(flatbuffers::FlatBufferBuilder &_fbb, const NativeInlineTableT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const NativeInlineTableT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _a = _o->a;
return CreateNativeInlineTable(
_fbb,
_a);
}
inline bool operator==(const TestNativeInlineTableT &lhs, const TestNativeInlineTableT &rhs) {
return
(lhs.t == rhs.t);
}
inline bool operator!=(const TestNativeInlineTableT &lhs, const TestNativeInlineTableT &rhs) {
return !(lhs == rhs);
}
inline TestNativeInlineTableT *TestNativeInlineTable::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
auto _o = std::unique_ptr<TestNativeInlineTableT>(new TestNativeInlineTableT());
UnPackTo(_o.get(), _resolver);
return _o.release();
}
inline void TestNativeInlineTable::UnPackTo(TestNativeInlineTableT *_o, const flatbuffers::resolver_function_t *_resolver) const {
(void)_o;
(void)_resolver;
{ auto _e = t(); if (_e) { _o->t.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->t[_i] = *flatbuffers::unique_ptr<NativeInlineTableT>(_e->Get(_i)->UnPack(_resolver)); } } }
}
inline flatbuffers::Offset<TestNativeInlineTable> TestNativeInlineTable::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TestNativeInlineTableT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
return CreateTestNativeInlineTable(_fbb, _o, _rehasher);
}
inline flatbuffers::Offset<TestNativeInlineTable> CreateTestNativeInlineTable(flatbuffers::FlatBufferBuilder &_fbb, const TestNativeInlineTableT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TestNativeInlineTableT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _t = _o->t.size() ? _fbb.CreateVector<flatbuffers::Offset<NativeInlineTable>> (_o->t.size(), [](size_t i, _VectorArgs *__va) { return CreateNativeInlineTable(*__va->__fbb, &(__va->__o->t[i]), __va->__rehasher); }, &_va ) : 0;
return CreateTestNativeInlineTable(
_fbb,
_t);
}
inline const flatbuffers::TypeTable *NativeInlineTableTypeTable() {
static const flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_INT, 0, -1 }
};
static const char * const names[] = {
"a"
};
static const flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, nullptr, names
};
return &tt;
}
inline const flatbuffers::TypeTable *TestNativeInlineTableTypeTable() {
static const flatbuffers::TypeCode type_codes[] = {
{ flatbuffers::ET_SEQUENCE, 1, 0 }
};
static const flatbuffers::TypeFunction type_refs[] = {
NativeInlineTableTypeTable
};
static const char * const names[] = {
"t"
};
static const flatbuffers::TypeTable tt = {
flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, nullptr, names
};
return &tt;
}
#endif // FLATBUFFERS_GENERATED_NATIVEINLINETABLETEST_H_

View File

@ -30,6 +30,7 @@
#include "monster_test.h"
#include "monster_test_generated.h"
#include "optional_scalars_test.h"
#include "native_inline_table_test_generated.h"
#include "parser_test.h"
#include "proto_test.h"
#include "reflection_test.h"
@ -1362,6 +1363,30 @@ void VectorSpanTest() {
}
}
void NativeInlineTableVectorTest() {
TestNativeInlineTableT test;
for (int i = 0; i < 10; ++i) {
NativeInlineTableT t;
t.a = i;
test.t.push_back(t);
}
flatbuffers::FlatBufferBuilder fbb;
auto offset = TestNativeInlineTable::Pack(fbb, &test);
fbb.Finish(offset);
auto *root =
flatbuffers::GetRoot<TestNativeInlineTable>(fbb.GetBufferPointer());
TestNativeInlineTableT unpacked;
root->UnPackTo(&unpacked);
for (int i = 0; i < 10; ++i) {
TEST_ASSERT(unpacked.t[i] == test.t[i]);
}
TEST_ASSERT(unpacked.t == test.t);
}
int FlatBufferTests(const std::string &tests_data_path) {
// Run our various test suites:
@ -1460,6 +1485,7 @@ int FlatBufferTests(const std::string &tests_data_path) {
PrivateAnnotationsLeaks();
JsonUnsortedArrayTest();
VectorSpanTest();
NativeInlineTableVectorTest();
return 0;
}
} // namespace