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.safeop;
8 import checkedint.tests.contract.internal;
9 
10 import checkedint.flags, checkedint.noex.safeop;
11 
12 void all() {
13     writeln();
14     write("Testing safeOp... ");
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 = "safeOp.cmp!\"" ~ op ~ "\"(n, m)";
47             else
48                 enum sc = "safeOp.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             static if(mostNegative!N <= cast(M)0 && mostNegative!M <= cast(N)0)
57                 fuzz!(sc, Unqual, OutIs!bool, control, N, M)();
58             else
59                 forbid!(sc, N, M)();
60         }
61         cover!true();
62         cover!false();
63     }
64 }
65 alias cmp(N, M = void) = cmp!(null, N, M);
66 
67 void abs(N = void)() {
68     static if(is(N == void)) {
69         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
70             abs!N1();
71     } else {
72         static assert(isFixedPoint!N);
73 
74         enum sc = "safeOp.abs(n)";
75 
76         static assert(real.mant_dig >= (8 * N.sizeof));
77         auto control(const real n, Unused m = null) {
78             return stdm.abs(n); }
79         alias R = CallType!(stdm.abs, N);
80 
81         static if(isIntegral!R)
82             fuzz!(sc, Unqual, OutIs!R, control, N)();
83         else
84             forbid!(sc, N)();
85     }
86 }
87 
88 void unary(string op = null, N = void)() {
89     static if(op == null) {
90         foreach(op1; AliasSeq!("+", "-", "~", "++", "--"))
91             unary!(op1, N)();
92     } else
93     static if(is(N == void)) {
94         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
95             unary!(op, N1)();
96     } else {
97         static assert(isFixedPoint!N);
98 
99         enum sc = "safeOp.unary!\"" ~ op ~ "\"(n)";
100 
101         static assert(real.mant_dig >= precision!N);
102         auto control(Select!(op == "~", N, real) n, Unused m = null) {
103             return mixin(op ~ "n"); }
104         alias R = OpType!(op, N);
105 
106         static if((op != "-" || isSigned!N) && isIntegral!R)
107             fuzz!(sc, Unqual, OutIs!R, control, N)();
108         else
109             forbid!(sc, N)();
110     }
111 }
112 alias unary(N) = unary!(null, N);
113 
114 void binary(string op = null, N = void, M = void)() {
115     static if(op == null) {
116         foreach(op1; AliasSeq!("+", "-", "*", "/", "%", "<<", ">>", ">>>", "&", "|", "^"))
117             binary!(op1, N, M)();
118     } else
119     static if(is(N == void)) {
120         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
121             binary!(op, N1, M)();
122     } else
123     static if(is(M == void)) {
124         foreach(M1; AliasSeq!(IntegralTypes, CharTypes))
125             binary!(op, N, M1)();
126     } else {
127         static assert(isFixedPoint!N && isFixedPoint!M);
128 
129         static void cover(bool assign)() {
130             enum sc = "safeOp.binary!\"" ~ op ~ (assign? "=" : "") ~ "\"(n, m)";
131 
132             alias P = OpType!(N, op, M);
133             alias R = Select!(assign, N, P);
134 
135             static assert(real.mant_dig >= max(precision!N, precision!M));
136             enum bc = "n " ~ op ~ " m";
137             static if(op.among!("<<", ">>", ">>>")) {
138                 real control(const N n, const M m) {
139                     if(m < 0 || m >= (8 * Promoted!(N).sizeof))
140                         return real.nan;
141 
142                     const wret = mixin(bc);
143                     return assign? cast(N)wret : wret;
144                 }
145             } else
146             static if(op.among!("&", "|", "^")) {
147                 auto control(const N n, const M m) {
148                     const wret = mixin(bc);
149                     static if(assign)
150                         return cast(N)wret;
151                     else
152                         return wret;
153                 }
154             } else {
155                 real control(const real n , const real m) {
156                     const wret = mixin(bc);
157                     static if(op == "/")
158                         return stdm.trunc(wret);
159                     else
160                     static if(op == "%")
161                         return ((R.min < 0) && (n == R.min) && (m == -1))? real.nan : wret;
162                     else
163                         return wret;
164                 }
165             }
166 
167             enum matchedSigns = (!isSigned!N && !isSigned!M) ||
168                 (isSigned!P && (isSigned!R || (op == "%" && !isSigned!N)));
169             static if((matchedSigns || op.among!("<<", ">>", ">>>", "&", "|", "^")) && isIntegral!R)
170                 fuzz!(sc, Unqual, OutIs!R, control, N, M)();
171             else
172                 forbid!(sc, N, M)();
173         }
174         cover!false();
175         cover!true();
176     }
177 }
178 alias binary(N, M = void) = binary!(null, N, M);
179 
180 void byPow2(N = void, M = void)() {
181     static if(is(N == void)) {
182         foreach(N1; AliasSeq!(IntegralTypes, CharTypes))
183             byPow2!(N1, M)();
184     } else
185     static if(is(M == void)) {
186         foreach(M1; AliasSeq!(IntegralTypes, CharTypes))
187             byPow2!(N, M1)();
188     } else {
189         static assert(isScalarType!N && isScalarType!M);
190 
191         static void cover(bool mul)() {
192             enum sc = "safeOp." ~ (mul? "mul" : "div") ~ "Pow2(n, m)";
193 
194             static assert(real.mant_dig >= max(precision!N, precision!M));
195             real control(const real n, const real m) {
196                 if(n == 0 && stdm.isFinite(m))
197                     return 0;
198                 else {
199                     const p2 = stdm.exp2(m);
200                     const wret = mul? (n * p2) : (n / p2);
201                     static if(isFloatingPoint!N || isFloatingPoint!M)
202                         return wret;
203                     else
204                         return stdm.trunc(wret);
205                 }
206             }
207             enum isVO(N, M, PR) = (PR.sizeof >= N.sizeof) &&
208                 ((isFloatingPoint!N || isFloatingPoint!M)?
209                     isFloatingPoint!PR :
210                     isIntegral!PR && (isSigned!PR || !isSigned!N));
211 
212             fuzz!(sc, Unqual, isVO, control, N, M)();
213         }
214         cover!true();
215         cover!false();
216     }
217 }
218 
219 void pow(N = void, M = void)() {
220     static if(is(N == void)) {
221         foreach(N1; IntegralTypes)
222             pow!(N1, M)();
223     } else
224     static if(is(M == void)) {
225         foreach(M1; IntegralTypes)
226             pow!(N, M1)();
227     } else {
228         static assert(isFixedPoint!N && isFixedPoint!M);
229         forbid!("safeOp.binary!\"^^\"(n, m)", N, M)();
230         forbid!("safeOp.binary!\"^^=\"(n, m)", N, M)();
231 
232         enum sc = "safeOp.pow(n, m)";
233 
234         static assert(real.mant_dig >= max(precision!N, precision!M));
235         real control(const real n, const real m) {
236             return (m < 0)?
237                 real.nan :
238                 stdm.pow(n, m);
239         }
240         alias R = CallType!(stdm.pow, N, M);
241 
242         static if((!isSigned!N || isSigned!R) && isIntegral!R)
243             fuzz!(sc, Unqual, OutIs!R, control, N, M)();
244         else
245             forbid!(sc, N, M)();
246     }
247 }