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