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