1*627f7eb2Smrg /**
2*627f7eb2Smrg * Contains support code for switch blocks using string constants.
3*627f7eb2Smrg *
4*627f7eb2Smrg * Copyright: Copyright Digital Mars 2004 - 2010.
5*627f7eb2Smrg * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6*627f7eb2Smrg * Authors: Walter Bright, Sean Kelly
7*627f7eb2Smrg */
8*627f7eb2Smrg
9*627f7eb2Smrg /* Copyright Digital Mars 2004 - 2010.
10*627f7eb2Smrg * Distributed under the Boost Software License, Version 1.0.
11*627f7eb2Smrg * (See accompanying file LICENSE or copy at
12*627f7eb2Smrg * http://www.boost.org/LICENSE_1_0.txt)
13*627f7eb2Smrg */
14*627f7eb2Smrg module rt.switch_;
15*627f7eb2Smrg
16*627f7eb2Smrg private import core.stdc.string;
17*627f7eb2Smrg
18*627f7eb2Smrg /******************************************************
19*627f7eb2Smrg * Support for switch statements switching on strings.
20*627f7eb2Smrg * Input:
21*627f7eb2Smrg * table[] sorted array of strings generated by compiler
22*627f7eb2Smrg * ca string to look up in table
23*627f7eb2Smrg * Output:
24*627f7eb2Smrg * result index of match in table[]
25*627f7eb2Smrg * -1 if not in table
26*627f7eb2Smrg */
27*627f7eb2Smrg
28*627f7eb2Smrg extern (C):
29*627f7eb2Smrg
_d_switch_string(char[][]table,char[]ca)30*627f7eb2Smrg int _d_switch_string(char[][] table, char[] ca)
31*627f7eb2Smrg in
32*627f7eb2Smrg {
33*627f7eb2Smrg //printf("in _d_switch_string()\n");
34*627f7eb2Smrg assert(table.length >= 0);
35*627f7eb2Smrg assert(ca.length >= 0);
36*627f7eb2Smrg
37*627f7eb2Smrg // Make sure table[] is sorted correctly
38*627f7eb2Smrg for (size_t j = 1u; j < table.length; j++)
39*627f7eb2Smrg {
40*627f7eb2Smrg auto len1 = table[j - 1].length;
41*627f7eb2Smrg auto len2 = table[j].length;
42*627f7eb2Smrg
43*627f7eb2Smrg assert(len1 <= len2);
44*627f7eb2Smrg if (len1 == len2)
45*627f7eb2Smrg {
46*627f7eb2Smrg int ci;
47*627f7eb2Smrg
48*627f7eb2Smrg ci = memcmp(table[j - 1].ptr, table[j].ptr, len1);
49*627f7eb2Smrg assert(ci < 0); // ci==0 means a duplicate
50*627f7eb2Smrg }
51*627f7eb2Smrg }
52*627f7eb2Smrg }
out(result)53*627f7eb2Smrg out (result)
54*627f7eb2Smrg {
55*627f7eb2Smrg int cj;
56*627f7eb2Smrg
57*627f7eb2Smrg //printf("out _d_switch_string()\n");
58*627f7eb2Smrg if (result == -1)
59*627f7eb2Smrg {
60*627f7eb2Smrg // Not found
61*627f7eb2Smrg for (auto i = 0u; i < table.length; i++)
62*627f7eb2Smrg {
63*627f7eb2Smrg if (table[i].length == ca.length)
64*627f7eb2Smrg { cj = memcmp(table[i].ptr, ca.ptr, ca.length);
65*627f7eb2Smrg assert(cj != 0);
66*627f7eb2Smrg }
67*627f7eb2Smrg }
68*627f7eb2Smrg }
69*627f7eb2Smrg else
70*627f7eb2Smrg {
71*627f7eb2Smrg assert(0 <= result && cast(size_t)result < table.length);
72*627f7eb2Smrg for (auto i = 0u; 1; i++)
73*627f7eb2Smrg {
74*627f7eb2Smrg assert(i < table.length);
75*627f7eb2Smrg if (table[i].length == ca.length)
76*627f7eb2Smrg {
77*627f7eb2Smrg cj = memcmp(table[i].ptr, ca.ptr, ca.length);
78*627f7eb2Smrg if (cj == 0)
79*627f7eb2Smrg {
80*627f7eb2Smrg assert(i == result);
81*627f7eb2Smrg break;
82*627f7eb2Smrg }
83*627f7eb2Smrg }
84*627f7eb2Smrg }
85*627f7eb2Smrg }
86*627f7eb2Smrg }
87*627f7eb2Smrg body
88*627f7eb2Smrg {
89*627f7eb2Smrg //printf("body _d_switch_string(%.*s)\n", ca.length, ca.ptr);
90*627f7eb2Smrg size_t low = 0;
91*627f7eb2Smrg size_t high = table.length;
92*627f7eb2Smrg
version(none)93*627f7eb2Smrg version (none)
94*627f7eb2Smrg {
95*627f7eb2Smrg // Print table
96*627f7eb2Smrg printf("ca[] = '%s'\n", ca.length, ca.ptr);
97*627f7eb2Smrg for (auto i = 0; i < high; i++)
98*627f7eb2Smrg {
99*627f7eb2Smrg auto pca = table[i];
100*627f7eb2Smrg printf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr);
101*627f7eb2Smrg }
102*627f7eb2Smrg }
103*627f7eb2Smrg if (high &&
104*627f7eb2Smrg ca.length >= table[0].length &&
105*627f7eb2Smrg ca.length <= table[high - 1].length)
106*627f7eb2Smrg {
107*627f7eb2Smrg // Looking for 0 length string, which would only be at the beginning
108*627f7eb2Smrg if (ca.length == 0)
109*627f7eb2Smrg return 0;
110*627f7eb2Smrg
111*627f7eb2Smrg char c1 = ca[0];
112*627f7eb2Smrg
113*627f7eb2Smrg // Do binary search
114*627f7eb2Smrg while (low < high)
115*627f7eb2Smrg {
116*627f7eb2Smrg auto mid = (low + high) >> 1;
117*627f7eb2Smrg auto pca = table[mid];
118*627f7eb2Smrg auto c = cast(sizediff_t)(ca.length - pca.length);
119*627f7eb2Smrg if (c == 0)
120*627f7eb2Smrg {
121*627f7eb2Smrg c = cast(ubyte)c1 - cast(ubyte)pca[0];
122*627f7eb2Smrg if (c == 0)
123*627f7eb2Smrg {
124*627f7eb2Smrg c = memcmp(ca.ptr, pca.ptr, ca.length);
125*627f7eb2Smrg if (c == 0)
126*627f7eb2Smrg { //printf("found %d\n", mid);
127*627f7eb2Smrg return cast(int)mid;
128*627f7eb2Smrg }
129*627f7eb2Smrg }
130*627f7eb2Smrg }
131*627f7eb2Smrg if (c < 0)
132*627f7eb2Smrg {
133*627f7eb2Smrg high = mid;
134*627f7eb2Smrg }
135*627f7eb2Smrg else
136*627f7eb2Smrg {
137*627f7eb2Smrg low = mid + 1;
138*627f7eb2Smrg }
139*627f7eb2Smrg }
140*627f7eb2Smrg }
141*627f7eb2Smrg
142*627f7eb2Smrg //printf("not found\n");
143*627f7eb2Smrg return -1; // not found
144*627f7eb2Smrg }
145*627f7eb2Smrg
146*627f7eb2Smrg unittest
147*627f7eb2Smrg {
148*627f7eb2Smrg switch (cast(char []) "c")
149*627f7eb2Smrg {
150*627f7eb2Smrg case "coo":
151*627f7eb2Smrg default:
152*627f7eb2Smrg break;
153*627f7eb2Smrg }
154*627f7eb2Smrg
bug5381(string s)155*627f7eb2Smrg int bug5381(string s)
156*627f7eb2Smrg {
157*627f7eb2Smrg switch (s)
158*627f7eb2Smrg {
159*627f7eb2Smrg case "unittest": return 1;
160*627f7eb2Smrg case "D_Version2": return 2;
161*627f7eb2Smrg case "none": return 3;
162*627f7eb2Smrg case "all": return 4;
163*627f7eb2Smrg default: return 5;
164*627f7eb2Smrg }
165*627f7eb2Smrg }
166*627f7eb2Smrg int rc = bug5381("none");
167*627f7eb2Smrg assert(rc == 3);
168*627f7eb2Smrg }
169*627f7eb2Smrg
170*627f7eb2Smrg /**********************************
171*627f7eb2Smrg * Same thing, but for wide chars.
172*627f7eb2Smrg */
173*627f7eb2Smrg
_d_switch_ustring(wchar[][]table,wchar[]ca)174*627f7eb2Smrg int _d_switch_ustring(wchar[][] table, wchar[] ca)
175*627f7eb2Smrg in
176*627f7eb2Smrg {
177*627f7eb2Smrg //printf("in _d_switch_ustring()\n");
178*627f7eb2Smrg assert(table.length >= 0);
179*627f7eb2Smrg assert(ca.length >= 0);
180*627f7eb2Smrg
181*627f7eb2Smrg // Make sure table[] is sorted correctly
182*627f7eb2Smrg for (size_t j = 1u; j < table.length; j++)
183*627f7eb2Smrg {
184*627f7eb2Smrg auto len1 = table[j - 1].length;
185*627f7eb2Smrg auto len2 = table[j].length;
186*627f7eb2Smrg
187*627f7eb2Smrg assert(len1 <= len2);
188*627f7eb2Smrg if (len1 == len2)
189*627f7eb2Smrg {
190*627f7eb2Smrg int c;
191*627f7eb2Smrg
192*627f7eb2Smrg c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof);
193*627f7eb2Smrg assert(c < 0); // c==0 means a duplicate
194*627f7eb2Smrg }
195*627f7eb2Smrg }
196*627f7eb2Smrg }
out(result)197*627f7eb2Smrg out (result)
198*627f7eb2Smrg {
199*627f7eb2Smrg int c;
200*627f7eb2Smrg
201*627f7eb2Smrg //printf("out _d_switch_ustring()\n");
202*627f7eb2Smrg if (result == -1)
203*627f7eb2Smrg {
204*627f7eb2Smrg // Not found
205*627f7eb2Smrg for (auto i = 0u; i < table.length; i++)
206*627f7eb2Smrg {
207*627f7eb2Smrg if (table[i].length == ca.length)
208*627f7eb2Smrg { c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
209*627f7eb2Smrg assert(c != 0);
210*627f7eb2Smrg }
211*627f7eb2Smrg }
212*627f7eb2Smrg }
213*627f7eb2Smrg else
214*627f7eb2Smrg {
215*627f7eb2Smrg assert(0 <= result && cast(size_t)result < table.length);
216*627f7eb2Smrg for (auto i = 0u; 1; i++)
217*627f7eb2Smrg {
218*627f7eb2Smrg assert(i < table.length);
219*627f7eb2Smrg if (table[i].length == ca.length)
220*627f7eb2Smrg {
221*627f7eb2Smrg c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
222*627f7eb2Smrg if (c == 0)
223*627f7eb2Smrg {
224*627f7eb2Smrg assert(i == result);
225*627f7eb2Smrg break;
226*627f7eb2Smrg }
227*627f7eb2Smrg }
228*627f7eb2Smrg }
229*627f7eb2Smrg }
230*627f7eb2Smrg }
231*627f7eb2Smrg body
232*627f7eb2Smrg {
233*627f7eb2Smrg //printf("body _d_switch_ustring()\n");
234*627f7eb2Smrg size_t low = 0;
235*627f7eb2Smrg auto high = table.length;
236*627f7eb2Smrg
version(none)237*627f7eb2Smrg version (none)
238*627f7eb2Smrg {
239*627f7eb2Smrg // Print table
240*627f7eb2Smrg wprintf("ca[] = '%.*s'\n", ca.length, ca.ptr);
241*627f7eb2Smrg for (auto i = 0; i < high; i++)
242*627f7eb2Smrg {
243*627f7eb2Smrg auto pca = table[i];
244*627f7eb2Smrg wprintf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr);
245*627f7eb2Smrg }
246*627f7eb2Smrg }
247*627f7eb2Smrg
248*627f7eb2Smrg // Do binary search
249*627f7eb2Smrg while (low < high)
250*627f7eb2Smrg {
251*627f7eb2Smrg auto mid = (low + high) >> 1;
252*627f7eb2Smrg auto pca = table[mid];
253*627f7eb2Smrg auto c = cast(sizediff_t)(ca.length - pca.length);
254*627f7eb2Smrg if (c == 0)
255*627f7eb2Smrg {
256*627f7eb2Smrg c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof);
257*627f7eb2Smrg if (c == 0)
258*627f7eb2Smrg { //printf("found %d\n", mid);
259*627f7eb2Smrg return cast(int)mid;
260*627f7eb2Smrg }
261*627f7eb2Smrg }
262*627f7eb2Smrg if (c < 0)
263*627f7eb2Smrg {
264*627f7eb2Smrg high = mid;
265*627f7eb2Smrg }
266*627f7eb2Smrg else
267*627f7eb2Smrg {
268*627f7eb2Smrg low = mid + 1;
269*627f7eb2Smrg }
270*627f7eb2Smrg }
271*627f7eb2Smrg //printf("not found\n");
272*627f7eb2Smrg return -1; // not found
273*627f7eb2Smrg }
274*627f7eb2Smrg
275*627f7eb2Smrg
276*627f7eb2Smrg unittest
277*627f7eb2Smrg {
278*627f7eb2Smrg switch (cast(wchar []) "c")
279*627f7eb2Smrg {
280*627f7eb2Smrg case "coo":
281*627f7eb2Smrg default:
282*627f7eb2Smrg break;
283*627f7eb2Smrg }
284*627f7eb2Smrg
bug5381(wstring ws)285*627f7eb2Smrg int bug5381(wstring ws)
286*627f7eb2Smrg {
287*627f7eb2Smrg switch (ws)
288*627f7eb2Smrg {
289*627f7eb2Smrg case "unittest": return 1;
290*627f7eb2Smrg case "D_Version2": return 2;
291*627f7eb2Smrg case "none": return 3;
292*627f7eb2Smrg case "all": return 4;
293*627f7eb2Smrg default: return 5;
294*627f7eb2Smrg }
295*627f7eb2Smrg }
296*627f7eb2Smrg int rc = bug5381("none"w);
297*627f7eb2Smrg assert(rc == 3);
298*627f7eb2Smrg }
299*627f7eb2Smrg
300*627f7eb2Smrg /**********************************
301*627f7eb2Smrg * Same thing, but for wide chars.
302*627f7eb2Smrg */
303*627f7eb2Smrg
_d_switch_dstring(dchar[][]table,dchar[]ca)304*627f7eb2Smrg int _d_switch_dstring(dchar[][] table, dchar[] ca)
305*627f7eb2Smrg in
306*627f7eb2Smrg {
307*627f7eb2Smrg //printf("in _d_switch_dstring()\n");
308*627f7eb2Smrg assert(table.length >= 0);
309*627f7eb2Smrg assert(ca.length >= 0);
310*627f7eb2Smrg
311*627f7eb2Smrg // Make sure table[] is sorted correctly
312*627f7eb2Smrg for (auto j = 1u; j < table.length; j++)
313*627f7eb2Smrg {
314*627f7eb2Smrg auto len1 = table[j - 1].length;
315*627f7eb2Smrg auto len2 = table[j].length;
316*627f7eb2Smrg
317*627f7eb2Smrg assert(len1 <= len2);
318*627f7eb2Smrg if (len1 == len2)
319*627f7eb2Smrg {
320*627f7eb2Smrg auto c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof);
321*627f7eb2Smrg assert(c < 0); // c==0 means a duplicate
322*627f7eb2Smrg }
323*627f7eb2Smrg }
324*627f7eb2Smrg }
out(result)325*627f7eb2Smrg out (result)
326*627f7eb2Smrg {
327*627f7eb2Smrg //printf("out _d_switch_dstring()\n");
328*627f7eb2Smrg if (result == -1)
329*627f7eb2Smrg {
330*627f7eb2Smrg // Not found
331*627f7eb2Smrg for (auto i = 0u; i < table.length; i++)
332*627f7eb2Smrg {
333*627f7eb2Smrg if (table[i].length == ca.length)
334*627f7eb2Smrg { auto c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
335*627f7eb2Smrg assert(c != 0);
336*627f7eb2Smrg }
337*627f7eb2Smrg }
338*627f7eb2Smrg }
339*627f7eb2Smrg else
340*627f7eb2Smrg {
341*627f7eb2Smrg assert(0 <= result && cast(size_t)result < table.length);
342*627f7eb2Smrg for (auto i = 0u; 1; i++)
343*627f7eb2Smrg {
344*627f7eb2Smrg assert(i < table.length);
345*627f7eb2Smrg if (table[i].length == ca.length)
346*627f7eb2Smrg {
347*627f7eb2Smrg auto c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
348*627f7eb2Smrg if (c == 0)
349*627f7eb2Smrg {
350*627f7eb2Smrg assert(i == result);
351*627f7eb2Smrg break;
352*627f7eb2Smrg }
353*627f7eb2Smrg }
354*627f7eb2Smrg }
355*627f7eb2Smrg }
356*627f7eb2Smrg }
357*627f7eb2Smrg body
358*627f7eb2Smrg {
359*627f7eb2Smrg //printf("body _d_switch_dstring()\n");
360*627f7eb2Smrg size_t low = 0;
361*627f7eb2Smrg auto high = table.length;
362*627f7eb2Smrg
version(none)363*627f7eb2Smrg version (none)
364*627f7eb2Smrg {
365*627f7eb2Smrg // Print table
366*627f7eb2Smrg wprintf("ca[] = '%.*s'\n", ca.length, ca.ptr);
367*627f7eb2Smrg for (auto i = 0; i < high; i++)
368*627f7eb2Smrg {
369*627f7eb2Smrg auto pca = table[i];
370*627f7eb2Smrg wprintf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr);
371*627f7eb2Smrg }
372*627f7eb2Smrg }
373*627f7eb2Smrg
374*627f7eb2Smrg // Do binary search
375*627f7eb2Smrg while (low < high)
376*627f7eb2Smrg {
377*627f7eb2Smrg auto mid = (low + high) >> 1;
378*627f7eb2Smrg auto pca = table[mid];
379*627f7eb2Smrg auto c = cast(sizediff_t)(ca.length - pca.length);
380*627f7eb2Smrg if (c == 0)
381*627f7eb2Smrg {
382*627f7eb2Smrg c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof);
383*627f7eb2Smrg if (c == 0)
384*627f7eb2Smrg { //printf("found %d\n", mid);
385*627f7eb2Smrg return cast(int)mid;
386*627f7eb2Smrg }
387*627f7eb2Smrg }
388*627f7eb2Smrg if (c < 0)
389*627f7eb2Smrg {
390*627f7eb2Smrg high = mid;
391*627f7eb2Smrg }
392*627f7eb2Smrg else
393*627f7eb2Smrg {
394*627f7eb2Smrg low = mid + 1;
395*627f7eb2Smrg }
396*627f7eb2Smrg }
397*627f7eb2Smrg //printf("not found\n");
398*627f7eb2Smrg return -1; // not found
399*627f7eb2Smrg }
400*627f7eb2Smrg
401*627f7eb2Smrg
402*627f7eb2Smrg unittest
403*627f7eb2Smrg {
404*627f7eb2Smrg switch (cast(dchar []) "c")
405*627f7eb2Smrg {
406*627f7eb2Smrg case "coo":
407*627f7eb2Smrg default:
408*627f7eb2Smrg break;
409*627f7eb2Smrg }
410*627f7eb2Smrg
bug5381(dstring ds)411*627f7eb2Smrg int bug5381(dstring ds)
412*627f7eb2Smrg {
413*627f7eb2Smrg switch (ds)
414*627f7eb2Smrg {
415*627f7eb2Smrg case "unittest": return 1;
416*627f7eb2Smrg case "D_Version2": return 2;
417*627f7eb2Smrg case "none": return 3;
418*627f7eb2Smrg case "all": return 4;
419*627f7eb2Smrg default: return 5;
420*627f7eb2Smrg }
421*627f7eb2Smrg }
422*627f7eb2Smrg int rc = bug5381("none"d);
423*627f7eb2Smrg assert(rc == 3);
424*627f7eb2Smrg }
425