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 import std.meta : AliasSeq;
19 
20 // checkedint.flags //////////////////////////////////////
21 static import checkedint.flags;
22 
23     /// See $(LINK2 ./flags.html#intFlagPolicyOf, `checkedint.flags.intFlagPolicyOf`)
24     alias intFlagPolicyOf = checkedint.flags.intFlagPolicyOf;
25 
26 
27 // checkedint ////////////////////////////////////////////
28 static import chkd = checkedint;
29 
30     /// See $(LINK2 ./package.html#isSafeInt, `checkedint.isSafeInt`)
31     alias isSafeInt = chkd.isSafeInt;
32 
33     /// See $(LINK2 ./package.html#isSmartInt, `checkedint.isSmartInt`)
34     alias isSmartInt = chkd.isSmartInt;
35 
36     /// See $(LINK2 ./package.html#isCheckedInt, `checkedint.isCheckedInt`)
37     alias isCheckedInt = chkd.isCheckedInt;
38 
39     /// See $(LINK2 ./package.html#hasBitOps, `checkedint.hasBitOps`)
40     alias hasBitOps = chkd.hasBitOps;
41 
42     /// See $(LINK2 ./package.html#BasicScalar, `checkedint.BasicScalar`)
43     alias BasicScalar = chkd.BasicScalar;
44 
45 
46 // std.traits ////////////////////////////////////////////
47 static import bsct = future.traits0;
48 
49     private template isEx(alias Predicate, T)
50     {
51         static if (isCheckedInt!T)
52             enum isEx = Predicate!(BasicScalar!T);
53         else
54             enum isEx = Predicate!T;
55     }
56 
57     /// See `std.traits.isScalarType`
58     alias isBasicScalar = bsct.isScalarType;
59     /// `checkedint`-aware wrapper for `std.traits.isScalarType`
60     template isScalarType(T)
61     {
62         alias isScalarType = isEx!(isBasicScalar, T);
63     }
64     ///
65     unittest
66     {
67         foreach (T; AliasSeq!(int, ushort, double, bool))
68             assert(isBasicScalar!T && isScalarType!T);
69 
70         assert(!isBasicScalar!(SmartInt!int));
71         assert( isScalarType!(SmartInt!int));
72 
73         foreach (T; AliasSeq!(int[]))
74             assert(!(isBasicScalar!T || isScalarType!T));
75     }
76 
77     /// See `std.traits.isNumeric`
78     alias isBasicNum = bsct.isNumeric;
79     /// `checkedint`-aware wrapper for `std.traits.isNumeric`
80     template isNumeric(T)
81     {
82         alias isNumeric = isEx!(isBasicNum, T);
83     }
84     ///
85     unittest
86     {
87         foreach (T; AliasSeq!(int, ushort, double))
88             assert(isBasicNum!T && isNumeric!T);
89 
90         assert(!isBasicNum!(SmartInt!int));
91         assert( isNumeric!(SmartInt!int));
92 
93         foreach (T; AliasSeq!(int[], bool))
94             assert(!(isBasicNum!T || isNumeric!T));
95     }
96 
97     /// See `std.traits.isFloatingPoint`
98     alias isFloatingPoint = bsct.isFloatingPoint;
99 
100     /// See `future.traits.isFixedPoint`
101     alias isBasicFixed = bsct.isFixedPoint;
102     /// `checkedint`-aware wrapper for `future.traits.isFixedPoint`
103     template isFixedPoint(T)
104     {
105         alias isFixedPoint = isEx!(isBasicFixed, T);
106     }
107     ///
108     unittest
109     {
110         foreach (T; AliasSeq!(int, ushort, bool))
111             assert(isBasicFixed!T && isFixedPoint!T);
112 
113         assert(!isBasicFixed!(SmartInt!int));
114         assert( isFixedPoint!(SmartInt!int));
115 
116         foreach (T; AliasSeq!(double, int[]))
117             assert(!(isBasicFixed!T || isFixedPoint!T));
118     }
119 
120     /// See `std.traits.isIntegral`
121     alias isBasicInt = bsct.isIntegral;
122     /// `checkedint`-aware wrapper for `std.traits.isIntegral`
123     template isIntegral(T)
124     {
125         alias isIntegral = isEx!(isBasicInt, T);
126     }
127     ///
128     unittest
129     {
130         foreach (T; AliasSeq!(int, ushort))
131             assert(isBasicInt!T && isIntegral!T);
132 
133         assert(!isBasicInt!(SmartInt!int));
134         assert( isIntegral!(SmartInt!int));
135 
136         foreach (T; AliasSeq!(double, int[], bool))
137             assert(!(isBasicInt!T || isIntegral!T));
138     }
139 
140     /// See `std.traits.isSomeChar`
141     alias isSomeChar = bsct.isSomeChar;
142     /// See `std.traits.isBoolean`
143     alias isBoolean = bsct.isBoolean;
144 
145     /// See `std.traits.isSigned`
146     alias isBasicSigned = bsct.isSigned;
147     /// `checkedint`-aware wrapper for `std.traits.isSigned`
148     template isSigned(T)
149     {
150         alias isSigned = isEx!(isBasicSigned, T);
151     }
152     ///
153     unittest
154     {
155         foreach (T; AliasSeq!(int, double))
156             assert(isBasicSigned!T && isSigned!T);
157 
158         assert(!isBasicSigned!(SmartInt!int));
159         assert( isSigned!(SmartInt!int));
160 
161         foreach (T; AliasSeq!(ushort, int[], bool))
162             assert(!(isBasicSigned!T || isSigned!T));
163     }
164 
165     /// See `std.traits.isUnsigned`
166     alias isBasicUnsigned = bsct.isUnsigned;
167     /// `checkedint`-aware wrapper for `isUnsigned`
168     template isUnsigned(T)
169     {
170         alias isUnsigned = isEx!(isBasicUnsigned, T);
171     }
172     ///
173     unittest
174     {
175         foreach (T; AliasSeq!(ushort))
176             assert(isBasicUnsigned!T && isUnsigned!T);
177 
178         assert(!isBasicUnsigned!(SmartInt!uint));
179         assert( isUnsigned!(SmartInt!uint));
180 
181         foreach (T; AliasSeq!(double, int[], bool))
182             assert(!(isBasicUnsigned!T || isUnsigned!T));
183     }
184 
185     /// `checkedint`-aware version of `std.traits.mostNegative`
186     template mostNegative(T)
187         if (isNumeric!T)
188     {
189         static if (isFloatingPoint!T)
190             enum mostNegative = -T.max;
191         else
192             enum mostNegative =  T.min;
193     }
194     ///
195     unittest
196     {
197         assert(mostNegative!int == int.min);
198         static assert(is(typeof(mostNegative!int) == int));
199         assert(mostNegative!(SmartInt!int) == SmartInt!(int).min);
200         static assert(is(typeof(mostNegative!(SmartInt!int)) == SmartInt!int));
201     }
202 
203     private template TransEx(alias TypeTransform, T)
204     {
205         static if (isCheckedInt!T)
206         {
207             import checkedint : SmartInt, SafeInt;
208             import future.traits0 : CopyTypeQualifiers, Select;
209 
210             alias TTB = TypeTransform!(CopyTypeQualifiers!(T, BasicScalar!T));
211             alias CheckedInt = Select!(isSmartInt!T, SmartInt, SafeInt);
212             alias TransEx = CopyTypeQualifiers!(TTB, CheckedInt!(TTB, intFlagPolicyOf!T, hasBitOps!T));
213         } else
214             alias TransEx = TypeTransform!T;
215     }
216 
217     /// `checkedint`-aware wrapper for `std.traits.Signed`
218     template Signed(T)
219     {
220         alias Signed = TransEx!(bsct.Signed, T);
221     }
222     ///
223     unittest
224     {
225         static assert(is(Signed!int == int));
226         static assert(is(Signed!(SmartInt!int) == SmartInt!int));
227         static assert(is(Signed!ulong == long));
228         static assert(is(Signed!(SmartInt!ulong) == SmartInt!long));
229     }
230 
231     /// `checkedint`-aware wrapper for `std.traits.Unsigned`
232     template Unsigned(T)
233     {
234         alias Unsigned = TransEx!(bsct.Unsigned, T);
235     }
236     ///
237     unittest
238     {
239         static assert(is(Unsigned!int == uint));
240         static assert(is(Unsigned!(SmartInt!int) == SmartInt!uint));
241         static assert(is(Unsigned!ulong == ulong));
242         static assert(is(Unsigned!(SmartInt!ulong) == SmartInt!ulong));
243     }
244 
245     /// `checkedint`-aware wrapper for `future.traits.Promoted`
246     template Promoted(T)
247     {
248         alias Promoted = TransEx!(bsct.Promoted, T);
249     }
250     ///
251     unittest
252     {
253         static assert(is(Promoted!byte == int));
254         static assert(is(Promoted!(SmartInt!byte) == SmartInt!int));
255         static assert(is(Promoted!int == int));
256         static assert(is(Promoted!(SmartInt!int) == SmartInt!int));
257     }