1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.util.TypeUtils;
13 
14 import hunt.util.Common;
15 import hunt.text.StringBuilder;
16 import hunt.Exceptions;
17 
18 import std.conv;
19 import std.string;
20 import std.typecons;
21 
22 /**
23 */
24 alias Pair(F, S) = Tuple!(F, "first", S, "second");
25 Pair!(F, S) makePair(F, S)(F first, S second) {
26     return tuple!("first", "second")(first, second);
27 }
28 
29 unittest {
30     Pair!(string, int) p = makePair("age", 20);
31 
32     assert(p.first == "age");
33     assert(p.second == 20);
34 }
35 
36 /**
37 */
38 class TypeUtils {
39 
40     static string getSimpleName(TypeInfo info) {
41         string name = info.toString();
42         ptrdiff_t index = lastIndexOf(name, '.');
43         if(index == -1)
44             return name;
45         else
46             return name[index+1 .. $];
47     }
48 
49     /**
50      * Returns the number of zero bits preceding the highest-order
51      * ("leftmost") one-bit in the two's complement binary representation
52      * of the specified {@code int} value.  Returns 32 if the
53      * specified value has no one-bits in its two's complement representation,
54      * in other words if it is equal to zero.
55      *
56      * <p>Note that this method is closely related to the logarithm base 2.
57      * For all positive {@code int} values x:
58      * <ul>
59      * <li>floor(log<sub>2</sub>(x)) = {@code 31 - numberOfLeadingZeros(x)}
60      * <li>ceil(log<sub>2</sub>(x)) = {@code 32 - numberOfLeadingZeros(x - 1)}
61      * </ul>
62      *
63      * @param i the value whose number of leading zeros is to be computed
64      * @return the number of zero bits preceding the highest-order
65      *     ("leftmost") one-bit in the two's complement binary representation
66      *     of the specified {@code int} value, or 32 if the value
67      *     is equal to zero.
68      * @since 1.5
69      */
70     static int numberOfLeadingZeros(int i) {
71         // HD, Figure 5-6
72         if (i == 0)
73             return 32;
74         int n = 1;
75         if (i >>> 16 == 0) {
76             n += 16;
77             i <<= 16;
78         }
79         if (i >>> 24 == 0) {
80             n += 8;
81             i <<= 8;
82         }
83         if (i >>> 28 == 0) {
84             n += 4;
85             i <<= 4;
86         }
87         if (i >>> 30 == 0) {
88             n += 2;
89             i <<= 2;
90         }
91         n -= i >>> 31;
92         return n;
93     }
94 
95     /**
96      * @param c An ASCII encoded character 0-9 a-f A-F
97      * @return The byte value of the character 0-16.
98      */
99     static byte convertHexDigit(byte c) {
100         byte b = cast(byte)((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
101         if (b < 0 || b > 15)
102             throw new NumberFormatException("!hex " ~ to!string(c));
103         return b;
104     }
105 
106     /* ------------------------------------------------------------ */
107 
108     /**
109      * @param c An ASCII encoded character 0-9 a-f A-F
110      * @return The byte value of the character 0-16.
111      */
112     static int convertHexDigit(char c) {
113         int d = ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
114         if (d < 0 || d > 15)
115             throw new NumberFormatException("!hex " ~ to!string(c));
116         return d;
117     }
118 
119     /* ------------------------------------------------------------ */
120 
121     /**
122      * @param c An ASCII encoded character 0-9 a-f A-F
123      * @return The byte value of the character 0-16.
124      */
125     static int convertHexDigit(int c) {
126         int d = ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10);
127         if (d < 0 || d > 15)
128             throw new NumberFormatException("!hex " ~ to!string(c));
129         return d;
130     }
131 
132     /* ------------------------------------------------------------ */
133     static void toHex(byte b, Appendable buf) {
134         try {
135             int d = 0xf & ((0xF0 & b) >> 4);
136             buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
137             d = 0xf & b;
138             buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
139         }
140         catch (IOException e) {
141             throw new RuntimeException(e);
142         }
143     }
144 
145     /* ------------------------------------------------------------ */
146     static void toHex(int value, Appendable buf) {
147         int d = 0xf & ((0xF0000000 & value) >> 28);
148         buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
149         d = 0xf & ((0x0F000000 & value) >> 24);
150         buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
151         d = 0xf & ((0x00F00000 & value) >> 20);
152         buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
153         d = 0xf & ((0x000F0000 & value) >> 16);
154         buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
155         d = 0xf & ((0x0000F000 & value) >> 12);
156         buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
157         d = 0xf & ((0x00000F00 & value) >> 8);
158         buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
159         d = 0xf & ((0x000000F0 & value) >> 4);
160         buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
161         d = 0xf & value;
162         buf.append(cast(char)((d > 9 ? ('A' - 10) : '0') + d));
163 
164         // Integer.toString(0, 36);
165     }
166 
167     /* ------------------------------------------------------------ */
168     static void toHex(long value, Appendable buf) {
169         toHex(cast(int)(value >> 32), buf);
170         toHex(cast(int) value, buf);
171     }
172 
173     /* ------------------------------------------------------------ */
174     static string toHexString(byte b) {
175         return toHexString([b], 0, 1);
176     }
177 
178     /* ------------------------------------------------------------ */
179     static string toHexString(byte[] b) {
180         return toHexString(b, 0, cast(int) b.length);
181     }
182 
183     /* ------------------------------------------------------------ */
184     static string toHexString(byte[] b, int offset, int length) {
185         StringBuilder buf = new StringBuilder();
186         for (int i = offset; i < offset + length; i++) {
187             int bi = 0xff & b[i];
188             int c = '0' + (bi / 16) % 16;
189             if (c > '9')
190                 c = 'A' + (c - '0' - 10);
191             buf.append(cast(char) c);
192             c = '0' + bi % 16;
193             if (c > '9')
194                 c = 'a' + (c - '0' - 10);
195             buf.append(cast(char) c);
196         }
197         return buf.toString();
198     }
199 
200     /* ------------------------------------------------------------ */
201     static byte[] fromHexString(string s) {
202         if (s.length % 2 != 0)
203             throw new IllegalArgumentException(s);
204         byte[] array = new byte[s.length / 2];
205         for (int i = 0; i < array.length; i++) {
206             int b = to!int(s[i * 2 .. i * 2 + 2], 16);
207             array[i] = cast(byte)(0xff & b);
208         }
209         return array;
210     }
211 
212     static int parseInt(string s, int offset, int length, int base) {
213         return to!int(s[offset .. offset + length], base);
214     }
215 
216 }