std.range.cacheFront proposal&working code: wraps a range to enforce front is called only once
Timothee Cour
thelastmammoth at gmail.com
Tue Oct 22 23:40:00 PDT 2013
Following the recent thread "front evaluated multiple time with joiner
depending on where extra arg given", I'd like to propose the following
addition in std.range :
The goal is to ensure that a given range's 'front' method is called only
once per element, allowing one to handle safely side effects in 'front'
methods
eg use case: lambdas with side effects given to a map/reduce/filter
function, etc.
import std.traits;
import std.range;
struct CacheFront(R){
alias T=ElementType!R;
R a;
import util.traits;
enum isRef=mixin(isLvalue(q{a.front}));
static if(isRef)
T* ai;
else{
T ai;
bool isValid=false;
}
auto ref front(){
//TODO: could also depend on whether front is pure
static if(isRef){
if(ai)
return *ai;
else{
ai=&a.front;
return *ai;
}
}
else{
if(isValid){
return ai;
}
else{
isValid=true;
ai=a.front;
return ai;
}
}
}
void popFront(){
a.popFront;
static if(isRef)
ai=null;
else
isValid=false;
}
//forward other properties automatically:
alias a this;
}
auto cacheFront(R)(R a) if(isInputRange!R){
return CacheFront!R(a);
}
//helper function (should be in phobos' std.traits)
void requireLvalue(T)(ref T);
string isLvalue(string a){
return `__traits(compiles, requireLvalue(`~a~`))`;
}
void main(){
import std.algorithm;
import std.array;
{
//checks that it calls front only once per element
uint counter;
auto b=[1,2,3].map!((a){counter++; return
[a];}).cacheFront.joiner.array;
assert(counter==3);
assert(b==[1,2,3]);
}
{
int counter=0;
auto b=[1,2,3].map!((a){counter++; return [a];}).joiner.array;
assert(counter==6);
}
{
//checks that it works with ref front
auto a0=[1,2,3];
auto ref fun0(ref int a){a=0; return a;}
auto b=a0. cacheFront.map!fun0.array;
assert(b==[0,0,0]);
assert(a0==[0,0,0]);
//checks that it forwards properties of range:
assert([1,2,3]. cacheFront.length==3);
}
}
And a side question: is there a way to denote that a lambda can return by
ref?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20131022/759d14c7/attachment.html>
More information about the Digitalmars-d
mailing list