1 /+
2 The MIT License (MIT)
3 
4     Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)>
5 
6     Permission is hereby granted, free of charge, to any person obtaining a copy
7     of this software and associated documentation files (the "Software"), to deal
8     in the Software without restriction, including without limitation the rights
9     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10     copies of the Software, and to permit persons to whom the Software is
11     furnished to do so, subject to the following conditions:
12 
13     The above copyright notice and this permission notice shall be included in
14     all copies or substantial portions of the Software.
15 
16     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22     THE SOFTWARE.
23 +/
24 
25 module des.math.util.flatdata;
26 
27 import std.traits;
28 import std.string;
29 import std.typetuple;
30 
31 import des.util.testsuite;
32 import des.math.basic.traits;
33 import des.math.linear.vector;
34 
35 ///
36 pure auto flatData(T,E...)( in E vals ) if( E.length > 0 )
37 {
38     T[] buf;
39     foreach( e; vals ) buf ~= flatValue!T(e);
40     return buf;
41 }
42 
43 ///
44 unittest
45 {
46     assert( eq( flatData!float([1.0,2],[[3,4]],5,[6,7]), [1,2,3,4,5,6,7] ) );
47     static assert( !__traits(compiles,flatData!char([1.0,2],[[300,4]],5,[6,7])) );
48     static assert(  __traits(compiles,flatData!ubyte([1.0,2],[[300,4]],5,[6,7])) );
49     static assert(  __traits(compiles,flatData!char("hello", "world")) );
50     assert( eq( flatData!cfloat(1-1i,2,3i), [1-1i,2+0i,0+3i] ) );
51 }
52 
53 ///
54 template hasIterableData(T)
55 { enum hasIterableData = is( typeof( isIterable!(typeof(T.init.data)) ) ); }
56 
57 pure auto flatValue(T,E)( in E val )
58 {
59     static if( isNumeric!T && isNumeric!E ) return [ cast(T)val ];
60     else static if( isComplex!T && ( isNumeric!E || isImaginary!E ) ) return [ T(0+0i+val) ];
61     else static if( is(typeof(T(val))) ) return [ T(val) ];
62     else static if( isIterable!E )
63     {
64         T[] buf;
65         foreach( v; val )
66             buf ~= flatValue!T(v);
67         return buf;
68     }
69     else static if( hasIterableData!E ) return flatValue!T(val.data);
70     else static assert(0, format("uncompatible types %s and %s", T.stringof, E.stringof ) );
71 }
72 
73 bool canStaticFill(size_t N,T,E...)() pure @property
74 if( E.length > 0 )
75 { return hasNoDynamic!E && N == getElemCount!E && isConvertable!(T,E); }
76 
77 bool hasNoDynamic(E...)() pure @property
78 {
79     static if( E.length == 1 ) return !hasIndirections!(E[0]);
80     else return hasNoDynamic!(E[0]) && hasNoDynamic!(E[1..$]);
81 }
82 
83 size_t getElemCount(E...)() pure @property
84 {
85     static if( E.length == 0 ) return 0;
86     else static if( E.length >= 1 )
87         return getTypeElemCount!(E[0]) + getElemCount!(E[1..$]);
88 }
89 
90 size_t getTypeElemCount(E)() pure @property
91 {
92     static if( isStaticArray!E ) return E.length;
93     else static if( isStaticVector!E ) return E.data.length;
94     else return 1;
95 }
96 
97 bool isConvertable(T,E...)() pure @property
98 {
99     static if( E.length == 1 )
100     {
101         alias E[0] X;
102         static if( is( typeof( T(X.init) ) ) ) return true;
103         else static if( isComplex!T && ( isNumeric!X || isImaginary!X ) ) return true;
104         else static if( isNumeric!X && isNumeric!T ) return true;
105         else static if( isStaticArray!X ) return isConvertable!(T,typeof(X.init[0]));
106         else static if( isStaticVector!X )
107         {
108             static if( isStaticVector!T )
109                 return T.length == X.length && isConvertable!(T.datatype,X.datatype);
110             else
111                 return isConvertable!(T,X.datatype);
112         }
113         else return false;
114     }
115     else return isConvertable!(T,E[0]) && isConvertable!(T,E[1..$]);
116 }
117 
118 string vectorStaticFill(string type, string data, string vals, T, E...)() pure @property
119 if( E.length > 0 )
120 {
121     string[] ret;
122     static if( isStaticVector!T )
123     {
124         ret ~= convertValues!(T.datatype,E)( type~".datatype", data, vals );
125         foreach( i, ref r; ret )
126             r = format( "%1$s[%2$s/%3$s][%2$s%%%3$s] = %4$s;", data, i, T.length, r );
127     }
128     else
129     {
130         ret ~= convertValues!(T,E)( type, data, vals );
131         foreach( i, ref r; ret )
132             r = format( "%s[%s] = %s;", data, i, r );
133     }
134     return ret.join("\n");
135 }
136 
137 string matrixStaticFill(string type, string data, string vals, size_t W, T, E...)() pure @property
138 if( E.length > 0 )
139 {
140     string[] ret;
141     ret ~= convertValues!(T,E)( type, data, vals );
142     foreach( i, ref r; ret )
143         r = format( "%s[%s][%s] = %s;", data, i/W, i%W, r );
144     return ret.join("\n");
145 }
146 
147 string[] convertValues(T,E...)( string type, string data, string vals, size_t valno=0 ) pure
148 {
149     static if( E.length == 1 )
150         return convertValue!(T,E[0])(type,data,vals,valno);
151     else
152         return convertValue!(T,E[0])(type,data,vals,valno) ~ 
153                convertValues!(T,E[1..$])(type,data,vals,valno+1); 
154 
155 }
156 
157 string[] convertValue(T, E)( string type, string data, string vals, size_t valno ) pure
158 {
159     static if( isStaticArray!E || isStaticVector!E )
160     {
161         string[] ret;
162         foreach( i; 0 .. E.length )
163             ret ~= format( convertRule!(T,typeof(E.init[0])), type, format( "%s[%d][%d]", vals, valno, i ) );
164         return ret;
165     }
166     else
167         return [ format( convertRule!(T,E), type, format( "%s[%d]", vals, valno ) ) ];
168 }
169 
170 string convertRule(T,E)() pure @property
171 {
172     static if( isNumeric!E && isNumeric!T )
173         return "cast(%s)(%s)";
174     else static if( isComplex!T && ( isNumeric!E || isImaginary!E ) )
175         return "%s(0+0i+%s)";
176     else static if( is( typeof( T(E.init) ) ) )
177         return "%s(%s)";
178     else static assert( 0, "uncompatible types [convertRule]" );
179 }