xref: /netbsd-src/external/gpl3/gcc.old/dist/libphobos/libdruntime/rt/switch_.d (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
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