www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using the functions "map" and "any" on tuples in compile time.

reply realhet <real_het hotmail.com> writes:
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)
Apr 12 2020
parent reply Harry Gillanders <ayjsy47yyz8 temp.mailbox.org> writes:
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.
Apr 12 2020
parent realhet <real_het hotmail.com> writes:
On Sunday, 12 April 2020 at 12:42:40 UTC, Harry Gillanders wrote:
 On Sunday, 12 April 2020 at 11:17:39 UTC, realhet wrote:
I only remembered the __traits(identifier...), but completely forgot about the getMember. And I never heard of anySatisfy. My JSON serializer is beautiful now. Thank You very much!
Apr 12 2020