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 }