Using the functions "map" and "any" on tuples in compile time.
Harry Gillanders
ayjsy47yyz8 at temp.mailbox.org
Sun Apr 12 12:42:40 UTC 2020
On Sunday, 12 April 2020 at 11:17:39 UTC, realhet wrote:
> Hello, anyone can help me make this better?
>
> The functionality I want to achieve is: While serializing the
> fields of a struct, I want it to check the @STORED UDA on every
> field. If there is no fields are marked with @STORED, that
> means every field must be serialized. Otherwise only the marked
> one.
>
> I had problems using map and any, so I come up with this lame
> foreach version: It works, but I think it does it in runtime.
>
> bool anySTORED = false;
> static foreach(fieldName; FieldNameTuple!T)
> mixin("anySTORED |= hasUDA!(data.*,
> STORED);".replace("*", fieldName));
>
> static foreach(fieldName; FieldNameTuple!T){{
> mixin("const thisSTORED = hasUDA!(data.*,
> STORED);".replace("*", fieldName));
> if(thisSTORED || !anySTORED)
> mixin("streamAppend_json!(dense, fieldName)(st, data.*,
> nextIndent);".replace("*", fieldName));
> }}
>
> Thanks in advance!
>
> (ps: I just love string mixins, I know :D)
Using a compile-time tuple as a range is easy, turn it into an
array via an
array literal (surround it in square bracket), e.g.
struct Foo
{
int a;
int b;
}
pragma(msg, [FieldNameTuple!Foo].map!(f => f ~ "_").array());
However, if you were to try that with `any` for `hasUDA`, wherein
the arguments
for `any`'s predicate are used for `hasUDA`'s template
parameters, you'll find that it
won't compile. That's because `any`'s predicate is a runtime
function, executed
at compile-time via CTFE, so the argument technically isn't known
at compile-time
for the `hasUDA` template, e.g.
struct Foo
{
int a;
int b;
}
enum STORED;
enum bool anyStored = [FieldNameTuple!Foo].any!(
f => hasUDA!(__traits(getMember, Foo, f), STORED)
);
The solution to that is to define a template predicate, and use
std.meta.anySatisfy,
instead of `any`. Which would accomplish what you want to do,
with something like so:
string serialiseFields (T) (auto ref T instance)
{
enum bool hasStored (string fieldName) =
hasUDA!(__traits(getMember, T, fieldName), STORED);
enum fields = FieldNameTuple!T;
static if (anySatisfy!(hasStored, fields))
{
enum fieldsToSerialise = Filter!(hasStored, fields);
}
else
{
enum fieldsToSerialise = fields;
}
string serialise (string name, T) (auto ref T value)
{
return format!(name ~ " = %s")(value);
}
string serialised;
static foreach (field; fieldsToSerialise)
{
serialised ~= serialise!field(__traits(getMember, instance,
field)) ~ "\n";
}
return serialised;
}
---
This source code in this reply is licensed under the terms of
Creative Commons CC0 1.0.
More information about the Digitalmars-d-learn
mailing list