Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 1747

Show
Ignore:
Timestamp:
07/12/10 00:48:49 (14 years ago)
Author:
andrei
Message:

Fixed http://d.puremagic.com/issues/show_bug.cgi?id=2971

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/phobos/std/conv.d

    r1733 r1747  
    11// Written in the D programming language. 
    22 
    33/** 
    44A one-stop shop for converting values from one type to another. 
    55 
    6 Copyright: Copyright Digital Mars 2007 - 2009
     6Copyright: Copyright Digital Mars 2007-
    77 
    88License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 
    99 
    1010Authors:   $(WEB digitalmars.com, Walter Bright), 
    1111           $(WEB erdani.org, Andrei Alexandrescu), 
    1212           Shin Fujishiro, 
    1313           Adam D. Ruppe 
    1414 
    15          Copyright Digital Mars 2007 - 2009. 
    16 Distributed under the Boost Software License, Version 1.0. 
    17    (See accompanying file LICENSE_1_0.txt or copy at 
    18          http://www.boost.org/LICENSE_1_0.txt) 
     15Copyright: Copyright Digital Mars 2007-. 
    1916*/ 
    2017module std.conv; 
    2118 
    2219import core.stdc.math : ldexpl; 
    2320import core.memory, core.stdc.errno, core.stdc.string, 
    2421    core.stdc.stdlib; 
    25 import std.array, std.ctype, std.exception, std.math, std.range, std.stdio
    26     std.string, std.traits, std.typecons, std.typetuple, std.utf; 
     22import std.algorithm, std.array, std.ctype, std.exception, std.math, std.range
     23    std.stdio, std.string, std.traits, std.typecons, std.typetuple, std.utf; 
    2724import std.metastrings; 
    2825 
    2926//debug=conv;           // uncomment to turn on debugging printf's 
    3027 
    3128/* ************* Exceptions *************** */ 
    3229 
    3330/** 
    3431 * Thrown on conversion errors. 
    3532 */ 
    3633class ConvError : Error 
    3734{ 
    3835    this(string s) 
    3936    { 
    4037        super(s); 
    4138    } 
    42     // static void raise(S, T)(S source) 
    43     // { 
    44     //     throw new ConvError(cast(string) 
    45     //             ("Can't convert value `"~to!(string)(source)~"' of type " 
    46     //                     ~S.stringof~" to type "~T.stringof)); 
    47     // } 
    48 
    49  
    50 private void conv_error(S, T, string f = __FILE__, uint ln = __LINE__) 
    51 (S source) 
     39
     40 
     41private void convError(S, T, string f = __FILE__, uint ln = __LINE__)(S source) 
    5242{ 
    5343    throw new ConvError(cast(string) 
    5444            ("std.conv("~to!string(ln) 
    5545                    ~"): Can't convert value `"~to!(string)(source)~"' of type " 
    5646                    ~S.stringof~" to type "~T.stringof)); 
    5747} 
    5848 
    5949/** 
    6050 * Thrown on conversion overflow errors. 
    6151 */ 
     
    7666private template implicitlyConverts(S, T) 
    7767{ 
    7868    enum bool implicitlyConverts = T.sizeof >= S.sizeof 
    7969        && is(typeof({S s; T t = s;}())); 
    8070} 
    8171 
    8272unittest 
    8373{ 
    8474    assert(!implicitlyConverts!(const(char)[], string)); 
    8575    assert(implicitlyConverts!(string, const(char)[])); 
     76} 
     77 
     78/** 
     79   Entry point that dispatches to the appropriate conversion 
     80   primitive. Client code normally calls $(D _to!TargetType(value)) 
     81   (and not some variant of $(D toImpl)). 
     82 */ 
     83template to(T) 
     84{ 
     85    T to(A...)(A args) { return toImpl!T(args); } 
    8686} 
    8787 
    8888/** 
    8989String _to string conversion works for any two string types having 
    9090($(D char), $(D wchar), $(D dchar)) character widths and any 
    9191combination of qualifiers (mutable, $(D const), or $(D immutable)). 
    9292 
    9393Example: 
    9494---- 
    9595char[] a = "abc"; 
    9696auto b = to!(immutable(dchar)[])(a); 
    9797assert(b == "abc"w); 
    9898---- 
    9999 */ 
    100 T to(T, S)(S s) if (!implicitlyConverts!(S, T) && isSomeString!(T) 
     100T toImpl(T, S)(S s) if (!implicitlyConverts!(S, T) && isSomeString!(T) 
    101101        && isSomeString!(S)) 
    102102{ 
    103103    // string-to-string conversion 
    104104    static if (s[0].sizeof == T[0].sizeof) { 
    105105        // same width, only qualifier conversion 
    106106        enum tIsConst = is(T == const(char)[]) || is(T == const(wchar)[]) 
    107107            || is(T == const(dchar)[]); 
    108108        enum tIsInvariant = is(T == immutable(char)[]) 
    109109            || is(T == immutable(wchar)[]) || is(T == immutable(dchar)[]); 
    110110        static if (tIsConst) { 
     
    137137    { 
    138138        alias TypeTuple!(LhsC[], const(LhsC)[], immutable(LhsC)[]) LhStrings; 
    139139        foreach (Lhs; LhStrings) 
    140140        { 
    141141            foreach (RhsC; Chars) 
    142142            { 
    143143                alias TypeTuple!(RhsC[], const(RhsC)[], immutable(RhsC)[]) 
    144144                    RhStrings; 
    145145                foreach (Rhs; RhStrings) 
    146146                { 
    147                     Lhs s1 = to!(Lhs)("wyda"); 
    148                     Rhs s2 = to!(Rhs)(s1); 
     147                    Lhs s1 = to!Lhs("wyda"); 
     148                    Rhs s2 = to!Rhs(s1); 
    149149                    //writeln(Lhs.stringof, " -> ", Rhs.stringof); 
    150                     assert(s1 == to!(Lhs)(s2)); 
     150                    assert(s1 == to!Lhs(s2)); 
    151151                } 
    152152            } 
    153153        } 
    154154    } 
    155155} 
    156156 
    157157/** 
    158158Converts array (other than strings) to string. The left bracket, 
    159159separator, and right bracket are configurable. Each element is 
    160160converted by calling $(D to!T). 
    161161 */ 
    162 T to(T, S)(S s, in T leftBracket = "[", in T separator = " ", 
     162T toImpl(T, S)(S s, in T leftBracket = "[", in T separator = " ", 
    163163    in T rightBracket = "]") 
    164164if (isSomeString!(T) && !isSomeString!(S) && isArray!(S)) 
    165165{ 
    166166    alias Unqual!(typeof(T.init[0])) Char; 
    167167    // array-to-string conversion 
    168168    static if (is(S == void[]) 
    169169            || is(S == const(void)[]) || is(S == immutable(void)[])) { 
    170170        auto raw = cast(const(ubyte)[]) s; 
    171171        enforce(raw.length % Char.sizeof == 0, "Alignment mismatch" 
    172172                " in converting a " ~ S.stringof ~ " to a " ~ T.stringof); 
     
    194194    double[2] a = [ 1.5, 2.5 ]; 
    195195    //writeln(to!string(a)); 
    196196    assert(to!string(a) == "[1.5 2.5]"); 
    197197} 
    198198 
    199199/** 
    200200Associative array to string conversion. The left bracket, key-value 
    201201separator, element separator, and right bracket are configurable. 
    202202Each element is printed by calling $(D to!T). 
    203203 */ 
    204 T to(T, S)(S s, in T leftBracket = "[", in T keyval = ":", 
     204T toImpl(T, S)(S s, in T leftBracket = "[", in T keyval = ":", 
    205205        in T separator = ", ", in T rightBracket = "]") 
    206206if (isAssociativeArray!(S) && isSomeString!(T)) 
    207207{ 
    208208    alias Unqual!(typeof(T.init[0])) Char; 
    209209    auto result = appender!(Char[])(); 
    210210    // hash-to-string conversion 
    211211    result.put(leftBracket); 
    212212    bool first = true; 
    213213    foreach (k, v; s) { 
    214214        if (!first) result.put(separator); 
     
    218218        result.put(to!(T)(v)); 
    219219    } 
    220220    result.put(rightBracket); 
    221221    return cast(T) result.data; 
    222222} 
    223223 
    224224/** 
    225225Object to string conversion calls $(D toString) against the object or 
    226226returns $(D nullstr) if the object is null. 
    227227 */ 
    228 T to(T, S)(S s, in T nullstr = "null") 
     228T toImpl(T, S)(S s, in T nullstr = "null") 
    229229if (is(S : Object) && isSomeString!(T)) 
    230230{ 
    231231    if (!s) return nullstr; 
    232232    return to!(T)(s.toString); 
    233233} 
    234234 
    235235unittest 
    236236{ 
    237237    class A { override string toString() { return "an A"; } } 
    238238    A a; 
    239239    assert(to!string(a) == "null"); 
    240240    a = new A; 
    241241    assert(to!string(a) == "an A"); 
    242242} 
    243243 
    244244/** 
    245245Struct to string conversion calls $(D toString) against the struct if 
    246246it is defined. 
    247247 */ 
    248 T to(T, S)(S s) 
     248T toImpl(T, S)(S s) 
    249249if (is(S == struct) && isSomeString!(T) && is(typeof(&S.init.toString))) 
    250250{ 
    251251    return to!T(s.toString); 
    252252} 
    253253 
    254254unittest 
    255255{ 
    256256    struct S { string toString() { return "wyda"; } } 
    257257    assert(to!string(S()) == "wyda"); 
    258258} 
    259259 
    260260/** 
    261261For structs that do not define $(D toString), the conversion to string 
    262262produces the list of fields. 
    263263 */ 
    264 T to(T, S)(S s, in T left = S.stringof~"(", in T separator = ", ", 
     264T toImpl(T, S)(S s, in T left = S.stringof~"(", in T separator = ", ", 
    265265        in T right = ")") 
    266266if (is(S == struct) && isSomeString!(T) && !is(typeof(&S.init.toString))) 
    267267{ 
    268268    Tuple!(FieldTypeTuple!(S)) * t = void; 
    269269    static if ((*t).sizeof == S.sizeof) 
    270270    { 
    271271        // ok, attempt to forge the tuple 
    272272        t = cast(typeof(t)) &s; 
    273273        alias Unqual!(typeof(T.init[0])) Char; 
    274274        auto app = appender!(Char[])(); 
     
    291291unittest 
    292292{ 
    293293    struct S { int a = 42; float b = 43.5; } 
    294294    S s; 
    295295    assert(to!string(s) == "S(42, 43.5)"); 
    296296} 
    297297 
    298298/** 
    299299Enumerated types are converted to strings as their symbolic names. 
    300300 */ 
    301 T to(T, S)(S s) if (is(S == enum) && isSomeString!(T) 
     301T toImpl(T, S)(S s) if (is(S == enum) && isSomeString!(T) 
    302302        && !implicitlyConverts!(S, T)) 
    303303{ 
    304304    mixin (enumToStringImpl!(S).code); 
    305305} 
    306306 
    307307// internal 
    308308private template enumToStringImpl(Enum) 
    309309{ 
    310310    template generate(alias members) 
    311311    { 
     
    344344        assert(0); 
    345345    } 
    346346    catch (ConvError e) 
    347347    { 
    348348    } 
    349349} 
    350350 
    351351/** 
    352352A $(D typedef Type Symbol) is converted to string as $(D "Type(value)"). 
    353353 */ 
    354 T to(T, S)(S s, in T left = S.stringof~"(", in T right = ")") 
     354T toImpl(T, S)(S s, in T left = S.stringof~"(", in T right = ")") 
    355355if (is(S == typedef) && isSomeString!(T)) 
    356356{ 
    357357    static if (is(S Original == typedef)) { 
    358358        // typedef 
    359359        return left ~ to!(T)(cast(Original) s) ~ right; 
    360360    } 
    361361} 
    362362 
    363363unittest 
    364364{ 
     
    489489conversion might throw an exception because $(D_PARAM to!(short)) 
    490490might fail the range check. 
    491491 
    492492Macros: WIKI=Phobos/StdConv 
    493493 */ 
    494494 
    495495/** 
    496496If the source type is implicitly convertible to the target type, $(D 
    497497to) simply performs the implicit conversion. 
    498498 */ 
    499 Target to(Target, Source)(Source value) if (implicitlyConverts!(Source, Target)) 
     499Target toImpl(Target, Source)(Source value) if (implicitlyConverts!(Source, Target)) 
    500500{ 
    501501    return value; 
    502502} 
    503503 
    504504unittest 
    505505{ 
    506506    int a = 42; 
    507507    auto b = to!long(a); 
    508508    assert(a == b); 
    509509} 
    510510 
    511511/** 
    512512Boolean values are printed as $(D "true") or $(D "false"). 
    513513 */ 
    514 T to(T, S)(S b) if (is(Unqual!S == bool) && isSomeString!(T)) 
     514T toImpl(T, S)(S b) if (is(Unqual!S == bool) && isSomeString!(T)) 
    515515{ 
    516516    return to!T(b ? "true" : "false"); 
    517517} 
    518518 
    519519unittest 
    520520{ 
    521521    bool b; 
    522522    assert(to!string(b) == "false"); 
    523523    b = true; 
    524524    assert(to!string(b) == "true"); 
    525525} 
    526526 
    527527 
    528528/** 
    529529When the source is a wide string, it is first converted to a narrow 
    530530string and then parsed. 
    531531 */ 
    532 T to(T, S)(S value) if ((is(S : const(wchar)[]) || is(S : const(dchar)[])) 
     532T toImpl(T, S)(S value) if ((is(S : const(wchar)[]) || is(S : const(dchar)[])) 
    533533        && !isSomeString!(T)) 
    534534{ 
    535535    // todo: improve performance 
    536536    return parseString!(T)(toUTF8(value)); 
    537537} 
    538538 
    539539/** 
    540540When the source is a narrow string, normal text parsing occurs. 
    541541 */ 
    542 T to(T, S)(S value) if (is(S : const(char)[]) && !isSomeString!(T)) 
     542T toImpl(T, S)(S value) if (is(S : const(char)[]) && !isSomeString!(T)) 
    543543{ 
    544544    return parseString!(T)(value); 
    545545} 
    546546 
    547547unittest 
    548548{ 
    549549    foreach (Char; TypeTuple!(char, wchar, dchar)) 
    550550    { 
    551551        auto a = to!(Char[])("123"); 
    552552        assert(to!int(a) == 123); 
    553553        assert(to!double(a) == 123); 
    554554    } 
    555555} 
    556556 
    557557/** 
    558558Object-to-object conversions throw exception when the source is 
    559559non-null and the target is null. 
    560560 */ 
    561 T to(T, S)(S value) if (is(S : Object) && is(T : Object)) 
     561T toImpl(T, S)(S value) if (is(S : Object) && is(T : Object)) 
    562562{ 
    563563    auto result = cast(T) value; 
    564564    if (!result && value) 
    565565    { 
    566566        throw new ConvError("Cannot convert object of static type " 
    567567                ~S.classinfo.name~" and dynamic type "~value.classinfo.name 
    568568                ~" to type "~T.classinfo.name); 
    569569    } 
    570570    return result; 
    571571} 
     
    603603    ... 
    604604} 
    605605 
    606606unittest 
    607607{ 
    608608    auto d = new Date; 
    609609    auto ts = to!long(d); // same as d.to!long() 
    610610} 
    611611---- 
    612612 */ 
    613 T to(T, S)(S value) if (is(S : Object) && !is(T : Object) && !isSomeString!T 
     613T toImpl(T, S)(S value) if (is(S : Object) && !is(T : Object) && !isSomeString!T 
    614614        && is(typeof(S.init.to!(T)()) : T)) 
    615615{ 
    616616    return value.to!T(); 
    617617} 
    618618 
    619619unittest 
    620620{ 
    621621    class B { T to(T)() { return 43; } } 
    622622    auto b = new B; 
    623623    assert(to!int(b) == 43); 
    624624} 
    625625 
    626626/** 
    627627Narrowing numeric-numeric conversions throw when the value does not 
    628628fit in the narrower type. 
    629629 */ 
    630 T to(T, S)(S value) 
     630T toImpl(T, S)(S value) 
    631631if (!implicitlyConverts!(S, T) 
    632632        && std.traits.isNumeric!(S) && std.traits.isNumeric!(T)) 
    633633{ 
    634634    enum sSmallest = mostNegative!(S); 
    635635    enum tSmallest = mostNegative!(T); 
    636636    static if (sSmallest < 0) { 
    637637        // possible underflow converting from a signed 
    638638        static if (tSmallest == 0) { 
    639639            immutable good = value >= 0; 
    640640        } else { 
     
    649649    } 
    650650    return cast(T) value; 
    651651} 
    652652 
    653653private T parseString(T)(const(char)[] v) 
    654654{ 
    655655    scope(exit) 
    656656    { 
    657657        if (v.length) 
    658658        { 
    659             conv_error!(const(char)[], T)(v); 
     659            convError!(const(char)[], T)(v); 
    660660        } 
    661661    } 
    662662    return parse!(T)(v); 
    663663} 
    664664 
    665665/** 
    666666Array-to-array conversion (except when target is a string type) 
    667667converts each element in turn by using $(D to). 
    668668 */ 
    669 T to(T, S)(S src) if (isArray!(S) && isArray!(T) && !isSomeString!(T) 
     669T toImpl(T, S)(S src) if (isArray!(S) && isArray!(T) && !isSomeString!(T) 
    670670        && !implicitlyConverts!(S, T)) 
    671671{ 
    672672    alias typeof(T.init[0]) E; 
    673673    auto result = new E[src.length]; 
    674674    foreach (i, e; src) { 
    675675    /* Temporarily cast to mutable type, so we can get it initialized, 
    676676     * this is ok because there are no other references to result[] 
    677677     */ 
    678678        cast()(result[i]) = to!(E)(e); 
    679679    } 
     
    693693    assert(b == [ 1.0f, 2, 3 ]); 
    694694    uint[][] e = [ a, a ]; 
    695695    auto f = to!(float[][])(e); 
    696696    assert(f[0] == b && f[1] == b); 
    697697} 
    698698 
    699699/** 
    700700Associative array to associative array conversion converts each key 
    701701and each value in turn. 
    702702 */ 
    703 T to(T, S)(S src) 
     703T toImpl(T, S)(S src) 
    704704if (isAssociativeArray!(S) && isAssociativeArray!(T)) 
    705705{ 
    706706    alias typeof(T.keys[0]) K2; 
    707707    alias typeof(T.values[0]) V2; 
    708708    T result; 
    709709    foreach (k1, v1; src) 
    710710    { 
    711711        result[to!(K2)(k1)] = to!(V2)(v1); 
    712712    } 
    713713    return result; 
     
    960960Target parse(Target, Source)(ref Source s) 
    961961if (isSomeChar!(ElementType!Source) && isIntegral!Target) 
    962962{ 
    963963    static if (Target.sizeof < int.sizeof) 
    964964    { 
    965965        // smaller types are handled like integers 
    966966        auto v = parse!(Select!(Target.min < 0, int, uint), Source)(s); 
    967967        auto result = cast(Target) v; 
    968968        if (result != v) 
    969969        { 
    970             conv_error!(Source, Target)(s); 
     970            convError!(Source, Target)(s); 
    971971        } 
    972972        return result; 
    973973    } 
    974974    else 
    975975    { 
    976976        // Larger than int types 
    977977        // immutable length = s.length; 
    978978        // if (!length) 
    979979        //     goto Lerr; 
    980980        if (s.empty) goto Lerr; 
     
    10261026        { 
    10271027            if (sign == -1) 
    10281028            { 
    10291029                v = -v; 
    10301030            } 
    10311031        } 
    10321032        return v; 
    10331033      Loverflow: 
    10341034        ConvOverflowError.raise("Overflow in integral conversion"); 
    10351035      Lerr: 
    1036         conv_error!(Source, Target)(s); 
     1036        convError!(Source, Target)(s); 
    10371037        return 0; 
    10381038    } 
    10391039} 
    10401040 
    10411041Target parse(Target, Source)(ref Source s) 
    10421042if (isSomeString!Source && is(Target == enum)) 
    10431043{ 
    10441044    mixin(enumFromStringImpl!Target.code); 
    10451045} 
    10461046 
     
    14011401    if (s.length >= 4 && icmp(s[0 .. 4], "true")==0) 
    14021402    { 
    14031403        s = s[4 .. $]; 
    14041404        return true; 
    14051405    } 
    14061406    if (s.length >= 5 && icmp(s[0 .. 5], "false")==0) 
    14071407    { 
    14081408        s = s[5 .. $]; 
    14091409        return false; 
    14101410    } 
    1411     conv_error!(Source, Target)(s); 
     1411    convError!(Source, Target)(s); 
    14121412    assert(0); 
    14131413} 
    14141414 
    14151415 
    14161416// Parsing typedefs forwards to their host types 
    14171417Target parse(Target, Source)(ref Source s) 
    14181418if (isSomeString!Source && is(Target == typedef)) 
    14191419{ 
    14201420    static if (is(Target T == typedef)) 
    14211421        return cast(Target) parse!T(s); 
     
    24682468        // incorrectly. 
    24692469        //if (cf > cfloat.max) 
    24702470        //    goto Loverflow; 
    24712471 
    24722472        return cf; 
    24732473 
    24742474      Loverflow: 
    24752475        conv_overflow(s); 
    24762476 
    24772477      Lerr: 
    2478         conv_error(s); 
     2478        convError(s); 
    24792479        return cast(cfloat)0.0e-0+0i; 
    24802480    } 
    24812481 
    24822482    unittest 
    24832483    { 
    24842484        debug(conv) writefln("conv.toCfloat.unittest"); 
    24852485        cfloat cf; 
    24862486 
    24872487        cf = toCfloat(to!string("1.2345e-5+0i")); 
    24882488        assert(to!string(cf) == to!string(1.2345e-5+0i)); 
     
    25432543        //Disabled, waiting on a bug fix. 
    25442544        //if (cd > cdouble.max)  //same problem the toCfloat() having 
    25452545        //    goto Loverflow; 
    25462546 
    25472547        return cd; 
    25482548 
    25492549      Loverflow: 
    25502550        conv_overflow(s); 
    25512551 
    25522552      Lerr: 
    2553         conv_error(s); 
     2553        convError(s); 
    25542554        return cast(cdouble)0.0e-0+0i; 
    25552555    } 
    25562556 
    25572557    unittest 
    25582558    { 
    25592559        debug(conv) writefln("conv.toCdouble.unittest"); 
    25602560        cdouble cd; 
    25612561 
    25622562        cd = toCdouble(to!string("1.2345e-5+0i")); 
    25632563        assert(to!string( cd ) == to!string(1.2345e-5+0i)); 
     
    26192619        if (s1 =="nan" && s2 == "nani") 
    26202620            cr = creal.nan; 
    26212621        else if (r2 != 0.0) 
    26222622            cr = cast(creal)(r1 + (r2 * 1.0i)); 
    26232623        else 
    26242624            cr = cast(creal)(r1 + 0.0i); 
    26252625 
    26262626        return cr; 
    26272627 
    26282628      Lerr: 
    2629         conv_error(s); 
     2629        convError(s); 
    26302630        return cast(creal)0.0e-0+0i; 
    26312631    } 
    26322632 
    26332633    unittest 
    26342634    { 
    26352635        debug(conv) writefln("conv.toCreal.unittest"); 
    26362636        creal cr; 
    26372637 
    26382638        cr = toCreal(to!string("1.2345e-5+0i")); 
    26392639        assert(to!string(cr) == to!string(1.2345e-5+0i)); 
     
    28052805    if (isnan(r1a)) 
    28062806        return cast(bool)isnan(r2b); 
    28072807 
    28082808    if (isnan(r2b)) 
    28092809        return 0; 
    28102810 
    28112811    return feq(r1a, r2b, 0.000001L); 
    28122812} 
    28132813 
    28142814/// Small unsigned integers to strings. 
    2815 T to(T, S)(S value) if (isIntegral!S && S.min == 0 
     2815T toImpl(T, S)(S value) if (isIntegral!S && S.min == 0 
    28162816        && S.sizeof < uint.sizeof && isSomeString!T) 
    28172817{ 
    28182818    return to!T(cast(uint) value); 
    28192819} 
    28202820 
    28212821/// Small signed integers to strings. 
    2822 T to(T, S)(S value) if (isIntegral!S && S.min < 0 
     2822T toImpl(T, S)(S value) if (isIntegral!S && S.min < 0 
    28232823        && S.sizeof < int.sizeof && isSomeString!T) 
    28242824{ 
    28252825    return to!T(cast(int) value); 
    28262826} 
    28272827 
    28282828/// Unsigned integers (uint and ulong) to string. 
    2829 T to(T, S)(S input) 
     2829T toImpl(T, S)(S input) 
    28302830if (staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T) 
    28312831{ 
    28322832    Unqual!S value = input; 
    28332833    alias Unqual!(typeof(T.init[0])) Char; 
    28342834    static if (is(typeof(T.init[0]) == const) || 
    28352835            is(typeof(T.init[0]) == immutable)) 
    28362836    { 
    28372837        if (value < 10) 
    28382838        { 
    28392839            static immutable Char[10] digits = "0123456789"; 
     
    28742874} 
    28752875 
    28762876unittest 
    28772877{ 
    28782878    assert(wtext(int.max) == "2147483647"w); 
    28792879    assert(wtext(int.min) == "-2147483648"w); 
    28802880    assert(to!string(0L) == "0"); 
    28812881} 
    28822882 
    28832883/// $(D char), $(D wchar), $(D dchar) to a string type. 
    2884 T to(T, S)(S c) if (staticIndexOf!(Unqual!S, char, wchar, dchar) >= 0 
     2884T toImpl(T, S)(S c) if (staticIndexOf!(Unqual!S, char, wchar, dchar) >= 0 
    28852885        && isSomeString!(T)) 
    28862886{ 
    28872887    alias typeof(T.init[0]) Char; 
    28882888    static if (Char.sizeof >= S.sizeof) 
    28892889    { 
    28902890        return [ c ]; 
    28912891    } 
    28922892    else 
    28932893    { 
    28942894        Unqual!Char[] result; 
     
    29112911        { 
    29122912            Char1 c = 'a'; 
    29132913            assert(to!(Char2[])(c)[0] == c); 
    29142914        } 
    29152915        uint x = 4; 
    29162916        assert(to!(Char1[])(x) == "4"); 
    29172917    } 
    29182918} 
    29192919 
    29202920/// Signed values ($(D int) and $(D long)). 
    2921 T to(T, S)(S value) 
     2921T toImpl(T, S)(S value) 
    29222922if (staticIndexOf!(Unqual!S, int, long) >= 0 && isSomeString!T) 
    29232923{ 
    29242924    if (value >= 0) 
    29252925        return to!T(cast(Unsigned!(S)) value); 
    29262926    alias Unqual!(typeof(T.init[0])) Char; 
    29272927 
    29282928    // Cache read-only data only for const and immutable - mutable 
    29292929    // data is supposed to use allocation in all cases 
    29302930    static if (is(ElementType!T == const) || is(ElementType!T == immutable)) 
    29312931    { 
     
    29822982    r = to!string(-123L); 
    29832983    i = cmp(r, "-123"); 
    29842984    assert(i == 0); 
    29852985 
    29862986    const h  = 6; 
    29872987    string s = to!string(h); 
    29882988    assert(s == "6"); 
    29892989} 
    29902990 
    29912991/// C-style strings 
    2992 T to(T, S)(S s) if (is(S : const(char)*) && isSomeString!(T)) 
     2992T toImpl(T, S)(S s) if (is(S : const(char)*) && isSomeString!(T)) 
    29932993{ 
    29942994    return s ? cast(T) s[0 .. strlen(s)].dup : cast(string)null; 
    29952995} 
    29962996 
    29972997/// $(D float) to all string types. 
    2998 T to(T, S)(S f) if (is(Unqual!S == float) && isSomeString!(T)) 
     2998T toImpl(T, S)(S f) if (is(Unqual!S == float) && isSomeString!(T)) 
    29992999{ 
    30003000    return to!T(cast(double) f); 
    30013001} 
    30023002 
    30033003/// $(D double) to all string types. 
    3004 T to(T, S)(S d) if (is(Unqual!S == double) && isSomeString!(T)) 
     3004T toImpl(T, S)(S d) if (is(Unqual!S == double) && isSomeString!(T)) 
    30053005{ 
    30063006    //alias Unqual!(ElementType!T) Char; 
    30073007    char[20] buffer; 
    30083008    int len = sprintf(buffer.ptr, "%g", d); 
    30093009    return to!T(buffer[0 .. len].dup); 
    30103010} 
    30113011 
    30123012/// $(D real) to all string types. 
    3013 T to(T, S)(S r) if (is(Unqual!S == real) && isSomeString!(T)) 
     3013T toImpl(T, S)(S r) if (is(Unqual!S == real) && isSomeString!(T)) 
    30143014{ 
    30153015    char[20] buffer; 
    30163016    int len = sprintf(buffer.ptr, "%Lg", r); 
    30173017    return to!T(buffer[0 .. len].dup); 
    30183018} 
    30193019 
    30203020/// $(D ifloat) to all string types. 
    3021 T to(T, S)(S f) if (is(Unqual!S == ifloat) && isSomeString!(T)) 
     3021T toImpl(T, S)(S f) if (is(Unqual!S == ifloat) && isSomeString!(T)) 
    30223022{ 
    30233023    return to!T(cast(idouble) f); 
    30243024} 
    30253025 
    30263026/// $(D idouble) to all string types. 
    3027 T to(T, S)(S d) if (is(Unqual!S == idouble) && isSomeString!(T)) 
     3027T toImpl(T, S)(S d) if (is(Unqual!S == idouble) && isSomeString!(T)) 
    30283028{ 
    30293029    char[21] buffer; 
    30303030    int len = sprintf(buffer.ptr, "%gi", d); 
    30313031    return to!T(buffer[0 .. len].dup); 
    30323032} 
    30333033 
    30343034/// $(D ireal) to all string types. 
    3035 T to(T, S)(S r) if (is(Unqual!S == ireal) && isSomeString!(T)) 
     3035T toImpl(T, S)(S r) if (is(Unqual!S == ireal) && isSomeString!(T)) 
    30363036{ 
    30373037    char[21] buffer; 
    30383038    int len = sprintf(buffer.ptr, "%Lgi", r); 
    30393039    //assert(len < buffer.length); // written bytes is len + 1 
    30403040    return to!T(buffer[0 .. len].dup); 
    30413041} 
    30423042 
    30433043/// $(D cfloat) to all string types. 
    3044 T to(T, S)(S f) if (is(Unqual!S == cfloat) && isSomeString!(T)) 
     3044T toImpl(T, S)(S f) if (is(Unqual!S == cfloat) && isSomeString!(T)) 
    30453045{ 
    30463046    return to!string(cast(cdouble) f); 
    30473047} 
    30483048 
    30493049/// $(D cdouble) to all string types. 
    3050 T to(T, S)(S d) if (is(Unqual!S == cdouble) && isSomeString!(T)) 
     3050T toImpl(T, S)(S d) if (is(Unqual!S == cdouble) && isSomeString!(T)) 
    30513051{ 
    30523052    char[20 + 1 + 20 + 1] buffer; 
    30533053 
    30543054    int len = sprintf(buffer.ptr, "%g+%gi", d.re, d.im); 
    30553055    return to!T(buffer[0 .. len]); 
    30563056} 
    30573057 
    30583058/// $(D creal) to all string types. 
    3059 T to(T, S)(S r) if (is(Unqual!S == creal) && isSomeString!(T)) 
     3059T toImpl(T, S)(S r) if (is(Unqual!S == creal) && isSomeString!(T)) 
    30603060{ 
    30613061    char[20 + 1 + 20 + 1] buffer; 
    30623062    int len = sprintf(buffer.ptr, "%Lg+%Lgi", r.re, r.im); 
    30633063    return to!T(buffer[0 .. len].dup); 
    30643064} 
    30653065 
    30663066/****************************************** 
    30673067 * Convert value to string in _radix radix. 
    30683068 * 
    30693069 * radix must be a value from 2 to 36. 
    30703070 * value is treated as a signed value only if radix is 10. 
    30713071 * The characters A through Z are used to represent values 10 through 36. 
    30723072 */ 
    3073 T to(T, S)(S value, uint radix) 
     3073T toImpl(T, S)(S value, uint radix) 
    30743074if (isIntegral!(Unqual!S) && !is(Unqual!S == ulong) && isSomeString!(T)) 
    30753075{ 
    30763076    enforce(radix >= 2 && radix <= 36); 
    30773077    if (radix == 10) 
    30783078        return to!string(value);     // handle signed cases only for radix 10 
    30793079    return to!string(cast(ulong) value, radix); 
    30803080} 
    30813081 
    30823082/// ditto 
    3083 T to(T, S)(S value, uint radix) 
     3083T toImpl(T, S)(S value, uint radix) 
    30843084if (is(Unqual!S == ulong) && isSomeString!(T)) 
    30853085in 
    30863086{ 
    30873087    assert(radix >= 2 && radix <= 36); 
    30883088} 
    30893089body 
    30903090{ 
    30913091    char[value.sizeof * 8] buffer; 
    30923092    uint i = buffer.length; 
    30933093 
     
    33353335    assert(i == 0); 
    33363336 
    33373337    r = to!string(123u); 
    33383338    i = cmp(r, "123"); 
    33393339    assert(i == 0); 
    33403340} 
    33413341 
    33423342/** 
    33433343Pointer to string conversions prints the pointer as a $(D size_t) value. 
    33443344 */ 
    3345 T to(T, S)(S value) 
     3345T toImpl(T, S)(S value) 
    33463346if (isPointer!S && !isSomeChar!(typeof(*S.init)) && isSomeString!T) 
    33473347{ 
    33483348    return to!T(cast(size_t) value, 16u); 
    33493349} 
    33503350 
    33513351private S textImpl(S, U...)(U args) 
    33523352{ 
    33533353    S result; 
    33543354    foreach (i, arg; args) 
    33553355    { 
     
    36133613 
    36143614    // this should pass, but it doesn't, since the int converter 
    36153615    // doesn't pass along its suffix to helper templates 
    36163616 
    36173617    //static assert(!__traits(compiles, a = octal!1L)); 
    36183618 
    36193619    static assert(__traits(compiles, b = octal!"1L")); 
    36203620    static assert(__traits(compiles, b = octal!1L)); 
    36213621} 
    36223622 
    3623 T to(T, S)(S src) if (is(T == struct) && is(typeof(T(src)))) 
     3623T toImpl(T, S)(S src) if (is(T == struct) && is(typeof(T(src)))) 
    36243624{ 
    36253625    return T(src); 
    36263626} 
    36273627 
    36283628// Bugzilla 3961 
    36293629unittest 
    36303630{ 
    36313631    struct Int { int x; } 
    36323632    Int i = to!Int(1); 
    36333633} 
     
    36983698        double x = 5, y = 6; 
    36993699        this(int a, int b) { assert(x == 5 && y == 6); x = a; y = b; } 
    37003700    } 
    37013701 
    37023702    auto s1 = new void[S.sizeof]; 
    37033703    auto s2 = S(42, 43); 
    37043704    assert(*emplace!S(s1, s2) == s2); 
    37053705    assert(*emplace!S(s1, 44, 45) == S(44, 45)); 
    37063706} 
    37073707 
     3708unittest 
     3709{ 
     3710    // Check fix for http://d.puremagic.com/issues/show_bug.cgi?id=2971 
     3711    assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345])); 
     3712} 
     3713