Skip to content

Instantly share code, notes, and snippets.

@AndrejMitrovic
Created February 21, 2020 16:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndrejMitrovic/282d062c09a6df697476a8304bb23c19 to your computer and use it in GitHub Desktop.
Save AndrejMitrovic/282d062c09a6df697476a8304bb23c19 to your computer and use it in GitHub Desktop.
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