1 module des.math.util.flatdata;
2 
3 import std.traits;
4 import std..string;
5 import std.typetuple;
6 
7 import des.util.testsuite;
8 import des.math.basic.traits;
9 import des.math.linear.vector;
10 
11 ///
12 pure auto flatData(T,E...)( in E vals ) if( E.length > 0 )
13 {
14     T[] buf;
15     foreach( e; vals ) buf ~= flatValue!T(e);
16     return buf;
17 }
18 
19 ///
20 unittest
21 {
22     assert( eq( flatData!float([1.0,2],[[3,4]],5,[6,7]), [1,2,3,4,5,6,7] ) );
23     static assert( !__traits(compiles,flatData!char([1.0,2],[[300,4]],5,[6,7])) );
24     static assert(  __traits(compiles,flatData!ubyte([1.0,2],[[300,4]],5,[6,7])) );
25     static assert(  __traits(compiles,flatData!char("hello", "world")) );
26     assert( eq( flatData!cfloat(1-1i,2,3i), [1-1i,2+0i,0+3i] ) );
27 }
28 
29 ///
30 template hasIterableData(T)
31 { enum hasIterableData = is( typeof( isIterable!(typeof(T.init.data)) ) ); }
32 
33 pure auto flatValue(T,E)( in E val )
34 {
35     static if( isNumeric!T && isNumeric!E ) return [ cast(T)val ];
36     else static if( isComplex!T && ( isNumeric!E || isImaginary!E ) ) return [ T(0+0i+val) ];
37     else static if( is(typeof(T(val))) ) return [ T(val) ];
38     else static if( isIterable!E )
39     {
40         T[] buf;
41         foreach( v; val )
42             buf ~= flatValue!T(v);
43         return buf;
44     }
45     else static if( hasIterableData!E ) return flatValue!T(val.data);
46     else static assert(0, format("uncompatible types %s and %s", T.stringof, E.stringof ) );
47 }
48 
49 bool canStaticFill(size_t N,T,E...)() pure @property
50 if( E.length > 0 )
51 { return hasNoDynamic!E && N == getElemCount!E && isConvertable!(T,E); }
52 
53 bool hasNoDynamic(E...)() pure @property
54 {
55     static if( E.length == 1 ) return !hasIndirections!(E[0]);
56     else return hasNoDynamic!(E[0]) && hasNoDynamic!(E[1..$]);
57 }
58 
59 size_t getElemCount(E...)() pure @property
60 {
61     static if( E.length == 0 ) return 0;
62     else static if( E.length >= 1 )
63         return getTypeElemCount!(E[0]) + getElemCount!(E[1..$]);
64 }
65 
66 size_t getTypeElemCount(E)() pure @property
67 {
68     static if( isStaticArray!E ) return E.length;
69     else static if( isStaticVector!E ) return E.data.length;
70     else return 1;
71 }
72 
73 bool isConvertable(T,E...)() pure @property
74 {
75     static if( E.length == 1 )
76     {
77         alias E[0] X;
78         static if( is( typeof( T(X.init) ) ) ) return true;
79         else static if( isComplex!T && ( isNumeric!X || isImaginary!X ) ) return true;
80         else static if( isNumeric!X && isNumeric!T ) return true;
81         else static if( isStaticArray!X ) return isConvertable!(T,typeof(X.init[0]));
82         else static if( isStaticVector!X )
83         {
84             static if( isStaticVector!T )
85                 return T.length == X.length && isConvertable!(T.datatype,X.datatype);
86             else
87                 return isConvertable!(T,X.datatype);
88         }
89         else return false;
90     }
91     else return isConvertable!(T,E[0]) && isConvertable!(T,E[1..$]);
92 }
93 
94 string vectorStaticFill(string type, string data, string vals, T, E...)() pure @property
95 if( E.length > 0 )
96 {
97     string[] ret;
98     static if( isStaticVector!T )
99     {
100         ret ~= convertValues!(T.datatype,E)( type~".datatype", data, vals );
101         foreach( i, ref r; ret )
102             r = format( "%1$s[%2$s/%3$s][%2$s%%%3$s] = %4$s;", data, i, T.length, r );
103     }
104     else
105     {
106         ret ~= convertValues!(T,E)( type, data, vals );
107         foreach( i, ref r; ret )
108             r = format( "%s[%s] = %s;", data, i, r );
109     }
110     return ret.join("\n");
111 }
112 
113 string matrixStaticFill(string type, string data, string vals, size_t W, T, E...)() pure @property
114 if( E.length > 0 )
115 {
116     string[] ret;
117     ret ~= convertValues!(T,E)( type, data, vals );
118     foreach( i, ref r; ret )
119         r = format( "%s[%s][%s] = %s;", data, i/W, i%W, r );
120     return ret.join("\n");
121 }
122 
123 string[] convertValues(T,E...)( string type, string data, string vals, size_t valno=0 ) pure
124 {
125     static if( E.length == 1 )
126         return convertValue!(T,E[0])(type,data,vals,valno);
127     else
128         return convertValue!(T,E[0])(type,data,vals,valno) ~ 
129                convertValues!(T,E[1..$])(type,data,vals,valno+1); 
130 
131 }
132 
133 string[] convertValue(T, E)( string type, string data, string vals, size_t valno ) pure
134 {
135     static if( isStaticArray!E || isStaticVector!E )
136     {
137         string[] ret;
138         foreach( i; 0 .. E.length )
139             ret ~= format( convertRule!(T,typeof(E.init[0])), type, format( "%s[%d][%d]", vals, valno, i ) );
140         return ret;
141     }
142     else
143         return [ format( convertRule!(T,E), type, format( "%s[%d]", vals, valno ) ) ];
144 }
145 
146 string convertRule(T,E)() pure @property
147 {
148     static if( isNumeric!E && isNumeric!T )
149         return "cast(%s)(%s)";
150     else static if( isComplex!T && ( isNumeric!E || isImaginary!E ) )
151         return "%s(0+0i+%s)";
152     else static if( is( typeof( T(E.init) ) ) )
153         return "%s(%s)";
154     else static assert( 0, "uncompatible types [convertRule]" );
155 }