the source _range to cache elements of
the minimum capacity to use for CircularBlocks, which is used as storage for the cached elements; the default value attemps to use one page of memory
Although opIndex is provided, isRandomAccessRange produces false because this implementation is not a BidirectionalRange at this time.
Todo:
Add opApplyReverse support and BidirectionalRange functions
// In the following typical usage, even though `slide(2)` would visit most // elements more than once, `cached` guarantees that the lambda function // executed by `map` will be executed only once per range element. auto r = iota(4) .map!(i => i * i) // [0, 1, 4, 9] .cached .slide(2) .array; // There are 3 sliding windows of width 2 over 4 elements r.length.shouldBe(3); assert(r[0].equal([0, 1])); assert(r[1].equal([1, 4])); assert(r[2].equal([4, 9]));
// Random access over an InputRange import std.algorithm : splitter; import std.range : popFrontN; auto lines = "monday,tuesday,wednesday,thursday"; auto s = lines.splitter(','); auto c = s.cached; // The source range does not provide random access: static assert(!__traits(compiles, s[0])); // The cached range does: assert(c[2] == "wednesday"); assert(c[1] == "tuesday"); c.popFrontN(3); // Now index 0 is another element assert(c[0] == "thursday");
// This version uses an existing buffer. It may never need to allocate // additional heap memory. ubyte[1024][2] buffers; auto r = iota(4) .map!(i => i * i) .cached(buffers) // Will use the provided buffers .slide(2) .array; r.length.shouldBe(3);
A _range algorithm that caches the elements of a _range by evaluating them only once.
As a natural benefit of caching, the returned _range is a ForwardRange even if the source _range is an InputRange. Although the returned _range provides opIndex, it is a RandomAccessRange only if the source _range hasLength.
The version that takes buffers may never need to allocate memory if the number of elements never exceed the capacity of the underlying CircularBlocks. (See CircularBlocks.)