| /** |
| * 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); |
| } |