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