I'm using the phobos "chain" function to iterate over a set of string arrays. However, one of the variables is actually an array of structs that each contain a string array. So I use "map" to get a range of string arrays, but "chain" expects each variable to be a string array, not a range of string arrays. The solution I came up with was to find a way to convert a range of ranges into one range. I couldn't find this transformation in phobos. Does anyone know if it already exists? It's actually similar to chain itself but chains a range of ranges, not a tuple of ranges. I implemented something that works below, but would love to use something that already exists in phobos.

import std.stdio, std.range, std.algorithm;

struct MyStrings
{
    string[] strings;
}

void main()
{
    auto normalStringArray1 = ["a", "b", "c"];
    auto normalStringArray2 = ["d", "e", "f"];
    auto myStringArrays = [
        MyStrings(["g", "h", "i"]),
        MyStrings(["j", "k", "l"]),
    ];

    foreach(str; chain(
        normalStringArray1,
        normalStringArray2,
        splice(map!(a => a.strings)(myStringArrays))))
    {
        writeln(str);
    }
}

auto splice(Range)(Range inputRange)
{
    static struct SplicedRanges(K)
    {
        static assert(K.init.empty);

        Range inputRange;
        K current;
        this(Range inputRange)
        {
            this.inputRange = inputRange;
            if(!this.inputRange.empty)
            {
                current = this.inputRange.front;
                if(current.empty)
                {
                    setCurrentToNext();
                }
            }
        }

        private void setCurrentToNext()
        {
            while(!inputRange.empty)
            {
                inputRange.popFront;
                if(inputRange.empty)
                {
                    break;
                }
                current = inputRange.front;
                if(!current.empty)
                {
                    break;
                }
            }
        }

        @property bool empty()
        {
            return current.empty;
        }
        @property auto front()
        {
            return current.front;
        }
        void popFront()
        {
            if(!current.empty)
            {
                current.popFront;
                if(!current.empty)
                {
                    return;
                }
            }
            setCurrentToNext();
        }
    }

    return SplicedRanges!(typeof(inputRange.front))(inputRange);
}

Reply via email to