1// Written in the D programming language.
2
3/**
4A one-stop shop for converting values from one type to another.
5
6$(SCRIPT inhibitQuickIndex = 1;)
7$(DIVC quickindex,
8$(BOOKTABLE,
9$(TR $(TH Category) $(TH Functions))
10$(TR $(TD Generic) $(TD
11        $(LREF asOriginalType)
12        $(LREF castFrom)
13        $(LREF parse)
14        $(LREF to)
15        $(LREF toChars)
16))
17$(TR $(TD Strings) $(TD
18        $(LREF text)
19        $(LREF wtext)
20        $(LREF dtext)
21        $(LREF hexString)
22))
23$(TR $(TD Numeric) $(TD
24        $(LREF octal)
25        $(LREF roundTo)
26        $(LREF signed)
27        $(LREF unsigned)
28))
29$(TR $(TD Exceptions) $(TD
30        $(LREF ConvException)
31        $(LREF ConvOverflowException)
32))
33))
34
35Copyright: Copyright The D Language Foundation 2007-.
36
37License:   $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
38
39Authors:   $(HTTP digitalmars.com, Walter Bright),
40           $(HTTP erdani.org, Andrei Alexandrescu),
41           Shin Fujishiro,
42           Adam D. Ruppe,
43           Kenji Hara
44
45Source:    $(PHOBOSSRC std/conv.d)
46
47*/
48module std.conv;
49
50public import std.ascii : LetterCase;
51
52import std.meta;
53import std.range;
54import std.traits;
55import std.typecons : Flag, Yes, No, tuple, isTuple;
56
57// Same as std.string.format, but "self-importing".
58// Helps reduce code and imports, particularly in static asserts.
59// Also helps with missing imports errors.
60package template convFormat()
61{
62    import std.format : format;
63    alias convFormat = format;
64}
65
66/* ************* Exceptions *************** */
67
68/**
69 * Thrown on conversion errors.
70 */
71class ConvException : Exception
72{
73    import std.exception : basicExceptionCtors;
74    ///
75    mixin basicExceptionCtors;
76}
77
78///
79@safe unittest
80{
81    import std.exception : assertThrown;
82    assertThrown!ConvException(to!int("abc"));
83}
84
85private auto convError(S, T)(S source, string fn = __FILE__, size_t ln = __LINE__)
86{
87    string msg;
88
89    if (source.empty)
90        msg = "Unexpected end of input when converting from type " ~ S.stringof ~ " to type " ~ T.stringof;
91    else
92    {
93        ElementType!S el = source.front;
94
95        if (el == '\n')
96            msg = text("Unexpected '\\n' when converting from type " ~ S.stringof ~ " to type " ~ T.stringof);
97        else
98            msg =  text("Unexpected '", el,
99                 "' when converting from type " ~ S.stringof ~ " to type " ~ T.stringof);
100    }
101
102    return new ConvException(msg, fn, ln);
103}
104
105private auto convError(S, T)(S source, int radix, string fn = __FILE__, size_t ln = __LINE__)
106{
107    string msg;
108
109    if (source.empty)
110        msg = text("Unexpected end of input when converting from type " ~ S.stringof ~ " base ", radix,
111                " to type " ~ T.stringof);
112    else
113        msg = text("Unexpected '", source.front,
114            "' when converting from type " ~ S.stringof ~ " base ", radix,
115            " to type " ~ T.stringof);
116
117    return new ConvException(msg, fn, ln);
118}
119
120@safe pure/* nothrow*/  // lazy parameter bug
121private auto parseError(lazy string msg, string fn = __FILE__, size_t ln = __LINE__)
122{
123    return new ConvException(text("Can't parse string: ", msg), fn, ln);
124}
125
126private void parseCheck(alias source)(dchar c, string fn = __FILE__, size_t ln = __LINE__)
127{
128    if (source.empty)
129        throw parseError(text("unexpected end of input when expecting \"", c, "\""));
130    if (source.front != c)
131        throw parseError(text("\"", c, "\" is missing"), fn, ln);
132    source.popFront();
133}
134
135private
136{
137    T toStr(T, S)(S src)
138    if (isSomeString!T)
139    {
140        // workaround for https://issues.dlang.org/show_bug.cgi?id=14198
141        static if (is(S == bool) && is(typeof({ T s = "string"; })))
142        {
143            return src ? "true" : "false";
144        }
145        else
146        {
147            import std.array : appender;
148            import std.format.spec : FormatSpec;
149            import std.format.write : formatValue;
150
151            auto w = appender!T();
152            FormatSpec!(ElementEncodingType!T) f;
153            formatValue(w, src, f);
154            return w.data;
155        }
156    }
157
158    template isExactSomeString(T)
159    {
160        enum isExactSomeString = isSomeString!T && !is(T == enum);
161    }
162
163    template isEnumStrToStr(S, T)
164    {
165        enum isEnumStrToStr = isImplicitlyConvertible!(S, T) &&
166                              is(S == enum) && isExactSomeString!T;
167    }
168    template isNullToStr(S, T)
169    {
170        enum isNullToStr = isImplicitlyConvertible!(S, T) &&
171                           (is(immutable S == immutable typeof(null))) && isExactSomeString!T;
172    }
173}
174
175/**
176 * Thrown on conversion overflow errors.
177 */
178class ConvOverflowException : ConvException
179{
180    @safe pure nothrow
181    this(string s, string fn = __FILE__, size_t ln = __LINE__)
182    {
183        super(s, fn, ln);
184    }
185}
186
187///
188@safe unittest
189{
190    import std.exception : assertThrown;
191    assertThrown!ConvOverflowException(to!ubyte(1_000_000));
192}
193
194/**
195The `to` template converts a value from one type _to another.
196The source type is deduced and the target type must be specified, for example the
197expression `to!int(42.0)` converts the number 42 from
198`double` _to `int`. The conversion is "safe", i.e.,
199it checks for overflow; `to!int(4.2e10)` would throw the
200`ConvOverflowException` exception. Overflow checks are only
201inserted when necessary, e.g., `to!double(42)` does not do
202any checking because any `int` fits in a `double`.
203
204Conversions from string _to numeric types differ from the C equivalents
205`atoi()` and `atol()` by checking for overflow and not allowing whitespace.
206
207For conversion of strings _to signed types, the grammar recognized is:
208$(PRE $(I Integer): $(I Sign UnsignedInteger)
209$(I UnsignedInteger)
210$(I Sign):
211    $(B +)
212    $(B -))
213
214For conversion _to unsigned types, the grammar recognized is:
215$(PRE $(I UnsignedInteger):
216    $(I DecimalDigit)
217    $(I DecimalDigit) $(I UnsignedInteger))
218 */
219template to(T)
220{
221    T to(A...)(A args)
222        if (A.length > 0)
223    {
224        return toImpl!T(args);
225    }
226
227    // Fix issue 6175
228    T to(S)(ref S arg)
229        if (isStaticArray!S)
230    {
231        return toImpl!T(arg);
232    }
233
234    // Fix issue 16108
235    T to(S)(ref S arg)
236        if (isAggregateType!S && !isCopyable!S)
237    {
238        return toImpl!T(arg);
239    }
240}
241
242/**
243 * Converting a value _to its own type (useful mostly for generic code)
244 * simply returns its argument.
245 */
246@safe pure unittest
247{
248    int a = 42;
249    int b = to!int(a);
250    double c = to!double(3.14); // c is double with value 3.14
251}
252
253/**
254 * Converting among numeric types is a safe way _to cast them around.
255 *
256 * Conversions from floating-point types _to integral types allow loss of
257 * precision (the fractional part of a floating-point number). The
258 * conversion is truncating towards zero, the same way a cast would
259 * truncate. (_To round a floating point value when casting _to an
260 * integral, use `roundTo`.)
261 */
262@safe pure unittest
263{
264    import std.exception : assertThrown;
265
266    int a = 420;
267    assert(to!long(a) == a);
268    assertThrown!ConvOverflowException(to!byte(a));
269
270    assert(to!int(4.2e6) == 4200000);
271    assertThrown!ConvOverflowException(to!uint(-3.14));
272    assert(to!uint(3.14) == 3);
273    assert(to!uint(3.99) == 3);
274    assert(to!int(-3.99) == -3);
275}
276
277/**
278 * When converting strings _to numeric types, note that the D hexadecimal and binary
279 * literals are not handled. Neither the prefixes that indicate the base, nor the
280 * horizontal bar used _to separate groups of digits are recognized. This also
281 * applies to the suffixes that indicate the type.
282 *
283 * _To work around this, you can specify a radix for conversions involving numbers.
284 */
285@safe pure unittest
286{
287    auto str = to!string(42, 16);
288    assert(str == "2A");
289    auto i = to!int(str, 16);
290    assert(i == 42);
291}
292
293/**
294 * Conversions from integral types _to floating-point types always
295 * succeed, but might lose accuracy. The largest integers with a
296 * predecessor representable in floating-point format are `2^24-1` for
297 * `float`, `2^53-1` for `double`, and `2^64-1` for `real` (when
298 * `real` is 80-bit, e.g. on Intel machines).
299 */
300@safe pure unittest
301{
302    // 2^24 - 1, largest proper integer representable as float
303    int a = 16_777_215;
304    assert(to!int(to!float(a)) == a);
305    assert(to!int(to!float(-a)) == -a);
306}
307
308/**
309   Conversion from string types to char types enforces the input
310   to consist of a single code point, and said code point must
311   fit in the target type. Otherwise, $(LREF ConvException) is thrown.
312 */
313@safe pure unittest
314{
315    import std.exception : assertThrown;
316
317    assert(to!char("a") == 'a');
318    assertThrown(to!char("��")); // '��' does not fit into a char
319    assert(to!wchar("��") == '��');
320    assertThrown(to!wchar("����")); // '����' does not fit into a wchar
321    assert(to!dchar("����") == '����');
322
323    // Using wstring or dstring as source type does not affect the result
324    assert(to!char("a"w) == 'a');
325    assert(to!char("a"d) == 'a');
326
327    // Two code points cannot be converted to a single one
328    assertThrown(to!char("ab"));
329}
330
331/**
332 * Converting an array _to another array type works by converting each
333 * element in turn. Associative arrays can be converted _to associative
334 * arrays as long as keys and values can in turn be converted.
335 */
336@safe pure unittest
337{
338    import std.string : split;
339
340    int[] a = [1, 2, 3];
341    auto b = to!(float[])(a);
342    assert(b == [1.0f, 2, 3]);
343    string str = "1 2 3 4 5 6";
344    auto numbers = to!(double[])(split(str));
345    assert(numbers == [1.0, 2, 3, 4, 5, 6]);
346    int[string] c;
347    c["a"] = 1;
348    c["b"] = 2;
349    auto d = to!(double[wstring])(c);
350    assert(d["a"w] == 1 && d["b"w] == 2);
351}
352
353/**
354 * Conversions operate transitively, meaning that they work on arrays and
355 * associative arrays of any complexity.
356 *
357 * This conversion works because `to!short` applies _to an `int`, `to!wstring`
358 * applies _to a `string`, `to!string` applies _to a `double`, and
359 * `to!(double[])` applies _to an `int[]`. The conversion might throw an
360 * exception because `to!short` might fail the range check.
361 */
362@safe unittest
363{
364    int[string][double[int[]]] a;
365    auto b = to!(short[wstring][string[double[]]])(a);
366}
367
368/**
369 * Object-to-object conversions by dynamic casting throw exception when
370 * the source is non-null and the target is null.
371 */
372@safe pure unittest
373{
374    import std.exception : assertThrown;
375    // Testing object conversions
376    class A {}
377    class B : A {}
378    class C : A {}
379    A a1 = new A, a2 = new B, a3 = new C;
380    assert(to!B(a2) is a2);
381    assert(to!C(a3) is a3);
382    assertThrown!ConvException(to!B(a3));
383}
384
385/**
386 * Stringize conversion from all types is supported.
387 * $(UL
388 *   $(LI String _to string conversion works for any two string types having
389 *        (`char`, `wchar`, `dchar`) character widths and any
390 *        combination of qualifiers (mutable, `const`, or `immutable`).)
391 *   $(LI Converts array (other than strings) _to string.
392 *        Each element is converted by calling `to!T`.)
393 *   $(LI Associative array _to string conversion.
394 *        Each element is converted by calling `to!T`.)
395 *   $(LI Object _to string conversion calls `toString` against the object or
396 *        returns `"null"` if the object is null.)
397 *   $(LI Struct _to string conversion calls `toString` against the struct if
398 *        it is defined.)
399 *   $(LI For structs that do not define `toString`, the conversion _to string
400 *        produces the list of fields.)
401 *   $(LI Enumerated types are converted _to strings as their symbolic names.)
402 *   $(LI Boolean values are converted to `"true"` or `"false"`.)
403 *   $(LI `char`, `wchar`, `dchar` _to a string type.)
404 *   $(LI Unsigned or signed integers _to strings.
405 *        $(DL $(DT [special case])
406 *             $(DD Convert integral value _to string in $(D_PARAM radix) radix.
407 *             radix must be a value from 2 to 36.
408 *             value is treated as a signed value only if radix is 10.
409 *             The characters A through Z are used to represent values 10 through 36
410 *             and their case is determined by the $(D_PARAM letterCase) parameter.)))
411 *   $(LI All floating point types _to all string types.)
412 *   $(LI Pointer to string conversions convert the pointer to a `size_t` value.
413 *        If pointer is `char*`, treat it as C-style strings.
414 *        In that case, this function is `@system`.))
415 * See $(REF formatValue, std,format) on how toString should be defined.
416 */
417@system pure unittest // @system due to cast and ptr
418{
419    // Conversion representing dynamic/static array with string
420    long[] a = [ 1, 3, 5 ];
421    assert(to!string(a) == "[1, 3, 5]");
422
423    // Conversion representing associative array with string
424    int[string] associativeArray = ["0":1, "1":2];
425    assert(to!string(associativeArray) == `["0":1, "1":2]` ||
426           to!string(associativeArray) == `["1":2, "0":1]`);
427
428    // char* to string conversion
429    assert(to!string(cast(char*) null) == "");
430    assert(to!string("foo\0".ptr) == "foo");
431
432    // Conversion reinterpreting void array to string
433    auto w = "abcx"w;
434    const(void)[] b = w;
435    assert(b.length == 8);
436
437    auto c = to!(wchar[])(b);
438    assert(c == "abcx");
439}
440
441// Tests for issue 6175
442@safe pure nothrow unittest
443{
444    char[9] sarr = "blablabla";
445    auto darr = to!(char[])(sarr);
446    assert(sarr.ptr == darr.ptr);
447    assert(sarr.length == darr.length);
448}
449
450// Tests for issue 7348
451@safe pure /+nothrow+/ unittest
452{
453    assert(to!string(null) == "null");
454    assert(text(null) == "null");
455}
456
457// Test `scope` inference of parameters of `text`
458@safe unittest
459{
460    static struct S
461    {
462        int* x; // make S a type with pointers
463        string toString() const scope
464        {
465            return "S";
466        }
467    }
468    scope S s;
469    assert(text("a", s) == "aS");
470}
471
472// Tests for issue 11390
473@safe pure /+nothrow+/ unittest
474{
475    const(typeof(null)) ctn;
476    immutable(typeof(null)) itn;
477    assert(to!string(ctn) == "null");
478    assert(to!string(itn) == "null");
479}
480
481// Tests for issue 8729: do NOT skip leading WS
482@safe pure unittest
483{
484    import std.exception;
485    static foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
486    {
487        assertThrown!ConvException(to!T(" 0"));
488        assertThrown!ConvException(to!T(" 0", 8));
489    }
490    static foreach (T; AliasSeq!(float, double, real))
491    {
492        assertThrown!ConvException(to!T(" 0"));
493    }
494
495    assertThrown!ConvException(to!bool(" true"));
496
497    alias NullType = typeof(null);
498    assertThrown!ConvException(to!NullType(" null"));
499
500    alias ARR = int[];
501    assertThrown!ConvException(to!ARR(" [1]"));
502
503    alias AA = int[int];
504    assertThrown!ConvException(to!AA(" [1:1]"));
505}
506
507// https://issues.dlang.org/show_bug.cgi?id=20623
508@safe pure nothrow unittest
509{
510    // static class C
511    // {
512    //     override string toString() const
513    //     {
514    //         return "C()";
515    //     }
516    // }
517
518    static struct S
519    {
520        bool b;
521        int i;
522        float f;
523        int[] a;
524        int[int] aa;
525        S* p;
526        // C c; // TODO: Fails because of hasToString
527
528        void fun() inout
529        {
530            static foreach (const idx; 0 .. this.tupleof.length)
531            {
532                {
533                    const _ = this.tupleof[idx].to!string();
534                }
535            }
536        }
537    }
538}
539
540/**
541If the source type is implicitly convertible to the target type, $(D
542to) simply performs the implicit conversion.
543 */
544private T toImpl(T, S)(S value)
545if (isImplicitlyConvertible!(S, T) &&
546    !isEnumStrToStr!(S, T) && !isNullToStr!(S, T))
547{
548    template isSignedInt(T)
549    {
550        enum isSignedInt = isIntegral!T && isSigned!T;
551    }
552    alias isUnsignedInt = isUnsigned;
553
554    // Conversion from integer to integer, and changing its sign
555    static if (isUnsignedInt!S && isSignedInt!T && S.sizeof == T.sizeof)
556    {   // unsigned to signed & same size
557        import std.exception : enforce;
558        enforce(value <= cast(S) T.max,
559                new ConvOverflowException("Conversion positive overflow"));
560    }
561    else static if (isSignedInt!S && isUnsignedInt!T)
562    {   // signed to unsigned
563        import std.exception : enforce;
564        enforce(0 <= value,
565                new ConvOverflowException("Conversion negative overflow"));
566    }
567
568    return value;
569}
570
571// https://issues.dlang.org/show_bug.cgi?id=9523: Allow identity enum conversion
572@safe pure nothrow unittest
573{
574    enum E { a }
575    auto e = to!E(E.a);
576    assert(e == E.a);
577}
578
579@safe pure nothrow unittest
580{
581    int a = 42;
582    auto b = to!long(a);
583    assert(a == b);
584}
585
586// https://issues.dlang.org/show_bug.cgi?id=6377
587@safe pure unittest
588{
589    import std.exception;
590    // Conversion between same size
591    static foreach (S; AliasSeq!(byte, short, int, long))
592    {{
593        alias U = Unsigned!S;
594
595        static foreach (Sint; AliasSeq!(S, const S, immutable S))
596        static foreach (Uint; AliasSeq!(U, const U, immutable U))
597        {{
598            // positive overflow
599            Uint un = Uint.max;
600            assertThrown!ConvOverflowException(to!Sint(un),
601                text(Sint.stringof, ' ', Uint.stringof, ' ', un));
602
603            // negative overflow
604            Sint sn = -1;
605            assertThrown!ConvOverflowException(to!Uint(sn),
606                text(Sint.stringof, ' ', Uint.stringof, ' ', un));
607        }}
608    }}
609
610    // Conversion between different size
611    static foreach (i, S1; AliasSeq!(byte, short, int, long))
612    static foreach (   S2; AliasSeq!(byte, short, int, long)[i+1..$])
613    {{
614        alias U1 = Unsigned!S1;
615        alias U2 = Unsigned!S2;
616
617        static assert(U1.sizeof < S2.sizeof);
618
619        // small unsigned to big signed
620        static foreach (Uint; AliasSeq!(U1, const U1, immutable U1))
621        static foreach (Sint; AliasSeq!(S2, const S2, immutable S2))
622        {{
623            Uint un = Uint.max;
624            assertNotThrown(to!Sint(un));
625            assert(to!Sint(un) == un);
626        }}
627
628        // big unsigned to small signed
629        static foreach (Uint; AliasSeq!(U2, const U2, immutable U2))
630        static foreach (Sint; AliasSeq!(S1, const S1, immutable S1))
631        {{
632            Uint un = Uint.max;
633            assertThrown(to!Sint(un));
634        }}
635
636        static assert(S1.sizeof < U2.sizeof);
637
638        // small signed to big unsigned
639        static foreach (Sint; AliasSeq!(S1, const S1, immutable S1))
640        static foreach (Uint; AliasSeq!(U2, const U2, immutable U2))
641        {{
642            Sint sn = -1;
643            assertThrown!ConvOverflowException(to!Uint(sn));
644        }}
645
646        // big signed to small unsigned
647        static foreach (Sint; AliasSeq!(S2, const S2, immutable S2))
648        static foreach (Uint; AliasSeq!(U1, const U1, immutable U1))
649        {{
650            Sint sn = -1;
651            assertThrown!ConvOverflowException(to!Uint(sn));
652        }}
653    }}
654}
655
656// https://issues.dlang.org/show_bug.cgi?id=13551
657private T toImpl(T, S)(S value)
658if (isTuple!T)
659{
660    T t;
661    static foreach (i; 0 .. T.length)
662    {
663        t[i] = value[i].to!(typeof(T[i]));
664    }
665    return t;
666}
667
668@safe unittest
669{
670    import std.typecons : Tuple;
671
672    auto test = ["10", "20", "30"];
673    assert(test.to!(Tuple!(int, int, int)) == Tuple!(int, int, int)(10, 20, 30));
674
675    auto test1 = [1, 2];
676    assert(test1.to!(Tuple!(int, int)) == Tuple!(int, int)(1, 2));
677
678    auto test2 = [1.0, 2.0, 3.0];
679    assert(test2.to!(Tuple!(int, int, int)) == Tuple!(int, int, int)(1, 2, 3));
680}
681
682/*
683  Converting static arrays forwards to their dynamic counterparts.
684 */
685private T toImpl(T, S)(ref S s)
686if (isStaticArray!S)
687{
688    return toImpl!(T, typeof(s[0])[])(s);
689}
690
691@safe pure nothrow unittest
692{
693    char[4] test = ['a', 'b', 'c', 'd'];
694    static assert(!isInputRange!(Unqual!(char[4])));
695    assert(to!string(test) == test);
696}
697
698/**
699When source type supports member template function opCast, it is used.
700*/
701private T toImpl(T, S)(S value)
702if (!isImplicitlyConvertible!(S, T) &&
703    is(typeof(S.init.opCast!T()) : T) &&
704    !isExactSomeString!T &&
705    !is(typeof(T(value))))
706{
707    return value.opCast!T();
708}
709
710@safe pure unittest
711{
712    static struct Test
713    {
714        struct T
715        {
716            this(S s) @safe pure { }
717        }
718        struct S
719        {
720            T opCast(U)() @safe pure { assert(false); }
721        }
722    }
723    cast(void) to!(Test.T)(Test.S());
724
725    // make sure std.conv.to is doing the same thing as initialization
726    Test.S s;
727    Test.T t = s;
728}
729
730@safe pure unittest
731{
732    class B
733    {
734        T opCast(T)() { return 43; }
735    }
736    auto b = new B;
737    assert(to!int(b) == 43);
738
739    struct S
740    {
741        T opCast(T)() { return 43; }
742    }
743    auto s = S();
744    assert(to!int(s) == 43);
745}
746
747/**
748When target type supports 'converting construction', it is used.
749$(UL $(LI If target type is struct, `T(value)` is used.)
750     $(LI If target type is class, $(D new T(value)) is used.))
751*/
752private T toImpl(T, S)(S value)
753if (!isImplicitlyConvertible!(S, T) &&
754    is(T == struct) && is(typeof(T(value))))
755{
756    return T(value);
757}
758
759// https://issues.dlang.org/show_bug.cgi?id=3961
760@safe pure unittest
761{
762    struct Int
763    {
764        int x;
765    }
766    Int i = to!Int(1);
767
768    static struct Int2
769    {
770        int x;
771        this(int x) @safe pure { this.x = x; }
772    }
773    Int2 i2 = to!Int2(1);
774
775    static struct Int3
776    {
777        int x;
778        static Int3 opCall(int x) @safe pure
779        {
780            Int3 i;
781            i.x = x;
782            return i;
783        }
784    }
785    Int3 i3 = to!Int3(1);
786}
787
788// https://issues.dlang.org/show_bug.cgi?id=6808
789@safe pure unittest
790{
791    static struct FakeBigInt
792    {
793        this(string s) @safe pure {}
794    }
795
796    string s = "101";
797    auto i3 = to!FakeBigInt(s);
798}
799
800/// ditto
801private T toImpl(T, S)(S value)
802if (!isImplicitlyConvertible!(S, T) &&
803    is(T == class) && is(typeof(new T(value))))
804{
805    return new T(value);
806}
807
808@safe pure unittest
809{
810    static struct S
811    {
812        int x;
813    }
814    static class C
815    {
816        int x;
817        this(int x) @safe pure { this.x = x; }
818    }
819
820    static class B
821    {
822        int value;
823        this(S src) @safe pure { value = src.x; }
824        this(C src) @safe pure { value = src.x; }
825    }
826
827    S s = S(1);
828    auto b1 = to!B(s);  // == new B(s)
829    assert(b1.value == 1);
830
831    C c = new C(2);
832    auto b2 = to!B(c);  // == new B(c)
833    assert(b2.value == 2);
834
835    auto c2 = to!C(3);   // == new C(3)
836    assert(c2.x == 3);
837}
838
839@safe pure unittest
840{
841    struct S
842    {
843        class A
844        {
845            this(B b) @safe pure {}
846        }
847        class B : A
848        {
849            this() @safe pure { super(this); }
850        }
851    }
852
853    S.B b = new S.B();
854    S.A a = to!(S.A)(b);      // == cast(S.A) b
855                              // (do not run construction conversion like new S.A(b))
856    assert(b is a);
857
858    static class C : Object
859    {
860        this() @safe pure {}
861        this(Object o) @safe pure {}
862    }
863
864    Object oc = new C();
865    C a2 = to!C(oc);    // == new C(a)
866                        // Construction conversion overrides down-casting conversion
867    assert(a2 !is a);   //
868}
869
870/**
871Object-to-object conversions by dynamic casting throw exception when the source is
872non-null and the target is null.
873 */
874private T toImpl(T, S)(S value)
875if (!isImplicitlyConvertible!(S, T) &&
876    (is(S == class) || is(S == interface)) && !is(typeof(value.opCast!T()) : T) &&
877    (is(T == class) || is(T == interface)) && !is(typeof(new T(value))))
878{
879    static if (is(T == immutable))
880    {
881            // immutable <- immutable
882            enum isModConvertible = is(S == immutable);
883    }
884    else static if (is(T == const))
885    {
886        static if (is(T == shared))
887        {
888            // shared const <- shared
889            // shared const <- shared const
890            // shared const <- immutable
891            enum isModConvertible = is(S == shared) || is(S == immutable);
892        }
893        else
894        {
895            // const <- mutable
896            // const <- immutable
897            enum isModConvertible = !is(S == shared);
898        }
899    }
900    else
901    {
902        static if (is(T == shared))
903        {
904            // shared <- shared mutable
905            enum isModConvertible = is(S == shared) && !is(S == const);
906        }
907        else
908        {
909            // (mutable) <- (mutable)
910            enum isModConvertible = is(Unqual!S == S);
911        }
912    }
913    static assert(isModConvertible, "Bad modifier conversion: "~S.stringof~" to "~T.stringof);
914
915    auto result = ()@trusted{ return cast(T) value; }();
916    if (!result && value)
917    {
918        throw new ConvException("Cannot convert object of static type "
919                ~S.classinfo.name~" and dynamic type "~value.classinfo.name
920                ~" to type "~T.classinfo.name);
921    }
922    return result;
923}
924
925// Unittest for 6288
926@safe pure unittest
927{
928    import std.exception;
929
930    alias Identity(T)      =              T;
931    alias toConst(T)       =        const T;
932    alias toShared(T)      =       shared T;
933    alias toSharedConst(T) = shared const T;
934    alias toImmutable(T)   =    immutable T;
935    template AddModifier(int n)
936    if (0 <= n && n < 5)
937    {
938             static if (n == 0) alias AddModifier = Identity;
939        else static if (n == 1) alias AddModifier = toConst;
940        else static if (n == 2) alias AddModifier = toShared;
941        else static if (n == 3) alias AddModifier = toSharedConst;
942        else static if (n == 4) alias AddModifier = toImmutable;
943    }
944
945    interface I {}
946    interface J {}
947
948    class A {}
949    class B : A {}
950    class C : B, I, J {}
951    class D : I {}
952
953    static foreach (m1; 0 .. 5) // enumerate modifiers
954    static foreach (m2; 0 .. 5) // ditto
955    {{
956        alias srcmod = AddModifier!m1;
957        alias tgtmod = AddModifier!m2;
958
959        // Compile time convertible equals to modifier convertible.
960        static if (isImplicitlyConvertible!(srcmod!Object, tgtmod!Object))
961        {
962            // Test runtime conversions: class to class, class to interface,
963            // interface to class, and interface to interface
964
965            // Check that the runtime conversion to succeed
966            srcmod!A ac = new srcmod!C();
967            srcmod!I ic = new srcmod!C();
968            assert(to!(tgtmod!C)(ac) !is null); // A(c) to C
969            assert(to!(tgtmod!I)(ac) !is null); // A(c) to I
970            assert(to!(tgtmod!C)(ic) !is null); // I(c) to C
971            assert(to!(tgtmod!J)(ic) !is null); // I(c) to J
972
973            // Check that the runtime conversion fails
974            srcmod!A ab = new srcmod!B();
975            srcmod!I id = new srcmod!D();
976            assertThrown(to!(tgtmod!C)(ab));    // A(b) to C
977            assertThrown(to!(tgtmod!I)(ab));    // A(b) to I
978            assertThrown(to!(tgtmod!C)(id));    // I(d) to C
979            assertThrown(to!(tgtmod!J)(id));    // I(d) to J
980        }
981        else
982        {
983            // Check that the conversion is rejected statically
984            static assert(!is(typeof(to!(tgtmod!C)(srcmod!A.init))));   // A to C
985            static assert(!is(typeof(to!(tgtmod!I)(srcmod!A.init))));   // A to I
986            static assert(!is(typeof(to!(tgtmod!C)(srcmod!I.init))));   // I to C
987            static assert(!is(typeof(to!(tgtmod!J)(srcmod!I.init))));   // I to J
988        }
989    }}
990}
991
992/**
993Handles type _to string conversions
994*/
995private T toImpl(T, S)(S value)
996if (!(isImplicitlyConvertible!(S, T) &&
997    !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
998    !isInfinite!S && isExactSomeString!T)
999{
1000    static if (isExactSomeString!S && value[0].sizeof == ElementEncodingType!T.sizeof)
1001    {
1002        // string-to-string with incompatible qualifier conversion
1003        static if (is(ElementEncodingType!T == immutable))
1004        {
1005            // conversion (mutable|const) -> immutable
1006            return value.idup;
1007        }
1008        else
1009        {
1010            // conversion (immutable|const) -> mutable
1011            return value.dup;
1012        }
1013    }
1014    else static if (isExactSomeString!S)
1015    {
1016        import std.array : appender;
1017        // other string-to-string
1018        //Use Appender directly instead of toStr, which also uses a formatedWrite
1019        auto w = appender!T();
1020        w.put(value);
1021        return w.data;
1022    }
1023    else static if (isIntegral!S && !is(S == enum))
1024    {
1025        // other integral-to-string conversions with default radix
1026        return toImpl!(T, S)(value, 10);
1027    }
1028    else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[]))
1029    {
1030        import core.stdc.string : memcpy;
1031        import std.exception : enforce;
1032        // Converting void array to string
1033        alias Char = Unqual!(ElementEncodingType!T);
1034        auto raw = cast(const(ubyte)[]) value;
1035        enforce(raw.length % Char.sizeof == 0,
1036                new ConvException("Alignment mismatch in converting a "
1037                        ~ S.stringof ~ " to a "
1038                        ~ T.stringof));
1039        auto result = new Char[raw.length / Char.sizeof];
1040        ()@trusted{ memcpy(result.ptr, value.ptr, value.length); }();
1041        return cast(T) result;
1042    }
1043    else static if (isPointer!S && isSomeChar!(PointerTarget!S))
1044    {
1045        // This is unsafe because we cannot guarantee that the pointer is null terminated.
1046        return () @system {
1047            static if (is(S : const(char)*))
1048                import core.stdc.string : strlen;
1049            else
1050                size_t strlen(S s) nothrow
1051                {
1052                    S p = s;
1053                    while (*p++) {}
1054                    return p-s-1;
1055                }
1056            return toImpl!T(value ? value[0 .. strlen(value)].dup : null);
1057        }();
1058    }
1059    else static if (isSomeString!T && is(S == enum))
1060    {
1061        static if (isSwitchable!(OriginalType!S) && EnumMembers!S.length <= 50)
1062        {
1063            switch (value)
1064            {
1065                foreach (member; NoDuplicates!(EnumMembers!S))
1066                {
1067                    case member:
1068                        return to!T(enumRep!(immutable(T), S, member));
1069                }
1070                default:
1071            }
1072        }
1073        else
1074        {
1075            foreach (member; EnumMembers!S)
1076            {
1077                if (value == member)
1078                    return to!T(enumRep!(immutable(T), S, member));
1079            }
1080        }
1081
1082        import std.array : appender;
1083        import std.format.spec : FormatSpec;
1084        import std.format.write : formatValue;
1085
1086        //Default case, delegate to format
1087        //Note: we don't call toStr directly, to avoid duplicate work.
1088        auto app = appender!T();
1089        app.put("cast(" ~ S.stringof ~ ")");
1090        FormatSpec!char f;
1091        formatValue(app, cast(OriginalType!S) value, f);
1092        return app.data;
1093    }
1094    else
1095    {
1096        // other non-string values runs formatting
1097        return toStr!T(value);
1098    }
1099}
1100
1101// https://issues.dlang.org/show_bug.cgi?id=14042
1102@system unittest
1103{
1104    immutable(char)* ptr = "hello".ptr;
1105    auto result = ptr.to!(char[]);
1106}
1107// https://issues.dlang.org/show_bug.cgi?id=8384
1108@system unittest
1109{
1110    void test1(T)(T lp, string cmp)
1111    {
1112        static foreach (e; AliasSeq!(char, wchar, dchar))
1113        {
1114            test2!(e[])(lp, cmp);
1115            test2!(const(e)[])(lp, cmp);
1116            test2!(immutable(e)[])(lp, cmp);
1117        }
1118    }
1119
1120    void test2(D, S)(S lp, string cmp)
1121    {
1122        assert(to!string(to!D(lp)) == cmp);
1123    }
1124
1125    static foreach (e; AliasSeq!("Hello, world!", "Hello, world!"w, "Hello, world!"d))
1126    {
1127        test1(e, "Hello, world!");
1128        test1(e.ptr, "Hello, world!");
1129    }
1130    static foreach (e; AliasSeq!("", ""w, ""d))
1131    {
1132        test1(e, "");
1133        test1(e.ptr, "");
1134    }
1135}
1136
1137/*
1138    To string conversion for non copy-able structs
1139 */
1140private T toImpl(T, S)(ref S value)
1141if (!(isImplicitlyConvertible!(S, T) &&
1142    !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
1143    !isInfinite!S && isExactSomeString!T && !isCopyable!S && !isStaticArray!S)
1144{
1145    import std.array : appender;
1146    import std.format.spec : FormatSpec;
1147    import std.format.write : formatValue;
1148
1149    auto w = appender!T();
1150    FormatSpec!(ElementEncodingType!T) f;
1151    formatValue(w, value, f);
1152    return w.data;
1153}
1154
1155// https://issues.dlang.org/show_bug.cgi?id=16108
1156@safe unittest
1157{
1158    static struct A
1159    {
1160        int val;
1161        bool flag;
1162
1163        string toString() { return text(val, ":", flag); }
1164
1165        @disable this(this);
1166    }
1167
1168    auto a = A();
1169    assert(to!string(a) == "0:false");
1170
1171    static struct B
1172    {
1173        int val;
1174        bool flag;
1175
1176        @disable this(this);
1177    }
1178
1179    auto b = B();
1180    assert(to!string(b) == "B(0, false)");
1181}
1182
1183// https://issues.dlang.org/show_bug.cgi?id=20070
1184@safe unittest
1185{
1186    void writeThem(T)(ref inout(T) them)
1187    {
1188        assert(them.to!string == "[1, 2, 3, 4]");
1189    }
1190
1191    const(uint)[4] vals = [ 1, 2, 3, 4 ];
1192    writeThem(vals);
1193}
1194
1195/*
1196    Check whether type `T` can be used in a switch statement.
1197    This is useful for compile-time generation of switch case statements.
1198*/
1199private template isSwitchable(E)
1200{
1201    enum bool isSwitchable = is(typeof({
1202        switch (E.init) { default: }
1203    }));
1204}
1205
1206//
1207@safe unittest
1208{
1209    static assert(isSwitchable!int);
1210    static assert(!isSwitchable!double);
1211    static assert(!isSwitchable!real);
1212}
1213
1214//Static representation of the index I of the enum S,
1215//In representation T.
1216//T must be an immutable string (avoids un-necessary initializations).
1217private template enumRep(T, S, S value)
1218if (is (T == immutable) && isExactSomeString!T && is(S == enum))
1219{
1220    static T enumRep = toStr!T(value);
1221}
1222
1223@safe pure unittest
1224{
1225    import std.exception;
1226    void dg()
1227    {
1228        // string to string conversion
1229        alias Chars = AliasSeq!(char, wchar, dchar);
1230        foreach (LhsC; Chars)
1231        {
1232            alias LhStrings = AliasSeq!(LhsC[], const(LhsC)[], immutable(LhsC)[]);
1233            foreach (Lhs; LhStrings)
1234            {
1235                foreach (RhsC; Chars)
1236                {
1237                    alias RhStrings = AliasSeq!(RhsC[], const(RhsC)[], immutable(RhsC)[]);
1238                    foreach (Rhs; RhStrings)
1239                    {
1240                        Lhs s1 = to!Lhs("wyda");
1241                        Rhs s2 = to!Rhs(s1);
1242                        //writeln(Lhs.stringof, " -> ", Rhs.stringof);
1243                        assert(s1 == to!Lhs(s2));
1244                    }
1245                }
1246            }
1247        }
1248
1249        foreach (T; Chars)
1250        {
1251            foreach (U; Chars)
1252            {
1253                T[] s1 = to!(T[])("Hello, world!");
1254                auto s2 = to!(U[])(s1);
1255                assert(s1 == to!(T[])(s2));
1256                auto s3 = to!(const(U)[])(s1);
1257                assert(s1 == to!(T[])(s3));
1258                auto s4 = to!(immutable(U)[])(s1);
1259                assert(s1 == to!(T[])(s4));
1260            }
1261        }
1262    }
1263    dg();
1264    assertCTFEable!dg;
1265}
1266
1267@safe pure unittest
1268{
1269    // Conversion representing bool value with string
1270    bool b;
1271    assert(to!string(b) == "false");
1272    b = true;
1273    assert(to!string(b) == "true");
1274}
1275
1276@safe pure unittest
1277{
1278    // Conversion representing character value with string
1279    alias AllChars =
1280        AliasSeq!( char, const( char), immutable( char),
1281                  wchar, const(wchar), immutable(wchar),
1282                  dchar, const(dchar), immutable(dchar));
1283    foreach (Char1; AllChars)
1284    {
1285        foreach (Char2; AllChars)
1286        {
1287            Char1 c = 'a';
1288            assert(to!(Char2[])(c)[0] == c);
1289        }
1290        uint x = 4;
1291        assert(to!(Char1[])(x) == "4");
1292    }
1293
1294    string s = "foo";
1295    string s2;
1296    foreach (char c; s)
1297    {
1298        s2 ~= to!string(c);
1299    }
1300    assert(s2 == "foo");
1301}
1302
1303@safe pure nothrow unittest
1304{
1305    import std.exception;
1306    // Conversion representing integer values with string
1307
1308    static foreach (Int; AliasSeq!(ubyte, ushort, uint, ulong))
1309    {
1310        assert(to!string(Int(0)) == "0");
1311        assert(to!string(Int(9)) == "9");
1312        assert(to!string(Int(123)) == "123");
1313    }
1314
1315    static foreach (Int; AliasSeq!(byte, short, int, long))
1316    {
1317        assert(to!string(Int(0)) == "0");
1318        assert(to!string(Int(9)) == "9");
1319        assert(to!string(Int(123)) == "123");
1320        assert(to!string(Int(-0)) == "0");
1321        assert(to!string(Int(-9)) == "-9");
1322        assert(to!string(Int(-123)) == "-123");
1323        assert(to!string(const(Int)(6)) == "6");
1324    }
1325
1326    assert(wtext(int.max) == "2147483647"w);
1327    assert(wtext(int.min) == "-2147483648"w);
1328    assert(to!string(0L) == "0");
1329
1330    assertCTFEable!(
1331    {
1332        assert(to!string(1uL << 62) == "4611686018427387904");
1333        assert(to!string(0x100000000) == "4294967296");
1334        assert(to!string(-138L) == "-138");
1335    });
1336}
1337
1338@safe unittest // sprintf issue
1339{
1340    double[2] a = [ 1.5, 2.5 ];
1341    assert(to!string(a) == "[1.5, 2.5]");
1342}
1343
1344@safe unittest
1345{
1346    // Conversion representing class object with string
1347    class A
1348    {
1349        override string toString() @safe const { return "an A"; }
1350    }
1351    A a;
1352    assert(to!string(a) == "null");
1353    a = new A;
1354    assert(to!string(a) == "an A");
1355
1356    // https://issues.dlang.org/show_bug.cgi?id=7660
1357    class C { override string toString() @safe const { return "C"; } }
1358    struct S { C c; alias c this; }
1359    S s; s.c = new C();
1360    assert(to!string(s) == "C");
1361}
1362
1363@safe unittest
1364{
1365    // Conversion representing struct object with string
1366    struct S1
1367    {
1368        string toString() { return "wyda"; }
1369    }
1370    assert(to!string(S1()) == "wyda");
1371
1372    struct S2
1373    {
1374        int a = 42;
1375        float b = 43.5;
1376    }
1377    S2 s2;
1378    assert(to!string(s2) == "S2(42, 43.5)");
1379
1380    // Test for issue 8080
1381    struct S8080
1382    {
1383        short[4] data;
1384        alias data this;
1385        string toString() { return "<S>"; }
1386    }
1387    S8080 s8080;
1388    assert(to!string(s8080) == "<S>");
1389}
1390
1391@safe unittest
1392{
1393    // Conversion representing enum value with string
1394    enum EB : bool { a = true }
1395    enum EU : uint { a = 0, b = 1, c = 2 }  // base type is unsigned
1396    // base type is signed (https://issues.dlang.org/show_bug.cgi?id=7909)
1397    enum EI : int { a = -1, b = 0, c = 1 }
1398    enum EF : real { a = 1.414, b = 1.732, c = 2.236 }
1399    enum EC : char { a = 'x', b = 'y' }
1400    enum ES : string { a = "aaa", b = "bbb" }
1401
1402    static foreach (E; AliasSeq!(EB, EU, EI, EF, EC, ES))
1403    {
1404        assert(to! string(E.a) == "a"c);
1405        assert(to!wstring(E.a) == "a"w);
1406        assert(to!dstring(E.a) == "a"d);
1407    }
1408
1409    // Test an value not corresponding to an enum member.
1410    auto o = cast(EU) 5;
1411    assert(to! string(o) == "cast(EU)5"c);
1412    assert(to!wstring(o) == "cast(EU)5"w);
1413    assert(to!dstring(o) == "cast(EU)5"d);
1414}
1415
1416@safe unittest
1417{
1418    enum E
1419    {
1420        foo,
1421        doo = foo, // check duplicate switch statements
1422        bar,
1423    }
1424
1425    //Test regression 12494
1426    assert(to!string(E.foo) == "foo");
1427    assert(to!string(E.doo) == "foo");
1428    assert(to!string(E.bar) == "bar");
1429
1430    static foreach (S; AliasSeq!(string, wstring, dstring, const(char[]), const(wchar[]), const(dchar[])))
1431    {{
1432        auto s1 = to!S(E.foo);
1433        auto s2 = to!S(E.foo);
1434        assert(s1 == s2);
1435        // ensure we don't allocate when it's unnecessary
1436        assert(s1 is s2);
1437    }}
1438
1439    static foreach (S; AliasSeq!(char[], wchar[], dchar[]))
1440    {{
1441        auto s1 = to!S(E.foo);
1442        auto s2 = to!S(E.foo);
1443        assert(s1 == s2);
1444        // ensure each mutable array is unique
1445        assert(s1 !is s2);
1446    }}
1447}
1448
1449// ditto
1450@trusted pure private T toImpl(T, S)(S value, uint radix, LetterCase letterCase = LetterCase.upper)
1451if (isIntegral!S &&
1452    isExactSomeString!T)
1453in
1454{
1455    assert(radix >= 2 && radix <= 36, "radix must be in range [2,36]");
1456}
1457do
1458{
1459    alias EEType = Unqual!(ElementEncodingType!T);
1460
1461    T toStringRadixConvert(size_t bufLen)(uint runtimeRadix = 0)
1462    {
1463        Unsigned!(Unqual!S) div = void, mValue = unsigned(value);
1464
1465        size_t index = bufLen;
1466        EEType[bufLen] buffer = void;
1467        char baseChar = letterCase == LetterCase.lower ? 'a' : 'A';
1468        char mod = void;
1469
1470        do
1471        {
1472            div = cast(S)(mValue / runtimeRadix );
1473            mod = cast(ubyte)(mValue % runtimeRadix);
1474            mod += mod < 10 ? '0' : baseChar - 10;
1475            buffer[--index] = cast(char) mod;
1476            mValue = div;
1477        } while (mValue);
1478
1479        return cast(T) buffer[index .. $].dup;
1480    }
1481
1482    import std.array : array;
1483    switch (radix)
1484    {
1485        case 10:
1486            // The (value+0) is so integral promotions happen to the type
1487            return toChars!(10, EEType)(value + 0).array;
1488        case 16:
1489            // The unsigned(unsigned(value)+0) is so unsigned integral promotions happen to the type
1490            if (letterCase == letterCase.upper)
1491                return toChars!(16, EEType, LetterCase.upper)(unsigned(unsigned(value) + 0)).array;
1492            else
1493                return toChars!(16, EEType, LetterCase.lower)(unsigned(unsigned(value) + 0)).array;
1494        case 2:
1495            return toChars!(2, EEType)(unsigned(unsigned(value) + 0)).array;
1496        case 8:
1497            return toChars!(8, EEType)(unsigned(unsigned(value) + 0)).array;
1498
1499        default:
1500            return toStringRadixConvert!(S.sizeof * 6)(radix);
1501    }
1502}
1503
1504@safe pure nothrow unittest
1505{
1506    static foreach (Int; AliasSeq!(uint, ulong))
1507    {
1508        assert(to!string(Int(16), 16) == "10");
1509        assert(to!string(Int(15), 2u) == "1111");
1510        assert(to!string(Int(1), 2u) == "1");
1511        assert(to!string(Int(0x1234AF), 16u) == "1234AF");
1512        assert(to!string(Int(0x1234BCD), 16u, LetterCase.upper) == "1234BCD");
1513        assert(to!string(Int(0x1234AF), 16u, LetterCase.lower) == "1234af");
1514    }
1515
1516    static foreach (Int; AliasSeq!(int, long))
1517    {
1518        assert(to!string(Int(-10), 10u) == "-10");
1519    }
1520
1521    assert(to!string(byte(-10), 16) == "F6");
1522    assert(to!string(long.min) == "-9223372036854775808");
1523    assert(to!string(long.max) == "9223372036854775807");
1524}
1525
1526/**
1527Narrowing numeric-numeric conversions throw when the value does not
1528fit in the narrower type.
1529 */
1530private T toImpl(T, S)(S value)
1531if (!isImplicitlyConvertible!(S, T) &&
1532    (isNumeric!S || isSomeChar!S || isBoolean!S) &&
1533    (isNumeric!T || isSomeChar!T || isBoolean!T) && !is(T == enum))
1534{
1535    static if (isFloatingPoint!S && isIntegral!T)
1536    {
1537        import std.math.traits : isNaN;
1538        if (value.isNaN) throw new ConvException("Input was NaN");
1539    }
1540
1541    enum sSmallest = mostNegative!S;
1542    enum tSmallest = mostNegative!T;
1543    static if (sSmallest < 0)
1544    {
1545        // possible underflow converting from a signed
1546        static if (tSmallest == 0)
1547        {
1548            immutable good = value >= 0;
1549        }
1550        else
1551        {
1552            static assert(tSmallest < 0,
1553                "minimum value of T must be smaller than 0");
1554            immutable good = value >= tSmallest;
1555        }
1556        if (!good)
1557            throw new ConvOverflowException("Conversion negative overflow");
1558    }
1559    static if (S.max > T.max)
1560    {
1561        // possible overflow
1562        if (value > T.max)
1563            throw new ConvOverflowException("Conversion positive overflow");
1564    }
1565    return (ref value)@trusted{ return cast(T) value; }(value);
1566}
1567
1568@safe pure unittest
1569{
1570    import std.exception;
1571
1572    dchar a = ' ';
1573    assert(to!char(a) == ' ');
1574    a = 300;
1575    assert(collectException(to!char(a)));
1576
1577    dchar from0 = 'A';
1578    char to0 = to!char(from0);
1579
1580    wchar from1 = 'A';
1581    char to1 = to!char(from1);
1582
1583    char from2 = 'A';
1584    char to2 = to!char(from2);
1585
1586    char from3 = 'A';
1587    wchar to3 = to!wchar(from3);
1588
1589    char from4 = 'A';
1590    dchar to4 = to!dchar(from4);
1591}
1592
1593@safe unittest
1594{
1595    import std.exception;
1596
1597    // Narrowing conversions from enum -> integral should be allowed, but they
1598    // should throw at runtime if the enum value doesn't fit in the target
1599    // type.
1600    enum E1 : ulong { A = 1, B = 1UL << 48, C = 0 }
1601    assert(to!int(E1.A) == 1);
1602    assert(to!bool(E1.A) == true);
1603    assertThrown!ConvOverflowException(to!int(E1.B)); // E1.B overflows int
1604    assertThrown!ConvOverflowException(to!bool(E1.B)); // E1.B overflows bool
1605    assert(to!bool(E1.C) == false);
1606
1607    enum E2 : long { A = -1L << 48, B = -1 << 31, C = 1 << 31 }
1608    assertThrown!ConvOverflowException(to!int(E2.A)); // E2.A overflows int
1609    assertThrown!ConvOverflowException(to!uint(E2.B)); // E2.B overflows uint
1610    assert(to!int(E2.B) == -1 << 31); // but does not overflow int
1611    assert(to!int(E2.C) == 1 << 31);  // E2.C does not overflow int
1612
1613    enum E3 : int { A = -1, B = 1, C = 255, D = 0 }
1614    assertThrown!ConvOverflowException(to!ubyte(E3.A));
1615    assertThrown!ConvOverflowException(to!bool(E3.A));
1616    assert(to!byte(E3.A) == -1);
1617    assert(to!byte(E3.B) == 1);
1618    assert(to!ubyte(E3.C) == 255);
1619    assert(to!bool(E3.B) == true);
1620    assertThrown!ConvOverflowException(to!byte(E3.C));
1621    assertThrown!ConvOverflowException(to!bool(E3.C));
1622    assert(to!bool(E3.D) == false);
1623
1624}
1625
1626@safe unittest
1627{
1628    import std.exception;
1629    import std.math.traits : isNaN;
1630
1631    double d = double.nan;
1632    float f = to!float(d);
1633    assert(f.isNaN);
1634    assert(to!double(f).isNaN);
1635    assertThrown!ConvException(to!int(d));
1636    assertThrown!ConvException(to!int(f));
1637    auto ex = collectException(d.to!int);
1638    assert(ex.msg == "Input was NaN");
1639}
1640
1641/**
1642Array-to-array conversion (except when target is a string type)
1643converts each element in turn by using `to`.
1644 */
1645private T toImpl(T, S)(scope S value)
1646if (!isImplicitlyConvertible!(S, T) &&
1647    !isSomeString!S && isDynamicArray!S &&
1648    !isExactSomeString!T && isArray!T)
1649{
1650    alias E = typeof(T.init[0]);
1651
1652    static if (isStaticArray!T)
1653    {
1654        import std.exception : enforce;
1655        auto res = to!(E[])(value);
1656        enforce!ConvException(T.length == res.length,
1657            convFormat("Length mismatch when converting to static array: %s vs %s", T.length, res.length));
1658        return res[0 .. T.length];
1659    }
1660    else
1661    {
1662        import std.array : appender;
1663        auto w = appender!(E[])();
1664        w.reserve(value.length);
1665        foreach (ref e; value)
1666        {
1667            w.put(to!E(e));
1668        }
1669        return w.data;
1670    }
1671}
1672
1673@safe pure unittest
1674{
1675    import std.exception;
1676
1677    // array to array conversions
1678    uint[] a = [ 1u, 2, 3 ];
1679    auto b = to!(float[])(a);
1680    assert(b == [ 1.0f, 2, 3 ]);
1681
1682    immutable(int)[3] d = [ 1, 2, 3 ];
1683    b = to!(float[])(d);
1684    assert(b == [ 1.0f, 2, 3 ]);
1685
1686    uint[][] e = [ a, a ];
1687    auto f = to!(float[][])(e);
1688    assert(f[0] == b && f[1] == b);
1689
1690    // Test for https://issues.dlang.org/show_bug.cgi?id=8264
1691    struct Wrap
1692    {
1693        string wrap;
1694        alias wrap this;
1695    }
1696    Wrap[] warr = to!(Wrap[])(["foo", "bar"]);  // should work
1697
1698    // https://issues.dlang.org/show_bug.cgi?id=12633
1699    import std.conv : to;
1700    const s2 = ["10", "20"];
1701
1702    immutable int[2] a3 = s2.to!(int[2]);
1703    assert(a3 == [10, 20]);
1704
1705    // verify length mismatches are caught
1706    immutable s4 = [1, 2, 3, 4];
1707    foreach (i; [1, 4])
1708    {
1709        auto ex = collectException(s4[0 .. i].to!(int[2]));
1710            assert(ex && ex.msg == "Length mismatch when converting to static array: 2 vs " ~ [cast(char)(i + '0')],
1711                ex ? ex.msg : "Exception was not thrown!");
1712    }
1713}
1714
1715@safe unittest
1716{
1717    auto b = [ 1.0f, 2, 3 ];
1718
1719    auto c = to!(string[])(b);
1720    assert(c[0] == "1" && c[1] == "2" && c[2] == "3");
1721}
1722
1723/**
1724Associative array to associative array conversion converts each key
1725and each value in turn.
1726 */
1727private T toImpl(T, S)(S value)
1728if (!isImplicitlyConvertible!(S, T) && isAssociativeArray!S &&
1729    isAssociativeArray!T && !is(T == enum))
1730{
1731    /* This code is potentially unsafe.
1732     */
1733    alias K2 = KeyType!T;
1734    alias V2 = ValueType!T;
1735
1736    // While we are "building" the AA, we need to unqualify its values, and only re-qualify at the end
1737    Unqual!V2[K2] result;
1738
1739    foreach (k1, v1; value)
1740    {
1741        // Cast values temporarily to Unqual!V2 to store them to result variable
1742        result[to!K2(k1)] = to!(Unqual!V2)(v1);
1743    }
1744    // Cast back to original type
1745    return () @trusted { return cast(T) result; }();
1746}
1747
1748@safe unittest
1749{
1750    // hash to hash conversions
1751    int[string] a;
1752    a["0"] = 1;
1753    a["1"] = 2;
1754    auto b = to!(double[dstring])(a);
1755    assert(b["0"d] == 1 && b["1"d] == 2);
1756}
1757
1758// https://issues.dlang.org/show_bug.cgi?id=8705, from doc
1759@safe unittest
1760{
1761    import std.exception;
1762    int[string][double[int[]]] a;
1763    auto b = to!(short[wstring][string[double[]]])(a);
1764    a = [null:["hello":int.max]];
1765    assertThrown!ConvOverflowException(to!(short[wstring][string[double[]]])(a));
1766}
1767@system unittest // Extra cases for AA with qualifiers conversion
1768{
1769    int[][int[]] a;// = [[], []];
1770    auto b = to!(immutable(short[])[immutable short[]])(a);
1771
1772    double[dstring][int[long[]]] c;
1773    auto d = to!(immutable(short[immutable wstring])[immutable string[double[]]])(c);
1774}
1775
1776@safe unittest
1777{
1778    import std.algorithm.comparison : equal;
1779    import std.array : byPair;
1780
1781    int[int] a;
1782    assert(a.to!(int[int]) == a);
1783    assert(a.to!(const(int)[int]).byPair.equal(a.byPair));
1784}
1785
1786@safe pure unittest
1787{
1788    static void testIntegralToFloating(Integral, Floating)()
1789    {
1790        Integral a = 42;
1791        auto b = to!Floating(a);
1792        assert(a == b);
1793        assert(a == to!Integral(b));
1794    }
1795    static void testFloatingToIntegral(Floating, Integral)()
1796    {
1797        import std.math : floatTraits, RealFormat;
1798
1799        bool convFails(Source, Target, E)(Source src)
1800        {
1801            try
1802                cast(void) to!Target(src);
1803            catch (E)
1804                return true;
1805            return false;
1806        }
1807
1808        // convert some value
1809        Floating a = 4.2e1;
1810        auto b = to!Integral(a);
1811        assert(is(typeof(b) == Integral) && b == 42);
1812        // convert some negative value (if applicable)
1813        a = -4.2e1;
1814        static if (Integral.min < 0)
1815        {
1816            b = to!Integral(a);
1817            assert(is(typeof(b) == Integral) && b == -42);
1818        }
1819        else
1820        {
1821            // no go for unsigned types
1822            assert(convFails!(Floating, Integral, ConvOverflowException)(a));
1823        }
1824        // convert to the smallest integral value
1825        a = 0.0 + Integral.min;
1826        static if (Integral.min < 0)
1827        {
1828            a = -a; // -Integral.min not representable as an Integral
1829            assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1830                    || Floating.sizeof <= Integral.sizeof
1831                    || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1832        }
1833        a = 0.0 + Integral.min;
1834        assert(to!Integral(a) == Integral.min);
1835        --a; // no more representable as an Integral
1836        assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1837                || Floating.sizeof <= Integral.sizeof
1838                || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1839        a = 0.0 + Integral.max;
1840        assert(to!Integral(a) == Integral.max
1841                || Floating.sizeof <= Integral.sizeof
1842                || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1843        ++a; // no more representable as an Integral
1844        assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1845                || Floating.sizeof <= Integral.sizeof
1846                || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1847        // convert a value with a fractional part
1848        a = 3.14;
1849        assert(to!Integral(a) == 3);
1850        a = 3.99;
1851        assert(to!Integral(a) == 3);
1852        static if (Integral.min < 0)
1853        {
1854            a = -3.14;
1855            assert(to!Integral(a) == -3);
1856            a = -3.99;
1857            assert(to!Integral(a) == -3);
1858        }
1859    }
1860
1861    alias AllInts = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong);
1862    alias AllFloats = AliasSeq!(float, double, real);
1863    alias AllNumerics = AliasSeq!(AllInts, AllFloats);
1864    // test with same type
1865    {
1866        foreach (T; AllNumerics)
1867        {
1868            T a = 42;
1869            auto b = to!T(a);
1870            assert(is(typeof(a) == typeof(b)) && a == b);
1871        }
1872    }
1873    // test that floating-point numbers convert properly to largest ints
1874    // see http://oregonstate.edu/~peterseb/mth351/docs/351s2001_fp80x87.html
1875    // look for "largest fp integer with a predecessor"
1876    {
1877        // float
1878        int a = 16_777_215; // 2^24 - 1
1879        assert(to!int(to!float(a)) == a);
1880        assert(to!int(to!float(-a)) == -a);
1881        // double
1882        long b = 9_007_199_254_740_991; // 2^53 - 1
1883        assert(to!long(to!double(b)) == b);
1884        assert(to!long(to!double(-b)) == -b);
1885        // real
1886        static if (real.mant_dig >= 64)
1887        {
1888            ulong c = 18_446_744_073_709_551_615UL; // 2^64 - 1
1889            assert(to!ulong(to!real(c)) == c);
1890        }
1891    }
1892    // test conversions floating => integral
1893    {
1894        // AllInts[0 .. $ - 1] should be AllInts
1895        // @@@ BUG IN COMPILER @@@
1896        foreach (Integral; AllInts[0 .. $ - 1])
1897        {
1898            foreach (Floating; AllFloats)
1899            {
1900                testFloatingToIntegral!(Floating, Integral)();
1901            }
1902        }
1903    }
1904    // test conversion integral => floating
1905    {
1906        foreach (Integral; AllInts[0 .. $ - 1])
1907        {
1908            foreach (Floating; AllFloats)
1909            {
1910                testIntegralToFloating!(Integral, Floating)();
1911            }
1912        }
1913    }
1914    // test parsing
1915    {
1916        foreach (T; AllNumerics)
1917        {
1918            // from type immutable(char)[2]
1919            auto a = to!T("42");
1920            assert(a == 42);
1921            // from type char[]
1922            char[] s1 = "42".dup;
1923            a = to!T(s1);
1924            assert(a == 42);
1925            // from type char[2]
1926            char[2] s2;
1927            s2[] = "42";
1928            a = to!T(s2);
1929            assert(a == 42);
1930            // from type immutable(wchar)[2]
1931            a = to!T("42"w);
1932            assert(a == 42);
1933        }
1934    }
1935}
1936
1937@safe unittest
1938{
1939    alias AllInts = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong);
1940    alias AllFloats = AliasSeq!(float, double, real);
1941    alias AllNumerics = AliasSeq!(AllInts, AllFloats);
1942    // test conversions to string
1943    {
1944        foreach (T; AllNumerics)
1945        {
1946            T a = 42;
1947            string s = to!string(a);
1948            assert(s == "42", s);
1949            wstring ws = to!wstring(a);
1950            assert(ws == "42"w, to!string(ws));
1951            dstring ds = to!dstring(a);
1952            assert(ds == "42"d, to!string(ds));
1953            // array test
1954            T[] b = new T[2];
1955            b[0] = 42;
1956            b[1] = 33;
1957            assert(to!string(b) == "[42, 33]");
1958        }
1959    }
1960    // test array to string conversion
1961    foreach (T ; AllNumerics)
1962    {
1963        auto a = [to!T(1), 2, 3];
1964        assert(to!string(a) == "[1, 2, 3]");
1965    }
1966    // test enum to int conversion
1967    enum Testing { Test1, Test2 }
1968    Testing t;
1969    auto a = to!string(t);
1970    assert(a == "Test1");
1971}
1972
1973
1974/**
1975String, or string-like input range, to non-string conversion runs parsing.
1976$(UL
1977  $(LI When the source is a wide string, it is first converted to a narrow
1978       string and then parsed.)
1979  $(LI When the source is a narrow string, normal text parsing occurs.))
1980*/
1981private T toImpl(T, S)(S value)
1982if (isInputRange!S && isSomeChar!(ElementEncodingType!S) &&
1983    !isExactSomeString!T && is(typeof(parse!T(value))) &&
1984    // issue 20539
1985    !(is(T == enum) && is(typeof(value == OriginalType!T.init)) && !isSomeString!(OriginalType!T)))
1986{
1987    scope(success)
1988    {
1989        if (!value.empty)
1990        {
1991            throw convError!(S, T)(value);
1992        }
1993    }
1994    return parse!T(value);
1995}
1996
1997/// ditto
1998private T toImpl(T, S)(S value, uint radix)
1999if (isSomeFiniteCharInputRange!S &&
2000    isIntegral!T && is(typeof(parse!T(value, radix))))
2001{
2002    scope(success)
2003    {
2004        if (!value.empty)
2005        {
2006            throw convError!(S, T)(value);
2007        }
2008    }
2009    return parse!T(value, radix);
2010}
2011
2012@safe pure unittest
2013{
2014    // https://issues.dlang.org/show_bug.cgi?id=6668
2015    // ensure no collaterals thrown
2016    try { to!uint("-1"); }
2017    catch (ConvException e) { assert(e.next is null); }
2018}
2019
2020@safe pure unittest
2021{
2022    static foreach (Str; AliasSeq!(string, wstring, dstring))
2023    {{
2024        Str a = "123";
2025        assert(to!int(a) == 123);
2026        assert(to!double(a) == 123);
2027    }}
2028
2029    // https://issues.dlang.org/show_bug.cgi?id=6255
2030    auto n = to!int("FF", 16);
2031    assert(n == 255);
2032}
2033
2034// https://issues.dlang.org/show_bug.cgi?id=15800
2035@safe unittest
2036{
2037    import std.utf : byCodeUnit, byChar, byWchar, byDchar;
2038
2039    assert(to!int(byCodeUnit("10")) == 10);
2040    assert(to!int(byCodeUnit("10"), 10) == 10);
2041    assert(to!int(byCodeUnit("10"w)) == 10);
2042    assert(to!int(byCodeUnit("10"w), 10) == 10);
2043
2044    assert(to!int(byChar("10")) == 10);
2045    assert(to!int(byChar("10"), 10) == 10);
2046    assert(to!int(byWchar("10")) == 10);
2047    assert(to!int(byWchar("10"), 10) == 10);
2048    assert(to!int(byDchar("10")) == 10);
2049    assert(to!int(byDchar("10"), 10) == 10);
2050}
2051
2052/**
2053String, or string-like input range, to char type not directly
2054supported by parse parses the first dchar of the source.
2055
2056Returns: the first code point of the input range, converted
2057         to type T.
2058
2059Throws: ConvException if the input range contains more than
2060        a single code point, or if the code point does not
2061        fit into a code unit of type T.
2062*/
2063private T toImpl(T, S)(S value)
2064if (isSomeChar!T && !is(typeof(parse!T(value))) &&
2065    is(typeof(parse!dchar(value))))
2066{
2067    import std.utf : encode;
2068
2069    immutable dchar codepoint = parse!dchar(value);
2070    if (!value.empty)
2071        throw new ConvException(convFormat("Cannot convert \"%s\" to %s because it " ~
2072                                           "contains more than a single code point.",
2073                                           value, T.stringof));
2074    T[dchar.sizeof / T.sizeof] decodedCodepoint;
2075    if (encode(decodedCodepoint, codepoint) != 1)
2076        throw new ConvException(convFormat("First code point '%s' of \"%s\" does not fit into a " ~
2077                                           "single %s code unit", codepoint, value, T.stringof));
2078    return decodedCodepoint[0];
2079}
2080
2081@safe pure unittest
2082{
2083    import std.exception : assertThrown;
2084
2085    assert(toImpl!wchar("a") == 'a');
2086
2087    assert(toImpl!char("a"d) == 'a');
2088    assert(toImpl!char("a"w) == 'a');
2089    assert(toImpl!wchar("a"d) == 'a');
2090
2091    assertThrown!ConvException(toImpl!wchar("ab"));
2092    assertThrown!ConvException(toImpl!char("����"d));
2093}
2094
2095/**
2096Convert a value that is implicitly convertible to the enum base type
2097into an Enum value. If the value does not match any enum member values
2098a ConvException is thrown.
2099Enums with floating-point or string base types are not supported.
2100*/
2101private T toImpl(T, S)(S value)
2102if (is(T == enum) && !is(S == enum)
2103    && is(typeof(value == OriginalType!T.init))
2104    && !isFloatingPoint!(OriginalType!T) && !isSomeString!(OriginalType!T))
2105{
2106    foreach (Member; EnumMembers!T)
2107    {
2108        if (Member == value)
2109            return Member;
2110    }
2111    throw new ConvException(convFormat("Value (%s) does not match any member value of enum '%s'", value, T.stringof));
2112}
2113
2114@safe pure unittest
2115{
2116    import std.exception;
2117    enum En8143 : int { A = 10, B = 20, C = 30, D = 20 }
2118    enum En8143[][] m3 = to!(En8143[][])([[10, 30], [30, 10]]);
2119    static assert(m3 == [[En8143.A, En8143.C], [En8143.C, En8143.A]]);
2120
2121    En8143 en1 = to!En8143(10);
2122    assert(en1 == En8143.A);
2123    assertThrown!ConvException(to!En8143(5));   // matches none
2124    En8143[][] m1 = to!(En8143[][])([[10, 30], [30, 10]]);
2125    assert(m1 == [[En8143.A, En8143.C], [En8143.C, En8143.A]]);
2126}
2127
2128// https://issues.dlang.org/show_bug.cgi?id=20539
2129@safe pure unittest
2130{
2131    import std.exception : assertNotThrown;
2132
2133    // To test that the bug is fixed it is required that the struct is static,
2134    // otherwise, the frame pointer makes the test pass even if the bug is not
2135    // fixed.
2136
2137    static struct A
2138    {
2139        auto opEquals(U)(U)
2140        {
2141            return true;
2142        }
2143    }
2144
2145    enum ColorA
2146    {
2147        red = A()
2148    }
2149
2150    assertNotThrown("xxx".to!ColorA);
2151
2152    // This is a guard for the future.
2153
2154    struct B
2155    {
2156        auto opEquals(U)(U)
2157        {
2158            return true;
2159        }
2160    }
2161
2162    enum ColorB
2163    {
2164        red = B()
2165    }
2166
2167    assertNotThrown("xxx".to!ColorB);
2168}
2169
2170/***************************************************************
2171 Rounded conversion from floating point to integral.
2172
2173Rounded conversions do not work with non-integral target types.
2174 */
2175
2176template roundTo(Target)
2177{
2178    Target roundTo(Source)(Source value)
2179    {
2180        import core.math : abs = fabs;
2181        import std.math.exponential : log2;
2182        import std.math.rounding : trunc;
2183
2184        static assert(isFloatingPoint!Source);
2185        static assert(isIntegral!Target);
2186
2187        // If value >= 2 ^^ (real.mant_dig - 1), the number is an integer
2188        // and adding 0.5 won't work, but we allready know, that we do
2189        // not have to round anything.
2190        if (log2(abs(value)) >= real.mant_dig - 1)
2191            return to!Target(value);
2192
2193        return to!Target(trunc(value + (value < 0 ? -0.5L : 0.5L)));
2194    }
2195}
2196
2197///
2198@safe unittest
2199{
2200    assert(roundTo!int(3.14) == 3);
2201    assert(roundTo!int(3.49) == 3);
2202    assert(roundTo!int(3.5) == 4);
2203    assert(roundTo!int(3.999) == 4);
2204    assert(roundTo!int(-3.14) == -3);
2205    assert(roundTo!int(-3.49) == -3);
2206    assert(roundTo!int(-3.5) == -4);
2207    assert(roundTo!int(-3.999) == -4);
2208    assert(roundTo!(const int)(to!(const double)(-3.999)) == -4);
2209}
2210
2211@safe unittest
2212{
2213    import std.exception;
2214    // boundary values
2215    static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint))
2216    {
2217        assert(roundTo!Int(Int.min - 0.4L) == Int.min);
2218        assert(roundTo!Int(Int.max + 0.4L) == Int.max);
2219        assertThrown!ConvOverflowException(roundTo!Int(Int.min - 0.5L));
2220        assertThrown!ConvOverflowException(roundTo!Int(Int.max + 0.5L));
2221    }
2222}
2223
2224@safe unittest
2225{
2226    import std.exception;
2227    assertThrown!ConvException(roundTo!int(float.init));
2228    auto ex = collectException(roundTo!int(float.init));
2229    assert(ex.msg == "Input was NaN");
2230}
2231
2232// https://issues.dlang.org/show_bug.cgi?id=5232
2233@safe pure unittest
2234{
2235    static if (real.mant_dig >= 64)
2236        ulong maxOdd = ulong.max;
2237    else
2238        ulong maxOdd = (1UL << real.mant_dig) - 1;
2239
2240    real r1 = maxOdd;
2241    assert(roundTo!ulong(r1) == maxOdd);
2242
2243    real r2 = maxOdd - 1;
2244    assert(roundTo!ulong(r2) == maxOdd - 1);
2245
2246    real r3 = maxOdd / 2;
2247    assert(roundTo!ulong(r3) == maxOdd / 2);
2248
2249    real r4 = maxOdd / 2 + 1;
2250    assert(roundTo!ulong(r4) == maxOdd / 2 + 1);
2251
2252    // this is only an issue on computers where real == double
2253    long l = -((1L << double.mant_dig) - 1);
2254    double r5 = l;
2255    assert(roundTo!long(r5) == l);
2256}
2257
2258/**
2259The `parse` family of functions works quite like the `to`
2260family, except that:
2261$(OL
2262    $(LI It only works with character ranges as input.)
2263    $(LI It takes the input by reference. (This means that rvalues - such
2264    as string literals - are not accepted: use `to` instead.))
2265    $(LI It advances the input to the position following the conversion.)
2266    $(LI It does not throw if it could not convert the entire input.))
2267
2268This overload converts a character input range to a `bool`.
2269
2270Params:
2271    Target = the type to convert to
2272    source = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2273    doCount = the flag for deciding to report the number of consumed characters
2274
2275Returns:
2276$(UL
2277    $(LI A `bool` if `doCount` is set to `No.doCount`)
2278    $(LI A `tuple` containing a `bool` and a `size_t` if `doCount` is set to `Yes.doCount`))
2279
2280Throws:
2281    A $(LREF ConvException) if the range does not represent a `bool`.
2282
2283Note:
2284    All character input range conversions using $(LREF to) are forwarded
2285    to `parse` and do not require lvalues.
2286*/
2287auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
2288if (isInputRange!Source &&
2289    isSomeChar!(ElementType!Source) &&
2290    is(immutable Target == immutable bool))
2291{
2292    import std.ascii : toLower;
2293
2294    static if (isNarrowString!Source)
2295    {
2296        import std.string : representation;
2297        auto s = source.representation;
2298    }
2299    else
2300    {
2301        alias s = source;
2302    }
2303
2304    if (!s.empty)
2305    {
2306        auto c1 = toLower(s.front);
2307        bool result = c1 == 't';
2308        if (result || c1 == 'f')
2309        {
2310            s.popFront();
2311            foreach (c; result ? "rue" : "alse")
2312            {
2313                if (s.empty || toLower(s.front) != c)
2314                    goto Lerr;
2315                s.popFront();
2316            }
2317
2318            static if (isNarrowString!Source)
2319                source = cast(Source) s;
2320
2321            static if (doCount)
2322            {
2323                if (result)
2324                    return tuple!("data", "count")(result, 4);
2325                return tuple!("data", "count")(result, 5);
2326            }
2327            else
2328            {
2329                return result;
2330            }
2331        }
2332    }
2333Lerr:
2334    throw parseError("bool should be case-insensitive 'true' or 'false'");
2335}
2336
2337///
2338@safe unittest
2339{
2340    import std.typecons : Flag, Yes, No;
2341    auto s = "true";
2342    bool b = parse!bool(s);
2343    assert(b);
2344    auto s2 = "true";
2345    bool b2 = parse!(bool, string, No.doCount)(s2);
2346    assert(b2);
2347    auto s3 = "true";
2348    auto b3 = parse!(bool, string, Yes.doCount)(s3);
2349    assert(b3.data && b3.count == 4);
2350    auto s4 = "falSE";
2351    auto b4 = parse!(bool, string, Yes.doCount)(s4);
2352    assert(!b4.data && b4.count == 5);
2353}
2354
2355@safe unittest
2356{
2357    import std.algorithm.comparison : equal;
2358    import std.exception;
2359    struct InputString
2360    {
2361        string _s;
2362        @property auto front() { return _s.front; }
2363        @property bool empty() { return _s.empty; }
2364        void popFront() { _s.popFront(); }
2365    }
2366
2367    auto s = InputString("trueFALSETrueFalsetRUEfALSE");
2368    assert(parse!bool(s) == true);
2369    assert(s.equal("FALSETrueFalsetRUEfALSE"));
2370    assert(parse!bool(s) == false);
2371    assert(s.equal("TrueFalsetRUEfALSE"));
2372    assert(parse!bool(s) == true);
2373    assert(s.equal("FalsetRUEfALSE"));
2374    assert(parse!bool(s) == false);
2375    assert(s.equal("tRUEfALSE"));
2376    assert(parse!bool(s) == true);
2377    assert(s.equal("fALSE"));
2378    assert(parse!bool(s) == false);
2379    assert(s.empty);
2380
2381    foreach (ss; ["tfalse", "ftrue", "t", "f", "tru", "fals", ""])
2382    {
2383        s = InputString(ss);
2384        assertThrown!ConvException(parse!bool(s));
2385    }
2386}
2387
2388/**
2389Parses a character $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2390to an integral value.
2391
2392Params:
2393    Target = the integral type to convert to
2394    s = the lvalue of an input range
2395    doCount = the flag for deciding to report the number of consumed characters
2396
2397Returns:
2398$(UL
2399    $(LI A number of type `Target` if `doCount` is set to `No.doCount`)
2400    $(LI A `tuple` containing a number of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
2401
2402Throws:
2403    A $(LREF ConvException) If an overflow occurred during conversion or
2404    if no character of the input was meaningfully converted.
2405*/
2406auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref scope Source s)
2407if (isSomeChar!(ElementType!Source) &&
2408    isIntegral!Target && !is(Target == enum))
2409{
2410    static if (Target.sizeof < int.sizeof)
2411    {
2412        // smaller types are handled like integers
2413        auto v = .parse!(Select!(Target.min < 0, int, uint), Source, Yes.doCount)(s);
2414        auto result = (() @trusted => cast (Target) v.data)();
2415        if (result == v.data)
2416        {
2417            static if (doCount)
2418            {
2419                return tuple!("data", "count")(result, v.count);
2420            }
2421            else
2422            {
2423                return result;
2424            }
2425        }
2426        throw new ConvOverflowException("Overflow in integral conversion");
2427    }
2428    else
2429    {
2430        // int or larger types
2431
2432        static if (Target.min < 0)
2433            bool sign = false;
2434        else
2435            enum bool sign = false;
2436
2437        enum char maxLastDigit = Target.min < 0 ? 7 : 5;
2438        uint c;
2439
2440        static if (isNarrowString!Source)
2441        {
2442            import std.string : representation;
2443            auto source = s.representation;
2444        }
2445        else
2446        {
2447            alias source = s;
2448        }
2449
2450        size_t count = 0;
2451
2452        if (source.empty)
2453            goto Lerr;
2454
2455        c = source.front;
2456
2457        static if (Target.min < 0)
2458        {
2459            switch (c)
2460            {
2461                case '-':
2462                    sign = true;
2463                    goto case '+';
2464                case '+':
2465                    ++count;
2466                    source.popFront();
2467
2468                    if (source.empty)
2469                        goto Lerr;
2470
2471                    c = source.front;
2472
2473                    break;
2474
2475                default:
2476                    break;
2477            }
2478        }
2479        c -= '0';
2480        if (c <= 9)
2481        {
2482            Target v = cast(Target) c;
2483
2484            ++count;
2485            source.popFront();
2486
2487            while (!source.empty)
2488            {
2489                c = cast(typeof(c)) (source.front - '0');
2490
2491                if (c > 9)
2492                    break;
2493
2494                if (v >= 0 && (v < Target.max/10 ||
2495                    (v == Target.max/10 && c <= maxLastDigit + sign)))
2496                {
2497                    // Note: `v` can become negative here in case of parsing
2498                    // the most negative value:
2499                    v = cast(Target) (v * 10 + c);
2500                    ++count;
2501                    source.popFront();
2502                }
2503                else
2504                    throw new ConvOverflowException("Overflow in integral conversion");
2505            }
2506
2507            if (sign)
2508                v = -v;
2509
2510            static if (isNarrowString!Source)
2511                s = s[$-source.length..$];
2512
2513            static if (doCount)
2514            {
2515                return tuple!("data", "count")(v, count);
2516            }
2517            else
2518            {
2519                return v;
2520            }
2521        }
2522Lerr:
2523        static if (isNarrowString!Source)
2524            throw convError!(Source, Target)(cast(Source) source);
2525        else
2526            throw convError!(Source, Target)(source);
2527    }
2528}
2529
2530///
2531@safe pure unittest
2532{
2533    import std.typecons : Flag, Yes, No;
2534    string s = "123";
2535    auto a = parse!int(s);
2536    assert(a == 123);
2537
2538    string s1 = "123";
2539    auto a1 = parse!(int, string, Yes.doCount)(s1);
2540    assert(a1.data == 123 && a1.count == 3);
2541
2542    // parse only accepts lvalues
2543    static assert(!__traits(compiles, parse!int("123")));
2544}
2545
2546///
2547@safe pure unittest
2548{
2549    import std.string : tr;
2550    import std.typecons : Flag, Yes, No;
2551    string test = "123 \t  76.14";
2552    auto a = parse!uint(test);
2553    assert(a == 123);
2554    assert(test == " \t  76.14"); // parse bumps string
2555    test = tr(test, " \t\n\r", "", "d"); // skip ws
2556    assert(test == "76.14");
2557    auto b = parse!double(test);
2558    assert(b == 76.14);
2559    assert(test == "");
2560
2561    string test2 = "123 \t  76.14";
2562    auto a2 = parse!(uint, string, Yes.doCount)(test2);
2563    assert(a2.data == 123 && a2.count == 3);
2564    assert(test2 == " \t  76.14");// parse bumps string
2565    test2 = tr(test2, " \t\n\r", "", "d"); // skip ws
2566    assert(test2 == "76.14");
2567    auto b2 = parse!(double, string, Yes.doCount)(test2);
2568    assert(b2.data == 76.14 && b2.count == 5);
2569    assert(test2 == "");
2570
2571}
2572
2573@safe pure unittest
2574{
2575    static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2576    {
2577        {
2578            assert(to!Int("0") == 0);
2579
2580            static if (isSigned!Int)
2581            {
2582                assert(to!Int("+0") == 0);
2583                assert(to!Int("-0") == 0);
2584            }
2585        }
2586
2587        static if (Int.sizeof >= byte.sizeof)
2588        {
2589                assert(to!Int("6") == 6);
2590                assert(to!Int("23") == 23);
2591                assert(to!Int("68") == 68);
2592                assert(to!Int("127") == 0x7F);
2593
2594            static if (isUnsigned!Int)
2595            {
2596                assert(to!Int("255") == 0xFF);
2597            }
2598            static if (isSigned!Int)
2599            {
2600                assert(to!Int("+6") == 6);
2601                assert(to!Int("+23") == 23);
2602                assert(to!Int("+68") == 68);
2603                assert(to!Int("+127") == 0x7F);
2604
2605                assert(to!Int("-6") == -6);
2606                assert(to!Int("-23") == -23);
2607                assert(to!Int("-68") == -68);
2608                assert(to!Int("-128") == -128);
2609            }
2610        }
2611
2612        static if (Int.sizeof >= short.sizeof)
2613        {
2614                assert(to!Int("468") == 468);
2615                assert(to!Int("32767") == 0x7FFF);
2616
2617            static if (isUnsigned!Int)
2618            {
2619                assert(to!Int("65535") == 0xFFFF);
2620            }
2621            static if (isSigned!Int)
2622            {
2623                assert(to!Int("+468") == 468);
2624                assert(to!Int("+32767") == 0x7FFF);
2625
2626                assert(to!Int("-468") == -468);
2627                assert(to!Int("-32768") == -32768);
2628            }
2629        }
2630
2631        static if (Int.sizeof >= int.sizeof)
2632        {
2633                assert(to!Int("2147483647") == 0x7FFFFFFF);
2634
2635            static if (isUnsigned!Int)
2636            {
2637                assert(to!Int("4294967295") == 0xFFFFFFFF);
2638            }
2639
2640            static if (isSigned!Int)
2641            {
2642                assert(to!Int("+2147483647") == 0x7FFFFFFF);
2643
2644                assert(to!Int("-2147483648") == -2147483648);
2645            }
2646        }
2647
2648        static if (Int.sizeof >= long.sizeof)
2649        {
2650                assert(to!Int("9223372036854775807") == 0x7FFFFFFFFFFFFFFF);
2651
2652            static if (isUnsigned!Int)
2653            {
2654                assert(to!Int("18446744073709551615") == 0xFFFFFFFFFFFFFFFF);
2655            }
2656
2657            static if (isSigned!Int)
2658            {
2659                assert(to!Int("+9223372036854775807") == 0x7FFFFFFFFFFFFFFF);
2660
2661                assert(to!Int("-9223372036854775808") == 0x8000000000000000);
2662            }
2663        }
2664    }
2665}
2666
2667@safe pure unittest
2668{
2669    import std.exception;
2670
2671    immutable string[] errors =
2672    [
2673        "",
2674        "-",
2675        "+",
2676        "-+",
2677        " ",
2678        " 0",
2679        "0 ",
2680        "- 0",
2681        "1-",
2682        "xx",
2683        "123h",
2684        "-+1",
2685        "--1",
2686        "+-1",
2687        "++1",
2688    ];
2689
2690    immutable string[] unsignedErrors =
2691    [
2692        "+5",
2693        "-78",
2694    ];
2695
2696    // parsing error check
2697    static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2698    {
2699        foreach (j, s; errors)
2700            assertThrown!ConvException(to!Int(s));
2701
2702        // parse!SomeUnsigned cannot parse head sign.
2703        static if (isUnsigned!Int)
2704        {
2705            foreach (j, s; unsignedErrors)
2706                assertThrown!ConvException(to!Int(s));
2707        }
2708    }
2709
2710    immutable string[] positiveOverflowErrors =
2711    [
2712        "128",                  // > byte.max
2713        "256",                  // > ubyte.max
2714        "32768",                // > short.max
2715        "65536",                // > ushort.max
2716        "2147483648",           // > int.max
2717        "4294967296",           // > uint.max
2718        "9223372036854775808",  // > long.max
2719        "18446744073709551616", // > ulong.max
2720    ];
2721    // positive overflow check
2722    static foreach (i, Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2723    {
2724        foreach (j, s; positiveOverflowErrors[i..$])
2725            assertThrown!ConvOverflowException(to!Int(s));
2726    }
2727
2728    immutable string[] negativeOverflowErrors =
2729    [
2730        "-129",                 // < byte.min
2731        "-32769",               // < short.min
2732        "-2147483649",          // < int.min
2733        "-9223372036854775809", // < long.min
2734    ];
2735    // negative overflow check
2736    static foreach (i, Int; AliasSeq!(byte, short, int, long))
2737    {
2738        foreach (j, s; negativeOverflowErrors[i..$])
2739            assertThrown!ConvOverflowException(to!Int(s));
2740    }
2741}
2742
2743@safe pure unittest
2744{
2745    void checkErrMsg(string input, dchar charInMsg, dchar charNotInMsg)
2746    {
2747        try
2748        {
2749            int x = input.to!int();
2750            assert(false, "Invalid conversion did not throw");
2751        }
2752        catch (ConvException e)
2753        {
2754            // Ensure error message contains failing character, not the character
2755            // beyond.
2756            import std.algorithm.searching : canFind;
2757            assert( e.msg.canFind(charInMsg) &&
2758                   !e.msg.canFind(charNotInMsg));
2759        }
2760        catch (Exception e)
2761        {
2762            assert(false, "Did not throw ConvException");
2763        }
2764    }
2765    checkErrMsg("@$", '@', '$');
2766    checkErrMsg("@$123", '@', '$');
2767    checkErrMsg("1@$23", '@', '$');
2768    checkErrMsg("1@$", '@', '$');
2769    checkErrMsg("1@$2", '@', '$');
2770    checkErrMsg("12@$", '@', '$');
2771}
2772
2773@safe pure unittest
2774{
2775    import std.exception;
2776    assertCTFEable!({ string s =  "1234abc"; assert(parse! int(s) ==  1234 && s == "abc"); });
2777    assertCTFEable!({ string s = "-1234abc"; assert(parse! int(s) == -1234 && s == "abc"); });
2778    assertCTFEable!({ string s =  "1234abc"; assert(parse!uint(s) ==  1234 && s == "abc"); });
2779
2780    assertCTFEable!({ string s =  "1234abc"; assert(parse!( int, string, Yes.doCount)(s) ==
2781        tuple( 1234, 4) && s == "abc"); });
2782    assertCTFEable!({ string s = "-1234abc"; assert(parse!( int, string, Yes.doCount)(s) ==
2783        tuple(-1234, 5) && s == "abc"); });
2784    assertCTFEable!({ string s =  "1234abc"; assert(parse!(uint, string, Yes.doCount)(s) ==
2785        tuple( 1234 ,4) && s == "abc"); });
2786}
2787
2788// https://issues.dlang.org/show_bug.cgi?id=13931
2789@safe pure unittest
2790{
2791    import std.exception;
2792
2793    assertThrown!ConvOverflowException("-21474836480".to!int());
2794    assertThrown!ConvOverflowException("-92233720368547758080".to!long());
2795}
2796
2797// https://issues.dlang.org/show_bug.cgi?id=14396
2798@safe pure unittest
2799{
2800    struct StrInputRange
2801    {
2802        this (string s) { str = s; }
2803        char front() const @property { return str[front_index]; }
2804        char popFront() { return str[front_index++]; }
2805        bool empty() const @property { return str.length <= front_index; }
2806        string str;
2807        size_t front_index = 0;
2808    }
2809    auto input = StrInputRange("777");
2810    assert(parse!int(input) == 777);
2811
2812    auto input2 = StrInputRange("777");
2813    assert(parse!(int, StrInputRange, Yes.doCount)(input2) == tuple(777, 3));
2814}
2815
2816// https://issues.dlang.org/show_bug.cgi?id=9621
2817@safe pure unittest
2818{
2819    string s1 = "[ \"\\141\", \"\\0\", \"\\41\", \"\\418\" ]";
2820    assert(parse!(string[])(s1) == ["a", "\0", "!", "!8"]);
2821
2822    s1 = "[ \"\\141\", \"\\0\", \"\\41\", \"\\418\" ]";
2823    auto len = s1.length;
2824    assert(parse!(string[], string, Yes.doCount)(s1) == tuple(["a", "\0", "!", "!8"], len));
2825}
2826
2827/// ditto
2828auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source, uint radix)
2829if (isSomeChar!(ElementType!Source) &&
2830    isIntegral!Target && !is(Target == enum))
2831in
2832{
2833    assert(radix >= 2 && radix <= 36, "radix must be in range [2,36]");
2834}
2835do
2836{
2837    import core.checkedint : mulu, addu;
2838    import std.exception : enforce;
2839
2840    if (radix == 10)
2841    {
2842        return parse!(Target, Source, doCount)(source);
2843    }
2844
2845    enforce!ConvException(!source.empty, "s must not be empty in integral parse");
2846
2847    immutable uint beyond = (radix < 10 ? '0' : 'a'-10) + radix;
2848    Target v = 0;
2849
2850    static if (isNarrowString!Source)
2851    {
2852        import std.string : representation;
2853        scope s = source.representation;
2854    }
2855    else
2856    {
2857        alias s = source;
2858    }
2859
2860    size_t count = 0;
2861    auto found = false;
2862    do
2863    {
2864        uint c = s.front;
2865        if (c < '0')
2866            break;
2867        if (radix < 10)
2868        {
2869            if (c >= beyond)
2870                break;
2871        }
2872        else
2873        {
2874            if (c > '9')
2875            {
2876                c |= 0x20;//poorman's tolower
2877                if (c < 'a' || c >= beyond)
2878                    break;
2879                c -= 'a'-10-'0';
2880            }
2881        }
2882
2883        bool overflow = false;
2884        auto nextv = v.mulu(radix, overflow).addu(c - '0', overflow);
2885        enforce!ConvOverflowException(!overflow && nextv <= Target.max, "Overflow in integral conversion");
2886        v = cast(Target) nextv;
2887        ++count;
2888        s.popFront();
2889        found = true;
2890    } while (!s.empty);
2891
2892    if (!found)
2893    {
2894        static if (isNarrowString!Source)
2895            throw convError!(Source, Target)(cast(Source) source);
2896        else
2897            throw convError!(Source, Target)(source);
2898    }
2899
2900    static if (isNarrowString!Source)
2901        source = source[$ - s.length .. $];
2902
2903    static if (doCount)
2904    {
2905        return tuple!("data", "count")(v, count);
2906    }
2907    else
2908    {
2909        return v;
2910    }
2911}
2912
2913@safe pure unittest
2914{
2915    string s; // parse doesn't accept rvalues
2916    foreach (i; 2 .. 37)
2917    {
2918        assert(parse!int(s = "0", i) == 0);
2919        assert(parse!int(s = "1", i) == 1);
2920        assert(parse!byte(s = "10", i) == i);
2921        assert(parse!(int, string, Yes.doCount)(s = "0", i) == tuple(0, 1));
2922        assert(parse!(int, string, Yes.doCount)(s = "1", i) == tuple(1, 1));
2923        assert(parse!(byte, string, Yes.doCount)(s = "10", i) == tuple(i, 2));
2924    }
2925
2926    assert(parse!int(s = "0011001101101", 2) == 0b0011001101101);
2927    assert(parse!int(s = "765", 8) == octal!765);
2928    assert(parse!int(s = "000135", 8) == octal!"135");
2929    assert(parse!int(s = "fCDe", 16) == 0xfcde);
2930
2931    // https://issues.dlang.org/show_bug.cgi?id=6609
2932    assert(parse!int(s = "-42", 10) == -42);
2933
2934    assert(parse!ubyte(s = "ff", 16) == 0xFF);
2935}
2936
2937// https://issues.dlang.org/show_bug.cgi?id=7302
2938@safe pure unittest
2939{
2940    import std.range : cycle;
2941    auto r = cycle("2A!");
2942    auto u = parse!uint(r, 16);
2943    assert(u == 42);
2944    assert(r.front == '!');
2945
2946    auto r2 = cycle("2A!");
2947    auto u2 = parse!(uint, typeof(r2), Yes.doCount)(r2, 16);
2948    assert(u2.data == 42 && u2.count == 2);
2949    assert(r2.front == '!');
2950}
2951
2952// https://issues.dlang.org/show_bug.cgi?id=13163
2953@safe pure unittest
2954{
2955    import std.exception;
2956    foreach (s; ["fff", "123"])
2957        assertThrown!ConvOverflowException(s.parse!ubyte(16));
2958}
2959
2960// https://issues.dlang.org/show_bug.cgi?id=17282
2961@safe pure unittest
2962{
2963    auto str = "0=\x00\x02\x55\x40&\xff\xf0\n\x00\x04\x55\x40\xff\xf0~4+10\n";
2964    assert(parse!uint(str) == 0);
2965
2966    str = "0=\x00\x02\x55\x40&\xff\xf0\n\x00\x04\x55\x40\xff\xf0~4+10\n";
2967    assert(parse!(uint, string, Yes.doCount)(str) == tuple(0, 1));
2968}
2969
2970// https://issues.dlang.org/show_bug.cgi?id=18248
2971@safe pure unittest
2972{
2973    import std.exception : assertThrown;
2974
2975    auto str = ";";
2976    assertThrown(str.parse!uint(16));
2977    assertThrown(str.parse!(uint, string, Yes.doCount)(16));
2978}
2979
2980/**
2981 * Takes a string representing an `enum` type and returns that type.
2982 *
2983 * Params:
2984 *     Target = the `enum` type to convert to
2985 *     s = the lvalue of the range to _parse
2986 *     doCount = the flag for deciding to report the number of consumed characters
2987 *
2988 * Returns:
2989 $(UL
2990 *     $(LI An `enum` of type `Target` if `doCount` is set to `No.doCount`)
2991 *     $(LI A `tuple` containing an `enum` of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
2992 *
2993 * Throws:
2994 *     A $(LREF ConvException) if type `Target` does not have a member
2995 *     represented by `s`.
2996 */
2997auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
2998if (isSomeString!Source && !is(Source == enum) &&
2999    is(Target == enum))
3000{
3001    import std.algorithm.searching : startsWith;
3002    import std.traits : Unqual, EnumMembers;
3003
3004    Unqual!Target result;
3005    size_t longest_match = 0;
3006
3007    foreach (i, e; EnumMembers!Target)
3008    {
3009        auto ident = __traits(allMembers, Target)[i];
3010        if (longest_match < ident.length && s.startsWith(ident))
3011        {
3012            result = e;
3013            longest_match = ident.length ;
3014        }
3015    }
3016
3017    if (longest_match > 0)
3018    {
3019        s = s[longest_match .. $];
3020        static if (doCount)
3021        {
3022            return tuple!("data", "count")(result, longest_match);
3023        }
3024        else
3025        {
3026            return result;
3027        }
3028    }
3029
3030    throw new ConvException(
3031        Target.stringof ~ " does not have a member named '"
3032        ~ to!string(s) ~ "'");
3033}
3034
3035///
3036@safe unittest
3037{
3038    import std.typecons : Flag, Yes, No, tuple;
3039    enum EnumType : bool { a = true, b = false, c = a }
3040
3041    auto str = "a";
3042    assert(parse!EnumType(str) == EnumType.a);
3043    auto str2 = "a";
3044    assert(parse!(EnumType, string, No.doCount)(str2) == EnumType.a);
3045    auto str3 = "a";
3046    assert(parse!(EnumType, string, Yes.doCount)(str3) == tuple(EnumType.a, 1));
3047
3048}
3049
3050@safe unittest
3051{
3052    import std.exception;
3053
3054    enum EB : bool { a = true, b = false, c = a }
3055    enum EU { a, b, c }
3056    enum EI { a = -1, b = 0, c = 1 }
3057    enum EF : real { a = 1.414, b = 1.732, c = 2.236 }
3058    enum EC : char { a = 'a', b = 'b', c = 'c' }
3059    enum ES : string { a = "aaa", b = "bbb", c = "ccc" }
3060
3061    static foreach (E; AliasSeq!(EB, EU, EI, EF, EC, ES))
3062    {
3063        assert(to!E("a"c) == E.a);
3064        assert(to!E("b"w) == E.b);
3065        assert(to!E("c"d) == E.c);
3066
3067        assert(to!(const E)("a") == E.a);
3068        assert(to!(immutable E)("a") == E.a);
3069        assert(to!(shared E)("a") == E.a);
3070
3071        assertThrown!ConvException(to!E("d"));
3072    }
3073}
3074
3075// https://issues.dlang.org/show_bug.cgi?id=4744
3076@safe pure unittest
3077{
3078    enum A { member1, member11, member111 }
3079    assert(to!A("member1"  ) == A.member1  );
3080    assert(to!A("member11" ) == A.member11 );
3081    assert(to!A("member111") == A.member111);
3082    auto s = "member1111";
3083    assert(parse!A(s) == A.member111 && s == "1");
3084    auto s2 = "member1111";
3085    assert(parse!(A, string, No.doCount)(s2) == A.member111 && s2 == "1");
3086    auto s3 = "member1111";
3087    assert(parse!(A, string, Yes.doCount)(s3) == tuple(A.member111, 9) && s3 == "1");
3088}
3089
3090/**
3091 * Parses a character range to a floating point number.
3092 *
3093 * Params:
3094 *     Target = a floating point type
3095 *     source = the lvalue of the range to _parse
3096 *     doCount = the flag for deciding to report the number of consumed characters
3097 *
3098 * Returns:
3099 $(UL
3100 *     $(LI A floating point number of type `Target` if `doCount` is set to `No.doCount`)
3101 *     $(LI A `tuple` containing a floating point number of��type `Target` and a `size_t`
3102 *     if `doCount` is set to `Yes.doCount`))
3103 *
3104 * Throws:
3105 *     A $(LREF ConvException) if `source` is empty, if no number could be
3106 *     parsed, or if an overflow occurred.
3107 */
3108auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
3109if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
3110    isFloatingPoint!Target && !is(Target == enum))
3111{
3112    import std.ascii : isDigit, isAlpha, toLower, toUpper, isHexDigit;
3113    import std.exception : enforce;
3114
3115    static if (isNarrowString!Source)
3116    {
3117        import std.string : representation;
3118        scope p = source.representation;
3119    }
3120    else
3121    {
3122        alias p = source;
3123    }
3124
3125    void advanceSource()
3126    {
3127        static if (isNarrowString!Source)
3128            source = source[$ - p.length .. $];
3129    }
3130
3131    static immutable real[14] negtab =
3132        [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L,
3133                1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ];
3134    static immutable real[13] postab =
3135        [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L,
3136                1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ];
3137
3138    ConvException bailOut()(string msg = null, string fn = __FILE__, size_t ln = __LINE__)
3139    {
3140        if (msg == null)
3141            msg = "Floating point conversion error";
3142        return new ConvException(text(msg, " for input \"", source, "\"."), fn, ln);
3143    }
3144
3145    enforce(!p.empty, bailOut());
3146
3147
3148    size_t count = 0;
3149    bool sign = false;
3150    switch (p.front)
3151    {
3152    case '-':
3153        sign = true;
3154        ++count;
3155        p.popFront();
3156        enforce(!p.empty, bailOut());
3157        if (toLower(p.front) == 'i')
3158            goto case 'i';
3159        break;
3160    case '+':
3161        ++count;
3162        p.popFront();
3163        enforce(!p.empty, bailOut());
3164        break;
3165    case 'i': case 'I':
3166        // inf
3167        ++count;
3168        p.popFront();
3169        enforce(!p.empty && toUpper(p.front) == 'N',
3170               bailOut("error converting input to floating point"));
3171        ++count;
3172        p.popFront();
3173        enforce(!p.empty && toUpper(p.front) == 'F',
3174               bailOut("error converting input to floating point"));
3175        // skip past the last 'f'
3176        ++count;
3177        p.popFront();
3178        advanceSource();
3179        static if (doCount)
3180        {
3181            return tuple!("data", "count")(sign ? -Target.infinity : Target.infinity, count);
3182        }
3183        else
3184        {
3185            return sign ? -Target.infinity : Target.infinity;
3186        }
3187    default: {}
3188    }
3189
3190    bool isHex = false;
3191    bool startsWithZero = p.front == '0';
3192    if (startsWithZero)
3193    {
3194        ++count;
3195        p.popFront();
3196        if (p.empty)
3197        {
3198            advanceSource();
3199            static if (doCount)
3200            {
3201                return tuple!("data", "count")(cast (Target) (sign ? -0.0 : 0.0), count);
3202            }
3203            else
3204            {
3205                return sign ? -0.0 : 0.0;
3206            }
3207        }
3208
3209        isHex = p.front == 'x' || p.front == 'X';
3210        if (isHex)
3211        {
3212            ++count;
3213            p.popFront();
3214        }
3215    }
3216    else if (toLower(p.front) == 'n')
3217    {
3218        // nan
3219        ++count;
3220        p.popFront();
3221        enforce(!p.empty && toUpper(p.front) == 'A',
3222               bailOut("error converting input to floating point"));
3223        ++count;
3224        p.popFront();
3225        enforce(!p.empty && toUpper(p.front) == 'N',
3226               bailOut("error converting input to floating point"));
3227        // skip past the last 'n'
3228        ++count;
3229        p.popFront();
3230        advanceSource();
3231        static if (doCount)
3232        {
3233            return tuple!("data", "count")(Target.nan, count);
3234        }
3235        else
3236        {
3237            return typeof(return).nan;
3238        }
3239    }
3240
3241    /*
3242     * The following algorithm consists of 2 steps:
3243     * 1) parseDigits processes the textual input into msdec and possibly
3244     *    lsdec/msscale variables, followed by the exponent parser which sets
3245     *    exp below.
3246     *    Hex: input is 0xaaaaa...p+000... where aaaa is the mantissa in hex
3247     *    and 000 is the exponent in decimal format with base 2.
3248     *    Decimal: input is 0.00333...p+000... where 0.0033 is the mantissa
3249     *    in decimal and 000 is the exponent in decimal format with base 10.
3250     * 2) Convert msdec/lsdec and exp into native real format
3251     */
3252
3253    real ldval = 0.0;
3254    char dot = 0;                        /* if decimal point has been seen */
3255    int exp = 0;
3256    ulong msdec = 0, lsdec = 0;
3257    ulong msscale = 1;
3258    bool sawDigits;
3259
3260    enum { hex, decimal }
3261
3262    // sets msdec, lsdec/msscale, and sawDigits by parsing the mantissa digits
3263    void parseDigits(alias FloatFormat)()
3264    {
3265        static if (FloatFormat == hex)
3266        {
3267            enum uint base = 16;
3268            enum ulong msscaleMax = 0x1000_0000_0000_0000UL; // largest power of 16 a ulong holds
3269            enum ubyte expIter = 4; // iterate the base-2 exponent by 4 for every hex digit
3270            alias checkDigit = isHexDigit;
3271            /*
3272             * convert letter to binary representation: First clear bit
3273             * to convert lower space chars to upperspace, then -('A'-10)
3274             * converts letter A to 10, letter B to 11, ...
3275             */
3276            alias convertDigit = (int x) => isAlpha(x) ? ((x & ~0x20) - ('A' - 10)) : x - '0';
3277            sawDigits = false;
3278        }
3279        else static if (FloatFormat == decimal)
3280        {
3281            enum uint base = 10;
3282            enum ulong msscaleMax = 10_000_000_000_000_000_000UL; // largest power of 10 a ulong holds
3283            enum ubyte expIter = 1; // iterate the base-10 exponent once for every decimal digit
3284            alias checkDigit = isDigit;
3285            alias convertDigit = (int x) => x - '0';
3286            // Used to enforce that any mantissa digits are present
3287            sawDigits = startsWithZero;
3288        }
3289        else
3290            static assert(false, "Unrecognized floating-point format used.");
3291
3292        while (!p.empty)
3293        {
3294            int i = p.front;
3295            while (checkDigit(i))
3296            {
3297                sawDigits = true;        /* must have at least 1 digit   */
3298
3299                i = convertDigit(i);
3300
3301                if (msdec < (ulong.max - base)/base)
3302                {
3303                    // For base 16: Y = ... + y3*16^3 + y2*16^2 + y1*16^1 + y0*16^0
3304                    msdec = msdec * base + i;
3305                }
3306                else if (msscale < msscaleMax)
3307                {
3308                    lsdec = lsdec * base + i;
3309                    msscale *= base;
3310                }
3311                else
3312                {
3313                    exp += expIter;
3314                }
3315                exp -= dot;
3316                ++count;
3317                p.popFront();
3318                if (p.empty)
3319                    break;
3320                i = p.front;
3321                if (i == '_')
3322                {
3323                    ++count;
3324                    p.popFront();
3325                    if (p.empty)
3326                        break;
3327                    i = p.front;
3328                }
3329            }
3330            if (i == '.' && !dot)
3331            {
3332                ++count;
3333                p.popFront();
3334                dot += expIter;
3335            }
3336            else
3337                break;
3338        }
3339
3340        // Have we seen any mantissa digits so far?
3341        enforce(sawDigits, bailOut("no digits seen"));
3342        static if (FloatFormat == hex)
3343            enforce(!p.empty && (p.front == 'p' || p.front == 'P'),
3344                    bailOut("Floating point parsing: exponent is required"));
3345    }
3346
3347    if (isHex)
3348        parseDigits!hex;
3349    else
3350        parseDigits!decimal;
3351
3352    if (isHex || (!p.empty && (p.front == 'e' || p.front == 'E')))
3353    {
3354        char sexp = 0;
3355        int e = 0;
3356
3357        ++count;
3358        p.popFront();
3359        enforce(!p.empty, new ConvException("Unexpected end of input"));
3360        switch (p.front)
3361        {
3362            case '-':    sexp++;
3363                         goto case;
3364            case '+':    ++count;
3365                         p.popFront();
3366                         break;
3367            default: {}
3368        }
3369        sawDigits = false;
3370        while (!p.empty && isDigit(p.front))
3371        {
3372            if (e < 0x7FFFFFFF / 10 - 10)   // prevent integer overflow
3373            {
3374                e = e * 10 + p.front - '0';
3375            }
3376            ++count;
3377            p.popFront();
3378            sawDigits = true;
3379        }
3380        exp += (sexp) ? -e : e;
3381        enforce(sawDigits, new ConvException("No digits seen."));
3382    }
3383
3384    ldval = msdec;
3385    if (msscale != 1)               /* if stuff was accumulated in lsdec */
3386        ldval = ldval * msscale + lsdec;
3387    if (isHex)
3388    {
3389        import core.math : ldexp;
3390
3391        // Exponent is power of 2, not power of 10
3392        ldval = ldexp(ldval,exp);
3393    }
3394    else if (ldval)
3395    {
3396        uint u = 0;
3397        int pow = 4096;
3398
3399        while (exp > 0)
3400        {
3401            while (exp >= pow)
3402            {
3403                ldval *= postab[u];
3404                exp -= pow;
3405            }
3406            pow >>= 1;
3407            u++;
3408        }
3409        while (exp < 0)
3410        {
3411            while (exp <= -pow)
3412            {
3413                ldval *= negtab[u];
3414                enforce(ldval != 0, new ConvException("Range error"));
3415                exp += pow;
3416            }
3417            pow >>= 1;
3418            u++;
3419        }
3420    }
3421
3422    // if overflow occurred
3423    enforce(ldval != real.infinity, new ConvException("Range error"));
3424
3425    advanceSource();
3426    static if (doCount)
3427    {
3428        return tuple!("data", "count")(cast (Target) (sign ? -ldval : ldval), count);
3429    }
3430    else
3431    {
3432        return cast (Target) (sign ? -ldval : ldval);
3433    }
3434}
3435
3436
3437///
3438@safe unittest
3439{
3440    import std.math.operations : isClose;
3441    import std.math.traits : isNaN, isInfinity;
3442    import std.typecons : Flag, Yes, No;
3443    auto str = "123.456";
3444    assert(parse!double(str).isClose(123.456));
3445    auto str2 = "123.456";
3446    assert(parse!(double, string, No.doCount)(str2).isClose(123.456));
3447    auto str3 = "123.456";
3448    auto r = parse!(double, string, Yes.doCount)(str3);
3449    assert(r.data.isClose(123.456));
3450    assert(r.count == 7);
3451    auto str4 = "-123.456";
3452    r = parse!(double, string, Yes.doCount)(str4);
3453    assert(r.data.isClose(-123.456));
3454    assert(r.count == 8);
3455    auto str5 = "+123.456";
3456    r = parse!(double, string, Yes.doCount)(str5);
3457    assert(r.data.isClose(123.456));
3458    assert(r.count == 8);
3459    auto str6 = "inf0";
3460    r = parse!(double, string, Yes.doCount)(str6);
3461    assert(isInfinity(r.data) && r.count == 3 && str6 == "0");
3462    auto str7 = "-0";
3463    auto r2 = parse!(float, string, Yes.doCount)(str7);
3464    assert(r2.data.isClose(0.0) && r2.count == 2);
3465    auto str8 = "nan";
3466    auto r3 = parse!(real, string, Yes.doCount)(str8);
3467    assert(isNaN(r3.data) && r3.count == 3);
3468}
3469
3470@safe unittest
3471{
3472    import std.exception;
3473    import std.math.traits : isNaN, isInfinity;
3474    import std.math.algebraic : fabs;
3475
3476    // Compare reals with given precision
3477    bool feq(in real rx, in real ry, in real precision = 0.000001L)
3478    {
3479        if (rx == ry)
3480            return 1;
3481
3482        if (isNaN(rx))
3483            return cast(bool) isNaN(ry);
3484
3485        if (isNaN(ry))
3486            return 0;
3487
3488        return cast(bool)(fabs(rx - ry) <= precision);
3489    }
3490
3491    // Make given typed literal
3492    F Literal(F)(F f)
3493    {
3494        return f;
3495    }
3496
3497    static foreach (Float; AliasSeq!(float, double, real))
3498    {
3499        assert(to!Float("123") == Literal!Float(123));
3500        assert(to!Float("+123") == Literal!Float(+123));
3501        assert(to!Float("-123") == Literal!Float(-123));
3502        assert(to!Float("123e2") == Literal!Float(123e2));
3503        assert(to!Float("123e+2") == Literal!Float(123e+2));
3504        assert(to!Float("123e-2") == Literal!Float(123e-2L));
3505        assert(to!Float("123.") == Literal!Float(123.0));
3506        assert(to!Float(".375") == Literal!Float(.375));
3507
3508        assert(to!Float("1.23375E+2") == Literal!Float(1.23375E+2));
3509
3510        assert(to!Float("0") is 0.0);
3511        assert(to!Float("-0") is -0.0);
3512
3513        assert(isNaN(to!Float("nan")));
3514
3515        assertThrown!ConvException(to!Float("\x00"));
3516    }
3517
3518    // min and max
3519    float f = to!float("1.17549e-38");
3520    assert(feq(cast(real) f, cast(real) 1.17549e-38));
3521    assert(feq(cast(real) f, cast(real) float.min_normal));
3522    f = to!float("3.40282e+38");
3523    assert(to!string(f) == to!string(3.40282e+38));
3524
3525    // min and max
3526    double d = to!double("2.22508e-308");
3527    assert(feq(cast(real) d, cast(real) 2.22508e-308));
3528    assert(feq(cast(real) d, cast(real) double.min_normal));
3529    d = to!double("1.79769e+308");
3530    assert(to!string(d) == to!string(1.79769e+308));
3531    assert(to!string(d) == to!string(double.max));
3532
3533    auto z = real.max / 2L;
3534    static assert(is(typeof(z) == real));
3535    assert(!isNaN(z));
3536    assert(!isInfinity(z));
3537    string a = to!string(z);
3538    real b = to!real(a);
3539    string c = to!string(b);
3540
3541    assert(c == a, "\n" ~ c ~ "\n" ~ a);
3542
3543    assert(to!string(to!real(to!string(real.max / 2L))) == to!string(real.max / 2L));
3544
3545    // min and max
3546    real r = to!real(to!string(real.min_normal));
3547    version (NetBSD)
3548    {
3549        // NetBSD notice
3550        // to!string returns 3.3621e-4932L. It is less than real.min_normal and it is subnormal value
3551        // Simple C code
3552        //     long double rd = 3.3621e-4932L;
3553        //     printf("%Le\n", rd);
3554        // has unexpected result: 1.681050e-4932
3555        //
3556        // Bug report: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50937
3557    }
3558    else
3559    {
3560        assert(to!string(r) == to!string(real.min_normal));
3561    }
3562    r = to!real(to!string(real.max));
3563    assert(to!string(r) == to!string(real.max));
3564
3565    real pi = 3.1415926535897932384626433832795028841971693993751L;
3566    string fullPrecision = "3.1415926535897932384626433832795028841971693993751";
3567    assert(feq(parse!real(fullPrecision), pi, 2*real.epsilon));
3568    string fullPrecision2 = "3.1415926535897932384626433832795028841971693993751";
3569    assert(feq(parse!(real, string, No.doCount)(fullPrecision2), pi, 2*real.epsilon));
3570    string fullPrecision3= "3.1415926535897932384626433832795028841971693993751";
3571    auto len = fullPrecision3.length;
3572    auto res = parse!(real, string, Yes.doCount)(fullPrecision3);
3573    assert(feq(res.data, pi, 2*real.epsilon));
3574    assert(res.count == len);
3575
3576    real x = 0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252L;
3577    string full = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3578    assert(parse!real(full) == x);
3579    string full2 = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3580    assert(parse!(real, string, No.doCount)(full2) == x);
3581    string full3 = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3582    auto len2 = full3.length;
3583    assert(parse!(real, string, Yes.doCount)(full3) == tuple(x, len2));
3584}
3585
3586// Tests for the double implementation
3587@system unittest
3588{
3589    // @system because strtod is not @safe.
3590    import std.math : floatTraits, RealFormat;
3591
3592    static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3593    {
3594        import core.stdc.stdlib, std.exception, std.math;
3595
3596        //Should be parsed exactly: 53 bit mantissa
3597        string s = "0x1A_BCDE_F012_3456p10";
3598        auto x = parse!real(s);
3599        assert(x == 0x1A_BCDE_F012_3456p10L);
3600        //1 bit is implicit
3601        assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0xA_BCDE_F012_3456);
3602        assert(strtod("0x1ABCDEF0123456p10", null) == x);
3603
3604        s = "0x1A_BCDE_F012_3456p10";
3605        auto len = s.length;
3606        assert(parse!(real, string, Yes.doCount)(s) == tuple(x, len));
3607
3608        //Should be parsed exactly: 10 bit mantissa
3609        s = "0x3FFp10";
3610        x = parse!real(s);
3611        assert(x == 0x03FFp10);
3612        //1 bit is implicit
3613        assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_F800_0000_0000);
3614        assert(strtod("0x3FFp10", null) == x);
3615
3616        //60 bit mantissa, round up
3617        s = "0xFFF_FFFF_FFFF_FFFFp10";
3618        x = parse!real(s);
3619        assert(isClose(x, 0xFFF_FFFF_FFFF_FFFFp10));
3620        //1 bit is implicit
3621        assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x0000_0000_0000_0000);
3622        assert(strtod("0xFFFFFFFFFFFFFFFp10", null) == x);
3623
3624        //60 bit mantissa, round down
3625        s = "0xFFF_FFFF_FFFF_FF90p10";
3626        x = parse!real(s);
3627        assert(isClose(x, 0xFFF_FFFF_FFFF_FF90p10));
3628        //1 bit is implicit
3629        assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_FFFF_FFFF_FFFF);
3630        assert(strtod("0xFFFFFFFFFFFFF90p10", null) == x);
3631
3632        //61 bit mantissa, round up 2
3633        s = "0x1F0F_FFFF_FFFF_FFFFp10";
3634        x = parse!real(s);
3635        assert(isClose(x, 0x1F0F_FFFF_FFFF_FFFFp10));
3636        //1 bit is implicit
3637        assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_1000_0000_0000);
3638        assert(strtod("0x1F0FFFFFFFFFFFFFp10", null) == x);
3639
3640        //61 bit mantissa, round down 2
3641        s = "0x1F0F_FFFF_FFFF_FF10p10";
3642        x = parse!real(s);
3643        assert(isClose(x, 0x1F0F_FFFF_FFFF_FF10p10));
3644        //1 bit is implicit
3645        assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_0FFF_FFFF_FFFF);
3646        assert(strtod("0x1F0FFFFFFFFFFF10p10", null) == x);
3647
3648        //Huge exponent
3649        s = "0x1F_FFFF_FFFF_FFFFp900";
3650        x = parse!real(s);
3651        assert(strtod("0x1FFFFFFFFFFFFFp900", null) == x);
3652
3653        //exponent too big -> converror
3654        s = "";
3655        assertThrown!ConvException(x = parse!real(s));
3656        assert(strtod("0x1FFFFFFFFFFFFFp1024", null) == real.infinity);
3657
3658        //-exponent too big -> 0
3659        s = "0x1FFFFFFFFFFFFFp-2000";
3660        x = parse!real(s);
3661        assert(x == 0);
3662        assert(strtod("0x1FFFFFFFFFFFFFp-2000", null) == x);
3663
3664        s = "0x1FFFFFFFFFFFFFp-2000";
3665        len = s.length;
3666        assert(parse!(real, string, Yes.doCount)(s) == tuple(x, len));
3667    }
3668}
3669
3670@system unittest
3671{
3672    import core.stdc.errno;
3673    import core.stdc.stdlib;
3674    import std.math : floatTraits, RealFormat;
3675
3676    errno = 0;  // In case it was set by another unittest in a different module.
3677    struct longdouble
3678    {
3679        static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple)
3680        {
3681            ushort[8] value;
3682        }
3683        else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended ||
3684                        floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3685        {
3686            ushort[5] value;
3687        }
3688        else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3689        {
3690            ushort[4] value;
3691        }
3692        else
3693            static assert(false, "Not implemented");
3694    }
3695
3696    real ld;
3697    longdouble x;
3698    real ld1;
3699    longdouble x1;
3700    int i;
3701
3702    static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple)
3703        enum s = "0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp-16382";
3704    else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended)
3705        enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
3706    else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3707        enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
3708    else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3709        enum s = "0x1.FFFFFFFFFFFFFFFEp-1000";
3710    else
3711        static assert(false, "Floating point format for real not supported");
3712
3713    auto s2 = s.idup;
3714    ld = parse!real(s2);
3715    assert(s2.empty);
3716    x = *cast(longdouble *)&ld;
3717
3718    static if (floatTraits!real.realFormat == RealFormat.ieeeExtended)
3719    {
3720        version (CRuntime_Microsoft)
3721            ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod
3722        else
3723            ld1 = strtold(s.ptr, null);
3724    }
3725    else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3726        ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold rounds to 53 bits.
3727    else
3728        ld1 = strtold(s.ptr, null);
3729
3730    x1 = *cast(longdouble *)&ld1;
3731    assert(x1 == x && ld1 == ld);
3732
3733    assert(!errno);
3734
3735    s2 = "1.0e5";
3736    ld = parse!real(s2);
3737    assert(s2.empty);
3738    x = *cast(longdouble *)&ld;
3739    ld1 = strtold("1.0e5", null);
3740    x1 = *cast(longdouble *)&ld1;
3741}
3742
3743@safe pure unittest
3744{
3745    import std.exception;
3746
3747    // https://issues.dlang.org/show_bug.cgi?id=4959
3748    {
3749        auto s = "0 ";
3750        auto x = parse!double(s);
3751        assert(s == " ");
3752        assert(x == 0.0);
3753    }
3754    {
3755        auto s = "0 ";
3756        auto x = parse!(double, string, Yes.doCount)(s);
3757        assert(s == " ");
3758        assert(x == tuple(0.0, 1));
3759    }
3760
3761    // https://issues.dlang.org/show_bug.cgi?id=3369
3762    assert(to!float("inf") == float.infinity);
3763    assert(to!float("-inf") == -float.infinity);
3764
3765    // https://issues.dlang.org/show_bug.cgi?id=6160
3766    assert(6_5.536e3L == to!real("6_5.536e3"));                     // 2^16
3767    assert(0x1000_000_000_p10 == to!real("0x1000_000_000_p10"));    // 7.03687e+13
3768
3769    // https://issues.dlang.org/show_bug.cgi?id=6258
3770    assertThrown!ConvException(to!real("-"));
3771    assertThrown!ConvException(to!real("in"));
3772
3773    // https://issues.dlang.org/show_bug.cgi?id=7055
3774    assertThrown!ConvException(to!float("INF2"));
3775
3776    //extra stress testing
3777    auto ssOK    = ["1.", "1.1.1", "1.e5", "2e1e", "2a", "2e1_1", "3.4_",
3778                    "inf", "-inf", "infa", "-infa", "inf2e2", "-inf2e2",
3779                    "nan", "-NAN", "+NaN", "-nAna", "NAn2e2", "-naN2e2"];
3780    auto ssKO    = ["", " ", "2e", "2e+", "2e-", "2ee", "2e++1", "2e--1", "2e_1",
3781                    "+inf", "-in", "I", "+N", "-NaD", "0x3.F"];
3782    foreach (s; ssOK)
3783        parse!double(s);
3784    foreach (s; ssKO)
3785        assertThrown!ConvException(parse!double(s));
3786}
3787
3788/**
3789Parsing one character off a range returns the first element and calls `popFront`.
3790
3791Params:
3792    Target = the type to convert to
3793    s = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3794    doCount = the flag for deciding to report the number of consumed characters
3795
3796Returns:
3797$(UL
3798    $(LI A character of type `Target` if `doCount` is set to `No.doCount`)
3799    $(LI A `tuple` containing a character of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
3800
3801Throws:
3802    A $(LREF ConvException) if the range is empty.
3803 */
3804auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3805if (isSomeString!Source && !is(Source == enum) &&
3806    staticIndexOf!(immutable Target, immutable dchar, immutable ElementEncodingType!Source) >= 0)
3807{
3808    if (s.empty)
3809        throw convError!(Source, Target)(s);
3810    static if (is(immutable Target == immutable dchar))
3811    {
3812        Target result = s.front;
3813        s.popFront();
3814        static if (doCount)
3815        {
3816            return tuple!("data", "count")(result, 1);
3817        }
3818        else
3819        {
3820            return result;
3821        }
3822
3823    }
3824    else
3825    {
3826        // Special case: okay so parse a Char off a Char[]
3827        Target result = s[0];
3828        s = s[1 .. $];
3829        static if (doCount)
3830        {
3831            return tuple!("data", "count")(result, 1);
3832        }
3833        else
3834        {
3835            return result;
3836        }
3837    }
3838}
3839
3840@safe pure unittest
3841{
3842    static foreach (Str; AliasSeq!(string, wstring, dstring))
3843    {
3844        static foreach (Char; AliasSeq!(char, wchar, dchar))
3845        {{
3846            static if (is(immutable Char == immutable dchar) ||
3847                       Char.sizeof == ElementEncodingType!Str.sizeof)
3848            {
3849                Str s = "aaa";
3850                assert(parse!Char(s) == 'a');
3851                assert(s == "aa");
3852                assert(parse!(Char, typeof(s), No.doCount)(s) == 'a');
3853                assert(s == "a");
3854                assert(parse!(Char, typeof(s), Yes.doCount)(s) == tuple('a', 1) && s == "");
3855            }
3856        }}
3857    }
3858}
3859
3860/// ditto
3861auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3862if (!isSomeString!Source && isInputRange!Source && isSomeChar!(ElementType!Source) &&
3863    isSomeChar!Target && Target.sizeof >= ElementType!Source.sizeof && !is(Target == enum))
3864{
3865    if (s.empty)
3866        throw convError!(Source, Target)(s);
3867    Target result = s.front;
3868    s.popFront();
3869    static if (doCount)
3870    {
3871        return tuple!("data", "count")(result, 1);
3872    }
3873    else
3874    {
3875        return result;
3876    }
3877}
3878
3879///
3880@safe pure unittest
3881{
3882    import std.typecons : Flag, Yes, No;
3883    auto s = "Hello, World!";
3884    char first = parse!char(s);
3885    assert(first == 'H');
3886    assert(s == "ello, World!");
3887    char second = parse!(char, string, No.doCount)(s);
3888    assert(second == 'e');
3889    assert(s == "llo, World!");
3890    auto third = parse!(char, string, Yes.doCount)(s);
3891    assert(third.data == 'l' && third.count == 1);
3892    assert(s == "lo, World!");
3893}
3894
3895
3896/*
3897    Tests for to!bool and parse!bool
3898*/
3899@safe pure unittest
3900{
3901    import std.exception;
3902
3903    assert(to!bool("TruE") == true);
3904    assert(to!bool("faLse"d) == false);
3905    assertThrown!ConvException(to!bool("maybe"));
3906
3907    auto t = "TrueType";
3908    assert(parse!bool(t) == true);
3909    assert(t == "Type");
3910
3911    auto f = "False killer whale"d;
3912    assert(parse!bool(f) == false);
3913    assert(f == " killer whale"d);
3914
3915    f = "False killer whale"d;
3916    assert(parse!(bool, dstring, Yes.doCount)(f) == tuple(false, 5));
3917    assert(f == " killer whale"d);
3918
3919    auto m = "maybe";
3920    assertThrown!ConvException(parse!bool(m));
3921    assertThrown!ConvException(parse!(bool, string, Yes.doCount)(m));
3922    assert(m == "maybe");  // m shouldn't change on failure
3923
3924    auto s = "true";
3925    auto b = parse!(const(bool))(s);
3926    assert(b == true);
3927}
3928
3929/**
3930Parsing a character range to `typeof(null)` returns `null` if the range
3931spells `"null"`. This function is case insensitive.
3932
3933Params:
3934    Target = the type to convert to
3935    s = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3936    doCount = the flag for deciding to report the number of consumed characters
3937
3938Returns:
3939$(UL
3940    $(LI `null` if `doCount` is set to `No.doCount`)
3941    $(LI A `tuple` containing `null` and a `size_t` if `doCount` is set to `Yes.doCount`))
3942
3943Throws:
3944    A $(LREF ConvException) if the range doesn't represent `null`.
3945 */
3946auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3947if (isInputRange!Source &&
3948    isSomeChar!(ElementType!Source) &&
3949    is(immutable Target == immutable typeof(null)))
3950{
3951    import std.ascii : toLower;
3952    foreach (c; "null")
3953    {
3954        if (s.empty || toLower(s.front) != c)
3955            throw parseError("null should be case-insensitive 'null'");
3956        s.popFront();
3957    }
3958    static if (doCount)
3959    {
3960        return tuple!("data", "count")(null, 4);
3961    }
3962    else
3963    {
3964        return null;
3965    }
3966}
3967
3968///
3969@safe pure unittest
3970{
3971    import std.exception : assertThrown;
3972    import std.typecons : Flag, Yes, No;
3973
3974    alias NullType = typeof(null);
3975    auto s1 = "null";
3976    assert(parse!NullType(s1) is null);
3977    assert(s1 == "");
3978
3979    auto s2 = "NUll"d;
3980    assert(parse!NullType(s2) is null);
3981    assert(s2 == "");
3982
3983    auto s3 = "nuLlNULl";
3984    assert(parse!(NullType, string, No.doCount)(s3) is null);
3985    auto r = parse!(NullType, string, Yes.doCount)(s3);
3986    assert(r.data is null && r.count == 4);
3987
3988    auto m = "maybe";
3989    assertThrown!ConvException(parse!NullType(m));
3990    assertThrown!ConvException(parse!(NullType, string, Yes.doCount)(m));
3991    assert(m == "maybe");  // m shouldn't change on failure
3992
3993    auto s = "NULL";
3994    assert(parse!(const NullType)(s) is null);
3995}
3996
3997//Used internally by parse Array/AA, to remove ascii whites
3998package auto skipWS(R, Flag!"doCount" doCount = No.doCount)(ref R r)
3999{
4000    import std.ascii : isWhite;
4001    static if (isSomeString!R)
4002    {
4003        //Implementation inspired from stripLeft.
4004        foreach (i, c; r)
4005        {
4006            if (!isWhite(c))
4007            {
4008                r = r[i .. $];
4009                static if (doCount)
4010                {
4011                    return i;
4012                }
4013                else
4014                {
4015                    return;
4016                }
4017            }
4018        }
4019        auto len = r.length;
4020        r = r[0 .. 0]; //Empty string with correct type.
4021        static if (doCount)
4022        {
4023            return len;
4024        }
4025        else
4026        {
4027            return;
4028        }
4029    }
4030    else
4031    {
4032        size_t i = 0;
4033        for (; !r.empty && isWhite(r.front); r.popFront(), ++i)
4034        { }
4035        static if (doCount)
4036        {
4037            return i;
4038        }
4039    }
4040}
4041
4042/**
4043 * Parses an array from a string given the left bracket (default $(D
4044 * '[')), right bracket (default `']'`), and element separator (by
4045 * default `','`). A trailing separator is allowed.
4046 *
4047 * Params:
4048 *     s = The string to parse
4049 *     lbracket = the character that starts the array
4050 *     rbracket = the character that ends the array
4051 *     comma = the character that separates the elements of the array
4052 *     doCount = the flag for deciding to report the number of consumed characters
4053 *
4054 * Returns:
4055 $(UL
4056 *     $(LI An array of type `Target` if `doCount` is set to `No.doCount`)
4057 *     $(LI A `tuple` containing an array of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
4058 */
4059auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4060    dchar rbracket = ']', dchar comma = ',')
4061if (isSomeString!Source && !is(Source == enum) &&
4062    isDynamicArray!Target && !is(Target == enum))
4063{
4064    import std.array : appender;
4065
4066    auto result = appender!Target();
4067
4068    parseCheck!s(lbracket);
4069    size_t count = 1 + skipWS!(Source, Yes.doCount)(s);
4070    if (s.empty)
4071        throw convError!(Source, Target)(s);
4072    if (s.front == rbracket)
4073    {
4074        s.popFront();
4075        static if (doCount)
4076        {
4077            return tuple!("data", "count")(result.data, ++count);
4078        }
4079        else
4080        {
4081            return result.data;
4082        }
4083    }
4084    for (;; s.popFront(), count += 1 + skipWS!(Source, Yes.doCount)(s))
4085    {
4086        if (!s.empty && s.front == rbracket)
4087            break;
4088        auto r = parseElement!(WideElementType!Target, Source, Yes.doCount)(s);
4089        result ~= r.data;
4090        count += r.count + skipWS!(Source, Yes.doCount)(s);
4091        if (s.empty)
4092            throw convError!(Source, Target)(s);
4093        if (s.front != comma)
4094            break;
4095    }
4096    parseCheck!s(rbracket);
4097    static if (doCount)
4098    {
4099        return tuple!("data", "count")(result.data, ++count);
4100    }
4101    else
4102    {
4103        return result.data;
4104    }
4105}
4106
4107///
4108@safe pure unittest
4109{
4110    import std.typecons : Flag, Yes, No;
4111    auto s1 = `[['h', 'e', 'l', 'l', 'o'], "world"]`;
4112    auto a1 = parse!(string[])(s1);
4113    assert(a1 == ["hello", "world"]);
4114
4115    auto s2 = `["aaa", "bbb", "ccc"]`;
4116    auto a2 = parse!(string[])(s2);
4117    assert(a2 == ["aaa", "bbb", "ccc"]);
4118
4119    auto s3 = `[['h', 'e', 'l', 'l', 'o'], "world"]`;
4120    auto len3 = s3.length;
4121    auto a3 = parse!(string[], string, Yes.doCount)(s3);
4122    assert(a3.data == ["hello", "world"]);
4123    assert(a3.count == len3);
4124}
4125
4126// https://issues.dlang.org/show_bug.cgi?id=9615
4127@safe unittest
4128{
4129    import std.typecons : Flag, Yes, No, tuple;
4130    string s0 = "[1,2, ]";
4131    string s1 = "[1,2, \t\v\r\n]";
4132    string s2 = "[1,2]";
4133    assert(s0.parse!(int[]) == [1,2]);
4134    assert(s1.parse!(int[]) == [1,2]);
4135    assert(s2.parse!(int[]) == [1,2]);
4136
4137    s0 = "[1,2, ]";
4138    auto len0 = s0.length;
4139    s1 = "[1,2, \t\v\r\n]";
4140    auto len1 = s1.length;
4141    s2 = "[1,2]";
4142    auto len2 = s2.length;
4143    assert(s0.parse!(int[], string, Yes.doCount) == tuple([1,2], len0));
4144    assert(s1.parse!(int[], string, Yes.doCount) == tuple([1,2], len1));
4145    assert(s2.parse!(int[], string, Yes.doCount) == tuple([1,2], len2));
4146
4147    string s3 = `["a","b",]`;
4148    string s4 = `["a","b"]`;
4149    assert(s3.parse!(string[]) == ["a","b"]);
4150    assert(s4.parse!(string[]) == ["a","b"]);
4151
4152    s3 = `["a","b",]`;
4153    auto len3 = s3.length;
4154    assert(s3.parse!(string[], string, Yes.doCount) == tuple(["a","b"], len3));
4155
4156    s3 = `[    ]`;
4157    assert(tuple([], s3.length) == s3.parse!(string[], string, Yes.doCount));
4158
4159    import std.exception : assertThrown;
4160    string s5 = "[,]";
4161    string s6 = "[, \t,]";
4162    assertThrown!ConvException(parse!(string[])(s5));
4163    assertThrown!ConvException(parse!(int[])(s6));
4164
4165    s5 = "[,]";
4166    s6 = "[,��\t,]";
4167    assertThrown!ConvException(parse!(string[], string, Yes.doCount)(s5));
4168    assertThrown!ConvException(parse!(string[], string, Yes.doCount)(s6));
4169}
4170
4171@safe unittest
4172{
4173    int[] a = [1, 2, 3, 4, 5];
4174    auto s = to!string(a);
4175    assert(to!(int[])(s) == a);
4176}
4177
4178@safe unittest
4179{
4180    int[][] a = [ [1, 2] , [3], [4, 5] ];
4181    auto s = to!string(a);
4182    assert(to!(int[][])(s) == a);
4183}
4184
4185@safe unittest
4186{
4187    int[][][] ia = [ [[1,2],[3,4],[5]] , [[6],[],[7,8,9]] , [[]] ];
4188
4189    char[] s = to!(char[])(ia);
4190    int[][][] ia2;
4191
4192    ia2 = to!(typeof(ia2))(s);
4193    assert( ia == ia2);
4194}
4195
4196@safe pure unittest
4197{
4198    import std.exception;
4199    import std.typecons : Flag, Yes, No;
4200
4201    //Check proper failure
4202    auto s = "[ 1 , 2 , 3 ]";
4203    auto s2 = s.save;
4204    foreach (i ; 0 .. s.length-1)
4205    {
4206        auto ss = s[0 .. i];
4207        assertThrown!ConvException(parse!(int[])(ss));
4208        assertThrown!ConvException(parse!(int[], string, Yes.doCount)(ss));
4209    }
4210    int[] arr = parse!(int[])(s);
4211    auto arr2 = parse!(int[], string, Yes.doCount)(s2);
4212    arr = arr2.data;
4213}
4214
4215@safe pure unittest
4216{
4217    //Checks parsing of strings with escaped characters
4218    string s1 = `[
4219        "Contains a\0null!",
4220        "tab\there",
4221        "line\nbreak",
4222        "backslash \\ slash / question \?",
4223        "number \x35 five",
4224        "unicode \u65E5 sun",
4225        "very long \U000065E5 sun"
4226    ]`;
4227
4228    //Note: escaped characters purposefully replaced and isolated to guarantee
4229    //there are no typos in the escape syntax
4230    string[] s2 = [
4231        "Contains a" ~ '\0' ~ "null!",
4232        "tab" ~ '\t' ~ "here",
4233        "line" ~ '\n' ~ "break",
4234        "backslash " ~ '\\' ~ " slash / question ?",
4235        "number 5 five",
4236        "unicode ��� sun",
4237        "very long ��� sun"
4238    ];
4239    string s3 = s1.save;
4240    assert(s2 == parse!(string[])(s1));
4241    assert(s1.empty);
4242    assert(tuple(s2, s3.length) == parse!(string[], string, Yes.doCount)(s3));
4243}
4244
4245/// ditto
4246auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4247    dchar rbracket = ']', dchar comma = ',')
4248if (isExactSomeString!Source &&
4249    isStaticArray!Target && !is(Target == enum))
4250{
4251    static if (hasIndirections!Target)
4252        Target result = Target.init[0].init;
4253    else
4254        Target result = void;
4255
4256    parseCheck!s(lbracket);
4257    size_t count = 1 + skipWS!(Source, Yes.doCount)(s);
4258    if (s.empty)
4259        throw convError!(Source, Target)(s);
4260    if (s.front == rbracket)
4261    {
4262        static if (result.length != 0)
4263            goto Lmanyerr;
4264        else
4265        {
4266            s.popFront();
4267            static if (doCount)
4268            {
4269                return tuple!("data", "count")(result, ++count);
4270            }
4271            else
4272            {
4273                return result;
4274            }
4275        }
4276    }
4277    for (size_t i = 0; ; s.popFront(), count += 1 + skipWS!(Source, Yes.doCount)(s))
4278    {
4279        if (i == result.length)
4280            goto Lmanyerr;
4281        auto r = parseElement!(ElementType!Target, Source, Yes.doCount)(s);
4282        result[i++] = r.data;
4283        count += r.count + skipWS!(Source, Yes.doCount)(s);
4284        if (s.empty)
4285            throw convError!(Source, Target)(s);
4286        if (s.front != comma)
4287        {
4288            if (i != result.length)
4289                goto Lfewerr;
4290            break;
4291        }
4292    }
4293    parseCheck!s(rbracket);
4294    static if (doCount)
4295    {
4296        return tuple!("data", "count")(result, ++count);
4297    }
4298    else
4299    {
4300        return result;
4301    }
4302
4303
4304Lmanyerr:
4305    throw parseError(text("Too many elements in input, ", result.length, " elements expected."));
4306
4307Lfewerr:
4308    throw parseError(text("Too few elements in input, ", result.length, " elements expected."));
4309}
4310
4311@safe pure unittest
4312{
4313    import std.exception;
4314
4315    auto s1 = "[1,2,3,4]";
4316    auto sa1 = parse!(int[4])(s1);
4317    assert(sa1 == [1,2,3,4]);
4318    s1 = "[1,2,3,4]";
4319    assert(tuple([1,2,3,4], s1.length) == parse!(int[4], string, Yes.doCount)(s1));
4320
4321    auto s2 = "[[1],[2,3],[4]]";
4322    auto sa2 = parse!(int[][3])(s2);
4323    assert(sa2 == [[1],[2,3],[4]]);
4324    s2 = "[[1],[2,3],[4]]";
4325    assert(tuple([[1],[2,3],[4]], s2.length) == parse!(int[][3], string, Yes.doCount)(s2));
4326
4327    auto s3 = "[1,2,3]";
4328    assertThrown!ConvException(parse!(int[4])(s3));
4329    assertThrown!ConvException(parse!(int[4], string, Yes.doCount)(s3));
4330
4331    auto s4 = "[1,2,3,4,5]";
4332    assertThrown!ConvException(parse!(int[4])(s4));
4333    assertThrown!ConvException(parse!(int[4], string, Yes.doCount)(s4));
4334}
4335
4336/**
4337 * Parses an associative array from a string given the left bracket (default $(D
4338 * '[')), right bracket (default `']'`), key-value separator (default $(D
4339 * ':')), and element seprator (by default `','`).
4340 *
4341 * Params:
4342 *     s = the string to parse
4343 *     lbracket = the character that starts the associative array
4344 *     rbracket = the character that ends the associative array
4345 *     keyval = the character that associates the key with the value
4346 *     comma = the character that separates the elements of the associative array
4347 *     doCount = the flag for deciding to report the number of consumed characters
4348 *
4349 * Returns:
4350 $(UL
4351 *     $(LI An associative array of type `Target` if `doCount` is set to `No.doCount`)
4352 *     $(LI A `tuple` containing an associative array of type `Target` and a `size_t`
4353 *     if `doCount` is set to `Yes.doCount`))
4354 */
4355auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4356                             dchar rbracket = ']', dchar keyval = ':', dchar comma = ',')
4357if (isSomeString!Source && !is(Source == enum) &&
4358    isAssociativeArray!Target && !is(Target == enum))
4359{
4360    alias KeyType = typeof(Target.init.keys[0]);
4361    alias ValType = typeof(Target.init.values[0]);
4362
4363    Target result;
4364
4365    parseCheck!s(lbracket);
4366    size_t count = 1 + skipWS!(Source, Yes.doCount)(s);
4367    if (s.empty)
4368        throw convError!(Source, Target)(s);
4369    if (s.front == rbracket)
4370    {
4371        s.popFront();
4372        static if (doCount)
4373        {
4374            return tuple!("data", "count")(result, ++count);
4375        }
4376        else
4377        {
4378            return result;
4379        }
4380    }
4381    for (;; s.popFront(), count += 1 + skipWS!(Source, Yes.doCount)(s))
4382    {
4383        auto key = parseElement!(KeyType, Source, Yes.doCount)(s);
4384        count += key.count + skipWS!(Source, Yes.doCount)(s);
4385        parseCheck!s(keyval);
4386        count += 1 + skipWS!(Source, Yes.doCount)(s);
4387        auto val = parseElement!(ValType, Source, Yes.doCount)(s);
4388        count += val.count + skipWS!(Source, Yes.doCount)(s);
4389        result[key.data] = val.data;
4390        if (s.empty)
4391            throw convError!(Source, Target)(s);
4392        if (s.front != comma)
4393            break;
4394    }
4395    parseCheck!s(rbracket);
4396    static if (doCount)
4397    {
4398        return tuple!("data", "count")(result, ++count);
4399    }
4400    else
4401    {
4402        return result;
4403    }
4404}
4405
4406///
4407@safe pure unittest
4408{
4409    import std.typecons : Flag, Yes, No, tuple;
4410    import std.range.primitives : save;
4411    import std.array : assocArray;
4412    auto s1 = "[1:10, 2:20, 3:30]";
4413    auto copyS1 = s1.save;
4414    auto aa1 = parse!(int[int])(s1);
4415    assert(aa1 == [1:10, 2:20, 3:30]);
4416    assert(tuple([1:10, 2:20, 3:30], copyS1.length) == parse!(int[int], string, Yes.doCount)(copyS1));
4417
4418    auto s2 = `["aaa":10, "bbb":20, "ccc":30]`;
4419    auto copyS2 = s2.save;
4420    auto aa2 = parse!(int[string])(s2);
4421    assert(aa2 == ["aaa":10, "bbb":20, "ccc":30]);
4422    assert(tuple(["aaa":10, "bbb":20, "ccc":30], copyS2.length) ==
4423        parse!(int[string], string, Yes.doCount)(copyS2));
4424
4425    auto s3 = `["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]`;
4426    auto copyS3 = s3.save;
4427    auto aa3 = parse!(int[][string])(s3);
4428    assert(aa3 == ["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]);
4429    assert(tuple(["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]], copyS3.length) ==
4430        parse!(int[][string], string, Yes.doCount)(copyS3));
4431
4432    auto s4 = `[]`;
4433    int[int] emptyAA;
4434    assert(tuple(emptyAA, s4.length) == parse!(int[int], string, Yes.doCount)(s4));
4435}
4436
4437@safe pure unittest
4438{
4439    import std.exception;
4440
4441    //Check proper failure
4442    auto s = "[1:10, 2:20, 3:30]";
4443    auto s2 = s.save;
4444    foreach (i ; 0 .. s.length-1)
4445    {
4446        auto ss = s[0 .. i];
4447        assertThrown!ConvException(parse!(int[int])(ss));
4448        assertThrown!ConvException(parse!(int[int], string, Yes.doCount)(ss));
4449    }
4450    int[int] aa = parse!(int[int])(s);
4451    auto aa2 = parse!(int[int], string, Yes.doCount)(s2);
4452    aa  = aa2[0];
4453
4454}
4455
4456private auto parseEscape(Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4457if (isInputRange!Source && isSomeChar!(ElementType!Source))
4458{
4459    parseCheck!s('\\');
4460    size_t count = 1;
4461    if (s.empty)
4462        throw parseError("Unterminated escape sequence");
4463
4464    // consumes 1 element from Source
4465    dchar getHexDigit()(ref Source s_ = s)  // workaround
4466    {
4467        import std.ascii : isAlpha, isHexDigit;
4468        if (s_.empty)
4469            throw parseError("Unterminated escape sequence");
4470        s_.popFront();
4471        if (s_.empty)
4472            throw parseError("Unterminated escape sequence");
4473        dchar c = s_.front;
4474        if (!isHexDigit(c))
4475            throw parseError("Hex digit is missing");
4476        return isAlpha(c) ? ((c & ~0x20) - ('A' - 10)) : c - '0';
4477    }
4478
4479    // We need to do octals separate, because they need a lookahead to find out,
4480    // where the escape sequence ends.
4481    auto first = s.front;
4482    if (first >= '0' && first <= '7')
4483    {
4484        dchar c1 = s.front;
4485        ++count;
4486        s.popFront();
4487        if (s.empty)
4488        {
4489            static if (doCount)
4490            {
4491                return tuple!("data", "count")(cast (dchar) (c1 - '0'), count);
4492            }
4493            else
4494            {
4495                return cast (dchar) (c1 - '0');
4496            }
4497        }
4498        dchar c2 = s.front;
4499        if (c2 < '0' || c2 > '7')
4500        {
4501            static if (doCount)
4502            {
4503                return tuple!("data", "count")(cast (dchar)(c1 - '0'), count);
4504            }
4505            else
4506            {
4507                return cast (dchar)(c1 - '0');
4508            }
4509        }
4510        ++count;
4511        s.popFront();
4512        dchar c3 = s.front;
4513        if (c3 < '0' || c3 > '7')
4514        {
4515            static if (doCount)
4516            {
4517                return tuple!("data", "count")(cast (dchar) (8 * (c1 - '0') + (c2 - '0')), count);
4518            }
4519            else
4520            {
4521                return cast (dchar) (8 * (c1 - '0') + (c2 - '0'));
4522            }
4523        }
4524        ++count;
4525        s.popFront();
4526        if (c1 > '3')
4527            throw parseError("Octal sequence is larger than \\377");
4528        static if (doCount)
4529        {
4530            return tuple!("data", "count")(cast (dchar) (64 * (c1 - '0') + 8 * (c2 - '0') + (c3 - '0')), count);
4531        }
4532        else
4533        {
4534            return cast (dchar) (64 * (c1 - '0') + 8 * (c2 - '0') + (c3 - '0'));
4535        }
4536    }
4537
4538    dchar result;
4539
4540    switch (first)
4541    {
4542        case '"':   result = '\"';  break;
4543        case '\'':  result = '\'';  break;
4544        case '?':   result = '\?';  break;
4545        case '\\':  result = '\\';  break;
4546        case 'a':   result = '\a';  break;
4547        case 'b':   result = '\b';  break;
4548        case 'f':   result = '\f';  break;
4549        case 'n':   result = '\n';  break;
4550        case 'r':   result = '\r';  break;
4551        case 't':   result = '\t';  break;
4552        case 'v':   result = '\v';  break;
4553        case 'x':
4554            result  = getHexDigit() << 4;
4555            result |= getHexDigit();
4556            count += 2;
4557            break;
4558        case 'u':
4559            result  = getHexDigit() << 12;
4560            result |= getHexDigit() << 8;
4561            result |= getHexDigit() << 4;
4562            result |= getHexDigit();
4563            count += 4;
4564            break;
4565        case 'U':
4566            result  = getHexDigit() << 28;
4567            result |= getHexDigit() << 24;
4568            result |= getHexDigit() << 20;
4569            result |= getHexDigit() << 16;
4570            result |= getHexDigit() << 12;
4571            result |= getHexDigit() << 8;
4572            result |= getHexDigit() << 4;
4573            result |= getHexDigit();
4574            count += 8;
4575            break;
4576        default:
4577            throw parseError("Unknown escape character " ~ to!string(s.front));
4578    }
4579    if (s.empty)
4580        throw parseError("Unterminated escape sequence");
4581
4582    s.popFront();
4583
4584    static if (doCount)
4585    {
4586        return tuple!("data", "count")(cast (dchar) result, ++count);
4587    }
4588    else
4589    {
4590        return cast (dchar) result;
4591    }
4592}
4593
4594@safe pure unittest
4595{
4596    string[] s1 = [
4597        `\"`, `\'`, `\?`, `\\`, `\a`, `\b`, `\f`, `\n`, `\r`, `\t`, `\v`, //Normal escapes
4598        `\141`,
4599        `\x61`,
4600        `\u65E5`, `\U00012456`,
4601         // https://issues.dlang.org/show_bug.cgi?id=9621 (Named Character Entities)
4602        //`\&amp;`, `\&quot;`,
4603    ];
4604    string[] copyS1 = s1 ~ s1[0 .. 0];
4605
4606    const(dchar)[] s2 = [
4607        '\"', '\'', '\?', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v', //Normal escapes
4608        '\141',
4609        '\x61',
4610        '\u65E5', '\U00012456',
4611        // https://issues.dlang.org/show_bug.cgi?id=9621 (Named Character Entities)
4612        //'\&amp;', '\&quot;',
4613    ];
4614
4615    foreach (i ; 0 .. s1.length)
4616    {
4617        assert(s2[i] == parseEscape(s1[i]));
4618        assert(s1[i].empty);
4619
4620        assert(tuple(s2[i], copyS1[i].length) == parseEscape!(string, Yes.doCount)(copyS1[i]));
4621        assert(copyS1[i].empty);
4622    }
4623}
4624
4625@safe pure unittest
4626{
4627    import std.exception;
4628
4629    string[] ss = [
4630        `hello!`,  //Not an escape
4631        `\`,       //Premature termination
4632        `\/`,      //Not an escape
4633        `\gggg`,   //Not an escape
4634        `\xzz`,    //Not an hex
4635        `\x0`,     //Premature hex end
4636        `\XB9`,    //Not legal hex syntax
4637        `\u!!`,    //Not a unicode hex
4638        `\777`,    //Octal is larger than a byte
4639        `\80`,     //Wrong digit at beginning of octal
4640        `\u123`,   //Premature hex end
4641        `\U123123` //Premature hex end
4642    ];
4643    foreach (s ; ss)
4644    {
4645        assertThrown!ConvException(parseEscape(s));
4646        assertThrown!ConvException(parseEscape!(string, Yes.doCount)(s));
4647    }
4648}
4649
4650// Undocumented
4651auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4652if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
4653    isExactSomeString!Target)
4654{
4655    import std.array : appender;
4656    auto result = appender!Target();
4657
4658    // parse array of chars
4659    if (s.empty)
4660        throw convError!(Source, Target)(s);
4661    if (s.front == '[')
4662    {
4663        return parse!(Target, Source, doCount)(s);
4664    }
4665
4666    parseCheck!s('\"');
4667    size_t count = 1;
4668    if (s.empty)
4669        throw convError!(Source, Target)(s);
4670    if (s.front == '\"')
4671    {
4672        s.popFront();
4673        static if (doCount)
4674        {
4675            return tuple!("data", "count")(result.data, ++count);
4676        }
4677        else
4678        {
4679            return result.data;
4680        }
4681
4682    }
4683    while (true)
4684    {
4685        if (s.empty)
4686            throw parseError("Unterminated quoted string");
4687        switch (s.front)
4688        {
4689            case '\"':
4690                s.popFront();
4691                static if (doCount)
4692                {
4693                    return tuple!("data", "count")(result.data, ++count);
4694                }
4695                else
4696                {
4697                    return result.data;
4698                }
4699            case '\\':
4700                auto r = parseEscape!(typeof(s), Yes.doCount)(s);
4701                result.put(r[0]);
4702                count += r[1];
4703                break;
4704            default:
4705                result.put(s.front);
4706                ++count;
4707                s.popFront();
4708                break;
4709        }
4710    }
4711    assert(false, "Unexpected fallthrough");
4712}
4713
4714// ditto
4715auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4716if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
4717    is(CharTypeOf!Target == dchar) && !is(Target == enum))
4718{
4719    Unqual!Target c;
4720
4721    parseCheck!s('\'');
4722    size_t count = 1;
4723    if (s.empty)
4724        throw convError!(Source, Target)(s);
4725    ++count; // for the following if-else sequence
4726    if (s.front != '\\')
4727    {
4728        c = s.front;
4729        s.popFront();
4730    }
4731    else
4732        c = parseEscape(s);
4733    parseCheck!s('\'');
4734    static if (doCount)
4735    {
4736        return tuple!("data", "count")(c, ++count);
4737    }
4738    else
4739    {
4740        return c;
4741    }
4742}
4743
4744// ditto
4745auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4746if (isInputRange!Source && isSomeChar!(ElementType!Source) &&
4747    !isSomeString!Target && !isSomeChar!Target)
4748{
4749    return parse!(Target, Source, doCount)(s);
4750}
4751
4752// Use this when parsing a type that will ultimately be appended to a
4753// string.
4754package template WideElementType(T)
4755{
4756    alias E = ElementType!T;
4757    static if (isSomeChar!E)
4758        alias WideElementType = dchar;
4759    else
4760        alias WideElementType = E;
4761}
4762
4763
4764/***************************************************************
4765 * Convenience functions for converting one or more arguments
4766 * of any type into _text (the three character widths).
4767 */
4768string text(T...)(T args)
4769if (T.length > 0) { return textImpl!string(args); }
4770
4771///ditto
4772wstring wtext(T...)(T args)
4773if (T.length > 0) { return textImpl!wstring(args); }
4774
4775///ditto
4776dstring dtext(T...)(T args)
4777if (T.length > 0) { return textImpl!dstring(args); }
4778
4779///
4780@safe unittest
4781{
4782    assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c);
4783    assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w);
4784    assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d);
4785}
4786
4787@safe unittest
4788{
4789    char  c = 'h';
4790    wchar w = '���';
4791    dchar d = '���';
4792
4793    assert( text(c, "ello", ' ', w, "��� ", d, "��� ��������� ������") == "hello ������ ������ ��������� ������"c);
4794    assert(wtext(c, "ello", ' ', w, "��� ", d, "��� ��������� ������") == "hello ������ ������ ��������� ������"w);
4795    assert(dtext(c, "ello", ' ', w, "��� ", d, "��� ��������� ������") == "hello ������ ������ ��������� ������"d);
4796
4797    string  cs = "���������";
4798    wstring ws = "������������";
4799    dstring ds = "������������������������";
4800
4801    assert( text(cs, ' ', ws, " ", ds) == "��������� ������������ ������������������������"c);
4802    assert(wtext(cs, ' ', ws, " ", ds) == "��������� ������������ ������������������������"w);
4803    assert(dtext(cs, ' ', ws, " ", ds) == "��������� ������������ ������������������������"d);
4804}
4805
4806private S textImpl(S, U...)(U args)
4807{
4808    static if (U.length == 0)
4809    {
4810        return null;
4811    }
4812    else static if (U.length == 1)
4813    {
4814        return to!S(args[0]);
4815    }
4816    else
4817    {
4818        import std.array : appender;
4819        import std.traits : isSomeChar, isSomeString;
4820
4821        auto app = appender!S();
4822
4823        // assume that on average, parameters will have less
4824        // than 20 elements
4825        app.reserve(U.length * 20);
4826        // Must be static foreach because of https://issues.dlang.org/show_bug.cgi?id=21209
4827        static foreach (arg; args)
4828        {
4829            static if (
4830                isSomeChar!(typeof(arg)) || isSomeString!(typeof(arg)) ||
4831                ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) )
4832            )
4833                app.put(arg);
4834            else static if (
4835
4836                is(immutable typeof(arg) == immutable uint) || is(immutable typeof(arg) == immutable ulong) ||
4837                is(immutable typeof(arg) == immutable int) || is(immutable typeof(arg) == immutable long)
4838            )
4839                // https://issues.dlang.org/show_bug.cgi?id=17712#c15
4840                app.put(textImpl!(S)(arg));
4841            else
4842                app.put(to!S(arg));
4843        }
4844
4845        return app.data;
4846    }
4847}
4848
4849
4850/***************************************************************
4851The `octal` facility provides a means to declare a number in base 8.
4852Using `octal!177` or `octal!"177"` for 127 represented in octal
4853(same as 0177 in C).
4854
4855The rules for strings are the usual for literals: If it can fit in an
4856`int`, it is an `int`. Otherwise, it is a `long`. But, if the
4857user specifically asks for a `long` with the `L` suffix, always
4858give the `long`. Give an unsigned iff it is asked for with the $(D
4859U) or `u` suffix. _Octals created from integers preserve the type
4860of the passed-in integral.
4861
4862See_Also:
4863    $(LREF parse) for parsing octal strings at runtime.
4864 */
4865template octal(string num)
4866if (isOctalLiteral(num))
4867{
4868    static if ((octalFitsInInt!num && !literalIsLong!num) && !literalIsUnsigned!num)
4869        enum octal = octal!int(num);
4870    else static if ((!octalFitsInInt!num || literalIsLong!num) && !literalIsUnsigned!num)
4871        enum octal = octal!long(num);
4872    else static if ((octalFitsInInt!num && !literalIsLong!num) && literalIsUnsigned!num)
4873        enum octal = octal!uint(num);
4874    else static if ((!octalFitsInInt!(num) || literalIsLong!(num)) && literalIsUnsigned!(num))
4875        enum octal = octal!ulong(num);
4876    else
4877        static assert(false, "Unusable input " ~ num);
4878}
4879
4880/// Ditto
4881template octal(alias decimalInteger)
4882if (is(typeof(decimalInteger)) && isIntegral!(typeof(decimalInteger)))
4883{
4884    enum octal = octal!(typeof(decimalInteger))(to!string(decimalInteger));
4885}
4886
4887///
4888@safe unittest
4889{
4890    // Same as 0177
4891    auto a = octal!177;
4892    // octal is a compile-time device
4893    enum b = octal!160;
4894    // Create an unsigned octal
4895    auto c = octal!"1_000_000u";
4896    // Leading zeros are allowed when converting from a string
4897    auto d = octal!"0001_200_000";
4898}
4899
4900/*
4901    Takes a string, num, which is an octal literal, and returns its
4902    value, in the type T specified.
4903*/
4904private T octal(T)(const string num)
4905{
4906    assert(isOctalLiteral(num), num ~ " is not an octal literal");
4907
4908    T value = 0;
4909
4910    foreach (const char s; num)
4911    {
4912        if (s < '0' || s > '7') // we only care about digits; skip the rest
4913        // safe to skip - this is checked out in the assert so these
4914        // are just suffixes
4915            continue;
4916
4917        value *= 8;
4918        value += s - '0';
4919    }
4920
4921    return value;
4922}
4923
4924@safe unittest
4925{
4926    int a = octal!int("10");
4927    assert(a == 8);
4928
4929    int b = octal!int("000137");
4930    assert(b == 95);
4931}
4932
4933/*
4934Take a look at int.max and int.max+1 in octal and the logic for this
4935function follows directly.
4936 */
4937private template octalFitsInInt(string octalNum)
4938{
4939    // note it is important to strip the literal of all
4940    // non-numbers. kill the suffix and underscores lest they mess up
4941    // the number of digits here that we depend on.
4942    enum bool octalFitsInInt = strippedOctalLiteral(octalNum).length < 11 ||
4943        strippedOctalLiteral(octalNum).length == 11 &&
4944        strippedOctalLiteral(octalNum)[0] == '1';
4945}
4946
4947private string strippedOctalLiteral(string original)
4948{
4949    string stripped = "";
4950    bool leading_zeros = true;
4951    foreach (c; original)
4952    {
4953        if (!('0' <= c && c <= '7'))
4954            continue;
4955        if (c == '0')
4956        {
4957            if (leading_zeros)
4958                continue;
4959        }
4960        else
4961        {
4962            leading_zeros = false;
4963        }
4964        stripped ~= c;
4965    }
4966    if (stripped.length == 0)
4967    {
4968        assert(leading_zeros);
4969        return "0";
4970    }
4971    return stripped;
4972}
4973
4974@safe unittest
4975{
4976    static assert(strippedOctalLiteral("7") == "7");
4977    static assert(strippedOctalLiteral("123") == "123");
4978    static assert(strippedOctalLiteral("00123") == "123");
4979    static assert(strippedOctalLiteral("01230") == "1230");
4980    static assert(strippedOctalLiteral("0") == "0");
4981    static assert(strippedOctalLiteral("00_000") == "0");
4982    static assert(strippedOctalLiteral("000_000_12_300") == "12300");
4983}
4984
4985private template literalIsLong(string num)
4986{
4987    static if (num.length > 1)
4988    // can be xxL or xxLu according to spec
4989        enum literalIsLong = (num[$-1] == 'L' || num[$-2] == 'L');
4990    else
4991        enum literalIsLong = false;
4992}
4993
4994private template literalIsUnsigned(string num)
4995{
4996    static if (num.length > 1)
4997    // can be xxU or xxUL according to spec
4998        enum literalIsUnsigned = (num[$-1] == 'u' || num[$-2] == 'u')
4999            // both cases are allowed too
5000            || (num[$-1] == 'U' || num[$-2] == 'U');
5001    else
5002        enum literalIsUnsigned = false;
5003}
5004
5005/*
5006Returns if the given string is a correctly formatted octal literal.
5007
5008The format is specified in spec/lex.html. The leading zeros are allowed,
5009but not required.
5010 */
5011@safe pure nothrow @nogc
5012private bool isOctalLiteral(const string num)
5013{
5014    if (num.length == 0)
5015        return false;
5016
5017    // Must start with a digit.
5018    if (num[0] < '0' || num[0] > '7')
5019        return false;
5020
5021    foreach (i, c; num)
5022    {
5023        if (('0' <= c && c <= '7') || c == '_')  // a legal character
5024            continue;
5025
5026        if (i < num.length - 2)
5027            return false;
5028
5029        // gotta check for those suffixes
5030        if (c != 'U' && c != 'u' && c != 'L')
5031            return false;
5032        if (i != num.length - 1)
5033        {
5034            // if we're not the last one, the next one must
5035            // also be a suffix to be valid
5036            char c2 = num[$-1];
5037            if (c2 != 'U' && c2 != 'u' && c2 != 'L')
5038                return false; // spam at the end of the string
5039            if (c2 == c)
5040                return false; // repeats are disallowed
5041        }
5042    }
5043
5044    return true;
5045}
5046
5047@safe unittest
5048{
5049    // ensure that you get the right types, even with embedded underscores
5050    auto w = octal!"100_000_000_000";
5051    static assert(!is(typeof(w) == int));
5052    auto w2 = octal!"1_000_000_000";
5053    static assert(is(typeof(w2) == int));
5054
5055    static assert(octal!"45" == 37);
5056    static assert(octal!"0" == 0);
5057    static assert(octal!"7" == 7);
5058    static assert(octal!"10" == 8);
5059    static assert(octal!"666" == 438);
5060    static assert(octal!"0004001" == 2049);
5061    static assert(octal!"00" == 0);
5062    static assert(octal!"0_0" == 0);
5063
5064    static assert(octal!45 == 37);
5065    static assert(octal!0 == 0);
5066    static assert(octal!7 == 7);
5067    static assert(octal!10 == 8);
5068    static assert(octal!666 == 438);
5069
5070    static assert(octal!"66_6" == 438);
5071    static assert(octal!"0_0_66_6" == 438);
5072
5073    static assert(octal!2520046213 == 356535435);
5074    static assert(octal!"2520046213" == 356535435);
5075
5076    static assert(octal!17777777777 == int.max);
5077
5078    static assert(!__traits(compiles, octal!823));
5079
5080    static assert(!__traits(compiles, octal!"823"));
5081
5082    static assert(!__traits(compiles, octal!"_823"));
5083    static assert(!__traits(compiles, octal!"spam"));
5084    static assert(!__traits(compiles, octal!"77%"));
5085
5086    static assert(is(typeof(octal!"17777777777") == int));
5087    static assert(octal!"17777777777" == int.max);
5088
5089    static assert(is(typeof(octal!"20000000000U") == ulong)); // Shouldn't this be uint?
5090    static assert(octal!"20000000000" == uint(int.max) + 1);
5091
5092    static assert(is(typeof(octal!"777777777777777777777") == long));
5093    static assert(octal!"777777777777777777777" == long.max);
5094
5095    static assert(is(typeof(octal!"1000000000000000000000U") == ulong));
5096    static assert(octal!"1000000000000000000000" == ulong(long.max) + 1);
5097
5098    int a;
5099    long b;
5100
5101    // biggest value that should fit in an it
5102    a = octal!"17777777777";
5103    assert(a == int.max);
5104    // should not fit in the int
5105    static assert(!__traits(compiles, a = octal!"20000000000"));
5106    // ... but should fit in a long
5107    b = octal!"20000000000";
5108    assert(b == 1L + int.max);
5109
5110    b = octal!"1L";
5111    assert(b == 1);
5112    b = octal!1L;
5113    assert(b == 1);
5114}
5115
5116// emplace() used to be here but was moved to druntime
5117public import core.lifetime : emplace;
5118
5119// https://issues.dlang.org/show_bug.cgi?id=9559
5120@safe unittest
5121{
5122    import std.algorithm.iteration : map;
5123    import std.array : array;
5124    import std.typecons : Nullable;
5125    alias I = Nullable!int;
5126    auto ints = [0, 1, 2].map!(i => i & 1 ? I.init : I(i))();
5127    auto asArray = array(ints);
5128}
5129
5130@system unittest //http://forum.dlang.org/post/nxbdgtdlmwscocbiypjs@forum.dlang.org
5131{
5132    import std.array : array;
5133    import std.datetime : SysTime, UTC;
5134    import std.math.traits : isNaN;
5135
5136    static struct A
5137    {
5138        double i;
5139    }
5140
5141    static struct B
5142    {
5143        invariant()
5144        {
5145            if (j == 0)
5146                assert(a.i.isNaN(), "why is 'j' zero?? and i is not NaN?");
5147            else
5148                assert(!a.i.isNaN());
5149        }
5150        SysTime when; // comment this line avoid the breakage
5151        int j;
5152        A a;
5153    }
5154
5155    B b1 = B.init;
5156    assert(&b1); // verify that default eyes invariants are ok;
5157
5158    auto b2 = B(SysTime(0, UTC()), 1, A(1));
5159    assert(&b2);
5160    auto b3 = B(SysTime(0, UTC()), 1, A(1));
5161    assert(&b3);
5162
5163    auto arr = [b2, b3];
5164
5165    assert(arr[0].j == 1);
5166    assert(arr[1].j == 1);
5167    auto a2 = arr.array(); // << bang, invariant is raised, also if b2 and b3 are good
5168}
5169
5170@safe unittest
5171{
5172    import std.algorithm.comparison : equal;
5173    import std.algorithm.iteration : map;
5174    // Check fix for https://issues.dlang.org/show_bug.cgi?id=2971
5175    assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345]));
5176}
5177
5178// Undocumented for the time being
5179void toTextRange(T, W)(T value, W writer)
5180if (isIntegral!T && isOutputRange!(W, char))
5181{
5182    import core.internal.string : SignedStringBuf, signedToTempString,
5183                                  UnsignedStringBuf, unsignedToTempString;
5184
5185    if (value < 0)
5186    {
5187        SignedStringBuf buf = void;
5188        put(writer, signedToTempString(value, buf));
5189    }
5190    else
5191    {
5192        UnsignedStringBuf buf = void;
5193        put(writer, unsignedToTempString(value, buf));
5194    }
5195}
5196
5197@safe unittest
5198{
5199    import std.array : appender;
5200    auto result = appender!(char[])();
5201    toTextRange(-1, result);
5202    assert(result.data == "-1");
5203}
5204
5205
5206/**
5207    Returns the corresponding _unsigned value for `x` (e.g. if `x` has type
5208    `int`, it returns $(D cast(uint) x)). The advantage compared to the cast
5209    is that you do not need to rewrite the cast if `x` later changes type
5210    (e.g from `int` to `long`).
5211
5212    Note that the result is always mutable even if the original type was const
5213    or immutable. In order to retain the constness, use $(REF Unsigned, std,traits).
5214 */
5215auto unsigned(T)(T x)
5216if (isIntegral!T)
5217{
5218    return cast(Unqual!(Unsigned!T))x;
5219}
5220
5221///
5222@safe unittest
5223{
5224    import std.traits : Unsigned;
5225    immutable int s = 42;
5226    auto u1 = unsigned(s); //not qualified
5227    static assert(is(typeof(u1) == uint));
5228    Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification
5229    static assert(is(typeof(u2) == immutable uint));
5230    immutable u3 = unsigned(s); //explicitly qualified
5231}
5232
5233/// Ditto
5234auto unsigned(T)(T x)
5235if (isSomeChar!T)
5236{
5237    // All characters are unsigned
5238    static assert(T.min == 0, T.stringof ~ ".min must be zero");
5239    return cast(Unqual!T) x;
5240}
5241
5242@safe unittest
5243{
5244    static foreach (T; AliasSeq!(byte, ubyte))
5245    {
5246        static assert(is(typeof(unsigned(cast(T) 1)) == ubyte));
5247        static assert(is(typeof(unsigned(cast(const T) 1)) == ubyte));
5248        static assert(is(typeof(unsigned(cast(immutable T) 1)) == ubyte));
5249    }
5250
5251    static foreach (T; AliasSeq!(short, ushort))
5252    {
5253        static assert(is(typeof(unsigned(cast(T) 1)) == ushort));
5254        static assert(is(typeof(unsigned(cast(const T) 1)) == ushort));
5255        static assert(is(typeof(unsigned(cast(immutable T) 1)) == ushort));
5256    }
5257
5258    static foreach (T; AliasSeq!(int, uint))
5259    {
5260        static assert(is(typeof(unsigned(cast(T) 1)) == uint));
5261        static assert(is(typeof(unsigned(cast(const T) 1)) == uint));
5262        static assert(is(typeof(unsigned(cast(immutable T) 1)) == uint));
5263    }
5264
5265    static foreach (T; AliasSeq!(long, ulong))
5266    {
5267        static assert(is(typeof(unsigned(cast(T) 1)) == ulong));
5268        static assert(is(typeof(unsigned(cast(const T) 1)) == ulong));
5269        static assert(is(typeof(unsigned(cast(immutable T) 1)) == ulong));
5270    }
5271}
5272
5273@safe unittest
5274{
5275    static foreach (T; AliasSeq!(char, wchar, dchar))
5276    {
5277        static assert(is(typeof(unsigned(cast(T)'A')) == T));
5278        static assert(is(typeof(unsigned(cast(const T)'A')) == T));
5279        static assert(is(typeof(unsigned(cast(immutable T)'A')) == T));
5280    }
5281}
5282
5283
5284/**
5285    Returns the corresponding _signed value for `x` (e.g. if `x` has type
5286    `uint`, it returns $(D cast(int) x)). The advantage compared to the cast
5287    is that you do not need to rewrite the cast if `x` later changes type
5288    (e.g from `uint` to `ulong`).
5289
5290    Note that the result is always mutable even if the original type was const
5291    or immutable. In order to retain the constness, use $(REF Signed, std,traits).
5292 */
5293auto signed(T)(T x)
5294if (isIntegral!T)
5295{
5296    return cast(Unqual!(Signed!T))x;
5297}
5298
5299///
5300@safe unittest
5301{
5302    import std.traits : Signed;
5303
5304    immutable uint u = 42;
5305    auto s1 = signed(u); //not qualified
5306    static assert(is(typeof(s1) == int));
5307    Signed!(typeof(u)) s2 = signed(u); //same qualification
5308    static assert(is(typeof(s2) == immutable int));
5309    immutable s3 = signed(u); //explicitly qualified
5310}
5311
5312@system unittest
5313{
5314    static foreach (T; AliasSeq!(byte, ubyte))
5315    {
5316        static assert(is(typeof(signed(cast(T) 1)) == byte));
5317        static assert(is(typeof(signed(cast(const T) 1)) == byte));
5318        static assert(is(typeof(signed(cast(immutable T) 1)) == byte));
5319    }
5320
5321    static foreach (T; AliasSeq!(short, ushort))
5322    {
5323        static assert(is(typeof(signed(cast(T) 1)) == short));
5324        static assert(is(typeof(signed(cast(const T) 1)) == short));
5325        static assert(is(typeof(signed(cast(immutable T) 1)) == short));
5326    }
5327
5328    static foreach (T; AliasSeq!(int, uint))
5329    {
5330        static assert(is(typeof(signed(cast(T) 1)) == int));
5331        static assert(is(typeof(signed(cast(const T) 1)) == int));
5332        static assert(is(typeof(signed(cast(immutable T) 1)) == int));
5333    }
5334
5335    static foreach (T; AliasSeq!(long, ulong))
5336    {
5337        static assert(is(typeof(signed(cast(T) 1)) == long));
5338        static assert(is(typeof(signed(cast(const T) 1)) == long));
5339        static assert(is(typeof(signed(cast(immutable T) 1)) == long));
5340    }
5341}
5342
5343// https://issues.dlang.org/show_bug.cgi?id=10874
5344@safe unittest
5345{
5346    enum Test { a = 0 }
5347    ulong l = 0;
5348    auto t = l.to!Test;
5349}
5350
5351// asOriginalType
5352/**
5353Returns the representation of an enumerated value, i.e. the value converted to
5354the base type of the enumeration.
5355*/
5356OriginalType!E asOriginalType(E)(E value)
5357if (is(E == enum))
5358{
5359    return value;
5360}
5361
5362///
5363@safe unittest
5364{
5365    enum A { a = 42 }
5366    static assert(is(typeof(A.a.asOriginalType) == int));
5367    assert(A.a.asOriginalType == 42);
5368    enum B : double { a = 43 }
5369    static assert(is(typeof(B.a.asOriginalType) == double));
5370    assert(B.a.asOriginalType == 43);
5371}
5372
5373/**
5374    A wrapper on top of the built-in cast operator that allows one to restrict
5375    casting of the original type of the value.
5376
5377    A common issue with using a raw cast is that it may silently continue to
5378    compile even if the value's type has changed during refactoring,
5379    which breaks the initial assumption about the cast.
5380
5381    Params:
5382        From  = The type to cast from. The programmer must ensure it is legal
5383                to make this cast.
5384 */
5385template castFrom(From)
5386{
5387    /**
5388        Params:
5389            To    = The type _to cast _to.
5390            value = The value _to cast. It must be of type `From`,
5391                    otherwise a compile-time error is emitted.
5392
5393        Returns:
5394            the value after the cast, returned by reference if possible.
5395     */
5396    auto ref to(To, T)(auto ref T value) @system
5397    {
5398        static assert(
5399            is(From == T),
5400            "the value to cast is not of specified type '" ~ From.stringof ~
5401                 "', it is of type '" ~ T.stringof ~ "'"
5402        );
5403
5404        static assert(
5405            is(typeof(cast(To) value)),
5406            "can't cast from '" ~ From.stringof ~ "' to '" ~ To.stringof ~ "'"
5407        );
5408
5409        return cast(To) value;
5410    }
5411}
5412
5413///
5414@system unittest
5415{
5416    // Regular cast, which has been verified to be legal by the programmer:
5417    {
5418        long x;
5419        auto y = cast(int) x;
5420    }
5421
5422    // However this will still compile if 'x' is changed to be a pointer:
5423    {
5424        long* x;
5425        auto y = cast(int) x;
5426    }
5427
5428    // castFrom provides a more reliable alternative to casting:
5429    {
5430        long x;
5431        auto y = castFrom!long.to!int(x);
5432    }
5433
5434    // Changing the type of 'x' will now issue a compiler error,
5435    // allowing bad casts to be caught before it's too late:
5436    {
5437        long* x;
5438        static assert(
5439            !__traits(compiles, castFrom!long.to!int(x))
5440        );
5441
5442        // if cast is still needed, must be changed to:
5443        auto y = castFrom!(long*).to!int(x);
5444    }
5445}
5446
5447// https://issues.dlang.org/show_bug.cgi?id=16667
5448@system unittest
5449{
5450    ubyte[] a = ['a', 'b', 'c'];
5451    assert(castFrom!(ubyte[]).to!(string)(a) == "abc");
5452}
5453
5454/**
5455Check the correctness of a string for `hexString`.
5456The result is true if and only if the input string is composed of whitespace
5457characters (\f\n\r\t\v lineSep paraSep nelSep) and
5458an even number of hexadecimal digits (regardless of the case).
5459*/
5460@safe pure @nogc
5461private bool isHexLiteral(String)(scope const String hexData)
5462{
5463    import std.ascii : isHexDigit;
5464    import std.uni : lineSep, paraSep, nelSep;
5465    size_t i;
5466    foreach (const dchar c; hexData)
5467    {
5468        switch (c)
5469        {
5470            case ' ':
5471            case '\t':
5472            case '\v':
5473            case '\f':
5474            case '\r':
5475            case '\n':
5476            case lineSep:
5477            case paraSep:
5478            case nelSep:
5479                continue;
5480
5481            default:
5482                break;
5483        }
5484        if (c.isHexDigit)
5485            ++i;
5486        else
5487            return false;
5488    }
5489    return !(i & 1);
5490}
5491
5492@safe unittest
5493{
5494    // test all the hex digits
5495    static assert( ("0123456789abcdefABCDEF").isHexLiteral);
5496    // empty or white strings are not valid
5497    static assert( "\r\n\t".isHexLiteral);
5498    // but are accepted if the count of hex digits is even
5499    static assert( "A\r\n\tB".isHexLiteral);
5500}
5501
5502@safe unittest
5503{
5504    import std.ascii;
5505    // empty/whites
5506    static assert( "".isHexLiteral);
5507    static assert( " \r".isHexLiteral);
5508    static assert( whitespace.isHexLiteral);
5509    static assert( ""w.isHexLiteral);
5510    static assert( " \r"w.isHexLiteral);
5511    static assert( ""d.isHexLiteral);
5512    static assert( " \r"d.isHexLiteral);
5513    static assert( "\u2028\u2029\u0085"d.isHexLiteral);
5514    // odd x strings
5515    static assert( !("5" ~ whitespace).isHexLiteral);
5516    static assert( !"123".isHexLiteral);
5517    static assert( !"1A3".isHexLiteral);
5518    static assert( !"1 23".isHexLiteral);
5519    static assert( !"\r\n\tC".isHexLiteral);
5520    static assert( !"123"w.isHexLiteral);
5521    static assert( !"1A3"w.isHexLiteral);
5522    static assert( !"1 23"w.isHexLiteral);
5523    static assert( !"\r\n\tC"w.isHexLiteral);
5524    static assert( !"123"d.isHexLiteral);
5525    static assert( !"1A3"d.isHexLiteral);
5526    static assert( !"1 23"d.isHexLiteral);
5527    static assert( !"\r\n\tC"d.isHexLiteral);
5528    // even x strings with invalid charset
5529    static assert( !"12gG".isHexLiteral);
5530    static assert( !"2A  3q".isHexLiteral);
5531    static assert( !"12gG"w.isHexLiteral);
5532    static assert( !"2A  3q"w.isHexLiteral);
5533    static assert( !"12gG"d.isHexLiteral);
5534    static assert( !"2A  3q"d.isHexLiteral);
5535    // valid x strings
5536    static assert( ("5A" ~ whitespace).isHexLiteral);
5537    static assert( ("5A 01A C FF de 1b").isHexLiteral);
5538    static assert( ("0123456789abcdefABCDEF").isHexLiteral);
5539    static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF").isHexLiteral);
5540    static assert( ("5A 01A C FF de 1b"w).isHexLiteral);
5541    static assert( ("0123456789abcdefABCDEF"w).isHexLiteral);
5542    static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"w).isHexLiteral);
5543    static assert( ("5A 01A C FF de 1b"d).isHexLiteral);
5544    static assert( ("0123456789abcdefABCDEF"d).isHexLiteral);
5545    static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"d).isHexLiteral);
5546    // library version allows what's pointed by issue 10454
5547    static assert( ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").isHexLiteral);
5548}
5549
5550/**
5551Converts a hex literal to a string at compile time.
5552
5553Takes a string made of hexadecimal digits and returns
5554the matching string by converting each pair of digits to a character.
5555The input string can also include white characters, which can be used
5556to keep the literal string readable in the source code.
5557
5558The function is intended to replace the hexadecimal literal strings
5559starting with `'x'`, which could be removed to simplify the core language.
5560
5561Params:
5562    hexData = string to be converted.
5563
5564Returns:
5565    a `string`, a `wstring` or a `dstring`, according to the type of hexData.
5566 */
5567template hexString(string hexData)
5568if (hexData.isHexLiteral)
5569{
5570    enum hexString = mixin(hexToString(hexData));
5571}
5572
5573/// ditto
5574template hexString(wstring hexData)
5575if (hexData.isHexLiteral)
5576{
5577    enum wstring hexString = mixin(hexToString(hexData));
5578}
5579
5580/// ditto
5581template hexString(dstring hexData)
5582if (hexData.isHexLiteral)
5583{
5584    enum dstring hexString = mixin(hexToString(hexData));
5585}
5586
5587///
5588@safe unittest
5589{
5590    // conversion at compile time
5591    auto string1 = hexString!"304A314B";
5592    assert(string1 == "0J1K");
5593    auto string2 = hexString!"304A314B"w;
5594    assert(string2 == "0J1K"w);
5595    auto string3 = hexString!"304A314B"d;
5596    assert(string3 == "0J1K"d);
5597}
5598
5599@safe nothrow pure private
5600{
5601    /* These are meant to be used with CTFE.
5602     * They cause the instantiations of hexStrLiteral()
5603     * to be in Phobos, not user code.
5604     */
5605    string hexToString(string s)
5606    {
5607        return hexStrLiteral(s);
5608    }
5609
5610    wstring hexToString(wstring s)
5611    {
5612        return hexStrLiteral(s);
5613    }
5614
5615    dstring hexToString(dstring s)
5616    {
5617        return hexStrLiteral(s);
5618    }
5619}
5620
5621/*
5622    Turn a hexadecimal string into a regular string literal.
5623    I.e. "dead beef" is transformed into "\xde\xad\xbe\xef"
5624    suitable for use in a mixin.
5625    Params:
5626        hexData is string, wstring, or dstring and validated by isHexLiteral()
5627 */
5628@trusted nothrow pure
5629private auto hexStrLiteral(String)(scope String hexData)
5630{
5631    import std.ascii : isHexDigit;
5632    alias C = Unqual!(ElementEncodingType!String);    // char, wchar or dchar
5633    C[] result;
5634    result.length = 1 + hexData.length * 2 + 1;       // don't forget the " "
5635    /* Use a pointer because we know it won't overrun,
5636     * and this will reduce the size of the function substantially
5637     * by not doing the array bounds checks.
5638     * This is why this function is @trusted.
5639     */
5640    auto r = result.ptr;
5641    r[0] = '"';
5642    size_t cnt = 0;
5643    foreach (c; hexData)
5644    {
5645        if (c.isHexDigit)
5646        {
5647            if ((cnt & 1) == 0)
5648            {
5649                r[1 + cnt]     = '\\';
5650                r[1 + cnt + 1] = 'x';
5651                cnt += 2;
5652            }
5653            r[1 + cnt] = c;
5654            ++cnt;
5655        }
5656    }
5657    r[1 + cnt] = '"';
5658    result.length = 1 + cnt + 1;        // trim off any excess length
5659    return result;
5660}
5661
5662
5663@safe unittest
5664{
5665    // compile time
5666    assert(hexString!"46 47 48 49 4A 4B" == "FGHIJK");
5667    assert(hexString!"30\r\n\t\f\v31 32 33 32 31 30" == "0123210");
5668    assert(hexString!"ab cd" == hexString!"ABCD");
5669}
5670
5671
5672/**
5673 * Convert integer to a range of characters.
5674 * Intended to be lightweight and fast.
5675 *
5676 * Params:
5677 *      radix = 2, 8, 10, 16
5678 *      Char = character type for output
5679 *      letterCase = lower for deadbeef, upper for DEADBEEF
5680 *      value = integer to convert. Can be uint or ulong. If radix is 10, can also be
5681 *              int or long.
5682 * Returns:
5683 *      Random access range with slicing and everything
5684 */
5685
5686auto toChars(ubyte radix = 10, Char = char, LetterCase letterCase = LetterCase.lower, T)(T value)
5687    pure nothrow @nogc @safe
5688if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) &&
5689    (is(immutable T == immutable uint) || is(immutable T == immutable ulong) ||
5690    radix == 10 && (is(immutable T == immutable int) || is(immutable T == immutable long))))
5691{
5692    alias UT = Unqual!T;
5693
5694    static if (radix == 10)
5695    {
5696        /* uint.max  is 42_9496_7295
5697         *  int.max  is 21_4748_3647
5698         * ulong.max is 1844_6744_0737_0955_1615
5699         *  long.max is  922_3372_0368_5477_5807
5700         */
5701        static struct Result
5702        {
5703            void initialize(UT value)
5704            {
5705                bool neg = false;
5706                if (value < 10)
5707                {
5708                    if (value >= 0)
5709                    {
5710                        lwr = 0;
5711                        upr = 1;
5712                        buf[0] = cast(char)(cast(uint) value + '0');
5713                        return;
5714                    }
5715                    value = -value;
5716                    neg = true;
5717                }
5718                auto i = cast(uint) buf.length - 1;
5719                while (cast(Unsigned!UT) value >= 10)
5720                {
5721                    buf[i] = cast(ubyte)('0' + cast(Unsigned!UT) value % 10);
5722                    value = unsigned(value) / 10;
5723                    --i;
5724                }
5725                buf[i] = cast(char)(cast(uint) value + '0');
5726                if (neg)
5727                {
5728                    buf[i - 1] = '-';
5729                    --i;
5730                }
5731                lwr = i;
5732                upr = cast(uint) buf.length;
5733            }
5734
5735            @property size_t length() { return upr - lwr; }
5736
5737            alias opDollar = length;
5738
5739            @property bool empty() { return upr == lwr; }
5740
5741            @property Char front() { return buf[lwr]; }
5742
5743            void popFront() { ++lwr; }
5744
5745            @property Char back() { return buf[upr - 1]; }
5746
5747            void popBack() { --upr; }
5748
5749            @property Result save() { return this; }
5750
5751            Char opIndex(size_t i) { return buf[lwr + i]; }
5752
5753            Result opSlice(size_t lwr, size_t upr)
5754            {
5755                Result result = void;
5756                result.buf = buf;
5757                result.lwr = cast(uint)(this.lwr + lwr);
5758                result.upr = cast(uint)(this.lwr + upr);
5759                return result;
5760            }
5761
5762          private:
5763            uint lwr = void, upr = void;
5764            char[(UT.sizeof == 4) ? 10 + isSigned!T : 20] buf = void;
5765        }
5766
5767        Result result;
5768        result.initialize(value);
5769        return result;
5770    }
5771    else
5772    {
5773        static if (radix == 2)
5774            enum SHIFT = 1;
5775        else static if (radix == 8)
5776            enum SHIFT = 3;
5777        else static if (radix == 16)
5778            enum SHIFT = 4;
5779        else
5780            static assert(false, "radix must be 2, 8, 10, or 16");
5781        static struct Result
5782        {
5783            this(UT value)
5784            {
5785                this.value = value;
5786
5787                ubyte len = 1;
5788                while (value >>>= SHIFT)
5789                   ++len;
5790                this.len = len;
5791            }
5792
5793            @property size_t length() { return len; }
5794
5795            @property bool empty() { return len == 0; }
5796
5797            @property Char front() { return opIndex(0); }
5798
5799            void popFront() { --len; }
5800
5801            @property Char back() { return opIndex(len - 1); }
5802
5803            void popBack()
5804            {
5805                value >>>= SHIFT;
5806                --len;
5807            }
5808
5809            @property Result save() { return this; }
5810
5811            Char opIndex(size_t i)
5812            {
5813                Char c = (value >>> ((len - i - 1) * SHIFT)) & ((1 << SHIFT) - 1);
5814                return cast(Char)((radix < 10 || c < 10) ? c + '0'
5815                                                         : (letterCase == LetterCase.upper ? c + 'A' - 10
5816                                                                                           : c + 'a' - 10));
5817            }
5818
5819            Result opSlice(size_t lwr, size_t upr)
5820            {
5821                Result result = void;
5822                result.value = value >>> ((len - upr) * SHIFT);
5823                result.len = cast(ubyte)(upr - lwr);
5824                return result;
5825            }
5826
5827          private:
5828            UT value;
5829            ubyte len;
5830        }
5831
5832        return Result(value);
5833    }
5834}
5835
5836///
5837@safe unittest
5838{
5839    import std.algorithm.comparison : equal;
5840
5841    assert(toChars(1).equal("1"));
5842    assert(toChars(1_000_000).equal("1000000"));
5843
5844    assert(toChars!(2)(2U).equal("10"));
5845    assert(toChars!(16)(255U).equal("ff"));
5846    assert(toChars!(16, char, LetterCase.upper)(255U).equal("FF"));
5847}
5848
5849
5850@safe unittest
5851{
5852    import std.array;
5853    import std.range;
5854
5855    assert(toChars(123) == toChars(123));
5856
5857    {
5858        assert(toChars!2(0u).array == "0");
5859        assert(toChars!2(0Lu).array == "0");
5860        assert(toChars!2(1u).array == "1");
5861        assert(toChars!2(1Lu).array == "1");
5862
5863        auto r = toChars!2(2u);
5864        assert(r.length == 2);
5865        assert(r[0] == '1');
5866        assert(r[1 .. 2].array == "0");
5867        auto s = r.save;
5868        assert(r.array == "10");
5869        assert(s.retro.array == "01");
5870    }
5871    {
5872        assert(toChars!8(0u).array == "0");
5873        assert(toChars!8(0Lu).array == "0");
5874        assert(toChars!8(1u).array == "1");
5875        assert(toChars!8(1234567Lu).array == "4553207");
5876
5877        auto r = toChars!8(8u);
5878        assert(r.length == 2);
5879        assert(r[0] == '1');
5880        assert(r[1 .. 2].array == "0");
5881        auto s = r.save;
5882        assert(r.array == "10");
5883        assert(s.retro.array == "01");
5884    }
5885    {
5886        assert(toChars!10(0u).array == "0");
5887        assert(toChars!10(0Lu).array == "0");
5888        assert(toChars!10(1u).array == "1");
5889        assert(toChars!10(1234567Lu).array == "1234567");
5890        assert(toChars!10(uint.max).array == "4294967295");
5891        assert(toChars!10(ulong.max).array == "18446744073709551615");
5892
5893        auto r = toChars(10u);
5894        assert(r.length == 2);
5895        assert(r[0] == '1');
5896        assert(r[1 .. 2].array == "0");
5897        auto s = r.save;
5898        assert(r.array == "10");
5899        assert(s.retro.array == "01");
5900    }
5901    {
5902        assert(toChars!10(0).array == "0");
5903        assert(toChars!10(0L).array == "0");
5904        assert(toChars!10(1).array == "1");
5905        assert(toChars!10(1234567L).array == "1234567");
5906        assert(toChars!10(int.max).array == "2147483647");
5907        assert(toChars!10(long.max).array == "9223372036854775807");
5908        assert(toChars!10(-int.max).array == "-2147483647");
5909        assert(toChars!10(-long.max).array == "-9223372036854775807");
5910        assert(toChars!10(int.min).array == "-2147483648");
5911        assert(toChars!10(long.min).array == "-9223372036854775808");
5912
5913        auto r = toChars!10(10);
5914        assert(r.length == 2);
5915        assert(r[0] == '1');
5916        assert(r[1 .. 2].array == "0");
5917        auto s = r.save;
5918        assert(r.array == "10");
5919        assert(s.retro.array == "01");
5920    }
5921    {
5922        assert(toChars!(16)(0u).array == "0");
5923        assert(toChars!(16)(0Lu).array == "0");
5924        assert(toChars!(16)(10u).array == "a");
5925        assert(toChars!(16, char, LetterCase.upper)(0x12AF34567Lu).array == "12AF34567");
5926
5927        auto r = toChars!(16)(16u);
5928        assert(r.length == 2);
5929        assert(r[0] == '1');
5930        assert(r[1 .. 2].array == "0");
5931        auto s = r.save;
5932        assert(r.array == "10");
5933        assert(s.retro.array == "01");
5934    }
5935}
5936
5937@safe unittest // opSlice (issue 16192)
5938{
5939    import std.meta : AliasSeq;
5940
5941    static struct Test { ubyte radix; uint number; }
5942
5943    alias tests = AliasSeq!(
5944        Test(2, 0b1_0110_0111u),
5945        Test(2, 0b10_1100_1110u),
5946        Test(8, octal!123456701u),
5947        Test(8, octal!1234567012u),
5948        Test(10, 123456789u),
5949        Test(10, 1234567890u),
5950        Test(16, 0x789ABCDu),
5951        Test(16, 0x789ABCDEu),
5952    );
5953
5954    foreach (test; tests)
5955    {
5956        enum ubyte radix = test.radix;
5957        auto original = toChars!radix(test.number);
5958
5959        // opSlice vs popFront
5960        auto r = original.save;
5961        size_t i = 0;
5962        for (; !r.empty; r.popFront(), ++i)
5963        {
5964            assert(original[i .. original.length].tupleof == r.tupleof);
5965                // tupleof is used to work around issue 16216.
5966        }
5967
5968        // opSlice vs popBack
5969        r = original.save;
5970        i = 0;
5971        for (; !r.empty; r.popBack(), ++i)
5972        {
5973            assert(original[0 .. original.length - i].tupleof == r.tupleof);
5974        }
5975
5976        // opSlice vs both popFront and popBack
5977        r = original.save;
5978        i = 0;
5979        for (; r.length >= 2; r.popFront(), r.popBack(), ++i)
5980        {
5981            assert(original[i .. original.length - i].tupleof == r.tupleof);
5982        }
5983    }
5984}
5985
5986// Converts an unsigned integer to a compile-time string constant.
5987package enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
5988
5989// Check that .stringof does what we expect, since it's not guaranteed by the
5990// language spec.
5991@safe /*@betterC*/ unittest
5992{
5993    assert(toCtString!0 == "0");
5994    assert(toCtString!123456 == "123456");
5995}
5996