xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/libdruntime/core/internal/string.d (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1 /**
2  * String manipulation and comparison utilities.
3  *
4  * Copyright: Copyright Sean Kelly 2005 - 2009.
5  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6  * Authors:   Sean Kelly, Walter Bright
7  * Source: $(DRUNTIMESRC rt/util/_string.d)
8  */
9 
10 module core.internal.string;
11 
12 pure:
13 nothrow:
14 @nogc:
15 
16 alias UnsignedStringBuf = char[20];
17 
18 /**
19 Converts an unsigned integer value to a string of characters.
20 
21 This implementation is a template so it can be used when compiling with -betterC.
22 
23 Params:
24     value = the unsigned integer value to convert
25     buf   = the pre-allocated buffer used to store the result
26     radix = the numeric base to use in the conversion (defaults to 10)
27 
28 Returns:
29     The unsigned integer value as a string of characters
30 */
31 char[] unsignedToTempString(uint radix = 10)(ulong value, return scope char[] buf) @safe
32 if (radix >= 2 && radix <= 16)
33 {
34     size_t i = buf.length;
35     do
36     {
37         uint x = void;
38         if (value < radix)
39         {
40             x = cast(uint)value;
41             value = 0;
42         }
43         else
44         {
45             x = cast(uint)(value % radix);
46             value /= radix;
47         }
48         buf[--i] = cast(char)((radix <= 10 || x < 10) ? x + '0' : x - 10 + 'a');
49     } while (value);
50     return buf[i .. $];
51 }
52 
TempStringNoAlloc(ubyte N)53 private struct TempStringNoAlloc(ubyte N)
54 {
55     private char[N] _buf = void;
56     private ubyte _len;
57     inout(char)[] get() inout return
58     {
59         return _buf[$-_len..$];
60     }
61     alias get this;
62 }
63 
64 /**
65 Converts an unsigned integer value to a string of characters.
66 
67 This implementation is a template so it can be used when compiling with -betterC.
68 
69 Params:
70     value = the unsigned integer value to convert
71     radix = the numeric base to use in the conversion (defaults to 10)
72 
73 Returns:
74     The unsigned integer value as a string of characters
75 */
76 auto unsignedToTempString(uint radix = 10)(ulong value) @safe
77 {
78     // Need a buffer of 65 bytes for radix of 2 with room for
79     // signedToTempString to possibly add a negative sign.
80     enum bufferSize = radix >= 10 ? 20 : 65;
81     TempStringNoAlloc!bufferSize result = void;
82     result._len = unsignedToTempString!radix(value, result._buf).length & 0xff;
83     return result;
84 }
85 
86 unittest
87 {
88     UnsignedStringBuf buf;
89     assert(0.unsignedToTempString(buf) == "0");
90     assert(1.unsignedToTempString(buf) == "1");
91     assert(12.unsignedToTempString(buf) == "12");
92     assert(0x12ABCF .unsignedToTempString!16(buf) == "12abcf");
93     assert(long.sizeof.unsignedToTempString(buf) == "8");
94     assert(uint.max.unsignedToTempString(buf) == "4294967295");
95     assert(ulong.max.unsignedToTempString(buf) == "18446744073709551615");
96 
97     // use stack allocated struct version
98     assert(0.unsignedToTempString == "0");
99     assert(1.unsignedToTempString == "1");
100     assert(12.unsignedToTempString == "12");
101     assert(0x12ABCF .unsignedToTempString!16 == "12abcf");
102     assert(long.sizeof.unsignedToTempString == "8");
103     assert(uint.max.unsignedToTempString == "4294967295");
104     assert(ulong.max.unsignedToTempString == "18446744073709551615");
105 
106     // test bad radices
107     assert(!is(typeof(100.unsignedToTempString!1(buf))));
108     assert(!is(typeof(100.unsignedToTempString!0(buf) == "")));
109 }
110 
111 alias SignedStringBuf = char[20];
112 
113 char[] signedToTempString(uint radix = 10)(long value, return scope char[] buf) @safe
114 {
115     bool neg = value < 0;
116     if (neg)
117         value = cast(ulong)-value;
118     auto r = unsignedToTempString!radix(value, buf);
119     if (neg)
120     {
121         // about to do a slice without a bounds check
trustedSlice(return scope char[]r)122         auto trustedSlice(return scope char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; }
123         r = trustedSlice(r);
124         r[0] = '-';
125     }
126     return r;
127 }
128 
129 auto signedToTempString(uint radix = 10)(long value) @safe
130 {
131     bool neg = value < 0;
132     if (neg)
133         value = cast(ulong)-value;
134     auto r = unsignedToTempString!radix(value);
135     if (neg)
136     {
137         r._len++;
138         r.get()[0] = '-';
139     }
140     return r;
141 }
142 
143 unittest
144 {
145     SignedStringBuf buf;
146     assert(0.signedToTempString(buf) == "0");
147     assert(1.signedToTempString(buf) == "1");
148     assert((-1).signedToTempString(buf) == "-1");
149     assert(12.signedToTempString(buf) == "12");
150     assert((-12).signedToTempString(buf) == "-12");
151     assert(0x12ABCF .signedToTempString!16(buf) == "12abcf");
152     assert((-0x12ABCF) .signedToTempString!16(buf) == "-12abcf");
153     assert(long.sizeof.signedToTempString(buf) == "8");
154     assert(int.max.signedToTempString(buf) == "2147483647");
155     assert(int.min.signedToTempString(buf) == "-2147483648");
156     assert(long.max.signedToTempString(buf) == "9223372036854775807");
157     assert(long.min.signedToTempString(buf) == "-9223372036854775808");
158 
159     // use stack allocated struct version
160     assert(0.signedToTempString() == "0");
161     assert(1.signedToTempString == "1");
162     assert((-1).signedToTempString == "-1");
163     assert(12.signedToTempString == "12");
164     assert((-12).signedToTempString == "-12");
165     assert(0x12ABCF .signedToTempString!16 == "12abcf");
166     assert((-0x12ABCF) .signedToTempString!16 == "-12abcf");
167     assert(long.sizeof.signedToTempString == "8");
168     assert(int.max.signedToTempString == "2147483647");
169     assert(int.min.signedToTempString == "-2147483648");
170     assert(long.max.signedToTempString == "9223372036854775807");
171     assert(long.min.signedToTempString == "-9223372036854775808");
172     assert(long.max.signedToTempString!2 == "111111111111111111111111111111111111111111111111111111111111111");
173     assert(long.min.signedToTempString!2 == "-1000000000000000000000000000000000000000000000000000000000000000");
174 }
175 
176 
177 /********************************
178  * Determine number of digits that will result from a
179  * conversion of value to a string.
180  * Params:
181  *      value = number to convert
182  *      radix = radix
183  * Returns:
184  *      number of digits
185  */
186 int numDigits(uint radix = 10)(ulong value) @safe if (radix >= 2 && radix <= 36)
187 {
188      int n = 1;
189      while (1)
190      {
191         if (value <= uint.max)
192         {
193             uint v = cast(uint)value;
194             while (1)
195             {
196                 if (v < radix)
197                     return n;
198                 if (v < radix * radix)
199                     return n + 1;
200                 if (v < radix * radix * radix)
201                     return n + 2;
202                 if (v < radix * radix * radix * radix)
203                     return n + 3;
204                 n += 4;
205                 v /= radix * radix * radix * radix;
206             }
207         }
208         n += 4;
209         value /= radix * radix * radix * radix;
210      }
211 }
212 
213 unittest
214 {
215     assert(0.numDigits == 1);
216     assert(9.numDigits == 1);
217     assert(10.numDigits == 2);
218     assert(99.numDigits == 2);
219     assert(100.numDigits == 3);
220     assert(999.numDigits == 3);
221     assert(1000.numDigits == 4);
222     assert(9999.numDigits == 4);
223     assert(10000.numDigits == 5);
224     assert(99999.numDigits == 5);
225     assert(uint.max.numDigits == 10);
226     assert(ulong.max.numDigits == 20);
227 
228     assert(0.numDigits!2 == 1);
229     assert(1.numDigits!2 == 1);
230     assert(2.numDigits!2 == 2);
231     assert(3.numDigits!2 == 2);
232 
233     // test bad radices
234     static assert(!__traits(compiles, 100.numDigits!1()));
235     static assert(!__traits(compiles, 100.numDigits!0()));
236     static assert(!__traits(compiles, 100.numDigits!37()));
237 }
238 
dstrcmp()239 int dstrcmp()( scope const char[] s1, scope const char[] s2 ) @trusted
240 {
241     immutable len = s1.length <= s2.length ? s1.length : s2.length;
242     if (__ctfe)
243     {
244         foreach (const u; 0 .. len)
245         {
246             if (s1[u] != s2[u])
247                 return s1[u] > s2[u] ? 1 : -1;
248         }
249     }
250     else
251     {
252         import core.stdc.string : memcmp;
253 
254         const ret = memcmp( s1.ptr, s2.ptr, len );
255         if ( ret )
256             return ret;
257     }
258     return (s1.length > s2.length) - (s1.length < s2.length);
259 }
260