Choice ranges?
Timon Gehr
timon.gehr at gmx.ch
Sat Mar 29 08:27:14 PDT 2014
On 03/28/2014 08:00 PM, H. S. Teoh wrote:
> Today I ran into an interesting situation where I have a function f that
> needs to return ranges of different types (but identical element types):
>
> auto f(A...)(A args) {
> ...
> if (someCondition)
> return cartesianProduct(x, y)
> .joiner;
> else
> return cartesianProduct(x, y)
> .joiner
> .filter!someFilter;
> }
>
> This obviously can't compile, because the return types are not the same.
> (Note that someCondition is only known at runtime.) But abstractly
> speaking, it *should* work, because the element type of the returned
> range is identical.
>
> So how would I implement something like this?
>
>
> T
>
The following is as close as I got. I think the definite initialization
checks DMD implements are horribly broken for union fields.
import std.range, std.algorithm, std.typetuple, std.traits;
template CommonElementType(T...)if(allSatisfy!(isInputRange,T)){
alias CommonElementType = CommonType!(staticMap!(ElementType,T));
}
private template Neg(alias a){
enum Neg(T...)=!a!T;
}
struct
SumRange(T...)if(allSatisfy!(isInputRange,T)&&!is(void==CommonElementType!T)&&allSatisfy!(Neg!hasElaborateDestructor,T)&&allSatisfy!(Neg!hasElaborateCopyConstructor,T)){
size_t tag;
private union{ T rs=void; }
// private this();
@property front()@trusted{
switch(tag){
foreach(i,_;T) case i: return rs[i].front;
default: assert(0);
}
}
@property bool empty()@trusted{
switch(tag){
foreach(i,_;T) case i: return rs[i].empty;
default: assert(0);
}
}
void popFront()@trusted{
switch(tag){
foreach(i,_;T) case i: return rs[i].popFront();
default: assert(0);
}
}
}
private T buildSum(T, size_t tag,S)(S arg)@trusted{
T r;
r.tag=tag;
r.rs[tag]=arg;
return r;
}
auto inl(T,S)(S
arg)if(!hasElaborateDestructor!S&&!hasElaborateDestructor!T&&!hasElaborateCopyConstructor!S&&!hasElaborateCopyConstructor!T){
return buildSum!(SumRange!(S,T),0)(arg);
}
auto inr(S,T)(T
arg)if(!hasElaborateDestructor!S&&!hasElaborateDestructor!T&&!hasElaborateCopyConstructor!S&&!hasElaborateCopyConstructor!T){
return buildSum!(SumRange!(S,T),1)(arg);
}
auto f(R,S)(bool condition,R x,S y){
auto r1(){
return cartesianProduct(x, y).map!(a=>[a.expand])
.joiner;
}
auto r2(){
return cartesianProduct(x, y).map!(a=>[a.expand])
.joiner
.filter!(a=>a>2);
}
if(condition) return r1().inl!(typeof(r2()));
else return r2().inr!(typeof(r1()));
}
void main(){
import std.stdio;
writeln(f(true, [1,2,3], [4,5,6]));
writeln(f(false, [1,2,3], [4,5,6]));
}
More information about the Digitalmars-d-learn
mailing list