1 /**
2 Copyright: Copyright Thomas Stuart Bockman 2015
3 License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
4 Authors: Thomas Stuart Bockman
5 */
6 
7 module checkedint.tests.contract.smartop;
8 import checkedint.tests.contract.internal;
9 
10 import checkedint.flags;
11 
12 void all() {
13     writeln();
14     write("Testing smartOp... ");
15     stdout.flush();
16 
17     cmp();
18     abs();
19     unary();
20     binary();
21     byPow2();
22     pow();
23 
24     writeln("DONE");
25 }
26 
27 /+@safe:+/
28 
29 void cmp(string op = null, N = void, M = void)() {
30     static if(op == null) {
31         foreach(op1; AliasSeq!("==", "!=", "<", "<=", ">", ">="))
32             cmp!(op1, N, M)();
33     } else
34     static if(is(N == void)) {
35         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
36             cmp!(op, N1, M)();
37     } else
38     static if(is(M == void)) {
39         foreach(M1; AliasSeq!(IntegralTypes, CharTypes))
40             cmp!(op, N, M1)();
41     } else {
42         static assert(isScalarType!N && isScalarType!M);
43 
44         static void cover(bool direct)() {
45             static if(direct)
46                 enum sc = "smartOp.cmp!\"" ~ op ~ "\"(n, m)";
47             else
48                 enum sc = "smartOp.cmp(n, m) " ~ op ~ " 0";
49 
50             static assert(real.mant_dig >= max(precision!N, precision!M));
51             auto control(const real n, const real m) {
52                 auto wret = stdm.cmp(n, m);
53                 return mixin("wret " ~ op ~ " 0");
54             }
55 
56             fuzz!(sc, Unqual, OutIs!bool, control, N, M)();
57         }
58         cover!true();
59         cover!false();
60     }
61 }
62 alias cmp(N, M = void) = cmp!(null, N, M);
63 
64 void abs(N = void)() {
65     static if(is(N == void)) {
66         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
67             abs!N1();
68     } else {
69         static assert(isFixedPoint!N);
70 
71         enum sc = "smartOp.abs(n)";
72 
73         static assert(real.mant_dig >= precision!N);
74         auto control(const real n, Unused m = null) {
75             return stdm.abs(n); }
76         alias R = Unsigned!(IntFromChar!N);
77 
78         fuzz!(sc, Unqual, OutIs!R, control, N)();
79     }
80 }
81 
82 void unary(string op = null, N = void)() {
83     static if(op == null) {
84         foreach(op1; AliasSeq!("~", "+", "-", "++", "--"))
85             unary!(op1, N)();
86     } else
87     static if(is(N == void)) {
88         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
89             unary!(op, N1)();
90     } else {
91         static assert(isFixedPoint!N);
92 
93         enum sc = "smartOp.unary!\"" ~ op ~ "\"(n)";
94 
95         static assert(real.mant_dig >= precision!N);
96         auto control(Select!(op == "~", N, real) n, Unused m = null) {
97             return mixin(op ~ "n"); }
98         enum isVO(N, M, PR) = (PR.sizeof >= N.sizeof) && (isSigned!PR || !op.among!("-", "+"));
99 
100         static if(isIntegral!N || !op.among!("++", "--"))
101             fuzz!(sc, Unqual, isVO, control, N)();
102         else
103             forbid!(sc, N)();
104     }
105 }
106 alias unary(N) = unary!(null, N);
107 
108 void binary(string op = null, N = void, M = void)() {
109     static if(op == null) {
110         foreach(op1; AliasSeq!("+", "-", "*", "/", "%", "<<", ">>", ">>>", "&", "|", "^"))
111             binary!(op1, N, M)();
112     } else
113     static if(is(N == void)) {
114         foreach(N1; AliasSeq!(IntegralTypes/+TODO:, CharTypes+/))
115             binary!(op, N1, M)();
116     } else
117     static if(is(M == void)) {
118         foreach(M1; AliasSeq!(IntegralTypes/+TODO:, CharTypes+/))
119             binary!(op, N, M1)();
120     } else {
121         static assert(isFixedPoint!N && isFixedPoint!M);
122 
123         enum sc = "smartOp.binary!\"" ~ op ~ "\"(n, m)";
124 
125         static assert(real.mant_dig >= max(precision!N, precision!M));
126         static if(op.among!("<<", ">>", ">>>")) {
127             static N control(const N n, const M m) {
128                 const shL = (op == "<<") ^ (m < 0);
129                 enum int maxSh = (8 * N.sizeof) - 1;
130                 const um = cast(Unsigned!M)std.math.abs(m);
131 
132                 static if(op == ">>>")
133                     auto wret = cast(Unsigned!N)n;
134                 else
135                     N wret = n;
136                 bool again = um > maxSh;
137                 const im = again? maxSh : cast(int)um;
138             Lagain:
139                 wret = cast(typeof(wret))(shL?
140                     wret << im :
141                     wret >> im);
142                 if(again) {
143                     again = false;
144                     goto Lagain;
145                 }
146 
147                 return cast(N)wret;
148             }
149             enum isVO(N, M, PR) = is(PR == N);
150         } else
151         static if(op.among!("&", "|", "^")) {
152             static auto control(const N n, const M m) {
153                 alias P = Select!(N.sizeof >= M.sizeof, N, M);
154                 alias R = Select!(isSigned!N && isSigned!M, P, Unsigned!P);
155 
156                 return cast(R)mixin("n " ~ op ~ " m");
157             }
158             template isVO(N, M, PR) {
159                 private alias UR = Unsigned!PR;
160                 enum isVO = (isSigned!PR == (isSigned!N && isSigned!M)) &&
161                     (is(UR == Unsigned!N) || is(UR == Unsigned!M));
162             }
163         } else {
164             static auto control(const real n, const real m) {
165                 static if(op == "/")
166                     return stdm.trunc(n / m);
167                 else
168                     return mixin("n " ~ op ~ " m");
169             }
170             enum isVO(N, M, PR) = isIntegral!PR &&
171                 ((isSigned!PR == (isSigned!N || (isSigned!M && op != "%"))) || op == "-");
172         }
173 
174         fuzz!(sc, Unqual, isVO, control, N, M)();
175     }
176 }
177 alias binary(N, M = void) = binary!(null, N, M);
178 
179 void byPow2(N = void, M = void)() {
180     static if(is(N == void)) {
181         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
182             byPow2!(N1, M)();
183     } else
184     static if(is(M == void)) {
185         foreach(M1; AliasSeq!(IntegralTypes, CharTypes))
186             byPow2!(N, M1)();
187     } else {
188         static assert(isScalarType!N && isScalarType!M);
189 
190         static void cover(bool mul)() {
191             enum sc = "smartOp." ~ (mul? "mul" : "div") ~ "Pow2(n, m)";
192 
193             static assert(real.mant_dig >= max(precision!N, precision!M));
194             real control(const real n, const real m) {
195                 if(n == 0 && stdm.isFinite(m))
196                     return 0;
197                 else {
198                     const p2 = stdm.exp2(m);
199                     const wret = mul? (n * p2) : (n / p2);
200                     static if(isFloatingPoint!N || isFloatingPoint!M)
201                         return wret;
202                     else
203                         return stdm.trunc(wret);
204                 }
205             }
206             enum isVO(N, M, PR) = (PR.sizeof >= N.sizeof) &&
207                 ((isFloatingPoint!N || isFloatingPoint!M)?
208                     isFloatingPoint!PR :
209                     isIntegral!PR && (isSigned!PR || !isSigned!N));
210 
211             fuzz!(sc, Unqual, isVO, control, N, M)();
212         }
213         cover!true();
214         cover!false();
215     }
216 }
217 
218 void pow(N = void, M = void)() {
219     static if(is(N == void)) {
220         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
221             pow!(N1, M)();
222     } else
223     static if(is(M == void)) {
224         foreach(M1; AliasSeq!(IntegralTypes, CharTypes))
225             pow!(N, M1)();
226     } else {
227         static assert(isFixedPoint!N && isFixedPoint!M);
228         forbid!("smartOp.binary!\"^^\"(n, m)", N, M)();
229         forbid!("smartOp.binary!\"^^=\"(n, m)", N, M)();
230 
231         enum sc = "smartOp.pow(n, m)";
232 
233         static assert(real.mant_dig >= max(precision!N, precision!M));
234         real control(const real n, const real m) {
235             static if(__VERSION__ >= 2070) {
236                 version(GNU) { static assert(false); }
237                 return stdm.trunc(stdm.pow(n, m));
238             } else {
239                 // DMD issue #14786
240                 if(n == -1 && stdm.fabs(m) <= ulong.max)
241                     return (cast(ulong)m & 0x1)? -1 : 1;
242                 else
243                     return stdm.trunc(stdm.pow(n, m));
244             }
245         }
246         enum isVO(N, M, PR) = isIntegral!PR && (PR.sizeof >= N.sizeof) && (isSigned!PR == isSigned!N);
247 
248         fuzz!(sc, Unqual, isVO, control, N, M)();
249     }
250 }