Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mak/COPY
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ COPY=\
$(IMPDIR)\core\internal\parseoptions.d \
$(IMPDIR)\core\internal\spinlock.d \
$(IMPDIR)\core\internal\string.d \
$(IMPDIR)\core\internal\switch_.d \
$(IMPDIR)\core\internal\traits.d \
$(IMPDIR)\core\internal\utf.d \
$(IMPDIR)\core\internal\lifetime.d \
Expand Down
2 changes: 2 additions & 0 deletions mak/DOCS
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ DOCS=\
$(DOCDIR)\core_sys_darwin_mach_semaphore.html \
$(DOCDIR)\core_sys_darwin_mach_thread_act.html \
$(DOCDIR)\core_sys_darwin_netinet_in_.html \
\
$(DOCDIR)\core_internal_switch_.html \
\
$(DOCDIR)\core_internal_array_appending.html \
$(DOCDIR)\core_internal_array_capacity.html \
Expand Down
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ SRCS=\
src\core\internal\parseoptions.d \
src\core\internal\spinlock.d \
src\core\internal\string.d \
src\core\internal\switch_.d \
src\core\internal\traits.d \
src\core\internal\utf.d \
src\core\internal\lifetime.d \
Expand Down
3 changes: 3 additions & 0 deletions mak/WINDOWS
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ $(IMPDIR)\core\internal\spinlock.d : src\core\internal\spinlock.d
$(IMPDIR)\core\internal\string.d : src\core\internal\string.d
copy $** $@

$(IMPDIR)\core\internal\switch_.d : src\core\internal\switch_.d
copy $** $@

$(IMPDIR)\core\internal\traits.d : src\core\internal\traits.d
copy $** $@

Expand Down
3 changes: 3 additions & 0 deletions posix.mak
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ $(DOCDIR)/core_sys_darwin_mach_%.html : src/core/sys/darwin/mach/%.d $(DMD)
$(DOCDIR)/core_sys_darwin_netinet_%.html : src/core/sys/darwin/netinet/%.d $(DMD)
$(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $<

$(DOCDIR)/core_internal_switch_.html : src/core/internal/switch_.d $(DMD)
$(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $<

$(DOCDIR)/core_internal_array_%.html : src/core/internal/array/%.d $(DMD)
$(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $<

Expand Down
189 changes: 189 additions & 0 deletions src/core/internal/switch_.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/**
This module contains compiler support for switch...case statements

Copyright: Copyright Digital Mars 2000 - 2019.
License: Distributed under the
$(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
(See accompanying file LICENSE)
Source: $(DRUNTIMESRC core/internal/_switch_.d)
*/
module core.internal.switch_;

/**
Support for switch statements switching on strings.
Params:
caseLabels = sorted array of strings generated by compiler. Note the
strings are sorted by length first, and then lexicographically.
condition = string to look up in table
Returns:
index of match in caseLabels, a negative integer if not found
*/
int __switch(T, caseLabels...)(/*in*/ const scope T[] condition) pure nothrow @safe @nogc
{
// This closes recursion for other cases.
static if (caseLabels.length == 0)
{
return int.min;
}
else static if (caseLabels.length == 1)
{
return __cmp(condition, caseLabels[0]) == 0 ? 0 : int.min;
}
// To be adjusted after measurements
// Compile-time inlined binary search.
else static if (caseLabels.length < 7)
{
int r = void;
enum mid = cast(int)caseLabels.length / 2;
if (condition.length == caseLabels[mid].length)
{
r = __cmp(condition, caseLabels[mid]);
if (r == 0) return mid;
}
else
{
// Equivalent to (but faster than) condition.length > caseLabels[$ / 2].length ? 1 : -1
r = ((condition.length > caseLabels[mid].length) << 1) - 1;
}

if (r < 0)
{
// Search the left side
return __switch!(T, caseLabels[0 .. mid])(condition);
}
else
{
// Search the right side
return __switch!(T, caseLabels[mid + 1 .. $])(condition) + mid + 1;
}
}
else
{
// Need immutable array to be accessible in pure code, but case labels are
// currently coerced to the switch condition type (e.g. const(char)[]).
static immutable T[][caseLabels.length] cases = {
auto res = new immutable(T)[][](caseLabels.length);
foreach (i, s; caseLabels)
res[i] = s.idup;
return res;
}();

// Run-time binary search in a static array of labels.
return __switchSearch!T(cases[], condition);
}
}

// binary search in sorted string cases, also see `__switch`.
private int __switchSearch(T)(/*in*/ const scope T[][] cases, /*in*/ const scope T[] condition) pure nothrow @safe @nogc
{
size_t low = 0;
size_t high = cases.length;

do
{
auto mid = (low + high) / 2;
int r = void;
if (condition.length == cases[mid].length)
{
r = __cmp(condition, cases[mid]);
if (r == 0) return cast(int) mid;
}
else
{
// Generates better code than "expr ? 1 : -1" on dmd and gdc, same with ldc
r = ((condition.length > cases[mid].length) << 1) - 1;
}

if (r > 0) low = mid + 1;
else high = mid;
}
while (low < high);

// Not found
return -1;
}

@system unittest
{
static void testSwitch(T)()
{
switch (cast(T[]) "c")
{
case "coo":
default:
break;
}

static int bug5381(immutable(T)[] s)
{
switch (s)
{
case "unittest": return 1;
case "D_Version2": return 2;
case "nonenone": return 3;
case "none": return 4;
case "all": return 5;
default: return 6;
}
}

int rc = bug5381("unittest");
assert(rc == 1);

rc = bug5381("D_Version2");
assert(rc == 2);

rc = bug5381("nonenone");
assert(rc == 3);

rc = bug5381("none");
assert(rc == 4);

rc = bug5381("all");
assert(rc == 5);

rc = bug5381("nonerandom");
assert(rc == 6);

static int binarySearch(immutable(T)[] s)
{
switch (s)
{
static foreach (i; 0 .. 16)
case i.stringof: return i;
default: return -1;
}
}
static foreach (i; 0 .. 16)
assert(binarySearch(i.stringof) == i);
assert(binarySearch("") == -1);
assert(binarySearch("sth.") == -1);
assert(binarySearch(null) == -1);

static int bug16739(immutable(T)[] s)
{
switch (s)
{
case "\u0100": return 1;
case "a": return 2;
default: return 3;
}
}
assert(bug16739("\u0100") == 1);
assert(bug16739("a") == 2);
assert(bug16739("foo") == 3);
}
testSwitch!char;
testSwitch!wchar;
testSwitch!dchar;
}

/**
Compiler lowers final switch default case to this (which is a runtime error)
Old implementation is in core/exception.d
*/
void __switch_error()(string file = __FILE__, size_t line = __LINE__)
{
import core.exception : __switch_errorT;
__switch_errorT(file, line);
}
Loading