Created
February 21, 2020 16:41
-
-
Save AndrejMitrovic/282d062c09a6df697476a8304bb23c19 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module get_recursive; | |
import std.concurrency; | |
import std.conv; | |
import std.range; | |
import std.traits; | |
private struct GetRecursive (alias getter, T) | |
{ | |
alias Target = ReturnType!({ T t; return getter(t); }); | |
/// Generator is a class, hacks ahead | |
private void[__traits(classInstanceSize, Generator!Target)] _buf; | |
private Generator!Target gen; | |
private T input; | |
///// Ctor | |
private this (T input) | |
{ | |
this.input = input; | |
auto support = (() @trusted => cast(Generator!Target)(_buf.ptr))(); | |
this.gen = emplace!(Generator!Target)(support, | |
{ | |
yieldValue!getter(this.input); | |
}); | |
} | |
/// Walk through the fields and invoke the getter, | |
/// Unless the field is a range of T elements, then recurse. | |
private static void yieldValue (alias getter)(T obj) | |
{ | |
yield(getter(obj)); | |
// try to recurse | |
foreach (field; __traits(allMembers, T)) | |
{ | |
alias Type = mixin("typeof(T." ~ field ~ ")"); | |
static if (isInputRange!Type && is(ElementType!Type == T)) | |
{ | |
foreach (val; __traits(getMember, obj, field)) | |
yieldValue!getter(val); // recurse | |
} | |
} | |
} | |
// alias this needs to be public.. | |
public auto getGen() { return gen; } | |
alias getGen this; // expose range interface | |
} | |
public auto getRecursive (alias getter, T)(T input) | |
{ | |
return GetRecursive!(getter, T)(input); | |
} | |
/// create some deeply nested nodes | |
private Node getNode () | |
{ | |
Node node1; | |
node1.name = "Node A"; | |
node1.numbers = [1]; | |
Node node2; | |
node2.name = "Node B"; | |
node2.numbers = [2]; | |
Node node3; | |
node3.name = "Node C"; | |
node3.numbers = [3]; | |
Node node4; | |
node4.name = "Node D"; | |
node4.numbers = [4]; | |
Node node5; | |
node5.name = "Node E"; | |
node5.numbers = [5]; | |
Node node6; | |
node6.name = "Node F"; | |
node6.numbers = [6]; | |
Node node7; | |
node7.name = "Node G"; | |
node7.numbers = [7]; | |
node3.nodes = [node6, node7]; | |
node2.nodes = [node4, node5]; | |
node1.nodes = [node2, node3]; | |
return node1; | |
} | |
struct Node | |
{ | |
string name; | |
int[] numbers; | |
Node[] nodes; | |
} | |
void main () | |
{ | |
import std.algorithm; | |
import std.stdio; | |
auto node = getNode(); | |
// bug: two 'each' templates match in std.algorithm.iteration, | |
// probably to do with ref/non-ref | |
//auto r = node.getRecursive!(n => n.numbers) | |
// .each!(numbers => writeln(numbers)); | |
auto r = node.getRecursive!(n => n.numbers); | |
r.each!(numbers => writeln(numbers)); | |
auto r2 = node.getRecursive!(n => n.name); | |
r2.each!(name => writeln(name)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment