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