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