On 7/26/20 3:10 AM, Charles wrote:
Suppose I have the following line of code where arr is an array, doSomething is some predicate that does a lot of processing on each element, sort must come after the mapping, and there are more operations done to the range after sort:

arr.map!doSomething.sort. ...;

Sort fails to instantiate because the range it's receiving doesn't support element swapping. This may and might be resolved by calling array:

arr.map!doSomething.array.sort. ...;

However, this might trigger an allocation, and there's still more to do! Is there something I'm missing with regards to ranges that could help me make the first line work without using array, or is it more of an issue with my code's design?

That is what you need to do.

A map that returns an lvalue would be sortable, but you would be sorting the processed elements, and probably not the original elements.

I have found this handy tool quite useful in my code where I need a temporary array:

// creates a concrete range (std.container.array.Array range) out of the
// original range that is eagerly fetched, and then can be processed, without
// allocating extra garbage on the heap.
auto concreteRange(Range)(Range r)
{
    import std.range : ElementType;
    import std.container.array : Array;
    return Array!(ElementType!Range)(r)[];
}

Slicing an Array will keep the reference count correctly, and destroy the memory automatically after you're done using it. So it's perfect for temporary arrays in pipelining.

-Steve

Reply via email to