<div dir="ltr"><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">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 :</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">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</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">eg use case: lambdas with side effects given to a map/reduce/filter function, etc.</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">import std.traits;<br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
import std.range;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">struct CacheFront(R){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> alias T=ElementType!R;</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> R a;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> import util.traits;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
enum isRef=mixin(isLvalue(q{a.front}));</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> static if(isRef)</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> T* ai;</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> else{</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> T ai; </div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
bool isValid=false;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> auto ref front(){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
//TODO: could also depend on whether front is pure</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> static if(isRef){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
if(ai)</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> return *ai;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> else{</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
ai=&a.front;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> return *ai;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> else{</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> if(isValid){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
return ai;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> else{</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
isValid=true;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> ai=a.front;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> return ai;</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> } </div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> void popFront(){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> a.popFront;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
static if(isRef)</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> ai=null;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> else</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
isValid=false;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> //forward other properties automatically:</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> alias a this;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
auto cacheFront(R)(R a) if(isInputRange!R){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> return CacheFront!R(a);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">//helper function (should be in phobos' std.traits)</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><div>void requireLvalue(T)(ref T);</div><div>string isLvalue(string a){</div><div><span style="white-space:pre-wrap"> </span>return `__traits(compiles, requireLvalue(`~a~`))`;</div>
<div>}</div></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">void main(){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
import std.algorithm;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> import std.array;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> {</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
//checks that it calls front only once per element</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> uint counter;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
auto b=[1,2,3].map!((a){counter++; return [a];}).cacheFront.joiner.array;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> assert(counter==3);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
assert(b==[1,2,3]);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> {</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
int counter=0;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> auto b=[1,2,3].map!((a){counter++; return [a];}).joiner.array;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
assert(counter==6);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> {</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
//checks that it works with ref front</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> auto a0=[1,2,3];</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> auto ref fun0(ref int a){a=0; return a;}</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> auto b=a0. cacheFront.map!fun0.array;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> assert(b==[0,0,0]);</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> assert(a0==[0,0,0]);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
//checks that it forwards properties of range:</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> assert([1,2,3]. cacheFront.length==3);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
<br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">And a side question: is there a way to denote that a lambda can return by ref? </div></div>