Simplify templates

This commit is contained in:
2026-07-29 23:11:48 +02:00
parent 4f6ad45b0e
commit a06c41f2c7
4 changed files with 21 additions and 42 deletions
+11 -5
View File
@@ -242,14 +242,19 @@ provide the following functions to aide in the serialization process:
}
```
- `native_type_template("type<{{T}}>")` (on a struct) together with
- `native_type_template("type")` (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:
struct declaration (and `native_type`) per instantiation.
`native_type_template_arg` is angle-bracket-appended to
`native_type_template` to form the field's native type, so
`native_type_template: "Native::Box"` with
`native_type_template_arg: "Native::TypeA"` produces
`Native::Box<Native::TypeA>`. For example:
```cpp
struct Box (native_type_template: "Native::Box<{{T}}>") {
struct Box (native_type_template: "Native::Box") {
value: int32;
}
@@ -271,10 +276,10 @@ is equivalent to writing, on each field itself:
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:
commas:
```cpp
struct Pair (native_type_template: "Native::Pair<{{T0}}, {{T1}}>") {
struct Pair (native_type_template: "Native::Pair") {
value: int32;
}
@@ -283,6 +288,7 @@ commas and using indexed placeholders:
}
```
which produces `Native::Pair<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`.
+8 -27
View File
@@ -1337,35 +1337,16 @@ CheckedError Parser::ParseField(StructDef& struct_def) {
}
}
// 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;
// The native type is `native_type_template`, the bare template name,
// with the arguments appended as a trailing, angle-bracketed template
// argument list, e.g. "Native::Box" + ["Native::TypeA"] ->
// "Native::Box<Native::TypeA>".
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 (i) native_type_str += ", ";
native_type_str += 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'");
native_type_str += ">";
auto native_type_val = new Value();
native_type_val->type = native_type_template_arg->type;
+2 -2
View File
@@ -24,12 +24,12 @@ table Matrix (native_type:"Native::Matrix") {
// 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}}>") {
struct Tagged (native_type_template: "Native::Tagged") {
value:int32;
}
// A native type template that takes more than one argument.
struct Pair (native_type_template: "Native::Pair<{{T0}}, {{T1}}>") {
struct Pair (native_type_template: "Native::Pair") {
value:int32;
}
-8
View File
@@ -106,14 +106,6 @@ void ErrorTest() {
"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");