1// Written in the D programming language. 2 3/** 4A one-stop shop for converting values from one type to another. 5 6$(SCRIPT inhibitQuickIndex = 1;) 7$(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 35Copyright: Copyright Digital Mars 2007-. 36 37License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 38 39Authors: $(HTTP digitalmars.com, Walter Bright), 40 $(HTTP erdani.org, Andrei Alexandrescu), 41 Shin Fujishiro, 42 Adam D. Ruppe, 43 Kenji Hara 44 45Source: $(PHOBOSSRC std/_conv.d) 46 47*/ 48module std.conv; 49 50public import std.ascii : LetterCase; 51 52import std.meta; 53import std.range.primitives; 54import 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. 59package template convFormat() 60{ 61 import std.format : format; 62 alias convFormat = format; 63} 64 65/* ************* Exceptions *************** */ 66 67/** 68 * Thrown on conversion errors. 69 */ 70class ConvException : Exception 71{ 72 import std.exception : basicExceptionCtors; 73 /// 74 mixin basicExceptionCtors; 75} 76 77private 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 97private 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 113private 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 118private 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 127private 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 */ 169class 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/** 179The `to` template converts a value from one type _to another. 180The source type is deduced and the target type must be specified, for example the 181expression `to!int(42.0)` converts the number 42 from 182`double` _to `int`. The conversion is "safe", i.e., 183it checks for overflow; `to!int(4.2e10)` would throw the 184`ConvOverflowException` exception. Overflow checks are only 185inserted when necessary, e.g., `to!double(42)` does not do 186any checking because any `int` fits in a `double`. 187 188Conversions from string _to numeric types differ from the C equivalents 189`atoi()` and `atol()` by checking for overflow and not allowing whitespace. 190 191For 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 198For conversion _to unsigned types, the grammar recognized is: 199$(PRE $(I UnsignedInteger): 200 $(I DecimalDigit) 201 $(I DecimalDigit) $(I UnsignedInteger)) 202 */ 203template 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/** 453If the source type is implicitly convertible to the target type, $(D 454to) simply performs the implicit conversion. 455 */ 456private T toImpl(T, S)(S value) 457if (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 */ 570private T toImpl(T, S)(ref S s) 571if (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/** 584When source type supports member template function opCast, it is used. 585*/ 586private T toImpl(T, S)(S value) 587if (!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/** 633When 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*/ 637private T toImpl(T, S)(S value) 638if (!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 686private T toImpl(T, S)(S value) 687if (!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/** 756Object-to-object conversions by dynamic casting throw exception when the source is 757non-null and the target is null. 758 */ 759private T toImpl(T, S)(S value) 760if (!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/** 878Handles type _to string conversions 879*/ 880private T toImpl(T, S)(S value) 881if (!(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 */ 1024private T toImpl(T, S)(ref S value) 1025if (!(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*/ 1070private 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). 1088private template enumRep(T, S, S value) 1089if (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) 1321if (isIntegral!S && 1322 isExactSomeString!T) 1323in 1324{ 1325 assert(radix >= 2 && radix <= 36); 1326} 1327body 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/** 1397Narrowing numeric-numeric conversions throw when the value does not 1398fit in the narrower type. 1399 */ 1400private T toImpl(T, S)(S value) 1401if (!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/** 1490Array-to-array conversion (except when target is a string type) 1491converts each element in turn by using $(D to). 1492 */ 1493private T toImpl(T, S)(S value) 1494if (!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/** 1572Associative array to associative array conversion converts each key 1573and each value in turn. 1574 */ 1575private T toImpl(T, S)(S value) 1576if (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 1622private 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 1630private 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/** 1802String, 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*/ 1808private T toImpl(T, S)(S value) 1809if (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 1823private T toImpl(T, S)(S value, uint radix) 1824if (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/** 1877Convert a value that is implicitly convertible to the enum base type 1878into an Enum value. If the value does not match any enum member values 1879a ConvException is thrown. 1880Enums with floating-point or string base types are not supported. 1881*/ 1882private T toImpl(T, S)(S value) 1883if (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 1912Rounded conversions do not work with non-integral target types. 1913 */ 1914 1915template 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/** 1955The $(D parse) family of functions works quite like the $(D to) 1956family, 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 1964This overload converts an character input range to a `bool`. 1965 1966Params: 1967 Target = the type to convert to 1968 source = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 1969 1970Returns: 1971 A `bool` 1972 1973Throws: 1974 A $(LREF ConvException) if the range does not represent a `bool`. 1975 1976Note: 1977 All character input range conversions using $(LREF to) are forwarded 1978 to `parse` and do not require lvalues. 1979*/ 1980Target parse(Target, Source)(ref Source source) 1981if (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 } 2017Lerr: 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/** 2063Parses a character $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 2064to an integral value. 2065 2066Params: 2067 Target = the integral type to convert to 2068 s = the lvalue of an input range 2069 2070Returns: 2071 A number of type `Target` 2072 2073Throws: 2074 A $(LREF ConvException) If an overflow occurred during conversion or 2075 if no character of the input was meaningfully converted. 2076*/ 2077Target parse(Target, Source)(ref Source s) 2078if (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 } 2173Lerr: 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 2440Target parse(Target, Source)(ref Source source, uint radix) 2441if (isSomeChar!(ElementType!Source) && 2442 isIntegral!Target && !is(Target == enum)) 2443in 2444{ 2445 assert(radix >= 2 && radix <= 36); 2446} 2447body 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 */ 2560Target parse(Target, Source)(ref Source s) 2561if (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 */ 2643Target parse(Target, Source)(ref Source source) 2644if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) && 2645 isFloatingPoint!Target && !is(Target == enum)) 2646{ 2647 import std.ascii : isDigit, isAlpha, toLower, toUpper, isHexDigit; 2648 import std.exception : enforce; 2649 2650 static if (isNarrowString!Source) 2651 { 2652 import std.string : representation; 2653 auto p = source.representation; 2654 } 2655 else 2656 { 2657 alias p = source; 2658 } 2659 2660 static immutable real[14] negtab = 2661 [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L, 2662 1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ]; 2663 static immutable real[13] postab = 2664 [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L, 2665 1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ]; 2666 2667 ConvException bailOut()(string msg = null, string fn = __FILE__, size_t ln = __LINE__) 2668 { 2669 if (msg == null) 2670 msg = "Floating point conversion error"; 2671 return new ConvException(text(msg, " for input \"", source, "\"."), fn, ln); 2672 } 2673 2674 2675 enforce(!p.empty, bailOut()); 2676 2677 bool sign = false; 2678 switch (p.front) 2679 { 2680 case '-': 2681 sign = true; 2682 p.popFront(); 2683 enforce(!p.empty, bailOut()); 2684 if (toLower(p.front) == 'i') 2685 goto case 'i'; 2686 break; 2687 case '+': 2688 p.popFront(); 2689 enforce(!p.empty, bailOut()); 2690 break; 2691 case 'i': case 'I': 2692 // inf 2693 p.popFront(); 2694 enforce(!p.empty && toUpper(p.front) == 'N', 2695 bailOut("error converting input to floating point")); 2696 p.popFront(); 2697 enforce(!p.empty && toUpper(p.front) == 'F', 2698 bailOut("error converting input to floating point")); 2699 // skip past the last 'f' 2700 p.popFront(); 2701 static if (isNarrowString!Source) 2702 source = cast(Source) p; 2703 return sign ? -Target.infinity : Target.infinity; 2704 default: {} 2705 } 2706 2707 bool isHex = false; 2708 bool startsWithZero = p.front == '0'; 2709 if (startsWithZero) 2710 { 2711 p.popFront(); 2712 if (p.empty) 2713 { 2714 static if (isNarrowString!Source) 2715 source = cast(Source) p; 2716 return sign ? -0.0 : 0.0; 2717 } 2718 2719 isHex = p.front == 'x' || p.front == 'X'; 2720 if (isHex) p.popFront(); 2721 } 2722 else if (toLower(p.front) == 'n') 2723 { 2724 // nan 2725 p.popFront(); 2726 enforce(!p.empty && toUpper(p.front) == 'A', 2727 bailOut("error converting input to floating point")); 2728 p.popFront(); 2729 enforce(!p.empty && toUpper(p.front) == 'N', 2730 bailOut("error converting input to floating point")); 2731 // skip past the last 'n' 2732 p.popFront(); 2733 static if (isNarrowString!Source) 2734 source = cast(Source) p; 2735 return typeof(return).nan; 2736 } 2737 2738 /* 2739 * The following algorithm consists of 2 steps: 2740 * 1) parseDigits processes the textual input into msdec and possibly 2741 * lsdec/msscale variables, followed by the exponent parser which sets 2742 * exp below. 2743 * Hex: input is 0xaaaaa...p+000... where aaaa is the mantissa in hex 2744 * and 000 is the exponent in decimal format with base 2. 2745 * Decimal: input is 0.00333...p+000... where 0.0033 is the mantissa 2746 * in decimal and 000 is the exponent in decimal format with base 10. 2747 * 2) Convert msdec/lsdec and exp into native real format 2748 */ 2749 2750 real ldval = 0.0; 2751 char dot = 0; /* if decimal point has been seen */ 2752 int exp = 0; 2753 ulong msdec = 0, lsdec = 0; 2754 ulong msscale = 1; 2755 bool sawDigits; 2756 2757 enum { hex, decimal } 2758 2759 // sets msdec, lsdec/msscale, and sawDigits by parsing the mantissa digits 2760 void parseDigits(alias FloatFormat)() 2761 { 2762 static if (FloatFormat == hex) 2763 { 2764 enum uint base = 16; 2765 enum ulong msscaleMax = 0x1000_0000_0000_0000UL; // largest power of 16 a ulong holds 2766 enum ubyte expIter = 4; // iterate the base-2 exponent by 4 for every hex digit 2767 alias checkDigit = isHexDigit; 2768 /* 2769 * convert letter to binary representation: First clear bit 2770 * to convert lower space chars to upperspace, then -('A'-10) 2771 * converts letter A to 10, letter B to 11, ... 2772 */ 2773 alias convertDigit = (int x) => isAlpha(x) ? ((x & ~0x20) - ('A' - 10)) : x - '0'; 2774 sawDigits = false; 2775 } 2776 else static if (FloatFormat == decimal) 2777 { 2778 enum uint base = 10; 2779 enum ulong msscaleMax = 10_000_000_000_000_000_000UL; // largest power of 10 a ulong holds 2780 enum ubyte expIter = 1; // iterate the base-10 exponent once for every decimal digit 2781 alias checkDigit = isDigit; 2782 alias convertDigit = (int x) => x - '0'; 2783 // Used to enforce that any mantissa digits are present 2784 sawDigits = startsWithZero; 2785 } 2786 else 2787 static assert(false, "Unrecognized floating-point format used."); 2788 2789 while (!p.empty) 2790 { 2791 int i = p.front; 2792 while (checkDigit(i)) 2793 { 2794 sawDigits = true; /* must have at least 1 digit */ 2795 2796 i = convertDigit(i); 2797 2798 if (msdec < (ulong.max - base)/base) 2799 { 2800 // For base 16: Y = ... + y3*16^3 + y2*16^2 + y1*16^1 + y0*16^0 2801 msdec = msdec * base + i; 2802 } 2803 else if (msscale < msscaleMax) 2804 { 2805 lsdec = lsdec * base + i; 2806 msscale *= base; 2807 } 2808 else 2809 { 2810 exp += expIter; 2811 } 2812 exp -= dot; 2813 p.popFront(); 2814 if (p.empty) 2815 break; 2816 i = p.front; 2817 if (i == '_') 2818 { 2819 p.popFront(); 2820 if (p.empty) 2821 break; 2822 i = p.front; 2823 } 2824 } 2825 if (i == '.' && !dot) 2826 { 2827 p.popFront(); 2828 dot += expIter; 2829 } 2830 else 2831 break; 2832 } 2833 2834 // Have we seen any mantissa digits so far? 2835 enforce(sawDigits, bailOut("no digits seen")); 2836 static if (FloatFormat == hex) 2837 enforce(!p.empty && (p.front == 'p' || p.front == 'P'), 2838 bailOut("Floating point parsing: exponent is required")); 2839 } 2840 2841 if (isHex) 2842 parseDigits!hex; 2843 else 2844 parseDigits!decimal; 2845 2846 if (isHex || (!p.empty && (p.front == 'e' || p.front == 'E'))) 2847 { 2848 char sexp = 0; 2849 int e = 0; 2850 2851 p.popFront(); 2852 enforce(!p.empty, new ConvException("Unexpected end of input")); 2853 switch (p.front) 2854 { 2855 case '-': sexp++; 2856 goto case; 2857 case '+': p.popFront(); 2858 break; 2859 default: {} 2860 } 2861 sawDigits = false; 2862 while (!p.empty && isDigit(p.front)) 2863 { 2864 if (e < 0x7FFFFFFF / 10 - 10) // prevent integer overflow 2865 { 2866 e = e * 10 + p.front - '0'; 2867 } 2868 p.popFront(); 2869 sawDigits = true; 2870 } 2871 exp += (sexp) ? -e : e; 2872 enforce(sawDigits, new ConvException("No digits seen.")); 2873 } 2874 2875 ldval = msdec; 2876 if (msscale != 1) /* if stuff was accumulated in lsdec */ 2877 ldval = ldval * msscale + lsdec; 2878 if (isHex) 2879 { 2880 import std.math : ldexp; 2881 2882 // Exponent is power of 2, not power of 10 2883 ldval = ldexp(ldval,exp); 2884 } 2885 else if (ldval) 2886 { 2887 uint u = 0; 2888 int pow = 4096; 2889 2890 while (exp > 0) 2891 { 2892 while (exp >= pow) 2893 { 2894 ldval *= postab[u]; 2895 exp -= pow; 2896 } 2897 pow >>= 1; 2898 u++; 2899 } 2900 while (exp < 0) 2901 { 2902 while (exp <= -pow) 2903 { 2904 ldval *= negtab[u]; 2905 enforce(ldval != 0, new ConvException("Range error")); 2906 exp += pow; 2907 } 2908 pow >>= 1; 2909 u++; 2910 } 2911 } 2912 2913 // if overflow occurred 2914 enforce(ldval != real.infinity, new ConvException("Range error")); 2915 2916 static if (isNarrowString!Source) 2917 source = cast(Source) p; 2918 return sign ? -ldval : ldval; 2919} 2920 2921/// 2922@safe unittest 2923{ 2924 import std.math : approxEqual; 2925 auto str = "123.456"; 2926 2927 assert(parse!double(str).approxEqual(123.456)); 2928} 2929 2930@safe unittest 2931{ 2932 import std.exception; 2933 import std.math : isNaN, fabs; 2934 2935 // Compare reals with given precision 2936 bool feq(in real rx, in real ry, in real precision = 0.000001L) 2937 { 2938 if (rx == ry) 2939 return 1; 2940 2941 if (isNaN(rx)) 2942 return cast(bool) isNaN(ry); 2943 2944 if (isNaN(ry)) 2945 return 0; 2946 2947 return cast(bool)(fabs(rx - ry) <= precision); 2948 } 2949 2950 // Make given typed literal 2951 F Literal(F)(F f) 2952 { 2953 return f; 2954 } 2955 2956 foreach (Float; AliasSeq!(float, double, real)) 2957 { 2958 assert(to!Float("123") == Literal!Float(123)); 2959 assert(to!Float("+123") == Literal!Float(+123)); 2960 assert(to!Float("-123") == Literal!Float(-123)); 2961 assert(to!Float("123e2") == Literal!Float(123e2)); 2962 assert(to!Float("123e+2") == Literal!Float(123e+2)); 2963 assert(to!Float("123e-2") == Literal!Float(123e-2)); 2964 assert(to!Float("123.") == Literal!Float(123.0)); 2965 assert(to!Float(".375") == Literal!Float(.375)); 2966 2967 assert(to!Float("1.23375E+2") == Literal!Float(1.23375E+2)); 2968 2969 assert(to!Float("0") is 0.0); 2970 assert(to!Float("-0") is -0.0); 2971 2972 assert(isNaN(to!Float("nan"))); 2973 2974 assertThrown!ConvException(to!Float("\x00")); 2975 } 2976 2977 // min and max 2978 float f = to!float("1.17549e-38"); 2979 assert(feq(cast(real) f, cast(real) 1.17549e-38)); 2980 assert(feq(cast(real) f, cast(real) float.min_normal)); 2981 f = to!float("3.40282e+38"); 2982 assert(to!string(f) == to!string(3.40282e+38)); 2983 2984 // min and max 2985 double d = to!double("2.22508e-308"); 2986 assert(feq(cast(real) d, cast(real) 2.22508e-308)); 2987 assert(feq(cast(real) d, cast(real) double.min_normal)); 2988 d = to!double("1.79769e+308"); 2989 assert(to!string(d) == to!string(1.79769e+308)); 2990 assert(to!string(d) == to!string(double.max)); 2991 2992 assert(to!string(to!real(to!string(real.max / 2L))) == to!string(real.max / 2L)); 2993 2994 // min and max 2995 real r = to!real(to!string(real.min_normal)); 2996 version (NetBSD) 2997 { 2998 // NetBSD notice 2999 // to!string returns 3.3621e-4932L. It is less than real.min_normal and it is subnormal value 3000 // Simple C code 3001 // long double rd = 3.3621e-4932L; 3002 // printf("%Le\n", rd); 3003 // has unexpected result: 1.681050e-4932 3004 // 3005 // Bug report: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50937 3006 } 3007 else 3008 { 3009 assert(to!string(r) == to!string(real.min_normal)); 3010 } 3011 r = to!real(to!string(real.max)); 3012 assert(to!string(r) == to!string(real.max)); 3013} 3014 3015// Tests for the double implementation 3016@system unittest 3017{ 3018 // @system because strtod is not @safe. 3019 static if (real.mant_dig == 53) 3020 { 3021 import core.stdc.stdlib, std.exception, std.math; 3022 3023 //Should be parsed exactly: 53 bit mantissa 3024 string s = "0x1A_BCDE_F012_3456p10"; 3025 auto x = parse!real(s); 3026 assert(x == 0x1A_BCDE_F012_3456p10L); 3027 //1 bit is implicit 3028 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0xA_BCDE_F012_3456); 3029 assert(strtod("0x1ABCDEF0123456p10", null) == x); 3030 3031 //Should be parsed exactly: 10 bit mantissa 3032 s = "0x3FFp10"; 3033 x = parse!real(s); 3034 assert(x == 0x03FFp10); 3035 //1 bit is implicit 3036 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_F800_0000_0000); 3037 assert(strtod("0x3FFp10", null) == x); 3038 3039 //60 bit mantissa, round up 3040 s = "0xFFF_FFFF_FFFF_FFFFp10"; 3041 x = parse!real(s); 3042 assert(approxEqual(x, 0xFFF_FFFF_FFFF_FFFFp10)); 3043 //1 bit is implicit 3044 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x0000_0000_0000_0000); 3045 assert(strtod("0xFFFFFFFFFFFFFFFp10", null) == x); 3046 3047 //60 bit mantissa, round down 3048 s = "0xFFF_FFFF_FFFF_FF90p10"; 3049 x = parse!real(s); 3050 assert(approxEqual(x, 0xFFF_FFFF_FFFF_FF90p10)); 3051 //1 bit is implicit 3052 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_FFFF_FFFF_FFFF); 3053 assert(strtod("0xFFFFFFFFFFFFF90p10", null) == x); 3054 3055 //61 bit mantissa, round up 2 3056 s = "0x1F0F_FFFF_FFFF_FFFFp10"; 3057 x = parse!real(s); 3058 assert(approxEqual(x, 0x1F0F_FFFF_FFFF_FFFFp10)); 3059 //1 bit is implicit 3060 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_1000_0000_0000); 3061 assert(strtod("0x1F0FFFFFFFFFFFFFp10", null) == x); 3062 3063 //61 bit mantissa, round down 2 3064 s = "0x1F0F_FFFF_FFFF_FF10p10"; 3065 x = parse!real(s); 3066 assert(approxEqual(x, 0x1F0F_FFFF_FFFF_FF10p10)); 3067 //1 bit is implicit 3068 assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_0FFF_FFFF_FFFF); 3069 assert(strtod("0x1F0FFFFFFFFFFF10p10", null) == x); 3070 3071 //Huge exponent 3072 s = "0x1F_FFFF_FFFF_FFFFp900"; 3073 x = parse!real(s); 3074 assert(strtod("0x1FFFFFFFFFFFFFp900", null) == x); 3075 3076 //exponent too big -> converror 3077 s = ""; 3078 assertThrown!ConvException(x = parse!real(s)); 3079 assert(strtod("0x1FFFFFFFFFFFFFp1024", null) == real.infinity); 3080 3081 //-exponent too big -> 0 3082 s = "0x1FFFFFFFFFFFFFp-2000"; 3083 x = parse!real(s); 3084 assert(x == 0); 3085 assert(strtod("0x1FFFFFFFFFFFFFp-2000", null) == x); 3086 } 3087} 3088 3089@system unittest 3090{ 3091 import core.stdc.errno; 3092 import core.stdc.stdlib; 3093 import std.math : floatTraits, RealFormat; 3094 3095 errno = 0; // In case it was set by another unittest in a different module. 3096 struct longdouble 3097 { 3098 static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple) 3099 { 3100 ushort[8] value; 3101 } 3102 else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended) 3103 { 3104 ushort[5] value; 3105 } 3106 else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble) 3107 { 3108 ushort[4] value; 3109 } 3110 else 3111 static assert(false, "Not implemented"); 3112 } 3113 3114 real ld; 3115 longdouble x; 3116 real ld1; 3117 longdouble x1; 3118 int i; 3119 3120 static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple) 3121 // Our parser is currently limited to ieeeExtended precision 3122 enum s = "0x1.FFFFFFFFFFFFFFFEp-16382"; 3123 else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended) 3124 enum s = "0x1.FFFFFFFFFFFFFFFEp-16382"; 3125 else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble) 3126 enum s = "0x1.FFFFFFFFFFFFFFFEp-1000"; 3127 else 3128 static assert(false, "Floating point format for real not supported"); 3129 3130 auto s2 = s.idup; 3131 ld = parse!real(s2); 3132 assert(s2.empty); 3133 x = *cast(longdouble *)&ld; 3134 3135 static if (floatTraits!real.realFormat == RealFormat.ieeeExtended) 3136 { 3137 version (CRuntime_Microsoft) 3138 ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod 3139 else version (CRuntime_Bionic) 3140 ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod 3141 else 3142 ld1 = strtold(s.ptr, null); 3143 } 3144 else 3145 ld1 = strtold(s.ptr, null); 3146 3147 x1 = *cast(longdouble *)&ld1; 3148 assert(x1 == x && ld1 == ld); 3149 3150 assert(!errno); 3151 3152 s2 = "1.0e5"; 3153 ld = parse!real(s2); 3154 assert(s2.empty); 3155 x = *cast(longdouble *)&ld; 3156 ld1 = strtold("1.0e5", null); 3157 x1 = *cast(longdouble *)&ld1; 3158} 3159 3160@safe pure unittest 3161{ 3162 import std.exception; 3163 3164 // Bugzilla 4959 3165 { 3166 auto s = "0 "; 3167 auto x = parse!double(s); 3168 assert(s == " "); 3169 assert(x == 0.0); 3170 } 3171 3172 // Bugzilla 3369 3173 assert(to!float("inf") == float.infinity); 3174 assert(to!float("-inf") == -float.infinity); 3175 3176 // Bugzilla 6160 3177 assert(6_5.536e3L == to!real("6_5.536e3")); // 2^16 3178 assert(0x1000_000_000_p10 == to!real("0x1000_000_000_p10")); // 7.03687e+13 3179 3180 // Bugzilla 6258 3181 assertThrown!ConvException(to!real("-")); 3182 assertThrown!ConvException(to!real("in")); 3183 3184 // Bugzilla 7055 3185 assertThrown!ConvException(to!float("INF2")); 3186 3187 //extra stress testing 3188 auto ssOK = ["1.", "1.1.1", "1.e5", "2e1e", "2a", "2e1_1", 3189 "inf", "-inf", "infa", "-infa", "inf2e2", "-inf2e2"]; 3190 auto ssKO = ["", " ", "2e", "2e+", "2e-", "2ee", "2e++1", "2e--1", "2e_1", "+inf"]; 3191 foreach (s; ssOK) 3192 parse!double(s); 3193 foreach (s; ssKO) 3194 assertThrown!ConvException(parse!double(s)); 3195} 3196 3197/** 3198Parsing one character off a range returns the first element and calls `popFront`. 3199 3200Params: 3201 Target = the type to convert to 3202 s = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 3203 3204Returns: 3205 A character of type `Target` 3206 3207Throws: 3208 A $(LREF ConvException) if the range is empty. 3209 */ 3210Target parse(Target, Source)(ref Source s) 3211if (isSomeString!Source && !is(Source == enum) && 3212 staticIndexOf!(Unqual!Target, dchar, Unqual!(ElementEncodingType!Source)) >= 0) 3213{ 3214 if (s.empty) 3215 throw convError!(Source, Target)(s); 3216 static if (is(Unqual!Target == dchar)) 3217 { 3218 Target result = s.front; 3219 s.popFront(); 3220 return result; 3221 } 3222 else 3223 { 3224 // Special case: okay so parse a Char off a Char[] 3225 Target result = s[0]; 3226 s = s[1 .. $]; 3227 return result; 3228 } 3229} 3230 3231@safe pure unittest 3232{ 3233 foreach (Str; AliasSeq!(string, wstring, dstring)) 3234 { 3235 foreach (Char; AliasSeq!(char, wchar, dchar)) 3236 { 3237 static if (is(Unqual!Char == dchar) || 3238 Char.sizeof == ElementEncodingType!Str.sizeof) 3239 { 3240 Str s = "aaa"; 3241 assert(parse!Char(s) == 'a'); 3242 assert(s == "aa"); 3243 } 3244 } 3245 } 3246} 3247 3248/// ditto 3249Target parse(Target, Source)(ref Source s) 3250if (!isSomeString!Source && isInputRange!Source && isSomeChar!(ElementType!Source) && 3251 isSomeChar!Target && Target.sizeof >= ElementType!Source.sizeof && !is(Target == enum)) 3252{ 3253 if (s.empty) 3254 throw convError!(Source, Target)(s); 3255 Target result = s.front; 3256 s.popFront(); 3257 return result; 3258} 3259 3260/// 3261@safe pure unittest 3262{ 3263 auto s = "Hello, World!"; 3264 char first = parse!char(s); 3265 assert(first == 'H'); 3266 assert(s == "ello, World!"); 3267} 3268 3269 3270/* 3271 Tests for to!bool and parse!bool 3272*/ 3273@safe pure unittest 3274{ 3275 import std.exception; 3276 3277 assert(to!bool("TruE") == true); 3278 assert(to!bool("faLse"d) == false); 3279 assertThrown!ConvException(to!bool("maybe")); 3280 3281 auto t = "TrueType"; 3282 assert(parse!bool(t) == true); 3283 assert(t == "Type"); 3284 3285 auto f = "False killer whale"d; 3286 assert(parse!bool(f) == false); 3287 assert(f == " killer whale"d); 3288 3289 auto m = "maybe"; 3290 assertThrown!ConvException(parse!bool(m)); 3291 assert(m == "maybe"); // m shouldn't change on failure 3292 3293 auto s = "true"; 3294 auto b = parse!(const(bool))(s); 3295 assert(b == true); 3296} 3297 3298/** 3299Parsing a character range to `typeof(null)` returns `null` if the range 3300spells `"null"`. This function is case insensitive. 3301 3302Params: 3303 Target = the type to convert to 3304 s = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives) 3305 3306Returns: 3307 `null` 3308 3309Throws: 3310 A $(LREF ConvException) if the range doesn't represent `null`. 3311 */ 3312Target parse(Target, Source)(ref Source s) 3313if (isInputRange!Source && 3314 isSomeChar!(ElementType!Source) && 3315 is(Unqual!Target == typeof(null))) 3316{ 3317 import std.ascii : toLower; 3318 foreach (c; "null") 3319 { 3320 if (s.empty || toLower(s.front) != c) 3321 throw parseError("null should be case-insensitive 'null'"); 3322 s.popFront(); 3323 } 3324 return null; 3325} 3326 3327/// 3328@safe pure unittest 3329{ 3330 import std.exception : assertThrown; 3331 3332 alias NullType = typeof(null); 3333 auto s1 = "null"; 3334 assert(parse!NullType(s1) is null); 3335 assert(s1 == ""); 3336 3337 auto s2 = "NUll"d; 3338 assert(parse!NullType(s2) is null); 3339 assert(s2 == ""); 3340 3341 auto m = "maybe"; 3342 assertThrown!ConvException(parse!NullType(m)); 3343 assert(m == "maybe"); // m shouldn't change on failure 3344 3345 auto s = "NULL"; 3346 assert(parse!(const NullType)(s) is null); 3347} 3348 3349//Used internally by parse Array/AA, to remove ascii whites 3350package void skipWS(R)(ref R r) 3351{ 3352 import std.ascii : isWhite; 3353 static if (isSomeString!R) 3354 { 3355 //Implementation inspired from stripLeft. 3356 foreach (i, c; r) 3357 { 3358 if (!isWhite(c)) 3359 { 3360 r = r[i .. $]; 3361 return; 3362 } 3363 } 3364 r = r[0 .. 0]; //Empty string with correct type. 3365 return; 3366 } 3367 else 3368 { 3369 for (; !r.empty && isWhite(r.front); r.popFront()) 3370 {} 3371 } 3372} 3373 3374/** 3375 * Parses an array from a string given the left bracket (default $(D 3376 * '[')), right bracket (default $(D ']')), and element separator (by 3377 * default $(D ',')). A trailing separator is allowed. 3378 * 3379 * Params: 3380 * s = The string to parse 3381 * lbracket = the character that starts the array 3382 * rbracket = the character that ends the array 3383 * comma = the character that separates the elements of the array 3384 * 3385 * Returns: 3386 * An array of type `Target` 3387 */ 3388Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar comma = ',') 3389if (isSomeString!Source && !is(Source == enum) && 3390 isDynamicArray!Target && !is(Target == enum)) 3391{ 3392 import std.array : appender; 3393 3394 auto result = appender!Target(); 3395 3396 parseCheck!s(lbracket); 3397 skipWS(s); 3398 if (s.empty) 3399 throw convError!(Source, Target)(s); 3400 if (s.front == rbracket) 3401 { 3402 s.popFront(); 3403 return result.data; 3404 } 3405 for (;; s.popFront(), skipWS(s)) 3406 { 3407 if (!s.empty && s.front == rbracket) 3408 break; 3409 result ~= parseElement!(ElementType!Target)(s); 3410 skipWS(s); 3411 if (s.empty) 3412 throw convError!(Source, Target)(s); 3413 if (s.front != comma) 3414 break; 3415 } 3416 parseCheck!s(rbracket); 3417 3418 return result.data; 3419} 3420 3421/// 3422@safe pure unittest 3423{ 3424 auto s1 = `[['h', 'e', 'l', 'l', 'o'], "world"]`; 3425 auto a1 = parse!(string[])(s1); 3426 assert(a1 == ["hello", "world"]); 3427 3428 auto s2 = `["aaa", "bbb", "ccc"]`; 3429 auto a2 = parse!(string[])(s2); 3430 assert(a2 == ["aaa", "bbb", "ccc"]); 3431} 3432 3433@safe unittest // Bugzilla 9615 3434{ 3435 string s0 = "[1,2, ]"; 3436 string s1 = "[1,2, \t\v\r\n]"; 3437 string s2 = "[1,2]"; 3438 assert(s0.parse!(int[]) == [1,2]); 3439 assert(s1.parse!(int[]) == [1,2]); 3440 assert(s2.parse!(int[]) == [1,2]); 3441 3442 string s3 = `["a","b",]`; 3443 string s4 = `["a","b"]`; 3444 assert(s3.parse!(string[]) == ["a","b"]); 3445 assert(s4.parse!(string[]) == ["a","b"]); 3446 3447 import std.exception : assertThrown; 3448 string s5 = "[,]"; 3449 string s6 = "[, \t,]"; 3450 assertThrown!ConvException(parse!(string[])(s5)); 3451 assertThrown!ConvException(parse!(int[])(s6)); 3452} 3453 3454@safe unittest 3455{ 3456 int[] a = [1, 2, 3, 4, 5]; 3457 auto s = to!string(a); 3458 assert(to!(int[])(s) == a); 3459} 3460 3461@safe unittest 3462{ 3463 int[][] a = [ [1, 2] , [3], [4, 5] ]; 3464 auto s = to!string(a); 3465 assert(to!(int[][])(s) == a); 3466} 3467 3468@safe unittest 3469{ 3470 int[][][] ia = [ [[1,2],[3,4],[5]] , [[6],[],[7,8,9]] , [[]] ]; 3471 3472 char[] s = to!(char[])(ia); 3473 int[][][] ia2; 3474 3475 ia2 = to!(typeof(ia2))(s); 3476 assert( ia == ia2); 3477} 3478 3479@safe pure unittest 3480{ 3481 import std.exception; 3482 3483 //Check proper failure 3484 auto s = "[ 1 , 2 , 3 ]"; 3485 foreach (i ; 0 .. s.length-1) 3486 { 3487 auto ss = s[0 .. i]; 3488 assertThrown!ConvException(parse!(int[])(ss)); 3489 } 3490 int[] arr = parse!(int[])(s); 3491} 3492 3493@safe pure unittest 3494{ 3495 //Checks parsing of strings with escaped characters 3496 string s1 = `[ 3497 "Contains a\0null!", 3498 "tab\there", 3499 "line\nbreak", 3500 "backslash \\ slash / question \?", 3501 "number \x35 five", 3502 "unicode \u65E5 sun", 3503 "very long \U000065E5 sun" 3504 ]`; 3505 3506 //Note: escaped characters purposefully replaced and isolated to guarantee 3507 //there are no typos in the escape syntax 3508 string[] s2 = [ 3509 "Contains a" ~ '\0' ~ "null!", 3510 "tab" ~ '\t' ~ "here", 3511 "line" ~ '\n' ~ "break", 3512 "backslash " ~ '\\' ~ " slash / question ?", 3513 "number 5 five", 3514 "unicode ��� sun", 3515 "very long ��� sun" 3516 ]; 3517 assert(s2 == parse!(string[])(s1)); 3518 assert(s1.empty); 3519} 3520 3521/// ditto 3522Target parse(Target, Source)(ref Source s, dchar lbracket = '[', dchar rbracket = ']', dchar comma = ',') 3523if (isExactSomeString!Source && 3524 isStaticArray!Target && !is(Target == enum)) 3525{ 3526 static if (hasIndirections!Target) 3527 Target result = Target.init[0].init; 3528 else 3529 Target result = void; 3530 3531 parseCheck!s(lbracket); 3532 skipWS(s); 3533 if (s.empty) 3534 throw convError!(Source, Target)(s); 3535 if (s.front == rbracket) 3536 { 3537 static if (result.length != 0) 3538 goto Lmanyerr; 3539 else 3540 { 3541 s.popFront(); 3542 return result; 3543 } 3544 } 3545 for (size_t i = 0; ; s.popFront(), skipWS(s)) 3546 { 3547 if (i == result.length) 3548 goto Lmanyerr; 3549 result[i++] = parseElement!(ElementType!Target)(s); 3550 skipWS(s); 3551 if (s.empty) 3552 throw convError!(Source, Target)(s); 3553 if (s.front != comma) 3554 { 3555 if (i != result.length) 3556 goto Lfewerr; 3557 break; 3558 } 3559 } 3560 parseCheck!s(rbracket); 3561 3562 return result; 3563 3564Lmanyerr: 3565 throw parseError(text("Too many elements in input, ", result.length, " elements expected.")); 3566 3567Lfewerr: 3568 throw parseError(text("Too few elements in input, ", result.length, " elements expected.")); 3569} 3570 3571@safe pure unittest 3572{ 3573 import std.exception; 3574 3575 auto s1 = "[1,2,3,4]"; 3576 auto sa1 = parse!(int[4])(s1); 3577 assert(sa1 == [1,2,3,4]); 3578 3579 auto s2 = "[[1],[2,3],[4]]"; 3580 auto sa2 = parse!(int[][3])(s2); 3581 assert(sa2 == [[1],[2,3],[4]]); 3582 3583 auto s3 = "[1,2,3]"; 3584 assertThrown!ConvException(parse!(int[4])(s3)); 3585 3586 auto s4 = "[1,2,3,4,5]"; 3587 assertThrown!ConvException(parse!(int[4])(s4)); 3588} 3589 3590/** 3591 * Parses an associative array from a string given the left bracket (default $(D 3592 * '[')), right bracket (default $(D ']')), key-value separator (default $(D 3593 * ':')), and element seprator (by default $(D ',')). 3594 * 3595 * Params: 3596 * s = the string to parse 3597 * lbracket = the character that starts the associative array 3598 * rbracket = the character that ends the associative array 3599 * keyval = the character that associates the key with the value 3600 * comma = the character that separates the elements of the associative array 3601 * 3602 * Returns: 3603 * An associative array of type `Target` 3604 */ 3605Target parse(Target, Source)(ref Source s, dchar lbracket = '[', 3606 dchar rbracket = ']', dchar keyval = ':', dchar comma = ',') 3607if (isSomeString!Source && !is(Source == enum) && 3608 isAssociativeArray!Target && !is(Target == enum)) 3609{ 3610 alias KeyType = typeof(Target.init.keys[0]); 3611 alias ValType = typeof(Target.init.values[0]); 3612 3613 Target result; 3614 3615 parseCheck!s(lbracket); 3616 skipWS(s); 3617 if (s.empty) 3618 throw convError!(Source, Target)(s); 3619 if (s.front == rbracket) 3620 { 3621 s.popFront(); 3622 return result; 3623 } 3624 for (;; s.popFront(), skipWS(s)) 3625 { 3626 auto key = parseElement!KeyType(s); 3627 skipWS(s); 3628 parseCheck!s(keyval); 3629 skipWS(s); 3630 auto val = parseElement!ValType(s); 3631 skipWS(s); 3632 result[key] = val; 3633 if (s.empty) 3634 throw convError!(Source, Target)(s); 3635 if (s.front != comma) 3636 break; 3637 } 3638 parseCheck!s(rbracket); 3639 3640 return result; 3641} 3642 3643/// 3644@safe pure unittest 3645{ 3646 auto s1 = "[1:10, 2:20, 3:30]"; 3647 auto aa1 = parse!(int[int])(s1); 3648 assert(aa1 == [1:10, 2:20, 3:30]); 3649 3650 auto s2 = `["aaa":10, "bbb":20, "ccc":30]`; 3651 auto aa2 = parse!(int[string])(s2); 3652 assert(aa2 == ["aaa":10, "bbb":20, "ccc":30]); 3653 3654 auto s3 = `["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]`; 3655 auto aa3 = parse!(int[][string])(s3); 3656 assert(aa3 == ["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]); 3657} 3658 3659@safe pure unittest 3660{ 3661 import std.exception; 3662 3663 //Check proper failure 3664 auto s = "[1:10, 2:20, 3:30]"; 3665 foreach (i ; 0 .. s.length-1) 3666 { 3667 auto ss = s[0 .. i]; 3668 assertThrown!ConvException(parse!(int[int])(ss)); 3669 } 3670 int[int] aa = parse!(int[int])(s); 3671} 3672 3673private dchar parseEscape(Source)(ref Source s) 3674if (isInputRange!Source && isSomeChar!(ElementType!Source)) 3675{ 3676 parseCheck!s('\\'); 3677 if (s.empty) 3678 throw parseError("Unterminated escape sequence"); 3679 3680 dchar getHexDigit()(ref Source s_ = s) // workaround 3681 { 3682 import std.ascii : isAlpha, isHexDigit; 3683 if (s_.empty) 3684 throw parseError("Unterminated escape sequence"); 3685 s_.popFront(); 3686 if (s_.empty) 3687 throw parseError("Unterminated escape sequence"); 3688 dchar c = s_.front; 3689 if (!isHexDigit(c)) 3690 throw parseError("Hex digit is missing"); 3691 return isAlpha(c) ? ((c & ~0x20) - ('A' - 10)) : c - '0'; 3692 } 3693 3694 dchar result; 3695 3696 switch (s.front) 3697 { 3698 case '"': result = '\"'; break; 3699 case '\'': result = '\''; break; 3700 case '0': result = '\0'; break; 3701 case '?': result = '\?'; break; 3702 case '\\': result = '\\'; break; 3703 case 'a': result = '\a'; break; 3704 case 'b': result = '\b'; break; 3705 case 'f': result = '\f'; break; 3706 case 'n': result = '\n'; break; 3707 case 'r': result = '\r'; break; 3708 case 't': result = '\t'; break; 3709 case 'v': result = '\v'; break; 3710 case 'x': 3711 result = getHexDigit() << 4; 3712 result |= getHexDigit(); 3713 break; 3714 case 'u': 3715 result = getHexDigit() << 12; 3716 result |= getHexDigit() << 8; 3717 result |= getHexDigit() << 4; 3718 result |= getHexDigit(); 3719 break; 3720 case 'U': 3721 result = getHexDigit() << 28; 3722 result |= getHexDigit() << 24; 3723 result |= getHexDigit() << 20; 3724 result |= getHexDigit() << 16; 3725 result |= getHexDigit() << 12; 3726 result |= getHexDigit() << 8; 3727 result |= getHexDigit() << 4; 3728 result |= getHexDigit(); 3729 break; 3730 default: 3731 throw parseError("Unknown escape character " ~ to!string(s.front)); 3732 } 3733 if (s.empty) 3734 throw parseError("Unterminated escape sequence"); 3735 3736 s.popFront(); 3737 3738 return result; 3739} 3740 3741@safe pure unittest 3742{ 3743 string[] s1 = [ 3744 `\"`, `\'`, `\?`, `\\`, `\a`, `\b`, `\f`, `\n`, `\r`, `\t`, `\v`, //Normal escapes 3745 //`\141`, //@@@9621@@@ Octal escapes. 3746 `\x61`, 3747 `\u65E5`, `\U00012456` 3748 //`\&`, `\"`, //@@@9621@@@ Named Character Entities. 3749 ]; 3750 3751 const(dchar)[] s2 = [ 3752 '\"', '\'', '\?', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v', //Normal escapes 3753 //'\141', //@@@9621@@@ Octal escapes. 3754 '\x61', 3755 '\u65E5', '\U00012456' 3756 //'\&', '\"', //@@@9621@@@ Named Character Entities. 3757 ]; 3758 3759 foreach (i ; 0 .. s1.length) 3760 { 3761 assert(s2[i] == parseEscape(s1[i])); 3762 assert(s1[i].empty); 3763 } 3764} 3765 3766@safe pure unittest 3767{ 3768 import std.exception; 3769 3770 string[] ss = [ 3771 `hello!`, //Not an escape 3772 `\`, //Premature termination 3773 `\/`, //Not an escape 3774 `\gggg`, //Not an escape 3775 `\xzz`, //Not an hex 3776 `\x0`, //Premature hex end 3777 `\XB9`, //Not legal hex syntax 3778 `\u!!`, //Not a unicode hex 3779 `\777`, //Octal is larger than a byte //Note: Throws, but simply because octals are unsupported 3780 `\u123`, //Premature hex end 3781 `\U123123` //Premature hex end 3782 ]; 3783 foreach (s ; ss) 3784 assertThrown!ConvException(parseEscape(s)); 3785} 3786 3787// Undocumented 3788Target parseElement(Target, Source)(ref Source s) 3789if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) && 3790 isExactSomeString!Target) 3791{ 3792 import std.array : appender; 3793 auto result = appender!Target(); 3794 3795 // parse array of chars 3796 if (s.empty) 3797 throw convError!(Source, Target)(s); 3798 if (s.front == '[') 3799 return parse!Target(s); 3800 3801 parseCheck!s('\"'); 3802 if (s.empty) 3803 throw convError!(Source, Target)(s); 3804 if (s.front == '\"') 3805 { 3806 s.popFront(); 3807 return result.data; 3808 } 3809 while (true) 3810 { 3811 if (s.empty) 3812 throw parseError("Unterminated quoted string"); 3813 switch (s.front) 3814 { 3815 case '\"': 3816 s.popFront(); 3817 return result.data; 3818 case '\\': 3819 result.put(parseEscape(s)); 3820 break; 3821 default: 3822 result.put(s.front); 3823 s.popFront(); 3824 break; 3825 } 3826 } 3827 assert(0); 3828} 3829 3830// ditto 3831Target parseElement(Target, Source)(ref Source s) 3832if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) && 3833 isSomeChar!Target && !is(Target == enum)) 3834{ 3835 Target c; 3836 3837 parseCheck!s('\''); 3838 if (s.empty) 3839 throw convError!(Source, Target)(s); 3840 if (s.front != '\\') 3841 { 3842 c = s.front; 3843 s.popFront(); 3844 } 3845 else 3846 c = parseEscape(s); 3847 parseCheck!s('\''); 3848 3849 return c; 3850} 3851 3852// ditto 3853Target parseElement(Target, Source)(ref Source s) 3854if (isInputRange!Source && isSomeChar!(ElementType!Source) && 3855 !isSomeString!Target && !isSomeChar!Target) 3856{ 3857 return parse!Target(s); 3858} 3859 3860 3861/*************************************************************** 3862 * Convenience functions for converting one or more arguments 3863 * of any type into _text (the three character widths). 3864 */ 3865string text(T...)(T args) 3866if (T.length > 0) { return textImpl!string(args); } 3867 3868///ditto 3869wstring wtext(T...)(T args) 3870if (T.length > 0) { return textImpl!wstring(args); } 3871 3872///ditto 3873dstring dtext(T...)(T args) 3874if (T.length > 0) { return textImpl!dstring(args); } 3875 3876/// 3877@safe unittest 3878{ 3879 assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c); 3880 assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w); 3881 assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d); 3882} 3883 3884@safe unittest 3885{ 3886 char c = 'h'; 3887 wchar w = '���'; 3888 dchar d = '���'; 3889 3890 assert( text(c, "ello", ' ', w, "��� ", d, "��� ��������� ������") == "hello ������ ������ ��������� ������"c); 3891 assert(wtext(c, "ello", ' ', w, "��� ", d, "��� ��������� ������") == "hello ������ ������ ��������� ������"w); 3892 assert(dtext(c, "ello", ' ', w, "��� ", d, "��� ��������� ������") == "hello ������ ������ ��������� ������"d); 3893 3894 string cs = "���������"; 3895 wstring ws = "������������"; 3896 dstring ds = "������������������������"; 3897 3898 assert( text(cs, ' ', ws, " ", ds) == "��������� ������������ ������������������������"c); 3899 assert(wtext(cs, ' ', ws, " ", ds) == "��������� ������������ ������������������������"w); 3900 assert(dtext(cs, ' ', ws, " ", ds) == "��������� ������������ ������������������������"d); 3901} 3902 3903private S textImpl(S, U...)(U args) 3904{ 3905 static if (U.length == 0) 3906 { 3907 return null; 3908 } 3909 else static if (U.length == 1) 3910 { 3911 return to!S(args[0]); 3912 } 3913 else 3914 { 3915 import std.array : appender; 3916 3917 auto app = appender!S(); 3918 3919 foreach (arg; args) 3920 app.put(to!S(arg)); 3921 return app.data; 3922 } 3923} 3924 3925 3926/*************************************************************** 3927The $(D octal) facility provides a means to declare a number in base 8. 3928Using $(D octal!177) or $(D octal!"177") for 127 represented in octal 3929(same as 0177 in C). 3930 3931The rules for strings are the usual for literals: If it can fit in an 3932$(D int), it is an $(D int). Otherwise, it is a $(D long). But, if the 3933user specifically asks for a $(D long) with the $(D L) suffix, always 3934give the $(D long). Give an unsigned iff it is asked for with the $(D 3935U) or $(D u) suffix. _Octals created from integers preserve the type 3936of the passed-in integral. 3937 3938See_Also: 3939 $(LREF parse) for parsing octal strings at runtime. 3940 */ 3941template octal(string num) 3942if (isOctalLiteral(num)) 3943{ 3944 static if ((octalFitsInInt!num && !literalIsLong!num) && !literalIsUnsigned!num) 3945 enum octal = octal!int(num); 3946 else static if ((!octalFitsInInt!num || literalIsLong!num) && !literalIsUnsigned!num) 3947 enum octal = octal!long(num); 3948 else static if ((octalFitsInInt!num && !literalIsLong!num) && literalIsUnsigned!num) 3949 enum octal = octal!uint(num); 3950 else static if ((!octalFitsInInt!(num) || literalIsLong!(num)) && literalIsUnsigned!(num)) 3951 enum octal = octal!ulong(num); 3952 else 3953 static assert(false); 3954} 3955 3956/// Ditto 3957template octal(alias decimalInteger) 3958if (isIntegral!(typeof(decimalInteger))) 3959{ 3960 enum octal = octal!(typeof(decimalInteger))(to!string(decimalInteger)); 3961} 3962 3963/// 3964@safe unittest 3965{ 3966 // same as 0177 3967 auto x = octal!177; 3968 // octal is a compile-time device 3969 enum y = octal!160; 3970 // Create an unsigned octal 3971 auto z = octal!"1_000_000u"; 3972} 3973 3974/* 3975 Takes a string, num, which is an octal literal, and returns its 3976 value, in the type T specified. 3977*/ 3978private T octal(T)(const string num) 3979{ 3980 assert(isOctalLiteral(num)); 3981 3982 T value = 0; 3983 3984 foreach (const char s; num) 3985 { 3986 if (s < '0' || s > '7') // we only care about digits; skip the rest 3987 // safe to skip - this is checked out in the assert so these 3988 // are just suffixes 3989 continue; 3990 3991 value *= 8; 3992 value += s - '0'; 3993 } 3994 3995 return value; 3996} 3997 3998@safe unittest 3999{ 4000 int a = octal!int("10"); 4001 assert(a == 8); 4002} 4003 4004/* 4005Take a look at int.max and int.max+1 in octal and the logic for this 4006function follows directly. 4007 */ 4008private template octalFitsInInt(string octalNum) 4009{ 4010 // note it is important to strip the literal of all 4011 // non-numbers. kill the suffix and underscores lest they mess up 4012 // the number of digits here that we depend on. 4013 enum bool octalFitsInInt = strippedOctalLiteral(octalNum).length < 11 || 4014 strippedOctalLiteral(octalNum).length == 11 && 4015 strippedOctalLiteral(octalNum)[0] == '1'; 4016} 4017 4018private string strippedOctalLiteral(string original) 4019{ 4020 string stripped = ""; 4021 foreach (c; original) 4022 if (c >= '0' && c <= '7') 4023 stripped ~= c; 4024 return stripped; 4025} 4026 4027private template literalIsLong(string num) 4028{ 4029 static if (num.length > 1) 4030 // can be xxL or xxLu according to spec 4031 enum literalIsLong = (num[$-1] == 'L' || num[$-2] == 'L'); 4032 else 4033 enum literalIsLong = false; 4034} 4035 4036private template literalIsUnsigned(string num) 4037{ 4038 static if (num.length > 1) 4039 // can be xxU or xxUL according to spec 4040 enum literalIsUnsigned = (num[$-1] == 'u' || num[$-2] == 'u') 4041 // both cases are allowed too 4042 || (num[$-1] == 'U' || num[$-2] == 'U'); 4043 else 4044 enum literalIsUnsigned = false; 4045} 4046 4047/* 4048Returns if the given string is a correctly formatted octal literal. 4049 4050The format is specified in spec/lex.html. The leading zero is allowed, but 4051not required. 4052 */ 4053@safe pure nothrow @nogc 4054private bool isOctalLiteral(const string num) 4055{ 4056 if (num.length == 0) 4057 return false; 4058 4059 // Must start with a number. To avoid confusion, literals that 4060 // start with a '0' are not allowed 4061 if (num[0] == '0' && num.length > 1) 4062 return false; 4063 if (num[0] < '0' || num[0] > '7') 4064 return false; 4065 4066 foreach (i, c; num) 4067 { 4068 if ((c < '0' || c > '7') && c != '_') // not a legal character 4069 { 4070 if (i < num.length - 2) 4071 return false; 4072 else // gotta check for those suffixes 4073 { 4074 if (c != 'U' && c != 'u' && c != 'L') 4075 return false; 4076 if (i != num.length - 1) 4077 { 4078 // if we're not the last one, the next one must 4079 // also be a suffix to be valid 4080 char c2 = num[$-1]; 4081 if (c2 != 'U' && c2 != 'u' && c2 != 'L') 4082 return false; // spam at the end of the string 4083 if (c2 == c) 4084 return false; // repeats are disallowed 4085 } 4086 } 4087 } 4088 } 4089 4090 return true; 4091} 4092 4093@safe unittest 4094{ 4095 // ensure that you get the right types, even with embedded underscores 4096 auto w = octal!"100_000_000_000"; 4097 static assert(!is(typeof(w) == int)); 4098 auto w2 = octal!"1_000_000_000"; 4099 static assert(is(typeof(w2) == int)); 4100 4101 static assert(octal!"45" == 37); 4102 static assert(octal!"0" == 0); 4103 static assert(octal!"7" == 7); 4104 static assert(octal!"10" == 8); 4105 static assert(octal!"666" == 438); 4106 4107 static assert(octal!45 == 37); 4108 static assert(octal!0 == 0); 4109 static assert(octal!7 == 7); 4110 static assert(octal!10 == 8); 4111 static assert(octal!666 == 438); 4112 4113 static assert(octal!"66_6" == 438); 4114 4115 static assert(octal!2520046213 == 356535435); 4116 static assert(octal!"2520046213" == 356535435); 4117 4118 static assert(octal!17777777777 == int.max); 4119 4120 static assert(!__traits(compiles, octal!823)); 4121 4122 static assert(!__traits(compiles, octal!"823")); 4123 4124 static assert(!__traits(compiles, octal!"_823")); 4125 static assert(!__traits(compiles, octal!"spam")); 4126 static assert(!__traits(compiles, octal!"77%")); 4127 4128 static assert(is(typeof(octal!"17777777777") == int)); 4129 static assert(octal!"17777777777" == int.max); 4130 4131 static assert(is(typeof(octal!"20000000000U") == ulong)); // Shouldn't this be uint? 4132 static assert(octal!"20000000000" == uint(int.max) + 1); 4133 4134 static assert(is(typeof(octal!"777777777777777777777") == long)); 4135 static assert(octal!"777777777777777777777" == long.max); 4136 4137 static assert(is(typeof(octal!"1000000000000000000000U") == ulong)); 4138 static assert(octal!"1000000000000000000000" == ulong(long.max) + 1); 4139 4140 int a; 4141 long b; 4142 4143 // biggest value that should fit in an it 4144 a = octal!"17777777777"; 4145 assert(a == int.max); 4146 // should not fit in the int 4147 static assert(!__traits(compiles, a = octal!"20000000000")); 4148 // ... but should fit in a long 4149 b = octal!"20000000000"; 4150 assert(b == 1L + int.max); 4151 4152 b = octal!"1L"; 4153 assert(b == 1); 4154 b = octal!1L; 4155 assert(b == 1); 4156} 4157 4158/+ 4159emplaceRef is a package function for phobos internal use. It works like 4160emplace, but takes its argument by ref (as opposed to "by pointer"). 4161 4162This makes it easier to use, easier to be safe, and faster in a non-inline 4163build. 4164 4165Furthermore, emplaceRef optionally takes a type paremeter, which specifies 4166the type we want to build. This helps to build qualified objects on mutable 4167buffer, without breaking the type system with unsafe casts. 4168+/ 4169package void emplaceRef(T, UT, Args...)(ref UT chunk, auto ref Args args) 4170{ 4171 static if (args.length == 0) 4172 { 4173 static assert(is(typeof({static T i;})), 4174 convFormat("Cannot emplace a %1$s because %1$s.this() is annotated with @disable.", T.stringof)); 4175 static if (is(T == class)) static assert(!isAbstractClass!T, 4176 T.stringof ~ " is abstract and it can't be emplaced"); 4177 emplaceInitializer(chunk); 4178 } 4179 else static if ( 4180 !is(T == struct) && Args.length == 1 /* primitives, enums, arrays */ 4181 || 4182 Args.length == 1 && is(typeof({T t = args[0];})) /* conversions */ 4183 || 4184 is(typeof(T(args))) /* general constructors */) 4185 { 4186 static struct S 4187 { 4188 T payload; 4189 this(ref Args x) 4190 { 4191 static if (Args.length == 1) 4192 static if (is(typeof(payload = x[0]))) 4193 payload = x[0]; 4194 else 4195 payload = T(x[0]); 4196 else 4197 payload = T(x); 4198 } 4199 } 4200 if (__ctfe) 4201 { 4202 static if (is(typeof(chunk = T(args)))) 4203 chunk = T(args); 4204 else static if (args.length == 1 && is(typeof(chunk = args[0]))) 4205 chunk = args[0]; 4206 else assert(0, "CTFE emplace doesn't support " 4207 ~ T.stringof ~ " from " ~ Args.stringof); 4208 } 4209 else 4210 { 4211 S* p = () @trusted { return cast(S*) &chunk; }(); 4212 emplaceInitializer(*p); 4213 p.__ctor(args); 4214 } 4215 } 4216 else static if (is(typeof(chunk.__ctor(args)))) 4217 { 4218 // This catches the rare case of local types that keep a frame pointer 4219 emplaceInitializer(chunk); 4220 chunk.__ctor(args); 4221 } 4222 else 4223 { 4224 //We can't emplace. Try to diagnose a disabled postblit. 4225 static assert(!(Args.length == 1 && is(Args[0] : T)), 4226 convFormat("Cannot emplace a %1$s because %1$s.this(this) is annotated with @disable.", T.stringof)); 4227 4228 //We can't emplace. 4229 static assert(false, 4230 convFormat("%s cannot be emplaced from %s.", T.stringof, Args[].stringof)); 4231 } 4232} 4233// ditto 4234package void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args) 4235if (is(UT == Unqual!UT)) 4236{ 4237 emplaceRef!(UT, UT)(chunk, args); 4238} 4239 4240//emplace helper functions 4241private void emplaceInitializer(T)(ref T chunk) @trusted pure nothrow 4242{ 4243 static if (!hasElaborateAssign!T && isAssignable!T) 4244 chunk = T.init; 4245 else 4246 { 4247 import core.stdc.string : memcpy; 4248 static immutable T init = T.init; 4249 memcpy(&chunk, &init, T.sizeof); 4250 } 4251} 4252 4253// emplace 4254/** 4255Given a pointer $(D chunk) to uninitialized memory (but already typed 4256as $(D T)), constructs an object of non-$(D class) type $(D T) at that 4257address. If `T` is a class, initializes the class reference to null. 4258 4259Returns: A pointer to the newly constructed object (which is the same 4260as $(D chunk)). 4261 */ 4262T* emplace(T)(T* chunk) @safe pure nothrow 4263{ 4264 emplaceRef!T(*chunk); 4265 return chunk; 4266} 4267 4268/// 4269@system unittest 4270{ 4271 static struct S 4272 { 4273 int i = 42; 4274 } 4275 S[2] s2 = void; 4276 emplace(&s2); 4277 assert(s2[0].i == 42 && s2[1].i == 42); 4278} 4279 4280/// 4281@system unittest 4282{ 4283 interface I {} 4284 class K : I {} 4285 4286 K k = void; 4287 emplace(&k); 4288 assert(k is null); 4289 4290 I i = void; 4291 emplace(&i); 4292 assert(i is null); 4293} 4294 4295/** 4296Given a pointer $(D chunk) to uninitialized memory (but already typed 4297as a non-class type $(D T)), constructs an object of type $(D T) at 4298that address from arguments $(D args). If `T` is a class, initializes 4299the class reference to `args[0]`. 4300 4301This function can be $(D @trusted) if the corresponding constructor of 4302$(D T) is $(D @safe). 4303 4304Returns: A pointer to the newly constructed object (which is the same 4305as $(D chunk)). 4306 */ 4307T* emplace(T, Args...)(T* chunk, auto ref Args args) 4308if (is(T == struct) || Args.length == 1) 4309{ 4310 emplaceRef!T(*chunk, args); 4311 return chunk; 4312} 4313 4314/// 4315@system unittest 4316{ 4317 int a; 4318 int b = 42; 4319 assert(*emplace!int(&a, b) == 42); 4320} 4321 4322@system unittest 4323{ 4324 shared int i; 4325 emplace(&i, 42); 4326 assert(i == 42); 4327} 4328 4329private void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment, string typeName) @nogc pure nothrow 4330{ 4331 assert(chunk.length >= typeSize, "emplace: Chunk size too small."); 4332 assert((cast(size_t) chunk.ptr) % typeAlignment == 0, "emplace: Chunk is not aligned."); 4333} 4334 4335/** 4336Given a raw memory area $(D chunk), constructs an object of $(D class) 4337type $(D T) at that address. The constructor is passed the arguments 4338$(D Args). 4339 4340If `T` is an inner class whose `outer` field can be used to access an instance 4341of the enclosing class, then `Args` must not be empty, and the first member of it 4342must be a valid initializer for that `outer` field. Correct initialization of 4343this field is essential to access members of the outer class inside `T` methods. 4344 4345Preconditions: 4346$(D chunk) must be at least as large as $(D T) needs 4347and should have an alignment multiple of $(D T)'s alignment. (The size 4348of a $(D class) instance is obtained by using $(D 4349__traits(classInstanceSize, T))). 4350 4351Note: 4352This function can be $(D @trusted) if the corresponding constructor of 4353$(D T) is $(D @safe). 4354 4355Returns: The newly constructed object. 4356 */ 4357T emplace(T, Args...)(void[] chunk, auto ref Args args) 4358if (is(T == class)) 4359{ 4360 static assert(!isAbstractClass!T, T.stringof ~ 4361 " is abstract and it can't be emplaced"); 4362 4363 enum classSize = __traits(classInstanceSize, T); 4364 testEmplaceChunk(chunk, classSize, classInstanceAlignment!T, T.stringof); 4365 auto result = cast(T) chunk.ptr; 4366 4367 // Initialize the object in its pre-ctor state 4368 chunk[0 .. classSize] = typeid(T).initializer[]; 4369 4370 static if (isInnerClass!T) 4371 { 4372 static assert(Args.length > 0, 4373 "Initializing an inner class requires a pointer to the outer class"); 4374 static assert(is(Args[0] : typeof(T.outer)), 4375 "The first argument must be a pointer to the outer class"); 4376 4377 result.outer = args[0]; 4378 alias args1 = args[1..$]; 4379 } 4380 else alias args1 = args; 4381 4382 // Call the ctor if any 4383 static if (is(typeof(result.__ctor(args1)))) 4384 { 4385 // T defines a genuine constructor accepting args 4386 // Go the classic route: write .init first, then call ctor 4387 result.__ctor(args1); 4388 } 4389 else 4390 { 4391 static assert(args1.length == 0 && !is(typeof(&T.__ctor)), 4392 "Don't know how to initialize an object of type " 4393 ~ T.stringof ~ " with arguments " ~ typeof(args1).stringof); 4394 } 4395 return result; 4396} 4397 4398/// 4399@system unittest 4400{ 4401 static class C 4402 { 4403 int i; 4404 this(int i){this.i = i;} 4405 } 4406 auto buf = new void[__traits(classInstanceSize, C)]; 4407 auto c = emplace!C(buf, 5); 4408 assert(c.i == 5); 4409} 4410 4411@system unittest 4412{ 4413 class Outer 4414 { 4415 int i = 3; 4416 class Inner 4417 { 4418 auto getI() { return i; } 4419 } 4420 } 4421 auto outerBuf = new void[__traits(classInstanceSize, Outer)]; 4422 auto innerBuf = new void[__traits(classInstanceSize, Outer.Inner)]; 4423 auto inner = innerBuf.emplace!(Outer.Inner)(outerBuf.emplace!Outer); 4424 assert(inner.getI == 3); 4425} 4426 4427@nogc pure nothrow @system unittest 4428{ 4429 int var = 6; 4430 align(__conv_EmplaceTestClass.alignof) ubyte[__traits(classInstanceSize, __conv_EmplaceTestClass)] buf; 4431 auto k = emplace!__conv_EmplaceTestClass(buf, 5, var); 4432 assert(k.i == 5); 4433 assert(var == 7); 4434} 4435 4436/** 4437Given a raw memory area $(D chunk), constructs an object of non-$(D 4438class) type $(D T) at that address. The constructor is passed the 4439arguments $(D args), if any. 4440 4441Preconditions: 4442$(D chunk) must be at least as large 4443as $(D T) needs and should have an alignment multiple of $(D T)'s 4444alignment. 4445 4446Note: 4447This function can be $(D @trusted) if the corresponding constructor of 4448$(D T) is $(D @safe). 4449 4450Returns: A pointer to the newly constructed object. 4451 */ 4452T* emplace(T, Args...)(void[] chunk, auto ref Args args) 4453if (!is(T == class)) 4454{ 4455 testEmplaceChunk(chunk, T.sizeof, T.alignof, T.stringof); 4456 emplaceRef!(T, Unqual!T)(*cast(Unqual!T*) chunk.ptr, args); 4457 return cast(T*) chunk.ptr; 4458} 4459 4460/// 4461@system unittest 4462{ 4463 struct S 4464 { 4465 int a, b; 4466 } 4467 auto buf = new void[S.sizeof]; 4468 S s; 4469 s.a = 42; 4470 s.b = 43; 4471 auto s1 = emplace!S(buf, s); 4472 assert(s1.a == 42 && s1.b == 43); 4473} 4474 4475// Bulk of emplace unittests starts here 4476 4477@system unittest /* unions */ 4478{ 4479 static union U 4480 { 4481 string a; 4482 int b; 4483 struct 4484 { 4485 long c; 4486 int[] d; 4487 } 4488 } 4489 U u1 = void; 4490 U u2 = { "hello" }; 4491 emplace(&u1, u2); 4492 assert(u1.a == "hello"); 4493} 4494 4495version (unittest) private struct __conv_EmplaceTest 4496{ 4497 int i = 3; 4498 this(int i) 4499 { 4500 assert(this.i == 3 && i == 5); 4501 this.i = i; 4502 } 4503 this(int i, ref int j) 4504 { 4505 assert(i == 5 && j == 6); 4506 this.i = i; 4507 ++j; 4508 } 4509 4510@disable: 4511 this(); 4512 this(this); 4513 void opAssign(); 4514} 4515 4516version (unittest) private class __conv_EmplaceTestClass 4517{ 4518 int i = 3; 4519 this(int i) @nogc @safe pure nothrow 4520 { 4521 assert(this.i == 3 && i == 5); 4522 this.i = i; 4523 } 4524 this(int i, ref int j) @nogc @safe pure nothrow 4525 { 4526 assert(i == 5 && j == 6); 4527 this.i = i; 4528 ++j; 4529 } 4530} 4531 4532@system unittest // bugzilla 15772 4533{ 4534 abstract class Foo {} 4535 class Bar: Foo {} 4536 void[] memory; 4537 // test in emplaceInitializer 4538 static assert(!is(typeof(emplace!Foo(cast(Foo*) memory.ptr)))); 4539 static assert( is(typeof(emplace!Bar(cast(Bar*) memory.ptr)))); 4540 // test in the emplace overload that takes void[] 4541 static assert(!is(typeof(emplace!Foo(memory)))); 4542 static assert( is(typeof(emplace!Bar(memory)))); 4543} 4544 4545@system unittest 4546{ 4547 struct S { @disable this(); } 4548 S s = void; 4549 static assert(!__traits(compiles, emplace(&s))); 4550 emplace(&s, S.init); 4551} 4552 4553@system unittest 4554{ 4555 struct S1 4556 {} 4557 4558 struct S2 4559 { 4560 void opAssign(S2); 4561 } 4562 4563 S1 s1 = void; 4564 S2 s2 = void; 4565 S1[2] as1 = void; 4566 S2[2] as2 = void; 4567 emplace(&s1); 4568 emplace(&s2); 4569 emplace(&as1); 4570 emplace(&as2); 4571} 4572 4573@system unittest 4574{ 4575 static struct S1 4576 { 4577 this(this) @disable; 4578 } 4579 static struct S2 4580 { 4581 this() @disable; 4582 } 4583 S1[2] ss1 = void; 4584 S2[2] ss2 = void; 4585 emplace(&ss1); 4586 static assert(!__traits(compiles, emplace(&ss2))); 4587 S1 s1 = S1.init; 4588 S2 s2 = S2.init; 4589 static assert(!__traits(compiles, emplace(&ss1, s1))); 4590 emplace(&ss2, s2); 4591} 4592 4593@system unittest 4594{ 4595 struct S 4596 { 4597 immutable int i; 4598 } 4599 S s = void; 4600 S[2] ss1 = void; 4601 S[2] ss2 = void; 4602 emplace(&s, 5); 4603 assert(s.i == 5); 4604 emplace(&ss1, s); 4605 assert(ss1[0].i == 5 && ss1[1].i == 5); 4606 emplace(&ss2, ss1); 4607 assert(ss2 == ss1); 4608} 4609 4610//Start testing emplace-args here 4611 4612@system unittest 4613{ 4614 interface I {} 4615 class K : I {} 4616 4617 K k = null, k2 = new K; 4618 assert(k !is k2); 4619 emplace!K(&k, k2); 4620 assert(k is k2); 4621 4622 I i = null; 4623 assert(i !is k); 4624 emplace!I(&i, k); 4625 assert(i is k); 4626} 4627 4628@system unittest 4629{ 4630 static struct S 4631 { 4632 int i = 5; 4633 void opAssign(S){assert(0);} 4634 } 4635 S[2] sa = void; 4636 S[2] sb; 4637 emplace(&sa, sb); 4638 assert(sa[0].i == 5 && sa[1].i == 5); 4639} 4640 4641//Start testing emplace-struct here 4642 4643// Test constructor branch 4644@system unittest 4645{ 4646 struct S 4647 { 4648 double x = 5, y = 6; 4649 this(int a, int b) 4650 { 4651 assert(x == 5 && y == 6); 4652 x = a; 4653 y = b; 4654 } 4655 } 4656 4657 auto s1 = new void[S.sizeof]; 4658 auto s2 = S(42, 43); 4659 assert(*emplace!S(cast(S*) s1.ptr, s2) == s2); 4660 assert(*emplace!S(cast(S*) s1, 44, 45) == S(44, 45)); 4661} 4662 4663@system unittest 4664{ 4665 __conv_EmplaceTest k = void; 4666 emplace(&k, 5); 4667 assert(k.i == 5); 4668} 4669 4670@system unittest 4671{ 4672 int var = 6; 4673 __conv_EmplaceTest k = void; 4674 emplace(&k, 5, var); 4675 assert(k.i == 5); 4676 assert(var == 7); 4677} 4678 4679// Test matching fields branch 4680@system unittest 4681{ 4682 struct S { uint n; } 4683 S s; 4684 emplace!S(&s, 2U); 4685 assert(s.n == 2); 4686} 4687 4688@safe unittest 4689{ 4690 struct S { int a, b; this(int){} } 4691 S s; 4692 static assert(!__traits(compiles, emplace!S(&s, 2, 3))); 4693} 4694 4695@system unittest 4696{ 4697 struct S { int a, b = 7; } 4698 S s1 = void, s2 = void; 4699 4700 emplace!S(&s1, 2); 4701 assert(s1.a == 2 && s1.b == 7); 4702 4703 emplace!S(&s2, 2, 3); 4704 assert(s2.a == 2 && s2.b == 3); 4705} 4706 4707//opAssign 4708@system unittest 4709{ 4710 static struct S 4711 { 4712 int i = 5; 4713 void opAssign(int){assert(0);} 4714 void opAssign(S){assert(0);} 4715 } 4716 S sa1 = void; 4717 S sa2 = void; 4718 S sb1 = S(1); 4719 emplace(&sa1, sb1); 4720 emplace(&sa2, 2); 4721 assert(sa1.i == 1); 4722 assert(sa2.i == 2); 4723} 4724 4725//postblit precedence 4726@system unittest 4727{ 4728 //Works, but breaks in "-w -O" because of @@@9332@@@. 4729 //Uncomment test when 9332 is fixed. 4730 static struct S 4731 { 4732 int i; 4733 4734 this(S other){assert(false);} 4735 this(int i){this.i = i;} 4736 this(this){} 4737 } 4738 S a = void; 4739 assert(is(typeof({S b = a;}))); //Postblit 4740 assert(is(typeof({S b = S(a);}))); //Constructor 4741 auto b = S(5); 4742 emplace(&a, b); 4743 assert(a.i == 5); 4744 4745 static struct S2 4746 { 4747 int* p; 4748 this(const S2){} 4749 } 4750 static assert(!is(immutable S2 : S2)); 4751 S2 s2 = void; 4752 immutable is2 = (immutable S2).init; 4753 emplace(&s2, is2); 4754} 4755 4756//nested structs and postblit 4757@system unittest 4758{ 4759 static struct S 4760 { 4761 int* p; 4762 this(int i){p = [i].ptr;} 4763 this(this) 4764 { 4765 if (p) 4766 p = [*p].ptr; 4767 } 4768 } 4769 static struct SS 4770 { 4771 S s; 4772 void opAssign(const SS) 4773 { 4774 assert(0); 4775 } 4776 } 4777 SS ssa = void; 4778 SS ssb = SS(S(5)); 4779 emplace(&ssa, ssb); 4780 assert(*ssa.s.p == 5); 4781 assert(ssa.s.p != ssb.s.p); 4782} 4783 4784//disabled postblit 4785@system unittest 4786{ 4787 static struct S1 4788 { 4789 int i; 4790 @disable this(this); 4791 } 4792 S1 s1 = void; 4793 emplace(&s1, 1); 4794 assert(s1.i == 1); 4795 static assert(!__traits(compiles, emplace(&s1, S1.init))); 4796 4797 static struct S2 4798 { 4799 int i; 4800 @disable this(this); 4801 this(ref S2){} 4802 } 4803 S2 s2 = void; 4804 static assert(!__traits(compiles, emplace(&s2, 1))); 4805 emplace(&s2, S2.init); 4806 4807 static struct SS1 4808 { 4809 S1 s; 4810 } 4811 SS1 ss1 = void; 4812 emplace(&ss1); 4813 static assert(!__traits(compiles, emplace(&ss1, SS1.init))); 4814 4815 static struct SS2 4816 { 4817 S2 s; 4818 } 4819 SS2 ss2 = void; 4820 emplace(&ss2); 4821 static assert(!__traits(compiles, emplace(&ss2, SS2.init))); 4822 4823 4824 // SS1 sss1 = s1; //This doesn't compile 4825 // SS1 sss1 = SS1(s1); //This doesn't compile 4826 // So emplace shouldn't compile either 4827 static assert(!__traits(compiles, emplace(&sss1, s1))); 4828 static assert(!__traits(compiles, emplace(&sss2, s2))); 4829} 4830 4831//Imutability 4832@system unittest 4833{ 4834 //Castable immutability 4835 { 4836 static struct S1 4837 { 4838 int i; 4839 } 4840 static assert(is( immutable(S1) : S1)); 4841 S1 sa = void; 4842 auto sb = immutable(S1)(5); 4843 emplace(&sa, sb); 4844 assert(sa.i == 5); 4845 } 4846 //Un-castable immutability 4847 { 4848 static struct S2 4849 { 4850 int* p; 4851 } 4852 static assert(!is(immutable(S2) : S2)); 4853 S2 sa = void; 4854 auto sb = immutable(S2)(null); 4855 assert(!__traits(compiles, emplace(&sa, sb))); 4856 } 4857} 4858 4859@system unittest 4860{ 4861 static struct S 4862 { 4863 immutable int i; 4864 immutable(int)* j; 4865 } 4866 S s = void; 4867 emplace(&s, 1, null); 4868 emplace(&s, 2, &s.i); 4869 assert(s is S(2, &s.i)); 4870} 4871 4872//Context pointer 4873@system unittest 4874{ 4875 int i = 0; 4876 { 4877 struct S1 4878 { 4879 void foo(){++i;} 4880 } 4881 S1 sa = void; 4882 S1 sb; 4883 emplace(&sa, sb); 4884 sa.foo(); 4885 assert(i == 1); 4886 } 4887 { 4888 struct S2 4889 { 4890 void foo(){++i;} 4891 this(this){} 4892 } 4893 S2 sa = void; 4894 S2 sb; 4895 emplace(&sa, sb); 4896 sa.foo(); 4897 assert(i == 2); 4898 } 4899} 4900 4901//Alias this 4902@system unittest 4903{ 4904 static struct S 4905 { 4906 int i; 4907 } 4908 //By Ref 4909 { 4910 static struct SS1 4911 { 4912 int j; 4913 S s; 4914 alias s this; 4915 } 4916 S s = void; 4917 SS1 ss = SS1(1, S(2)); 4918 emplace(&s, ss); 4919 assert(s.i == 2); 4920 } 4921 //By Value 4922 { 4923 static struct SS2 4924 { 4925 int j; 4926 S s; 4927 S foo() @property{return s;} 4928 alias foo this; 4929 } 4930 S s = void; 4931 SS2 ss = SS2(1, S(2)); 4932 emplace(&s, ss); 4933 assert(s.i == 2); 4934 } 4935} 4936version (unittest) 4937{ 4938 //Ambiguity 4939 struct __std_conv_S 4940 { 4941 int i; 4942 this(__std_conv_SS ss) {assert(0);} 4943 static opCall(__std_conv_SS ss) 4944 { 4945 __std_conv_S s; s.i = ss.j; 4946 return s; 4947 } 4948 } 4949 struct __std_conv_SS 4950 { 4951 int j; 4952 __std_conv_S s; 4953 ref __std_conv_S foo() return @property {s.i = j; return s;} 4954 alias foo this; 4955 } 4956 static assert(is(__std_conv_SS : __std_conv_S)); 4957 @system unittest 4958 { 4959 __std_conv_S s = void; 4960 __std_conv_SS ss = __std_conv_SS(1); 4961 4962 __std_conv_S sTest1 = ss; //this calls "SS alias this" (and not "S.this(SS)") 4963 emplace(&s, ss); //"alias this" should take precedence in emplace over "opCall" 4964 assert(s.i == 1); 4965 } 4966} 4967 4968//Nested classes 4969@system unittest 4970{ 4971 class A{} 4972 static struct S 4973 { 4974 A a; 4975 } 4976 S s1 = void; 4977 S s2 = S(new A); 4978 emplace(&s1, s2); 4979 assert(s1.a is s2.a); 4980} 4981 4982//safety & nothrow & CTFE 4983@system unittest 4984{ 4985 //emplace should be safe for anything with no elaborate opassign 4986 static struct S1 4987 { 4988 int i; 4989 } 4990 static struct S2 4991 { 4992 int i; 4993 this(int j)@safe nothrow{i = j;} 4994 } 4995 4996 int i; 4997 S1 s1 = void; 4998 S2 s2 = void; 4999 5000 auto pi = &i; 5001 auto ps1 = &s1; 5002 auto ps2 = &s2; 5003 5004 void foo() @safe nothrow 5005 { 5006 emplace(pi); 5007 emplace(pi, 5); 5008 emplace(ps1); 5009 emplace(ps1, 5); 5010 emplace(ps1, S1.init); 5011 emplace(ps2); 5012 emplace(ps2, 5); 5013 emplace(ps2, S2.init); 5014 } 5015 foo(); 5016 5017 T bar(T)() @property 5018 { 5019 T t/+ = void+/; //CTFE void illegal 5020 emplace(&t, 5); 5021 return t; 5022 } 5023 // CTFE 5024 enum a = bar!int; 5025 static assert(a == 5); 5026 enum b = bar!S1; 5027 static assert(b.i == 5); 5028 enum c = bar!S2; 5029 static assert(c.i == 5); 5030 // runtime 5031 auto aa = bar!int; 5032 assert(aa == 5); 5033 auto bb = bar!S1; 5034 assert(bb.i == 5); 5035 auto cc = bar!S2; 5036 assert(cc.i == 5); 5037} 5038 5039 5040@system unittest 5041{ 5042 struct S 5043 { 5044 int[2] get(){return [1, 2];} 5045 alias get this; 5046 } 5047 struct SS 5048 { 5049 int[2] ii; 5050 } 5051 struct ISS 5052 { 5053 int[2] ii; 5054 } 5055 S s; 5056 SS ss = void; 5057 ISS iss = void; 5058 emplace(&ss, s); 5059 emplace(&iss, s); 5060 assert(ss.ii == [1, 2]); 5061 assert(iss.ii == [1, 2]); 5062} 5063 5064//disable opAssign 5065@system unittest 5066{ 5067 static struct S 5068 { 5069 @disable void opAssign(S); 5070 } 5071 S s; 5072 emplace(&s, S.init); 5073} 5074 5075//opCall 5076@system unittest 5077{ 5078 int i; 5079 //Without constructor 5080 { 5081 static struct S1 5082 { 5083 int i; 5084 static S1 opCall(int*){assert(0);} 5085 } 5086 S1 s = void; 5087 static assert(!__traits(compiles, emplace(&s, 1))); 5088 } 5089 //With constructor 5090 { 5091 static struct S2 5092 { 5093 int i = 0; 5094 static S2 opCall(int*){assert(0);} 5095 static S2 opCall(int){assert(0);} 5096 this(int i){this.i = i;} 5097 } 5098 S2 s = void; 5099 emplace(&s, 1); 5100 assert(s.i == 1); 5101 } 5102 //With postblit ambiguity 5103 { 5104 static struct S3 5105 { 5106 int i = 0; 5107 static S3 opCall(ref S3){assert(0);} 5108 } 5109 S3 s = void; 5110 emplace(&s, S3.init); 5111 } 5112} 5113 5114@safe unittest //@@@9559@@@ 5115{ 5116 import std.algorithm.iteration : map; 5117 import std.array : array; 5118 import std.typecons : Nullable; 5119 alias I = Nullable!int; 5120 auto ints = [0, 1, 2].map!(i => i & 1 ? I.init : I(i))(); 5121 auto asArray = array(ints); 5122} 5123 5124@system unittest //http://forum.dlang.org/post/nxbdgtdlmwscocbiypjs@forum.dlang.org 5125{ 5126 import std.array : array; 5127 import std.datetime : SysTime, UTC; 5128 import std.math : isNaN; 5129 5130 static struct A 5131 { 5132 double i; 5133 } 5134 5135 static struct B 5136 { 5137 invariant() 5138 { 5139 if (j == 0) 5140 assert(a.i.isNaN(), "why is 'j' zero?? and i is not NaN?"); 5141 else 5142 assert(!a.i.isNaN()); 5143 } 5144 SysTime when; // comment this line avoid the breakage 5145 int j; 5146 A a; 5147 } 5148 5149 B b1 = B.init; 5150 assert(&b1); // verify that default eyes invariants are ok; 5151 5152 auto b2 = B(SysTime(0, UTC()), 1, A(1)); 5153 assert(&b2); 5154 auto b3 = B(SysTime(0, UTC()), 1, A(1)); 5155 assert(&b3); 5156 5157 auto arr = [b2, b3]; 5158 5159 assert(arr[0].j == 1); 5160 assert(arr[1].j == 1); 5161 auto a2 = arr.array(); // << bang, invariant is raised, also if b2 and b3 are good 5162} 5163 5164//static arrays 5165@system unittest 5166{ 5167 static struct S 5168 { 5169 int[2] ii; 5170 } 5171 static struct IS 5172 { 5173 immutable int[2] ii; 5174 } 5175 int[2] ii; 5176 S s = void; 5177 IS ims = void; 5178 ubyte ub = 2; 5179 emplace(&s, ub); 5180 emplace(&s, ii); 5181 emplace(&ims, ub); 5182 emplace(&ims, ii); 5183 uint[2] uu; 5184 static assert(!__traits(compiles, {S ss = S(uu);})); 5185 static assert(!__traits(compiles, emplace(&s, uu))); 5186} 5187 5188@system unittest 5189{ 5190 int[2] sii; 5191 int[2] sii2; 5192 uint[2] uii; 5193 uint[2] uii2; 5194 emplace(&sii, 1); 5195 emplace(&sii, 1U); 5196 emplace(&uii, 1); 5197 emplace(&uii, 1U); 5198 emplace(&sii, sii2); 5199 //emplace(&sii, uii2); //Sorry, this implementation doesn't know how to... 5200 //emplace(&uii, sii2); //Sorry, this implementation doesn't know how to... 5201 emplace(&uii, uii2); 5202 emplace(&sii, sii2[]); 5203 //emplace(&sii, uii2[]); //Sorry, this implementation doesn't know how to... 5204 //emplace(&uii, sii2[]); //Sorry, this implementation doesn't know how to... 5205 emplace(&uii, uii2[]); 5206} 5207 5208@system unittest 5209{ 5210 bool allowDestruction = false; 5211 struct S 5212 { 5213 int i; 5214 this(this){} 5215 ~this(){assert(allowDestruction);} 5216 } 5217 S s = S(1); 5218 S[2] ss1 = void; 5219 S[2] ss2 = void; 5220 S[2] ss3 = void; 5221 emplace(&ss1, s); 5222 emplace(&ss2, ss1); 5223 emplace(&ss3, ss2[]); 5224 assert(ss1[1] == s); 5225 assert(ss2[1] == s); 5226 assert(ss3[1] == s); 5227 allowDestruction = true; 5228} 5229 5230@system unittest 5231{ 5232 //Checks postblit, construction, and context pointer 5233 int count = 0; 5234 struct S 5235 { 5236 this(this) 5237 { 5238 ++count; 5239 } 5240 ~this() 5241 { 5242 --count; 5243 } 5244 } 5245 5246 S s; 5247 { 5248 S[4] ss = void; 5249 emplace(&ss, s); 5250 assert(count == 4); 5251 } 5252 assert(count == 0); 5253} 5254 5255@system unittest 5256{ 5257 struct S 5258 { 5259 int i; 5260 } 5261 S s; 5262 S[2][2][2] sss = void; 5263 emplace(&sss, s); 5264} 5265 5266@system unittest //Constness 5267{ 5268 import std.stdio; 5269 5270 int a = void; 5271 emplaceRef!(const int)(a, 5); 5272 5273 immutable i = 5; 5274 const(int)* p = void; 5275 emplaceRef!(const int*)(p, &i); 5276 5277 struct S 5278 { 5279 int* p; 5280 } 5281 alias IS = immutable(S); 5282 S s = void; 5283 emplaceRef!IS(s, IS()); 5284 S[2] ss = void; 5285 emplaceRef!(IS[2])(ss, IS()); 5286 5287 IS[2] iss = IS.init; 5288 emplaceRef!(IS[2])(ss, iss); 5289 emplaceRef!(IS[2])(ss, iss[]); 5290} 5291 5292pure nothrow @safe @nogc unittest 5293{ 5294 int i; 5295 emplaceRef(i); 5296 emplaceRef!int(i); 5297 emplaceRef(i, 5); 5298 emplaceRef!int(i, 5); 5299} 5300 5301// Test attribute propagation for UDTs 5302pure nothrow @safe /* @nogc */ unittest 5303{ 5304 static struct Safe 5305 { 5306 this(this) pure nothrow @safe @nogc {} 5307 } 5308 5309 Safe safe = void; 5310 emplaceRef(safe, Safe()); 5311 5312 Safe[1] safeArr = [Safe()]; 5313 Safe[1] uninitializedSafeArr = void; 5314 emplaceRef(uninitializedSafeArr, safe); 5315 emplaceRef(uninitializedSafeArr, safeArr); 5316 5317 static struct Unsafe 5318 { 5319 this(this) @system {} 5320 } 5321 5322 Unsafe unsafe = void; 5323 static assert(!__traits(compiles, emplaceRef(unsafe, Unsafe()))); 5324 5325 Unsafe[1] unsafeArr = [Unsafe()]; 5326 Unsafe[1] uninitializedUnsafeArr = void; 5327 static assert(!__traits(compiles, emplaceRef(uninitializedUnsafeArr, unsafe))); 5328 static assert(!__traits(compiles, emplaceRef(uninitializedUnsafeArr, unsafeArr))); 5329} 5330 5331@system unittest 5332{ 5333 // Issue 15313 5334 static struct Node 5335 { 5336 int payload; 5337 Node* next; 5338 uint refs; 5339 } 5340 5341 import core.stdc.stdlib : malloc; 5342 void[] buf = malloc(Node.sizeof)[0 .. Node.sizeof]; 5343 5344 import std.conv : emplace; 5345 const Node* n = emplace!(const Node)(buf, 42, null, 10); 5346 assert(n.payload == 42); 5347 assert(n.next == null); 5348 assert(n.refs == 10); 5349} 5350 5351@system unittest 5352{ 5353 int var = 6; 5354 auto k = emplace!__conv_EmplaceTest(new void[__conv_EmplaceTest.sizeof], 5, var); 5355 assert(k.i == 5); 5356 assert(var == 7); 5357} 5358 5359@system unittest 5360{ 5361 class A 5362 { 5363 int x = 5; 5364 int y = 42; 5365 this(int z) 5366 { 5367 assert(x == 5 && y == 42); 5368 x = y = z; 5369 } 5370 } 5371 void[] buf; 5372 5373 static align(A.alignof) byte[__traits(classInstanceSize, A)] sbuf; 5374 buf = sbuf[]; 5375 auto a = emplace!A(buf, 55); 5376 assert(a.x == 55 && a.y == 55); 5377 5378 // emplace in bigger buffer 5379 buf = new byte[](__traits(classInstanceSize, A) + 10); 5380 a = emplace!A(buf, 55); 5381 assert(a.x == 55 && a.y == 55); 5382 5383 // need ctor args 5384 static assert(!is(typeof(emplace!A(buf)))); 5385} 5386// Bulk of emplace unittests ends here 5387 5388@safe unittest 5389{ 5390 import std.algorithm.comparison : equal; 5391 import std.algorithm.iteration : map; 5392 // Check fix for http://d.puremagic.com/issues/show_bug.cgi?id=2971 5393 assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345])); 5394} 5395 5396// Undocumented for the time being 5397void toTextRange(T, W)(T value, W writer) 5398if (isIntegral!T && isOutputRange!(W, char)) 5399{ 5400 import core.internal.string : SignedStringBuf, signedToTempString, 5401 UnsignedStringBuf, unsignedToTempString; 5402 5403 if (value < 0) 5404 { 5405 SignedStringBuf buf = void; 5406 put(writer, signedToTempString(value, buf, 10)); 5407 } 5408 else 5409 { 5410 UnsignedStringBuf buf = void; 5411 put(writer, unsignedToTempString(value, buf, 10)); 5412 } 5413} 5414 5415@safe unittest 5416{ 5417 import std.array : appender; 5418 auto result = appender!(char[])(); 5419 toTextRange(-1, result); 5420 assert(result.data == "-1"); 5421} 5422 5423 5424/** 5425 Returns the corresponding _unsigned value for $(D x) (e.g. if $(D x) has type 5426 $(D int), it returns $(D cast(uint) x)). The advantage compared to the cast 5427 is that you do not need to rewrite the cast if $(D x) later changes type 5428 (e.g from $(D int) to $(D long)). 5429 5430 Note that the result is always mutable even if the original type was const 5431 or immutable. In order to retain the constness, use $(REF Unsigned, std,traits). 5432 */ 5433auto unsigned(T)(T x) 5434if (isIntegral!T) 5435{ 5436 return cast(Unqual!(Unsigned!T))x; 5437} 5438 5439/// 5440@safe unittest 5441{ 5442 import std.traits : Unsigned; 5443 immutable int s = 42; 5444 auto u1 = unsigned(s); //not qualified 5445 static assert(is(typeof(u1) == uint)); 5446 Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification 5447 static assert(is(typeof(u2) == immutable uint)); 5448 immutable u3 = unsigned(s); //explicitly qualified 5449} 5450 5451@safe unittest 5452{ 5453 foreach (T; AliasSeq!(byte, ubyte)) 5454 { 5455 static assert(is(typeof(unsigned(cast(T) 1)) == ubyte)); 5456 static assert(is(typeof(unsigned(cast(const T) 1)) == ubyte)); 5457 static assert(is(typeof(unsigned(cast(immutable T) 1)) == ubyte)); 5458 } 5459 5460 foreach (T; AliasSeq!(short, ushort)) 5461 { 5462 static assert(is(typeof(unsigned(cast(T) 1)) == ushort)); 5463 static assert(is(typeof(unsigned(cast(const T) 1)) == ushort)); 5464 static assert(is(typeof(unsigned(cast(immutable T) 1)) == ushort)); 5465 } 5466 5467 foreach (T; AliasSeq!(int, uint)) 5468 { 5469 static assert(is(typeof(unsigned(cast(T) 1)) == uint)); 5470 static assert(is(typeof(unsigned(cast(const T) 1)) == uint)); 5471 static assert(is(typeof(unsigned(cast(immutable T) 1)) == uint)); 5472 } 5473 5474 foreach (T; AliasSeq!(long, ulong)) 5475 { 5476 static assert(is(typeof(unsigned(cast(T) 1)) == ulong)); 5477 static assert(is(typeof(unsigned(cast(const T) 1)) == ulong)); 5478 static assert(is(typeof(unsigned(cast(immutable T) 1)) == ulong)); 5479 } 5480} 5481 5482auto unsigned(T)(T x) 5483if (isSomeChar!T) 5484{ 5485 // All characters are unsigned 5486 static assert(T.min == 0); 5487 return cast(Unqual!T) x; 5488} 5489 5490@safe unittest 5491{ 5492 foreach (T; AliasSeq!(char, wchar, dchar)) 5493 { 5494 static assert(is(typeof(unsigned(cast(T)'A')) == T)); 5495 static assert(is(typeof(unsigned(cast(const T)'A')) == T)); 5496 static assert(is(typeof(unsigned(cast(immutable T)'A')) == T)); 5497 } 5498} 5499 5500 5501/** 5502 Returns the corresponding _signed value for $(D x) (e.g. if $(D x) has type 5503 $(D uint), it returns $(D cast(int) x)). The advantage compared to the cast 5504 is that you do not need to rewrite the cast if $(D x) later changes type 5505 (e.g from $(D uint) to $(D ulong)). 5506 5507 Note that the result is always mutable even if the original type was const 5508 or immutable. In order to retain the constness, use $(REF Signed, std,traits). 5509 */ 5510auto signed(T)(T x) 5511if (isIntegral!T) 5512{ 5513 return cast(Unqual!(Signed!T))x; 5514} 5515 5516/// 5517@safe unittest 5518{ 5519 import std.traits : Signed; 5520 5521 immutable uint u = 42; 5522 auto s1 = signed(u); //not qualified 5523 static assert(is(typeof(s1) == int)); 5524 Signed!(typeof(u)) s2 = signed(u); //same qualification 5525 static assert(is(typeof(s2) == immutable int)); 5526 immutable s3 = signed(u); //explicitly qualified 5527} 5528 5529@system unittest 5530{ 5531 foreach (T; AliasSeq!(byte, ubyte)) 5532 { 5533 static assert(is(typeof(signed(cast(T) 1)) == byte)); 5534 static assert(is(typeof(signed(cast(const T) 1)) == byte)); 5535 static assert(is(typeof(signed(cast(immutable T) 1)) == byte)); 5536 } 5537 5538 foreach (T; AliasSeq!(short, ushort)) 5539 { 5540 static assert(is(typeof(signed(cast(T) 1)) == short)); 5541 static assert(is(typeof(signed(cast(const T) 1)) == short)); 5542 static assert(is(typeof(signed(cast(immutable T) 1)) == short)); 5543 } 5544 5545 foreach (T; AliasSeq!(int, uint)) 5546 { 5547 static assert(is(typeof(signed(cast(T) 1)) == int)); 5548 static assert(is(typeof(signed(cast(const T) 1)) == int)); 5549 static assert(is(typeof(signed(cast(immutable T) 1)) == int)); 5550 } 5551 5552 foreach (T; AliasSeq!(long, ulong)) 5553 { 5554 static assert(is(typeof(signed(cast(T) 1)) == long)); 5555 static assert(is(typeof(signed(cast(const T) 1)) == long)); 5556 static assert(is(typeof(signed(cast(immutable T) 1)) == long)); 5557 } 5558} 5559 5560@safe unittest 5561{ 5562 // issue 10874 5563 enum Test { a = 0 } 5564 ulong l = 0; 5565 auto t = l.to!Test; 5566} 5567 5568// asOriginalType 5569/** 5570Returns the representation of an enumerated value, i.e. the value converted to 5571the base type of the enumeration. 5572*/ 5573OriginalType!E asOriginalType(E)(E value) if (is(E == enum)) 5574{ 5575 return value; 5576} 5577 5578/// 5579@safe unittest 5580{ 5581 enum A { a = 42 } 5582 static assert(is(typeof(A.a.asOriginalType) == int)); 5583 assert(A.a.asOriginalType == 42); 5584 enum B : double { a = 43 } 5585 static assert(is(typeof(B.a.asOriginalType) == double)); 5586 assert(B.a.asOriginalType == 43); 5587} 5588 5589/** 5590 A wrapper on top of the built-in cast operator that allows one to restrict 5591 casting of the original type of the value. 5592 5593 A common issue with using a raw cast is that it may silently continue to 5594 compile even if the value's type has changed during refactoring, 5595 which breaks the initial assumption about the cast. 5596 5597 Params: 5598 From = The type to cast from. The programmer must ensure it is legal 5599 to make this cast. 5600 */ 5601template castFrom(From) 5602{ 5603 /** 5604 Params: 5605 To = The type _to cast _to. 5606 value = The value _to cast. It must be of type $(D From), 5607 otherwise a compile-time error is emitted. 5608 5609 Returns: 5610 the value after the cast, returned by reference if possible. 5611 */ 5612 auto ref to(To, T)(auto ref T value) @system 5613 { 5614 static assert( 5615 is(From == T), 5616 "the value to cast is not of specified type '" ~ From.stringof ~ 5617 "', it is of type '" ~ T.stringof ~ "'" 5618 ); 5619 5620 static assert( 5621 is(typeof(cast(To) value)), 5622 "can't cast from '" ~ From.stringof ~ "' to '" ~ To.stringof ~ "'" 5623 ); 5624 5625 return cast(To) value; 5626 } 5627} 5628 5629/// 5630@system unittest 5631{ 5632 // Regular cast, which has been verified to be legal by the programmer: 5633 { 5634 long x; 5635 auto y = cast(int) x; 5636 } 5637 5638 // However this will still compile if 'x' is changed to be a pointer: 5639 { 5640 long* x; 5641 auto y = cast(int) x; 5642 } 5643 5644 // castFrom provides a more reliable alternative to casting: 5645 { 5646 long x; 5647 auto y = castFrom!long.to!int(x); 5648 } 5649 5650 // Changing the type of 'x' will now issue a compiler error, 5651 // allowing bad casts to be caught before it's too late: 5652 { 5653 long* x; 5654 static assert( 5655 !__traits(compiles, castFrom!long.to!int(x)) 5656 ); 5657 5658 // if cast is still needed, must be changed to: 5659 auto y = castFrom!(long*).to!int(x); 5660 } 5661} 5662 5663// https://issues.dlang.org/show_bug.cgi?id=16667 5664@system unittest 5665{ 5666 ubyte[] a = ['a', 'b', 'c']; 5667 assert(castFrom!(ubyte[]).to!(string)(a) == "abc"); 5668} 5669 5670/** 5671Check the correctness of a string for $(D hexString). 5672The result is true if and only if the input string is composed of whitespace 5673characters (\f\n\r\t\v lineSep paraSep nelSep) and 5674an even number of hexadecimal digits (regardless of the case). 5675*/ 5676@safe pure @nogc 5677private bool isHexLiteral(String)(scope const String hexData) 5678{ 5679 import std.ascii : isHexDigit; 5680 import std.uni : lineSep, paraSep, nelSep; 5681 size_t i; 5682 foreach (const dchar c; hexData) 5683 { 5684 switch (c) 5685 { 5686 case ' ': 5687 case '\t': 5688 case '\v': 5689 case '\f': 5690 case '\r': 5691 case '\n': 5692 case lineSep: 5693 case paraSep: 5694 case nelSep: 5695 continue; 5696 5697 default: 5698 break; 5699 } 5700 if (c.isHexDigit) 5701 ++i; 5702 else 5703 return false; 5704 } 5705 return !(i & 1); 5706} 5707 5708@safe unittest 5709{ 5710 // test all the hex digits 5711 static assert( ("0123456789abcdefABCDEF").isHexLiteral); 5712 // empty or white strings are not valid 5713 static assert( "\r\n\t".isHexLiteral); 5714 // but are accepted if the count of hex digits is even 5715 static assert( "A\r\n\tB".isHexLiteral); 5716} 5717 5718@safe unittest 5719{ 5720 import std.ascii; 5721 // empty/whites 5722 static assert( "".isHexLiteral); 5723 static assert( " \r".isHexLiteral); 5724 static assert( whitespace.isHexLiteral); 5725 static assert( ""w.isHexLiteral); 5726 static assert( " \r"w.isHexLiteral); 5727 static assert( ""d.isHexLiteral); 5728 static assert( " \r"d.isHexLiteral); 5729 static assert( "\u2028\u2029\u0085"d.isHexLiteral); 5730 // odd x strings 5731 static assert( !("5" ~ whitespace).isHexLiteral); 5732 static assert( !"123".isHexLiteral); 5733 static assert( !"1A3".isHexLiteral); 5734 static assert( !"1 23".isHexLiteral); 5735 static assert( !"\r\n\tC".isHexLiteral); 5736 static assert( !"123"w.isHexLiteral); 5737 static assert( !"1A3"w.isHexLiteral); 5738 static assert( !"1 23"w.isHexLiteral); 5739 static assert( !"\r\n\tC"w.isHexLiteral); 5740 static assert( !"123"d.isHexLiteral); 5741 static assert( !"1A3"d.isHexLiteral); 5742 static assert( !"1 23"d.isHexLiteral); 5743 static assert( !"\r\n\tC"d.isHexLiteral); 5744 // even x strings with invalid charset 5745 static assert( !"12gG".isHexLiteral); 5746 static assert( !"2A 3q".isHexLiteral); 5747 static assert( !"12gG"w.isHexLiteral); 5748 static assert( !"2A 3q"w.isHexLiteral); 5749 static assert( !"12gG"d.isHexLiteral); 5750 static assert( !"2A 3q"d.isHexLiteral); 5751 // valid x strings 5752 static assert( ("5A" ~ whitespace).isHexLiteral); 5753 static assert( ("5A 01A C FF de 1b").isHexLiteral); 5754 static assert( ("0123456789abcdefABCDEF").isHexLiteral); 5755 static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF").isHexLiteral); 5756 static assert( ("5A 01A C FF de 1b"w).isHexLiteral); 5757 static assert( ("0123456789abcdefABCDEF"w).isHexLiteral); 5758 static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"w).isHexLiteral); 5759 static assert( ("5A 01A C FF de 1b"d).isHexLiteral); 5760 static assert( ("0123456789abcdefABCDEF"d).isHexLiteral); 5761 static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"d).isHexLiteral); 5762 // library version allows what's pointed by issue 10454 5763 static assert( ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").isHexLiteral); 5764} 5765 5766/** 5767Converts a hex literal to a string at compile time. 5768 5769Takes a string made of hexadecimal digits and returns 5770the matching string by converting each pair of digits to a character. 5771The input string can also include white characters, which can be used 5772to keep the literal string readable in the source code. 5773 5774The function is intended to replace the hexadecimal literal strings 5775starting with $(D 'x'), which could be removed to simplify the core language. 5776 5777Params: 5778 hexData = string to be converted. 5779 5780Returns: 5781 a $(D string), a $(D wstring) or a $(D dstring), according to the type of hexData. 5782 */ 5783template hexString(string hexData) 5784if (hexData.isHexLiteral) 5785{ 5786 immutable hexString = hexStrImpl(hexData); 5787} 5788 5789/// ditto 5790template hexString(wstring hexData) 5791if (hexData.isHexLiteral) 5792{ 5793 immutable hexString = hexStrImpl(hexData); 5794} 5795 5796/// ditto 5797template hexString(dstring hexData) 5798if (hexData.isHexLiteral) 5799{ 5800 immutable hexString = hexStrImpl(hexData); 5801} 5802 5803/// 5804@safe unittest 5805{ 5806 // conversion at compile time 5807 auto string1 = hexString!"304A314B"; 5808 assert(string1 == "0J1K"); 5809 auto string2 = hexString!"304A314B"w; 5810 assert(string2 == "0J1K"w); 5811 auto string3 = hexString!"304A314B"d; 5812 assert(string3 == "0J1K"d); 5813} 5814 5815/* 5816 Takes a hexadecimal string literal and returns its representation. 5817 hexData is granted to be a valid string by the caller. 5818 C is granted to be a valid char type by the caller. 5819*/ 5820@safe nothrow pure 5821private auto hexStrImpl(String)(scope String hexData) 5822{ 5823 import std.ascii : isHexDigit; 5824 alias C = Unqual!(ElementEncodingType!String); 5825 C[] result; 5826 result.length = hexData.length / 2; 5827 size_t cnt; 5828 ubyte v; 5829 foreach (c; hexData) 5830 { 5831 if (c.isHexDigit) 5832 { 5833 ubyte x; 5834 if (c >= '0' && c <= '9') 5835 x = cast(ubyte)(c - '0'); 5836 else if (c >= 'a' && c <= 'f') 5837 x = cast(ubyte)(c - ('a' - 10)); 5838 else if (c >= 'A' && c <= 'F') 5839 x = cast(ubyte)(c - ('A' - 10)); 5840 if (cnt & 1) 5841 { 5842 v = cast(ubyte)((v << 4) | x); 5843 result[cnt / 2] = v; 5844 } 5845 else 5846 v = x; 5847 ++cnt; 5848 } 5849 } 5850 result.length = cnt / 2; 5851 return result; 5852} 5853 5854@safe unittest 5855{ 5856 // compile time 5857 assert(hexString!"46 47 48 49 4A 4B" == "FGHIJK"); 5858 assert(hexString!"30\r\n\t\f\v31 32 33 32 31 30" == "0123210"); 5859 assert(hexString!"ab cd" == hexString!"ABCD"); 5860} 5861 5862 5863/** 5864 * Convert integer to a range of characters. 5865 * Intended to be lightweight and fast. 5866 * 5867 * Params: 5868 * radix = 2, 8, 10, 16 5869 * Char = character type for output 5870 * letterCase = lower for deadbeef, upper for DEADBEEF 5871 * value = integer to convert. Can be uint or ulong. If radix is 10, can also be 5872 * int or long. 5873 * Returns: 5874 * Random access range with slicing and everything 5875 */ 5876 5877auto toChars(ubyte radix = 10, Char = char, LetterCase letterCase = LetterCase.lower, T)(T value) 5878 pure nothrow @nogc @safe 5879if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) && 5880 (is(Unqual!T == uint) || is(Unqual!T == ulong) || 5881 radix == 10 && (is(Unqual!T == int) || is(Unqual!T == long)))) 5882{ 5883 alias UT = Unqual!T; 5884 5885 static if (radix == 10) 5886 { 5887 /* uint.max is 42_9496_7295 5888 * int.max is 21_4748_3647 5889 * ulong.max is 1844_6744_0737_0955_1615 5890 * long.max is 922_3372_0368_5477_5807 5891 */ 5892 static struct Result 5893 { 5894 void initialize(UT value) 5895 { 5896 bool neg = false; 5897 if (value < 10) 5898 { 5899 if (value >= 0) 5900 { 5901 lwr = 0; 5902 upr = 1; 5903 buf[0] = cast(char)(cast(uint) value + '0'); 5904 return; 5905 } 5906 value = -value; 5907 neg = true; 5908 } 5909 auto i = cast(uint) buf.length - 1; 5910 while (cast(Unsigned!UT) value >= 10) 5911 { 5912 buf[i] = cast(ubyte)('0' + cast(Unsigned!UT) value % 10); 5913 value = unsigned(value) / 10; 5914 --i; 5915 } 5916 buf[i] = cast(char)(cast(uint) value + '0'); 5917 if (neg) 5918 { 5919 buf[i - 1] = '-'; 5920 --i; 5921 } 5922 lwr = i; 5923 upr = cast(uint) buf.length; 5924 } 5925 5926 @property size_t length() { return upr - lwr; } 5927 5928 alias opDollar = length; 5929 5930 @property bool empty() { return upr == lwr; } 5931 5932 @property Char front() { return buf[lwr]; } 5933 5934 void popFront() { ++lwr; } 5935 5936 @property Char back() { return buf[upr - 1]; } 5937 5938 void popBack() { --upr; } 5939 5940 @property Result save() { return this; } 5941 5942 Char opIndex(size_t i) { return buf[lwr + i]; } 5943 5944 Result opSlice(size_t lwr, size_t upr) 5945 { 5946 Result result = void; 5947 result.buf = buf; 5948 result.lwr = cast(uint)(this.lwr + lwr); 5949 result.upr = cast(uint)(this.lwr + upr); 5950 return result; 5951 } 5952 5953 private: 5954 uint lwr = void, upr = void; 5955 char[(UT.sizeof == 4) ? 10 + isSigned!T : 20] buf = void; 5956 } 5957 5958 Result result = void; 5959 result.initialize(value); 5960 return result; 5961 } 5962 else 5963 { 5964 static if (radix == 2) 5965 enum SHIFT = 1; 5966 else static if (radix == 8) 5967 enum SHIFT = 3; 5968 else static if (radix == 16) 5969 enum SHIFT = 4; 5970 else 5971 static assert(0); 5972 static struct Result 5973 { 5974 this(UT value) 5975 { 5976 this.value = value; 5977 5978 ubyte len = 1; 5979 while (value >>>= SHIFT) 5980 ++len; 5981 this.len = len; 5982 } 5983 5984 @property size_t length() { return len; } 5985 5986 @property bool empty() { return len == 0; } 5987 5988 @property Char front() { return opIndex(0); } 5989 5990 void popFront() { --len; } 5991 5992 @property Char back() { return opIndex(len - 1); } 5993 5994 void popBack() 5995 { 5996 value >>>= SHIFT; 5997 --len; 5998 } 5999 6000 @property Result save() { return this; } 6001 6002 Char opIndex(size_t i) 6003 { 6004 Char c = (value >>> ((len - i - 1) * SHIFT)) & ((1 << SHIFT) - 1); 6005 return cast(Char)((radix < 10 || c < 10) ? c + '0' 6006 : (letterCase == LetterCase.upper ? c + 'A' - 10 6007 : c + 'a' - 10)); 6008 } 6009 6010 Result opSlice(size_t lwr, size_t upr) 6011 { 6012 Result result = void; 6013 result.value = value >>> ((len - upr) * SHIFT); 6014 result.len = cast(ubyte)(upr - lwr); 6015 return result; 6016 } 6017 6018 private: 6019 UT value; 6020 ubyte len; 6021 } 6022 6023 return Result(value); 6024 } 6025} 6026 6027 6028@safe unittest 6029{ 6030 import std.array; 6031 import std.range; 6032 6033 { 6034 assert(toChars!2(0u).array == "0"); 6035 assert(toChars!2(0Lu).array == "0"); 6036 assert(toChars!2(1u).array == "1"); 6037 assert(toChars!2(1Lu).array == "1"); 6038 6039 auto r = toChars!2(2u); 6040 assert(r.length == 2); 6041 assert(r[0] == '1'); 6042 assert(r[1 .. 2].array == "0"); 6043 auto s = r.save; 6044 assert(r.array == "10"); 6045 assert(s.retro.array == "01"); 6046 } 6047 { 6048 assert(toChars!8(0u).array == "0"); 6049 assert(toChars!8(0Lu).array == "0"); 6050 assert(toChars!8(1u).array == "1"); 6051 assert(toChars!8(1234567Lu).array == "4553207"); 6052 6053 auto r = toChars!8(8u); 6054 assert(r.length == 2); 6055 assert(r[0] == '1'); 6056 assert(r[1 .. 2].array == "0"); 6057 auto s = r.save; 6058 assert(r.array == "10"); 6059 assert(s.retro.array == "01"); 6060 } 6061 { 6062 assert(toChars!10(0u).array == "0"); 6063 assert(toChars!10(0Lu).array == "0"); 6064 assert(toChars!10(1u).array == "1"); 6065 assert(toChars!10(1234567Lu).array == "1234567"); 6066 assert(toChars!10(uint.max).array == "4294967295"); 6067 assert(toChars!10(ulong.max).array == "18446744073709551615"); 6068 6069 auto r = toChars(10u); 6070 assert(r.length == 2); 6071 assert(r[0] == '1'); 6072 assert(r[1 .. 2].array == "0"); 6073 auto s = r.save; 6074 assert(r.array == "10"); 6075 assert(s.retro.array == "01"); 6076 } 6077 { 6078 assert(toChars!10(0).array == "0"); 6079 assert(toChars!10(0L).array == "0"); 6080 assert(toChars!10(1).array == "1"); 6081 assert(toChars!10(1234567L).array == "1234567"); 6082 assert(toChars!10(int.max).array == "2147483647"); 6083 assert(toChars!10(long.max).array == "9223372036854775807"); 6084 assert(toChars!10(-int.max).array == "-2147483647"); 6085 assert(toChars!10(-long.max).array == "-9223372036854775807"); 6086 assert(toChars!10(int.min).array == "-2147483648"); 6087 assert(toChars!10(long.min).array == "-9223372036854775808"); 6088 6089 auto r = toChars!10(10); 6090 assert(r.length == 2); 6091 assert(r[0] == '1'); 6092 assert(r[1 .. 2].array == "0"); 6093 auto s = r.save; 6094 assert(r.array == "10"); 6095 assert(s.retro.array == "01"); 6096 } 6097 { 6098 assert(toChars!(16)(0u).array == "0"); 6099 assert(toChars!(16)(0Lu).array == "0"); 6100 assert(toChars!(16)(10u).array == "a"); 6101 assert(toChars!(16, char, LetterCase.upper)(0x12AF34567Lu).array == "12AF34567"); 6102 6103 auto r = toChars!(16)(16u); 6104 assert(r.length == 2); 6105 assert(r[0] == '1'); 6106 assert(r[1 .. 2].array == "0"); 6107 auto s = r.save; 6108 assert(r.array == "10"); 6109 assert(s.retro.array == "01"); 6110 } 6111} 6112 6113@safe unittest // opSlice (issue 16192) 6114{ 6115 import std.meta : AliasSeq; 6116 6117 static struct Test { ubyte radix; uint number; } 6118 6119 alias tests = AliasSeq!( 6120 Test(2, 0b1_0110_0111u), 6121 Test(2, 0b10_1100_1110u), 6122 Test(8, octal!123456701u), 6123 Test(8, octal!1234567012u), 6124 Test(10, 123456789u), 6125 Test(10, 1234567890u), 6126 Test(16, 0x789ABCDu), 6127 Test(16, 0x789ABCDEu), 6128 ); 6129 6130 foreach (test; tests) 6131 { 6132 enum ubyte radix = test.radix; 6133 auto original = toChars!radix(test.number); 6134 6135 // opSlice vs popFront 6136 auto r = original.save; 6137 size_t i = 0; 6138 for (; !r.empty; r.popFront(), ++i) 6139 { 6140 assert(original[i .. original.length].tupleof == r.tupleof); 6141 // tupleof is used to work around issue 16216. 6142 } 6143 6144 // opSlice vs popBack 6145 r = original.save; 6146 i = 0; 6147 for (; !r.empty; r.popBack(), ++i) 6148 { 6149 assert(original[0 .. original.length - i].tupleof == r.tupleof); 6150 } 6151 6152 // opSlice vs both popFront and popBack 6153 r = original.save; 6154 i = 0; 6155 for (; r.length >= 2; r.popFront(), r.popBack(), ++i) 6156 { 6157 assert(original[i .. original.length - i].tupleof == r.tupleof); 6158 } 6159 } 6160} 6161