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