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