| /** | |
| * Contains support code for switch blocks using string constants. | |
| * | |
| * Copyright: Copyright Digital Mars 2004 - 2010. | |
| * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). | |
| * Authors: Walter Bright, Sean Kelly | |
| */ | |
| /* Copyright Digital Mars 2004 - 2010. | |
| * Distributed under the Boost Software License, Version 1.0. | |
| * (See accompanying file LICENSE or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| */ | |
| module rt.switch_; | |
| private import core.stdc.string; | |
| /****************************************************** | |
| * Support for switch statements switching on strings. | |
| * Input: | |
| * table[] sorted array of strings generated by compiler | |
| * ca string to look up in table | |
| * Output: | |
| * result index of match in table[] | |
| * -1 if not in table | |
| */ | |
| extern (C): | |
| int _d_switch_string(char[][] table, char[] ca) | |
| in | |
| { | |
| //printf("in _d_switch_string()\n"); | |
| assert(table.length >= 0); | |
| assert(ca.length >= 0); | |
| // Make sure table[] is sorted correctly | |
| for (size_t j = 1u; j < table.length; j++) | |
| { | |
| auto len1 = table[j - 1].length; | |
| auto len2 = table[j].length; | |
| assert(len1 <= len2); | |
| if (len1 == len2) | |
| { | |
| int ci; | |
| ci = memcmp(table[j - 1].ptr, table[j].ptr, len1); | |
| assert(ci < 0); // ci==0 means a duplicate | |
| } | |
| } | |
| } | |
| out (result) | |
| { | |
| int cj; | |
| //printf("out _d_switch_string()\n"); | |
| if (result == -1) | |
| { | |
| // Not found | |
| for (auto i = 0u; i < table.length; i++) | |
| { | |
| if (table[i].length == ca.length) | |
| { cj = memcmp(table[i].ptr, ca.ptr, ca.length); | |
| assert(cj != 0); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| assert(0 <= result && cast(size_t)result < table.length); | |
| for (auto i = 0u; 1; i++) | |
| { | |
| assert(i < table.length); | |
| if (table[i].length == ca.length) | |
| { | |
| cj = memcmp(table[i].ptr, ca.ptr, ca.length); | |
| if (cj == 0) | |
| { | |
| assert(i == result); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| body | |
| { | |
| //printf("body _d_switch_string(%.*s)\n", ca.length, ca.ptr); | |
| size_t low = 0; | |
| size_t high = table.length; | |
| version (none) | |
| { | |
| // Print table | |
| printf("ca[] = '%s'\n", ca.length, ca.ptr); | |
| for (auto i = 0; i < high; i++) | |
| { | |
| auto pca = table[i]; | |
| printf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr); | |
| } | |
| } | |
| if (high && | |
| ca.length >= table[0].length && | |
| ca.length <= table[high - 1].length) | |
| { | |
| // Looking for 0 length string, which would only be at the beginning | |
| if (ca.length == 0) | |
| return 0; | |
| char c1 = ca[0]; | |
| // Do binary search | |
| while (low < high) | |
| { | |
| auto mid = (low + high) >> 1; | |
| auto pca = table[mid]; | |
| auto c = cast(sizediff_t)(ca.length - pca.length); | |
| if (c == 0) | |
| { | |
| c = cast(ubyte)c1 - cast(ubyte)pca[0]; | |
| if (c == 0) | |
| { | |
| c = memcmp(ca.ptr, pca.ptr, ca.length); | |
| if (c == 0) | |
| { //printf("found %d\n", mid); | |
| return cast(int)mid; | |
| } | |
| } | |
| } | |
| if (c < 0) | |
| { | |
| high = mid; | |
| } | |
| else | |
| { | |
| low = mid + 1; | |
| } | |
| } | |
| } | |
| //printf("not found\n"); | |
| return -1; // not found | |
| } | |
| unittest | |
| { | |
| switch (cast(char []) "c") | |
| { | |
| case "coo": | |
| default: | |
| break; | |
| } | |
| int bug5381(string s) | |
| { | |
| switch (s) | |
| { | |
| case "unittest": return 1; | |
| case "D_Version2": return 2; | |
| case "none": return 3; | |
| case "all": return 4; | |
| default: return 5; | |
| } | |
| } | |
| int rc = bug5381("none"); | |
| assert(rc == 3); | |
| } | |
| /********************************** | |
| * Same thing, but for wide chars. | |
| */ | |
| int _d_switch_ustring(wchar[][] table, wchar[] ca) | |
| in | |
| { | |
| //printf("in _d_switch_ustring()\n"); | |
| assert(table.length >= 0); | |
| assert(ca.length >= 0); | |
| // Make sure table[] is sorted correctly | |
| for (size_t j = 1u; j < table.length; j++) | |
| { | |
| auto len1 = table[j - 1].length; | |
| auto len2 = table[j].length; | |
| assert(len1 <= len2); | |
| if (len1 == len2) | |
| { | |
| int c; | |
| c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof); | |
| assert(c < 0); // c==0 means a duplicate | |
| } | |
| } | |
| } | |
| out (result) | |
| { | |
| int c; | |
| //printf("out _d_switch_ustring()\n"); | |
| if (result == -1) | |
| { | |
| // Not found | |
| for (auto i = 0u; i < table.length; i++) | |
| { | |
| if (table[i].length == ca.length) | |
| { c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof); | |
| assert(c != 0); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| assert(0 <= result && cast(size_t)result < table.length); | |
| for (auto i = 0u; 1; i++) | |
| { | |
| assert(i < table.length); | |
| if (table[i].length == ca.length) | |
| { | |
| c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof); | |
| if (c == 0) | |
| { | |
| assert(i == result); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| body | |
| { | |
| //printf("body _d_switch_ustring()\n"); | |
| size_t low = 0; | |
| auto high = table.length; | |
| version (none) | |
| { | |
| // Print table | |
| wprintf("ca[] = '%.*s'\n", ca.length, ca.ptr); | |
| for (auto i = 0; i < high; i++) | |
| { | |
| auto pca = table[i]; | |
| wprintf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr); | |
| } | |
| } | |
| // Do binary search | |
| while (low < high) | |
| { | |
| auto mid = (low + high) >> 1; | |
| auto pca = table[mid]; | |
| auto c = cast(sizediff_t)(ca.length - pca.length); | |
| if (c == 0) | |
| { | |
| c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof); | |
| if (c == 0) | |
| { //printf("found %d\n", mid); | |
| return cast(int)mid; | |
| } | |
| } | |
| if (c < 0) | |
| { | |
| high = mid; | |
| } | |
| else | |
| { | |
| low = mid + 1; | |
| } | |
| } | |
| //printf("not found\n"); | |
| return -1; // not found | |
| } | |
| unittest | |
| { | |
| switch (cast(wchar []) "c") | |
| { | |
| case "coo": | |
| default: | |
| break; | |
| } | |
| int bug5381(wstring ws) | |
| { | |
| switch (ws) | |
| { | |
| case "unittest": return 1; | |
| case "D_Version2": return 2; | |
| case "none": return 3; | |
| case "all": return 4; | |
| default: return 5; | |
| } | |
| } | |
| int rc = bug5381("none"w); | |
| assert(rc == 3); | |
| } | |
| /********************************** | |
| * Same thing, but for wide chars. | |
| */ | |
| int _d_switch_dstring(dchar[][] table, dchar[] ca) | |
| in | |
| { | |
| //printf("in _d_switch_dstring()\n"); | |
| assert(table.length >= 0); | |
| assert(ca.length >= 0); | |
| // Make sure table[] is sorted correctly | |
| for (auto j = 1u; j < table.length; j++) | |
| { | |
| auto len1 = table[j - 1].length; | |
| auto len2 = table[j].length; | |
| assert(len1 <= len2); | |
| if (len1 == len2) | |
| { | |
| auto c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof); | |
| assert(c < 0); // c==0 means a duplicate | |
| } | |
| } | |
| } | |
| out (result) | |
| { | |
| //printf("out _d_switch_dstring()\n"); | |
| if (result == -1) | |
| { | |
| // Not found | |
| for (auto i = 0u; i < table.length; i++) | |
| { | |
| if (table[i].length == ca.length) | |
| { auto c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof); | |
| assert(c != 0); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| assert(0 <= result && cast(size_t)result < table.length); | |
| for (auto i = 0u; 1; i++) | |
| { | |
| assert(i < table.length); | |
| if (table[i].length == ca.length) | |
| { | |
| auto c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof); | |
| if (c == 0) | |
| { | |
| assert(i == result); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| body | |
| { | |
| //printf("body _d_switch_dstring()\n"); | |
| size_t low = 0; | |
| auto high = table.length; | |
| version (none) | |
| { | |
| // Print table | |
| wprintf("ca[] = '%.*s'\n", ca.length, ca.ptr); | |
| for (auto i = 0; i < high; i++) | |
| { | |
| auto pca = table[i]; | |
| wprintf("table[%d] = %d, '%.*s'\n", i, pca.length, pca.length, pca.ptr); | |
| } | |
| } | |
| // Do binary search | |
| while (low < high) | |
| { | |
| auto mid = (low + high) >> 1; | |
| auto pca = table[mid]; | |
| auto c = cast(sizediff_t)(ca.length - pca.length); | |
| if (c == 0) | |
| { | |
| c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof); | |
| if (c == 0) | |
| { //printf("found %d\n", mid); | |
| return cast(int)mid; | |
| } | |
| } | |
| if (c < 0) | |
| { | |
| high = mid; | |
| } | |
| else | |
| { | |
| low = mid + 1; | |
| } | |
| } | |
| //printf("not found\n"); | |
| return -1; // not found | |
| } | |
| unittest | |
| { | |
| switch (cast(dchar []) "c") | |
| { | |
| case "coo": | |
| default: | |
| break; | |
| } | |
| int bug5381(dstring ds) | |
| { | |
| switch (ds) | |
| { | |
| case "unittest": return 1; | |
| case "D_Version2": return 2; | |
| case "none": return 3; | |
| case "all": return 4; | |
| default: return 5; | |
| } | |
| } | |
| int rc = bug5381("none"d); | |
| assert(rc == 3); | |
| } |