From 4cc47e6dc21ac3f42cd1b21f8dd37d2c56c070fa Mon Sep 17 00:00:00 2001 From: Nathan Sashihara <21227491+n8sh@users.noreply.github.com> Date: Wed, 31 Oct 2018 01:33:22 -0400 Subject: [PATCH] Fix Issue 19364 - Decrease template bloat for string functions Use const(E)[] instead of E[] when it is valid and doesn't change the return type. --- std/range/primitives.d | 25 ++++++++++++++++--------- std/string.d | 12 ++++++------ std/utf.d | 24 +++++++++++++++++------- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/std/range/primitives.d b/std/range/primitives.d index 12f2e6087..91639478e 100644 --- a/std/range/primitives.d +++ b/std/range/primitives.d @@ -2192,7 +2192,7 @@ the first argument using the dot notation, `array.save` is equivalent to `save(array)`. The function does not duplicate the content of the array, it simply returns its argument. */ -@property T[] save(T)(T[] a) @safe pure nothrow @nogc +@property inout(T)[] save(T)(return scope inout(T)[] a) @safe pure nothrow @nogc { return a; } @@ -2213,7 +2213,7 @@ equivalent to `popFront(array)`. For $(GLOSSARY narrow strings), `popFront` automatically advances to the next $(GLOSSARY code point). */ -void popFront(T)(ref T[] a) @safe pure nothrow @nogc +void popFront(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof); @@ -2236,7 +2236,7 @@ if (!isNarrowString!(T[]) && !is(T[] == void[])) } /// ditto -void popFront(C)(ref C[] str) @trusted pure nothrow +void popFront(C)(scope ref inout(C)[] str) @trusted pure nothrow if (isNarrowString!(C[])) { import std.algorithm.comparison : min; @@ -2334,7 +2334,7 @@ the first argument using the dot notation, `array.popBack` is equivalent to `popBack(array)`. For $(GLOSSARY narrow strings), $(D popFront) automatically eliminates the last $(GLOSSARY code point). */ -void popBack(T)(ref T[] a) @safe pure nothrow @nogc +void popBack(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length); @@ -2357,7 +2357,7 @@ if (!isNarrowString!(T[]) && !is(T[] == void[])) } /// ditto -void popBack(T)(ref T[] a) @safe pure +void popBack(T)(scope ref inout(T)[] a) @safe pure if (isNarrowString!(T[])) { import std.utf : strideBack; @@ -2401,8 +2401,15 @@ equivalent to `front(array)`. For $(GLOSSARY narrow strings), $(D front) automatically returns the first $(GLOSSARY code point) as _a $(D dchar). */ -@property ref T front(T)(T[] a) @safe pure nothrow @nogc +@property ref T front(T)(return scope T[] a) @safe pure nothrow @nogc if (!isNarrowString!(T[]) && !is(T[] == void[])) +// We would have preferred to write the function template +// --- +// @property ref inout(T) front(T)(return scope inout(T)[] a) +// if (/* same constraint */) +// --- +// as that would cause fewer distinct functions to be generated with +// IFTI, but that caused a linker error in the test suite on Win32_64. { assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); return a[0]; @@ -2430,7 +2437,7 @@ if (!isNarrowString!(T[]) && !is(T[] == void[])) } /// ditto -@property dchar front(T)(T[] a) @safe pure +@property dchar front(T)(scope const(T)[] a) @safe pure if (isNarrowString!(T[])) { import std.utf : decode; @@ -2447,7 +2454,7 @@ equivalent to `back(array)`. For $(GLOSSARY narrow strings), $(D back) automatically returns the last $(GLOSSARY code point) as _a $(D dchar). */ -@property ref T back(T)(T[] a) @safe pure nothrow @nogc +@property ref inout(T) back(T)(return scope inout(T)[] a) @safe pure nothrow @nogc if (!isNarrowString!(T[]) && !is(T[] == void[])) { assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); @@ -2474,7 +2481,7 @@ if (!isNarrowString!(T[]) && !is(T[] == void[])) /// ditto // Specialization for strings -@property dchar back(T)(T[] a) @safe pure +@property dchar back(T)(scope const(T)[] a) @safe pure if (isNarrowString!(T[])) { import std.utf : decode, strideBack; diff --git a/std/string.d b/std/string.d index cfd036c67..ef8696d80 100644 --- a/std/string.d +++ b/std/string.d @@ -219,7 +219,7 @@ class StringException : Exception $(RED Important Note:) The returned array is a slice of the original buffer. The original data is not changed and not copied. +/ -Char[] fromStringz(Char)(Char* cString) @nogc @system pure nothrow +inout(Char)[] fromStringz(Char)(return scope inout(Char)* cString) @nogc @system pure nothrow if (isSomeChar!Char) { import core.stdc.stddef : wchar_t; @@ -229,7 +229,7 @@ if (isSomeChar!Char) else static if (is(Unqual!Char == wchar_t)) import core.stdc.wchar_ : cstrlen = wcslen; else - static size_t cstrlen(const Char* s) + static size_t cstrlen(scope const Char* s) { const(Char)* p = s; while (*p) @@ -432,7 +432,7 @@ if (isInputRange!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range) } /// Ditto -ptrdiff_t indexOf(C)(C[] s, dchar c, CaseSensitive cs = Yes.caseSensitive) +ptrdiff_t indexOf(C)(scope const(C)[] s, dchar c, CaseSensitive cs = Yes.caseSensitive) if (isSomeChar!C) { return _indexOf(s, c, cs); @@ -446,7 +446,7 @@ if (isInputRange!Range && isSomeChar!(ElementType!Range) && !isSomeString!Range) } /// Ditto -ptrdiff_t indexOf(C)(C[] s, dchar c, size_t startIdx, CaseSensitive cs = Yes.caseSensitive) +ptrdiff_t indexOf(C)(scope const(C)[] s, dchar c, size_t startIdx, CaseSensitive cs = Yes.caseSensitive) if (isSomeChar!C) { return _indexOf(s, c, startIdx, cs); @@ -5301,7 +5301,7 @@ if (isSomeChar!C1 && isSomeString!S && isSomeChar!C2) toRemove = The characters to remove from the string. buffer = An output range to write the contents to. +/ -void translate(C1, C2 = immutable char, Buffer)(C1[] str, +void translate(C1, C2 = immutable char, Buffer)(const(C1)[] str, in dchar[dchar] transTable, const(C2)[] toRemove, Buffer buffer) @@ -5357,7 +5357,7 @@ if (isSomeChar!C1 && isSomeString!S && isSomeChar!C2 && isOutputRange!(Buffer, S translateImpl(str, transTable, toRemove, buffer); } -private void translateImpl(C1, T, C2, Buffer)(C1[] str, +private void translateImpl(C1, T, C2, Buffer)(const(C1)[] str, T transTable, const(C2)[] toRemove, Buffer buffer) diff --git a/std/utf.d b/std/utf.d index c6b809ca3..4e4832189 100644 --- a/std/utf.d +++ b/std/utf.d @@ -1065,6 +1065,15 @@ if (isSomeChar!C) /// Whether or not to replace invalid UTF with $(LREF replacementDchar) alias UseReplacementDchar = Flag!"useReplacementDchar"; +// Reduce distinct instantiations of decodeImpl. +private template TypeForDecode(T) +{ + static if (isDynamicArray!T && is(T : E[], E) && __traits(isArithmetic, E) && !is(E == shared)) + alias TypeForDecode = const(Unqual!E)[]; + else + alias TypeForDecode = T; +} + /++ Decodes and returns the code point starting at `str[index]`. `index` is advanced to one past the decoded code point. If the code point is not @@ -1103,7 +1112,7 @@ do if (str[index] < codeUnitLimit!S) return str[index++]; else - return decodeImpl!(true, useReplacementDchar)(str, index); + return decodeImpl!(true, useReplacementDchar)(cast(TypeForDecode!S) str, index); } /// ditto @@ -1123,7 +1132,7 @@ do if (str[index] < codeUnitLimit!S) return str[index++]; else - return decodeImpl!(true, useReplacementDchar)(str, index); + return decodeImpl!(true, useReplacementDchar)(cast(TypeForDecode!S) str, index); } /// @@ -1200,7 +1209,7 @@ do //is undesirable, since not all overloads of decodeImpl need it. So, it //should be moved back into decodeImpl once bug# 8521 has been fixed. enum canIndex = isRandomAccessRange!S && hasSlicing!S && hasLength!S; - immutable retval = decodeImpl!(canIndex, useReplacementDchar)(str, numCodeUnits); + immutable retval = decodeImpl!(canIndex, useReplacementDchar)(cast(TypeForDecode!S) str, numCodeUnits); // The other range types were already popped by decodeImpl. static if (isRandomAccessRange!S && hasSlicing!S && hasLength!S) @@ -1233,7 +1242,7 @@ do } else { - immutable retval = decodeImpl!(true, useReplacementDchar)(str, numCodeUnits); + immutable retval = decodeImpl!(true, useReplacementDchar)(cast(TypeForDecode!S) str, numCodeUnits); str = str[numCodeUnits .. $]; return retval; } @@ -1307,7 +1316,7 @@ do numCodeUnits = strideBack(str); immutable newLength = str.length - numCodeUnits; size_t index = newLength; - immutable retval = decodeImpl!(true, useReplacementDchar)(str, index); + immutable retval = decodeImpl!(true, useReplacementDchar)(cast(TypeForDecode!S) str, index); str = str[0 .. newLength]; return retval; } @@ -1341,7 +1350,7 @@ do static if (isRandomAccessRange!S) { size_t index = str.length - numCodeUnits; - immutable retval = decodeImpl!(true, useReplacementDchar)(str, index); + immutable retval = decodeImpl!(true, useReplacementDchar)(cast(TypeForDecode!S) str, index); str.popBackExactly(numCodeUnits); return retval; } @@ -1357,7 +1366,8 @@ do } const Char[] codePoint = codeUnits[0 .. numCodeUnits]; size_t index = 0; - immutable retval = decodeImpl!(true, useReplacementDchar)(codePoint, index); + immutable retval = decodeImpl!(true, useReplacementDchar)( + cast(TypeForDecode!(typeof(codePoint))) codePoint, index); str = tmp; return retval; }