PageRenderTime 187ms CodeModel.GetById 25ms app.highlight 143ms RepoModel.GetById 1ms app.codeStats 1ms

/std/conv.d

http://github.com/jcd/phobos
D | 4888 lines | 3813 code | 448 blank | 627 comment | 824 complexity | 9f8975efc579f42aff691130644fc5ba MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1// Written in the D programming language.
   2
   3/**
   4A one-stop shop for converting values from one type to another.
   5
   6Copyright: Copyright Digital Mars 2007-.
   7
   8License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
   9
  10Authors:   $(WEB digitalmars.com, Walter Bright),
  11           $(WEB erdani.org, Andrei Alexandrescu),
  12           Shin Fujishiro,
  13           Adam D. Ruppe,
  14           Kenji Hara
  15
  16Source:    $(PHOBOSSRC std/_conv.d)
  17
  18Macros:
  19WIKI = Phobos/StdConv
  20
  21*/
  22module std.conv;
  23
  24import core.stdc.string;
  25import std.algorithm, std.array, std.ascii, std.exception, std.range,
  26    std.string, std.traits, std.typecons, std.typetuple, std.uni,
  27    std.utf;
  28import std.format;
  29
  30//debug=conv;           // uncomment to turn on debugging printf's
  31
  32/* ************* Exceptions *************** */
  33
  34/**
  35 * Thrown on conversion errors.
  36 */
  37class ConvException : Exception
  38{
  39    @safe pure nothrow
  40    this(string s, string fn = __FILE__, size_t ln = __LINE__)
  41    {
  42        super(s, fn, ln);
  43    }
  44}
  45
  46private string convError_unexpected(S)(S source)
  47{
  48    return source.empty ? "end of input" : text("'", source.front, "'");
  49}
  50
  51private auto convError(S, T)(S source, string fn = __FILE__, size_t ln = __LINE__)
  52{
  53    return new ConvException(
  54        text("Unexpected ", convError_unexpected(source),
  55             " when converting from type "~S.stringof~" to type "~T.stringof),
  56        fn, ln);
  57}
  58
  59private auto convError(S, T)(S source, int radix, string fn = __FILE__, size_t ln = __LINE__)
  60{
  61    return new ConvException(
  62        text("Unexpected ", convError_unexpected(source),
  63             " when converting from type "~S.stringof~" base ", radix,
  64             " to type "~T.stringof),
  65        fn, ln);
  66}
  67
  68@safe pure/* nothrow*/  // lazy parameter bug
  69private auto parseError(lazy string msg, string fn = __FILE__, size_t ln = __LINE__)
  70{
  71    return new ConvException(text("Can't parse string: ", msg), fn, ln);
  72}
  73
  74private void parseCheck(alias source)(dchar c, string fn = __FILE__, size_t ln = __LINE__)
  75{
  76    if (source.empty)
  77        throw parseError(text("unexpected end of input when expecting", "\"", c, "\""));
  78    if (source.front != c)
  79        throw parseError(text("\"", c, "\" is missing"), fn, ln);
  80    source.popFront();
  81}
  82
  83private
  84{
  85    template isImaginary(T)
  86    {
  87        enum bool isImaginary = staticIndexOf!(Unqual!T,
  88                ifloat, idouble, ireal) >= 0;
  89    }
  90    template isComplex(T)
  91    {
  92        enum bool isComplex = staticIndexOf!(Unqual!T,
  93                cfloat, cdouble, creal) >= 0;
  94    }
  95    template isNarrowInteger(T)
  96    {
  97        enum bool isNarrowInteger = staticIndexOf!(Unqual!T,
  98                byte, ubyte, short, ushort) >= 0;
  99    }
 100
 101    T toStr(T, S)(S src)
 102        if (isSomeString!T)
 103    {
 104        import std.format : FormatSpec, formatValue;
 105
 106        auto w = appender!T();
 107        FormatSpec!(ElementEncodingType!T) f;
 108        formatValue(w, src, f);
 109        return w.data;
 110    }
 111
 112    template isExactSomeString(T)
 113    {
 114        enum isExactSomeString = isSomeString!T && !is(T == enum);
 115    }
 116
 117    template isEnumStrToStr(S, T)
 118    {
 119        enum isEnumStrToStr = isImplicitlyConvertible!(S, T) &&
 120                              is(S == enum) && isExactSomeString!T;
 121    }
 122    template isNullToStr(S, T)
 123    {
 124        enum isNullToStr = isImplicitlyConvertible!(S, T) &&
 125                           (is(Unqual!S == typeof(null))) && isExactSomeString!T;
 126    }
 127
 128    template isRawStaticArray(T, A...)
 129    {
 130        enum isRawStaticArray =
 131            A.length == 0 &&
 132            isStaticArray!T &&
 133            !is(T == class) &&
 134            !is(T == interface) &&
 135            !is(T == struct) &&
 136            !is(T == union);
 137    }
 138}
 139
 140/**
 141 * Thrown on conversion overflow errors.
 142 */
 143class ConvOverflowException : ConvException
 144{
 145    @safe pure nothrow
 146    this(string s, string fn = __FILE__, size_t ln = __LINE__)
 147    {
 148        super(s, fn, ln);
 149    }
 150}
 151
 152/**
 153
 154The $(D_PARAM to) family of functions converts a value from type
 155$(D_PARAM Source) to type $(D_PARAM Target). The source type is
 156deduced and the target type must be specified, for example the
 157expression $(D_PARAM to!int(42.0)) converts the number 42 from
 158$(D_PARAM double) to $(D_PARAM int). The conversion is "safe", i.e.,
 159it checks for overflow; $(D_PARAM to!int(4.2e10)) would throw the
 160$(D_PARAM ConvOverflowException) exception. Overflow checks are only
 161inserted when necessary, e.g., $(D_PARAM to!double(42)) does not do
 162any checking because any int fits in a double.
 163
 164Converting a value to its own type (useful mostly for generic code)
 165simply returns its argument.
 166
 167Example:
 168-------------------------
 169int a = 42;
 170auto b = to!int(a); // b is int with value 42
 171auto c = to!double(3.14); // c is double with value 3.14
 172-------------------------
 173
 174Converting among numeric types is a safe way to cast them around.
 175
 176Conversions from floating-point types to integral types allow loss of
 177precision (the fractional part of a floating-point number). The
 178conversion is truncating towards zero, the same way a cast would
 179truncate. (To round a floating point value when casting to an
 180integral, use $(D_PARAM roundTo).)
 181
 182Examples:
 183-------------------------
 184int a = 420;
 185auto b = to!long(a); // same as long b = a;
 186auto c = to!byte(a / 10); // fine, c = 42
 187auto d = to!byte(a); // throw ConvOverflowException
 188double e = 4.2e6;
 189auto f = to!int(e); // f == 4200000
 190e = -3.14;
 191auto g = to!uint(e); // fails: floating-to-integral negative overflow
 192e = 3.14;
 193auto h = to!uint(e); // h = 3
 194e = 3.99;
 195h = to!uint(a); // h = 3
 196e = -3.99;
 197f = to!int(a); // f = -3
 198-------------------------
 199
 200Conversions from integral types to floating-point types always
 201succeed, but might lose accuracy. The largest integers with a
 202predecessor representable in floating-point format are 2^24-1 for
 203float, 2^53-1 for double, and 2^64-1 for $(D_PARAM real) (when
 204$(D_PARAM real) is 80-bit, e.g. on Intel machines).
 205
 206Example:
 207-------------------------
 208int a = 16_777_215; // 2^24 - 1, largest proper integer representable as float
 209assert(to!int(to!float(a)) == a);
 210assert(to!int(to!float(-a)) == -a);
 211a += 2;
 212assert(to!int(to!float(a)) == a); // fails!
 213-------------------------
 214
 215Conversions from string to numeric types differ from the C equivalents
 216$(D_PARAM atoi()) and $(D_PARAM atol()) by checking for overflow and
 217not allowing whitespace.
 218
 219For conversion of strings to signed types, the grammar recognized is:
 220<pre>
 221$(I Integer): $(I Sign UnsignedInteger)
 222$(I UnsignedInteger)
 223$(I Sign):
 224    $(B +)
 225    $(B -)
 226</pre>
 227
 228For conversion to unsigned types, the grammar recognized is:
 229<pre>
 230$(I UnsignedInteger):
 231    $(I DecimalDigit)
 232    $(I DecimalDigit) $(I UnsignedInteger)
 233</pre>
 234
 235Converting an array to another array type works by converting each
 236element in turn. Associative arrays can be converted to associative
 237arrays as long as keys and values can in turn be converted.
 238
 239Example:
 240-------------------------
 241int[] a = ([1, 2, 3]).dup;
 242auto b = to!(float[])(a);
 243assert(b == [1.0f, 2, 3]);
 244string str = "1 2 3 4 5 6";
 245auto numbers = to!(double[])(split(str));
 246assert(numbers == [1.0, 2, 3, 4, 5, 6]);
 247int[string] c;
 248c["a"] = 1;
 249c["b"] = 2;
 250auto d = to!(double[wstring])(c);
 251assert(d["a"w] == 1 && d["b"w] == 2);
 252-------------------------
 253
 254Conversions operate transitively, meaning that they work on arrays and
 255associative arrays of any complexity:
 256
 257-------------------------
 258int[string][double[int[]]] a;
 259...
 260auto b = to!(short[wstring][string[double[]]])(a);
 261-------------------------
 262
 263This conversion works because $(D_PARAM to!short) applies to an
 264$(D_PARAM int), $(D_PARAM to!wstring) applies to a $(D_PARAM
 265string), $(D_PARAM to!string) applies to a $(D_PARAM double), and
 266$(D_PARAM to!(double[])) applies to an $(D_PARAM int[]). The
 267conversion might throw an exception because $(D_PARAM to!short)
 268might fail the range check.
 269
 270 */
 271
 272/**
 273   Entry point that dispatches to the appropriate conversion
 274   primitive. Client code normally calls $(D _to!TargetType(value))
 275   (and not some variant of $(D toImpl)).
 276 */
 277template to(T)
 278{
 279    T to(A...)(A args)
 280        if (!isRawStaticArray!A)
 281    {
 282        return toImpl!T(args);
 283    }
 284
 285    // Fix issue 6175
 286    T to(S)(ref S arg)
 287        if (isRawStaticArray!S)
 288    {
 289        return toImpl!T(arg);
 290    }
 291}
 292
 293// Tests for issue 6175
 294@safe pure unittest
 295{
 296    char[9] sarr = "blablabla";
 297    auto darr = to!(char[])(sarr);
 298    assert(sarr.ptr == darr.ptr);
 299    assert(sarr.length == darr.length);
 300}
 301
 302// Tests for issue 7348
 303@safe pure unittest
 304{
 305    assert(to!string(null) == "null");
 306    assert(text(null) == "null");
 307}
 308
 309// Tests for issue 11390
 310@safe pure unittest
 311{
 312    const(typeof(null)) ctn;
 313    immutable(typeof(null)) itn;
 314    assert(to!string(ctn) == "null");
 315    assert(to!string(itn) == "null");
 316}
 317
 318// Tests for issue 8729: do NOT skip leading WS
 319@safe pure unittest
 320{
 321    foreach (T; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong))
 322    {
 323        assertThrown!ConvException(to!T(" 0"));
 324        assertThrown!ConvException(to!T(" 0", 8));
 325    }
 326    foreach (T; TypeTuple!(float, double, real))
 327    {
 328        assertThrown!ConvException(to!T(" 0"));
 329    }
 330
 331    assertThrown!ConvException(to!bool(" true"));
 332
 333    alias NullType = typeof(null);
 334    assertThrown!ConvException(to!NullType(" null"));
 335
 336    alias ARR = int[];
 337    assertThrown!ConvException(to!ARR(" [1]"));
 338
 339    alias AA = int[int];
 340    assertThrown!ConvException(to!AA(" [1:1]"));
 341}
 342
 343/**
 344If the source type is implicitly convertible to the target type, $(D
 345to) simply performs the implicit conversion.
 346 */
 347T toImpl(T, S)(S value)
 348    if (isImplicitlyConvertible!(S, T) &&
 349        !isEnumStrToStr!(S, T) && !isNullToStr!(S, T))
 350{
 351    template isSignedInt(T)
 352    {
 353        enum isSignedInt = isIntegral!T && isSigned!T;
 354    }
 355    alias isUnsignedInt = isUnsigned;
 356
 357    // Conversion from integer to integer, and changing its sign
 358    static if (isUnsignedInt!S && isSignedInt!T && S.sizeof == T.sizeof)
 359    {   // unsigned to signed & same size
 360        enforce(value <= cast(S)T.max,
 361                new ConvOverflowException("Conversion positive overflow"));
 362    }
 363    else static if (isSignedInt!S && isUnsignedInt!T)
 364    {   // signed to unsigned
 365        enforce(0 <= value,
 366                new ConvOverflowException("Conversion negative overflow"));
 367    }
 368
 369    return value;
 370}
 371
 372@safe pure unittest
 373{
 374    enum E { a }  // Issue 9523 - Allow identity enum conversion
 375    auto e = to!E(E.a);
 376    assert(e == E.a);
 377}
 378
 379@safe pure unittest
 380{
 381    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 382    int a = 42;
 383    auto b = to!long(a);
 384    assert(a == b);
 385}
 386
 387// Tests for issue 6377
 388@safe pure unittest
 389{
 390    // Conversion between same size
 391    foreach (S; TypeTuple!(byte, short, int, long))
 392    {
 393        alias Unsigned!S U;
 394
 395        foreach (Sint; TypeTuple!(S, const S, immutable S))
 396        foreach (Uint; TypeTuple!(U, const U, immutable U))
 397        {
 398            // positive overflow
 399            Uint un = Uint.max;
 400            assertThrown!ConvOverflowException(to!Sint(un),
 401                text(Sint.stringof, ' ', Uint.stringof, ' ', un));
 402
 403            // negative overflow
 404            Sint sn = -1;
 405            assertThrown!ConvOverflowException(to!Uint(sn),
 406                text(Sint.stringof, ' ', Uint.stringof, ' ', un));
 407        }
 408    }
 409
 410    // Conversion between different size
 411    foreach (i, S1; TypeTuple!(byte, short, int, long))
 412    foreach (   S2; TypeTuple!(byte, short, int, long)[i+1..$])
 413    {
 414        alias Unsigned!S1 U1;
 415        alias Unsigned!S2 U2;
 416
 417        static assert(U1.sizeof < S2.sizeof);
 418
 419        // small unsigned to big signed
 420        foreach (Uint; TypeTuple!(U1, const U1, immutable U1))
 421        foreach (Sint; TypeTuple!(S2, const S2, immutable S2))
 422        {
 423            Uint un = Uint.max;
 424            assertNotThrown(to!Sint(un));
 425            assert(to!Sint(un) == un);
 426        }
 427
 428        // big unsigned to small signed
 429        foreach (Uint; TypeTuple!(U2, const U2, immutable U2))
 430        foreach (Sint; TypeTuple!(S1, const S1, immutable S1))
 431        {
 432            Uint un = Uint.max;
 433            assertThrown(to!Sint(un));
 434        }
 435
 436        static assert(S1.sizeof < U2.sizeof);
 437
 438        // small signed to big unsigned
 439        foreach (Sint; TypeTuple!(S1, const S1, immutable S1))
 440        foreach (Uint; TypeTuple!(U2, const U2, immutable U2))
 441        {
 442            Sint sn = -1;
 443            assertThrown!ConvOverflowException(to!Uint(sn));
 444        }
 445
 446        // big signed to small unsigned
 447        foreach (Sint; TypeTuple!(S2, const S2, immutable S2))
 448        foreach (Uint; TypeTuple!(U1, const U1, immutable U1))
 449        {
 450            Sint sn = -1;
 451            assertThrown!ConvOverflowException(to!Uint(sn));
 452        }
 453    }
 454}
 455
 456/*
 457  Converting static arrays forwards to their dynamic counterparts.
 458 */
 459T toImpl(T, S)(ref S s)
 460    if (isRawStaticArray!S)
 461{
 462    return toImpl!(T, typeof(s[0])[])(s);
 463}
 464
 465@safe pure unittest
 466{
 467    char[4] test = ['a', 'b', 'c', 'd'];
 468    static assert(!isInputRange!(Unqual!(char[4])));
 469    assert(to!string(test) == test);
 470}
 471
 472/**
 473When source type supports member template function opCast, is is used.
 474*/
 475T toImpl(T, S)(S value)
 476    if (!isImplicitlyConvertible!(S, T) &&
 477        is(typeof(S.init.opCast!T()) : T) &&
 478        !isExactSomeString!T)
 479{
 480    return value.opCast!T();
 481}
 482
 483@safe pure unittest
 484{
 485    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 486    class B
 487    {
 488        T opCast(T)() { return 43; }
 489    }
 490    auto b = new B;
 491    assert(to!int(b) == 43);
 492
 493    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 494    struct S
 495    {
 496        T opCast(T)() { return 43; }
 497    }
 498    auto s = S();
 499    assert(to!int(s) == 43);
 500}
 501
 502/**
 503When target type supports 'converting construction', it is used.
 504$(UL $(LI If target type is struct, $(D T(value)) is used.)
 505     $(LI If target type is class, $(D new T(value)) is used.))
 506*/
 507T toImpl(T, S)(S value)
 508    if (!isImplicitlyConvertible!(S, T) &&
 509        is(T == struct) && is(typeof(T(value))))
 510{
 511    return T(value);
 512}
 513
 514// Bugzilla 3961
 515@safe pure unittest
 516{
 517    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 518    struct Int
 519    {
 520        int x;
 521    }
 522    Int i = to!Int(1);
 523
 524    static struct Int2
 525    {
 526        int x;
 527        this(int x) @safe pure { this.x = x; }
 528    }
 529    Int2 i2 = to!Int2(1);
 530
 531    static struct Int3
 532    {
 533        int x;
 534        static Int3 opCall(int x) @safe pure
 535        {
 536            Int3 i;
 537            i.x = x;
 538            return i;
 539        }
 540    }
 541    Int3 i3 = to!Int3(1);
 542}
 543
 544// Bugzilla 6808
 545@safe pure unittest
 546{
 547    static struct FakeBigInt
 548    {
 549        this(string s) @safe pure {}
 550    }
 551
 552    string s = "101";
 553    auto i3 = to!FakeBigInt(s);
 554}
 555
 556/// ditto
 557T toImpl(T, S)(S value)
 558    if (!isImplicitlyConvertible!(S, T) &&
 559        is(T == class) && is(typeof(new T(value))))
 560{
 561    return new T(value);
 562}
 563
 564@safe pure unittest
 565{
 566    static struct S
 567    {
 568        int x;
 569    }
 570    static class C
 571    {
 572        int x;
 573        this(int x) @safe pure { this.x = x; }
 574    }
 575
 576    static class B
 577    {
 578        int value;
 579        this(S src) @safe pure { value = src.x; }
 580        this(C src) @safe pure { value = src.x; }
 581    }
 582
 583    S s = S(1);
 584    auto b1 = to!B(s);  // == new B(s)
 585    assert(b1.value == 1);
 586
 587    C c = new C(2);
 588    auto b2 = to!B(c);  // == new B(c)
 589    assert(b2.value == 2);
 590
 591    auto c2 = to!C(3);   // == new C(3)
 592    assert(c2.x == 3);
 593}
 594
 595@safe pure unittest
 596{
 597    struct S
 598    {
 599        class A
 600        {
 601            this(B b) @safe pure {}
 602        }
 603        class B : A
 604        {
 605            this() @safe pure { super(this); }
 606        }
 607    }
 608
 609    S.B b = new S.B();
 610    S.A a = to!(S.A)(b);      // == cast(S.A)b
 611                              // (do not run construction conversion like new S.A(b))
 612    assert(b is a);
 613
 614    static class C : Object
 615    {
 616        this() @safe pure {}
 617        this(Object o) @safe pure {}
 618    }
 619
 620    Object oc = new C();
 621    C a2 = to!C(oc);    // == new C(a)
 622                        // Construction conversion overrides down-casting conversion
 623    assert(a2 !is a);   //
 624}
 625
 626/**
 627Object-to-object conversions by dynamic casting throw exception when the source is
 628non-null and the target is null.
 629 */
 630T toImpl(T, S)(S value)
 631    if (!isImplicitlyConvertible!(S, T) &&
 632        (is(S == class) || is(S == interface)) && !is(typeof(value.opCast!T()) : T) &&
 633        (is(T == class) || is(T == interface)) && !is(typeof(new T(value))))
 634{
 635    static if (is(T == immutable))
 636    {
 637            // immutable <- immutable
 638            enum isModConvertible = is(S == immutable);
 639    }
 640    else static if (is(T == const))
 641    {
 642        static if (is(T == shared))
 643        {
 644            // shared const <- shared
 645            // shared const <- shared const
 646            // shared const <- immutable
 647            enum isModConvertible = is(S == shared) || is(S == immutable);
 648        }
 649        else
 650        {
 651            // const <- mutable
 652            // const <- immutable
 653            enum isModConvertible = !is(S == shared);
 654        }
 655    }
 656    else
 657    {
 658        static if (is(T == shared))
 659        {
 660            // shared <- shared mutable
 661            enum isModConvertible = is(S == shared) && !is(S == const);
 662        }
 663        else
 664        {
 665            // (mutable) <- (mutable)
 666            enum isModConvertible = is(Unqual!S == S);
 667        }
 668    }
 669    static assert(isModConvertible, "Bad modifier conversion: "~S.stringof~" to "~T.stringof);
 670
 671    auto result = ()@trusted{ return cast(T) value; }();
 672    if (!result && value)
 673    {
 674        throw new ConvException("Cannot convert object of static type "
 675                ~S.classinfo.name~" and dynamic type "~value.classinfo.name
 676                ~" to type "~T.classinfo.name);
 677    }
 678    return result;
 679}
 680
 681@safe pure unittest
 682{
 683    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 684    // Testing object conversions
 685    class A {}
 686    class B : A {}
 687    class C : A {}
 688    A a1 = new A, a2 = new B, a3 = new C;
 689    assert(to!B(a2) is a2);
 690    assert(to!C(a3) is a3);
 691    assertThrown!ConvException(to!B(a3));
 692}
 693
 694// Unittest for 6288
 695@safe pure unittest
 696{
 697    template Identity(T)        { alias              T   Identity; }
 698    template toConst(T)         { alias        const(T)  toConst; }
 699    template toShared(T)        { alias       shared(T)  toShared; }
 700    template toSharedConst(T)   { alias shared(const(T)) toSharedConst; }
 701    template toImmutable(T)     { alias    immutable(T)  toImmutable; }
 702    template AddModifier(int n) if (0 <= n && n < 5)
 703    {
 704             static if (n == 0) alias Identity       AddModifier;
 705        else static if (n == 1) alias toConst        AddModifier;
 706        else static if (n == 2) alias toShared       AddModifier;
 707        else static if (n == 3) alias toSharedConst  AddModifier;
 708        else static if (n == 4) alias toImmutable    AddModifier;
 709    }
 710
 711    interface I {}
 712    interface J {}
 713
 714    class A {}
 715    class B : A {}
 716    class C : B, I, J {}
 717    class D : I {}
 718
 719    foreach (m1; TypeTuple!(0,1,2,3,4)) // enumerate modifiers
 720    foreach (m2; TypeTuple!(0,1,2,3,4)) // ditto
 721    {
 722        alias AddModifier!m1 srcmod;
 723        alias AddModifier!m2 tgtmod;
 724        //pragma(msg, srcmod!Object, " -> ", tgtmod!Object, ", convertible = ",
 725        //            isImplicitlyConvertible!(srcmod!Object, tgtmod!Object));
 726
 727        // Compile time convertible equals to modifier convertible.
 728        static if (isImplicitlyConvertible!(srcmod!Object, tgtmod!Object))
 729        {
 730            // Test runtime conversions: class to class, class to interface,
 731            // interface to class, and interface to interface
 732
 733            // Check that the runtime conversion to succeed
 734            srcmod!A ac = new srcmod!C();
 735            srcmod!I ic = new srcmod!C();
 736            assert(to!(tgtmod!C)(ac) !is null); // A(c) to C
 737            assert(to!(tgtmod!I)(ac) !is null); // A(c) to I
 738            assert(to!(tgtmod!C)(ic) !is null); // I(c) to C
 739            assert(to!(tgtmod!J)(ic) !is null); // I(c) to J
 740
 741            // Check that the runtime conversion fails
 742            srcmod!A ab = new srcmod!B();
 743            srcmod!I id = new srcmod!D();
 744            assertThrown(to!(tgtmod!C)(ab));    // A(b) to C
 745            assertThrown(to!(tgtmod!I)(ab));    // A(b) to I
 746            assertThrown(to!(tgtmod!C)(id));    // I(d) to C
 747            assertThrown(to!(tgtmod!J)(id));    // I(d) to J
 748        }
 749        else
 750        {
 751            // Check that the conversion is rejected statically
 752            static assert(!is(typeof(to!(tgtmod!C)(srcmod!A.init))));   // A to C
 753            static assert(!is(typeof(to!(tgtmod!I)(srcmod!A.init))));   // A to I
 754            static assert(!is(typeof(to!(tgtmod!C)(srcmod!I.init))));   // I to C
 755            static assert(!is(typeof(to!(tgtmod!J)(srcmod!I.init))));   // I to J
 756        }
 757    }
 758}
 759
 760/**
 761Stringize conversion from all types is supported.
 762$(UL
 763  $(LI String _to string conversion works for any two string types having
 764       ($(D char), $(D wchar), $(D dchar)) character widths and any
 765       combination of qualifiers (mutable, $(D const), or $(D immutable)).)
 766  $(LI Converts array (other than strings) to string.
 767       Each element is converted by calling $(D to!T).)
 768  $(LI Associative array to string conversion.
 769       Each element is printed by calling $(D to!T).)
 770  $(LI Object to string conversion calls $(D toString) against the object or
 771       returns $(D "null") if the object is null.)
 772  $(LI Struct to string conversion calls $(D toString) against the struct if
 773       it is defined.)
 774  $(LI For structs that do not define $(D toString), the conversion to string
 775       produces the list of fields.)
 776  $(LI Enumerated types are converted to strings as their symbolic names.)
 777  $(LI Boolean values are printed as $(D "true") or $(D "false").)
 778  $(LI $(D char), $(D wchar), $(D dchar) to a string type.)
 779  $(LI Unsigned or signed integers to strings.
 780       $(DL $(DT [special case])
 781            $(DD Convert integral value to string in $(D_PARAM radix) radix.
 782            radix must be a value from 2 to 36.
 783            value is treated as a signed value only if radix is 10.
 784            The characters A through Z are used to represent values 10 through 36
 785            and their case is determined by the $(D_PARAM letterCase) parameter.)))
 786  $(LI All floating point types to all string types.)
 787  $(LI Pointer to string conversions prints the pointer as a $(D size_t) value.
 788       If pointer is $(D char*), treat it as C-style strings.
 789       In that case, this function is $(D @system).))
 790*/
 791T toImpl(T, S)(S value)
 792    if (!(isImplicitlyConvertible!(S, T) &&
 793          !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
 794        isExactSomeString!T)
 795{
 796    static if (isExactSomeString!S && value[0].sizeof == ElementEncodingType!T.sizeof)
 797    {
 798        // string-to-string with incompatible qualifier conversion
 799        static if (is(ElementEncodingType!T == immutable))
 800        {
 801            // conversion (mutable|const) -> immutable
 802            return value.idup;
 803        }
 804        else
 805        {
 806            // conversion (immutable|const) -> mutable
 807            return value.dup;
 808        }
 809    }
 810    else static if (isExactSomeString!S)
 811    {
 812        // other string-to-string
 813        //Use Appender directly instead of toStr, which also uses a formatedWrite
 814        auto w = appender!T();
 815        w.put(value);
 816        return w.data;
 817    }
 818    else static if (isIntegral!S && !is(S == enum))
 819    {
 820        // other integral-to-string conversions with default radix
 821        return toImpl!(T, S)(value, 10);
 822    }
 823    else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[]))
 824    {
 825        // Converting void array to string
 826        alias Unqual!(ElementEncodingType!T) Char;
 827        auto raw = cast(const(ubyte)[]) value;
 828        enforce(raw.length % Char.sizeof == 0,
 829                new ConvException("Alignment mismatch in converting a "
 830                        ~ S.stringof ~ " to a "
 831                        ~ T.stringof));
 832        auto result = new Char[raw.length / Char.sizeof];
 833        ()@trusted{ memcpy(result.ptr, value.ptr, value.length); }();
 834        return cast(T) result;
 835    }
 836    else static if (isPointer!S && is(S : const(char)*))
 837    {
 838        // It is unsafe because we cannot guarantee that the pointer is null terminated.
 839        return value ? cast(T) value[0 .. strlen(value)].dup : cast(string)null;
 840    }
 841    else static if (isSomeString!T && is(S == enum))
 842    {
 843        static if (isSwitchable!(OriginalType!S) && EnumMembers!S.length <= 50)
 844        {
 845            switch(value)
 846            {
 847                foreach (I, member; NoDuplicates!(EnumMembers!S))
 848                {
 849                    case member:
 850                        return to!T(enumRep!(immutable(T), S, I));
 851                }
 852                default:
 853            }
 854        }
 855        else
 856        {
 857            foreach (I, member; EnumMembers!S)
 858            {
 859                if (value == member)
 860                    return to!T(enumRep!(immutable(T), S, I));
 861            }
 862        }
 863
 864        import std.format : FormatSpec, formatValue;
 865
 866        //Default case, delegate to format
 867        //Note: we don't call toStr directly, to avoid duplicate work.
 868        auto app = appender!T();
 869        app.put("cast(");
 870        app.put(S.stringof);
 871        app.put(')');
 872        FormatSpec!char f;
 873        formatValue(app, cast(OriginalType!S)value, f);
 874        return app.data;
 875    }
 876    else
 877    {
 878        // other non-string values runs formatting
 879        return toStr!T(value);
 880    }
 881}
 882
 883/*
 884    Check whether type $(D T) can be used in a switch statement.
 885    This is useful for compile-time generation of switch case statements.
 886*/
 887private template isSwitchable(E)
 888{
 889    enum bool isSwitchable = is(typeof({
 890        switch (E.init) { default: }
 891    }));
 892}
 893
 894//
 895unittest
 896{
 897    static assert(isSwitchable!int);
 898    static assert(!isSwitchable!double);
 899    static assert(!isSwitchable!real);
 900}
 901
 902//Static representation of the index I of the enum S,
 903//In representation T.
 904//T must be an immutable string (avoids un-necessary initializations).
 905private template enumRep(T, S, size_t I)
 906if (is (T == immutable) && isExactSomeString!T && is(S == enum))
 907{
 908    static T enumRep = to!T(__traits(allMembers, S)[I]);
 909}
 910
 911@safe pure unittest
 912{
 913    void dg()
 914    {
 915        // string to string conversion
 916        debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 917
 918        alias TypeTuple!(char, wchar, dchar) Chars;
 919        foreach (LhsC; Chars)
 920        {
 921            alias TypeTuple!(LhsC[], const(LhsC)[], immutable(LhsC)[]) LhStrings;
 922            foreach (Lhs; LhStrings)
 923            {
 924                foreach (RhsC; Chars)
 925                {
 926                    alias TypeTuple!(RhsC[], const(RhsC)[], immutable(RhsC)[])
 927                        RhStrings;
 928                    foreach (Rhs; RhStrings)
 929                    {
 930                        Lhs s1 = to!Lhs("wyda");
 931                        Rhs s2 = to!Rhs(s1);
 932                        //writeln(Lhs.stringof, " -> ", Rhs.stringof);
 933                        assert(s1 == to!Lhs(s2));
 934                    }
 935                }
 936            }
 937        }
 938
 939        foreach (T; Chars)
 940        {
 941            foreach (U; Chars)
 942            {
 943                T[] s1 = to!(T[])("Hello, world!");
 944                auto s2 = to!(U[])(s1);
 945                assert(s1 == to!(T[])(s2));
 946                auto s3 = to!(const(U)[])(s1);
 947                assert(s1 == to!(T[])(s3));
 948                auto s4 = to!(immutable(U)[])(s1);
 949                assert(s1 == to!(T[])(s4));
 950            }
 951        }
 952    }
 953    dg();
 954    assertCTFEable!dg;
 955}
 956
 957@safe pure unittest
 958{
 959    // Conversion reinterpreting void array to string
 960    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 961
 962    auto a = "abcx"w;
 963    const(void)[] b = a;
 964    assert(b.length == 8);
 965
 966    auto c = to!(wchar[])(b);
 967    assert(c == "abcx");
 968}
 969
 970@system pure unittest
 971{
 972    // char* to string conversion
 973    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 974    debug(conv) printf("string.to!string(char*).unittest\n");
 975
 976    assert(to!string(cast(char*) null) == "");
 977    assert(to!string("foo\0".ptr) == "foo");
 978}
 979
 980@safe pure unittest
 981{
 982    // Conversion representing bool value with string
 983    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 984
 985    bool b;
 986    assert(to!string(b) == "false");
 987    b = true;
 988    assert(to!string(b) == "true");
 989}
 990
 991@safe pure unittest
 992{
 993    // Conversion representing character value with string
 994    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
 995
 996    alias TypeTuple!(
 997         char, const( char), immutable( char),
 998        wchar, const(wchar), immutable(wchar),
 999        dchar, const(dchar), immutable(dchar)) AllChars;
1000    foreach (Char1; AllChars)
1001    {
1002        foreach (Char2; AllChars)
1003        {
1004            Char1 c = 'a';
1005            assert(to!(Char2[])(c)[0] == c);
1006        }
1007        uint x = 4;
1008        assert(to!(Char1[])(x) == "4");
1009    }
1010
1011    string s = "foo";
1012    string s2;
1013    foreach (char c; s)
1014    {
1015        s2 ~= to!string(c);
1016    }
1017    //printf("%.*s", s2);
1018    assert(s2 == "foo");
1019}
1020
1021@safe pure unittest
1022{
1023    // Conversion representing integer values with string
1024
1025    foreach (Int; TypeTuple!(ubyte, ushort, uint, ulong))
1026    {
1027        debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1028        debug(conv) printf("string.to!string(%.*s).unittest\n", Int.stringof.length, Int.stringof.ptr);
1029
1030        assert(to!string(to!Int(0)) == "0");
1031        assert(to!string(to!Int(9)) == "9");
1032        assert(to!string(to!Int(123)) == "123");
1033    }
1034
1035    foreach (Int; TypeTuple!(byte, short, int, long))
1036    {
1037        debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1038        debug(conv) printf("string.to!string(%.*s).unittest\n", Int.stringof.length, Int.stringof.ptr);
1039
1040        assert(to!string(to!Int(0)) == "0");
1041        assert(to!string(to!Int(9)) == "9");
1042        assert(to!string(to!Int(123)) == "123");
1043        assert(to!string(to!Int(-0)) == "0");
1044        assert(to!string(to!Int(-9)) == "-9");
1045        assert(to!string(to!Int(-123)) == "-123");
1046        assert(to!string(to!(const Int)(6)) == "6");
1047    }
1048
1049    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1050    assert(wtext(int.max) == "2147483647"w);
1051    assert(wtext(int.min) == "-2147483648"w);
1052    assert(to!string(0L) == "0");
1053
1054    assertCTFEable!(
1055    {
1056        assert(to!string(1uL << 62) == "4611686018427387904");
1057        assert(to!string(0x100000000) == "4294967296");
1058        assert(to!string(-138L) == "-138");
1059    });
1060}
1061
1062@safe pure unittest
1063{
1064    // Conversion representing dynamic/static array with string
1065    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1066
1067    long[] b = [ 1, 3, 5 ];
1068    auto s = to!string(b);
1069    assert(to!string(b) == "[1, 3, 5]", s);
1070}
1071/*@safe pure */unittest // sprintf issue
1072{
1073    double[2] a = [ 1.5, 2.5 ];
1074    assert(to!string(a) == "[1.5, 2.5]");
1075}
1076
1077/*@safe pure */unittest
1078{
1079    // Conversion representing associative array with string
1080    int[string] a = ["0":1, "1":2];
1081    assert(to!string(a) == `["0":1, "1":2]`);
1082}
1083
1084unittest
1085{
1086    // Conversion representing class object with string
1087    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1088
1089    class A
1090    {
1091        override string toString() const { return "an A"; }
1092    }
1093    A a;
1094    assert(to!string(a) == "null");
1095    a = new A;
1096    assert(to!string(a) == "an A");
1097
1098    // Bug 7660
1099    class C { override string toString() const { return "C"; } }
1100    struct S { C c; alias c this; }
1101    S s; s.c = new C();
1102    assert(to!string(s) == "C");
1103}
1104
1105unittest
1106{
1107    // Conversion representing struct object with string
1108    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1109
1110    struct S1
1111    {
1112        string toString() { return "wyda"; }
1113    }
1114    assert(to!string(S1()) == "wyda");
1115
1116    struct S2
1117    {
1118        int a = 42;
1119        float b = 43.5;
1120    }
1121    S2 s2;
1122    assert(to!string(s2) == "S2(42, 43.5)");
1123
1124    // Test for issue 8080
1125    struct S8080
1126    {
1127        short[4] data;
1128        alias data this;
1129        string toString() { return "<S>"; }
1130    }
1131    S8080 s8080;
1132    assert(to!string(s8080) == "<S>");
1133}
1134
1135unittest
1136{
1137    // Conversion representing enum value with string
1138    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1139
1140    enum EB : bool { a = true }
1141    enum EU : uint { a = 0, b = 1, c = 2 }  // base type is unsigned
1142    enum EI : int { a = -1, b = 0, c = 1 }  // base type is signed (bug 7909)
1143    enum EF : real { a = 1.414, b = 1.732, c = 2.236 }
1144    enum EC : char { a = 'x', b = 'y' }
1145    enum ES : string { a = "aaa", b = "bbb" }
1146
1147    foreach (E; TypeTuple!(EB, EU, EI, EF, EC, ES))
1148    {
1149        assert(to! string(E.a) == "a"c);
1150        assert(to!wstring(E.a) == "a"w);
1151        assert(to!dstring(E.a) == "a"d);
1152    }
1153
1154    // Test an value not corresponding to an enum member.
1155    auto o = cast(EU)5;
1156    assert(to! string(o) == "cast(EU)5"c);
1157    assert(to!wstring(o) == "cast(EU)5"w);
1158    assert(to!dstring(o) == "cast(EU)5"d);
1159}
1160
1161unittest
1162{
1163    enum E
1164    {
1165        foo,
1166        bar,
1167        doo = foo, // check duplicate switch statements
1168    }
1169
1170    foreach (S; TypeTuple!(string, wstring, dstring, const(char[]), const(wchar[]), const(dchar[])))
1171    {
1172        auto s1 = to!S(E.foo);
1173        auto s2 = to!S(E.foo);
1174        assert(s1 == s2);
1175        // ensure we don't allocate when it's unnecessary
1176        assert(s1 is s2);
1177    }
1178
1179    foreach (S; TypeTuple!(char[], wchar[], dchar[]))
1180    {
1181        auto s1 = to!S(E.foo);
1182        auto s2 = to!S(E.foo);
1183        assert(s1 == s2);
1184        // ensure each mutable array is unique
1185        assert(s1 !is s2);
1186    }
1187}
1188
1189/// ditto
1190@trusted pure T toImpl(T, S)(S value, uint radix, LetterCase letterCase = LetterCase.upper)
1191    if (isIntegral!S &&
1192        isExactSomeString!T)
1193in
1194{
1195    assert(radix >= 2 && radix <= 36);
1196}
1197body
1198{
1199    alias EEType = Unqual!(ElementEncodingType!T);
1200
1201    T toStringRadixConvert(size_t bufLen, uint radix = 0, bool neg = false)(uint runtimeRadix = 0)
1202    {
1203        static if (neg)
1204            ulong div = void, mValue = unsigned(-value);
1205        else
1206            Unsigned!(Unqual!S) div = void, mValue = unsigned(value);
1207
1208        size_t index = bufLen;
1209        EEType[bufLen] buffer = void;
1210        char baseChar = letterCase == LetterCase.lower ? 'a' : 'A';
1211        char mod = void;
1212
1213        do
1214        {
1215            static if (radix == 0)
1216            {
1217                div = cast(S)(mValue / runtimeRadix );
1218                mod = cast(ubyte)(mValue % runtimeRadix);
1219                mod += mod < 10 ? '0' : baseChar - 10;
1220            }
1221            else static if (radix > 10)
1222            {
1223                div = cast(S)(mValue / radix );
1224                mod = cast(ubyte)(mValue % radix);
1225                mod += mod < 10 ? '0' : baseChar - 10;
1226            }
1227            else
1228            {
1229                div = cast(S)(mValue / radix);
1230                mod = mValue % radix + '0';
1231            }
1232            buffer[--index] = cast(char)mod;
1233            mValue = div;
1234        } while (mValue);
1235
1236        static if (neg)
1237        {
1238            buffer[--index] = '-';
1239        }
1240        return cast(T)buffer[index .. $].dup;
1241    }
1242
1243    enforce(radix >= 2 && radix <= 36, new ConvException("Radix error"));
1244
1245    switch(radix)
1246    {
1247        case 10:
1248            if (value < 0)
1249                return toStringRadixConvert!(S.sizeof * 3 + 1, 10, true)();
1250            else
1251                return toStringRadixConvert!(S.sizeof * 3, 10)();
1252        case 16:
1253            return toStringRadixConvert!(S.sizeof * 2, 16)();
1254        case 2:
1255            return toStringRadixConvert!(S.sizeof * 8, 2)();
1256        case 8:
1257            return toStringRadixConvert!(S.sizeof * 3, 8)();
1258        default:
1259           return toStringRadixConvert!(S.sizeof * 6)(radix);
1260    }
1261}
1262
1263@safe pure unittest
1264{
1265    foreach (Int; TypeTuple!(uint, ulong))
1266    {
1267        debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1268        debug(conv) printf("string.to!string(%.*s, uint).unittest\n", Int.stringof.length, Int.stringof.ptr);
1269
1270        assert(to!string(to!Int(16), 16) == "10");
1271        assert(to!string(to!Int(15), 2u) == "1111");
1272        assert(to!string(to!Int(1), 2u) == "1");
1273        assert(to!string(to!Int(0x1234AF), 16u) == "1234AF");
1274        assert(to!string(to!Int(0x1234BCD), 16u, LetterCase.upper) == "1234BCD");
1275        assert(to!string(to!Int(0x1234AF), 16u, LetterCase.lower) == "1234af");
1276    }
1277
1278    foreach (Int; TypeTuple!(int, long))
1279    {
1280        debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1281        debug(conv) printf("string.to!string(%.*s, uint).unittest\n", Int.stringof.length, Int.stringof.ptr);
1282
1283        assert(to!string(to!Int(-10), 10u) == "-10");
1284    }
1285
1286    assert(to!string(cast(byte)-10, 16) == "F6");
1287    assert(to!string(long.min) == "-9223372036854775808");
1288    assert(to!string(long.max) == "9223372036854775807");
1289}
1290
1291
1292/**
1293Narrowing numeric-numeric conversions throw when the value does not
1294fit in the narrower type.
1295 */
1296T toImpl(T, S)(S value)
1297    if (!isImplicitlyConvertible!(S, T) &&
1298        (isNumeric!S || isSomeChar!S || isBoolean!S) &&
1299        (isNumeric!T || isSomeChar!T || isBoolean!T) && !is(T == enum))
1300{
1301    enum sSmallest = mostNegative!S;
1302    enum tSmallest = mostNegative!T;
1303    static if (sSmallest < 0)
1304    {
1305        // possible underflow converting from a signed
1306        static if (tSmallest == 0)
1307        {
1308            immutable good = value >= 0;
1309        }
1310        else
1311        {
1312            static assert(tSmallest < 0);
1313            immutable good = value >= tSmallest;
1314        }
1315        if (!good)
1316            throw new ConvOverflowException("Conversion negative overflow");
1317    }
1318    static if (S.max > T.max)
1319    {
1320        // possible overflow
1321        if (value > T.max)
1322            throw new ConvOverflowException("Conversion positive overflow");
1323    }
1324    return (ref value)@trusted{ return cast(T) value; }(value);
1325}
1326
1327@safe pure unittest
1328{
1329    dchar a = ' ';
1330    assert(to!char(a) == ' ');
1331    a = 300;
1332    assert(collectException(to!char(a)));
1333
1334    dchar from0 = 'A';
1335    char to0 = to!char(from0);
1336
1337    wchar from1 = 'A';
1338    char to1 = to!char(from1);
1339
1340    char from2 = 'A';
1341    char to2 = to!char(from2);
1342
1343    char from3 = 'A';
1344    wchar to3 = to!wchar(from3);
1345
1346    char from4 = 'A';
1347    dchar to4 = to!dchar(from4);
1348}
1349
1350unittest
1351{
1352    // Narrowing conversions from enum -> integral should be allowed, but they
1353    // should throw at runtime if the enum value doesn't fit in the target
1354    // type.
1355    enum E1 : ulong { A = 1, B = 1UL<<48, C = 0 }
1356    assert(to!int(E1.A) == 1);
1357    assert(to!bool(E1.A) == true);
1358    assertThrown!ConvOverflowException(to!int(E1.B)); // E1.B overflows int
1359    assertThrown!ConvOverflowException(to!bool(E1.B)); // E1.B overflows bool
1360    assert(to!bool(E1.C) == false);
1361
1362    enum E2 : long { A = -1L<<48, B = -1<<31, C = 1<<31 }
1363    assertThrown!ConvOverflowException(to!int(E2.A)); // E2.A overflows int
1364    assertThrown!ConvOverflowException(to!uint(E2.B)); // E2.B overflows uint
1365    assert(to!int(E2.B) == -1<<31); // but does not overflow int
1366    assert(to!int(E2.C) == 1<<31);  // E2.C does not overflow int
1367
1368    enum E3 : int { A = -1, B = 1, C = 255, D = 0 }
1369    assertThrown!ConvOverflowException(to!ubyte(E3.A));
1370    assertThrown!ConvOverflowException(to!bool(E3.A));
1371    assert(to!byte(E3.A) == -1);
1372    assert(to!byte(E3.B) == 1);
1373    assert(to!ubyte(E3.C) == 255);
1374    assert(to!bool(E3.B) == true);
1375    assertThrown!ConvOverflowException(to!byte(E3.C));
1376    assertThrown!ConvOverflowException(to!bool(E3.C));
1377    assert(to!bool(E3.D) == false);
1378
1379}
1380
1381/**
1382Array-to-array conversion (except when target is a string type)
1383converts each element in turn by using $(D to).
1384 */
1385T toImpl(T, S)(S value)
1386    if (!isImplicitlyConvertible!(S, T) &&
1387        !isSomeString!S && isDynamicArray!S &&
1388        !isExactSomeString!T && isArray!T)
1389{
1390    alias E = typeof(T.init[0]);
1391
1392    auto w = appender!(E[])();
1393    w.reserve(value.length);
1394    foreach (i, ref e; value)
1395    {
1396        w.put(to!E(e));
1397    }
1398    return w.data;
1399}
1400
1401@safe pure unittest
1402{
1403    // array to array conversions
1404    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1405
1406    uint[] a = ([ 1u, 2, 3 ]).dup;
1407    auto b = to!(float[])(a);
1408    assert(b == [ 1.0f, 2, 3 ]);
1409
1410    //auto c = to!(string[])(b);
1411    //assert(c[0] == "1" && c[1] == "2" && c[2] == "3");
1412
1413    immutable(int)[3] d = [ 1, 2, 3 ];
1414    b = to!(float[])(d);
1415    assert(b == [ 1.0f, 2, 3 ]);
1416
1417    uint[][] e = [ a, a ];
1418    auto f = to!(float[][])(e);
1419    assert(f[0] == b && f[1] == b);
1420
1421    // Test for bug 8264
1422    struct Wrap
1423    {
1424        string wrap;
1425        alias wrap this;
1426    }
1427    Wrap[] warr = to!(Wrap[])(["foo", "bar"]);  // should work
1428}
1429/*@safe pure */unittest
1430{
1431    auto b = [ 1.0f, 2, 3 ];
1432
1433    auto c = to!(string[])(b);
1434    assert(c[0] == "1" && c[1] == "2" && c[2] == "3");
1435}
1436
1437/**
1438Associative array to associative array conversion converts each key
1439and each value in turn.
1440 */
1441T toImpl(T, S)(S value)
1442    if (isAssociativeArray!S &&
1443        isAssociativeArray!T && !is(T == enum))
1444{
1445    /* This code is potentially unsafe.
1446     */
1447    alias KeyType!T   K2;
1448    alias ValueType!T V2;
1449
1450    // While we are "building" the AA, we need to unqualify its values, and only re-qualify at the end
1451    Unqual!V2[K2] result;
1452
1453    foreach (k1, v1; value)
1454    {
1455        // Cast values temporarily to Unqual!V2 to store them to result variable
1456        result[to!K2(k1)] = cast(Unqual!V2) to!V2(v1);
1457    }
1458    // Cast back to original type
1459    return cast(T)result;
1460}
1461
1462@safe /*pure */unittest
1463{
1464    // hash to hash conversions
1465    int[string] a;
1466    a["0"] = 1;
1467    a["1"] = 2;
1468    auto b = to!(double[dstring])(a);
1469    assert(b["0"d] == 1 && b["1"d] == 2);
1470}
1471@safe /*pure */unittest // Bugzilla 8705, from doc
1472{
1473    int[string][double[int[]]] a;
1474    auto b = to!(short[wstring][string[double[]]])(a);
1475    a = [null:["hello":int.max]];
1476    assertThrown!ConvOverflowException(to!(short[wstring][string[double[]]])(a));
1477}
1478version(none) // masked by unexpected linker error in posix platforms
1479unittest // Extra cases for AA with qualifiers conversion
1480{
1481    int[][int[]] a;// = [[], []];
1482    auto b = to!(immutable(short[])[immutable short[]])(a);
1483
1484    double[dstring][int[long[]]] c;
1485    auto d = to!(immutable(short[immutable wstring])[immutable string[double[]]])(c);
1486}
1487
1488private void testIntegralToFloating(Integral, Floating)()
1489{
1490    Integral a = 42;
1491    auto b = to!Floating(a);
1492    assert(a == b);
1493    assert(a == to!Integral(b));
1494}
1495
1496private void testFloatingToIntegral(Floating, Integral)()
1497{
1498    bool convFails(Source, Target, E)(Source src)
1499    {
1500        try
1501            auto t = to!Target(src);
1502        catch (E)
1503            return true;
1504        return false;
1505    }
1506
1507    // convert some value
1508    Floating a = 4.2e1;
1509    auto b = to!Integral(a);
1510    assert(is(typeof(b) == Integral) && b == 42);
1511    // convert some negative value (if applicable)
1512    a = -4.2e1;
1513    static if (Integral.min < 0)
1514    {
1515        b = to!Integral(a);
1516        assert(is(typeof(b) == Integral) && b == -42);
1517    }
1518    else
1519    {
1520        // no go for unsigned types
1521        assert(convFails!(Floating, Integral, ConvOverflowException)(a));
1522    }
1523    // convert to the smallest integral value
1524    a = 0.0 + Integral.min;
1525    static if (Integral.min < 0)
1526    {
1527        a = -a; // -Integral.min not representable as an Integral
1528        assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1529                || Floating.sizeof <= Integral.sizeof);
1530    }
1531    a = 0.0 + Integral.min;
1532    assert(to!Integral(a) == Integral.min);
1533    --a; // no more representable as an Integral
1534    assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1535            || Floating.sizeof <= Integral.sizeof);
1536    a = 0.0 + Integral.max;
1537//   fwritefln(stderr, "%s a=%g, %s conv=%s", Floating.stringof, a,
1538//             Integral.stringof, to!Integral(a));
1539    assert(to!Integral(a) == Integral.max || Floating.sizeof <= Integral.sizeof);
1540    ++a; // no more representable as an Integral
1541    assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1542            || Floating.sizeof <= Integral.sizeof);
1543    // convert a value with a fractional part
1544    a = 3.14;
1545    assert(to!Integral(a) == 3);
1546    a = 3.99;
1547    assert(to!Integral(a) == 3);
1548    static if (Integral.min < 0)
1549    {
1550        a = -3.14;
1551        assert(to!Integral(a) == -3);
1552        a = -3.99;
1553        assert(to!Integral(a) == -3);
1554    }
1555}
1556
1557@safe pure unittest
1558{
1559    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1560
1561    alias AllInts = TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong);
1562    alias AllFloats = TypeTuple!(float, double, real);
1563    alias AllNumerics = TypeTuple!(AllInts, AllFloats);
1564    // test with same type
1565    {
1566        foreach (T; AllNumerics)
1567        {
1568            T a = 42;
1569            auto b = to!T(a);
1570            assert(is(typeof(a) == typeof(b)) && a == b);
1571        }
1572    }
1573    // test that floating-point numbers convert properly to largest ints
1574    // see http://oregonstate.edu/~peterseb/mth351/docs/351s2001_fp80x87.html
1575    // look for "largest fp integer with a predecessor"
1576    {
1577        // float
1578        int a = 16_777_215; // 2^24 - 1
1579        assert(to!int(to!float(a)) == a);
1580        assert(to!int(to!float(-a)) == -a);
1581        // double
1582        long b = 9_007_199_254_740_991; // 2^53 - 1
1583        assert(to!long(to!double(b)) == b);
1584        assert(to!long(to!double(-b)) == -b);
1585        // real
1586        // @@@ BUG IN COMPILER @@@
1587//     ulong c = 18_446_744_073_709_551_615UL; // 2^64 - 1
1588//     assert(to!ulong(to!real(c)) == c);
1589//     assert(to!ulong(-to!real(c)) == c);
1590    }
1591    // test conversions floating => integral
1592    {
1593        // AllInts[0 .. $ - 1] should be AllInts
1594        // @@@ BUG IN COMPILER @@@
1595        foreach (Integral; AllInts[0 .. $ - 1])
1596        {
1597            foreach (Floating; AllFloats)
1598            {
1599                testFloatingToIntegral!(Floating, Integral)();
1600            }
1601        }
1602    }
1603    // test conversion integral => floating
1604    {
1605        foreach (Integral; AllInts[0 .. $ - 1])
1606        {
1607            foreach (Floating; AllFloats)
1608            {
1609                testIntegralToFloating!(Integral, Floating)();
1610            }
1611        }
1612    }
1613    // test parsing
1614    {
1615        foreach (T; AllNumerics)
1616        {
1617            // from type immutable(char)[2]
1618            auto a = to!T("42");
1619            assert(a == 42);
1620            // from type char[]
1621            char[] s1 = "42".dup;
1622            a = to!T(s1);
1623            assert(a == 42);
1624            // from type char[2]
1625            char[2] s2;
1626            s2[] = "42";
1627            a = to!T(s2);
1628            assert(a == 42);
1629            // from type immutable(wchar)[2]
1630            a = to!T("42"w);
1631            assert(a == 42);
1632        }
1633    }
1634}
1635/*@safe pure */unittest
1636{
1637    alias AllInts = TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong);
1638    alias AllFloats = TypeTuple!(float, double, real);
1639    alias AllNumerics = TypeTuple!(AllInts, AllFloats);
1640    // test conversions to string
1641    {
1642        foreach (T; AllNumerics)
1643        {
1644            T a = 42;
1645            assert(to!string(a) == "42");
1646            //assert(to!wstring(a) == "42"w);
1647            //assert(to!dstring(a) == "42"d);
1648            // array test
1649//       T[] b = new T[2];
1650//       b[0] = 42;
1651//       b[1] = 33;
1652//       assert(to!string(b) == "[42,33]");
1653        }
1654    }
1655    // test array to string conversion
1656    foreach (T ; AllNumerics)
1657    {
1658        auto a = [to!T(1), 2, 3];
1659        assert(to!string(a) == "[1, 2, 3]");
1660    }
1661    // test enum to int conversion
1662    // enum Testing { Test1, Test2 };
1663    // Testing t;
1664    // auto a = to!string(t);
1665    // assert(a == "0");
1666}
1667
1668
1669/**
1670String to non-string conversion runs parsing.
1671$(UL
1672  $(LI When the source is a wide string, it is first converted to a narrow
1673       string and then parsed.)
1674  $(LI When the source is a narrow string, normal text parsing occurs.))
1675*/
1676T toImpl(T, S)(S value)
1677    if ( isExactSomeString!S && isDynamicArray!S &&
1678        !isExactSomeString!T && is(typeof(parse!T(value))))
1679{
1680    scope(success)
1681    {
1682        if (value.length)
1683        {
1684            throw convError!(S, T)(value);
1685        }
1686    }
1687    return parse!T(value);
1688}
1689
1690/// ditto
1691T toImpl(T, S)(S value, uint radix)
1692    if ( isExactSomeString!S && isDynamicArray!S &&
1693        !isExactSomeString!T && is(typeof(parse!T(value, radix))))
1694{
1695    scope(success)
1696    {
1697        if (value.length)
1698        {
1699            throw convError!(S, T)(value);
1700        }
1701    }
1702    return parse!T(value, radix);
1703}
1704
1705@safe pure unittest
1706{
1707    // Issue 6668 - ensure no collaterals thrown
1708    try { to!uint("-1"); }
1709    catch (ConvException e) { assert(e.next is null); }
1710}
1711
1712@safe pure unittest
1713{
1714    debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
1715    foreach (Str; TypeTuple!(string, wstring, dstring))
1716    {
1717        Str a = "123";
1718        assert(to!int(a) == 123);
1719        assert(to!double(a) == 123);
1720    }
1721
1722    // 6255
1723    auto n = to!int("FF", 16);
1724    assert(n == 255);
1725}
1726
1727/**
1728Convert a value that is implicitly convertible to the enum base type
1729into an Enum value. If the value does not match any enum member values
1730a ConvException is thrown.
1731Enums with floating-point or string base types are not 

Large files files are truncated, but you can click here to view the full file