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.util.algo;
26 
27 public import std.array;
28 public import std.algorithm;
29 public import std.range;
30 public import std.traits;
31 
32 template amap(fun...) if ( fun.length >= 1 )
33 {
34     auto amap(Range)(Range r) 
35         if (isInputRange!(Unqual!Range))
36     { return array( map!fun(r) ); }
37 }
38 
39 unittest
40 {
41     int[] res = [ 1, 2, 3 ];
42     void func( int[] arr ) { res ~= arr; }
43     func( amap!(a=>a^^2)(res) );
44     assert( res == [ 1, 2, 3, 1, 4, 9 ] );
45 }
46 
47 bool oneOf(E,T)( T val )
48 {
49     foreach( pv; [EnumMembers!E] )
50         if( pv == val ) return true;
51     return false;
52 }
53 
54 private version(unittest)
55 {
56     enum TestEnum
57     {
58         ONE = 1,
59         TWO = 2,
60         FOUR = 4
61     }
62 }
63 
64 unittest
65 {
66     assert( !oneOf!TestEnum(0) );
67     assert(  oneOf!TestEnum(1) );
68     assert(  oneOf!TestEnum(2) );
69     assert( !oneOf!TestEnum(3) );
70     assert(  oneOf!TestEnum(4) );
71     assert( !oneOf!TestEnum(5) );
72 }
73 
74 bool oneOf(E,T)( E[] arr, T val )
75     if( is( typeof( arr[0] == val ) ) )
76 {
77     foreach( pv; arr ) if( pv == val ) return true;
78     return false;
79 }
80 
81 unittest
82 {
83     assert( !oneOf( [TestEnum.ONE, TestEnum.TWO], 0) );
84     assert(  oneOf( [TestEnum.ONE, TestEnum.TWO], 2) );
85 }
86 
87 struct lim_t(T) if( isNumeric!T )
88 {
89     T minimum=0, maximum=T.max;
90     bool fix = false;
91 
92     pure nothrow this( T Min, T Max )
93     {
94         minimum = Min;
95         maximum = Max;
96     }
97 
98     T opCall( T old, T nval ) const
99     {
100         if( fix ) return old;
101         return nval >= minimum ? ( nval < maximum ? nval : maximum ) : minimum;
102     }
103 }
104 
105 struct ValueHandler(size_t CNT,T=float)
106 if( CNT > 0 && isFloatingPoint!T )
107 {
108 protected:
109     T min_limit;
110     T max_limit;
111 
112     T[CNT] values;
113 
114 public:
115     @property
116     {
117         T minLimit() const { return min_limit; }
118 
119         T minLimit( T v )
120         {
121             min_limit = v > max_limit ? max_limit : v;
122             correctValuesMinMax();
123             return min_limit;
124         }
125 
126         T maxLimit() const { return max_limit; }
127 
128         T maxLimit( T v )
129         {
130             max_limit = v < min_limit ? min_limit : v;
131             correctValuesMinMax();
132             return max_limit;
133         }
134     }
135 
136     T set( size_t i, T v )
137     in{ assert( i < CNT ); }
138     body
139     {
140         import std.algorithm;
141         values[i] = min( max( min_limit, v ), max_limit );
142         moveValues(i);
143         return values[i];
144     }
145 
146     T setNorm( size_t i, T nv )
147     in
148     {
149         assert( i < CNT );
150         assert( nv <= 1.0 );
151     }
152     body
153     {
154         auto v = full(nv);
155         set(i,v);
156         return getNorm(i);
157     }
158 
159     T get( size_t i )
160     in{ assert( i < CNT ); }
161     body { return values[i]; }
162 
163     T getNorm( size_t i )
164     in{ assert( i < CNT ); }
165     body { return norm( get(i) ); }
166 
167 protected:
168 
169     void correctValuesMinMax() { foreach( ref v; values ) correctMinMax( v ); }
170 
171     void correctMinMax( ref T v )
172     { v = ( v >= min_limit ? ( v <= max_limit ? v : max_limit ) : min_limit ); }
173 
174     void moveValues( size_t k )
175     {
176         foreach( i, ref v; values )
177         {
178             if( i == k ) continue;
179             if( i < k && v > values[k] )
180                 v = values[k];
181             if( i > k && v < values[k] )
182                 v = values[k];
183         }
184     }
185 
186     T norm( T v ) const
187     { return (v - min_limit) / (max_limit - min_limit); }
188 
189     T full( T v ) const
190     { return min_limit + v * (max_limit - min_limit); }
191 }
192 
193 unittest
194 {
195     auto vh = ValueHandler!(2,float)();
196 
197     vh.minLimit = 0;
198     vh.maxLimit = 10;
199 
200     vh.set( 0, 5 );
201     vh.set( 1, 7 );
202 
203     assert( vh.get(0) == 5 );
204     assert( vh.get(1) == 7 );
205 
206     vh.set(1,3);
207 
208     assert( vh.get(0) == 3 );
209     assert( vh.get(1) == 3 );
210 }
211 
212 unittest
213 {
214     auto vh = ValueHandler!2();
215 
216     vh.minLimit = 0;
217     vh.maxLimit = 10;
218 
219     vh.setNorm( 0, 0.5 );
220     vh.setNorm( 1, 0.7 );
221 
222     assert( vh.get(0) == 5 );
223     assert( vh.get(1) == 7 );
224 
225     vh.setNorm( 0, 0.8 );
226 
227     assert( vh.get(0) == 8 );
228     assert( vh.get(1) == 8 );
229 
230     import std.math;
231 
232     assert( abs( vh.getNorm(0) - .8 ) < float.epsilon * 2 );
233     assert( abs( vh.getNorm(1) - .8 ) < float.epsilon * 2 );
234 }