templated type

This commit is contained in:
2026-07-29 22:57:58 +02:00
parent 81e5f093f9
commit 4f6ad45b0e
10 changed files with 478 additions and 25 deletions
+44
View File
@@ -242,6 +242,50 @@ provide the following functions to aide in the serialization process:
} }
``` ```
- `native_type_template("type<{{T}}>")` (on a struct) together with
`native_type_template_arg("type")` (on a field of that struct type):
lets a single struct declaration back a native type that is a C++
template, instantiated differently per field, instead of requiring one
struct declaration (and `native_type`) per instantiation. For example:
```cpp
struct Box (native_type_template: "Native::Box<{{T}}>") {
value: int32;
}
table Example {
a: Box (native_inline, native_type_template_arg: "Native::TypeA");
b: Box (native_inline, native_type_template_arg: "Native::TypeB");
}
```
is equivalent to writing, on each field itself:
```cpp
a: Box (native_inline, native_type: "Native::Box<Native::TypeA>", native_type_pack_name: "BoxTypeA");
b: Box (native_inline, native_type: "Native::Box<Native::TypeB>", native_type_pack_name: "BoxTypeB");
```
`native_type_template_arg` also auto-derives a `native_type_pack_name` of
`<StructName><ArgShortName>` (here, `BoxTypeA`/`BoxTypeB`) so the Pack/UnPack
functions stay unique across instantiations without spelling it out
yourself; an explicit `native_type_pack_name` on the field still overrides
this. More than one template parameter is supported by separating them with
commas and using indexed placeholders:
```cpp
struct Pair (native_type_template: "Native::Pair<{{T0}}, {{T1}}>") {
value: int32;
}
table Example2 {
p: Pair (native_inline, native_type_template_arg: "Native::Key, Native::Value");
}
```
`native_type_template_arg` is only valid on fields whose type is a struct
(or vector of structs) that declares `native_type_template`.
- `native_type("type")` (on a table): Tables can also be represented with - `native_type("type")` (on a table): Tables can also be represented with
native types. For example, the following schema: native types. For example, the following schema:
+2
View File
@@ -1018,6 +1018,8 @@ class Parser : public ParserState {
known_attributes_["native_custom_alloc"] = true; known_attributes_["native_custom_alloc"] = true;
known_attributes_["native_type"] = true; known_attributes_["native_type"] = true;
known_attributes_["native_type_pack_name"] = true; known_attributes_["native_type_pack_name"] = true;
known_attributes_["native_type_template"] = true;
known_attributes_["native_type_template_arg"] = true;
known_attributes_["native_default"] = true; known_attributes_["native_default"] = true;
known_attributes_["flexbuffer"] = true; known_attributes_["flexbuffer"] = true;
known_attributes_["private"] = true; known_attributes_["private"] = true;
+30 -14
View File
@@ -892,6 +892,24 @@ class CppGenerator : public BaseGenerator {
return opts_.gen_nullable ? " _Nullable " : ""; return opts_.gen_nullable ? " _Nullable " : "";
} }
// A field's `native_type`/`native_type_pack_name` normally come from the
// referenced struct's own declaration. A field can override both (see
// `native_type_template_arg` in idl_parser.cpp, which synthesizes these
// two attributes directly on the field) to instantiate a templated
// native type differently per field.
static const Value* EffectiveNativeType(const FieldDef& field,
const StructDef& struct_def) {
if (const auto v = field.attributes.Lookup("native_type")) return v;
return struct_def.attributes.Lookup("native_type");
}
static const Value* EffectiveNativeTypePackName(const FieldDef& field,
const StructDef& struct_def) {
if (const auto v = field.attributes.Lookup("native_type_pack_name"))
return v;
return struct_def.attributes.Lookup("native_type_pack_name");
}
static std::string NativeName(const std::string& name, const StructDef* sd, static std::string NativeName(const std::string& name, const StructDef* sd,
const IDLOptions& opts) { const IDLOptions& opts) {
// If the table is a native_type, return the native_type name. // If the table is a native_type, return the native_type name.
@@ -1005,7 +1023,7 @@ class CppGenerator : public BaseGenerator {
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
auto type_name = WrapInNameSpace(*type.struct_def); auto type_name = WrapInNameSpace(*type.struct_def);
if (IsStruct(type)) { if (IsStruct(type)) {
auto native_type = type.struct_def->attributes.Lookup("native_type"); auto native_type = EffectiveNativeType(field, *type.struct_def);
if (native_type) { if (native_type) {
type_name = native_type->constant; type_name = native_type->constant;
} }
@@ -3533,11 +3551,11 @@ class CppGenerator : public BaseGenerator {
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
if (IsStruct(type)) { if (IsStruct(type)) {
const auto& struct_attrs = type.struct_def->attributes; const auto native_type = EffectiveNativeType(afield, *type.struct_def);
const auto native_type = struct_attrs.Lookup("native_type");
if (native_type) { if (native_type) {
std::string unpack_call = "::flatbuffers::UnPack"; std::string unpack_call = "::flatbuffers::UnPack";
const auto pack_name = struct_attrs.Lookup("native_type_pack_name"); const auto pack_name =
EffectiveNativeTypePackName(afield, *type.struct_def);
if (pack_name) { if (pack_name) {
unpack_call += pack_name->constant; unpack_call += pack_name->constant;
} }
@@ -3820,9 +3838,8 @@ class CppGenerator : public BaseGenerator {
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
if (IsStruct(vector_type)) { if (IsStruct(vector_type)) {
const auto& struct_attrs = const auto native_type =
field.value.type.struct_def->attributes; EffectiveNativeType(field, *field.value.type.struct_def);
const auto native_type = struct_attrs.Lookup("native_type");
if (native_type) { if (native_type) {
code += "_fbb.CreateVectorOfNativeStructs<"; code += "_fbb.CreateVectorOfNativeStructs<";
code += WrapInNameSpace(*vector_type.struct_def) + ", " + code += WrapInNameSpace(*vector_type.struct_def) + ", " +
@@ -3832,8 +3849,8 @@ class CppGenerator : public BaseGenerator {
} else { } else {
code += "(" + value; code += "(" + value;
} }
const auto pack_name = const auto pack_name = EffectiveNativeTypePackName(
struct_attrs.Lookup("native_type_pack_name"); field, *field.value.type.struct_def);
if (pack_name) { if (pack_name) {
code += ", ::flatbuffers::Pack" + pack_name->constant; code += ", ::flatbuffers::Pack" + pack_name->constant;
} }
@@ -3999,12 +4016,12 @@ class CppGenerator : public BaseGenerator {
} }
case BASE_TYPE_STRUCT: { case BASE_TYPE_STRUCT: {
if (IsStruct(field.value.type)) { if (IsStruct(field.value.type)) {
const auto& struct_attribs = field.value.type.struct_def->attributes; const auto native_type =
const auto native_type = struct_attribs.Lookup("native_type"); EffectiveNativeType(field, *field.value.type.struct_def);
if (native_type && field.native_inline) { if (native_type && field.native_inline) {
code += "::flatbuffers::Pack"; code += "::flatbuffers::Pack";
const auto pack_name = const auto pack_name =
struct_attribs.Lookup("native_type_pack_name"); EffectiveNativeTypePackName(field, *field.value.type.struct_def);
if (pack_name) { if (pack_name) {
code += pack_name->constant; code += pack_name->constant;
} }
@@ -4169,8 +4186,7 @@ class CppGenerator : public BaseGenerator {
if (field->value.type.base_type == BASE_TYPE_STRUCT) { if (field->value.type.base_type == BASE_TYPE_STRUCT) {
if (IsStruct(field->value.type)) { if (IsStruct(field->value.type)) {
auto native_type = auto native_type =
field->value.type.struct_def->attributes.Lookup( EffectiveNativeType(*field, *field->value.type.struct_def);
"native_type");
auto native_inline = field->attributes.Lookup("native_inline"); auto native_inline = field->attributes.Lookup("native_inline");
if (native_type) { if (native_type) {
pass_by_address = true; pass_by_address = true;
+100
View File
@@ -1286,6 +1286,106 @@ CheckedError Parser::ParseField(StructDef& struct_def) {
"'native_inline' can only be defined on structs, vector of structs or " "'native_inline' can only be defined on structs, vector of structs or "
"vector of tables"); "vector of tables");
auto native_type_template_arg =
field->attributes.Lookup("native_type_template_arg");
if (native_type_template_arg) {
if (!IsStruct(field->value.type) && !IsVectorOfStruct(field->value.type))
return Error(
"'native_type_template_arg' can only be defined on struct-typed "
"fields or vectors of structs");
const auto* target_struct = field->value.type.struct_def;
const auto* native_type_template =
target_struct->attributes.Lookup("native_type_template");
if (!native_type_template)
return Error(
"'native_type_template_arg' requires the field's type ('" +
target_struct->name +
"') to declare a 'native_type_template' attribute");
if (field->attributes.Lookup("native_type"))
return Error(
"'native_type_template_arg' cannot be combined with an explicit "
"'native_type' on the same field");
// Split on top-level commas, so multiple template arguments can be
// given (e.g. "::Foo::Key, ::Foo::Value"). Commas nested inside a
// template argument that is itself templated (e.g.
// "std::pair<int, T>") are not treated as separators.
std::vector<std::string> args;
{
const auto& s = native_type_template_arg->constant;
int depth = 0;
size_t start = 0;
for (size_t i = 0; i < s.size(); ++i) {
if (s[i] == '<') {
++depth;
} else if (s[i] == '>') {
--depth;
} else if (s[i] == ',' && depth == 0) {
args.push_back(s.substr(start, i - start));
start = i + 1;
}
}
args.push_back(s.substr(start));
for (auto& arg : args) {
const auto b = arg.find_first_not_of(" \t");
const auto e = arg.find_last_not_of(" \t");
arg = b == std::string::npos ? "" : arg.substr(b, e - b + 1);
if (arg.empty())
return Error(
"'native_type_template_arg' contains an empty template "
"argument");
}
}
// Substitute each argument for its placeholder: `{{T0}}`, `{{T1}}`, etc.
// For a single argument, the unindexed `{{T}}` spelling is also
// accepted (equivalent to `{{T0}}`).
std::string native_type_str = native_type_template->constant;
for (size_t i = 0; i < args.size(); ++i) {
std::vector<std::string> placeholders = { "{{T" + NumToString(i) +
"}}" };
if (i == 0) placeholders.push_back("{{T}}");
size_t replaced = 0;
for (const auto& placeholder : placeholders) {
for (;;) {
const auto pos = native_type_str.find(placeholder);
if (pos == std::string::npos) break;
native_type_str.replace(pos, placeholder.length(), args[i]);
++replaced;
}
}
if (!replaced)
return Error("'native_type_template' on '" + target_struct->name +
"' does not reference the '{{T" + NumToString(i) +
"}}' placeholder required for template argument " +
NumToString(i + 1) + " ('" + args[i] + "')");
}
if (native_type_str.find("{{T") != std::string::npos)
return Error(
"'native_type_template' on '" + target_struct->name +
"' references a '{{T<n>}}' placeholder beyond the " +
NumToString(args.size()) +
" template argument(s) given in 'native_type_template_arg'");
auto native_type_val = new Value();
native_type_val->type = native_type_template_arg->type;
native_type_val->constant = native_type_str;
field->attributes.Add("native_type", native_type_val);
if (!field->attributes.Lookup("native_type_pack_name")) {
std::string pack_name = target_struct->name;
for (const auto& arg : args) {
const auto last_colon = arg.find_last_of(':');
pack_name +=
last_colon == std::string::npos ? arg : arg.substr(last_colon + 1);
}
auto pack_name_val = new Value();
pack_name_val->type = native_type_template_arg->type;
pack_name_val->constant = pack_name;
field->attributes.Add("native_type_pack_name", pack_name_val);
}
}
auto nested = field->attributes.Lookup("nested_flatbuffer"); auto nested = field->attributes.Lookup("nested_flatbuffer");
if (nested) { if (nested) {
if (nested->type.base_type != BASE_TYPE_STRING) if (nested->type.base_type != BASE_TYPE_STRING)
+16
View File
@@ -20,6 +20,19 @@ table Matrix (native_type:"Native::Matrix") {
values:[float]; values:[float];
} }
// A struct whose native type is a template, instantiated differently per
// field via `native_type_template_arg` instead of needing one flatbuffers
// struct declaration per specialization (compare to Vector3D/Vector3DAlt
// above).
struct Tagged (native_type_template: "Native::Tagged<{{T}}>") {
value:int32;
}
// A native type template that takes more than one argument.
struct Pair (native_type_template: "Native::Pair<{{T0}}, {{T1}}>") {
value:int32;
}
table ApplicationData { table ApplicationData {
vectors:[Vector3D]; vectors:[Vector3D];
vectors_alt:[Vector3DAlt]; vectors_alt:[Vector3DAlt];
@@ -27,6 +40,9 @@ table ApplicationData {
position_inline:Vector3D (native_inline); position_inline:Vector3D (native_inline);
matrix:Matrix; matrix:Matrix;
matrices:[Matrix]; matrices:[Matrix];
tagged_a:Tagged (native_inline, native_type_template_arg: "Native::TagA");
tagged_b:Tagged (native_inline, native_type_template_arg: "Native::TagB");
pair_ab:Pair (native_inline, native_type_template_arg: "Native::TagA, Native::TagB");
} }
root_type ApplicationData; root_type ApplicationData;
+191 -11
View File
@@ -24,10 +24,18 @@ struct Vector3DAlt;
struct Matrix; struct Matrix;
struct MatrixBuilder; struct MatrixBuilder;
struct Tagged;
struct Pair;
struct ApplicationData; struct ApplicationData;
struct ApplicationDataBuilder; struct ApplicationDataBuilder;
struct ApplicationDataT; struct ApplicationDataT;
bool operator==(const Tagged &lhs, const Tagged &rhs);
bool operator!=(const Tagged &lhs, const Tagged &rhs);
bool operator==(const Pair &lhs, const Pair &rhs);
bool operator!=(const Pair &lhs, const Pair &rhs);
bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs); bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs);
bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs); bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs);
@@ -37,6 +45,10 @@ inline const ::flatbuffers::TypeTable *Vector3DAltTypeTable();
inline const ::flatbuffers::TypeTable *MatrixTypeTable(); inline const ::flatbuffers::TypeTable *MatrixTypeTable();
inline const ::flatbuffers::TypeTable *TaggedTypeTable();
inline const ::flatbuffers::TypeTable *PairTypeTable();
inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable(); inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable();
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS { FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS {
@@ -121,6 +133,72 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3DAlt FLATBUFFERS_FINAL_CLASS {
}; };
FLATBUFFERS_STRUCT_END(Vector3DAlt, 12); FLATBUFFERS_STRUCT_END(Vector3DAlt, 12);
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Tagged FLATBUFFERS_FINAL_CLASS {
private:
int32_t value_;
public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return TaggedTypeTable();
}
Tagged()
: value_(0) {
}
Tagged(int32_t _value)
: value_(::flatbuffers::EndianScalar(_value)) {
}
int32_t value() const {
return ::flatbuffers::EndianScalar(value_);
}
void mutate_value(int32_t _value) {
::flatbuffers::WriteScalar(&value_, _value);
}
};
FLATBUFFERS_STRUCT_END(Tagged, 4);
inline bool operator==(const Tagged &lhs, const Tagged &rhs) {
return
(lhs.value() == rhs.value());
}
inline bool operator!=(const Tagged &lhs, const Tagged &rhs) {
return !(lhs == rhs);
}
FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Pair FLATBUFFERS_FINAL_CLASS {
private:
int32_t value_;
public:
static const ::flatbuffers::TypeTable *MiniReflectTypeTable() {
return PairTypeTable();
}
Pair()
: value_(0) {
}
Pair(int32_t _value)
: value_(::flatbuffers::EndianScalar(_value)) {
}
int32_t value() const {
return ::flatbuffers::EndianScalar(value_);
}
void mutate_value(int32_t _value) {
::flatbuffers::WriteScalar(&value_, _value);
}
};
FLATBUFFERS_STRUCT_END(Pair, 4);
inline bool operator==(const Pair &lhs, const Pair &rhs) {
return
(lhs.value() == rhs.value());
}
inline bool operator!=(const Pair &lhs, const Pair &rhs) {
return !(lhs == rhs);
}
struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { struct Matrix FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
typedef Native::Matrix NativeTableType; typedef Native::Matrix NativeTableType;
typedef MatrixBuilder Builder; typedef MatrixBuilder Builder;
@@ -223,6 +301,9 @@ struct ApplicationDataT : public ::flatbuffers::NativeTable {
Native::Vector3D position_inline{}; Native::Vector3D position_inline{};
std::unique_ptr<Native::Matrix> matrix{}; std::unique_ptr<Native::Matrix> matrix{};
std::vector<std::unique_ptr<Native::Matrix>> matrices{}; std::vector<std::unique_ptr<Native::Matrix>> matrices{};
Native::Tagged<Native::TagA> tagged_a{};
Native::Tagged<Native::TagB> tagged_b{};
Native::Pair<Native::TagA, Native::TagB> pair_ab{};
ApplicationDataT() = default; ApplicationDataT() = default;
ApplicationDataT(const ApplicationDataT &o); ApplicationDataT(const ApplicationDataT &o);
ApplicationDataT(ApplicationDataT&&) FLATBUFFERS_NOEXCEPT = default; ApplicationDataT(ApplicationDataT&&) FLATBUFFERS_NOEXCEPT = default;
@@ -241,7 +322,10 @@ struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
VT_POSITION = 8, VT_POSITION = 8,
VT_POSITION_INLINE = 10, VT_POSITION_INLINE = 10,
VT_MATRIX = 12, VT_MATRIX = 12,
VT_MATRICES = 14 VT_MATRICES = 14,
VT_TAGGED_A = 16,
VT_TAGGED_B = 18,
VT_PAIR_AB = 20
}; };
const ::flatbuffers::Vector<const Geometry::Vector3D *> *vectors() const { const ::flatbuffers::Vector<const Geometry::Vector3D *> *vectors() const {
return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS); return GetPointer<const ::flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS);
@@ -279,6 +363,24 @@ struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *mutable_matrices() { ::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *mutable_matrices() {
return GetPointer<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *>(VT_MATRICES); return GetPointer<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>> *>(VT_MATRICES);
} }
const Geometry::Tagged *tagged_a() const {
return GetStruct<const Geometry::Tagged *>(VT_TAGGED_A);
}
Geometry::Tagged *mutable_tagged_a() {
return GetStruct<Geometry::Tagged *>(VT_TAGGED_A);
}
const Geometry::Tagged *tagged_b() const {
return GetStruct<const Geometry::Tagged *>(VT_TAGGED_B);
}
Geometry::Tagged *mutable_tagged_b() {
return GetStruct<Geometry::Tagged *>(VT_TAGGED_B);
}
const Geometry::Pair *pair_ab() const {
return GetStruct<const Geometry::Pair *>(VT_PAIR_AB);
}
Geometry::Pair *mutable_pair_ab() {
return GetStruct<Geometry::Pair *>(VT_PAIR_AB);
}
template <bool B = false> template <bool B = false>
bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const { bool Verify(::flatbuffers::VerifierTemplate<B> &verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
@@ -293,6 +395,9 @@ struct ApplicationData FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
VerifyOffset(verifier, VT_MATRICES) && VerifyOffset(verifier, VT_MATRICES) &&
verifier.VerifyVector(matrices()) && verifier.VerifyVector(matrices()) &&
verifier.VerifyVectorOfTables(matrices()) && verifier.VerifyVectorOfTables(matrices()) &&
VerifyField<Geometry::Tagged>(verifier, VT_TAGGED_A, 4) &&
VerifyField<Geometry::Tagged>(verifier, VT_TAGGED_B, 4) &&
VerifyField<Geometry::Pair>(verifier, VT_PAIR_AB, 4) &&
verifier.EndTable(); verifier.EndTable();
} }
ApplicationDataT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const; ApplicationDataT *UnPack(const ::flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -322,6 +427,15 @@ struct ApplicationDataBuilder {
void add_matrices(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>>> matrices) { void add_matrices(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset<Geometry::Matrix>>> matrices) {
fbb_.AddOffset(ApplicationData::VT_MATRICES, matrices); fbb_.AddOffset(ApplicationData::VT_MATRICES, matrices);
} }
void add_tagged_a(const Geometry::Tagged *tagged_a) {
fbb_.AddStruct(ApplicationData::VT_TAGGED_A, tagged_a);
}
void add_tagged_b(const Geometry::Tagged *tagged_b) {
fbb_.AddStruct(ApplicationData::VT_TAGGED_B, tagged_b);
}
void add_pair_ab(const Geometry::Pair *pair_ab) {
fbb_.AddStruct(ApplicationData::VT_PAIR_AB, pair_ab);
}
explicit ApplicationDataBuilder(::flatbuffers::FlatBufferBuilder &_fbb) explicit ApplicationDataBuilder(::flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) { : fbb_(_fbb) {
start_ = fbb_.StartTable(); start_ = fbb_.StartTable();
@@ -340,8 +454,14 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(
const Geometry::Vector3D *position = nullptr, const Geometry::Vector3D *position = nullptr,
const Geometry::Vector3D *position_inline = nullptr, const Geometry::Vector3D *position_inline = nullptr,
::flatbuffers::Offset<Geometry::Matrix> matrix = 0, ::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::Tagged *tagged_a = nullptr,
const Geometry::Tagged *tagged_b = nullptr,
const Geometry::Pair *pair_ab = nullptr) {
ApplicationDataBuilder builder_(_fbb); ApplicationDataBuilder builder_(_fbb);
builder_.add_pair_ab(pair_ab);
builder_.add_tagged_b(tagged_b);
builder_.add_tagged_a(tagged_a);
builder_.add_matrices(matrices); builder_.add_matrices(matrices);
builder_.add_matrix(matrix); builder_.add_matrix(matrix);
builder_.add_position_inline(position_inline); builder_.add_position_inline(position_inline);
@@ -358,7 +478,10 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
const Geometry::Vector3D *position = nullptr, const Geometry::Vector3D *position = nullptr,
const Geometry::Vector3D *position_inline = nullptr, const Geometry::Vector3D *position_inline = nullptr,
::flatbuffers::Offset<Geometry::Matrix> matrix = 0, ::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::Tagged *tagged_a = nullptr,
const Geometry::Tagged *tagged_b = nullptr,
const Geometry::Pair *pair_ab = nullptr) {
auto vectors__ = vectors ? _fbb.CreateVectorOfStructs<Geometry::Vector3D>(*vectors) : 0; auto vectors__ = vectors ? _fbb.CreateVectorOfStructs<Geometry::Vector3D>(*vectors) : 0;
auto vectors_alt__ = vectors_alt ? _fbb.CreateVectorOfStructs<Geometry::Vector3DAlt>(*vectors_alt) : 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 matrices__ = matrices ? _fbb.CreateVector<::flatbuffers::Offset<Geometry::Matrix>>(*matrices) : 0;
@@ -369,7 +492,10 @@ inline ::flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
position, position,
position_inline, position_inline,
matrix, matrix,
matrices__); matrices__,
tagged_a,
tagged_b,
pair_ab);
} }
::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr); ::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher = nullptr);
@@ -392,7 +518,10 @@ inline bool operator==(const ApplicationDataT &lhs, const ApplicationDataT &rhs)
((lhs.position == rhs.position) || (lhs.position && rhs.position && *lhs.position == *rhs.position)) && ((lhs.position == rhs.position) || (lhs.position && rhs.position && *lhs.position == *rhs.position)) &&
(lhs.position_inline == rhs.position_inline) && (lhs.position_inline == rhs.position_inline) &&
((lhs.matrix == rhs.matrix) || (lhs.matrix && rhs.matrix && *lhs.matrix == *rhs.matrix)) && ((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.tagged_a == rhs.tagged_a) &&
(lhs.tagged_b == rhs.tagged_b) &&
(lhs.pair_ab == rhs.pair_ab);
} }
inline bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs) { inline bool operator!=(const ApplicationDataT &lhs, const ApplicationDataT &rhs) {
@@ -405,7 +534,10 @@ inline ApplicationDataT::ApplicationDataT(const ApplicationDataT &o)
vectors_alt(o.vectors_alt), vectors_alt(o.vectors_alt),
position((o.position) ? new Native::Vector3D(*o.position) : nullptr), position((o.position) ? new Native::Vector3D(*o.position) : nullptr),
position_inline(o.position_inline), position_inline(o.position_inline),
matrix((o.matrix) ? new Native::Matrix(*o.matrix) : nullptr) { matrix((o.matrix) ? new Native::Matrix(*o.matrix) : nullptr),
tagged_a(o.tagged_a),
tagged_b(o.tagged_b),
pair_ab(o.pair_ab) {
matrices.reserve(o.matrices.size()); matrices.reserve(o.matrices.size());
for (const auto &matrices_ : o.matrices) { matrices.emplace_back((matrices_) ? new Native::Matrix(*matrices_) : nullptr); } for (const auto &matrices_ : o.matrices) { matrices.emplace_back((matrices_) ? new Native::Matrix(*matrices_) : nullptr); }
} }
@@ -417,6 +549,9 @@ inline ApplicationDataT &ApplicationDataT::operator=(ApplicationDataT o) FLATBUF
std::swap(position_inline, o.position_inline); std::swap(position_inline, o.position_inline);
std::swap(matrix, o.matrix); std::swap(matrix, o.matrix);
std::swap(matrices, o.matrices); std::swap(matrices, o.matrices);
std::swap(tagged_a, o.tagged_a);
std::swap(tagged_b, o.tagged_b);
std::swap(pair_ab, o.pair_ab);
return *this; return *this;
} }
@@ -435,6 +570,9 @@ inline void ApplicationData::UnPackTo(ApplicationDataT *_o, const ::flatbuffers:
{ auto _e = position_inline(); if (_e) _o->position_inline = ::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<Native::Matrix>(_e->UnPack(_resolver)); } } else if (_o->matrix) { _o->matrix.reset(); } } { 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 = 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 = tagged_a(); if (_e) _o->tagged_a = ::flatbuffers::UnPackTaggedTagA(*_e); }
{ auto _e = tagged_b(); if (_e) _o->tagged_b = ::flatbuffers::UnPackTaggedTagB(*_e); }
{ auto _e = pair_ab(); if (_e) _o->pair_ab = ::flatbuffers::UnPackPairTagATagB(*_e); }
} }
inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) { inline ::flatbuffers::Offset<ApplicationData> CreateApplicationData(::flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const ::flatbuffers::rehasher_function_t *_rehasher) {
@@ -451,6 +589,9 @@ inline ::flatbuffers::Offset<ApplicationData> ApplicationData::Pack(::flatbuffer
auto _position_inline = ::flatbuffers::Pack(_o->position_inline); auto _position_inline = ::flatbuffers::Pack(_o->position_inline);
auto _matrix = _o->matrix ? CreateMatrix(_fbb, _o->matrix.get(), _rehasher) : 0; 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 _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 _tagged_a = ::flatbuffers::PackTaggedTagA(_o->tagged_a);
auto _tagged_b = ::flatbuffers::PackTaggedTagB(_o->tagged_b);
auto _pair_ab = ::flatbuffers::PackPairTagATagB(_o->pair_ab);
return Geometry::CreateApplicationData( return Geometry::CreateApplicationData(
_fbb, _fbb,
_vectors, _vectors,
@@ -458,7 +599,10 @@ inline ::flatbuffers::Offset<ApplicationData> ApplicationData::Pack(::flatbuffer
_o->position ? &_position : nullptr, _o->position ? &_position : nullptr,
&_position_inline, &_position_inline,
_matrix, _matrix,
_matrices); _matrices,
&_tagged_a,
&_tagged_b,
&_pair_ab);
} }
inline const ::flatbuffers::TypeTable *Vector3DTypeTable() { inline const ::flatbuffers::TypeTable *Vector3DTypeTable() {
@@ -514,6 +658,34 @@ inline const ::flatbuffers::TypeTable *MatrixTypeTable() {
return &tt; return &tt;
} }
inline const ::flatbuffers::TypeTable *TaggedTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_INT, 0, -1 }
};
static const int64_t values[] = { 0, 4 };
static const char * const names[] = {
"value"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 1, type_codes, nullptr, nullptr, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *PairTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_INT, 0, -1 }
};
static const int64_t values[] = { 0, 4 };
static const char * const names[] = {
"value"
};
static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_STRUCT, 1, type_codes, nullptr, nullptr, values, names
};
return &tt;
}
inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable() { inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable() {
static const ::flatbuffers::TypeCode type_codes[] = { static const ::flatbuffers::TypeCode type_codes[] = {
{ ::flatbuffers::ET_SEQUENCE, 1, 0 }, { ::flatbuffers::ET_SEQUENCE, 1, 0 },
@@ -521,12 +693,17 @@ inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable() {
{ ::flatbuffers::ET_SEQUENCE, 0, 0 }, { ::flatbuffers::ET_SEQUENCE, 0, 0 },
{ ::flatbuffers::ET_SEQUENCE, 0, 0 }, { ::flatbuffers::ET_SEQUENCE, 0, 0 },
{ ::flatbuffers::ET_SEQUENCE, 0, 2 }, { ::flatbuffers::ET_SEQUENCE, 0, 2 },
{ ::flatbuffers::ET_SEQUENCE, 1, 2 } { ::flatbuffers::ET_SEQUENCE, 1, 2 },
{ ::flatbuffers::ET_SEQUENCE, 0, 3 },
{ ::flatbuffers::ET_SEQUENCE, 0, 3 },
{ ::flatbuffers::ET_SEQUENCE, 0, 4 }
}; };
static const ::flatbuffers::TypeFunction type_refs[] = { static const ::flatbuffers::TypeFunction type_refs[] = {
Geometry::Vector3DTypeTable, Geometry::Vector3DTypeTable,
Geometry::Vector3DAltTypeTable, Geometry::Vector3DAltTypeTable,
Geometry::MatrixTypeTable Geometry::MatrixTypeTable,
Geometry::TaggedTypeTable,
Geometry::PairTypeTable
}; };
static const char * const names[] = { static const char * const names[] = {
"vectors", "vectors",
@@ -534,10 +711,13 @@ inline const ::flatbuffers::TypeTable *ApplicationDataTypeTable() {
"position", "position",
"position_inline", "position_inline",
"matrix", "matrix",
"matrices" "matrices",
"tagged_a",
"tagged_b",
"pair_ab"
}; };
static const ::flatbuffers::TypeTable tt = { static const ::flatbuffers::TypeTable tt = {
::flatbuffers::ST_TABLE, 6, type_codes, type_refs, nullptr, nullptr, names ::flatbuffers::ST_TABLE, 9, type_codes, type_refs, nullptr, nullptr, names
}; };
return &tt; return &tt;
} }
+28
View File
@@ -18,6 +18,34 @@ Geometry::Vector3DAlt PackVector3DAlt(const Native::Vector3D& obj) {
const Native::Vector3D UnPackVector3DAlt(const Geometry::Vector3DAlt& obj) { const Native::Vector3D UnPackVector3DAlt(const Geometry::Vector3DAlt& obj) {
return Native::Vector3D(obj.a(), obj.b(), obj.c()); return Native::Vector3D(obj.a(), obj.b(), obj.c());
} }
Geometry::Tagged PackTaggedTagA(const Native::Tagged<Native::TagA>& obj) {
return Geometry::Tagged(obj.value);
}
const Native::Tagged<Native::TagA> UnPackTaggedTagA(
const Geometry::Tagged& obj) {
return Native::Tagged<Native::TagA>(obj.value());
}
Geometry::Tagged PackTaggedTagB(const Native::Tagged<Native::TagB>& obj) {
return Geometry::Tagged(obj.value);
}
const Native::Tagged<Native::TagB> UnPackTaggedTagB(
const Geometry::Tagged& obj) {
return Native::Tagged<Native::TagB>(obj.value());
}
Geometry::Pair PackPairTagATagB(
const Native::Pair<Native::TagA, Native::TagB>& obj) {
return Geometry::Pair(obj.value);
}
const Native::Pair<Native::TagA, Native::TagB> UnPackPairTagATagB(
const Geometry::Pair& obj) {
return Native::Pair<Native::TagA, Native::TagB>(obj.value());
}
} // namespace flatbuffers } // namespace flatbuffers
namespace Geometry { namespace Geometry {
+41
View File
@@ -43,11 +43,42 @@ struct Matrix {
(values == other.values); (values == other.values);
} }
}; };
// Phantom tag types used purely to select a template specialization; they
// carry no data of their own.
struct TagA {};
struct TagB {};
// A native type template, instantiated per-field in the schema via
// `native_type_template_arg` rather than needing one flatbuffers struct
// declaration per specialization.
template <typename T>
struct Tagged {
int32_t value;
Tagged() : value(0) {}
explicit Tagged(int32_t _value) : value(_value) {}
bool operator==(const Tagged& other) const { return value == other.value; }
};
// A native type template taking more than one argument.
template <typename T0, typename T1>
struct Pair {
int32_t value;
Pair() : value(0) {}
explicit Pair(int32_t _value) : value(_value) {}
bool operator==(const Pair& other) const { return value == other.value; }
};
} // namespace Native } // namespace Native
namespace Geometry { namespace Geometry {
struct Vector3D; struct Vector3D;
struct Vector3DAlt; struct Vector3DAlt;
struct Tagged;
struct Pair;
} // namespace Geometry } // namespace Geometry
namespace flatbuffers { namespace flatbuffers {
@@ -55,6 +86,16 @@ Geometry::Vector3D Pack(const Native::Vector3D& obj);
const Native::Vector3D UnPack(const Geometry::Vector3D& obj); const Native::Vector3D UnPack(const Geometry::Vector3D& obj);
Geometry::Vector3DAlt PackVector3DAlt(const Native::Vector3D& obj); Geometry::Vector3DAlt PackVector3DAlt(const Native::Vector3D& obj);
const Native::Vector3D UnPackVector3DAlt(const Geometry::Vector3DAlt& obj); const Native::Vector3D UnPackVector3DAlt(const Geometry::Vector3DAlt& obj);
Geometry::Tagged PackTaggedTagA(const Native::Tagged<Native::TagA>& obj);
const Native::Tagged<Native::TagA> UnPackTaggedTagA(const Geometry::Tagged& obj);
Geometry::Tagged PackTaggedTagB(const Native::Tagged<Native::TagB>& obj);
const Native::Tagged<Native::TagB> UnPackTaggedTagB(const Geometry::Tagged& obj);
Geometry::Pair PackPairTagATagB(
const Native::Pair<Native::TagA, Native::TagB>& obj);
const Native::Pair<Native::TagA, Native::TagB> UnPackPairTagATagB(
const Geometry::Pair& obj);
} // namespace flatbuffers } // namespace flatbuffers
#endif // VECTOR3D_PACK_H #endif // VECTOR3D_PACK_H
+19
View File
@@ -97,6 +97,25 @@ void ErrorTest() {
"datatype already"); "datatype already");
TestError("struct X (force_align: 7) { Y:int; }", "force_align"); TestError("struct X (force_align: 7) { Y:int; }", "force_align");
TestError("struct X {}", "size 0"); TestError("struct X {}", "size 0");
TestError(
"struct X { Y:int; } table T { y:X (native_type_template_arg:\"int\"); "
"}",
"'native_type_template' attribute");
TestError(
"table T { y:int (native_type_template_arg:\"int\"); }",
"struct-typed fields");
TestError(
"struct X (native_type_template: \"Foo\") { Y:int; } "
"table T { y:X (native_type_template_arg:\"int\"); }",
"does not reference");
TestError(
"struct X (native_type_template: \"Foo<{{T0}}, {{T1}}>\") { Y:int; } "
"table T { y:X (native_type_template_arg:\"int\"); }",
"beyond the");
TestError(
"struct X (native_type_template: \"Foo<{{T}}>\") { Y:int; } "
"table T { y:X (native_type_template_arg:\"\"); }",
"empty template argument");
TestError("{}", "no root"); TestError("{}", "no root");
TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file"); TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }", TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
+7
View File
@@ -930,6 +930,10 @@ void NativeTypeTest() {
Native::Vector3D(20 * i + 0.1f, 20 * i + 0.2f, 20 * i + 0.3f)); Native::Vector3D(20 * i + 0.1f, 20 * i + 0.2f, 20 * i + 0.3f));
} }
src_data.tagged_a = Native::Tagged<Native::TagA>(7);
src_data.tagged_b = Native::Tagged<Native::TagB>(8);
src_data.pair_ab = Native::Pair<Native::TagA, Native::TagB>(9);
src_data.matrix = std::unique_ptr<Native::Matrix>(new Native::Matrix(1, 2)); src_data.matrix = std::unique_ptr<Native::Matrix>(new Native::Matrix(1, 2));
src_data.matrix->values = {3, 4}; src_data.matrix->values = {3, 4};
@@ -951,6 +955,9 @@ void NativeTypeTest() {
TEST_EQ(dstDataT->position_inline.x, 4.0f); TEST_EQ(dstDataT->position_inline.x, 4.0f);
TEST_EQ(dstDataT->position_inline.y, 5.0f); TEST_EQ(dstDataT->position_inline.y, 5.0f);
TEST_EQ(dstDataT->position_inline.z, 6.0f); TEST_EQ(dstDataT->position_inline.z, 6.0f);
TEST_EQ(dstDataT->tagged_a.value, 7);
TEST_EQ(dstDataT->tagged_b.value, 8);
TEST_EQ(dstDataT->pair_ab.value, 9);
for (int i = 0; i < N; ++i) { for (int i = 0; i < N; ++i) {
const Native::Vector3D& v = dstDataT->vectors[i]; const Native::Vector3D& v = dstDataT->vectors[i];