Merge pull request #8360 from WebFreak001/is-some-finite-char-input-range

add isSomeFiniteCharInputRange as simplification

Signed-off-by: Nicholas Wilson <thewilsonator@users.noreply.github.com>
Merged-on-behalf-of: Nicholas Wilson <thewilsonator@users.noreply.github.com>
This commit is contained in:
The Dlang Bot 2022-01-16 01:48:19 +00:00 committed by GitHub
commit 263652cee6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 110 additions and 96 deletions

View file

@ -50,7 +50,7 @@ module std.conv;
public import std.ascii : LetterCase;
import std.meta;
import std.range.primitives;
import std.range;
import std.traits;
import std.typecons : Flag, Yes, No, tuple, isTuple;
@ -1996,7 +1996,7 @@ if (isInputRange!S && isSomeChar!(ElementEncodingType!S) &&
/// ditto
private T toImpl(T, S)(S value, uint radix)
if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S) &&
if (isSomeFiniteCharInputRange!S &&
isIntegral!T && is(typeof(parse!T(value, radix))))
{
scope(success)

View file

@ -89,7 +89,7 @@ import std.datetime.date : DateTime;
import std.datetime.systime : Clock, SysTime, unixTimeToStdTime;
import std.internal.cstring;
import std.meta;
import std.range.primitives;
import std.range;
import std.traits;
import std.typecons;
@ -313,8 +313,7 @@ Throws: $(LREF FileException) on error.
*/
void[] read(R)(R name, size_t upTo = size_t.max)
if (isInputRange!R && isSomeChar!(ElementEncodingType!R) && !isInfinite!R &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
return readImpl(name, name.tempCString!FSChar(), upTo);
@ -500,7 +499,7 @@ version (linux) @safe unittest
$(REF UTFException, std, utf) on UTF decoding error.
+/
S readText(S = string, R)(auto ref R name)
if (isSomeString!S && (isInputRange!R && !isInfinite!R && isSomeChar!(ElementType!R) || is(StringTypeOf!R)))
if (isSomeString!S && (isSomeFiniteCharInputRange!R || is(StringTypeOf!R)))
{
import std.algorithm.searching : startsWith;
import std.encoding : getBOM, BOM;
@ -736,8 +735,7 @@ Throws: $(LREF FileException) on error.
See_also: $(REF toFile, std,stdio)
*/
void write(R)(R name, const void[] buffer)
if ((isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) || isSomeString!R) &&
!isConvertibleToString!R)
if ((isSomeFiniteCharInputRange!R || isSomeString!R) && !isConvertibleToString!R)
{
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
writeImpl(name, name.tempCString!FSChar(), buffer, false);
@ -785,8 +783,7 @@ Params:
Throws: $(LREF FileException) on error.
*/
void append(R)(R name, const void[] buffer)
if ((isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) || isSomeString!R) &&
!isConvertibleToString!R)
if ((isSomeFiniteCharInputRange!R || isSomeString!R) && !isConvertibleToString!R)
{
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
writeImpl(name, name.tempCString!FSChar(), buffer, true);
@ -915,10 +912,8 @@ version (Windows) private void writeImpl(scope const(char)[] name, scope const(F
* Throws: $(LREF FileException) on error.
*/
void rename(RF, RT)(RF from, RT to)
if ((isInputRange!RF && !isInfinite!RF && isSomeChar!(ElementEncodingType!RF) || isSomeString!RF)
&& !isConvertibleToString!RF &&
(isInputRange!RT && !isInfinite!RT && isSomeChar!(ElementEncodingType!RT) || isSomeString!RT)
&& !isConvertibleToString!RT)
if ((isSomeFiniteCharInputRange!RF || isSomeString!RF) && !isConvertibleToString!RF &&
(isSomeFiniteCharInputRange!RT || isSomeString!RT) && !isConvertibleToString!RT)
{
// Place outside of @trusted block
auto fromz = from.tempCString!FSChar();
@ -1027,8 +1022,7 @@ Params:
Throws: $(LREF FileException) on error.
*/
void remove(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
removeImpl(name, name.tempCString!FSChar());
@ -1082,7 +1076,7 @@ private void removeImpl(scope const(char)[] name, scope const(FSChar)* namez) @t
}
version (Windows) private WIN32_FILE_ATTRIBUTE_DATA getFileAttributesWin(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R))
if (isSomeFiniteCharInputRange!R)
{
auto namez = name.tempCString!FSChar();
@ -1137,8 +1131,7 @@ Throws:
$(LREF FileException) on error (e.g., file not found).
*/
ulong getSize(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@ -1233,8 +1226,7 @@ private SysTime statTimeToStdTime(char which)(ref const stat_t statbuf)
void getTimes(R)(R name,
out SysTime accessTime,
out SysTime modificationTime)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@ -1378,8 +1370,9 @@ version (StdDdoc)
out SysTime fileCreationTime,
out SysTime fileAccessTime,
out SysTime fileModificationTime)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R);
if (isSomeFiniteCharInputRange!R || isConvertibleToString!R);
// above line contains both constraints for docs
// (so users know how it can be called)
}
else version (Windows)
{
@ -1387,8 +1380,7 @@ else version (Windows)
out SysTime fileCreationTime,
out SysTime fileAccessTime,
out SysTime fileModificationTime)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
import std.datetime.systime : FILETIMEToSysTime;
@ -1509,8 +1501,7 @@ private
void setTimes(R)(R name,
SysTime accessTime,
SysTime modificationTime)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
auto namez = name.tempCString!FSChar();
static if (isNarrowString!R && is(immutable ElementEncodingType!R == immutable char))
@ -1657,8 +1648,7 @@ private void setTimesImpl(scope const(char)[] names, scope const(FSChar)* namez,
$(LREF FileException) if the given file does not exist.
+/
SysTime timeLastModified(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@ -1742,7 +1732,7 @@ else
--------------------
+/
SysTime timeLastModified(R)(R name, SysTime returnIfMissing)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R))
if (isSomeFiniteCharInputRange!R)
{
version (Windows)
{
@ -1902,8 +1892,7 @@ version (OSX) {} else
* true if the file _name specified as input _exists
*/
bool exists(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
return existsImpl(name.tempCString!FSChar());
}
@ -2004,8 +1993,7 @@ private bool existsImpl(scope const(FSChar)* namez) @trusted nothrow @nogc
Throws: $(LREF FileException) on error.
+/
uint getAttributes(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@ -2105,8 +2093,7 @@ if (isConvertibleToString!R)
$(LREF FileException) on error.
+/
uint getLinkAttributes(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@ -2214,8 +2201,7 @@ if (isConvertibleToString!R)
$(LREF FileException) if the given file does not exist.
+/
void setAttributes(R)(R name, uint attributes)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@ -2323,8 +2309,7 @@ if (isConvertibleToString!R)
$(LREF FileException) if the given file does not exist.
+/
@property bool isDir(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
{
@ -2503,8 +2488,7 @@ bool attrIsDir(uint attributes) @safe pure nothrow @nogc
$(LREF FileException) if the given file does not exist.
+/
@property bool isFile(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
return !name.isDir;
@ -2679,8 +2663,7 @@ bool attrIsFile(uint attributes) @safe pure nothrow @nogc
$(LREF FileException) if the given file does not exist.
+/
@property bool isSymlink(R)(R name)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
version (Windows)
return (getAttributes(name) & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
@ -2860,8 +2843,7 @@ Params:
Throws: $(LREF FileException) on error.
*/
void chdir(R)(R pathname)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
// Place outside of @trusted block
auto pathz = pathname.tempCString!FSChar();
@ -2931,8 +2913,7 @@ Throws:
if an error occured.
*/
void mkdir(R)(R pathname)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
// Place outside of @trusted block
const pathz = pathname.tempCString!FSChar();
@ -3135,8 +3116,7 @@ Params:
Throws: $(LREF FileException) on error.
*/
void rmdir(R)(R pathname)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) &&
!isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)
{
// Place outside of @trusted block
auto pathz = pathname.tempCString!FSChar();
@ -3202,15 +3182,11 @@ if (isConvertibleToString!R)
exists).
+/
version (StdDdoc) void symlink(RO, RL)(RO original, RL link)
if ((isInputRange!RO && !isInfinite!RO && isSomeChar!(ElementEncodingType!RO) ||
isConvertibleToString!RO) &&
(isInputRange!RL && !isInfinite!RL && isSomeChar!(ElementEncodingType!RL) ||
isConvertibleToString!RL));
if ((isSomeFiniteCharInputRange!RO || isConvertibleToString!RO) &&
(isSomeFiniteCharInputRange!RL || isConvertibleToString!RL));
else version (Posix) void symlink(RO, RL)(RO original, RL link)
if ((isInputRange!RO && !isInfinite!RO && isSomeChar!(ElementEncodingType!RO) ||
isConvertibleToString!RO) &&
(isInputRange!RL && !isInfinite!RL && isSomeChar!(ElementEncodingType!RL) ||
isConvertibleToString!RL))
if ((isSomeFiniteCharInputRange!RO || isConvertibleToString!RO) &&
(isSomeFiniteCharInputRange!RL || isConvertibleToString!RL))
{
static if (isConvertibleToString!RO || isConvertibleToString!RL)
{
@ -3291,11 +3267,9 @@ version (Posix) @safe unittest
$(LREF FileException) on error.
+/
version (StdDdoc) string readLink(R)(R link)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) ||
isConvertibleToString!R);
if (isSomeFiniteCharInputRange!R || isConvertibleToString!R);
else version (Posix) string readLink(R)(R link)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R) ||
isConvertibleToString!R)
if (isSomeFiniteCharInputRange!R || isConvertibleToString!R)
{
static if (isConvertibleToString!R)
{
@ -4216,8 +4190,8 @@ Params:
Throws: $(LREF FileException) on error.
*/
void copy(RF, RT)(RF from, RT to, PreserveAttributes preserve = preserveAttributesDefault)
if (isInputRange!RF && !isInfinite!RF && isSomeChar!(ElementEncodingType!RF) && !isConvertibleToString!RF &&
isInputRange!RT && !isInfinite!RT && isSomeChar!(ElementEncodingType!RT) && !isConvertibleToString!RT)
if (isSomeFiniteCharInputRange!RF && !isConvertibleToString!RF &&
isSomeFiniteCharInputRange!RT && !isConvertibleToString!RT)
{
// Place outside of @trusted block
auto fromz = from.tempCString!FSChar();
@ -4781,7 +4755,7 @@ private struct DirIteratorImpl
}
this(R)(R pathname, SpanMode mode, bool followSymlink)
if (isInputRange!R && isSomeChar!(ElementEncodingType!R))
if (isSomeFiniteCharInputRange!R)
{
_mode = mode;
_followSymlink = followSymlink;

View file

@ -19,7 +19,7 @@ module std.json;
import std.array;
import std.conv;
import std.range.primitives;
import std.range;
import std.traits;
///
@ -929,7 +929,7 @@ Params:
options = enable decoding string representations of NaN/Inf as float values
*/
JSONValue parseJSON(T)(T json, int maxDepth = -1, JSONOptions options = JSONOptions.none)
if (isInputRange!T && !isInfinite!T && isSomeChar!(ElementEncodingType!T))
if (isSomeFiniteCharInputRange!T)
{
import std.ascii : isDigit, isHexDigit, toUpper, toLower;
import std.typecons : Nullable, Yes;
@ -1437,7 +1437,7 @@ Params:
options = enable decoding string representations of NaN/Inf as float values
*/
JSONValue parseJSON(T)(T json, JSONOptions options)
if (isInputRange!T && !isInfinite!T && isSomeChar!(ElementEncodingType!T))
if (isSomeFiniteCharInputRange!T)
{
return parseJSON!T(json, -1, options);
}

View file

@ -98,7 +98,7 @@ module std.path;
import std.file : getcwd;
static import std.meta;
import std.range.primitives;
import std.range;
import std.traits;
version (OSX)
@ -262,8 +262,7 @@ version (Windows)
from a path.
*/
private auto ltrimDirSeparators(R)(R path)
if (isInputRange!R && !isInfinite!R && isSomeChar!(ElementType!R) ||
isNarrowString!R)
if (isSomeFiniteCharInputRange!R || isNarrowString!R)
{
static if (isRandomAccessRange!R && hasSlicing!R || isNarrowString!R)
{
@ -3213,12 +3212,8 @@ int filenameCharCmp(CaseSensitive cs = CaseSensitive.osDefault)(dchar a, dchar b
*/
int filenameCmp(CaseSensitive cs = CaseSensitive.osDefault, Range1, Range2)
(Range1 filename1, Range2 filename2)
if (isInputRange!Range1 && !isInfinite!Range1 &&
isSomeChar!(ElementEncodingType!Range1) &&
!isConvertibleToString!Range1 &&
isInputRange!Range2 && !isInfinite!Range2 &&
isSomeChar!(ElementEncodingType!Range2) &&
!isConvertibleToString!Range2)
if (isSomeFiniteCharInputRange!Range1 && !isConvertibleToString!Range1 &&
isSomeFiniteCharInputRange!Range2 && !isConvertibleToString!Range2)
{
alias C1 = Unqual!(ElementEncodingType!Range1);
alias C2 = Unqual!(ElementEncodingType!Range2);

View file

@ -106,9 +106,8 @@ version (Windows)
}
import std.internal.cstring;
import std.range.primitives;
import std.range;
import std.stdio;
import std.traits : isSomeChar;
version (OSX)
version = Darwin;
@ -1527,7 +1526,7 @@ package(std) string searchPathFor(scope const(char)[] executable)
// current user.
version (Posix)
private bool isExecutable(R)(R path) @trusted nothrow @nogc
if (isInputRange!R && isSomeChar!(ElementEncodingType!R))
if (isSomeFiniteCharInputRange!R)
{
return (access(path.tempCString(), X_OK) == 0);
}

View file

@ -13521,3 +13521,49 @@ pure @safe unittest
assert([1, 2, 3, 4].padRight(0, 10)[7 .. 9].equal([0, 0]));
}
/**
This simplifies a commonly used idiom in phobos for accepting any kind of string
parameter. The type `R` can for example be a simple string, chained string using
$(REF chain, std,range), $(REF chainPath, std,path) or any other input range of
characters.
Only finite length character ranges are allowed with this constraint.
This template is equivalent to:
---
isInputRange!R && !isInfinite!R && isSomeChar!(ElementEncodingType!R)
---
See_Also:
$(REF isInputRange, std,range,primitives),
$(REF isInfinite, std,range,primitives),
$(LREF isSomeChar),
$(REF ElementEncodingType, std,range,primitives)
*/
template isSomeFiniteCharInputRange(R)
{
import std.traits : isSomeChar;
enum isSomeFiniteCharInputRange = isInputRange!R && !isInfinite!R
&& isSomeChar!(ElementEncodingType!R);
}
///
@safe unittest
{
import std.path : chainPath;
import std.range : chain;
void someLibraryMethod(R)(R argument)
if (isSomeFiniteCharInputRange!R)
{
// implementation detail, would iterate over each character of argument
}
someLibraryMethod("simple strings work");
someLibraryMethod(chain("chained", " ", "strings", " ", "work"));
someLibraryMethod(chainPath("chained", "paths", "work"));
// you can also use custom structs implementing a char range
}

View file

@ -50,8 +50,8 @@ import core.stdc.stddef : wchar_t;
public import core.stdc.stdio;
import std.algorithm.mutation : copy;
import std.meta : allSatisfy;
import std.range.primitives : ElementEncodingType, empty, front,
isBidirectionalRange, isInputRange, put;
import std.range : ElementEncodingType, empty, front, isBidirectionalRange,
isInputRange, isSomeFiniteCharInputRange, put;
import std.traits : isSomeChar, isSomeString, Unqual, isPointer;
import std.typecons : Flag, No, Yes;
@ -555,7 +555,7 @@ Throws: `ErrnoException` if the file could not be opened.
/// ditto
this(R1, R2)(R1 name)
if (isInputRange!R1 && isSomeChar!(ElementEncodingType!R1))
if (isSomeFiniteCharInputRange!R1)
{
import std.conv : to;
this(name.to!string, "rb");
@ -563,8 +563,8 @@ Throws: `ErrnoException` if the file could not be opened.
/// ditto
this(R1, R2)(R1 name, R2 mode)
if (isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) &&
isInputRange!R2 && isSomeChar!(ElementEncodingType!R2))
if (isSomeFiniteCharInputRange!R1 &&
isSomeFiniteCharInputRange!R2)
{
import std.conv : to;
this(name.to!string, mode.to!string);
@ -4642,8 +4642,8 @@ if (isSomeChar!C && is(Unqual!C == C) && !is(C == enum) &&
* with appropriately-constructed C-style strings.
*/
private FILE* _fopen(R1, R2)(R1 name, R2 mode = "r")
if ((isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) || isSomeString!R1) &&
(isInputRange!R2 && isSomeChar!(ElementEncodingType!R2) || isSomeString!R2))
if ((isSomeFiniteCharInputRange!R1 || isSomeString!R1) &&
(isSomeFiniteCharInputRange!R2 || isSomeString!R2))
{
import std.internal.cstring : tempCString;
@ -4684,8 +4684,8 @@ version (Posix)
* with appropriately-constructed C-style strings.
*/
FILE* _popen(R1, R2)(R1 name, R2 mode = "r") @trusted nothrow @nogc
if ((isInputRange!R1 && isSomeChar!(ElementEncodingType!R1) || isSomeString!R1) &&
(isInputRange!R2 && isSomeChar!(ElementEncodingType!R2) || isSomeString!R2))
if ((isSomeFiniteCharInputRange!R1 || isSomeString!R1) &&
(isSomeFiniteCharInputRange!R2 || isSomeString!R2))
{
import std.internal.cstring : tempCString;

View file

@ -65,9 +65,9 @@ module std.utf;
import std.exception : basicExceptionCtors;
import core.exception : UnicodeException;
import std.meta : AliasSeq;
import std.range.primitives;
import std.traits : isAutodecodableString, isPointer, isSomeChar,
isSomeString, isStaticArray, Unqual, isConvertibleToString;
import std.range;
import std.traits : isAutodecodableString, isConvertibleToString, isPointer,
isSomeChar, isSomeString, isStaticArray, Unqual;
import std.typecons : Flag, Yes, No;
@ -2809,7 +2809,7 @@ if (isSomeChar!C)
The number of code units in `input` when encoded to `C`
+/
size_t codeLength(C, InputRange)(InputRange input)
if (isInputRange!InputRange && !isInfinite!InputRange && isSomeChar!(ElementType!InputRange))
if (isSomeFiniteCharInputRange!InputRange)
{
alias EncType = Unqual!(ElementEncodingType!InputRange);
static if (isSomeString!InputRange && is(EncType == C) && is(typeof(input.length)))
@ -2961,7 +2961,7 @@ if (isSomeString!S)
* For a lazy, non-allocating version of these functions, see $(LREF byUTF).
*/
string toUTF8(S)(S s)
if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
if (isSomeFiniteCharInputRange!S)
{
return toUTFImpl!string(s);
}
@ -3003,7 +3003,7 @@ if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
* For a lazy, non-allocating version of these functions, see $(LREF byUTF).
*/
wstring toUTF16(S)(S s)
if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
if (isSomeFiniteCharInputRange!S)
{
return toUTFImpl!wstring(s);
}
@ -3047,7 +3047,7 @@ if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
* For a lazy, non-allocating version of these functions, see $(LREF byUTF).
*/
dstring toUTF32(S)(scope S s)
if (isInputRange!S && !isInfinite!S && isSomeChar!(ElementEncodingType!S))
if (isSomeFiniteCharInputRange!S)
{
return toUTFImpl!dstring(s);
}