mirror of
https://github.com/dlang/phobos.git
synced 2025-05-01 23:50:31 +03:00
Merge pull request #1540 from AndrejMitrovic/ConvOptimize
Use a switch table for enum->string conversion, which avoids runtime memory allocation.
This commit is contained in:
commit
d39696d151
1 changed files with 94 additions and 7 deletions
101
std/conv.d
101
std/conv.d
|
@ -803,7 +803,7 @@ T toImpl(T, S)(S value)
|
|||
}
|
||||
else static if (isIntegral!S && !is(S == enum))
|
||||
{
|
||||
// other integral-to-string conversions with default radix
|
||||
// other integral-to-string conversions with default radix
|
||||
return toImpl!(T, S)(value, 10);
|
||||
}
|
||||
else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[]))
|
||||
|
@ -824,6 +824,25 @@ T toImpl(T, S)(S value)
|
|||
// It is unsafe because we cannot guarantee that the pointer is null terminated.
|
||||
return value ? cast(T) value[0 .. strlen(value)].dup : cast(string)null;
|
||||
}
|
||||
else static if (isSomeString!T && is(S == enum) && isSwitchable!(OriginalType!S))
|
||||
{
|
||||
// generate a switch statement with string literals instead of allocating memory
|
||||
// @@@BUG@@@ 10950 workaround: [CTFE] enum "char[]" not correctly duplicated when used.
|
||||
enum rep(S val) = mixin(format(`"%s"%s`,
|
||||
toStr!string(val), charLiteralSuffix!(ElementEncodingType!T)));
|
||||
|
||||
switch (value)
|
||||
{
|
||||
foreach (member; NoDuplicates!(EnumMembers!S))
|
||||
{
|
||||
case member:
|
||||
return to!T(rep!member);
|
||||
}
|
||||
|
||||
default:
|
||||
return toStr!T(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// other non-string values runs formatting
|
||||
|
@ -831,6 +850,46 @@ T toImpl(T, S)(S value)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Check whether type $(D T) can be used in a switch statement.
|
||||
This is useful for compile-time generation of switch case statements.
|
||||
*/
|
||||
private template isSwitchable(E)
|
||||
{
|
||||
enum bool isSwitchable = is(typeof({
|
||||
switch (E.init) { default: }
|
||||
}));
|
||||
}
|
||||
|
||||
//
|
||||
unittest
|
||||
{
|
||||
static assert(isSwitchable!int);
|
||||
static assert(!isSwitchable!double);
|
||||
static assert(!isSwitchable!real);
|
||||
}
|
||||
|
||||
/*
|
||||
Get the char literal suffix for some char type $(D T),
|
||||
to be used as a suffix to create a string literal
|
||||
with the element encoding type $(D T).
|
||||
*/
|
||||
private template charLiteralSuffix(T) if (isSomeChar!T)
|
||||
{
|
||||
alias literalSuffix = TypeTuple!('c', 'w', 'd');
|
||||
alias charTypes = TypeTuple!(char, wchar, dchar);
|
||||
enum charLiteralSuffix = literalSuffix[staticIndexOf!(Unqual!T, charTypes)];
|
||||
}
|
||||
|
||||
//
|
||||
unittest
|
||||
{
|
||||
static assert(charLiteralSuffix!char == 'c');
|
||||
static assert(charLiteralSuffix!wchar == 'w');
|
||||
static assert(charLiteralSuffix!dchar == 'd');
|
||||
static assert(charLiteralSuffix!(immutable(char)) == 'c');
|
||||
}
|
||||
|
||||
/*@safe pure */unittest
|
||||
{
|
||||
// string to string conversion
|
||||
|
@ -1076,6 +1135,34 @@ unittest
|
|||
assert(to!dstring(o) == "cast(EU)5"d);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
enum E
|
||||
{
|
||||
foo,
|
||||
bar,
|
||||
doo = foo, // check duplicate switch statements
|
||||
}
|
||||
|
||||
foreach (S; TypeTuple!(string, wstring, dstring, const(char[]), const(wchar[]), const(dchar[])))
|
||||
{
|
||||
auto s1 = to!S(E.foo);
|
||||
auto s2 = to!S(E.foo);
|
||||
assert(s1 == s2);
|
||||
// ensure we don't allocate when it's unnecessary
|
||||
assert(s1 is s2);
|
||||
}
|
||||
|
||||
foreach (S; TypeTuple!(char[], wchar[], dchar[]))
|
||||
{
|
||||
auto s1 = to!S(E.foo);
|
||||
auto s2 = to!S(E.foo);
|
||||
assert(s1 == s2);
|
||||
// ensure each mutable array is unique
|
||||
assert(s1 !is s2);
|
||||
}
|
||||
}
|
||||
|
||||
/// ditto
|
||||
@trusted pure T toImpl(T, S)(S value, uint radix, LetterCase letterCase = LetterCase.upper)
|
||||
if (isIntegral!S &&
|
||||
|
@ -3827,8 +3914,8 @@ T* emplace(T, Args...)(T* chunk, auto ref Args args)
|
|||
}
|
||||
else
|
||||
{
|
||||
//We can't emplace. Try to diagnose a disabled postblit.
|
||||
static assert(!(Args.length == 1 && is(Args[0] : T)),
|
||||
//We can't emplace. Try to diagnose a disabled postblit.
|
||||
static assert(!(Args.length == 1 && is(Args[0] : T)),
|
||||
"struct " ~ T.stringof ~ " is not emplaceable because its copy is annotated with @disable");
|
||||
|
||||
//We can't emplace.
|
||||
|
@ -3966,7 +4053,7 @@ unittest
|
|||
static struct S
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
this(S other){assert(false);}
|
||||
this(int i){this.i = i;}
|
||||
this(this){}
|
||||
|
@ -4055,7 +4142,7 @@ unittest
|
|||
static assert( __traits(compiles, emplace(&ss2)));
|
||||
static assert(!__traits(compiles, emplace(&ss2, SS2.init)));
|
||||
|
||||
|
||||
|
||||
// SS1 sss1 = s1; //This doesn't compile
|
||||
// SS1 sss1 = SS1(s1); //This doesn't compile
|
||||
// So emplace shouldn't compile either
|
||||
|
@ -4349,10 +4436,10 @@ unittest //http://forum.dlang.org/thread/nxbdgtdlmwscocbiypjs@forum.dlang.org
|
|||
assert(&b2);
|
||||
auto b3 = B(SysTime(0, UTC()), 1, A(1));
|
||||
assert(&b3);
|
||||
|
||||
|
||||
import std.array;
|
||||
auto arr = [b2, b3];
|
||||
|
||||
|
||||
assert(arr[0].j == 1);
|
||||
assert(arr[1].j == 1);
|
||||
auto a2 = arr.array(); // << bang, invariant is raised, also if b2 and b3 are good
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue