1 module des.stdx.range; 2 3 public import std.range; 4 5 import std.conv; 6 import std.algorithm; 7 8 import des.stdx.traits; 9 import des.ts; 10 11 private version(unittest) 12 { 13 struct VecN(size_t N){ float[N] data; alias data this; } 14 alias Vec=VecN!3; 15 static assert( canUseAsArray!Vec ); 16 } 17 18 /++ fill output range with result of fn() called per elements 19 +/ 20 void mapFlat(alias fn,R,V,E...)( ref R output, V val, E tail ) 21 if( is( typeof( output.put( fn( (ElementTypeRec!V).init ) ) ) ) ) 22 { 23 static if( E.length > 0 ) 24 { 25 mapFlat!fn( output, val ); 26 mapFlat!fn( output, tail ); 27 } 28 else 29 { 30 static if( isInputRange!V ) 31 foreach( l; val ) mapFlat!fn( output, l ); 32 else static if( canUseAsArray!V ) 33 foreach( i; 0 .. val.length ) 34 mapFlat!fn( output, val[i] ); 35 else static if( is( ElementTypeRec!V == V ) ) 36 output.put( fn( val ) ); 37 else static assert( 0, "V has elements, " ~ 38 "but isn't input range, or not have length" ); 39 } 40 } 41 42 /// 43 unittest 44 { 45 import std.array; 46 47 auto app = appender!(int[])(); 48 mapFlat!(a=>to!int(a)*2)( app, [1,2], 3, 49 [[4,5],[6]], 50 iota(7,9), 51 [[[9],[10,11]],[[12]]], 52 Vec([13.3,666,105]) ); 53 assertEq( app.data, [2,4,6,8,10,12,14,16,18,20,22,24,26,1332,210] ); 54 } 55 56 /// 57 template ElementTypeRec(T) 58 { 59 static if( is( ElementType!T == void ) ) // is not range or array 60 alias ElementTypeRec = T; 61 else // if is range or array 62 alias ElementTypeRec = ElementTypeRec!(ElementType!T); 63 } 64 65 /// 66 unittest 67 { 68 static assert( is( ElementTypeRec!int == int ) ); 69 static assert( is( ElementTypeRec!(int[]) == int ) ); 70 static assert( is( ElementTypeRec!(int[2]) == int ) ); 71 static assert( is( ElementTypeRec!(int[][]) == int ) ); 72 static assert( is( ElementTypeRec!(int[3][2]) == int ) ); 73 static assert( is( ElementTypeRec!(typeof(iota(7))) == int ) ); 74 static assert( is( ElementTypeRec!(VecN!10) == float ) ); 75 } 76 77 /++ fill output range with flat values 78 +/ 79 void fillFlat(T,R,V,E...)( ref R output, V val, E tail ) 80 if( isOutputRange!(R,T) ) 81 { mapFlat!(a=>to!T(a))( output, val, tail ); } 82 83 /// 84 unittest 85 { 86 import std.array; 87 88 auto app = appender!(int[])(); 89 fillFlat!int( app, [1,2], 3, 90 [[4,5],[6]], 91 iota(7,9), 92 [[[9],[10,11]],[[12]]], 93 Vec([13.3,666,105]) ); 94 assertEq( app.data, [1,2,3,4,5,6,7,8,9,10,11,12,13,666,105] ); 95 } 96 97 /++ get flat length of values 98 +/ 99 size_t getFlatLength(V,E...)( V val, E tail ) @nogc 100 { 101 static if( E.length > 0 ) 102 return getFlatLength( val ) + getFlatLength( tail ); 103 else 104 { 105 static if( isInfinite!V ) 106 static assert( 0, "not support infinite range" ); 107 else static if( isForwardRange!V ) 108 return val.save().map!(a=>getFlatLength(a)).sum; 109 else static if( canUseAsArray!V ) 110 { 111 size_t s = 0; 112 foreach( i; 0 .. val.length ) 113 s += getFlatLength( val[i] ); 114 return s; 115 } 116 else static if( is( ElementType!V == void ) ) 117 return 1; 118 else static assert( 0, "unsupported type" ); 119 } 120 } 121 122 /// 123 unittest 124 { 125 assertEq( getFlatLength( 1,2,3 ), 3 ); 126 assertEq( getFlatLength( [1,2,3] ), 3 ); 127 assertEq( getFlatLength( Vec([1,2,3]) ), 3 ); 128 assertEq( getFlatLength( [1,2], 3, [[[4],[5,6]],[[7,8,9]]], Vec([1,2,3]) ), 12 ); 129 assertEq( getFlatLength( 1, 2, iota(4) ), 6 ); 130 assertEq( getFlatLength( 1, 2, iota(4) ), 6 ); 131 } 132 133 /// return output range with reference to array 134 auto arrayOutputRange(A)( ref A arr ) 135 if( isArray!A || isStaticArray!A ) 136 { 137 alias T = ElementType!A; 138 139 static struct Result 140 { 141 T* end, cur; 142 143 this( T* start, T* end ) 144 { 145 this.cur = start; 146 this.end = end; 147 } 148 149 void put( T val ) 150 { 151 assert( cur != end ); 152 *(cur++) = val; 153 } 154 } 155 156 return Result( arr.ptr, arr.ptr + arr.length ); 157 } 158 159 /// 160 unittest 161 { 162 int[13] arr1; 163 auto rng1 = arrayOutputRange( arr1 ); 164 fillFlat!int( rng1, [1,2], 3, [[4,5],[6]], iota(7,9), [[[9],[10,11]],[[12]]] ); 165 assertEq( arr1, [1,2,3,4,5,6,7,8,9,10,11,12,0] ); 166 167 int[] arr2 = new int[]( 13 ) ; 168 auto rng2 = arrayOutputRange( arr2 ); 169 fillFlat!int( rng2, [1,2], 3, [[4,5],[6]], iota(7,9), [[[9],[10,11]],[[12]]] ); 170 assertEq( arr2, [1,2,3,4,5,6,7,8,9,10,11,12,0] ); 171 } 172 173 /// create flat copy of vals 174 auto flatData(T,E...)( in E vals ) 175 if( E.length > 0 ) 176 { 177 auto ret = appender!(T[])(); 178 fillFlat!T( ret, vals ); 179 return ret.data; 180 } 181 182 /// 183 unittest 184 { 185 assertEq( flatData!float([1.0,2],[[3,4]],5,[6,7]), [1,2,3,4,5,6,7] ); 186 187 assertEq( flatData!double( VecN!3([1,2,3]) ), [1,2,3] ); 188 assertEq( flatData!double( VecN!1([2]) ), [2] ); 189 }