Do not cost the permute node that are part of SLP load-lanes
[official-gcc.git] / libphobos / src / std / conv.d
blob5d02df08bf9d3b5ca6d86a78ec851b47b45c4ea4
1 // Written in the D programming language.
3 /**
4 A one-stop shop for converting values from one type to another.
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)
17 $(TR $(TD Strings) $(TD
18 $(LREF text)
19 $(LREF wtext)
20 $(LREF dtext)
21 $(LREF hexString)
23 $(TR $(TD Numeric) $(TD
24 $(LREF octal)
25 $(LREF roundTo)
26 $(LREF signed)
27 $(LREF unsigned)
29 $(TR $(TD Exceptions) $(TD
30 $(LREF ConvException)
31 $(LREF ConvOverflowException)
35 Copyright: Copyright The D Language Foundation 2007-.
37 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
39 Authors: $(HTTP digitalmars.com, Walter Bright),
40 $(HTTP erdani.org, Andrei Alexandrescu),
41 Shin Fujishiro,
42 Adam D. Ruppe,
43 Kenji Hara
45 Source: $(PHOBOSSRC std/conv.d)
48 module std.conv;
50 public import std.ascii : LetterCase;
52 import std.meta;
53 import std.range;
54 import std.traits;
55 import std.typecons : Flag, Yes, No, tuple, isTuple;
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.
60 package template convFormat()
62 import std.format : format;
63 alias convFormat = format;
66 /* ************* Exceptions *************** */
68 /**
69 * Thrown on conversion errors.
71 class ConvException : Exception
73 import std.exception : basicExceptionCtors;
74 ///
75 mixin basicExceptionCtors;
78 ///
79 @safe unittest
81 import std.exception : assertThrown;
82 assertThrown!ConvException(to!int("abc"));
85 private auto convError(S, T)(S source, string fn = __FILE__, size_t ln = __LINE__)
87 string msg;
89 if (source.empty)
90 msg = "Unexpected end of input when converting from type " ~ S.stringof ~ " to type " ~ T.stringof;
91 else
93 ElementType!S el = source.front;
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);
102 return new ConvException(msg, fn, ln);
105 @safe pure/* nothrow*/ // lazy parameter bug
106 private auto parseError(lazy string msg, string fn = __FILE__, size_t ln = __LINE__)
108 return new ConvException(text("Can't parse string: ", msg), fn, ln);
111 private void parseCheck(alias source)(dchar c, string fn = __FILE__, size_t ln = __LINE__)
113 if (source.empty)
114 throw parseError(text("unexpected end of input when expecting \"", c, "\""));
115 if (source.front != c)
116 throw parseError(text("\"", c, "\" is missing"), fn, ln);
117 source.popFront();
120 private
122 T toStr(T, S)(S src)
123 if (isSomeString!T)
125 // workaround for https://issues.dlang.org/show_bug.cgi?id=14198
126 static if (is(S == bool) && is(typeof({ T s = "string"; })))
128 return src ? "true" : "false";
130 else
132 import std.array : appender;
133 import std.format.spec : FormatSpec;
134 import std.format.write : formatValue;
136 auto w = appender!T();
137 FormatSpec!(ElementEncodingType!T) f;
138 formatValue(w, src, f);
139 return w.data;
143 template isExactSomeString(T)
145 enum isExactSomeString = isSomeString!T && !is(T == enum);
148 template isEnumStrToStr(S, T)
150 enum isEnumStrToStr = is(S : T) &&
151 is(S == enum) && isExactSomeString!T;
153 template isNullToStr(S, T)
155 enum isNullToStr = is(S : T) &&
156 (is(immutable S == immutable typeof(null))) && isExactSomeString!T;
161 * Thrown on conversion overflow errors.
163 class ConvOverflowException : ConvException
165 @safe pure nothrow
166 this(string s, string fn = __FILE__, size_t ln = __LINE__)
168 super(s, fn, ln);
173 @safe unittest
175 import std.exception : assertThrown;
176 assertThrown!ConvOverflowException(to!ubyte(1_000_000));
180 The `to` template converts a value from one type _to another.
181 The source type is deduced and the target type must be specified, for example the
182 expression `to!int(42.0)` converts the number 42 from
183 `double` _to `int`. The conversion is "safe", i.e.,
184 it checks for overflow; `to!int(4.2e10)` would throw the
185 `ConvOverflowException` exception. Overflow checks are only
186 inserted when necessary, e.g., `to!double(42)` does not do
187 any checking because any `int` fits in a `double`.
189 Conversions from string _to numeric types differ from the C equivalents
190 `atoi()` and `atol()` by checking for overflow and not allowing whitespace.
192 For conversion of strings _to signed types, the grammar recognized is:
193 $(PRE $(I Integer):
194 $(I Sign UnsignedInteger)
195 $(I UnsignedInteger)
196 $(I Sign):
197 $(B +)
198 $(B -))
200 For conversion _to unsigned types, the grammar recognized is:
201 $(PRE $(I UnsignedInteger):
202 $(I DecimalDigit)
203 $(I DecimalDigit) $(I UnsignedInteger))
205 template to(T)
207 T to(A...)(A args)
208 if (A.length > 0)
210 return toImpl!T(args);
213 // Fix https://issues.dlang.org/show_bug.cgi?id=6175
214 T to(S)(ref S arg)
215 if (isStaticArray!S)
217 return toImpl!T(arg);
220 // Fix https://issues.dlang.org/show_bug.cgi?id=16108
221 T to(S)(ref S arg)
222 if (isAggregateType!S && !isCopyable!S)
224 return toImpl!T(arg);
229 * Converting a value _to its own type (useful mostly for generic code)
230 * simply returns its argument.
232 @safe pure unittest
234 int a = 42;
235 int b = to!int(a);
236 double c = to!double(3.14); // c is double with value 3.14
240 * Converting among numeric types is a safe way _to cast them around.
242 * Conversions from floating-point types _to integral types allow loss of
243 * precision (the fractional part of a floating-point number). The
244 * conversion is truncating towards zero, the same way a cast would
245 * truncate. (_To round a floating point value when casting _to an
246 * integral, use `roundTo`.)
248 @safe pure unittest
250 import std.exception : assertThrown;
252 int a = 420;
253 assert(to!long(a) == a);
254 assertThrown!ConvOverflowException(to!byte(a));
256 assert(to!int(4.2e6) == 4200000);
257 assertThrown!ConvOverflowException(to!uint(-3.14));
258 assert(to!uint(3.14) == 3);
259 assert(to!uint(3.99) == 3);
260 assert(to!int(-3.99) == -3);
264 * When converting strings _to numeric types, note that D hexadecimal and binary
265 * literals are not handled. Neither the prefixes that indicate the base, nor the
266 * horizontal bar used _to separate groups of digits are recognized. This also
267 * applies to the suffixes that indicate the type.
269 * _To work around this, you can specify a radix for conversions involving numbers.
271 @safe pure unittest
273 auto str = to!string(42, 16);
274 assert(str == "2A");
275 auto i = to!int(str, 16);
276 assert(i == 42);
280 * Conversions from integral types _to floating-point types always
281 * succeed, but might lose accuracy. The largest integers with a
282 * predecessor representable in floating-point format are `2^24-1` for
283 * `float`, `2^53-1` for `double`, and `2^64-1` for `real` (when
284 * `real` is 80-bit, e.g. on Intel machines).
286 @safe pure unittest
288 // 2^24 - 1, largest proper integer representable as float
289 int a = 16_777_215;
290 assert(to!int(to!float(a)) == a);
291 assert(to!int(to!float(-a)) == -a);
295 Conversion from string types to char types enforces the input
296 to consist of a single code point, and said code point must
297 fit in the target type. Otherwise, $(LREF ConvException) is thrown.
299 @safe pure unittest
301 import std.exception : assertThrown;
303 assert(to!char("a") == 'a');
304 assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
305 assert(to!wchar("ñ") == 'ñ');
306 assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
307 assert(to!dchar("😃") == '😃');
309 // Using wstring or dstring as source type does not affect the result
310 assert(to!char("a"w) == 'a');
311 assert(to!char("a"d) == 'a');
313 // Two code points cannot be converted to a single one
314 assertThrown(to!char("ab"));
318 * Converting an array _to another array type works by converting each
319 * element in turn. Associative arrays can be converted _to associative
320 * arrays as long as keys and values can in turn be converted.
322 @safe pure unittest
324 import std.string : split;
326 int[] a = [1, 2, 3];
327 auto b = to!(float[])(a);
328 assert(b == [1.0f, 2, 3]);
329 string str = "1 2 3 4 5 6";
330 auto numbers = to!(double[])(split(str));
331 assert(numbers == [1.0, 2, 3, 4, 5, 6]);
332 int[string] c;
333 c["a"] = 1;
334 c["b"] = 2;
335 auto d = to!(double[wstring])(c);
336 assert(d["a"w] == 1 && d["b"w] == 2);
340 * Conversions operate transitively, meaning that they work on arrays and
341 * associative arrays of any complexity.
343 * This conversion works because `to!short` applies _to an `int`, `to!wstring`
344 * applies _to a `string`, `to!string` applies _to a `double`, and
345 * `to!(double[])` applies _to an `int[]`. The conversion might throw an
346 * exception because `to!short` might fail the range check.
348 @safe unittest
350 int[string][double[int[]]] a;
351 auto b = to!(short[wstring][string[double[]]])(a);
355 * Object-to-object conversions by dynamic casting throw exception when
356 * the source is non-null and the target is null.
358 @safe pure unittest
360 import std.exception : assertThrown;
361 // Testing object conversions
362 class A {}
363 class B : A {}
364 class C : A {}
365 A a1 = new A, a2 = new B, a3 = new C;
366 assert(to!B(a2) is a2);
367 assert(to!C(a3) is a3);
368 assertThrown!ConvException(to!B(a3));
372 * Stringize conversion from all types is supported.
373 * $(UL
374 * $(LI String _to string conversion works for any two string types having
375 * (`char`, `wchar`, `dchar`) character widths and any
376 * combination of qualifiers (mutable, `const`, or `immutable`).)
377 * $(LI Converts array (other than strings) _to string.
378 * Each element is converted by calling `to!T`.)
379 * $(LI Associative array _to string conversion.
380 * Each element is converted by calling `to!T`.)
381 * $(LI Object _to string conversion calls `toString` against the object or
382 * returns `"null"` if the object is null.)
383 * $(LI Struct _to string conversion calls `toString` against the struct if
384 * it is defined.)
385 * $(LI For structs that do not define `toString`, the conversion _to string
386 * produces the list of fields.)
387 * $(LI Enumerated types are converted _to strings as their symbolic names.)
388 * $(LI Boolean values are converted to `"true"` or `"false"`.)
389 * $(LI `char`, `wchar`, `dchar` _to a string type.)
390 * $(LI Unsigned or signed integers _to strings.
391 * $(DL $(DT [special case])
392 * $(DD Convert integral value _to string in $(D_PARAM radix) radix.
393 * radix must be a value from 2 to 36.
394 * value is treated as a signed value only if radix is 10.
395 * The characters A through Z are used to represent values 10 through 36
396 * and their case is determined by the $(D_PARAM letterCase) parameter.)))
397 * $(LI All floating point types _to all string types.)
398 * $(LI Pointer to string conversions convert the pointer to a `size_t` value.
399 * If pointer is `char*`, treat it as C-style strings.
400 * In that case, this function is `@system`.))
401 * See $(REF formatValue, std,format) on how `toString` should be defined.
403 @system pure unittest // @system due to cast and ptr
405 // Conversion representing dynamic/static array with string
406 long[] a = [ 1, 3, 5 ];
407 assert(to!string(a) == "[1, 3, 5]");
409 // Conversion representing associative array with string
410 int[string] associativeArray = ["0":1, "1":2];
411 assert(to!string(associativeArray) == `["0":1, "1":2]` ||
412 to!string(associativeArray) == `["1":2, "0":1]`);
414 // char* to string conversion
415 assert(to!string(cast(char*) null) == "");
416 assert(to!string("foo\0".ptr) == "foo");
418 // Conversion reinterpreting void array to string
419 auto w = "abcx"w;
420 const(void)[] b = w;
421 assert(b.length == 8);
423 auto c = to!(wchar[])(b);
424 assert(c == "abcx");
428 * Strings can be converted to enum types. The enum member with the same name as the
429 * input string is returned. The comparison is case-sensitive.
431 * A $(LREF ConvException) is thrown if the enum does not have the specified member.
433 @safe pure unittest
435 import std.exception : assertThrown;
437 enum E { a, b, c }
438 assert(to!E("a") == E.a);
439 assert(to!E("b") == E.b);
440 assertThrown!ConvException(to!E("A"));
443 // Tests for https://issues.dlang.org/show_bug.cgi?id=6175
444 @safe pure nothrow unittest
446 char[9] sarr = "blablabla";
447 auto darr = to!(char[])(sarr);
448 assert(sarr.ptr == darr.ptr);
449 assert(sarr.length == darr.length);
452 // Tests for https://issues.dlang.org/show_bug.cgi?id=7348
453 @safe pure /+nothrow+/ unittest
455 assert(to!string(null) == "null");
456 assert(text(null) == "null");
459 // Test `scope` inference of parameters of `text`
460 @safe unittest
462 static struct S
464 int* x; // make S a type with pointers
465 string toString() const scope
467 return "S";
470 scope S s;
471 assert(text("a", s) == "aS");
474 // Tests for https://issues.dlang.org/show_bug.cgi?id=11390
475 @safe pure /+nothrow+/ unittest
477 const(typeof(null)) ctn;
478 immutable(typeof(null)) itn;
479 assert(to!string(ctn) == "null");
480 assert(to!string(itn) == "null");
483 // Tests for https://issues.dlang.org/show_bug.cgi?id=8729: do NOT skip leading WS
484 @safe pure unittest
486 import std.exception;
487 static foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
489 assertThrown!ConvException(to!T(" 0"));
490 assertThrown!ConvException(to!T(" 0", 8));
492 static foreach (T; AliasSeq!(float, double, real))
494 assertThrown!ConvException(to!T(" 0"));
497 assertThrown!ConvException(to!bool(" true"));
499 alias NullType = typeof(null);
500 assertThrown!ConvException(to!NullType(" null"));
502 alias ARR = int[];
503 assertThrown!ConvException(to!ARR(" [1]"));
505 alias AA = int[int];
506 assertThrown!ConvException(to!AA(" [1:1]"));
509 // https://issues.dlang.org/show_bug.cgi?id=20623
510 @safe pure nothrow unittest
512 // static class C
513 // {
514 // override string toString() const
515 // {
516 // return "C()";
517 // }
518 // }
520 static struct S
522 bool b;
523 int i;
524 float f;
525 int[] a;
526 int[int] aa;
527 S* p;
528 // C c; // TODO: Fails because of hasToString
530 void fun() inout
532 static foreach (const idx; 0 .. this.tupleof.length)
535 const _ = this.tupleof[idx].to!string();
543 If the source type is implicitly convertible to the target type, $(D
544 to) simply performs the implicit conversion.
546 private T toImpl(T, S)(S value)
547 if (is(S : T) &&
548 !isEnumStrToStr!(S, T) && !isNullToStr!(S, T))
550 template isSignedInt(T)
552 enum isSignedInt = isIntegral!T && isSigned!T;
554 alias isUnsignedInt = isUnsigned;
556 // Conversion from integer to integer, and changing its sign
557 static if (isUnsignedInt!S && isSignedInt!T && S.sizeof == T.sizeof)
558 { // unsigned to signed & same size
559 import std.exception : enforce;
560 enforce(value <= cast(S) T.max,
561 new ConvOverflowException("Conversion positive overflow"));
563 else static if (isSignedInt!S && isUnsignedInt!T)
564 { // signed to unsigned
565 import std.exception : enforce;
566 enforce(0 <= value,
567 new ConvOverflowException("Conversion negative overflow"));
570 return value;
573 // https://issues.dlang.org/show_bug.cgi?id=9523: Allow identity enum conversion
574 @safe pure nothrow unittest
576 enum E { a }
577 auto e = to!E(E.a);
578 assert(e == E.a);
581 @safe pure nothrow unittest
583 int a = 42;
584 auto b = to!long(a);
585 assert(a == b);
588 // https://issues.dlang.org/show_bug.cgi?id=6377
589 @safe pure unittest
591 import std.exception;
592 // Conversion between same size
593 static foreach (S; AliasSeq!(byte, short, int, long))
595 alias U = Unsigned!S;
597 static foreach (Sint; AliasSeq!(S, const S, immutable S))
598 static foreach (Uint; AliasSeq!(U, const U, immutable U))
600 // positive overflow
601 Uint un = Uint.max;
602 assertThrown!ConvOverflowException(to!Sint(un),
603 text(Sint.stringof, ' ', Uint.stringof, ' ', un));
605 // negative overflow
606 Sint sn = -1;
607 assertThrown!ConvOverflowException(to!Uint(sn),
608 text(Sint.stringof, ' ', Uint.stringof, ' ', un));
612 // Conversion between different size
613 static foreach (i, S1; AliasSeq!(byte, short, int, long))
614 static foreach ( S2; AliasSeq!(byte, short, int, long)[i+1..$])
616 alias U1 = Unsigned!S1;
617 alias U2 = Unsigned!S2;
619 static assert(U1.sizeof < S2.sizeof);
621 // small unsigned to big signed
622 static foreach (Uint; AliasSeq!(U1, const U1, immutable U1))
623 static foreach (Sint; AliasSeq!(S2, const S2, immutable S2))
625 Uint un = Uint.max;
626 assertNotThrown(to!Sint(un));
627 assert(to!Sint(un) == un);
630 // big unsigned to small signed
631 static foreach (Uint; AliasSeq!(U2, const U2, immutable U2))
632 static foreach (Sint; AliasSeq!(S1, const S1, immutable S1))
634 Uint un = Uint.max;
635 assertThrown(to!Sint(un));
638 static assert(S1.sizeof < U2.sizeof);
640 // small signed to big unsigned
641 static foreach (Sint; AliasSeq!(S1, const S1, immutable S1))
642 static foreach (Uint; AliasSeq!(U2, const U2, immutable U2))
644 Sint sn = -1;
645 assertThrown!ConvOverflowException(to!Uint(sn));
648 // big signed to small unsigned
649 static foreach (Sint; AliasSeq!(S2, const S2, immutable S2))
650 static foreach (Uint; AliasSeq!(U1, const U1, immutable U1))
652 Sint sn = -1;
653 assertThrown!ConvOverflowException(to!Uint(sn));
658 // https://issues.dlang.org/show_bug.cgi?id=13551
659 private T toImpl(T, S)(S value)
660 if (isTuple!T)
662 T t;
663 static foreach (i; 0 .. T.length)
665 t[i] = value[i].to!(typeof(T[i]));
667 return t;
670 @safe unittest
672 import std.typecons : Tuple;
674 auto test = ["10", "20", "30"];
675 assert(test.to!(Tuple!(int, int, int)) == Tuple!(int, int, int)(10, 20, 30));
677 auto test1 = [1, 2];
678 assert(test1.to!(Tuple!(int, int)) == Tuple!(int, int)(1, 2));
680 auto test2 = [1.0, 2.0, 3.0];
681 assert(test2.to!(Tuple!(int, int, int)) == Tuple!(int, int, int)(1, 2, 3));
685 Converting static arrays forwards to their dynamic counterparts.
687 private T toImpl(T, S)(ref S s)
688 if (isStaticArray!S)
690 return toImpl!(T, typeof(s[0])[])(s);
693 @safe pure nothrow unittest
695 char[4] test = ['a', 'b', 'c', 'd'];
696 static assert(!isInputRange!(Unqual!(char[4])));
697 assert(to!string(test) == test);
701 When source type supports member template function opCast, it is used.
703 private T toImpl(T, S)(S value)
704 if (!is(S : T) &&
705 is(typeof(S.init.opCast!T()) : T) &&
706 !isExactSomeString!T &&
707 !is(typeof(T(value))))
709 return value.opCast!T();
712 @safe pure unittest
714 static struct Test
716 struct T
718 this(S s) @safe pure { }
720 struct S
722 T opCast(U)() @safe pure { assert(false); }
725 cast(void) to!(Test.T)(Test.S());
727 // make sure std.conv.to is doing the same thing as initialization
728 Test.S s;
729 Test.T t = s;
732 @safe pure unittest
734 class B
736 T opCast(T)() { return 43; }
738 auto b = new B;
739 assert(to!int(b) == 43);
741 struct S
743 T opCast(T)() { return 43; }
745 auto s = S();
746 assert(to!int(s) == 43);
750 When target type supports 'converting construction', it is used.
751 $(UL $(LI If target type is struct, `T(value)` is used.)
752 $(LI If target type is class, $(D new T(value)) is used.))
754 private T toImpl(T, S)(S value)
755 if (!is(S : T) &&
756 is(T == struct) && is(typeof(T(value))))
758 return T(value);
761 // https://issues.dlang.org/show_bug.cgi?id=3961
762 @safe pure unittest
764 struct Int
766 int x;
768 Int i = to!Int(1);
770 static struct Int2
772 int x;
773 this(int x) @safe pure { this.x = x; }
775 Int2 i2 = to!Int2(1);
777 static struct Int3
779 int x;
780 static Int3 opCall(int x) @safe pure
782 Int3 i;
783 i.x = x;
784 return i;
787 Int3 i3 = to!Int3(1);
790 // https://issues.dlang.org/show_bug.cgi?id=6808
791 @safe pure unittest
793 static struct FakeBigInt
795 this(string s) @safe pure {}
798 string s = "101";
799 auto i3 = to!FakeBigInt(s);
802 /// ditto
803 private T toImpl(T, S)(S value)
804 if (!is(S : T) &&
805 is(T == class) && is(typeof(new T(value))))
807 return new T(value);
810 @safe pure unittest
812 static struct S
814 int x;
816 static class C
818 int x;
819 this(int x) @safe pure { this.x = x; }
822 static class B
824 int value;
825 this(S src) @safe pure { value = src.x; }
826 this(C src) @safe pure { value = src.x; }
829 S s = S(1);
830 auto b1 = to!B(s); // == new B(s)
831 assert(b1.value == 1);
833 C c = new C(2);
834 auto b2 = to!B(c); // == new B(c)
835 assert(b2.value == 2);
837 auto c2 = to!C(3); // == new C(3)
838 assert(c2.x == 3);
841 @safe pure unittest
843 struct S
845 class A
847 this(B b) @safe pure {}
849 class B : A
851 this() @safe pure { super(this); }
855 S.B b = new S.B();
856 S.A a = to!(S.A)(b); // == cast(S.A) b
857 // (do not run construction conversion like new S.A(b))
858 assert(b is a);
860 static class C : Object
862 this() @safe pure {}
863 this(Object o) @safe pure {}
866 Object oc = new C();
867 C a2 = to!C(oc); // == new C(a)
868 // Construction conversion overrides down-casting conversion
869 assert(a2 !is a); //
873 Object-to-object conversions by dynamic casting throw exception when the source is
874 non-null and the target is null.
876 private T toImpl(T, S)(S value)
877 if (!is(S : T) &&
878 (is(S == class) || is(S == interface)) && !is(typeof(value.opCast!T()) : T) &&
879 (is(T == class) || is(T == interface)) && !is(typeof(new T(value))))
881 static if (is(T == immutable))
883 // immutable <- immutable
884 enum isModConvertible = is(S == immutable);
886 else static if (is(T == const))
888 static if (is(T == shared))
890 // shared const <- shared
891 // shared const <- shared const
892 // shared const <- immutable
893 enum isModConvertible = is(S == shared) || is(S == immutable);
895 else
897 // const <- mutable
898 // const <- immutable
899 enum isModConvertible = !is(S == shared);
902 else
904 static if (is(T == shared))
906 // shared <- shared mutable
907 enum isModConvertible = is(S == shared) && !is(S == const);
909 else
911 // (mutable) <- (mutable)
912 enum isModConvertible = is(Unqual!S == S);
915 static assert(isModConvertible, "Bad modifier conversion: "~S.stringof~" to "~T.stringof);
917 auto result = ()@trusted{ return cast(T) value; }();
918 if (!result && value)
920 throw new ConvException("Cannot convert object of static type "
921 ~S.classinfo.name~" and dynamic type "~value.classinfo.name
922 ~" to type "~T.classinfo.name);
924 return result;
927 // Unittest for 6288
928 @safe pure unittest
930 import std.exception;
932 alias Identity(T) = T;
933 alias toConst(T) = const T;
934 alias toShared(T) = shared T;
935 alias toSharedConst(T) = shared const T;
936 alias toImmutable(T) = immutable T;
937 template AddModifier(int n)
938 if (0 <= n && n < 5)
940 static if (n == 0) alias AddModifier = Identity;
941 else static if (n == 1) alias AddModifier = toConst;
942 else static if (n == 2) alias AddModifier = toShared;
943 else static if (n == 3) alias AddModifier = toSharedConst;
944 else static if (n == 4) alias AddModifier = toImmutable;
947 interface I {}
948 interface J {}
950 class A {}
951 class B : A {}
952 class C : B, I, J {}
953 class D : I {}
955 static foreach (m1; 0 .. 5) // enumerate modifiers
956 static foreach (m2; 0 .. 5) // ditto
958 alias srcmod = AddModifier!m1;
959 alias tgtmod = AddModifier!m2;
961 // Compile time convertible equals to modifier convertible.
962 static if (is(srcmod!Object : tgtmod!Object))
964 // Test runtime conversions: class to class, class to interface,
965 // interface to class, and interface to interface
967 // Check that the runtime conversion to succeed
968 srcmod!A ac = new srcmod!C();
969 srcmod!I ic = new srcmod!C();
970 assert(to!(tgtmod!C)(ac) !is null); // A(c) to C
971 assert(to!(tgtmod!I)(ac) !is null); // A(c) to I
972 assert(to!(tgtmod!C)(ic) !is null); // I(c) to C
973 assert(to!(tgtmod!J)(ic) !is null); // I(c) to J
975 // Check that the runtime conversion fails
976 srcmod!A ab = new srcmod!B();
977 srcmod!I id = new srcmod!D();
978 assertThrown(to!(tgtmod!C)(ab)); // A(b) to C
979 assertThrown(to!(tgtmod!I)(ab)); // A(b) to I
980 assertThrown(to!(tgtmod!C)(id)); // I(d) to C
981 assertThrown(to!(tgtmod!J)(id)); // I(d) to J
983 else
985 // Check that the conversion is rejected statically
986 static assert(!is(typeof(to!(tgtmod!C)(srcmod!A.init)))); // A to C
987 static assert(!is(typeof(to!(tgtmod!I)(srcmod!A.init)))); // A to I
988 static assert(!is(typeof(to!(tgtmod!C)(srcmod!I.init)))); // I to C
989 static assert(!is(typeof(to!(tgtmod!J)(srcmod!I.init)))); // I to J
995 Handles type _to string conversions
997 private T toImpl(T, S)(S value)
998 if (!(is(S : T) &&
999 !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
1000 !isInfinite!S && isExactSomeString!T)
1002 static if (isExactSomeString!S && value[0].sizeof == ElementEncodingType!T.sizeof)
1004 // string-to-string with incompatible qualifier conversion
1005 static if (is(ElementEncodingType!T == immutable))
1007 // conversion (mutable|const) -> immutable
1008 return value.idup;
1010 else
1012 // conversion (immutable|const) -> mutable
1013 return value.dup;
1016 else static if (isExactSomeString!S)
1018 import std.array : appender;
1019 // other string-to-string
1020 //Use Appender directly instead of toStr, which also uses a formatedWrite
1021 auto w = appender!T();
1022 w.put(value);
1023 return w.data;
1025 else static if (isIntegral!S && !is(S == enum))
1027 // other integral-to-string conversions with default radix
1029 import core.internal.string : signedToTempString, unsignedToTempString;
1031 alias EEType = Unqual!(ElementEncodingType!T);
1032 EEType[long.sizeof * 3 + 1] buf = void;
1033 EEType[] t = isSigned!S
1034 ? signedToTempString!(10, false, EEType)(value, buf)
1035 : unsignedToTempString!(10, false, EEType)(value, buf);
1036 return t.dup;
1038 else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[]))
1040 import core.stdc.string : memcpy;
1041 import std.exception : enforce;
1042 // Converting void array to string
1043 alias Char = Unqual!(ElementEncodingType!T);
1044 auto raw = cast(const(ubyte)[]) value;
1045 enforce(raw.length % Char.sizeof == 0,
1046 new ConvException("Alignment mismatch in converting a "
1047 ~ S.stringof ~ " to a "
1048 ~ T.stringof));
1049 auto result = new Char[raw.length / Char.sizeof];
1050 ()@trusted{ memcpy(result.ptr, value.ptr, value.length); }();
1051 return cast(T) result;
1053 else static if (isPointer!S && isSomeChar!(PointerTarget!S))
1055 // This is unsafe because we cannot guarantee that the pointer is null terminated.
1056 return () @system {
1057 static if (is(S : const(char)*))
1058 import core.stdc.string : strlen;
1059 else
1060 size_t strlen(S s) nothrow
1062 S p = s;
1063 while (*p++) {}
1064 return p-s-1;
1066 return toImpl!T(value ? value[0 .. strlen(value)].dup : null);
1067 }();
1069 else static if (isSomeString!T && is(S == enum))
1071 static if (isSwitchable!(OriginalType!S) && EnumMembers!S.length <= 50)
1073 switch (value)
1075 foreach (member; NoDuplicates!(EnumMembers!S))
1077 case member:
1078 return to!T(enumRep!(immutable(T), S, member));
1080 default:
1083 else
1085 foreach (member; EnumMembers!S)
1087 if (value == member)
1088 return to!T(enumRep!(immutable(T), S, member));
1092 import std.array : appender;
1093 import std.format.spec : FormatSpec;
1094 import std.format.write : formatValue;
1096 //Default case, delegate to format
1097 //Note: we don't call toStr directly, to avoid duplicate work.
1098 auto app = appender!T();
1099 app.put("cast(" ~ S.stringof ~ ")");
1100 FormatSpec!char f;
1101 formatValue(app, cast(OriginalType!S) value, f);
1102 return app.data;
1104 else
1106 // other non-string values runs formatting
1107 return toStr!T(value);
1111 // https://issues.dlang.org/show_bug.cgi?id=14042
1112 @system unittest
1114 immutable(char)* ptr = "hello".ptr;
1115 auto result = ptr.to!(char[]);
1117 // https://issues.dlang.org/show_bug.cgi?id=8384
1118 @system unittest
1120 void test1(T)(T lp, string cmp)
1122 static foreach (e; AliasSeq!(char, wchar, dchar))
1124 test2!(e[])(lp, cmp);
1125 test2!(const(e)[])(lp, cmp);
1126 test2!(immutable(e)[])(lp, cmp);
1130 void test2(D, S)(S lp, string cmp)
1132 assert(to!string(to!D(lp)) == cmp);
1135 static foreach (e; AliasSeq!("Hello, world!", "Hello, world!"w, "Hello, world!"d))
1137 test1(e, "Hello, world!");
1138 test1(e.ptr, "Hello, world!");
1140 static foreach (e; AliasSeq!("", ""w, ""d))
1142 test1(e, "");
1143 test1(e.ptr, "");
1148 To string conversion for non copy-able structs
1150 private T toImpl(T, S)(ref S value)
1151 if (!(is(S : T) &&
1152 !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
1153 !isInfinite!S && isExactSomeString!T && !isCopyable!S && !isStaticArray!S)
1155 import std.array : appender;
1156 import std.format.spec : FormatSpec;
1157 import std.format.write : formatValue;
1159 auto w = appender!T();
1160 FormatSpec!(ElementEncodingType!T) f;
1161 formatValue(w, value, f);
1162 return w.data;
1165 // https://issues.dlang.org/show_bug.cgi?id=16108
1166 @safe unittest
1168 static struct A
1170 int val;
1171 bool flag;
1173 string toString() { return text(val, ":", flag); }
1175 @disable this(this);
1178 auto a = A();
1179 assert(to!string(a) == "0:false");
1181 static struct B
1183 int val;
1184 bool flag;
1186 @disable this(this);
1189 auto b = B();
1190 assert(to!string(b) == "B(0, false)");
1193 // https://issues.dlang.org/show_bug.cgi?id=20070
1194 @safe unittest
1196 void writeThem(T)(ref inout(T) them)
1198 assert(them.to!string == "[1, 2, 3, 4]");
1201 const(uint)[4] vals = [ 1, 2, 3, 4 ];
1202 writeThem(vals);
1206 Check whether type `T` can be used in a switch statement.
1207 This is useful for compile-time generation of switch case statements.
1209 private template isSwitchable(E)
1211 enum bool isSwitchable = is(typeof({
1212 switch (E.init) { default: }
1213 }));
1217 @safe unittest
1219 static assert(isSwitchable!int);
1220 static assert(!isSwitchable!double);
1221 static assert(!isSwitchable!real);
1224 //Static representation of the index I of the enum S,
1225 //In representation T.
1226 //T must be an immutable string (avoids un-necessary initializations).
1227 private template enumRep(T, S, S value)
1228 if (is (T == immutable) && isExactSomeString!T && is(S == enum))
1230 static T enumRep = toStr!T(value);
1233 @safe pure unittest
1235 import std.exception;
1236 void dg()
1238 // string to string conversion
1239 alias Chars = AliasSeq!(char, wchar, dchar);
1240 foreach (LhsC; Chars)
1242 alias LhStrings = AliasSeq!(LhsC[], const(LhsC)[], immutable(LhsC)[]);
1243 foreach (Lhs; LhStrings)
1245 foreach (RhsC; Chars)
1247 alias RhStrings = AliasSeq!(RhsC[], const(RhsC)[], immutable(RhsC)[]);
1248 foreach (Rhs; RhStrings)
1250 Lhs s1 = to!Lhs("wyda");
1251 Rhs s2 = to!Rhs(s1);
1252 //writeln(Lhs.stringof, " -> ", Rhs.stringof);
1253 assert(s1 == to!Lhs(s2));
1259 foreach (T; Chars)
1261 foreach (U; Chars)
1263 T[] s1 = to!(T[])("Hello, world!");
1264 auto s2 = to!(U[])(s1);
1265 assert(s1 == to!(T[])(s2));
1266 auto s3 = to!(const(U)[])(s1);
1267 assert(s1 == to!(T[])(s3));
1268 auto s4 = to!(immutable(U)[])(s1);
1269 assert(s1 == to!(T[])(s4));
1273 dg();
1274 assertCTFEable!dg;
1277 @safe pure unittest
1279 // Conversion representing bool value with string
1280 bool b;
1281 assert(to!string(b) == "false");
1282 b = true;
1283 assert(to!string(b) == "true");
1286 @safe pure unittest
1288 // Conversion representing character value with string
1289 alias AllChars =
1290 AliasSeq!( char, const( char), immutable( char),
1291 wchar, const(wchar), immutable(wchar),
1292 dchar, const(dchar), immutable(dchar));
1293 foreach (Char1; AllChars)
1295 foreach (Char2; AllChars)
1297 Char1 c = 'a';
1298 assert(to!(Char2[])(c)[0] == c);
1300 uint x = 4;
1301 assert(to!(Char1[])(x) == "4");
1304 string s = "foo";
1305 string s2;
1306 foreach (char c; s)
1308 s2 ~= to!string(c);
1310 assert(s2 == "foo");
1313 @safe pure nothrow unittest
1315 import std.exception;
1316 // Conversion representing integer values with string
1318 static foreach (Int; AliasSeq!(ubyte, ushort, uint, ulong))
1320 assert(to!string(Int(0)) == "0");
1321 assert(to!string(Int(9)) == "9");
1322 assert(to!string(Int(123)) == "123");
1325 static foreach (Int; AliasSeq!(byte, short, int, long))
1327 assert(to!string(Int(0)) == "0");
1328 assert(to!string(Int(9)) == "9");
1329 assert(to!string(Int(123)) == "123");
1330 assert(to!string(Int(-0)) == "0");
1331 assert(to!string(Int(-9)) == "-9");
1332 assert(to!string(Int(-123)) == "-123");
1333 assert(to!string(const(Int)(6)) == "6");
1336 assert(wtext(int.max) == "2147483647"w);
1337 assert(wtext(int.min) == "-2147483648"w);
1338 assert(to!string(0L) == "0");
1340 assertCTFEable!(
1342 assert(to!string(1uL << 62) == "4611686018427387904");
1343 assert(to!string(0x100000000) == "4294967296");
1344 assert(to!string(-138L) == "-138");
1348 @safe unittest // sprintf issue
1350 double[2] a = [ 1.5, 2.5 ];
1351 assert(to!string(a) == "[1.5, 2.5]");
1354 @safe unittest
1356 // Conversion representing class object with string
1357 class A
1359 override string toString() @safe const { return "an A"; }
1361 A a;
1362 assert(to!string(a) == "null");
1363 a = new A;
1364 assert(to!string(a) == "an A");
1366 // https://issues.dlang.org/show_bug.cgi?id=7660
1367 class C { override string toString() @safe const { return "C"; } }
1368 struct S { C c; alias c this; }
1369 S s; s.c = new C();
1370 assert(to!string(s) == "C");
1373 @safe unittest
1375 // Conversion representing struct object with string
1376 struct S1
1378 string toString() { return "wyda"; }
1380 assert(to!string(S1()) == "wyda");
1382 struct S2
1384 int a = 42;
1385 float b = 43.5;
1387 S2 s2;
1388 assert(to!string(s2) == "S2(42, 43.5)");
1390 // Test for https://issues.dlang.org/show_bug.cgi?id=8080
1391 struct S8080
1393 short[4] data;
1394 alias data this;
1395 string toString() { return "<S>"; }
1397 S8080 s8080;
1398 assert(to!string(s8080) == "<S>");
1401 @safe unittest
1403 // Conversion representing enum value with string
1404 enum EB : bool { a = true }
1405 enum EU : uint { a = 0, b = 1, c = 2 } // base type is unsigned
1406 // base type is signed (https://issues.dlang.org/show_bug.cgi?id=7909)
1407 enum EI : int { a = -1, b = 0, c = 1 }
1408 enum EF : real { a = 1.414, b = 1.732, c = 2.236 }
1409 enum EC : char { a = 'x', b = 'y' }
1410 enum ES : string { a = "aaa", b = "bbb" }
1412 static foreach (E; AliasSeq!(EB, EU, EI, EF, EC, ES))
1414 assert(to! string(E.a) == "a"c);
1415 assert(to!wstring(E.a) == "a"w);
1416 assert(to!dstring(E.a) == "a"d);
1419 // Test an value not corresponding to an enum member.
1420 auto o = cast(EU) 5;
1421 assert(to! string(o) == "cast(EU)5"c);
1422 assert(to!wstring(o) == "cast(EU)5"w);
1423 assert(to!dstring(o) == "cast(EU)5"d);
1426 @safe unittest
1428 enum E
1430 foo,
1431 doo = foo, // check duplicate switch statements
1432 bar,
1435 //Test regression 12494
1436 assert(to!string(E.foo) == "foo");
1437 assert(to!string(E.doo) == "foo");
1438 assert(to!string(E.bar) == "bar");
1440 static foreach (S; AliasSeq!(string, wstring, dstring, const(char[]), const(wchar[]), const(dchar[])))
1442 auto s1 = to!S(E.foo);
1443 auto s2 = to!S(E.foo);
1444 assert(s1 == s2);
1445 // ensure we don't allocate when it's unnecessary
1446 assert(s1 is s2);
1449 static foreach (S; AliasSeq!(char[], wchar[], dchar[]))
1451 auto s1 = to!S(E.foo);
1452 auto s2 = to!S(E.foo);
1453 assert(s1 == s2);
1454 // ensure each mutable array is unique
1455 assert(s1 !is s2);
1459 // ditto
1460 @trusted pure private T toImpl(T, S)(S value, uint radix, LetterCase letterCase = LetterCase.upper)
1461 if (isIntegral!S &&
1462 isExactSomeString!T)
1465 assert(radix >= 2 && radix <= 36, "radix must be in range [2,36]");
1469 alias EEType = Unqual!(ElementEncodingType!T);
1471 T toStringRadixConvert(size_t bufLen)(uint runtimeRadix = 0)
1473 Unsigned!(Unqual!S) div = void, mValue = unsigned(value);
1475 size_t index = bufLen;
1476 EEType[bufLen] buffer = void;
1477 char baseChar = letterCase == LetterCase.lower ? 'a' : 'A';
1478 char mod = void;
1482 div = cast(S)(mValue / runtimeRadix );
1483 mod = cast(ubyte)(mValue % runtimeRadix);
1484 mod += mod < 10 ? '0' : baseChar - 10;
1485 buffer[--index] = cast(char) mod;
1486 mValue = div;
1487 } while (mValue);
1489 return cast(T) buffer[index .. $].dup;
1492 import std.array : array;
1493 switch (radix)
1495 case 10:
1496 // The (value+0) is so integral promotions happen to the type
1497 return toChars!(10, EEType)(value + 0).array;
1498 case 16:
1499 // The unsigned(unsigned(value)+0) is so unsigned integral promotions happen to the type
1500 if (letterCase == letterCase.upper)
1501 return toChars!(16, EEType, LetterCase.upper)(unsigned(unsigned(value) + 0)).array;
1502 else
1503 return toChars!(16, EEType, LetterCase.lower)(unsigned(unsigned(value) + 0)).array;
1504 case 2:
1505 return toChars!(2, EEType)(unsigned(unsigned(value) + 0)).array;
1506 case 8:
1507 return toChars!(8, EEType)(unsigned(unsigned(value) + 0)).array;
1509 default:
1510 return toStringRadixConvert!(S.sizeof * 6)(radix);
1514 @safe pure nothrow unittest
1516 static foreach (Int; AliasSeq!(uint, ulong))
1518 assert(to!string(Int(16), 16) == "10");
1519 assert(to!string(Int(15), 2u) == "1111");
1520 assert(to!string(Int(1), 2u) == "1");
1521 assert(to!string(Int(0x1234AF), 16u) == "1234AF");
1522 assert(to!string(Int(0x1234BCD), 16u, LetterCase.upper) == "1234BCD");
1523 assert(to!string(Int(0x1234AF), 16u, LetterCase.lower) == "1234af");
1526 static foreach (Int; AliasSeq!(int, long))
1528 assert(to!string(Int(-10), 10u) == "-10");
1531 assert(to!string(byte(-10), 16) == "F6");
1532 assert(to!string(long.min) == "-9223372036854775808");
1533 assert(to!string(long.max) == "9223372036854775807");
1537 Narrowing numeric-numeric conversions throw when the value does not
1538 fit in the narrower type.
1540 private T toImpl(T, S)(S value)
1541 if (!is(S : T) &&
1542 (isNumeric!S || isSomeChar!S || isBoolean!S) &&
1543 (isNumeric!T || isSomeChar!T || isBoolean!T) && !is(T == enum))
1545 static if (isFloatingPoint!S && isIntegral!T)
1547 import std.math.traits : isNaN;
1548 if (value.isNaN) throw new ConvException("Input was NaN");
1551 enum sSmallest = mostNegative!S;
1552 enum tSmallest = mostNegative!T;
1553 static if (sSmallest < 0)
1555 // possible underflow converting from a signed
1556 static if (tSmallest == 0)
1558 immutable good = value >= 0;
1560 else
1562 static assert(tSmallest < 0,
1563 "minimum value of T must be smaller than 0");
1564 immutable good = value >= tSmallest;
1566 if (!good)
1567 throw new ConvOverflowException("Conversion negative overflow");
1569 static if (S.max > T.max)
1571 // possible overflow
1572 if (value > T.max)
1573 throw new ConvOverflowException("Conversion positive overflow");
1575 return (ref value)@trusted{ return cast(T) value; }(value);
1578 @safe pure unittest
1580 import std.exception;
1582 dchar a = ' ';
1583 assert(to!char(a) == ' ');
1584 a = 300;
1585 assert(collectException(to!char(a)));
1587 dchar from0 = 'A';
1588 char to0 = to!char(from0);
1590 wchar from1 = 'A';
1591 char to1 = to!char(from1);
1593 char from2 = 'A';
1594 char to2 = to!char(from2);
1596 char from3 = 'A';
1597 wchar to3 = to!wchar(from3);
1599 char from4 = 'A';
1600 dchar to4 = to!dchar(from4);
1603 @safe unittest
1605 import std.exception;
1607 // Narrowing conversions from enum -> integral should be allowed, but they
1608 // should throw at runtime if the enum value doesn't fit in the target
1609 // type.
1610 enum E1 : ulong { A = 1, B = 1UL << 48, C = 0 }
1611 assert(to!int(E1.A) == 1);
1612 assert(to!bool(E1.A) == true);
1613 assertThrown!ConvOverflowException(to!int(E1.B)); // E1.B overflows int
1614 assertThrown!ConvOverflowException(to!bool(E1.B)); // E1.B overflows bool
1615 assert(to!bool(E1.C) == false);
1617 enum E2 : long { A = -1L << 48, B = -1 << 31, C = 1 << 31 }
1618 assertThrown!ConvOverflowException(to!int(E2.A)); // E2.A overflows int
1619 assertThrown!ConvOverflowException(to!uint(E2.B)); // E2.B overflows uint
1620 assert(to!int(E2.B) == -1 << 31); // but does not overflow int
1621 assert(to!int(E2.C) == 1 << 31); // E2.C does not overflow int
1623 enum E3 : int { A = -1, B = 1, C = 255, D = 0 }
1624 assertThrown!ConvOverflowException(to!ubyte(E3.A));
1625 assertThrown!ConvOverflowException(to!bool(E3.A));
1626 assert(to!byte(E3.A) == -1);
1627 assert(to!byte(E3.B) == 1);
1628 assert(to!ubyte(E3.C) == 255);
1629 assert(to!bool(E3.B) == true);
1630 assertThrown!ConvOverflowException(to!byte(E3.C));
1631 assertThrown!ConvOverflowException(to!bool(E3.C));
1632 assert(to!bool(E3.D) == false);
1636 @safe unittest
1638 import std.exception;
1639 import std.math.traits : isNaN;
1641 double d = double.nan;
1642 float f = to!float(d);
1643 assert(f.isNaN);
1644 assert(to!double(f).isNaN);
1645 assertThrown!ConvException(to!int(d));
1646 assertThrown!ConvException(to!int(f));
1647 auto ex = collectException(d.to!int);
1648 assert(ex.msg == "Input was NaN");
1652 Array-to-array conversion (except when target is a string type)
1653 converts each element in turn by using `to`.
1655 private T toImpl(T, S)(scope S value)
1656 if (!is(S : T) &&
1657 !isSomeString!S && isDynamicArray!S &&
1658 !isExactSomeString!T && isArray!T)
1660 alias E = typeof(T.init[0]);
1662 static if (isStaticArray!T)
1664 import std.exception : enforce;
1665 auto res = to!(E[])(value);
1666 enforce!ConvException(T.length == res.length,
1667 convFormat("Length mismatch when converting to static array: %s vs %s", T.length, res.length));
1668 return res[0 .. T.length];
1670 else
1672 import std.array : appender;
1673 auto w = appender!(E[])();
1674 w.reserve(value.length);
1675 foreach (ref e; value)
1677 w.put(to!E(e));
1679 return w.data;
1683 @safe pure unittest
1685 import std.exception;
1687 // array to array conversions
1688 uint[] a = [ 1u, 2, 3 ];
1689 auto b = to!(float[])(a);
1690 assert(b == [ 1.0f, 2, 3 ]);
1692 immutable(int)[3] d = [ 1, 2, 3 ];
1693 b = to!(float[])(d);
1694 assert(b == [ 1.0f, 2, 3 ]);
1696 uint[][] e = [ a, a ];
1697 auto f = to!(float[][])(e);
1698 assert(f[0] == b && f[1] == b);
1700 // Test for https://issues.dlang.org/show_bug.cgi?id=8264
1701 struct Wrap
1703 string wrap;
1704 alias wrap this;
1706 Wrap[] warr = to!(Wrap[])(["foo", "bar"]); // should work
1708 // https://issues.dlang.org/show_bug.cgi?id=12633
1709 import std.conv : to;
1710 const s2 = ["10", "20"];
1712 immutable int[2] a3 = s2.to!(int[2]);
1713 assert(a3 == [10, 20]);
1715 // verify length mismatches are caught
1716 immutable s4 = [1, 2, 3, 4];
1717 foreach (i; [1, 4])
1719 auto ex = collectException(s4[0 .. i].to!(int[2]));
1720 assert(ex && ex.msg == "Length mismatch when converting to static array: 2 vs " ~ [cast(char)(i + '0')],
1721 ex ? ex.msg : "Exception was not thrown!");
1725 @safe unittest
1727 auto b = [ 1.0f, 2, 3 ];
1729 auto c = to!(string[])(b);
1730 assert(c[0] == "1" && c[1] == "2" && c[2] == "3");
1734 Associative array to associative array conversion converts each key
1735 and each value in turn.
1737 private T toImpl(T, S)(S value)
1738 if (!is(S : T) && isAssociativeArray!S &&
1739 isAssociativeArray!T && !is(T == enum))
1741 /* This code is potentially unsafe.
1743 alias K2 = KeyType!T;
1744 alias V2 = ValueType!T;
1746 // While we are "building" the AA, we need to unqualify its values, and only re-qualify at the end
1747 Unqual!V2[K2] result;
1749 foreach (k1, v1; value)
1751 // Cast values temporarily to Unqual!V2 to store them to result variable
1752 result[to!K2(k1)] = to!(Unqual!V2)(v1);
1754 // Cast back to original type
1755 return () @trusted { return cast(T) result; }();
1758 @safe unittest
1760 // hash to hash conversions
1761 int[string] a;
1762 a["0"] = 1;
1763 a["1"] = 2;
1764 auto b = to!(double[dstring])(a);
1765 assert(b["0"d] == 1 && b["1"d] == 2);
1768 // https://issues.dlang.org/show_bug.cgi?id=8705, from doc
1769 @safe unittest
1771 import std.exception;
1772 int[string][double[int[]]] a;
1773 auto b = to!(short[wstring][string[double[]]])(a);
1774 a = [null:["hello":int.max]];
1775 assertThrown!ConvOverflowException(to!(short[wstring][string[double[]]])(a));
1777 @system unittest // Extra cases for AA with qualifiers conversion
1779 int[][int[]] a;// = [[], []];
1780 auto b = to!(immutable(short[])[immutable short[]])(a);
1782 double[dstring][int[long[]]] c;
1783 auto d = to!(immutable(short[immutable wstring])[immutable string[double[]]])(c);
1786 @safe unittest
1788 import std.algorithm.comparison : equal;
1789 import std.array : byPair;
1791 int[int] a;
1792 assert(a.to!(int[int]) == a);
1793 assert(a.to!(const(int)[int]).byPair.equal(a.byPair));
1796 @safe pure unittest
1798 static void testIntegralToFloating(Integral, Floating)()
1800 Integral a = 42;
1801 auto b = to!Floating(a);
1802 assert(a == b);
1803 assert(a == to!Integral(b));
1805 static void testFloatingToIntegral(Floating, Integral)()
1807 import std.math.traits : floatTraits, RealFormat;
1809 bool convFails(Source, Target, E)(Source src)
1812 cast(void) to!Target(src);
1813 catch (E)
1814 return true;
1815 return false;
1818 // convert some value
1819 Floating a = 4.2e1;
1820 auto b = to!Integral(a);
1821 assert(is(typeof(b) == Integral) && b == 42);
1822 // convert some negative value (if applicable)
1823 a = -4.2e1;
1824 static if (Integral.min < 0)
1826 b = to!Integral(a);
1827 assert(is(typeof(b) == Integral) && b == -42);
1829 else
1831 // no go for unsigned types
1832 assert(convFails!(Floating, Integral, ConvOverflowException)(a));
1834 // convert to the smallest integral value
1835 a = 0.0 + Integral.min;
1836 static if (Integral.min < 0)
1838 a = -a; // -Integral.min not representable as an Integral
1839 assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1840 || Floating.sizeof <= Integral.sizeof
1841 || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1843 a = 0.0 + Integral.min;
1844 assert(to!Integral(a) == Integral.min);
1845 --a; // no more representable as an Integral
1846 assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1847 || Floating.sizeof <= Integral.sizeof
1848 || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1849 a = 0.0 + Integral.max;
1850 assert(to!Integral(a) == Integral.max
1851 || Floating.sizeof <= Integral.sizeof
1852 || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1853 ++a; // no more representable as an Integral
1854 assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1855 || Floating.sizeof <= Integral.sizeof
1856 || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1857 // convert a value with a fractional part
1858 a = 3.14;
1859 assert(to!Integral(a) == 3);
1860 a = 3.99;
1861 assert(to!Integral(a) == 3);
1862 static if (Integral.min < 0)
1864 a = -3.14;
1865 assert(to!Integral(a) == -3);
1866 a = -3.99;
1867 assert(to!Integral(a) == -3);
1871 alias AllInts = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong);
1872 alias AllFloats = AliasSeq!(float, double, real);
1873 alias AllNumerics = AliasSeq!(AllInts, AllFloats);
1874 // test with same type
1876 foreach (T; AllNumerics)
1878 T a = 42;
1879 auto b = to!T(a);
1880 assert(is(typeof(a) == typeof(b)) && a == b);
1883 // test that floating-point numbers convert properly to largest ints
1884 // see http://oregonstate.edu/~peterseb/mth351/docs/351s2001_fp80x87.html
1885 // look for "largest fp integer with a predecessor"
1887 // float
1888 int a = 16_777_215; // 2^24 - 1
1889 assert(to!int(to!float(a)) == a);
1890 assert(to!int(to!float(-a)) == -a);
1891 // double
1892 long b = 9_007_199_254_740_991; // 2^53 - 1
1893 assert(to!long(to!double(b)) == b);
1894 assert(to!long(to!double(-b)) == -b);
1895 // real
1896 static if (real.mant_dig >= 64)
1898 ulong c = 18_446_744_073_709_551_615UL; // 2^64 - 1
1899 assert(to!ulong(to!real(c)) == c);
1902 // test conversions floating => integral
1904 foreach (Integral; AllInts)
1906 foreach (Floating; AllFloats)
1908 testFloatingToIntegral!(Floating, Integral)();
1912 // test conversion integral => floating
1914 foreach (Integral; AllInts)
1916 foreach (Floating; AllFloats)
1918 testIntegralToFloating!(Integral, Floating)();
1922 // test parsing
1924 foreach (T; AllNumerics)
1926 // from type immutable(char)[2]
1927 auto a = to!T("42");
1928 assert(a == 42);
1929 // from type char[]
1930 char[] s1 = "42".dup;
1931 a = to!T(s1);
1932 assert(a == 42);
1933 // from type char[2]
1934 char[2] s2;
1935 s2[] = "42";
1936 a = to!T(s2);
1937 assert(a == 42);
1938 // from type immutable(wchar)[2]
1939 a = to!T("42"w);
1940 assert(a == 42);
1945 @safe unittest
1947 alias AllInts = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong);
1948 alias AllFloats = AliasSeq!(float, double, real);
1949 alias AllNumerics = AliasSeq!(AllInts, AllFloats);
1950 // test conversions to string
1952 foreach (T; AllNumerics)
1954 T a = 42;
1955 string s = to!string(a);
1956 assert(s == "42", s);
1957 wstring ws = to!wstring(a);
1958 assert(ws == "42"w, to!string(ws));
1959 dstring ds = to!dstring(a);
1960 assert(ds == "42"d, to!string(ds));
1961 // array test
1962 T[] b = new T[2];
1963 b[0] = 42;
1964 b[1] = 33;
1965 assert(to!string(b) == "[42, 33]");
1968 // test array to string conversion
1969 foreach (T ; AllNumerics)
1971 auto a = [to!T(1), 2, 3];
1972 assert(to!string(a) == "[1, 2, 3]");
1974 // test enum to int conversion
1975 enum Testing { Test1, Test2 }
1976 Testing t;
1977 auto a = to!string(t);
1978 assert(a == "Test1");
1983 String, or string-like input range, to non-string conversion runs parsing.
1984 $(UL
1985 $(LI When the source is a wide string, it is first converted to a narrow
1986 string and then parsed.)
1987 $(LI When the source is a narrow string, normal text parsing occurs.))
1989 private T toImpl(T, S)(S value)
1990 if (isInputRange!S && isSomeChar!(ElementEncodingType!S) &&
1991 !isExactSomeString!T && is(typeof(parse!T(value))) &&
1992 // https://issues.dlang.org/show_bug.cgi?id=20539
1993 !(is(T == enum) && is(typeof(value == OriginalType!T.init)) && !isSomeString!(OriginalType!T)))
1995 scope(success)
1997 if (!value.empty)
1999 throw convError!(S, T)(value);
2002 return parse!T(value);
2005 /// ditto
2006 private T toImpl(T, S)(S value, uint radix)
2007 if (isSomeFiniteCharInputRange!S &&
2008 isIntegral!T && is(typeof(parse!T(value, radix))))
2010 scope(success)
2012 if (!value.empty)
2014 throw convError!(S, T)(value);
2017 return parse!T(value, radix);
2020 @safe pure unittest
2022 // https://issues.dlang.org/show_bug.cgi?id=6668
2023 // ensure no collaterals thrown
2024 try { to!uint("-1"); }
2025 catch (ConvException e) { assert(e.next is null); }
2028 @safe pure unittest
2030 static foreach (Str; AliasSeq!(string, wstring, dstring))
2032 Str a = "123";
2033 assert(to!int(a) == 123);
2034 assert(to!double(a) == 123);
2037 // https://issues.dlang.org/show_bug.cgi?id=6255
2038 auto n = to!int("FF", 16);
2039 assert(n == 255);
2042 // https://issues.dlang.org/show_bug.cgi?id=15800
2043 @safe unittest
2045 import std.utf : byCodeUnit, byChar, byWchar, byDchar;
2047 assert(to!int(byCodeUnit("10")) == 10);
2048 assert(to!int(byCodeUnit("10"), 10) == 10);
2049 assert(to!int(byCodeUnit("10"w)) == 10);
2050 assert(to!int(byCodeUnit("10"w), 10) == 10);
2052 assert(to!int(byChar("10")) == 10);
2053 assert(to!int(byChar("10"), 10) == 10);
2054 assert(to!int(byWchar("10")) == 10);
2055 assert(to!int(byWchar("10"), 10) == 10);
2056 assert(to!int(byDchar("10")) == 10);
2057 assert(to!int(byDchar("10"), 10) == 10);
2061 String, or string-like input range, to char type not directly
2062 supported by parse parses the first dchar of the source.
2064 Returns: the first code point of the input range, converted
2065 to type T.
2067 Throws: ConvException if the input range contains more than
2068 a single code point, or if the code point does not
2069 fit into a code unit of type T.
2071 private T toImpl(T, S)(S value)
2072 if (isSomeChar!T && !is(typeof(parse!T(value))) &&
2073 is(typeof(parse!dchar(value))))
2075 import std.utf : encode;
2077 immutable dchar codepoint = parse!dchar(value);
2078 if (!value.empty)
2079 throw new ConvException(convFormat("Cannot convert \"%s\" to %s because it " ~
2080 "contains more than a single code point.",
2081 value, T.stringof));
2082 T[dchar.sizeof / T.sizeof] decodedCodepoint;
2083 if (encode(decodedCodepoint, codepoint) != 1)
2084 throw new ConvException(convFormat("First code point '%s' of \"%s\" does not fit into a " ~
2085 "single %s code unit", codepoint, value, T.stringof));
2086 return decodedCodepoint[0];
2089 @safe pure unittest
2091 import std.exception : assertThrown;
2093 assert(toImpl!wchar("a") == 'a');
2095 assert(toImpl!char("a"d) == 'a');
2096 assert(toImpl!char("a"w) == 'a');
2097 assert(toImpl!wchar("a"d) == 'a');
2099 assertThrown!ConvException(toImpl!wchar("ab"));
2100 assertThrown!ConvException(toImpl!char("😃"d));
2104 Convert a value that is implicitly convertible to the enum base type
2105 into an Enum value. If the value does not match any enum member values
2106 a ConvException is thrown.
2107 Enums with floating-point or string base types are not supported.
2109 private T toImpl(T, S)(S value)
2110 if (is(T == enum) && !is(S == enum)
2111 && is(typeof(value == OriginalType!T.init))
2112 && !isFloatingPoint!(OriginalType!T) && !isSomeString!(OriginalType!T))
2114 foreach (Member; EnumMembers!T)
2116 if (Member == value)
2117 return Member;
2119 throw new ConvException(convFormat("Value (%s) does not match any member value of enum '%s'", value, T.stringof));
2122 @safe pure unittest
2124 import std.exception;
2125 enum En8143 : int { A = 10, B = 20, C = 30, D = 20 }
2126 enum En8143[][] m3 = to!(En8143[][])([[10, 30], [30, 10]]);
2127 static assert(m3 == [[En8143.A, En8143.C], [En8143.C, En8143.A]]);
2129 En8143 en1 = to!En8143(10);
2130 assert(en1 == En8143.A);
2131 assertThrown!ConvException(to!En8143(5)); // matches none
2132 En8143[][] m1 = to!(En8143[][])([[10, 30], [30, 10]]);
2133 assert(m1 == [[En8143.A, En8143.C], [En8143.C, En8143.A]]);
2136 // https://issues.dlang.org/show_bug.cgi?id=20539
2137 @safe pure unittest
2139 import std.exception : assertNotThrown;
2141 // To test that the bug is fixed it is required that the struct is static,
2142 // otherwise, the frame pointer makes the test pass even if the bug is not
2143 // fixed.
2145 static struct A
2147 auto opEquals(U)(U)
2149 return true;
2153 enum ColorA
2155 red = A()
2158 assertNotThrown("xxx".to!ColorA);
2160 // This is a guard for the future.
2162 struct B
2164 auto opEquals(U)(U)
2166 return true;
2170 enum ColorB
2172 red = B()
2175 assertNotThrown("xxx".to!ColorB);
2178 /***************************************************************
2179 Rounded conversion from floating point to integral.
2181 Rounded conversions do not work with non-integral target types.
2184 template roundTo(Target)
2186 Target roundTo(Source)(Source value)
2188 import core.math : abs = fabs;
2189 import std.math.exponential : log2;
2190 import std.math.rounding : trunc;
2192 static assert(isFloatingPoint!Source);
2193 static assert(isIntegral!Target);
2195 // If value >= 2 ^^ (real.mant_dig - 1), the number is an integer
2196 // and adding 0.5 won't work, but we allready know, that we do
2197 // not have to round anything.
2198 if (log2(abs(value)) >= real.mant_dig - 1)
2199 return to!Target(value);
2201 return to!Target(trunc(value + (value < 0 ? -0.5L : 0.5L)));
2206 @safe unittest
2208 assert(roundTo!int(3.14) == 3);
2209 assert(roundTo!int(3.49) == 3);
2210 assert(roundTo!int(3.5) == 4);
2211 assert(roundTo!int(3.999) == 4);
2212 assert(roundTo!int(-3.14) == -3);
2213 assert(roundTo!int(-3.49) == -3);
2214 assert(roundTo!int(-3.5) == -4);
2215 assert(roundTo!int(-3.999) == -4);
2216 assert(roundTo!(const int)(to!(const double)(-3.999)) == -4);
2219 @safe unittest
2221 import std.exception;
2222 // boundary values
2223 static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint))
2225 assert(roundTo!Int(Int.min - 0.4L) == Int.min);
2226 assert(roundTo!Int(Int.max + 0.4L) == Int.max);
2227 assertThrown!ConvOverflowException(roundTo!Int(Int.min - 0.5L));
2228 assertThrown!ConvOverflowException(roundTo!Int(Int.max + 0.5L));
2232 @safe unittest
2234 import std.exception;
2235 assertThrown!ConvException(roundTo!int(float.init));
2236 auto ex = collectException(roundTo!int(float.init));
2237 assert(ex.msg == "Input was NaN");
2240 // https://issues.dlang.org/show_bug.cgi?id=5232
2241 @safe pure unittest
2243 static if (real.mant_dig >= 64)
2244 ulong maxOdd = ulong.max;
2245 else
2246 ulong maxOdd = (1UL << real.mant_dig) - 1;
2248 real r1 = maxOdd;
2249 assert(roundTo!ulong(r1) == maxOdd);
2251 real r2 = maxOdd - 1;
2252 assert(roundTo!ulong(r2) == maxOdd - 1);
2254 real r3 = maxOdd / 2;
2255 assert(roundTo!ulong(r3) == maxOdd / 2);
2257 real r4 = maxOdd / 2 + 1;
2258 assert(roundTo!ulong(r4) == maxOdd / 2 + 1);
2260 // this is only an issue on computers where real == double
2261 long l = -((1L << double.mant_dig) - 1);
2262 double r5 = l;
2263 assert(roundTo!long(r5) == l);
2267 $(PANEL
2268 The `parse` family of functions works quite like the $(LREF to)
2269 family, except that:
2270 $(OL
2271 $(LI It only works with character ranges as input.)
2272 $(LI It takes the input by reference. This means that rvalues (such
2273 as string literals) are not accepted: use `to` instead.)
2274 $(LI It advances the input to the position following the conversion.)
2275 $(LI It does not throw if it could not convert the entire input.))
2278 This overload parses a `bool` from a character input range.
2280 Params:
2281 Target = the boolean type to convert to
2282 source = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2283 doCount = the flag for deciding to report the number of consumed characters
2285 Returns:
2286 $(UL
2287 $(LI A `bool` if `doCount` is set to `No.doCount`)
2288 $(LI A `tuple` containing a `bool` and a `size_t` if `doCount` is set to `Yes.doCount`))
2290 Throws:
2291 A $(LREF ConvException) if the range does not represent a `bool`.
2293 Note:
2294 All character input range conversions using $(LREF to) are forwarded
2295 to `parse` and do not require lvalues.
2297 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
2298 if (is(immutable Target == immutable bool) &&
2299 isInputRange!Source &&
2300 isSomeChar!(ElementType!Source))
2302 import std.ascii : toLower;
2304 static if (isNarrowString!Source)
2306 import std.string : representation;
2307 auto s = source.representation;
2309 else
2311 alias s = source;
2314 if (!s.empty)
2316 auto c1 = toLower(s.front);
2317 bool result = c1 == 't';
2318 if (result || c1 == 'f')
2320 s.popFront();
2321 foreach (c; result ? "rue" : "alse")
2323 if (s.empty || toLower(s.front) != c)
2324 goto Lerr;
2325 s.popFront();
2328 static if (isNarrowString!Source)
2329 source = cast(Source) s;
2331 static if (doCount)
2333 if (result)
2334 return tuple!("data", "count")(result, 4);
2335 return tuple!("data", "count")(result, 5);
2337 else
2339 return result;
2343 Lerr:
2344 throw parseError("bool should be case-insensitive 'true' or 'false'");
2348 @safe unittest
2350 import std.typecons : Flag, Yes, No;
2351 auto s = "true";
2352 bool b = parse!bool(s);
2353 assert(b);
2354 auto s2 = "true";
2355 bool b2 = parse!(bool, string, No.doCount)(s2);
2356 assert(b2);
2357 auto s3 = "true";
2358 auto b3 = parse!(bool, string, Yes.doCount)(s3);
2359 assert(b3.data && b3.count == 4);
2360 auto s4 = "falSE";
2361 auto b4 = parse!(bool, string, Yes.doCount)(s4);
2362 assert(!b4.data && b4.count == 5);
2365 @safe unittest
2367 import std.algorithm.comparison : equal;
2368 import std.exception;
2369 struct InputString
2371 string _s;
2372 @property auto front() { return _s.front; }
2373 @property bool empty() { return _s.empty; }
2374 void popFront() { _s.popFront(); }
2377 auto s = InputString("trueFALSETrueFalsetRUEfALSE");
2378 assert(parse!bool(s) == true);
2379 assert(s.equal("FALSETrueFalsetRUEfALSE"));
2380 assert(parse!bool(s) == false);
2381 assert(s.equal("TrueFalsetRUEfALSE"));
2382 assert(parse!bool(s) == true);
2383 assert(s.equal("FalsetRUEfALSE"));
2384 assert(parse!bool(s) == false);
2385 assert(s.equal("tRUEfALSE"));
2386 assert(parse!bool(s) == true);
2387 assert(s.equal("fALSE"));
2388 assert(parse!bool(s) == false);
2389 assert(s.empty);
2391 foreach (ss; ["tfalse", "ftrue", "t", "f", "tru", "fals", ""])
2393 s = InputString(ss);
2394 assertThrown!ConvException(parse!bool(s));
2399 Parses an integer from a character $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
2401 Params:
2402 Target = the integral type to convert to
2403 s = the lvalue of an input range
2404 doCount = the flag for deciding to report the number of consumed characters
2406 Returns:
2407 $(UL
2408 $(LI A number of type `Target` if `doCount` is set to `No.doCount`)
2409 $(LI A `tuple` containing a number of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
2411 Throws:
2412 A $(LREF ConvException) If an overflow occurred during conversion or
2413 if no character of the input was meaningfully converted.
2415 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref scope Source s)
2416 if (isIntegral!Target && !is(Target == enum) &&
2417 isSomeChar!(ElementType!Source))
2419 static if (Target.sizeof < int.sizeof)
2421 // smaller types are handled like integers
2422 auto v = .parse!(Select!(Target.min < 0, int, uint), Source, Yes.doCount)(s);
2423 auto result = (() @trusted => cast (Target) v.data)();
2424 if (result == v.data)
2426 static if (doCount)
2428 return tuple!("data", "count")(result, v.count);
2430 else
2432 return result;
2435 throw new ConvOverflowException("Overflow in integral conversion");
2437 else
2439 // int or larger types
2441 static if (Target.min < 0)
2442 bool sign = false;
2443 else
2444 enum bool sign = false;
2446 enum char maxLastDigit = Target.min < 0 ? 7 : 5;
2447 uint c;
2449 static if (isNarrowString!Source)
2451 import std.string : representation;
2452 auto source = s.representation;
2454 else
2456 alias source = s;
2459 size_t count = 0;
2461 if (source.empty)
2462 goto Lerr;
2464 c = source.front;
2466 static if (Target.min < 0)
2468 switch (c)
2470 case '-':
2471 sign = true;
2472 goto case '+';
2473 case '+':
2474 ++count;
2475 source.popFront();
2477 if (source.empty)
2478 goto Lerr;
2480 c = source.front;
2482 break;
2484 default:
2485 break;
2488 c -= '0';
2489 if (c <= 9)
2491 Target v = cast(Target) c;
2493 ++count;
2494 source.popFront();
2496 while (!source.empty)
2498 c = cast(typeof(c)) (source.front - '0');
2500 if (c > 9)
2501 break;
2503 if (v >= 0 && (v < Target.max/10 ||
2504 (v == Target.max/10 && c <= maxLastDigit + sign)))
2506 // Note: `v` can become negative here in case of parsing
2507 // the most negative value:
2508 v = cast(Target) (v * 10 + c);
2509 ++count;
2510 source.popFront();
2512 else
2513 throw new ConvOverflowException("Overflow in integral conversion");
2516 if (sign)
2517 v = -v;
2519 static if (isNarrowString!Source)
2520 s = s[$-source.length..$];
2522 static if (doCount)
2524 return tuple!("data", "count")(v, count);
2526 else
2528 return v;
2531 Lerr:
2532 static if (isNarrowString!Source)
2533 throw convError!(Source, Target)(cast(Source) source);
2534 else
2535 throw convError!(Source, Target)(source);
2540 @safe pure unittest
2542 import std.typecons : Flag, Yes, No;
2543 string s = "123";
2544 auto a = parse!int(s);
2545 assert(a == 123);
2547 string s1 = "123";
2548 auto a1 = parse!(int, string, Yes.doCount)(s1);
2549 assert(a1.data == 123 && a1.count == 3);
2551 // parse only accepts lvalues
2552 static assert(!__traits(compiles, parse!int("123")));
2556 @safe pure unittest
2558 import std.string : tr;
2559 import std.typecons : Flag, Yes, No;
2560 string test = "123 \t 76.14";
2561 auto a = parse!uint(test);
2562 assert(a == 123);
2563 assert(test == " \t 76.14"); // parse bumps string
2564 test = tr(test, " \t\n\r", "", "d"); // skip ws
2565 assert(test == "76.14");
2566 auto b = parse!double(test);
2567 assert(b == 76.14);
2568 assert(test == "");
2570 string test2 = "123 \t 76.14";
2571 auto a2 = parse!(uint, string, Yes.doCount)(test2);
2572 assert(a2.data == 123 && a2.count == 3);
2573 assert(test2 == " \t 76.14");// parse bumps string
2574 test2 = tr(test2, " \t\n\r", "", "d"); // skip ws
2575 assert(test2 == "76.14");
2576 auto b2 = parse!(double, string, Yes.doCount)(test2);
2577 assert(b2.data == 76.14 && b2.count == 5);
2578 assert(test2 == "");
2582 @safe pure unittest
2584 static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2587 assert(to!Int("0") == 0);
2589 static if (isSigned!Int)
2591 assert(to!Int("+0") == 0);
2592 assert(to!Int("-0") == 0);
2596 static if (Int.sizeof >= byte.sizeof)
2598 assert(to!Int("6") == 6);
2599 assert(to!Int("23") == 23);
2600 assert(to!Int("68") == 68);
2601 assert(to!Int("127") == 0x7F);
2603 static if (isUnsigned!Int)
2605 assert(to!Int("255") == 0xFF);
2607 static if (isSigned!Int)
2609 assert(to!Int("+6") == 6);
2610 assert(to!Int("+23") == 23);
2611 assert(to!Int("+68") == 68);
2612 assert(to!Int("+127") == 0x7F);
2614 assert(to!Int("-6") == -6);
2615 assert(to!Int("-23") == -23);
2616 assert(to!Int("-68") == -68);
2617 assert(to!Int("-128") == -128);
2621 static if (Int.sizeof >= short.sizeof)
2623 assert(to!Int("468") == 468);
2624 assert(to!Int("32767") == 0x7FFF);
2626 static if (isUnsigned!Int)
2628 assert(to!Int("65535") == 0xFFFF);
2630 static if (isSigned!Int)
2632 assert(to!Int("+468") == 468);
2633 assert(to!Int("+32767") == 0x7FFF);
2635 assert(to!Int("-468") == -468);
2636 assert(to!Int("-32768") == -32768);
2640 static if (Int.sizeof >= int.sizeof)
2642 assert(to!Int("2147483647") == 0x7FFFFFFF);
2644 static if (isUnsigned!Int)
2646 assert(to!Int("4294967295") == 0xFFFFFFFF);
2649 static if (isSigned!Int)
2651 assert(to!Int("+2147483647") == 0x7FFFFFFF);
2653 assert(to!Int("-2147483648") == -2147483648);
2657 static if (Int.sizeof >= long.sizeof)
2659 assert(to!Int("9223372036854775807") == 0x7FFFFFFFFFFFFFFF);
2661 static if (isUnsigned!Int)
2663 assert(to!Int("18446744073709551615") == 0xFFFFFFFFFFFFFFFF);
2666 static if (isSigned!Int)
2668 assert(to!Int("+9223372036854775807") == 0x7FFFFFFFFFFFFFFF);
2670 assert(to!Int("-9223372036854775808") == 0x8000000000000000);
2676 @safe pure unittest
2678 import std.exception;
2680 immutable string[] errors =
2683 "-",
2684 "+",
2685 "-+",
2686 " ",
2687 " 0",
2688 "0 ",
2689 "- 0",
2690 "1-",
2691 "xx",
2692 "123h",
2693 "-+1",
2694 "--1",
2695 "+-1",
2696 "++1",
2699 immutable string[] unsignedErrors =
2701 "+5",
2702 "-78",
2705 // parsing error check
2706 static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2708 foreach (j, s; errors)
2709 assertThrown!ConvException(to!Int(s));
2711 // parse!SomeUnsigned cannot parse head sign.
2712 static if (isUnsigned!Int)
2714 foreach (j, s; unsignedErrors)
2715 assertThrown!ConvException(to!Int(s));
2719 immutable string[] positiveOverflowErrors =
2721 "128", // > byte.max
2722 "256", // > ubyte.max
2723 "32768", // > short.max
2724 "65536", // > ushort.max
2725 "2147483648", // > int.max
2726 "4294967296", // > uint.max
2727 "9223372036854775808", // > long.max
2728 "18446744073709551616", // > ulong.max
2730 // positive overflow check
2731 static foreach (i, Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2733 foreach (j, s; positiveOverflowErrors[i..$])
2734 assertThrown!ConvOverflowException(to!Int(s));
2737 immutable string[] negativeOverflowErrors =
2739 "-129", // < byte.min
2740 "-32769", // < short.min
2741 "-2147483649", // < int.min
2742 "-9223372036854775809", // < long.min
2744 // negative overflow check
2745 static foreach (i, Int; AliasSeq!(byte, short, int, long))
2747 foreach (j, s; negativeOverflowErrors[i..$])
2748 assertThrown!ConvOverflowException(to!Int(s));
2752 @safe pure unittest
2754 void checkErrMsg(string input, dchar charInMsg, dchar charNotInMsg)
2758 int x = input.to!int();
2759 assert(false, "Invalid conversion did not throw");
2761 catch (ConvException e)
2763 // Ensure error message contains failing character, not the character
2764 // beyond.
2765 import std.algorithm.searching : canFind;
2766 assert( e.msg.canFind(charInMsg) &&
2767 !e.msg.canFind(charNotInMsg));
2769 catch (Exception e)
2771 assert(false, "Did not throw ConvException");
2774 checkErrMsg("@$", '@', '$');
2775 checkErrMsg("@$123", '@', '$');
2776 checkErrMsg("1@$23", '@', '$');
2777 checkErrMsg("1@$", '@', '$');
2778 checkErrMsg("1@$2", '@', '$');
2779 checkErrMsg("12@$", '@', '$');
2782 @safe pure unittest
2784 import std.exception;
2785 assertCTFEable!({ string s = "1234abc"; assert(parse! int(s) == 1234 && s == "abc"); });
2786 assertCTFEable!({ string s = "-1234abc"; assert(parse! int(s) == -1234 && s == "abc"); });
2787 assertCTFEable!({ string s = "1234abc"; assert(parse!uint(s) == 1234 && s == "abc"); });
2789 assertCTFEable!({ string s = "1234abc"; assert(parse!( int, string, Yes.doCount)(s) ==
2790 tuple( 1234, 4) && s == "abc"); });
2791 assertCTFEable!({ string s = "-1234abc"; assert(parse!( int, string, Yes.doCount)(s) ==
2792 tuple(-1234, 5) && s == "abc"); });
2793 assertCTFEable!({ string s = "1234abc"; assert(parse!(uint, string, Yes.doCount)(s) ==
2794 tuple( 1234 ,4) && s == "abc"); });
2797 // https://issues.dlang.org/show_bug.cgi?id=13931
2798 @safe pure unittest
2800 import std.exception;
2802 assertThrown!ConvOverflowException("-21474836480".to!int());
2803 assertThrown!ConvOverflowException("-92233720368547758080".to!long());
2806 // https://issues.dlang.org/show_bug.cgi?id=14396
2807 @safe pure unittest
2809 struct StrInputRange
2811 this (string s) { str = s; }
2812 char front() const @property { return str[front_index]; }
2813 char popFront() { return str[front_index++]; }
2814 bool empty() const @property { return str.length <= front_index; }
2815 string str;
2816 size_t front_index = 0;
2818 auto input = StrInputRange("777");
2819 assert(parse!int(input) == 777);
2821 auto input2 = StrInputRange("777");
2822 assert(parse!(int, StrInputRange, Yes.doCount)(input2) == tuple(777, 3));
2825 // https://issues.dlang.org/show_bug.cgi?id=9621
2826 @safe pure unittest
2828 string s1 = "[ \"\\141\", \"\\0\", \"\\41\", \"\\418\" ]";
2829 assert(parse!(string[])(s1) == ["a", "\0", "!", "!8"]);
2831 s1 = "[ \"\\141\", \"\\0\", \"\\41\", \"\\418\" ]";
2832 auto len = s1.length;
2833 assert(parse!(string[], string, Yes.doCount)(s1) == tuple(["a", "\0", "!", "!8"], len));
2836 /// ditto
2837 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source, uint radix)
2838 if (isIntegral!Target && !is(Target == enum) &&
2839 isSomeChar!(ElementType!Source))
2842 assert(radix >= 2 && radix <= 36, "radix must be in range [2,36]");
2846 import core.checkedint : mulu, addu;
2847 import std.exception : enforce;
2849 if (radix == 10)
2851 return parse!(Target, Source, doCount)(source);
2854 enforce!ConvException(!source.empty, "s must not be empty in integral parse");
2856 immutable uint beyond = (radix < 10 ? '0' : 'a'-10) + radix;
2857 Target v = 0;
2859 static if (isNarrowString!Source)
2861 import std.string : representation;
2862 scope s = source.representation;
2864 else
2866 alias s = source;
2869 size_t count = 0;
2870 auto found = false;
2873 uint c = s.front;
2874 if (c < '0')
2875 break;
2876 if (radix < 10)
2878 if (c >= beyond)
2879 break;
2881 else
2883 if (c > '9')
2885 c |= 0x20;//poorman's tolower
2886 if (c < 'a' || c >= beyond)
2887 break;
2888 c -= 'a'-10-'0';
2892 bool overflow = false;
2893 auto nextv = v.mulu(radix, overflow).addu(c - '0', overflow);
2894 enforce!ConvOverflowException(!overflow && nextv <= Target.max, "Overflow in integral conversion");
2895 v = cast(Target) nextv;
2896 ++count;
2897 s.popFront();
2898 found = true;
2899 } while (!s.empty);
2901 if (!found)
2903 static if (isNarrowString!Source)
2904 throw convError!(Source, Target)(cast(Source) source);
2905 else
2906 throw convError!(Source, Target)(source);
2909 static if (isNarrowString!Source)
2910 source = source[$ - s.length .. $];
2912 static if (doCount)
2914 return tuple!("data", "count")(v, count);
2916 else
2918 return v;
2922 @safe pure unittest
2924 string s; // parse doesn't accept rvalues
2925 foreach (i; 2 .. 37)
2927 assert(parse!int(s = "0", i) == 0);
2928 assert(parse!int(s = "1", i) == 1);
2929 assert(parse!byte(s = "10", i) == i);
2930 assert(parse!(int, string, Yes.doCount)(s = "0", i) == tuple(0, 1));
2931 assert(parse!(int, string, Yes.doCount)(s = "1", i) == tuple(1, 1));
2932 assert(parse!(byte, string, Yes.doCount)(s = "10", i) == tuple(i, 2));
2935 assert(parse!int(s = "0011001101101", 2) == 0b0011001101101);
2936 assert(parse!int(s = "765", 8) == octal!765);
2937 assert(parse!int(s = "000135", 8) == octal!"135");
2938 assert(parse!int(s = "fCDe", 16) == 0xfcde);
2940 // https://issues.dlang.org/show_bug.cgi?id=6609
2941 assert(parse!int(s = "-42", 10) == -42);
2943 assert(parse!ubyte(s = "ff", 16) == 0xFF);
2946 // https://issues.dlang.org/show_bug.cgi?id=7302
2947 @safe pure unittest
2949 import std.range : cycle;
2950 auto r = cycle("2A!");
2951 auto u = parse!uint(r, 16);
2952 assert(u == 42);
2953 assert(r.front == '!');
2955 auto r2 = cycle("2A!");
2956 auto u2 = parse!(uint, typeof(r2), Yes.doCount)(r2, 16);
2957 assert(u2.data == 42 && u2.count == 2);
2958 assert(r2.front == '!');
2961 // https://issues.dlang.org/show_bug.cgi?id=13163
2962 @safe pure unittest
2964 import std.exception;
2965 foreach (s; ["fff", "123"])
2966 assertThrown!ConvOverflowException(s.parse!ubyte(16));
2969 // https://issues.dlang.org/show_bug.cgi?id=17282
2970 @safe pure unittest
2972 auto str = "0=\x00\x02\x55\x40&\xff\xf0\n\x00\x04\x55\x40\xff\xf0~4+10\n";
2973 assert(parse!uint(str) == 0);
2975 str = "0=\x00\x02\x55\x40&\xff\xf0\n\x00\x04\x55\x40\xff\xf0~4+10\n";
2976 assert(parse!(uint, string, Yes.doCount)(str) == tuple(0, 1));
2979 // https://issues.dlang.org/show_bug.cgi?id=18248
2980 @safe pure unittest
2982 import std.exception : assertThrown;
2984 auto str = ";";
2985 assertThrown(str.parse!uint(16));
2986 assertThrown(str.parse!(uint, string, Yes.doCount)(16));
2990 * Parses an `enum` type from a string representing an enum member name.
2992 * Params:
2993 * Target = the `enum` type to convert to
2994 * s = the lvalue of the range to _parse
2995 * doCount = the flag for deciding to report the number of consumed characters
2997 * Returns:
2998 $(UL
2999 * $(LI An `enum` of type `Target` if `doCount` is set to `No.doCount`)
3000 * $(LI A `tuple` containing an `enum` of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
3002 * Throws:
3003 * A $(LREF ConvException) if type `Target` does not have a member
3004 * represented by `s`.
3006 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3007 if (is(Target == enum) && isSomeString!Source && !is(Source == enum))
3009 import std.algorithm.searching : startsWith;
3010 import std.traits : Unqual, EnumMembers;
3012 Unqual!Target result;
3013 size_t longest_match = 0;
3015 foreach (i, e; EnumMembers!Target)
3017 auto ident = __traits(allMembers, Target)[i];
3018 if (longest_match < ident.length && s.startsWith(ident))
3020 result = e;
3021 longest_match = ident.length ;
3025 if (longest_match > 0)
3027 s = s[longest_match .. $];
3028 static if (doCount)
3030 return tuple!("data", "count")(result, longest_match);
3032 else
3034 return result;
3038 throw new ConvException(
3039 Target.stringof ~ " does not have a member named '"
3040 ~ to!string(s) ~ "'");
3044 @safe unittest
3046 import std.typecons : Flag, Yes, No, tuple;
3047 enum EnumType : bool { a = true, b = false, c = a }
3049 auto str = "a";
3050 assert(parse!EnumType(str) == EnumType.a);
3051 auto str2 = "a";
3052 assert(parse!(EnumType, string, No.doCount)(str2) == EnumType.a);
3053 auto str3 = "a";
3054 assert(parse!(EnumType, string, Yes.doCount)(str3) == tuple(EnumType.a, 1));
3058 @safe unittest
3060 import std.exception;
3062 enum EB : bool { a = true, b = false, c = a }
3063 enum EU { a, b, c }
3064 enum EI { a = -1, b = 0, c = 1 }
3065 enum EF : real { a = 1.414, b = 1.732, c = 2.236 }
3066 enum EC : char { a = 'a', b = 'b', c = 'c' }
3067 enum ES : string { a = "aaa", b = "bbb", c = "ccc" }
3069 static foreach (E; AliasSeq!(EB, EU, EI, EF, EC, ES))
3071 assert(to!E("a"c) == E.a);
3072 assert(to!E("b"w) == E.b);
3073 assert(to!E("c"d) == E.c);
3075 assert(to!(const E)("a") == E.a);
3076 assert(to!(immutable E)("a") == E.a);
3077 assert(to!(shared E)("a") == E.a);
3079 assertThrown!ConvException(to!E("d"));
3083 // https://issues.dlang.org/show_bug.cgi?id=4744
3084 @safe pure unittest
3086 enum A { member1, member11, member111 }
3087 assert(to!A("member1" ) == A.member1 );
3088 assert(to!A("member11" ) == A.member11 );
3089 assert(to!A("member111") == A.member111);
3090 auto s = "member1111";
3091 assert(parse!A(s) == A.member111 && s == "1");
3092 auto s2 = "member1111";
3093 assert(parse!(A, string, No.doCount)(s2) == A.member111 && s2 == "1");
3094 auto s3 = "member1111";
3095 assert(parse!(A, string, Yes.doCount)(s3) == tuple(A.member111, 9) && s3 == "1");
3099 * Parses a floating point number from a character range.
3101 * Params:
3102 * Target = a floating point type
3103 * source = the lvalue of the range to _parse
3104 * doCount = the flag for deciding to report the number of consumed characters
3106 * Returns:
3107 $(UL
3108 * $(LI A floating point number of type `Target` if `doCount` is set to `No.doCount`)
3109 * $(LI A `tuple` containing a floating point number of·type `Target` and a `size_t`
3110 * if `doCount` is set to `Yes.doCount`))
3112 * Throws:
3113 * A $(LREF ConvException) if `source` is empty, if no number could be
3114 * parsed, or if an overflow occurred.
3116 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
3117 if (isFloatingPoint!Target && !is(Target == enum) &&
3118 isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum))
3120 import std.ascii : isDigit, isAlpha, toLower, toUpper, isHexDigit;
3121 import std.exception : enforce;
3123 static if (isNarrowString!Source)
3125 import std.string : representation;
3126 scope p = source.representation;
3128 else
3130 alias p = source;
3133 void advanceSource()
3135 static if (isNarrowString!Source)
3136 source = source[$ - p.length .. $];
3139 static immutable real[14] negtab =
3140 [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L,
3141 1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ];
3142 static immutable real[13] postab =
3143 [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L,
3144 1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ];
3146 ConvException bailOut()(string msg = null, string fn = __FILE__, size_t ln = __LINE__)
3148 if (msg == null)
3149 msg = "Floating point conversion error";
3150 return new ConvException(text(msg, " for input \"", source, "\"."), fn, ln);
3153 enforce(!p.empty, bailOut());
3156 size_t count = 0;
3157 bool sign = false;
3158 switch (p.front)
3160 case '-':
3161 sign = true;
3162 ++count;
3163 p.popFront();
3164 enforce(!p.empty, bailOut());
3165 if (toLower(p.front) == 'i')
3166 goto case 'i';
3167 break;
3168 case '+':
3169 ++count;
3170 p.popFront();
3171 enforce(!p.empty, bailOut());
3172 break;
3173 case 'i': case 'I':
3174 // inf
3175 ++count;
3176 p.popFront();
3177 enforce(!p.empty && toUpper(p.front) == 'N',
3178 bailOut("error converting input to floating point"));
3179 ++count;
3180 p.popFront();
3181 enforce(!p.empty && toUpper(p.front) == 'F',
3182 bailOut("error converting input to floating point"));
3183 // skip past the last 'f'
3184 ++count;
3185 p.popFront();
3186 advanceSource();
3187 static if (doCount)
3189 return tuple!("data", "count")(sign ? -Target.infinity : Target.infinity, count);
3191 else
3193 return sign ? -Target.infinity : Target.infinity;
3195 default: {}
3198 bool isHex = false;
3199 bool startsWithZero = p.front == '0';
3200 if (startsWithZero)
3202 ++count;
3203 p.popFront();
3204 if (p.empty)
3206 advanceSource();
3207 static if (doCount)
3209 return tuple!("data", "count")(cast (Target) (sign ? -0.0 : 0.0), count);
3211 else
3213 return sign ? -0.0 : 0.0;
3217 isHex = p.front == 'x' || p.front == 'X';
3218 if (isHex)
3220 ++count;
3221 p.popFront();
3224 else if (toLower(p.front) == 'n')
3226 // nan
3227 ++count;
3228 p.popFront();
3229 enforce(!p.empty && toUpper(p.front) == 'A',
3230 bailOut("error converting input to floating point"));
3231 ++count;
3232 p.popFront();
3233 enforce(!p.empty && toUpper(p.front) == 'N',
3234 bailOut("error converting input to floating point"));
3235 // skip past the last 'n'
3236 ++count;
3237 p.popFront();
3238 advanceSource();
3239 static if (doCount)
3241 return tuple!("data", "count")(Target.nan, count);
3243 else
3245 return typeof(return).nan;
3250 * The following algorithm consists of 2 steps:
3251 * 1) parseDigits processes the textual input into msdec and possibly
3252 * lsdec/msscale variables, followed by the exponent parser which sets
3253 * exp below.
3254 * Hex: input is 0xaaaaa...p+000... where aaaa is the mantissa in hex
3255 * and 000 is the exponent in decimal format with base 2.
3256 * Decimal: input is 0.00333...p+000... where 0.0033 is the mantissa
3257 * in decimal and 000 is the exponent in decimal format with base 10.
3258 * 2) Convert msdec/lsdec and exp into native real format
3261 real ldval = 0.0;
3262 char dot = 0; /* if decimal point has been seen */
3263 int exp = 0;
3264 ulong msdec = 0, lsdec = 0;
3265 ulong msscale = 1;
3266 bool sawDigits;
3268 enum { hex, decimal }
3270 // sets msdec, lsdec/msscale, and sawDigits by parsing the mantissa digits
3271 void parseDigits(alias FloatFormat)()
3273 static if (FloatFormat == hex)
3275 enum uint base = 16;
3276 enum ulong msscaleMax = 0x1000_0000_0000_0000UL; // largest power of 16 a ulong holds
3277 enum ubyte expIter = 4; // iterate the base-2 exponent by 4 for every hex digit
3278 alias checkDigit = isHexDigit;
3280 * convert letter to binary representation: First clear bit
3281 * to convert lower space chars to upperspace, then -('A'-10)
3282 * converts letter A to 10, letter B to 11, ...
3284 alias convertDigit = (int x) => isAlpha(x) ? ((x & ~0x20) - ('A' - 10)) : x - '0';
3285 sawDigits = false;
3287 else static if (FloatFormat == decimal)
3289 enum uint base = 10;
3290 enum ulong msscaleMax = 10_000_000_000_000_000_000UL; // largest power of 10 a ulong holds
3291 enum ubyte expIter = 1; // iterate the base-10 exponent once for every decimal digit
3292 alias checkDigit = isDigit;
3293 alias convertDigit = (int x) => x - '0';
3294 // Used to enforce that any mantissa digits are present
3295 sawDigits = startsWithZero;
3297 else
3298 static assert(false, "Unrecognized floating-point format used.");
3300 while (!p.empty)
3302 int i = p.front;
3303 while (checkDigit(i))
3305 sawDigits = true; /* must have at least 1 digit */
3307 i = convertDigit(i);
3309 if (msdec < (ulong.max - base)/base)
3311 // For base 16: Y = ... + y3*16^3 + y2*16^2 + y1*16^1 + y0*16^0
3312 msdec = msdec * base + i;
3314 else if (msscale < msscaleMax)
3316 lsdec = lsdec * base + i;
3317 msscale *= base;
3319 else
3321 exp += expIter;
3323 exp -= dot;
3324 ++count;
3325 p.popFront();
3326 if (p.empty)
3327 break;
3328 i = p.front;
3329 if (i == '_')
3331 ++count;
3332 p.popFront();
3333 if (p.empty)
3334 break;
3335 i = p.front;
3338 if (i == '.' && !dot)
3340 ++count;
3341 p.popFront();
3342 dot += expIter;
3344 else
3345 break;
3348 // Have we seen any mantissa digits so far?
3349 enforce(sawDigits, bailOut("no digits seen"));
3350 static if (FloatFormat == hex)
3351 enforce(!p.empty && (p.front == 'p' || p.front == 'P'),
3352 bailOut("Floating point parsing: exponent is required"));
3355 if (isHex)
3356 parseDigits!hex;
3357 else
3358 parseDigits!decimal;
3360 if (isHex || (!p.empty && (p.front == 'e' || p.front == 'E')))
3362 char sexp = 0;
3363 int e = 0;
3365 ++count;
3366 p.popFront();
3367 enforce(!p.empty, new ConvException("Unexpected end of input"));
3368 switch (p.front)
3370 case '-': sexp++;
3371 goto case;
3372 case '+': ++count;
3373 p.popFront();
3374 break;
3375 default: {}
3377 sawDigits = false;
3378 while (!p.empty && isDigit(p.front))
3380 if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow
3382 e = e * 10 + p.front - '0';
3384 ++count;
3385 p.popFront();
3386 sawDigits = true;
3388 exp += (sexp) ? -e : e;
3389 enforce(sawDigits, new ConvException("No digits seen."));
3392 ldval = msdec;
3393 if (msscale != 1) /* if stuff was accumulated in lsdec */
3394 ldval = ldval * msscale + lsdec;
3395 if (isHex)
3397 import core.math : ldexp;
3399 // Exponent is power of 2, not power of 10
3400 ldval = ldexp(ldval,exp);
3402 else if (ldval)
3404 uint u = 0;
3405 int pow = 4096;
3407 while (exp > 0)
3409 while (exp >= pow)
3411 ldval *= postab[u];
3412 exp -= pow;
3414 pow >>= 1;
3415 u++;
3417 while (exp < 0)
3419 while (exp <= -pow)
3421 ldval *= negtab[u];
3422 enforce(ldval != 0, new ConvException("Range error"));
3423 exp += pow;
3425 pow >>= 1;
3426 u++;
3430 Target result = cast(Target) (sign ? -ldval : ldval);
3432 // if overflow occurred
3433 import std.math.traits : isFinite;
3434 enforce(isFinite(result), new ConvException("Range error"));
3436 advanceSource();
3437 static if (doCount)
3439 return tuple!("data", "count")(result, count);
3441 else
3443 return result;
3449 @safe unittest
3451 import std.math.operations : isClose;
3452 import std.math.traits : isNaN, isInfinity;
3453 import std.typecons : Flag, Yes, No;
3454 auto str = "123.456";
3455 assert(parse!double(str).isClose(123.456));
3456 auto str2 = "123.456";
3457 assert(parse!(double, string, No.doCount)(str2).isClose(123.456));
3458 auto str3 = "123.456";
3459 auto r = parse!(double, string, Yes.doCount)(str3);
3460 assert(r.data.isClose(123.456));
3461 assert(r.count == 7);
3462 auto str4 = "-123.456";
3463 r = parse!(double, string, Yes.doCount)(str4);
3464 assert(r.data.isClose(-123.456));
3465 assert(r.count == 8);
3466 auto str5 = "+123.456";
3467 r = parse!(double, string, Yes.doCount)(str5);
3468 assert(r.data.isClose(123.456));
3469 assert(r.count == 8);
3470 auto str6 = "inf0";
3471 r = parse!(double, string, Yes.doCount)(str6);
3472 assert(isInfinity(r.data) && r.count == 3 && str6 == "0");
3473 auto str7 = "-0";
3474 auto r2 = parse!(float, string, Yes.doCount)(str7);
3475 assert(r2.data.isClose(0.0) && r2.count == 2);
3476 auto str8 = "nan";
3477 auto r3 = parse!(real, string, Yes.doCount)(str8);
3478 assert(isNaN(r3.data) && r3.count == 3);
3481 @safe unittest
3483 import std.exception;
3484 import std.math.traits : isNaN, isInfinity;
3485 import std.math.algebraic : fabs;
3487 // Compare reals with given precision
3488 bool feq(in real rx, in real ry, in real precision = 0.000001L)
3490 if (rx == ry)
3491 return 1;
3493 if (isNaN(rx))
3494 return cast(bool) isNaN(ry);
3496 if (isNaN(ry))
3497 return 0;
3499 return cast(bool)(fabs(rx - ry) <= precision);
3502 // Make given typed literal
3503 F Literal(F)(F f)
3505 return f;
3508 static foreach (Float; AliasSeq!(float, double, real))
3510 assert(to!Float("123") == Literal!Float(123));
3511 assert(to!Float("+123") == Literal!Float(+123));
3512 assert(to!Float("-123") == Literal!Float(-123));
3513 assert(to!Float("123e2") == Literal!Float(123e2));
3514 assert(to!Float("123e+2") == Literal!Float(123e+2));
3515 assert(to!Float("123e-2") == Literal!Float(123e-2L));
3516 assert(to!Float("123.") == Literal!Float(123.0));
3517 assert(to!Float(".375") == Literal!Float(.375));
3519 assert(to!Float("1.23375E+2") == Literal!Float(1.23375E+2));
3521 assert(to!Float("0") is 0.0);
3522 assert(to!Float("-0") is -0.0);
3524 assert(isNaN(to!Float("nan")));
3526 assertThrown!ConvException(to!Float("\x00"));
3529 // min and max
3530 float f = to!float("1.17549e-38");
3531 assert(feq(cast(real) f, cast(real) 1.17549e-38));
3532 assert(feq(cast(real) f, cast(real) float.min_normal));
3533 f = to!float("3.40282e+38");
3534 assert(to!string(f) == to!string(3.40282e+38));
3536 // min and max
3537 double d = to!double("2.22508e-308");
3538 assert(feq(cast(real) d, cast(real) 2.22508e-308));
3539 assert(feq(cast(real) d, cast(real) double.min_normal));
3540 d = to!double("1.79769e+308");
3541 assert(to!string(d) == to!string(1.79769e+308));
3542 assert(to!string(d) == to!string(double.max));
3544 auto z = real.max / 2L;
3545 static assert(is(typeof(z) == real));
3546 assert(!isNaN(z));
3547 assert(!isInfinity(z));
3548 string a = to!string(z);
3549 real b = to!real(a);
3550 string c = to!string(b);
3552 assert(c == a, "\n" ~ c ~ "\n" ~ a);
3554 assert(to!string(to!real(to!string(real.max / 2L))) == to!string(real.max / 2L));
3556 // min and max
3557 real r = to!real(to!string(real.min_normal));
3558 version (NetBSD)
3560 // NetBSD notice
3561 // to!string returns 3.3621e-4932L. It is less than real.min_normal and it is subnormal value
3562 // Simple C code
3563 // long double rd = 3.3621e-4932L;
3564 // printf("%Le\n", rd);
3565 // has unexpected result: 1.681050e-4932
3567 // Bug report: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50937
3569 else
3571 assert(to!string(r) == to!string(real.min_normal));
3573 r = to!real(to!string(real.max));
3574 assert(to!string(r) == to!string(real.max));
3576 real pi = 3.1415926535897932384626433832795028841971693993751L;
3577 string fullPrecision = "3.1415926535897932384626433832795028841971693993751";
3578 assert(feq(parse!real(fullPrecision), pi, 2*real.epsilon));
3579 string fullPrecision2 = "3.1415926535897932384626433832795028841971693993751";
3580 assert(feq(parse!(real, string, No.doCount)(fullPrecision2), pi, 2*real.epsilon));
3581 string fullPrecision3= "3.1415926535897932384626433832795028841971693993751";
3582 auto len = fullPrecision3.length;
3583 auto res = parse!(real, string, Yes.doCount)(fullPrecision3);
3584 assert(feq(res.data, pi, 2*real.epsilon));
3585 assert(res.count == len);
3587 real x = 0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252L;
3588 string full = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3589 assert(parse!real(full) == x);
3590 string full2 = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3591 assert(parse!(real, string, No.doCount)(full2) == x);
3592 string full3 = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3593 auto len2 = full3.length;
3594 assert(parse!(real, string, Yes.doCount)(full3) == tuple(x, len2));
3597 // Tests for the double implementation
3598 @system unittest
3600 // @system because strtod is not @safe.
3601 import std.math.traits : floatTraits, RealFormat;
3603 static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3605 import core.stdc.stdlib, std.exception, std.math;
3607 //Should be parsed exactly: 53 bit mantissa
3608 string s = "0x1A_BCDE_F012_3456p10";
3609 auto x = parse!real(s);
3610 assert(x == 0x1A_BCDE_F012_3456p10L);
3611 //1 bit is implicit
3612 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0xA_BCDE_F012_3456);
3613 assert(strtod("0x1ABCDEF0123456p10", null) == x);
3615 s = "0x1A_BCDE_F012_3456p10";
3616 auto len = s.length;
3617 assert(parse!(real, string, Yes.doCount)(s) == tuple(x, len));
3619 //Should be parsed exactly: 10 bit mantissa
3620 s = "0x3FFp10";
3621 x = parse!real(s);
3622 assert(x == 0x03FFp10);
3623 //1 bit is implicit
3624 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_F800_0000_0000);
3625 assert(strtod("0x3FFp10", null) == x);
3627 //60 bit mantissa, round up
3628 s = "0xFFF_FFFF_FFFF_FFFFp10";
3629 x = parse!real(s);
3630 assert(isClose(x, 0xFFF_FFFF_FFFF_FFFFp10));
3631 //1 bit is implicit
3632 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x0000_0000_0000_0000);
3633 assert(strtod("0xFFFFFFFFFFFFFFFp10", null) == x);
3635 //60 bit mantissa, round down
3636 s = "0xFFF_FFFF_FFFF_FF90p10";
3637 x = parse!real(s);
3638 assert(isClose(x, 0xFFF_FFFF_FFFF_FF90p10));
3639 //1 bit is implicit
3640 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_FFFF_FFFF_FFFF);
3641 assert(strtod("0xFFFFFFFFFFFFF90p10", null) == x);
3643 //61 bit mantissa, round up 2
3644 s = "0x1F0F_FFFF_FFFF_FFFFp10";
3645 x = parse!real(s);
3646 assert(isClose(x, 0x1F0F_FFFF_FFFF_FFFFp10));
3647 //1 bit is implicit
3648 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_1000_0000_0000);
3649 assert(strtod("0x1F0FFFFFFFFFFFFFp10", null) == x);
3651 //61 bit mantissa, round down 2
3652 s = "0x1F0F_FFFF_FFFF_FF10p10";
3653 x = parse!real(s);
3654 assert(isClose(x, 0x1F0F_FFFF_FFFF_FF10p10));
3655 //1 bit is implicit
3656 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_0FFF_FFFF_FFFF);
3657 assert(strtod("0x1F0FFFFFFFFFFF10p10", null) == x);
3659 //Huge exponent
3660 s = "0x1F_FFFF_FFFF_FFFFp900";
3661 x = parse!real(s);
3662 assert(strtod("0x1FFFFFFFFFFFFFp900", null) == x);
3664 //exponent too big -> converror
3665 s = "";
3666 assertThrown!ConvException(x = parse!real(s));
3667 assert(strtod("0x1FFFFFFFFFFFFFp1024", null) == real.infinity);
3669 //-exponent too big -> 0
3670 s = "0x1FFFFFFFFFFFFFp-2000";
3671 x = parse!real(s);
3672 assert(x == 0);
3673 assert(strtod("0x1FFFFFFFFFFFFFp-2000", null) == x);
3675 s = "0x1FFFFFFFFFFFFFp-2000";
3676 len = s.length;
3677 assert(parse!(real, string, Yes.doCount)(s) == tuple(x, len));
3681 @system unittest
3683 import core.stdc.errno;
3684 import core.stdc.stdlib;
3685 import std.math.traits : floatTraits, RealFormat;
3687 errno = 0; // In case it was set by another unittest in a different module.
3688 struct longdouble
3690 static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple)
3692 ushort[8] value;
3694 else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended ||
3695 floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3697 ushort[5] value;
3699 else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3701 ushort[4] value;
3703 else
3704 static assert(false, "Not implemented");
3707 real ld;
3708 longdouble x;
3709 real ld1;
3710 longdouble x1;
3711 int i;
3713 static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple)
3714 enum s = "0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp-16382";
3715 else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended)
3716 enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
3717 else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3718 enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
3719 else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3720 enum s = "0x1.FFFFFFFFFFFFFFFEp-1000";
3721 else
3722 static assert(false, "Floating point format for real not supported");
3724 auto s2 = s.idup;
3725 ld = parse!real(s2);
3726 assert(s2.empty);
3727 x = *cast(longdouble *)&ld;
3729 static if (floatTraits!real.realFormat == RealFormat.ieeeExtended)
3731 version (CRuntime_Microsoft)
3732 ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod
3733 else
3734 ld1 = strtold(s.ptr, null);
3736 else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3737 ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold rounds to 53 bits.
3738 else
3739 ld1 = strtold(s.ptr, null);
3741 x1 = *cast(longdouble *)&ld1;
3742 assert(x1 == x && ld1 == ld);
3744 assert(!errno);
3746 s2 = "1.0e5";
3747 ld = parse!real(s2);
3748 assert(s2.empty);
3749 x = *cast(longdouble *)&ld;
3750 ld1 = strtold("1.0e5", null);
3751 x1 = *cast(longdouble *)&ld1;
3754 @safe pure unittest
3756 import std.exception;
3758 // https://issues.dlang.org/show_bug.cgi?id=4959
3760 auto s = "0 ";
3761 auto x = parse!double(s);
3762 assert(s == " ");
3763 assert(x == 0.0);
3766 auto s = "0 ";
3767 auto x = parse!(double, string, Yes.doCount)(s);
3768 assert(s == " ");
3769 assert(x == tuple(0.0, 1));
3772 // https://issues.dlang.org/show_bug.cgi?id=3369
3773 assert(to!float("inf") == float.infinity);
3774 assert(to!float("-inf") == -float.infinity);
3776 // https://issues.dlang.org/show_bug.cgi?id=6160
3777 assert(6_5.536e3L == to!real("6_5.536e3")); // 2^16
3778 assert(0x1000_000_000_p10 == to!real("0x1000_000_000_p10")); // 7.03687e+13
3780 // https://issues.dlang.org/show_bug.cgi?id=6258
3781 assertThrown!ConvException(to!real("-"));
3782 assertThrown!ConvException(to!real("in"));
3784 // https://issues.dlang.org/show_bug.cgi?id=7055
3785 assertThrown!ConvException(to!float("INF2"));
3787 //extra stress testing
3788 auto ssOK = ["1.", "1.1.1", "1.e5", "2e1e", "2a", "2e1_1", "3.4_",
3789 "inf", "-inf", "infa", "-infa", "inf2e2", "-inf2e2",
3790 "nan", "-NAN", "+NaN", "-nAna", "NAn2e2", "-naN2e2"];
3791 auto ssKO = ["", " ", "2e", "2e+", "2e-", "2ee", "2e++1", "2e--1", "2e_1",
3792 "+inf", "-in", "I", "+N", "-NaD", "0x3.F"];
3793 foreach (s; ssOK)
3794 parse!double(s);
3795 foreach (s; ssKO)
3796 assertThrown!ConvException(parse!double(s));
3799 @safe unittest // https://issues.dlang.org/show_bug.cgi?id=22637
3801 import std.exception : assertThrown, assertNotThrown;
3802 auto src = "9991232549867999698999493543521458974414359998784641646846435132132543645435456345634541999999999999999"
3803 ~ "9999999943321231321311999231345312413646846354354354399999934153465464654646464654134135354199999999996515734999"
3804 ~ "9999999320135273486741354354731567431324134999999999999999999999999999999999999999999999135411.9";
3805 assertThrown!ConvException(parse!double(src));
3806 static if (real.max_10_exp > 310) assertNotThrown!ConvException(parse!real(src));
3810 Parses one character from a character range.
3812 Params:
3813 Target = the type to convert to
3814 s = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3815 doCount = the flag for deciding to report the number of consumed characters
3817 Returns:
3818 $(UL
3819 $(LI A character of type `Target` if `doCount` is set to `No.doCount`)
3820 $(LI A `tuple` containing a character of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
3822 Throws:
3823 A $(LREF ConvException) if the range is empty.
3825 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3826 if (staticIndexOf!(immutable Target, immutable dchar, immutable ElementEncodingType!Source) >= 0 &&
3827 isSomeString!Source && !is(Source == enum))
3829 if (s.empty)
3830 throw convError!(Source, Target)(s);
3831 static if (is(immutable Target == immutable dchar))
3833 Target result = s.front;
3834 s.popFront();
3835 static if (doCount)
3837 return tuple!("data", "count")(result, 1);
3839 else
3841 return result;
3845 else
3847 // Special case: okay so parse a Char off a Char[]
3848 Target result = s[0];
3849 s = s[1 .. $];
3850 static if (doCount)
3852 return tuple!("data", "count")(result, 1);
3854 else
3856 return result;
3861 @safe pure unittest
3863 static foreach (Str; AliasSeq!(string, wstring, dstring))
3865 static foreach (Char; AliasSeq!(char, wchar, dchar))
3867 static if (is(immutable Char == immutable dchar) ||
3868 Char.sizeof == ElementEncodingType!Str.sizeof)
3870 Str s = "aaa";
3871 assert(parse!Char(s) == 'a');
3872 assert(s == "aa");
3873 assert(parse!(Char, typeof(s), No.doCount)(s) == 'a');
3874 assert(s == "a");
3875 assert(parse!(Char, typeof(s), Yes.doCount)(s) == tuple('a', 1) && s == "");
3881 /// ditto
3882 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3883 if (isSomeChar!Target && Target.sizeof >= ElementType!Source.sizeof && !is(Target == enum) &&
3884 !isSomeString!Source && isInputRange!Source && isSomeChar!(ElementType!Source))
3886 if (s.empty)
3887 throw convError!(Source, Target)(s);
3888 Target result = s.front;
3889 s.popFront();
3890 static if (doCount)
3892 return tuple!("data", "count")(result, 1);
3894 else
3896 return result;
3901 @safe pure unittest
3903 import std.typecons : Flag, Yes, No;
3904 auto s = "Hello, World!";
3905 char first = parse!char(s);
3906 assert(first == 'H');
3907 assert(s == "ello, World!");
3908 char second = parse!(char, string, No.doCount)(s);
3909 assert(second == 'e');
3910 assert(s == "llo, World!");
3911 auto third = parse!(char, string, Yes.doCount)(s);
3912 assert(third.data == 'l' && third.count == 1);
3913 assert(s == "lo, World!");
3918 Tests for to!bool and parse!bool
3920 @safe pure unittest
3922 import std.exception;
3924 assert(to!bool("TruE") == true);
3925 assert(to!bool("faLse"d) == false);
3926 assertThrown!ConvException(to!bool("maybe"));
3928 auto t = "TrueType";
3929 assert(parse!bool(t) == true);
3930 assert(t == "Type");
3932 auto f = "False killer whale"d;
3933 assert(parse!bool(f) == false);
3934 assert(f == " killer whale"d);
3936 f = "False killer whale"d;
3937 assert(parse!(bool, dstring, Yes.doCount)(f) == tuple(false, 5));
3938 assert(f == " killer whale"d);
3940 auto m = "maybe";
3941 assertThrown!ConvException(parse!bool(m));
3942 assertThrown!ConvException(parse!(bool, string, Yes.doCount)(m));
3943 assert(m == "maybe"); // m shouldn't change on failure
3945 auto s = "true";
3946 auto b = parse!(const(bool))(s);
3947 assert(b == true);
3951 Parses `typeof(null)` from a character range if the range
3952 spells `"null"`. This function is case insensitive.
3954 Params:
3955 Target = the type to convert to
3956 s = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3957 doCount = the flag for deciding to report the number of consumed characters
3959 Returns:
3960 $(UL
3961 $(LI `null` if `doCount` is set to `No.doCount`)
3962 $(LI A `tuple` containing `null` and a `size_t` if `doCount` is set to `Yes.doCount`))
3964 Throws:
3965 A $(LREF ConvException) if the range doesn't represent `null`.
3967 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3968 if (is(immutable Target == immutable typeof(null)) &&
3969 isInputRange!Source &&
3970 isSomeChar!(ElementType!Source))
3972 import std.ascii : toLower;
3973 foreach (c; "null")
3975 if (s.empty || toLower(s.front) != c)
3976 throw parseError("null should be case-insensitive 'null'");
3977 s.popFront();
3979 static if (doCount)
3981 return tuple!("data", "count")(null, 4);
3983 else
3985 return null;
3990 @safe pure unittest
3992 import std.exception : assertThrown;
3993 import std.typecons : Flag, Yes, No;
3995 alias NullType = typeof(null);
3996 auto s1 = "null";
3997 assert(parse!NullType(s1) is null);
3998 assert(s1 == "");
4000 auto s2 = "NUll"d;
4001 assert(parse!NullType(s2) is null);
4002 assert(s2 == "");
4004 auto s3 = "nuLlNULl";
4005 assert(parse!(NullType, string, No.doCount)(s3) is null);
4006 auto r = parse!(NullType, string, Yes.doCount)(s3);
4007 assert(r.data is null && r.count == 4);
4009 auto m = "maybe";
4010 assertThrown!ConvException(parse!NullType(m));
4011 assertThrown!ConvException(parse!(NullType, string, Yes.doCount)(m));
4012 assert(m == "maybe"); // m shouldn't change on failure
4014 auto s = "NULL";
4015 assert(parse!(const NullType)(s) is null);
4018 //Used internally by parse Array/AA, to remove ascii whites
4019 package auto skipWS(R, Flag!"doCount" doCount = No.doCount)(ref R r)
4021 import std.ascii : isWhite;
4022 static if (isSomeString!R)
4024 //Implementation inspired from stripLeft.
4025 foreach (i, c; r)
4027 if (!isWhite(c))
4029 r = r[i .. $];
4030 static if (doCount)
4032 return i;
4034 else
4036 return;
4040 auto len = r.length;
4041 r = r[0 .. 0]; //Empty string with correct type.
4042 static if (doCount)
4044 return len;
4046 else
4048 return;
4051 else
4053 size_t i = 0;
4054 for (; !r.empty && isWhite(r.front); r.popFront(), ++i)
4056 static if (doCount)
4058 return i;
4064 * Parses an array from a string given the left bracket (default $(D
4065 * '[')), right bracket (default `']'`), and element separator (by
4066 * default `','`). A trailing separator is allowed.
4068 * Params:
4069 * s = The string to parse
4070 * lbracket = the character that starts the array
4071 * rbracket = the character that ends the array
4072 * comma = the character that separates the elements of the array
4073 * doCount = the flag for deciding to report the number of consumed characters
4075 * Returns:
4076 $(UL
4077 * $(LI An array of type `Target` if `doCount` is set to `No.doCount`)
4078 * $(LI A `tuple` containing an array of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
4080 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4081 dchar rbracket = ']', dchar comma = ',')
4082 if (isDynamicArray!Target && !is(Target == enum) &&
4083 isSomeString!Source && !is(Source == enum))
4085 import std.array : appender;
4087 auto result = appender!Target();
4089 parseCheck!s(lbracket);
4090 size_t count = 1 + skipWS!(Source, Yes.doCount)(s);
4091 if (s.empty)
4092 throw convError!(Source, Target)(s);
4093 if (s.front == rbracket)
4095 s.popFront();
4096 static if (doCount)
4098 return tuple!("data", "count")(result.data, ++count);
4100 else
4102 return result.data;
4105 for (;; s.popFront(), count += 1 + skipWS!(Source, Yes.doCount)(s))
4107 if (!s.empty && s.front == rbracket)
4108 break;
4109 auto r = parseElement!(WideElementType!Target, Source, Yes.doCount)(s);
4110 result ~= r.data;
4111 count += r.count + skipWS!(Source, Yes.doCount)(s);
4112 if (s.empty)
4113 throw convError!(Source, Target)(s);
4114 if (s.front != comma)
4115 break;
4117 parseCheck!s(rbracket);
4118 static if (doCount)
4120 return tuple!("data", "count")(result.data, ++count);
4122 else
4124 return result.data;
4129 @safe pure unittest
4131 import std.typecons : Flag, Yes, No;
4132 auto s1 = `[['h', 'e', 'l', 'l', 'o'], "world"]`;
4133 auto a1 = parse!(string[])(s1);
4134 assert(a1 == ["hello", "world"]);
4136 auto s2 = `["aaa", "bbb", "ccc"]`;
4137 auto a2 = parse!(string[])(s2);
4138 assert(a2 == ["aaa", "bbb", "ccc"]);
4140 auto s3 = `[['h', 'e', 'l', 'l', 'o'], "world"]`;
4141 auto len3 = s3.length;
4142 auto a3 = parse!(string[], string, Yes.doCount)(s3);
4143 assert(a3.data == ["hello", "world"]);
4144 assert(a3.count == len3);
4147 // https://issues.dlang.org/show_bug.cgi?id=9615
4148 @safe unittest
4150 import std.typecons : Flag, Yes, No, tuple;
4151 string s0 = "[1,2, ]";
4152 string s1 = "[1,2, \t\v\r\n]";
4153 string s2 = "[1,2]";
4154 assert(s0.parse!(int[]) == [1,2]);
4155 assert(s1.parse!(int[]) == [1,2]);
4156 assert(s2.parse!(int[]) == [1,2]);
4158 s0 = "[1,2, ]";
4159 auto len0 = s0.length;
4160 s1 = "[1,2, \t\v\r\n]";
4161 auto len1 = s1.length;
4162 s2 = "[1,2]";
4163 auto len2 = s2.length;
4164 assert(s0.parse!(int[], string, Yes.doCount) == tuple([1,2], len0));
4165 assert(s1.parse!(int[], string, Yes.doCount) == tuple([1,2], len1));
4166 assert(s2.parse!(int[], string, Yes.doCount) == tuple([1,2], len2));
4168 string s3 = `["a","b",]`;
4169 string s4 = `["a","b"]`;
4170 assert(s3.parse!(string[]) == ["a","b"]);
4171 assert(s4.parse!(string[]) == ["a","b"]);
4173 s3 = `["a","b",]`;
4174 auto len3 = s3.length;
4175 assert(s3.parse!(string[], string, Yes.doCount) == tuple(["a","b"], len3));
4177 s3 = `[ ]`;
4178 assert(tuple([], s3.length) == s3.parse!(string[], string, Yes.doCount));
4180 import std.exception : assertThrown;
4181 string s5 = "[,]";
4182 string s6 = "[, \t,]";
4183 assertThrown!ConvException(parse!(string[])(s5));
4184 assertThrown!ConvException(parse!(int[])(s6));
4186 s5 = "[,]";
4187 s6 = "[,·\t,]";
4188 assertThrown!ConvException(parse!(string[], string, Yes.doCount)(s5));
4189 assertThrown!ConvException(parse!(string[], string, Yes.doCount)(s6));
4192 @safe unittest
4194 int[] a = [1, 2, 3, 4, 5];
4195 auto s = to!string(a);
4196 assert(to!(int[])(s) == a);
4199 @safe unittest
4201 int[][] a = [ [1, 2] , [3], [4, 5] ];
4202 auto s = to!string(a);
4203 assert(to!(int[][])(s) == a);
4206 @safe unittest
4208 int[][][] ia = [ [[1,2],[3,4],[5]] , [[6],[],[7,8,9]] , [[]] ];
4210 char[] s = to!(char[])(ia);
4211 int[][][] ia2;
4213 ia2 = to!(typeof(ia2))(s);
4214 assert( ia == ia2);
4217 @safe pure unittest
4219 import std.exception;
4220 import std.typecons : Flag, Yes, No;
4222 //Check proper failure
4223 auto s = "[ 1 , 2 , 3 ]";
4224 auto s2 = s.save;
4225 foreach (i ; 0 .. s.length-1)
4227 auto ss = s[0 .. i];
4228 assertThrown!ConvException(parse!(int[])(ss));
4229 assertThrown!ConvException(parse!(int[], string, Yes.doCount)(ss));
4231 int[] arr = parse!(int[])(s);
4232 auto arr2 = parse!(int[], string, Yes.doCount)(s2);
4233 arr = arr2.data;
4236 @safe pure unittest
4238 //Checks parsing of strings with escaped characters
4239 string s1 = `[
4240 "Contains a\0null!",
4241 "tab\there",
4242 "line\nbreak",
4243 "backslash \\ slash / question \?",
4244 "number \x35 five",
4245 "unicode \u65E5 sun",
4246 "very long \U000065E5 sun"
4249 //Note: escaped characters purposefully replaced and isolated to guarantee
4250 //there are no typos in the escape syntax
4251 string[] s2 = [
4252 "Contains a" ~ '\0' ~ "null!",
4253 "tab" ~ '\t' ~ "here",
4254 "line" ~ '\n' ~ "break",
4255 "backslash " ~ '\\' ~ " slash / question ?",
4256 "number 5 five",
4257 "unicode 日 sun",
4258 "very long 日 sun"
4260 string s3 = s1.save;
4261 assert(s2 == parse!(string[])(s1));
4262 assert(s1.empty);
4263 assert(tuple(s2, s3.length) == parse!(string[], string, Yes.doCount)(s3));
4266 /// ditto
4267 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4268 dchar rbracket = ']', dchar comma = ',')
4269 if (isStaticArray!Target && !is(Target == enum) &&
4270 isExactSomeString!Source)
4272 static if (hasIndirections!Target)
4273 Target result = Target.init[0].init;
4274 else
4275 Target result = void;
4277 parseCheck!s(lbracket);
4278 size_t count = 1 + skipWS!(Source, Yes.doCount)(s);
4279 if (s.empty)
4280 throw convError!(Source, Target)(s);
4281 if (s.front == rbracket)
4283 static if (result.length != 0)
4284 goto Lmanyerr;
4285 else
4287 s.popFront();
4288 static if (doCount)
4290 return tuple!("data", "count")(result, ++count);
4292 else
4294 return result;
4298 for (size_t i = 0; ; s.popFront(), count += 1 + skipWS!(Source, Yes.doCount)(s))
4300 if (i == result.length)
4301 goto Lmanyerr;
4302 auto r = parseElement!(ElementType!Target, Source, Yes.doCount)(s);
4303 result[i++] = r.data;
4304 count += r.count + skipWS!(Source, Yes.doCount)(s);
4305 if (s.empty)
4306 throw convError!(Source, Target)(s);
4307 if (s.front != comma)
4309 if (i != result.length)
4310 goto Lfewerr;
4311 break;
4314 parseCheck!s(rbracket);
4315 static if (doCount)
4317 return tuple!("data", "count")(result, ++count);
4319 else
4321 return result;
4325 Lmanyerr:
4326 throw parseError(text("Too many elements in input, ", result.length, " elements expected."));
4328 Lfewerr:
4329 throw parseError(text("Too few elements in input, ", result.length, " elements expected."));
4332 @safe pure unittest
4334 import std.exception;
4336 auto s1 = "[1,2,3,4]";
4337 auto sa1 = parse!(int[4])(s1);
4338 assert(sa1 == [1,2,3,4]);
4339 s1 = "[1,2,3,4]";
4340 assert(tuple([1,2,3,4], s1.length) == parse!(int[4], string, Yes.doCount)(s1));
4342 auto s2 = "[[1],[2,3],[4]]";
4343 auto sa2 = parse!(int[][3])(s2);
4344 assert(sa2 == [[1],[2,3],[4]]);
4345 s2 = "[[1],[2,3],[4]]";
4346 assert(tuple([[1],[2,3],[4]], s2.length) == parse!(int[][3], string, Yes.doCount)(s2));
4348 auto s3 = "[1,2,3]";
4349 assertThrown!ConvException(parse!(int[4])(s3));
4350 assertThrown!ConvException(parse!(int[4], string, Yes.doCount)(s3));
4352 auto s4 = "[1,2,3,4,5]";
4353 assertThrown!ConvException(parse!(int[4])(s4));
4354 assertThrown!ConvException(parse!(int[4], string, Yes.doCount)(s4));
4358 * Parses an associative array from a string given the left bracket (default $(D
4359 * '[')), right bracket (default `']'`), key-value separator (default $(D
4360 * ':')), and element seprator (by default `','`).
4362 * Params:
4363 * s = the string to parse
4364 * lbracket = the character that starts the associative array
4365 * rbracket = the character that ends the associative array
4366 * keyval = the character that associates the key with the value
4367 * comma = the character that separates the elements of the associative array
4368 * doCount = the flag for deciding to report the number of consumed characters
4370 * Returns:
4371 $(UL
4372 * $(LI An associative array of type `Target` if `doCount` is set to `No.doCount`)
4373 * $(LI A `tuple` containing an associative array of type `Target` and a `size_t`
4374 * if `doCount` is set to `Yes.doCount`))
4376 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4377 dchar rbracket = ']', dchar keyval = ':', dchar comma = ',')
4378 if (isAssociativeArray!Target && !is(Target == enum) &&
4379 isSomeString!Source && !is(Source == enum))
4381 alias KeyType = typeof(Target.init.keys[0]);
4382 alias ValType = typeof(Target.init.values[0]);
4384 Target result;
4386 parseCheck!s(lbracket);
4387 size_t count = 1 + skipWS!(Source, Yes.doCount)(s);
4388 if (s.empty)
4389 throw convError!(Source, Target)(s);
4390 if (s.front == rbracket)
4392 s.popFront();
4393 static if (doCount)
4395 return tuple!("data", "count")(result, ++count);
4397 else
4399 return result;
4402 for (;; s.popFront(), count += 1 + skipWS!(Source, Yes.doCount)(s))
4404 auto key = parseElement!(KeyType, Source, Yes.doCount)(s);
4405 count += key.count + skipWS!(Source, Yes.doCount)(s);
4406 parseCheck!s(keyval);
4407 count += 1 + skipWS!(Source, Yes.doCount)(s);
4408 auto val = parseElement!(ValType, Source, Yes.doCount)(s);
4409 count += val.count + skipWS!(Source, Yes.doCount)(s);
4410 result[key.data] = val.data;
4411 if (s.empty)
4412 throw convError!(Source, Target)(s);
4413 if (s.front != comma)
4414 break;
4416 parseCheck!s(rbracket);
4417 static if (doCount)
4419 return tuple!("data", "count")(result, ++count);
4421 else
4423 return result;
4428 @safe pure unittest
4430 import std.typecons : Flag, Yes, No, tuple;
4431 import std.range.primitives : save;
4432 import std.array : assocArray;
4433 auto s1 = "[1:10, 2:20, 3:30]";
4434 auto copyS1 = s1.save;
4435 auto aa1 = parse!(int[int])(s1);
4436 assert(aa1 == [1:10, 2:20, 3:30]);
4437 assert(tuple([1:10, 2:20, 3:30], copyS1.length) == parse!(int[int], string, Yes.doCount)(copyS1));
4439 auto s2 = `["aaa":10, "bbb":20, "ccc":30]`;
4440 auto copyS2 = s2.save;
4441 auto aa2 = parse!(int[string])(s2);
4442 assert(aa2 == ["aaa":10, "bbb":20, "ccc":30]);
4443 assert(tuple(["aaa":10, "bbb":20, "ccc":30], copyS2.length) ==
4444 parse!(int[string], string, Yes.doCount)(copyS2));
4446 auto s3 = `["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]`;
4447 auto copyS3 = s3.save;
4448 auto aa3 = parse!(int[][string])(s3);
4449 assert(aa3 == ["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]);
4450 assert(tuple(["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]], copyS3.length) ==
4451 parse!(int[][string], string, Yes.doCount)(copyS3));
4453 auto s4 = `[]`;
4454 int[int] emptyAA;
4455 assert(tuple(emptyAA, s4.length) == parse!(int[int], string, Yes.doCount)(s4));
4458 @safe pure unittest
4460 import std.exception;
4462 //Check proper failure
4463 auto s = "[1:10, 2:20, 3:30]";
4464 auto s2 = s.save;
4465 foreach (i ; 0 .. s.length-1)
4467 auto ss = s[0 .. i];
4468 assertThrown!ConvException(parse!(int[int])(ss));
4469 assertThrown!ConvException(parse!(int[int], string, Yes.doCount)(ss));
4471 int[int] aa = parse!(int[int])(s);
4472 auto aa2 = parse!(int[int], string, Yes.doCount)(s2);
4473 aa = aa2[0];
4477 private auto parseEscape(Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4478 if (isInputRange!Source && isSomeChar!(ElementType!Source))
4480 parseCheck!s('\\');
4481 size_t count = 1;
4482 if (s.empty)
4483 throw parseError("Unterminated escape sequence");
4485 // consumes 1 element from Source
4486 dchar getHexDigit()(ref Source s_ = s) // workaround
4488 import std.ascii : isAlpha, isHexDigit;
4489 if (s_.empty)
4490 throw parseError("Unterminated escape sequence");
4491 s_.popFront();
4492 if (s_.empty)
4493 throw parseError("Unterminated escape sequence");
4494 dchar c = s_.front;
4495 if (!isHexDigit(c))
4496 throw parseError("Hex digit is missing");
4497 return isAlpha(c) ? ((c & ~0x20) - ('A' - 10)) : c - '0';
4500 // We need to do octals separate, because they need a lookahead to find out,
4501 // where the escape sequence ends.
4502 auto first = s.front;
4503 if (first >= '0' && first <= '7')
4505 dchar c1 = s.front;
4506 ++count;
4507 s.popFront();
4508 if (s.empty)
4510 static if (doCount)
4512 return tuple!("data", "count")(cast (dchar) (c1 - '0'), count);
4514 else
4516 return cast (dchar) (c1 - '0');
4519 dchar c2 = s.front;
4520 if (c2 < '0' || c2 > '7')
4522 static if (doCount)
4524 return tuple!("data", "count")(cast (dchar)(c1 - '0'), count);
4526 else
4528 return cast (dchar)(c1 - '0');
4531 ++count;
4532 s.popFront();
4533 dchar c3 = s.front;
4534 if (c3 < '0' || c3 > '7')
4536 static if (doCount)
4538 return tuple!("data", "count")(cast (dchar) (8 * (c1 - '0') + (c2 - '0')), count);
4540 else
4542 return cast (dchar) (8 * (c1 - '0') + (c2 - '0'));
4545 ++count;
4546 s.popFront();
4547 if (c1 > '3')
4548 throw parseError("Octal sequence is larger than \\377");
4549 static if (doCount)
4551 return tuple!("data", "count")(cast (dchar) (64 * (c1 - '0') + 8 * (c2 - '0') + (c3 - '0')), count);
4553 else
4555 return cast (dchar) (64 * (c1 - '0') + 8 * (c2 - '0') + (c3 - '0'));
4559 dchar result;
4561 switch (first)
4563 case '"': result = '\"'; break;
4564 case '\'': result = '\''; break;
4565 case '?': result = '\?'; break;
4566 case '\\': result = '\\'; break;
4567 case 'a': result = '\a'; break;
4568 case 'b': result = '\b'; break;
4569 case 'f': result = '\f'; break;
4570 case 'n': result = '\n'; break;
4571 case 'r': result = '\r'; break;
4572 case 't': result = '\t'; break;
4573 case 'v': result = '\v'; break;
4574 case 'x':
4575 result = getHexDigit() << 4;
4576 result |= getHexDigit();
4577 count += 2;
4578 break;
4579 case 'u':
4580 result = getHexDigit() << 12;
4581 result |= getHexDigit() << 8;
4582 result |= getHexDigit() << 4;
4583 result |= getHexDigit();
4584 count += 4;
4585 break;
4586 case 'U':
4587 result = getHexDigit() << 28;
4588 result |= getHexDigit() << 24;
4589 result |= getHexDigit() << 20;
4590 result |= getHexDigit() << 16;
4591 result |= getHexDigit() << 12;
4592 result |= getHexDigit() << 8;
4593 result |= getHexDigit() << 4;
4594 result |= getHexDigit();
4595 count += 8;
4596 break;
4597 default:
4598 throw parseError("Unknown escape character " ~ to!string(s.front));
4600 if (s.empty)
4601 throw parseError("Unterminated escape sequence");
4603 s.popFront();
4605 static if (doCount)
4607 return tuple!("data", "count")(cast (dchar) result, ++count);
4609 else
4611 return cast (dchar) result;
4615 @safe pure unittest
4617 string[] s1 = [
4618 `\"`, `\'`, `\?`, `\\`, `\a`, `\b`, `\f`, `\n`, `\r`, `\t`, `\v`, //Normal escapes
4619 `\141`,
4620 `\x61`,
4621 `\u65E5`, `\U00012456`,
4622 // https://issues.dlang.org/show_bug.cgi?id=9621 (Named Character Entities)
4623 //`\&amp;`, `\&quot;`,
4625 string[] copyS1 = s1 ~ s1[0 .. 0];
4627 const(dchar)[] s2 = [
4628 '\"', '\'', '\?', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v', //Normal escapes
4629 '\141',
4630 '\x61',
4631 '\u65E5', '\U00012456',
4632 // https://issues.dlang.org/show_bug.cgi?id=9621 (Named Character Entities)
4633 //'\&amp;', '\&quot;',
4636 foreach (i ; 0 .. s1.length)
4638 assert(s2[i] == parseEscape(s1[i]));
4639 assert(s1[i].empty);
4641 assert(tuple(s2[i], copyS1[i].length) == parseEscape!(string, Yes.doCount)(copyS1[i]));
4642 assert(copyS1[i].empty);
4646 @safe pure unittest
4648 import std.exception;
4650 string[] ss = [
4651 `hello!`, //Not an escape
4652 `\`, //Premature termination
4653 `\/`, //Not an escape
4654 `\gggg`, //Not an escape
4655 `\xzz`, //Not an hex
4656 `\x0`, //Premature hex end
4657 `\XB9`, //Not legal hex syntax
4658 `\u!!`, //Not a unicode hex
4659 `\777`, //Octal is larger than a byte
4660 `\80`, //Wrong digit at beginning of octal
4661 `\u123`, //Premature hex end
4662 `\U123123` //Premature hex end
4664 foreach (s ; ss)
4666 assertThrown!ConvException(parseEscape(s));
4667 assertThrown!ConvException(parseEscape!(string, Yes.doCount)(s));
4671 // Undocumented
4672 auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4673 if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
4674 isExactSomeString!Target)
4676 import std.array : appender;
4677 auto result = appender!Target();
4679 // parse array of chars
4680 if (s.empty)
4681 throw convError!(Source, Target)(s);
4682 if (s.front == '[')
4684 return parse!(Target, Source, doCount)(s);
4687 parseCheck!s('\"');
4688 size_t count = 1;
4689 if (s.empty)
4690 throw convError!(Source, Target)(s);
4691 if (s.front == '\"')
4693 s.popFront();
4694 static if (doCount)
4696 return tuple!("data", "count")(result.data, ++count);
4698 else
4700 return result.data;
4704 while (true)
4706 if (s.empty)
4707 throw parseError("Unterminated quoted string");
4708 switch (s.front)
4710 case '\"':
4711 s.popFront();
4712 static if (doCount)
4714 return tuple!("data", "count")(result.data, ++count);
4716 else
4718 return result.data;
4720 case '\\':
4721 auto r = parseEscape!(typeof(s), Yes.doCount)(s);
4722 result.put(r[0]);
4723 count += r[1];
4724 break;
4725 default:
4726 result.put(s.front);
4727 ++count;
4728 s.popFront();
4729 break;
4732 assert(false, "Unexpected fallthrough");
4735 // ditto
4736 auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4737 if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
4738 is(CharTypeOf!Target == dchar) && !is(Target == enum))
4740 Unqual!Target c;
4742 parseCheck!s('\'');
4743 size_t count = 1;
4744 if (s.empty)
4745 throw convError!(Source, Target)(s);
4746 ++count; // for the following if-else sequence
4747 if (s.front != '\\')
4749 c = s.front;
4750 s.popFront();
4752 else
4753 c = parseEscape(s);
4754 parseCheck!s('\'');
4755 static if (doCount)
4757 return tuple!("data", "count")(c, ++count);
4759 else
4761 return c;
4765 // ditto
4766 auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4767 if (isInputRange!Source && isSomeChar!(ElementType!Source) &&
4768 !isSomeString!Target && !isSomeChar!Target)
4770 return parse!(Target, Source, doCount)(s);
4773 // Use this when parsing a type that will ultimately be appended to a
4774 // string.
4775 package template WideElementType(T)
4777 alias E = ElementType!T;
4778 static if (isSomeChar!E)
4779 alias WideElementType = dchar;
4780 else
4781 alias WideElementType = E;
4785 /***************************************************************
4786 * Convenience functions for converting one or more arguments
4787 * of any type into _text (the three character widths).
4789 string text(T...)(T args)
4790 if (T.length > 0) { return textImpl!string(args); }
4792 ///ditto
4793 wstring wtext(T...)(T args)
4794 if (T.length > 0) { return textImpl!wstring(args); }
4796 ///ditto
4797 dstring dtext(T...)(T args)
4798 if (T.length > 0) { return textImpl!dstring(args); }
4801 @safe unittest
4803 assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c);
4804 assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w);
4805 assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d);
4808 @safe unittest
4810 char c = 'h';
4811 wchar w = '你';
4812 dchar d = 'እ';
4814 assert( text(c, "ello", ' ', w, "好 ", d, "ው ሰላም ነው") == "hello 你好 እው ሰላም ነው"c);
4815 assert(wtext(c, "ello", ' ', w, "好 ", d, "ው ሰላም ነው") == "hello 你好 እው ሰላም ነው"w);
4816 assert(dtext(c, "ello", ' ', w, "好 ", d, "ው ሰላም ነው") == "hello 你好 እው ሰላም ነው"d);
4818 string cs = "今日は";
4819 wstring ws = "여보세요";
4820 dstring ds = "Здравствуйте";
4822 assert( text(cs, ' ', ws, " ", ds) == "今日は 여보세요 Здравствуйте"c);
4823 assert(wtext(cs, ' ', ws, " ", ds) == "今日は 여보세요 Здравствуйте"w);
4824 assert(dtext(cs, ' ', ws, " ", ds) == "今日は 여보세요 Здравствуйте"d);
4827 private S textImpl(S, U...)(U args)
4829 static if (U.length == 0)
4831 return null;
4833 else static if (U.length == 1)
4835 return to!S(args[0]);
4837 else
4839 import std.array : appender;
4840 import std.traits : isSomeChar, isSomeString;
4842 auto app = appender!S();
4844 // assume that on average, parameters will have less
4845 // than 20 elements
4846 app.reserve(U.length * 20);
4847 // Must be static foreach because of https://issues.dlang.org/show_bug.cgi?id=21209
4848 static foreach (arg; args)
4850 static if (
4851 isSomeChar!(typeof(arg))
4852 || isSomeString!(typeof(arg))
4853 || ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) )
4855 app.put(arg);
4856 else static if (
4858 is(immutable typeof(arg) == immutable uint) || is(immutable typeof(arg) == immutable ulong) ||
4859 is(immutable typeof(arg) == immutable int) || is(immutable typeof(arg) == immutable long)
4861 // https://issues.dlang.org/show_bug.cgi?id=17712#c15
4862 app.put(textImpl!(S)(arg));
4863 else
4864 app.put(to!S(arg));
4867 return app.data;
4872 /***************************************************************
4873 The `octal` facility provides a means to declare a number in base 8.
4874 Using `octal!177` or `octal!"177"` for 127 represented in octal
4875 (same as 0177 in C).
4877 The rules for strings are the usual for literals: If it can fit in an
4878 `int`, it is an `int`. Otherwise, it is a `long`. But, if the
4879 user specifically asks for a `long` with the `L` suffix, always
4880 give the `long`. Give an unsigned iff it is asked for with the $(D
4881 U) or `u` suffix. _Octals created from integers preserve the type
4882 of the passed-in integral.
4884 See_Also:
4885 $(LREF parse) for parsing octal strings at runtime.
4887 template octal(string num)
4888 if (isOctalLiteral(num))
4890 static if ((octalFitsInInt!num && !literalIsLong!num) && !literalIsUnsigned!num)
4891 enum octal = octal!int(num);
4892 else static if ((!octalFitsInInt!num || literalIsLong!num) && !literalIsUnsigned!num)
4893 enum octal = octal!long(num);
4894 else static if ((octalFitsInInt!num && !literalIsLong!num) && literalIsUnsigned!num)
4895 enum octal = octal!uint(num);
4896 else static if ((!octalFitsInInt!(num) || literalIsLong!(num)) && literalIsUnsigned!(num))
4897 enum octal = octal!ulong(num);
4898 else
4899 static assert(false, "Unusable input " ~ num);
4902 /// Ditto
4903 template octal(alias decimalInteger)
4904 if (is(typeof(decimalInteger)) && isIntegral!(typeof(decimalInteger)))
4906 enum octal = convertToOctal(decimalInteger);
4910 @safe unittest
4912 // Same as 0177
4913 auto a = octal!177;
4914 // octal is a compile-time device
4915 enum b = octal!160;
4916 // Create an unsigned octal
4917 auto c = octal!"1_000_000u";
4918 // Leading zeros are allowed when converting from a string
4919 auto d = octal!"0001_200_000";
4922 /*************************************
4923 * Convert a decimal integer to an octal integer with the same digits.
4924 * Params:
4925 * i = integer to convert
4926 * Returns:
4927 * octal integer with the same type and same digits
4929 private T convertToOctal(T)(T i)
4931 assert((i % 10) < 8);
4932 return i ? convertToOctal(i / 10) * 8 + i % 10 : 0;
4936 Takes a string, num, which is an octal literal, and returns its
4937 value, in the type T specified.
4939 private T octal(T)(const string num)
4941 assert(isOctalLiteral(num), num ~ " is not an octal literal");
4943 T value = 0;
4945 foreach (const char s; num)
4947 if (s < '0' || s > '7') // we only care about digits; skip the rest
4948 // safe to skip - this is checked out in the assert so these
4949 // are just suffixes
4950 continue;
4952 value *= 8;
4953 value += s - '0';
4956 return value;
4959 @safe unittest
4961 int a = octal!int("10");
4962 assert(a == 8);
4964 int b = octal!int("000137");
4965 assert(b == 95);
4969 Take a look at int.max and int.max+1 in octal and the logic for this
4970 function follows directly.
4972 private template octalFitsInInt(string octalNum)
4974 // note it is important to strip the literal of all
4975 // non-numbers. kill the suffix and underscores lest they mess up
4976 // the number of digits here that we depend on.
4977 enum bool octalFitsInInt = strippedOctalLiteral(octalNum).length < 11 ||
4978 strippedOctalLiteral(octalNum).length == 11 &&
4979 strippedOctalLiteral(octalNum)[0] == '1';
4982 private string strippedOctalLiteral(string original)
4984 string stripped = "";
4985 bool leading_zeros = true;
4986 foreach (c; original)
4988 if (!('0' <= c && c <= '7'))
4989 continue;
4990 if (c == '0')
4992 if (leading_zeros)
4993 continue;
4995 else
4997 leading_zeros = false;
4999 stripped ~= c;
5001 if (stripped.length == 0)
5003 assert(leading_zeros);
5004 return "0";
5006 return stripped;
5009 @safe unittest
5011 static assert(strippedOctalLiteral("7") == "7");
5012 static assert(strippedOctalLiteral("123") == "123");
5013 static assert(strippedOctalLiteral("00123") == "123");
5014 static assert(strippedOctalLiteral("01230") == "1230");
5015 static assert(strippedOctalLiteral("0") == "0");
5016 static assert(strippedOctalLiteral("00_000") == "0");
5017 static assert(strippedOctalLiteral("000_000_12_300") == "12300");
5020 private template literalIsLong(string num)
5022 static if (num.length > 1)
5023 // can be xxL or xxLu according to spec
5024 enum literalIsLong = (num[$-1] == 'L' || num[$-2] == 'L');
5025 else
5026 enum literalIsLong = false;
5029 private template literalIsUnsigned(string num)
5031 static if (num.length > 1)
5032 // can be xxU or xxUL according to spec
5033 enum literalIsUnsigned = (num[$-1] == 'u' || num[$-2] == 'u')
5034 // both cases are allowed too
5035 || (num[$-1] == 'U' || num[$-2] == 'U');
5036 else
5037 enum literalIsUnsigned = false;
5041 Returns if the given string is a correctly formatted octal literal.
5043 The format is specified in spec/lex.html. The leading zeros are allowed,
5044 but not required.
5046 @safe pure nothrow @nogc
5047 private bool isOctalLiteral(const string num)
5049 if (num.length == 0)
5050 return false;
5052 // Must start with a digit.
5053 if (num[0] < '0' || num[0] > '7')
5054 return false;
5056 foreach (i, c; num)
5058 if (('0' <= c && c <= '7') || c == '_') // a legal character
5059 continue;
5061 if (i < num.length - 2)
5062 return false;
5064 // gotta check for those suffixes
5065 if (c != 'U' && c != 'u' && c != 'L')
5066 return false;
5067 if (i != num.length - 1)
5069 // if we're not the last one, the next one must
5070 // also be a suffix to be valid
5071 char c2 = num[$-1];
5072 if (c2 != 'U' && c2 != 'u' && c2 != 'L')
5073 return false; // spam at the end of the string
5074 if (c2 == c)
5075 return false; // repeats are disallowed
5079 return true;
5082 @safe unittest
5084 // ensure that you get the right types, even with embedded underscores
5085 auto w = octal!"100_000_000_000";
5086 static assert(!is(typeof(w) == int));
5087 auto w2 = octal!"1_000_000_000";
5088 static assert(is(typeof(w2) == int));
5090 static assert(octal!"45" == 37);
5091 static assert(octal!"0" == 0);
5092 static assert(octal!"7" == 7);
5093 static assert(octal!"10" == 8);
5094 static assert(octal!"666" == 438);
5095 static assert(octal!"0004001" == 2049);
5096 static assert(octal!"00" == 0);
5097 static assert(octal!"0_0" == 0);
5099 static assert(octal!45 == 37);
5100 static assert(octal!0 == 0);
5101 static assert(octal!7 == 7);
5102 static assert(octal!10 == 8);
5103 static assert(octal!666 == 438);
5105 static assert(octal!"66_6" == 438);
5106 static assert(octal!"0_0_66_6" == 438);
5108 static assert(octal!2520046213 == 356535435);
5109 static assert(octal!"2520046213" == 356535435);
5111 static assert(octal!17777777777 == int.max);
5113 static assert(!__traits(compiles, octal!823));
5115 static assert(!__traits(compiles, octal!"823"));
5117 static assert(!__traits(compiles, octal!"_823"));
5118 static assert(!__traits(compiles, octal!"spam"));
5119 static assert(!__traits(compiles, octal!"77%"));
5121 static assert(is(typeof(octal!"17777777777") == int));
5122 static assert(octal!"17777777777" == int.max);
5124 static assert(is(typeof(octal!"20000000000U") == ulong)); // Shouldn't this be uint?
5125 static assert(octal!"20000000000" == uint(int.max) + 1);
5127 static assert(is(typeof(octal!"777777777777777777777") == long));
5128 static assert(octal!"777777777777777777777" == long.max);
5130 static assert(is(typeof(octal!"1000000000000000000000U") == ulong));
5131 static assert(octal!"1000000000000000000000" == ulong(long.max) + 1);
5133 int a;
5134 long b;
5136 // biggest value that should fit in an it
5137 a = octal!"17777777777";
5138 assert(a == int.max);
5139 // should not fit in the int
5140 static assert(!__traits(compiles, a = octal!"20000000000"));
5141 // ... but should fit in a long
5142 b = octal!"20000000000";
5143 assert(b == 1L + int.max);
5145 b = octal!"1L";
5146 assert(b == 1);
5147 b = octal!1L;
5148 assert(b == 1);
5151 // emplace() used to be here but was moved to druntime
5152 public import core.lifetime : emplace;
5154 // https://issues.dlang.org/show_bug.cgi?id=9559
5155 @safe unittest
5157 import std.algorithm.iteration : map;
5158 import std.array : array;
5159 import std.typecons : Nullable;
5160 alias I = Nullable!int;
5161 auto ints = [0, 1, 2].map!(i => i & 1 ? I.init : I(i))();
5162 auto asArray = array(ints);
5165 @system unittest //http://forum.dlang.org/post/nxbdgtdlmwscocbiypjs@forum.dlang.org
5167 import std.array : array;
5168 import std.datetime : SysTime, UTC;
5169 import std.math.traits : isNaN;
5171 static struct A
5173 double i;
5176 static struct B
5178 invariant()
5180 if (j == 0)
5181 assert(a.i.isNaN(), "why is 'j' zero?? and i is not NaN?");
5182 else
5183 assert(!a.i.isNaN());
5185 SysTime when; // comment this line avoid the breakage
5186 int j;
5187 A a;
5190 B b1 = B.init;
5191 assert(&b1); // verify that default eyes invariants are ok;
5193 auto b2 = B(SysTime(0, UTC()), 1, A(1));
5194 assert(&b2);
5195 auto b3 = B(SysTime(0, UTC()), 1, A(1));
5196 assert(&b3);
5198 auto arr = [b2, b3];
5200 assert(arr[0].j == 1);
5201 assert(arr[1].j == 1);
5202 auto a2 = arr.array(); // << bang, invariant is raised, also if b2 and b3 are good
5205 @safe unittest
5207 import std.algorithm.comparison : equal;
5208 import std.algorithm.iteration : map;
5209 // Check fix for https://issues.dlang.org/show_bug.cgi?id=2971
5210 assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345]));
5213 // Undocumented for the time being
5214 void toTextRange(T, W)(T value, W writer)
5215 if (isIntegral!T && isOutputRange!(W, char))
5217 import core.internal.string : SignedStringBuf, signedToTempString,
5218 UnsignedStringBuf, unsignedToTempString;
5220 if (value < 0)
5222 SignedStringBuf buf = void;
5223 put(writer, signedToTempString(value, buf));
5225 else
5227 UnsignedStringBuf buf = void;
5228 put(writer, unsignedToTempString(value, buf));
5232 @safe unittest
5234 import std.array : appender;
5235 auto result = appender!(char[])();
5236 toTextRange(-1, result);
5237 assert(result.data == "-1");
5242 Returns the corresponding _unsigned value for `x` (e.g. if `x` has type
5243 `int`, it returns $(D cast(uint) x)). The advantage compared to the cast
5244 is that you do not need to rewrite the cast if `x` later changes type
5245 (e.g from `int` to `long`).
5247 Note that the result is always mutable even if the original type was const
5248 or immutable. In order to retain the constness, use $(REF Unsigned, std,traits).
5250 auto unsigned(T)(T x)
5251 if (isIntegral!T)
5253 return cast(Unqual!(Unsigned!T))x;
5257 @safe unittest
5259 import std.traits : Unsigned;
5260 immutable int s = 42;
5261 auto u1 = unsigned(s); //not qualified
5262 static assert(is(typeof(u1) == uint));
5263 Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification
5264 static assert(is(typeof(u2) == immutable uint));
5265 immutable u3 = unsigned(s); //explicitly qualified
5268 /// Ditto
5269 auto unsigned(T)(T x)
5270 if (isSomeChar!T)
5272 // All characters are unsigned
5273 static assert(T.min == 0, T.stringof ~ ".min must be zero");
5274 return cast(Unqual!T) x;
5277 @safe unittest
5279 static foreach (T; AliasSeq!(byte, ubyte))
5281 static assert(is(typeof(unsigned(cast(T) 1)) == ubyte));
5282 static assert(is(typeof(unsigned(cast(const T) 1)) == ubyte));
5283 static assert(is(typeof(unsigned(cast(immutable T) 1)) == ubyte));
5286 static foreach (T; AliasSeq!(short, ushort))
5288 static assert(is(typeof(unsigned(cast(T) 1)) == ushort));
5289 static assert(is(typeof(unsigned(cast(const T) 1)) == ushort));
5290 static assert(is(typeof(unsigned(cast(immutable T) 1)) == ushort));
5293 static foreach (T; AliasSeq!(int, uint))
5295 static assert(is(typeof(unsigned(cast(T) 1)) == uint));
5296 static assert(is(typeof(unsigned(cast(const T) 1)) == uint));
5297 static assert(is(typeof(unsigned(cast(immutable T) 1)) == uint));
5300 static foreach (T; AliasSeq!(long, ulong))
5302 static assert(is(typeof(unsigned(cast(T) 1)) == ulong));
5303 static assert(is(typeof(unsigned(cast(const T) 1)) == ulong));
5304 static assert(is(typeof(unsigned(cast(immutable T) 1)) == ulong));
5308 @safe unittest
5310 static foreach (T; AliasSeq!(char, wchar, dchar))
5312 static assert(is(typeof(unsigned(cast(T)'A')) == T));
5313 static assert(is(typeof(unsigned(cast(const T)'A')) == T));
5314 static assert(is(typeof(unsigned(cast(immutable T)'A')) == T));
5320 Returns the corresponding _signed value for `x` (e.g. if `x` has type
5321 `uint`, it returns $(D cast(int) x)). The advantage compared to the cast
5322 is that you do not need to rewrite the cast if `x` later changes type
5323 (e.g from `uint` to `ulong`).
5325 Note that the result is always mutable even if the original type was const
5326 or immutable. In order to retain the constness, use $(REF Signed, std,traits).
5328 auto signed(T)(T x)
5329 if (isIntegral!T)
5331 return cast(Unqual!(Signed!T))x;
5335 @safe unittest
5337 import std.traits : Signed;
5339 immutable uint u = 42;
5340 auto s1 = signed(u); //not qualified
5341 static assert(is(typeof(s1) == int));
5342 Signed!(typeof(u)) s2 = signed(u); //same qualification
5343 static assert(is(typeof(s2) == immutable int));
5344 immutable s3 = signed(u); //explicitly qualified
5347 @system unittest
5349 static foreach (T; AliasSeq!(byte, ubyte))
5351 static assert(is(typeof(signed(cast(T) 1)) == byte));
5352 static assert(is(typeof(signed(cast(const T) 1)) == byte));
5353 static assert(is(typeof(signed(cast(immutable T) 1)) == byte));
5356 static foreach (T; AliasSeq!(short, ushort))
5358 static assert(is(typeof(signed(cast(T) 1)) == short));
5359 static assert(is(typeof(signed(cast(const T) 1)) == short));
5360 static assert(is(typeof(signed(cast(immutable T) 1)) == short));
5363 static foreach (T; AliasSeq!(int, uint))
5365 static assert(is(typeof(signed(cast(T) 1)) == int));
5366 static assert(is(typeof(signed(cast(const T) 1)) == int));
5367 static assert(is(typeof(signed(cast(immutable T) 1)) == int));
5370 static foreach (T; AliasSeq!(long, ulong))
5372 static assert(is(typeof(signed(cast(T) 1)) == long));
5373 static assert(is(typeof(signed(cast(const T) 1)) == long));
5374 static assert(is(typeof(signed(cast(immutable T) 1)) == long));
5378 // https://issues.dlang.org/show_bug.cgi?id=10874
5379 @safe unittest
5381 enum Test { a = 0 }
5382 ulong l = 0;
5383 auto t = l.to!Test;
5386 // asOriginalType
5388 Returns the representation of an enumerated value, i.e. the value converted to
5389 the base type of the enumeration.
5391 OriginalType!E asOriginalType(E)(E value)
5392 if (is(E == enum))
5394 return value;
5398 @safe unittest
5400 enum A { a = 42 }
5401 static assert(is(typeof(A.a.asOriginalType) == int));
5402 assert(A.a.asOriginalType == 42);
5403 enum B : double { a = 43 }
5404 static assert(is(typeof(B.a.asOriginalType) == double));
5405 assert(B.a.asOriginalType == 43);
5409 A wrapper on top of the built-in cast operator that allows one to restrict
5410 casting of the original type of the value.
5412 A common issue with using a raw cast is that it may silently continue to
5413 compile even if the value's type has changed during refactoring,
5414 which breaks the initial assumption about the cast.
5416 Params:
5417 From = The type to cast from. The programmer must ensure it is legal
5418 to make this cast.
5420 template castFrom(From)
5423 Params:
5424 To = The type _to cast _to.
5425 value = The value _to cast. It must be of type `From`,
5426 otherwise a compile-time error is emitted.
5428 Returns:
5429 the value after the cast, returned by reference if possible.
5431 auto ref to(To, T)(auto ref T value) @system
5433 static assert(
5434 is(From == T),
5435 "the value to cast is not of specified type '" ~ From.stringof ~
5436 "', it is of type '" ~ T.stringof ~ "'"
5439 static assert(
5440 is(typeof(cast(To) value)),
5441 "can't cast from '" ~ From.stringof ~ "' to '" ~ To.stringof ~ "'"
5444 return cast(To) value;
5449 @system unittest
5451 // Regular cast, which has been verified to be legal by the programmer:
5453 long x;
5454 auto y = cast(int) x;
5457 // However this will still compile if 'x' is changed to be a pointer:
5459 long* x;
5460 auto y = cast(int) x;
5463 // castFrom provides a more reliable alternative to casting:
5465 long x;
5466 auto y = castFrom!long.to!int(x);
5469 // Changing the type of 'x' will now issue a compiler error,
5470 // allowing bad casts to be caught before it's too late:
5472 long* x;
5473 static assert(
5474 !__traits(compiles, castFrom!long.to!int(x))
5477 // if cast is still needed, must be changed to:
5478 auto y = castFrom!(long*).to!int(x);
5482 // https://issues.dlang.org/show_bug.cgi?id=16667
5483 @system unittest
5485 ubyte[] a = ['a', 'b', 'c'];
5486 assert(castFrom!(ubyte[]).to!(string)(a) == "abc");
5490 Check the correctness of a string for `hexString`.
5491 The result is true if and only if the input string is composed of whitespace
5492 characters (\f\n\r\t\v lineSep paraSep nelSep) and
5493 an even number of hexadecimal digits (regardless of the case).
5495 @safe pure @nogc
5496 private bool isHexLiteral(String)(scope const String hexData)
5498 import std.ascii : isHexDigit;
5499 import std.uni : lineSep, paraSep, nelSep;
5500 size_t i;
5501 foreach (const dchar c; hexData)
5503 switch (c)
5505 case ' ':
5506 case '\t':
5507 case '\v':
5508 case '\f':
5509 case '\r':
5510 case '\n':
5511 case lineSep:
5512 case paraSep:
5513 case nelSep:
5514 continue;
5516 default:
5517 break;
5519 if (c.isHexDigit)
5520 ++i;
5521 else
5522 return false;
5524 return !(i & 1);
5527 @safe unittest
5529 // test all the hex digits
5530 static assert( ("0123456789abcdefABCDEF").isHexLiteral);
5531 // empty or white strings are not valid
5532 static assert( "\r\n\t".isHexLiteral);
5533 // but are accepted if the count of hex digits is even
5534 static assert( "A\r\n\tB".isHexLiteral);
5537 @safe unittest
5539 import std.ascii;
5540 // empty/whites
5541 static assert( "".isHexLiteral);
5542 static assert( " \r".isHexLiteral);
5543 static assert( whitespace.isHexLiteral);
5544 static assert( ""w.isHexLiteral);
5545 static assert( " \r"w.isHexLiteral);
5546 static assert( ""d.isHexLiteral);
5547 static assert( " \r"d.isHexLiteral);
5548 static assert( "\u2028\u2029\u0085"d.isHexLiteral);
5549 // odd x strings
5550 static assert( !("5" ~ whitespace).isHexLiteral);
5551 static assert( !"123".isHexLiteral);
5552 static assert( !"1A3".isHexLiteral);
5553 static assert( !"1 23".isHexLiteral);
5554 static assert( !"\r\n\tC".isHexLiteral);
5555 static assert( !"123"w.isHexLiteral);
5556 static assert( !"1A3"w.isHexLiteral);
5557 static assert( !"1 23"w.isHexLiteral);
5558 static assert( !"\r\n\tC"w.isHexLiteral);
5559 static assert( !"123"d.isHexLiteral);
5560 static assert( !"1A3"d.isHexLiteral);
5561 static assert( !"1 23"d.isHexLiteral);
5562 static assert( !"\r\n\tC"d.isHexLiteral);
5563 // even x strings with invalid charset
5564 static assert( !"12gG".isHexLiteral);
5565 static assert( !"2A 3q".isHexLiteral);
5566 static assert( !"12gG"w.isHexLiteral);
5567 static assert( !"2A 3q"w.isHexLiteral);
5568 static assert( !"12gG"d.isHexLiteral);
5569 static assert( !"2A 3q"d.isHexLiteral);
5570 // valid x strings
5571 static assert( ("5A" ~ whitespace).isHexLiteral);
5572 static assert( ("5A 01A C FF de 1b").isHexLiteral);
5573 static assert( ("0123456789abcdefABCDEF").isHexLiteral);
5574 static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF").isHexLiteral);
5575 static assert( ("5A 01A C FF de 1b"w).isHexLiteral);
5576 static assert( ("0123456789abcdefABCDEF"w).isHexLiteral);
5577 static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"w).isHexLiteral);
5578 static assert( ("5A 01A C FF de 1b"d).isHexLiteral);
5579 static assert( ("0123456789abcdefABCDEF"d).isHexLiteral);
5580 static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"d).isHexLiteral);
5581 // library version allows what's pointed by https://issues.dlang.org/show_bug.cgi?id=10454
5582 static assert( ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").isHexLiteral);
5586 Converts a hex literal to a string at compile time.
5588 Takes a string made of hexadecimal digits and returns
5589 the matching string by converting each pair of digits to a character.
5590 The input string can also include white characters, which can be used
5591 to keep the literal string readable in the source code.
5593 The function is intended to replace the hexadecimal literal strings
5594 starting with `'x'`, which could be removed to simplify the core language.
5596 Params:
5597 hexData = string to be converted.
5599 Returns:
5600 a `string`, a `wstring` or a `dstring`, according to the type of hexData.
5602 template hexString(string hexData)
5603 if (hexData.isHexLiteral)
5605 enum hexString = mixin(hexToString(hexData));
5608 /// ditto
5609 template hexString(wstring hexData)
5610 if (hexData.isHexLiteral)
5612 enum wstring hexString = mixin(hexToString(hexData));
5615 /// ditto
5616 template hexString(dstring hexData)
5617 if (hexData.isHexLiteral)
5619 enum dstring hexString = mixin(hexToString(hexData));
5623 @safe unittest
5625 // conversion at compile time
5626 auto string1 = hexString!"304A314B";
5627 assert(string1 == "0J1K");
5628 auto string2 = hexString!"304A314B"w;
5629 assert(string2 == "0J1K"w);
5630 auto string3 = hexString!"304A314B"d;
5631 assert(string3 == "0J1K"d);
5634 @safe nothrow pure private
5636 /* These are meant to be used with CTFE.
5637 * They cause the instantiations of hexStrLiteral()
5638 * to be in Phobos, not user code.
5640 string hexToString(string s)
5642 return hexStrLiteral(s);
5645 wstring hexToString(wstring s)
5647 return hexStrLiteral(s);
5650 dstring hexToString(dstring s)
5652 return hexStrLiteral(s);
5657 Turn a hexadecimal string into a regular string literal.
5658 I.e. "dead beef" is transformed into "\xde\xad\xbe\xef"
5659 suitable for use in a mixin.
5660 Params:
5661 hexData is string, wstring, or dstring and validated by isHexLiteral()
5663 @trusted nothrow pure
5664 private auto hexStrLiteral(String)(scope String hexData)
5666 import std.ascii : isHexDigit;
5667 alias C = Unqual!(ElementEncodingType!String); // char, wchar or dchar
5668 C[] result;
5669 result.length = 1 + hexData.length * 2 + 1; // don't forget the " "
5670 /* Use a pointer because we know it won't overrun,
5671 * and this will reduce the size of the function substantially
5672 * by not doing the array bounds checks.
5673 * This is why this function is @trusted.
5675 auto r = result.ptr;
5676 r[0] = '"';
5677 size_t cnt = 0;
5678 foreach (c; hexData)
5680 if (c.isHexDigit)
5682 if ((cnt & 1) == 0)
5684 r[1 + cnt] = '\\';
5685 r[1 + cnt + 1] = 'x';
5686 cnt += 2;
5688 r[1 + cnt] = c;
5689 ++cnt;
5692 r[1 + cnt] = '"';
5693 result.length = 1 + cnt + 1; // trim off any excess length
5694 return result;
5698 @safe unittest
5700 // compile time
5701 assert(hexString!"46 47 48 49 4A 4B" == "FGHIJK");
5702 assert(hexString!"30\r\n\t\f\v31 32 33 32 31 30" == "0123210");
5703 assert(hexString!"ab cd" == hexString!"ABCD");
5708 * Convert integer to a range of characters.
5709 * Intended to be lightweight and fast.
5711 * Params:
5712 * radix = 2, 8, 10, 16
5713 * Char = character type for output
5714 * letterCase = lower for deadbeef, upper for DEADBEEF
5715 * value = integer to convert. Can be ubyte, ushort, uint or ulong. If radix
5716 * is 10, can also be byte, short, int or long.
5717 * Returns:
5718 * Random access range with slicing and everything
5721 auto toChars(ubyte radix = 10, Char = char, LetterCase letterCase = LetterCase.lower, T)(T value)
5722 pure nothrow @nogc @safe
5723 if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) &&
5724 isIntegral!T && (radix == 10 || isUnsigned!T))
5726 alias UT = Unqual!T;
5728 static if (radix == 10)
5730 /* uint.max is 42_9496_7295
5731 * int.max is 21_4748_3647
5732 * ulong.max is 1844_6744_0737_0955_1615
5733 * long.max is 922_3372_0368_5477_5807
5735 static struct Result
5737 void initialize(UT value)
5739 import core.internal.string : signedToTempString, unsignedToTempString;
5741 char[] t = value < 0
5742 ? signedToTempString!(10, false, char)(value, buf)
5743 : unsignedToTempString!(10, false, char)(value, buf);
5745 lwr = cast(uint) (buf.length - t.length);
5746 upr = cast(uint) buf.length;
5749 @property size_t length() { return upr - lwr; }
5751 alias opDollar = length;
5753 @property bool empty() { return upr == lwr; }
5755 @property Char front() { return buf[lwr]; }
5757 void popFront() { ++lwr; }
5759 @property Char back() { return buf[upr - 1]; }
5761 void popBack() { --upr; }
5763 @property Result save() { return this; }
5765 Char opIndex(size_t i) { return buf[lwr + i]; }
5767 Result opSlice(size_t lwr, size_t upr)
5769 Result result = void;
5770 result.buf = buf;
5771 result.lwr = cast(uint)(this.lwr + lwr);
5772 result.upr = cast(uint)(this.lwr + upr);
5773 return result;
5776 private:
5777 uint lwr = void, upr = void;
5778 char[(UT.sizeof == 4) ? 10 + isSigned!T : 20] buf = void;
5781 Result result;
5782 result.initialize(value);
5783 return result;
5785 else
5787 static if (radix == 2)
5788 enum SHIFT = 1;
5789 else static if (radix == 8)
5790 enum SHIFT = 3;
5791 else static if (radix == 16)
5792 enum SHIFT = 4;
5793 else
5794 static assert(false, "radix must be 2, 8, 10, or 16");
5795 static struct Result
5797 this(UT value)
5799 this.value = value;
5801 ubyte len = 1;
5802 while (value >>>= SHIFT)
5803 ++len;
5804 this.len = len;
5807 @property size_t length() { return len; }
5809 @property bool empty() { return len == 0; }
5811 @property Char front() { return opIndex(0); }
5813 void popFront() { --len; }
5815 @property Char back() { return opIndex(len - 1); }
5817 void popBack()
5819 value >>>= SHIFT;
5820 --len;
5823 @property Result save() { return this; }
5825 Char opIndex(size_t i)
5827 Char c = (value >>> ((len - i - 1) * SHIFT)) & ((1 << SHIFT) - 1);
5828 return cast(Char)((radix < 10 || c < 10) ? c + '0'
5829 : (letterCase == LetterCase.upper ? c + 'A' - 10
5830 : c + 'a' - 10));
5833 Result opSlice(size_t lwr, size_t upr)
5835 Result result = void;
5836 result.value = value >>> ((len - upr) * SHIFT);
5837 result.len = cast(ubyte)(upr - lwr);
5838 return result;
5841 private:
5842 UT value;
5843 ubyte len;
5846 return Result(value);
5851 @safe unittest
5853 import std.algorithm.comparison : equal;
5855 assert(toChars(1).equal("1"));
5856 assert(toChars(1_000_000).equal("1000000"));
5858 assert(toChars!(2)(2U).equal("10"));
5859 assert(toChars!(16)(255U).equal("ff"));
5860 assert(toChars!(16, char, LetterCase.upper)(255U).equal("FF"));
5864 @safe unittest
5866 import std.array;
5867 import std.range;
5869 assert(toChars(123) == toChars(123));
5872 assert(toChars!2(ubyte(0)).array == "0");
5873 assert(toChars!2(ushort(0)).array == "0");
5874 assert(toChars!2(0u).array == "0");
5875 assert(toChars!2(0Lu).array == "0");
5876 assert(toChars!2(ubyte(1)).array == "1");
5877 assert(toChars!2(ushort(1)).array == "1");
5878 assert(toChars!2(1u).array == "1");
5879 assert(toChars!2(1Lu).array == "1");
5881 auto r = toChars!2(2u);
5882 assert(r.length == 2);
5883 assert(r[0] == '1');
5884 assert(r[1 .. 2].array == "0");
5885 auto s = r.save;
5886 assert(r.array == "10");
5887 assert(s.retro.array == "01");
5890 assert(toChars!8(ubyte(0)).array == "0");
5891 assert(toChars!8(ushort(0)).array == "0");
5892 assert(toChars!8(0u).array == "0");
5893 assert(toChars!8(0Lu).array == "0");
5894 assert(toChars!8(1u).array == "1");
5895 assert(toChars!8(1234567Lu).array == "4553207");
5896 assert(toChars!8(ubyte.max).array == "377");
5897 assert(toChars!8(ushort.max).array == "177777");
5899 auto r = toChars!8(8u);
5900 assert(r.length == 2);
5901 assert(r[0] == '1');
5902 assert(r[1 .. 2].array == "0");
5903 auto s = r.save;
5904 assert(r.array == "10");
5905 assert(s.retro.array == "01");
5908 assert(toChars!10(ubyte(0)).array == "0");
5909 assert(toChars!10(ushort(0)).array == "0");
5910 assert(toChars!10(0u).array == "0");
5911 assert(toChars!10(0Lu).array == "0");
5912 assert(toChars!10(1u).array == "1");
5913 assert(toChars!10(1234567Lu).array == "1234567");
5914 assert(toChars!10(ubyte.max).array == "255");
5915 assert(toChars!10(ushort.max).array == "65535");
5916 assert(toChars!10(uint.max).array == "4294967295");
5917 assert(toChars!10(ulong.max).array == "18446744073709551615");
5919 auto r = toChars(10u);
5920 assert(r.length == 2);
5921 assert(r[0] == '1');
5922 assert(r[1 .. 2].array == "0");
5923 auto s = r.save;
5924 assert(r.array == "10");
5925 assert(s.retro.array == "01");
5928 assert(toChars!10(0).array == "0");
5929 assert(toChars!10(0L).array == "0");
5930 assert(toChars!10(1).array == "1");
5931 assert(toChars!10(1234567L).array == "1234567");
5932 assert(toChars!10(byte.max).array == "127");
5933 assert(toChars!10(short.max).array == "32767");
5934 assert(toChars!10(int.max).array == "2147483647");
5935 assert(toChars!10(long.max).array == "9223372036854775807");
5936 assert(toChars!10(-byte.max).array == "-127");
5937 assert(toChars!10(-short.max).array == "-32767");
5938 assert(toChars!10(-int.max).array == "-2147483647");
5939 assert(toChars!10(-long.max).array == "-9223372036854775807");
5940 assert(toChars!10(byte.min).array == "-128");
5941 assert(toChars!10(short.min).array == "-32768");
5942 assert(toChars!10(int.min).array == "-2147483648");
5943 assert(toChars!10(long.min).array == "-9223372036854775808");
5945 auto r = toChars!10(10);
5946 assert(r.length == 2);
5947 assert(r[0] == '1');
5948 assert(r[1 .. 2].array == "0");
5949 auto s = r.save;
5950 assert(r.array == "10");
5951 assert(s.retro.array == "01");
5954 assert(toChars!(16)(0u).array == "0");
5955 assert(toChars!(16)(0Lu).array == "0");
5956 assert(toChars!(16)(10u).array == "a");
5957 assert(toChars!(16, char, LetterCase.upper)(0x12AF34567Lu).array == "12AF34567");
5958 assert(toChars!(16)(ubyte(0)).array == "0");
5959 assert(toChars!(16)(ushort(0)).array == "0");
5960 assert(toChars!(16)(ubyte.max).array == "ff");
5961 assert(toChars!(16)(ushort.max).array == "ffff");
5963 auto r = toChars!(16)(16u);
5964 assert(r.length == 2);
5965 assert(r[0] == '1');
5966 assert(r[1 .. 2].array == "0");
5967 auto s = r.save;
5968 assert(r.array == "10");
5969 assert(s.retro.array == "01");
5973 @safe unittest // opSlice (https://issues.dlang.org/show_bug.cgi?id=16192)
5975 import std.meta : AliasSeq;
5977 static struct Test { ubyte radix; uint number; }
5979 alias tests = AliasSeq!(
5980 Test(2, 0b1_0110_0111u),
5981 Test(2, 0b10_1100_1110u),
5982 Test(8, octal!123456701u),
5983 Test(8, octal!1234567012u),
5984 Test(10, 123456789u),
5985 Test(10, 1234567890u),
5986 Test(16, 0x789ABCDu),
5987 Test(16, 0x789ABCDEu),
5990 foreach (test; tests)
5992 enum ubyte radix = test.radix;
5993 auto original = toChars!radix(test.number);
5995 // opSlice vs popFront
5996 auto r = original.save;
5997 size_t i = 0;
5998 for (; !r.empty; r.popFront(), ++i)
6000 assert(original[i .. original.length].tupleof == r.tupleof);
6001 // tupleof is used to work around https://issues.dlang.org/show_bug.cgi?id=16216.
6004 // opSlice vs popBack
6005 r = original.save;
6006 i = 0;
6007 for (; !r.empty; r.popBack(), ++i)
6009 assert(original[0 .. original.length - i].tupleof == r.tupleof);
6012 // opSlice vs both popFront and popBack
6013 r = original.save;
6014 i = 0;
6015 for (; r.length >= 2; r.popFront(), r.popBack(), ++i)
6017 assert(original[i .. original.length - i].tupleof == r.tupleof);
6022 // Converts an unsigned integer to a compile-time string constant.
6023 package enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
6025 // Check that .stringof does what we expect, since it's not guaranteed by the
6026 // language spec.
6027 @safe /*@betterC*/ unittest
6029 assert(toCtString!0 == "0");
6030 assert(toCtString!123456 == "123456");