1 /**
2 Templates to facilitate treating $(LINK2 ./package.html#SmartInt, `checkedint.SmartInt`) and $(LINK2 ./package.html#SafeInt, `checkedint.SafeInt`) like the built-in numeric types in
3 generic code.
4 
5 Copyright: Copyright Thomas Stuart Bockman 2015
6 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
7 Authors: Thomas Stuart Bockman
8 
9 This module wraps various templates from `std.traits` to make them `checkedint`-aware. For example,
10 `std.traits.isSigned!(SmartInt!int)` is `false`, but `checkedint.traits.isSigned!(SmartInt!int)` is `true`.
11 
12 This module is separate from `checkedint` because it is only useful in generic code, and its symbols (deliberately)
13 conflict with some from `std.traits`.
14 **/
15 module checkedint.traits;
16 import checkedint.asserts : SmartInt;
17 
18 static if (__VERSION__ >= 2068)
19 {
20     version(GNU) { static assert(false); }
21     import std.meta : AliasSeq;
22 }
23 else
24     import std.typetuple : AliasSeq = TypeTuple;
25 
26 // checkedint.flags //////////////////////////////////////
27 static import checkedint.flags;
28 
29     /// See $(LINK2 ./flags.html#intFlagPolicyOf, `checkedint.flags.intFlagPolicyOf`)
30     alias intFlagPolicyOf = checkedint.flags.intFlagPolicyOf;
31 
32 
33 // checkedint ////////////////////////////////////////////
34 static import chkd = checkedint;
35 
36     /// See $(LINK2 ./package.html#isSafeInt, `checkedint.isSafeInt`)
37     alias isSafeInt = chkd.isSafeInt;
38 
39     /// See $(LINK2 ./package.html#isSmartInt, `checkedint.isSmartInt`)
40     alias isSmartInt = chkd.isSmartInt;
41 
42     /// See $(LINK2 ./package.html#isCheckedInt, `checkedint.isCheckedInt`)
43     alias isCheckedInt = chkd.isCheckedInt;
44 
45     /// See $(LINK2 ./package.html#hasBitOps, `checkedint.hasBitOps`)
46     alias hasBitOps = chkd.hasBitOps;
47 
48     /// See $(LINK2 ./package.html#BasicScalar, `checkedint.BasicScalar`)
49     alias BasicScalar = chkd.BasicScalar;
50 
51 
52 // std.traits ////////////////////////////////////////////
53 static import bsct = future.traits0;
54 
55     private template isEx(alias Predicate, T)
56     {
57         static if (isCheckedInt!T)
58             enum isEx = Predicate!(BasicScalar!T);
59         else
60             enum isEx = Predicate!T;
61     }
62 
63     /// See `std.traits.isScalarType`
64     alias isBasicScalar = bsct.isScalarType;
65     /// `checkedint`-aware wrapper for `std.traits.isScalarType`
66     template isScalarType(T)
67     {
68         alias isScalarType = isEx!(isBasicScalar, T);
69     }
70     ///
71     unittest
72     {
73         foreach(T; AliasSeq!(int, ushort, double, bool))
74             assert(isBasicScalar!T && isScalarType!T);
75 
76         assert(!isBasicScalar!(SmartInt!int));
77         assert( isScalarType!(SmartInt!int));
78 
79         foreach(T; AliasSeq!(int[]))
80             assert(!(isBasicScalar!T || isScalarType!T));
81     }
82 
83     /// See `std.traits.isNumeric`
84     alias isBasicNum = bsct.isNumeric;
85     /// `checkedint`-aware wrapper for `std.traits.isNumeric`
86     template isNumeric(T)
87     {
88         alias isNumeric = isEx!(isBasicNum, T);
89     }
90     ///
91     unittest
92     {
93         foreach(T; AliasSeq!(int, ushort, double))
94             assert(isBasicNum!T && isNumeric!T);
95 
96         assert(!isBasicNum!(SmartInt!int));
97         assert( isNumeric!(SmartInt!int));
98 
99         foreach(T; AliasSeq!(int[], bool))
100             assert(!(isBasicNum!T || isNumeric!T));
101     }
102 
103     /// See `std.traits.isFloatingPoint`
104     alias isFloatingPoint = bsct.isFloatingPoint;
105 
106     /// See `future.traits.isFixedPoint`
107     alias isBasicFixed = bsct.isFixedPoint;
108     /// `checkedint`-aware wrapper for `future.traits.isFixedPoint`
109     template isFixedPoint(T)
110     {
111         alias isFixedPoint = isEx!(isBasicFixed, T);
112     }
113     ///
114     unittest
115     {
116         foreach(T; AliasSeq!(int, ushort, bool))
117             assert(isBasicFixed!T && isFixedPoint!T);
118 
119         assert(!isBasicFixed!(SmartInt!int));
120         assert( isFixedPoint!(SmartInt!int));
121 
122         foreach(T; AliasSeq!(double, int[]))
123             assert(!(isBasicFixed!T || isFixedPoint!T));
124     }
125 
126     /// See `std.traits.isIntegral`
127     alias isBasicInt = bsct.isIntegral;
128     /// `checkedint`-aware wrapper for `std.traits.isIntegral`
129     template isIntegral(T)
130     {
131         alias isIntegral = isEx!(isBasicInt, T);
132     }
133     ///
134     unittest
135     {
136         foreach(T; AliasSeq!(int, ushort))
137             assert(isBasicInt!T && isIntegral!T);
138 
139         assert(!isBasicInt!(SmartInt!int));
140         assert( isIntegral!(SmartInt!int));
141 
142         foreach(T; AliasSeq!(double, int[], bool))
143             assert(!(isBasicInt!T || isIntegral!T));
144     }
145 
146     /// See `std.traits.isSomeChar`
147     alias isSomeChar = bsct.isSomeChar;
148     /// See `std.traits.isBoolean`
149     alias isBoolean = bsct.isBoolean;
150 
151     /// See `std.traits.isSigned`
152     alias isBasicSigned = bsct.isSigned;
153     /// `checkedint`-aware wrapper for `std.traits.isSigned`
154     template isSigned(T)
155     {
156         alias isSigned = isEx!(isBasicSigned, T);
157     }
158     ///
159     unittest
160     {
161         foreach(T; AliasSeq!(int, double))
162             assert(isBasicSigned!T && isSigned!T);
163 
164         assert(!isBasicSigned!(SmartInt!int));
165         assert( isSigned!(SmartInt!int));
166 
167         foreach(T; AliasSeq!(ushort, int[], bool))
168             assert(!(isBasicSigned!T || isSigned!T));
169     }
170 
171     /// See `std.traits.isUnsigned`
172     alias isBasicUnsigned = bsct.isUnsigned;
173     /// `checkedint`-aware wrapper for `isUnsigned`
174     template isUnsigned(T)
175     {
176         alias isUnsigned = isEx!(isBasicUnsigned, T);
177     }
178     ///
179     unittest
180     {
181         foreach(T; AliasSeq!(ushort))
182             assert(isBasicUnsigned!T && isUnsigned!T);
183 
184         assert(!isBasicUnsigned!(SmartInt!uint));
185         assert( isUnsigned!(SmartInt!uint));
186 
187         foreach(T; AliasSeq!(double, int[], bool))
188             assert(!(isBasicUnsigned!T || isUnsigned!T));
189     }
190 
191     /// `checkedint`-aware version of `std.traits.mostNegative`
192     template mostNegative(T)
193         if (isNumeric!T)
194     {
195         static if (isFloatingPoint!T)
196             enum mostNegative = -T.max;
197         else
198             enum mostNegative =  T.min;
199     }
200     ///
201     unittest
202     {
203         assert(mostNegative!int == int.min);
204         static assert(is(typeof(mostNegative!int) == int));
205         assert(mostNegative!(SmartInt!int) == SmartInt!(int).min);
206         static assert(is(typeof(mostNegative!(SmartInt!int)) == SmartInt!int));
207     }
208 
209     private template TransEx(alias TypeTransform, T)
210     {
211         static if (isCheckedInt!T)
212         {
213             import checkedint : SmartInt, SafeInt;
214             import future.traits0 : CopyTypeQualifiers, Select;
215 
216             alias TTB = TypeTransform!(CopyTypeQualifiers!(T, BasicScalar!T));
217             alias CheckedInt = Select!(isSmartInt!T, SmartInt, SafeInt);
218             alias TransEx = CopyTypeQualifiers!(TTB, CheckedInt!(TTB, intFlagPolicyOf!T, hasBitOps!T));
219         } else
220             alias TransEx = TypeTransform!T;
221     }
222 
223     /// `checkedint`-aware wrapper for `std.traits.Signed`
224     template Signed(T)
225     {
226         alias Signed = TransEx!(bsct.Signed, T);
227     }
228     ///
229     unittest
230     {
231         static assert(is(Signed!int == int));
232         static assert(is(Signed!(SmartInt!int) == SmartInt!int));
233         static assert(is(Signed!ulong == long));
234         static assert(is(Signed!(SmartInt!ulong) == SmartInt!long));
235     }
236 
237     /// `checkedint`-aware wrapper for `std.traits.Unsigned`
238     template Unsigned(T)
239     {
240         alias Unsigned = TransEx!(bsct.Unsigned, T);
241     }
242     ///
243     unittest
244     {
245         static assert(is(Unsigned!int == uint));
246         static assert(is(Unsigned!(SmartInt!int) == SmartInt!uint));
247         static assert(is(Unsigned!ulong == ulong));
248         static assert(is(Unsigned!(SmartInt!ulong) == SmartInt!ulong));
249     }
250 
251     /// `checkedint`-aware wrapper for `future.traits.Promoted`
252     template Promoted(T)
253     {
254         alias Promoted = TransEx!(bsct.Promoted, T);
255     }
256     ///
257     unittest
258     {
259         static assert(is(Promoted!byte == int));
260         static assert(is(Promoted!(SmartInt!byte) == SmartInt!int));
261         static assert(is(Promoted!int == int));
262         static assert(is(Promoted!(SmartInt!int) == SmartInt!int));
263     }