| |
| Posted by Harry Gillanders in reply to realhet | PermalinkReply |
|
Harry Gillanders
Posted in reply to realhet
| 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.
|