1 /** 2 This module is a submodule of $(MREF std, range). 3 4 It defines the bidirectional and forward range primitives for arrays: 5 $(LREF empty), $(LREF front), $(LREF back), $(LREF popFront), $(LREF popBack) and $(LREF save). 6 7 It provides basic range functionality by defining several templates for testing 8 whether a given object is a range, and what kind of range it is: 9 10 $(SCRIPT inhibitQuickIndex = 1;) 11 $(DIVC quickindex, 12 $(BOOKTABLE , 13 $(TR $(TD $(LREF isInputRange)) 14 $(TD Tests if something is an $(I input range), defined to be 15 something from which one can sequentially read data using the 16 primitives `front`, `popFront`, and `empty`. 17 )) 18 $(TR $(TD $(LREF isOutputRange)) 19 $(TD Tests if something is an $(I output range), defined to be 20 something to which one can sequentially write data using the 21 $(LREF put) primitive. 22 )) 23 $(TR $(TD $(LREF isForwardRange)) 24 $(TD Tests if something is a $(I forward range), defined to be an 25 input range with the additional capability that one can save one's 26 current position with the `save` primitive, thus allowing one to 27 iterate over the same range multiple times. 28 )) 29 $(TR $(TD $(LREF isBidirectionalRange)) 30 $(TD Tests if something is a $(I bidirectional range), that is, a 31 forward range that allows reverse traversal using the primitives $(D 32 back) and `popBack`. 33 )) 34 $(TR $(TD $(LREF isRandomAccessRange)) 35 $(TD Tests if something is a $(I random access range), which is a 36 bidirectional range that also supports the array subscripting 37 operation via the primitive `opIndex`. 38 )) 39 )) 40 41 It also provides number of templates that test for various range capabilities: 42 43 $(BOOKTABLE , 44 $(TR $(TD $(LREF hasMobileElements)) 45 $(TD Tests if a given range's elements can be moved around using the 46 primitives `moveFront`, `moveBack`, or `moveAt`. 47 )) 48 $(TR $(TD $(LREF ElementType)) 49 $(TD Returns the element type of a given range. 50 )) 51 $(TR $(TD $(LREF ElementEncodingType)) 52 $(TD Returns the encoding element type of a given range. 53 )) 54 $(TR $(TD $(LREF hasSwappableElements)) 55 $(TD Tests if a range is a forward range with swappable elements. 56 )) 57 $(TR $(TD $(LREF hasAssignableElements)) 58 $(TD Tests if a range is a forward range with mutable elements. 59 )) 60 $(TR $(TD $(LREF hasLvalueElements)) 61 $(TD Tests if a range is a forward range with elements that can be 62 passed by reference and have their address taken. 63 )) 64 $(TR $(TD $(LREF hasLength)) 65 $(TD Tests if a given range has the `length` attribute. 66 )) 67 $(TR $(TD $(LREF isInfinite)) 68 $(TD Tests if a given range is an $(I infinite range). 69 )) 70 $(TR $(TD $(LREF hasSlicing)) 71 $(TD Tests if a given range supports the array slicing operation $(D 72 R[x .. y]). 73 )) 74 ) 75 76 Finally, it includes some convenience functions for manipulating ranges: 77 78 $(BOOKTABLE , 79 $(TR $(TD $(LREF popFrontN)) 80 $(TD Advances a given range by up to $(I n) elements. 81 )) 82 $(TR $(TD $(LREF popBackN)) 83 $(TD Advances a given bidirectional range from the right by up to 84 $(I n) elements. 85 )) 86 $(TR $(TD $(LREF popFrontExactly)) 87 $(TD Advances a given range by up exactly $(I n) elements. 88 )) 89 $(TR $(TD $(LREF popBackExactly)) 90 $(TD Advances a given bidirectional range from the right by exactly 91 $(I n) elements. 92 )) 93 $(TR $(TD $(LREF moveFront)) 94 $(TD Removes the front element of a range. 95 )) 96 $(TR $(TD $(LREF moveBack)) 97 $(TD Removes the back element of a bidirectional range. 98 )) 99 $(TR $(TD $(LREF moveAt)) 100 $(TD Removes the $(I i)'th element of a random-access range. 101 )) 102 $(TR $(TD $(LREF walkLength)) 103 $(TD Computes the length of any range in O(n) time. 104 )) 105 $(TR $(TD $(LREF put)) 106 $(TD Outputs element `e` to a range. 107 )) 108 ) 109 110 Source: $(PHOBOSSRC std/range/primitives.d) 111 112 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 113 114 Authors: $(HTTP erdani.com, Andrei Alexandrescu), David Simcha, and 115 $(HTTP jmdavisprog.com, Jonathan M Davis). Credit for some of the ideas 116 in building this module goes to 117 $(HTTP fantascienza.net/leonardo/so/, Leonardo Maffi). 118 */ 119 module std.range.primitives; 120 121 import std.traits; 122 123 /** 124 Returns `true` if `R` is an input range. An input range must 125 define the primitives `empty`, `popFront`, and `front`. The 126 following code should compile for any input range. 127 128 ---- 129 R r; // can define a range object 130 if (r.empty) {} // can test for empty 131 r.popFront(); // can invoke popFront() 132 auto h = r.front; // can get the front of the range of non-void type 133 ---- 134 135 The following are rules of input ranges are assumed to hold true in all 136 Phobos code. These rules are not checkable at compile-time, so not conforming 137 to these rules when writing ranges or range based code will result in 138 undefined behavior. 139 140 $(UL 141 $(LI `r.empty` returns `false` if and only if there is more data 142 available in the range.) 143 $(LI `r.empty` evaluated multiple times, without calling 144 `r.popFront`, or otherwise mutating the range object or the 145 underlying data, yields the same result for every evaluation.) 146 $(LI `r.front` returns the current element in the range. 147 It may return by value or by reference.) 148 $(LI `r.front` can be legally evaluated if and only if evaluating 149 `r.empty` has, or would have, equaled `false`.) 150 $(LI `r.front` evaluated multiple times, without calling 151 `r.popFront`, or otherwise mutating the range object or the 152 underlying data, yields the same result for every evaluation.) 153 $(LI `r.popFront` advances to the next element in the range.) 154 $(LI `r.popFront` can be called if and only if evaluating `r.empty` 155 has, or would have, equaled `false`.) 156 ) 157 158 Also, note that Phobos code assumes that the primitives `r.front` and 159 `r.empty` are $(BIGOH 1) time complexity wise or "cheap" in terms of 160 running time. $(BIGOH) statements in the documentation of range functions 161 are made with this assumption. 162 163 See_Also: 164 The header of $(MREF std,range) for tutorials on ranges. 165 166 Params: 167 R = type to be tested 168 169 Returns: 170 `true` if R is an input range, `false` if not 171 */ 172 enum bool isInputRange(R) = 173 is(typeof(R.init) == R) 174 && is(ReturnType!((R r) => r.empty) == bool) 175 && is(typeof((return ref R r) => r.front)) 176 && !is(ReturnType!((R r) => r.front) == void) 177 && is(typeof((R r) => r.popFront)); 178 179 /// 180 @safe unittest 181 { 182 struct A {} 183 struct B 184 { 185 void popFront(); 186 @property bool empty(); 187 @property int front(); 188 } 189 static assert(!isInputRange!A); 190 static assert( isInputRange!B); 191 static assert( isInputRange!(int[])); 192 static assert( isInputRange!(char[])); 193 static assert(!isInputRange!(char[4])); 194 static assert( isInputRange!(inout(int)[])); 195 196 static struct NotDefaultConstructible 197 { 198 @disable this(); 199 void popFront(); 200 @property bool empty(); 201 @property int front(); 202 } 203 static assert( isInputRange!NotDefaultConstructible); 204 205 static struct NotDefaultConstructibleOrCopyable 206 { 207 @disable this(); 208 @disable this(this); 209 void popFront(); 210 @property bool empty(); 211 @property int front(); 212 } 213 static assert(isInputRange!NotDefaultConstructibleOrCopyable); 214 215 static struct Frontless 216 { 217 void popFront(); 218 @property bool empty(); 219 } 220 static assert(!isInputRange!Frontless); 221 222 static struct VoidFront 223 { 224 void popFront(); 225 @property bool empty(); 226 void front(); 227 } 228 static assert(!isInputRange!VoidFront); 229 } 230 231 @safe unittest 232 { 233 import std.algorithm.comparison : equal; 234 235 static struct R 236 { 237 static struct Front 238 { 239 R* impl; 240 @property int value() { return impl._front; } 241 alias value this; 242 } 243 244 int _front; 245 246 @property bool empty() { return _front >= 3; } 247 @property auto front() { return Front(&this); } 248 void popFront() { _front++; } 249 } 250 R r; 251 252 static assert(isInputRange!R); 253 assert(r.equal([ 0, 1, 2 ])); 254 } 255 256 /+ 257 puts the whole raw element `e` into `r`. doPut will not attempt to 258 iterate, slice or transcode `e` in any way shape or form. It will $(B only) 259 call the correct primitive (`r.put(e)`, $(D r.front = e) or 260 `r(e)` once. 261 262 This can be important when `e` needs to be placed in `r` unchanged. 263 Furthermore, it can be useful when working with `InputRange`s, as doPut 264 guarantees that no more than a single element will be placed. 265 +/ 266 private void doPut(R, E)(ref R r, auto ref E e) 267 { 268 static if (is(PointerTarget!R == struct)) 269 enum usingPut = hasMember!(PointerTarget!R, "put"); 270 else 271 enum usingPut = hasMember!(R, "put"); 272 273 static if (usingPut) 274 { 275 static assert(is(typeof(r.put(e))), 276 "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); 277 r.put(e); 278 } 279 else static if (isNarrowString!R && is(const(E) == const(typeof(r[0])))) 280 { 281 // one character, we can put it 282 r[0] = e; 283 r = r[1 .. $]; 284 } 285 else static if (isNarrowString!R && isNarrowString!E && is(typeof(r[] = e))) 286 { 287 // slice assign. Note that this is a duplicate from put, but because 288 // putChar uses doPut exclusively, we have to copy it here. 289 immutable len = e.length; 290 r[0 .. len] = e; 291 r = r[len .. $]; 292 } 293 else static if (isInputRange!R) 294 { 295 static assert(is(typeof(r.front = e)), 296 "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); 297 r.front = e; 298 r.popFront(); 299 } 300 else static if (is(typeof(r(e)))) 301 { 302 r(e); 303 } 304 else 305 { 306 static assert(false, 307 "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); 308 } 309 } 310 311 @safe unittest 312 { 313 static assert(!isNativeOutputRange!(int, int)); 314 static assert( isNativeOutputRange!(int[], int)); 315 static assert(!isNativeOutputRange!(int[][], int)); 316 317 static assert(!isNativeOutputRange!(int, int[])); 318 static assert(!isNativeOutputRange!(int[], int[])); 319 static assert( isNativeOutputRange!(int[][], int[])); 320 321 static assert(!isNativeOutputRange!(int, int[][])); 322 static assert(!isNativeOutputRange!(int[], int[][])); 323 static assert(!isNativeOutputRange!(int[][], int[][])); 324 325 static assert(!isNativeOutputRange!(int[4], int)); 326 static assert( isNativeOutputRange!(int[4][], int)); //Scary! 327 static assert( isNativeOutputRange!(int[4][], int[4])); 328 329 static assert( isNativeOutputRange!( char[], char)); 330 static assert(!isNativeOutputRange!( char[], dchar)); 331 static assert( isNativeOutputRange!(dchar[], char)); 332 static assert( isNativeOutputRange!(dchar[], dchar)); 333 334 } 335 336 /++ 337 Outputs `e` to `r`. The exact effect is dependent upon the two 338 types. Several cases are accepted, as described below. The code snippets 339 are attempted in order, and the first to compile "wins" and gets 340 evaluated. 341 342 In this table "doPut" is a method that places `e` into `r`, using the 343 correct primitive: `r.put(e)` if `R` defines `put`, $(D r.front = e) 344 if `r` is an input range (followed by `r.popFront()`), or `r(e)` 345 otherwise. 346 347 $(BOOKTABLE , 348 $(TR 349 $(TH Code Snippet) 350 $(TH Scenario) 351 ) 352 $(TR 353 $(TD `r.doPut(e);`) 354 $(TD `R` specifically accepts an `E`.) 355 ) 356 $(TR 357 $(TD $(D r.doPut([ e ]);)) 358 $(TD `R` specifically accepts an `E[]`.) 359 ) 360 $(TR 361 $(TD `r.putChar(e);`) 362 $(TD `R` accepts some form of string or character. put will 363 transcode the character `e` accordingly.) 364 ) 365 $(TR 366 $(TD $(D for (; !e.empty; e.popFront()) put(r, e.front);)) 367 $(TD Copying range `E` into `R`.) 368 ) 369 ) 370 371 Tip: `put` should $(I not) be used "UFCS-style", e.g. `r.put(e)`. 372 Doing this may call `R.put` directly, by-passing any transformation 373 feature provided by `Range.put`. $(D put(r, e)) is prefered. 374 +/ 375 void put(R, E)(ref R r, E e) 376 { 377 //First level: simply straight up put. 378 static if (is(typeof(doPut(r, e)))) 379 { 380 doPut(r, e); 381 } 382 //Optional optimization block for straight up array to array copy. 383 else static if (isDynamicArray!R && 384 !isAutodecodableString!R && 385 isDynamicArray!E && 386 is(typeof(r[] = e[]))) 387 { 388 immutable len = e.length; 389 r[0 .. len] = e[]; 390 r = r[len .. $]; 391 } 392 //Accepts E[] ? 393 else static if (is(typeof(doPut(r, [e]))) && !isDynamicArray!R) 394 { 395 if (__ctfe) 396 { 397 E[1] arr = [e]; 398 doPut(r, arr[]); 399 } 400 else 401 doPut(r, (ref e) @trusted { return (&e)[0 .. 1]; }(e)); 402 } 403 //special case for char to string. 404 else static if (isSomeChar!E && is(typeof(putChar(r, e)))) 405 { 406 putChar(r, e); 407 } 408 //Extract each element from the range 409 //We can use "put" here, so we can recursively test a RoR of E. 410 else static if (isInputRange!E && is(typeof(put(r, e.front)))) 411 { 412 //Special optimization: If E is a narrow string, and r accepts characters no-wider than the string's 413 //Then simply feed the characters 1 by 1. 414 static if (isAutodecodableString!E && !isAggregateType!E && ( 415 (is(E : const char[]) && is(typeof(doPut(r, char.max))) && !is(typeof(doPut(r, dchar.max))) && 416 !is(typeof(doPut(r, wchar.max)))) || 417 (is(E : const wchar[]) && is(typeof(doPut(r, wchar.max))) && !is(typeof(doPut(r, dchar.max)))) ) ) 418 { 419 foreach (c; e) 420 doPut(r, c); 421 } 422 else 423 { 424 for (; !e.empty; e.popFront()) 425 put(r, e.front); 426 } 427 } 428 else 429 { 430 static assert(false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); 431 } 432 } 433 434 /** 435 * When an output range's `put` method only accepts elements of type 436 * `T`, use the global `put` to handle outputting a `T[]` to the range 437 * or vice-versa. 438 */ 439 @safe pure unittest 440 { 441 import std.traits : isSomeChar; 442 443 static struct A 444 { 445 string data; 446 447 void put(C)(C c) if (isSomeChar!C) 448 { 449 data ~= c; 450 } 451 } 452 static assert(isOutputRange!(A, char)); 453 454 auto a = A(); 455 put(a, "Hello"); 456 assert(a.data == "Hello"); 457 } 458 459 /** 460 * `put` treats dynamic arrays as array slices, and will call `popFront` 461 * on the slice after an element has been copied. 462 * 463 * Be sure to save the position of the array before calling `put`. 464 */ 465 @safe pure nothrow unittest 466 { 467 int[] a = [1, 2, 3], b = [10, 20]; 468 auto c = a; 469 put(a, b); 470 assert(c == [10, 20, 3]); 471 // at this point, a was advanced twice, so it only contains 472 // its last element while c represents the whole array 473 assert(a == [3]); 474 } 475 476 /** 477 * It's also possible to `put` any width strings or characters into narrow 478 * strings -- put does the conversion for you. 479 * 480 * Note that putting the same width character as the target buffer type is 481 * `nothrow`, but transcoding can throw a $(REF UTFException, std, utf). 482 */ 483 @safe pure unittest 484 { 485 // the elements must be mutable, so using string or const(char)[] 486 // won't compile 487 char[] s1 = new char[13]; 488 auto r1 = s1; 489 put(r1, "Hello, World!"w); 490 assert(s1 == "Hello, World!"); 491 } 492 493 @safe pure nothrow unittest 494 { 495 // same thing, just using same character width. 496 char[] s1 = new char[13]; 497 auto r1 = s1; 498 put(r1, "Hello, World!"); 499 assert(s1 == "Hello, World!"); 500 } 501 502 503 @safe pure nothrow @nogc unittest 504 { 505 static struct R() { void put(scope const(char)[]) {} } 506 R!() r; 507 put(r, 'a'); 508 } 509 510 //Helper function to handle chars as quickly and as elegantly as possible 511 //Assumes r.put(e)/r(e) has already been tested 512 private void putChar(R, E)(ref R r, E e) 513 if (isSomeChar!E) 514 { 515 // https://issues.dlang.org/show_bug.cgi?id=9186: Can't use (E[]).init 516 ref const( char)[] cstringInit(); 517 ref const(wchar)[] wstringInit(); 518 ref const(dchar)[] dstringInit(); 519 520 enum csCond = is(typeof(doPut(r, cstringInit()))); 521 enum wsCond = is(typeof(doPut(r, wstringInit()))); 522 enum dsCond = is(typeof(doPut(r, dstringInit()))); 523 524 //Use "max" to avoid static type demotion 525 enum ccCond = is(typeof(doPut(r, char.max))); 526 enum wcCond = is(typeof(doPut(r, wchar.max))); 527 //enum dcCond = is(typeof(doPut(r, dchar.max))); 528 529 //Fast transform a narrow char into a wider string 530 static if ((wsCond && E.sizeof < wchar.sizeof) || (dsCond && E.sizeof < dchar.sizeof)) 531 { 532 enum w = wsCond && E.sizeof < wchar.sizeof; 533 Select!(w, wchar, dchar) c = e; 534 typeof(c)[1] arr = [c]; 535 doPut(r, arr[]); 536 } 537 //Encode a wide char into a narrower string 538 else static if (wsCond || csCond) 539 { 540 import std.utf : encode; 541 /+static+/ Select!(wsCond, wchar[2], char[4]) buf; //static prevents purity. 542 doPut(r, buf[0 .. encode(buf, e)]); 543 } 544 //Slowly encode a wide char into a series of narrower chars 545 else static if (wcCond || ccCond) 546 { 547 import std.encoding : encode; 548 alias C = Select!(wcCond, wchar, char); 549 encode!(C, R)(e, r); 550 } 551 else 552 { 553 static assert(false, "Cannot put a " ~ E.stringof ~ " into a " ~ R.stringof ~ "."); 554 } 555 } 556 557 pure @safe unittest 558 { 559 auto f = delegate (const(char)[]) {}; 560 putChar(f, cast(dchar)'a'); 561 } 562 563 564 @safe pure unittest 565 { 566 static struct R() { void put(scope const(char)[]) {} } 567 R!() r; 568 putChar(r, 'a'); 569 } 570 571 @safe unittest 572 { 573 struct A {} 574 static assert(!isInputRange!(A)); 575 struct B 576 { 577 void put(int) {} 578 } 579 B b; 580 put(b, 5); 581 } 582 583 @safe unittest 584 { 585 int[] a = new int[10]; 586 int b; 587 static assert(isInputRange!(typeof(a))); 588 put(a, b); 589 } 590 591 @safe unittest 592 { 593 void myprint(scope const(char)[] s) { } 594 auto r = &myprint; 595 put(r, 'a'); 596 } 597 598 @safe unittest 599 { 600 int[] a = new int[10]; 601 static assert(!__traits(compiles, put(a, 1.0L))); 602 put(a, 1); 603 assert(a.length == 9); 604 /* 605 * a[0] = 65; // OK 606 * a[0] = 'A'; // OK 607 * a[0] = "ABC"[0]; // OK 608 * put(a, "ABC"); // OK 609 */ 610 put(a, "ABC"); 611 assert(a.length == 6); 612 } 613 614 @safe unittest 615 { 616 char[] a = new char[10]; 617 static assert(!__traits(compiles, put(a, 1.0L))); 618 static assert(!__traits(compiles, put(a, 1))); 619 //char[] is now an output range for char, wchar, dchar, and ranges of such. 620 static assert(__traits(compiles, putChar(a, 'a'))); 621 static assert(__traits(compiles, put(a, wchar('a')))); 622 static assert(__traits(compiles, put(a, dchar('a')))); 623 static assert(__traits(compiles, put(a, "ABC"))); 624 static assert(__traits(compiles, put(a, "ABC"w))); 625 static assert(__traits(compiles, put(a, "ABC"d))); 626 } 627 628 @safe unittest 629 { 630 // attempt putting into narrow strings by transcoding 631 char[] a = new char[10]; 632 auto b = a; 633 put(a, "ABC"w); 634 assert(b[0 .. 3] == "ABC"); 635 assert(a.length == 7); 636 637 a = b; // reset 638 put(a, 'λ'); 639 assert(b[0 .. 2] == "λ"); 640 assert(a.length == 8); 641 642 a = b; // reset 643 put(a, "ABC"d); 644 assert(b[0 .. 3] == "ABC"); 645 assert(a.length == 7); 646 647 a = b; // reset 648 put(a, '𐐷'); 649 assert(b[0 .. 4] == "𐐷"); 650 assert(a.length == 6); 651 652 wchar[] aw = new wchar[10]; 653 auto bw = aw; 654 put(aw, "ABC"); 655 assert(bw[0 .. 3] == "ABC"w); 656 assert(aw.length == 7); 657 658 aw = bw; // reset 659 put(aw, 'λ'); 660 assert(bw[0 .. 1] == "λ"w); 661 assert(aw.length == 9); 662 663 aw = bw; // reset 664 put(aw, "ABC"d); 665 assert(bw[0 .. 3] == "ABC"w); 666 assert(aw.length == 7); 667 668 aw = bw; // reset 669 put(aw, '𐐷'); 670 assert(bw[0 .. 2] == "𐐷"w); 671 assert(aw.length == 8); 672 673 aw = bw; // reset 674 put(aw, "𐐷"); // try transcoding from char[] 675 assert(bw[0 .. 2] == "𐐷"w); 676 assert(aw.length == 8); 677 } 678 679 @safe unittest 680 { 681 int[][] a = new int[][10]; 682 int[] b = new int[10]; 683 int c; 684 put(b, c); 685 assert(b.length == 9); 686 put(a, b); 687 assert(a.length == 9); 688 static assert(!__traits(compiles, put(a, c))); 689 } 690 691 @safe unittest 692 { 693 int[][] a = new int[][](3); 694 int[] b = [1]; 695 auto aa = a; 696 put(aa, b); 697 assert(aa == [[], []]); 698 assert(a == [[1], [], []]); 699 int[][3] c = [2]; 700 aa = a; 701 put(aa, c[]); 702 assert(aa.empty); 703 assert(a == [[2], [2], [2]]); 704 } 705 706 @safe unittest 707 { 708 // Test fix for bug 7476. 709 struct LockingTextWriter 710 { 711 void put(dchar c){} 712 } 713 struct RetroResult 714 { 715 bool end = false; 716 @property bool empty() const { return end; } 717 @property dchar front(){ return 'a'; } 718 void popFront(){ end = true; } 719 } 720 LockingTextWriter w; 721 RetroResult re; 722 put(w, re); 723 } 724 725 @system unittest 726 { 727 import std.conv : to; 728 import std.meta : AliasSeq; 729 import std.typecons : tuple; 730 731 static struct PutC(C) 732 { 733 string result; 734 void put(const(C) c) { result ~= to!string((&c)[0 .. 1]); } 735 } 736 static struct PutS(C) 737 { 738 string result; 739 void put(const(C)[] s) { result ~= to!string(s); } 740 } 741 static struct PutSS(C) 742 { 743 string result; 744 void put(const(C)[][] ss) 745 { 746 foreach (s; ss) 747 result ~= to!string(s); 748 } 749 } 750 751 PutS!char p; 752 putChar(p, cast(dchar)'a'); 753 754 //Source Char 755 static foreach (SC; AliasSeq!(char, wchar, dchar)) 756 {{ 757 SC ch = 'I'; 758 dchar dh = '♥'; 759 immutable(SC)[] s = "日本語!"; 760 immutable(SC)[][] ss = ["日本語", "が", "好き", "ですか", "?"]; 761 762 //Target Char 763 static foreach (TC; AliasSeq!(char, wchar, dchar)) 764 { 765 //Testing PutC and PutS 766 static foreach (Type; AliasSeq!(PutC!TC, PutS!TC)) 767 {{ 768 Type type; 769 auto sink = new Type(); 770 771 //Testing put and sink 772 foreach (value ; tuple(type, sink)) 773 { 774 put(value, ch); 775 assert(value.result == "I"); 776 put(value, dh); 777 assert(value.result == "I♥"); 778 put(value, s); 779 assert(value.result == "I♥日本語!"); 780 put(value, ss); 781 assert(value.result == "I♥日本語!日本語が好きですか?"); 782 } 783 }} 784 } 785 }} 786 } 787 788 @safe unittest 789 { 790 static struct CharRange 791 { 792 char c; 793 enum empty = false; 794 void popFront(){} 795 ref char front() return @property 796 { 797 return c; 798 } 799 } 800 CharRange c; 801 put(c, cast(dchar)'H'); 802 put(c, "hello"d); 803 } 804 805 // https://issues.dlang.org/show_bug.cgi?id=9823 806 @system unittest 807 { 808 const(char)[] r; 809 void delegate(const(char)[]) dg = (s) { r = s; }; 810 put(dg, ["ABC"]); 811 assert(r == "ABC"); 812 } 813 814 // https://issues.dlang.org/show_bug.cgi?id=10571 815 @safe unittest 816 { 817 import std.format; 818 string buf; 819 formattedWrite((scope const(char)[] s) { buf ~= s; }, "%s", "hello"); 820 assert(buf == "hello"); 821 } 822 823 @safe unittest 824 { 825 import std.format; 826 import std.meta : AliasSeq; 827 struct PutC(C) 828 { 829 void put(C){} 830 } 831 struct PutS(C) 832 { 833 void put(const(C)[]){} 834 } 835 struct CallC(C) 836 { 837 void opCall(C){} 838 } 839 struct CallS(C) 840 { 841 void opCall(const(C)[]){} 842 } 843 struct FrontC(C) 844 { 845 enum empty = false; 846 auto front()@property{return C.init;} 847 void front(C)@property{} 848 void popFront(){} 849 } 850 struct FrontS(C) 851 { 852 enum empty = false; 853 auto front()@property{return C[].init;} 854 void front(const(C)[])@property{} 855 void popFront(){} 856 } 857 void foo() 858 { 859 static foreach (C; AliasSeq!(char, wchar, dchar)) 860 {{ 861 formattedWrite((C c){}, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 862 formattedWrite((const(C)[]){}, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 863 formattedWrite(PutC!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 864 formattedWrite(PutS!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 865 CallC!C callC; 866 CallS!C callS; 867 formattedWrite(callC, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 868 formattedWrite(callS, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 869 formattedWrite(FrontC!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 870 formattedWrite(FrontS!C(), "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 871 }} 872 formattedWrite((dchar[]).init, "", 1, 'a', cast(wchar)'a', cast(dchar)'a', "a"c, "a"w, "a"d); 873 } 874 } 875 876 /+ 877 Returns `true` if `R` is a native output range for elements of type 878 `E`. An output range is defined functionally as a range that 879 supports the operation $(D doPut(r, e)) as defined above. if $(D doPut(r, e)) 880 is valid, then `put(r,e)` will have the same behavior. 881 882 The two guarantees isNativeOutputRange gives over the larger `isOutputRange` 883 are: 884 1: `e` is $(B exactly) what will be placed (not `[e]`, for example). 885 2: if `E` is a non $(empty) `InputRange`, then placing `e` is 886 guaranteed to not overflow the range. 887 +/ 888 package(std) enum bool isNativeOutputRange(R, E) = 889 is(typeof(doPut(lvalueOf!R, lvalueOf!E))); 890 891 @safe unittest 892 { 893 int[] r = new int[](4); 894 static assert(isInputRange!(int[])); 895 static assert( isNativeOutputRange!(int[], int)); 896 static assert(!isNativeOutputRange!(int[], int[])); 897 static assert( isOutputRange!(int[], int[])); 898 899 if (!r.empty) 900 put(r, 1); //guaranteed to succeed 901 if (!r.empty) 902 put(r, [1, 2]); //May actually error out. 903 } 904 905 /++ 906 Returns `true` if `R` is an output range for elements of type 907 `E`. An output range is defined functionally as a range that 908 supports the operation $(D put(r, e)) as defined above. 909 910 See_Also: 911 The header of $(MREF std,range) for tutorials on ranges. 912 +/ 913 enum bool isOutputRange(R, E) = 914 is(typeof(put(lvalueOf!R, lvalueOf!E))); 915 916 /// 917 @safe unittest 918 { 919 void myprint(scope const(char)[] s) { } 920 static assert(isOutputRange!(typeof(&myprint), char)); 921 922 static assert( isOutputRange!(char[], char)); 923 static assert( isOutputRange!(dchar[], wchar)); 924 static assert( isOutputRange!(dchar[], dchar)); 925 } 926 927 @safe unittest 928 { 929 import std.array; 930 import std.stdio : writeln; 931 932 auto app = appender!string(); 933 string s; 934 static assert( isOutputRange!(Appender!string, string)); 935 static assert( isOutputRange!(Appender!string*, string)); 936 static assert(!isOutputRange!(Appender!string, int)); 937 static assert( isOutputRange!(wchar[], wchar)); 938 static assert( isOutputRange!(dchar[], char)); 939 static assert( isOutputRange!(dchar[], string)); 940 static assert( isOutputRange!(dchar[], wstring)); 941 static assert( isOutputRange!(dchar[], dstring)); 942 943 static assert(!isOutputRange!(const(int)[], int)); 944 static assert(!isOutputRange!(inout(int)[], int)); 945 } 946 947 948 /** 949 Returns `true` if `R` is a forward range. A forward range is an 950 input range `r` that can save "checkpoints" by saving `r.save` 951 to another value of type `R`. Notable examples of input ranges that 952 are $(I not) forward ranges are file/socket ranges; copying such a 953 range will not save the position in the stream, and they most likely 954 reuse an internal buffer as the entire stream does not sit in 955 memory. Subsequently, advancing either the original or the copy will 956 advance the stream, so the copies are not independent. 957 958 The following code should compile for any forward range. 959 960 ---- 961 static assert(isInputRange!R); 962 R r1; 963 auto s1 = r1.save; 964 static assert(is(typeof(s1) == R)); 965 ---- 966 967 Saving a range is not duplicating it; in the example above, `r1` 968 and `r2` still refer to the same underlying data. They just 969 navigate that data independently. 970 971 The semantics of a forward range (not checkable during compilation) 972 are the same as for an input range, with the additional requirement 973 that backtracking must be possible by saving a copy of the range 974 object with `save` and using it later. 975 976 See_Also: 977 The header of $(MREF std,range) for tutorials on ranges. 978 */ 979 enum bool isForwardRange(R) = isInputRange!R 980 && is(ReturnType!((R r) => r.save) == R); 981 982 /// 983 @safe unittest 984 { 985 static assert(!isForwardRange!(int)); 986 static assert( isForwardRange!(int[])); 987 static assert( isForwardRange!(inout(int)[])); 988 } 989 990 @safe unittest 991 { 992 // BUG 14544 993 struct R14544 994 { 995 int front() { return 0;} 996 void popFront() {} 997 bool empty() { return false; } 998 R14544 save() {return this;} 999 } 1000 1001 static assert( isForwardRange!R14544 ); 1002 } 1003 1004 /** 1005 Returns `true` if `R` is a bidirectional range. A bidirectional 1006 range is a forward range that also offers the primitives `back` and 1007 `popBack`. The following code should compile for any bidirectional 1008 range. 1009 1010 The semantics of a bidirectional range (not checkable during 1011 compilation) are assumed to be the following (`r` is an object of 1012 type `R`): 1013 1014 $(UL $(LI `r.back` returns (possibly a reference to) the last 1015 element in the range. Calling `r.back` is allowed only if calling 1016 `r.empty` has, or would have, returned `false`.)) 1017 1018 See_Also: 1019 The header of $(MREF std,range) for tutorials on ranges. 1020 */ 1021 enum bool isBidirectionalRange(R) = isForwardRange!R 1022 && is(typeof((R r) => r.popBack)) 1023 && is(ReturnType!((R r) => r.back) == ElementType!R); 1024 1025 /// 1026 @safe unittest 1027 { 1028 alias R = int[]; 1029 R r = [0,1]; 1030 static assert(isForwardRange!R); // is forward range 1031 r.popBack(); // can invoke popBack 1032 auto t = r.back; // can get the back of the range 1033 auto w = r.front; 1034 static assert(is(typeof(t) == typeof(w))); // same type for front and back 1035 } 1036 1037 @safe unittest 1038 { 1039 struct A {} 1040 struct B 1041 { 1042 void popFront(); 1043 @property bool empty(); 1044 @property int front(); 1045 } 1046 struct C 1047 { 1048 @property bool empty(); 1049 @property C save(); 1050 void popFront(); 1051 @property int front(); 1052 void popBack(); 1053 @property int back(); 1054 } 1055 static assert(!isBidirectionalRange!(A)); 1056 static assert(!isBidirectionalRange!(B)); 1057 static assert( isBidirectionalRange!(C)); 1058 static assert( isBidirectionalRange!(int[])); 1059 static assert( isBidirectionalRange!(char[])); 1060 static assert( isBidirectionalRange!(inout(int)[])); 1061 } 1062 1063 /** 1064 Returns `true` if `R` is a random-access range. A random-access 1065 range is a bidirectional range that also offers the primitive $(D 1066 opIndex), OR an infinite forward range that offers `opIndex`. In 1067 either case, the range must either offer `length` or be 1068 infinite. The following code should compile for any random-access 1069 range. 1070 1071 The semantics of a random-access range (not checkable during 1072 compilation) are assumed to be the following (`r` is an object of 1073 type `R`): $(UL $(LI `r.opIndex(n)` returns a reference to the 1074 `n`th element in the range.)) 1075 1076 Although `char[]` and `wchar[]` (as well as their qualified 1077 versions including `string` and `wstring`) are arrays, $(D 1078 isRandomAccessRange) yields `false` for them because they use 1079 variable-length encodings (UTF-8 and UTF-16 respectively). These types 1080 are bidirectional ranges only. 1081 1082 See_Also: 1083 The header of $(MREF std,range) for tutorials on ranges. 1084 */ 1085 enum bool isRandomAccessRange(R) = 1086 is(typeof(lvalueOf!R[1]) == ElementType!R) 1087 && !(isAutodecodableString!R && !isAggregateType!R) 1088 && isForwardRange!R 1089 && (isBidirectionalRange!R || isInfinite!R) 1090 && (hasLength!R || isInfinite!R) 1091 && (isInfinite!R || !is(typeof(lvalueOf!R[$ - 1])) 1092 || is(typeof(lvalueOf!R[$ - 1]) == ElementType!R)); 1093 1094 /// 1095 @safe unittest 1096 { 1097 import std.traits : isAggregateType, isAutodecodableString; 1098 1099 alias R = int[]; 1100 1101 // range is finite and bidirectional or infinite and forward. 1102 static assert(isBidirectionalRange!R || 1103 isForwardRange!R && isInfinite!R); 1104 1105 R r = [0,1]; 1106 auto e = r[1]; // can index 1107 auto f = r.front; 1108 static assert(is(typeof(e) == typeof(f))); // same type for indexed and front 1109 static assert(!(isAutodecodableString!R && !isAggregateType!R)); // narrow strings cannot be indexed as ranges 1110 static assert(hasLength!R || isInfinite!R); // must have length or be infinite 1111 1112 // $ must work as it does with arrays if opIndex works with $ 1113 static if (is(typeof(r[$]))) 1114 { 1115 static assert(is(typeof(f) == typeof(r[$]))); 1116 1117 // $ - 1 doesn't make sense with infinite ranges but needs to work 1118 // with finite ones. 1119 static if (!isInfinite!R) 1120 static assert(is(typeof(f) == typeof(r[$ - 1]))); 1121 } 1122 } 1123 1124 @safe unittest 1125 { 1126 struct A {} 1127 struct B 1128 { 1129 void popFront(); 1130 @property bool empty(); 1131 @property int front(); 1132 } 1133 struct C 1134 { 1135 void popFront(); 1136 @property bool empty(); 1137 @property int front(); 1138 void popBack(); 1139 @property int back(); 1140 } 1141 struct D 1142 { 1143 @property bool empty(); 1144 @property D save(); 1145 @property int front(); 1146 void popFront(); 1147 @property int back(); 1148 void popBack(); 1149 ref int opIndex(uint); 1150 @property size_t length(); 1151 alias opDollar = length; 1152 //int opSlice(uint, uint); 1153 } 1154 struct E 1155 { 1156 bool empty(); 1157 E save(); 1158 int front(); 1159 void popFront(); 1160 int back(); 1161 void popBack(); 1162 ref int opIndex(uint); 1163 size_t length(); 1164 alias opDollar = length; 1165 //int opSlice(uint, uint); 1166 } 1167 static assert(!isRandomAccessRange!(A)); 1168 static assert(!isRandomAccessRange!(B)); 1169 static assert(!isRandomAccessRange!(C)); 1170 static assert( isRandomAccessRange!(D)); 1171 static assert( isRandomAccessRange!(E)); 1172 static assert( isRandomAccessRange!(int[])); 1173 static assert( isRandomAccessRange!(inout(int)[])); 1174 } 1175 1176 @safe unittest 1177 { 1178 // Test fix for bug 6935. 1179 struct R 1180 { 1181 @disable this(); 1182 1183 @property bool empty() const { return false; } 1184 @property int front() const { return 0; } 1185 void popFront() {} 1186 1187 @property R save() { return this; } 1188 1189 @property int back() const { return 0; } 1190 void popBack(){} 1191 1192 int opIndex(size_t n) const { return 0; } 1193 @property size_t length() const { return 0; } 1194 alias opDollar = length; 1195 1196 void put(int e){ } 1197 } 1198 static assert(isInputRange!R); 1199 static assert(isForwardRange!R); 1200 static assert(isBidirectionalRange!R); 1201 static assert(isRandomAccessRange!R); 1202 static assert(isOutputRange!(R, int)); 1203 } 1204 1205 /** 1206 Returns `true` iff `R` is an input range that supports the 1207 `moveFront` primitive, as well as `moveBack` and `moveAt` if it's a 1208 bidirectional or random access range. These may be explicitly implemented, or 1209 may work via the default behavior of the module level functions `moveFront` 1210 and friends. The following code should compile for any range 1211 with mobile elements. 1212 1213 ---- 1214 alias E = ElementType!R; 1215 R r; 1216 static assert(isInputRange!R); 1217 static assert(is(typeof(moveFront(r)) == E)); 1218 static if (isBidirectionalRange!R) 1219 static assert(is(typeof(moveBack(r)) == E)); 1220 static if (isRandomAccessRange!R) 1221 static assert(is(typeof(moveAt(r, 0)) == E)); 1222 ---- 1223 */ 1224 enum bool hasMobileElements(R) = 1225 isInputRange!R 1226 && is(typeof(moveFront(lvalueOf!R)) == ElementType!R) 1227 && (!isBidirectionalRange!R 1228 || is(typeof(moveBack(lvalueOf!R)) == ElementType!R)) 1229 && (!isRandomAccessRange!R 1230 || is(typeof(moveAt(lvalueOf!R, 0)) == ElementType!R)); 1231 1232 /// 1233 @safe unittest 1234 { 1235 import std.algorithm.iteration : map; 1236 import std.range : iota, repeat; 1237 1238 static struct HasPostblit 1239 { 1240 this(this) {} 1241 } 1242 1243 auto nonMobile = map!"a"(repeat(HasPostblit.init)); 1244 static assert(!hasMobileElements!(typeof(nonMobile))); 1245 static assert( hasMobileElements!(int[])); 1246 static assert( hasMobileElements!(inout(int)[])); 1247 static assert( hasMobileElements!(typeof(iota(1000)))); 1248 1249 static assert( hasMobileElements!( string)); 1250 static assert( hasMobileElements!(dstring)); 1251 static assert( hasMobileElements!( char[])); 1252 static assert( hasMobileElements!(dchar[])); 1253 } 1254 1255 /** 1256 The element type of `R`. `R` does not have to be a range. The 1257 element type is determined as the type yielded by `r.front` for an 1258 object `r` of type `R`. For example, `ElementType!(T[])` is 1259 `T` if `T[]` isn't a narrow string; if it is, the element type is 1260 `dchar`. If `R` doesn't have `front`, `ElementType!R` is 1261 `void`. 1262 */ 1263 template ElementType(R) 1264 { 1265 static if (is(typeof(R.init.front.init) T)) 1266 alias ElementType = T; 1267 else 1268 alias ElementType = void; 1269 } 1270 1271 /// 1272 @safe unittest 1273 { 1274 import std.range : iota; 1275 1276 // Standard arrays: returns the type of the elements of the array 1277 static assert(is(ElementType!(int[]) == int)); 1278 1279 // Accessing .front retrieves the decoded dchar 1280 static assert(is(ElementType!(char[]) == dchar)); // rvalue 1281 static assert(is(ElementType!(dchar[]) == dchar)); // lvalue 1282 1283 // Ditto 1284 static assert(is(ElementType!(string) == dchar)); 1285 static assert(is(ElementType!(dstring) == immutable(dchar))); 1286 1287 // For ranges it gets the type of .front. 1288 auto range = iota(0, 10); 1289 static assert(is(ElementType!(typeof(range)) == int)); 1290 } 1291 1292 @safe unittest 1293 { 1294 static assert(is(ElementType!(byte[]) == byte)); 1295 static assert(is(ElementType!(wchar[]) == dchar)); // rvalue 1296 static assert(is(ElementType!(wstring) == dchar)); 1297 } 1298 1299 @safe unittest 1300 { 1301 enum XYZ : string { a = "foo" } 1302 auto x = XYZ.a.front; 1303 immutable char[3] a = "abc"; 1304 int[] i; 1305 void[] buf; 1306 static assert(is(ElementType!(XYZ) == dchar)); 1307 static assert(is(ElementType!(typeof(a)) == dchar)); 1308 static assert(is(ElementType!(typeof(i)) == int)); 1309 static assert(is(ElementType!(typeof(buf)) == void)); 1310 static assert(is(ElementType!(inout(int)[]) == inout(int))); 1311 static assert(is(ElementType!(inout(int[])) == inout(int))); 1312 } 1313 1314 @safe unittest 1315 { 1316 static assert(is(ElementType!(int[5]) == int)); 1317 static assert(is(ElementType!(int[0]) == int)); 1318 static assert(is(ElementType!(char[5]) == dchar)); 1319 static assert(is(ElementType!(char[0]) == dchar)); 1320 } 1321 1322 // https://issues.dlang.org/show_bug.cgi?id=11336 1323 @safe unittest 1324 { 1325 static struct S 1326 { 1327 this(this) @disable; 1328 } 1329 static assert(is(ElementType!(S[]) == S)); 1330 } 1331 1332 // https://issues.dlang.org/show_bug.cgi?id=11401 1333 @safe unittest 1334 { 1335 // ElementType should also work for non-@propety 'front' 1336 struct E { ushort id; } 1337 struct R 1338 { 1339 E front() { return E.init; } 1340 } 1341 static assert(is(ElementType!R == E)); 1342 } 1343 1344 /** 1345 The encoding element type of `R`. For narrow strings (`char[]`, 1346 `wchar[]` and their qualified variants including `string` and 1347 `wstring`), `ElementEncodingType` is the character type of the 1348 string. For all other types, `ElementEncodingType` is the same as 1349 `ElementType`. 1350 */ 1351 template ElementEncodingType(R) 1352 { 1353 static if (is(StringTypeOf!R) && is(R : E[], E)) 1354 alias ElementEncodingType = E; 1355 else 1356 alias ElementEncodingType = ElementType!R; 1357 } 1358 1359 /// 1360 @safe unittest 1361 { 1362 import std.range : iota; 1363 // internally the range stores the encoded type 1364 static assert(is(ElementEncodingType!(char[]) == char)); 1365 1366 static assert(is(ElementEncodingType!(wstring) == immutable(wchar))); 1367 1368 static assert(is(ElementEncodingType!(byte[]) == byte)); 1369 1370 auto range = iota(0, 10); 1371 static assert(is(ElementEncodingType!(typeof(range)) == int)); 1372 } 1373 1374 @safe unittest 1375 { 1376 static assert(is(ElementEncodingType!(wchar[]) == wchar)); 1377 static assert(is(ElementEncodingType!(dchar[]) == dchar)); 1378 static assert(is(ElementEncodingType!(string) == immutable(char))); 1379 static assert(is(ElementEncodingType!(dstring) == immutable(dchar))); 1380 static assert(is(ElementEncodingType!(int[]) == int)); 1381 } 1382 1383 @safe unittest 1384 { 1385 enum XYZ : string { a = "foo" } 1386 auto x = XYZ.a.front; 1387 immutable char[3] a = "abc"; 1388 int[] i; 1389 void[] buf; 1390 static assert(is(ElementType!(XYZ) : dchar)); 1391 static assert(is(ElementEncodingType!(char[]) == char)); 1392 static assert(is(ElementEncodingType!(string) == immutable char)); 1393 static assert(is(ElementType!(typeof(a)) : dchar)); 1394 static assert(is(ElementType!(typeof(i)) == int)); 1395 static assert(is(ElementEncodingType!(typeof(i)) == int)); 1396 static assert(is(ElementType!(typeof(buf)) : void)); 1397 1398 static assert(is(ElementEncodingType!(inout char[]) : inout(char))); 1399 } 1400 1401 @safe unittest 1402 { 1403 static assert(is(ElementEncodingType!(int[5]) == int)); 1404 static assert(is(ElementEncodingType!(int[0]) == int)); 1405 static assert(is(ElementEncodingType!(char[5]) == char)); 1406 static assert(is(ElementEncodingType!(char[0]) == char)); 1407 } 1408 1409 /** 1410 Returns `true` if `R` is an input range and has swappable 1411 elements. The following code should compile for any range 1412 with swappable elements. 1413 1414 ---- 1415 R r; 1416 static assert(isInputRange!R); 1417 swap(r.front, r.front); 1418 static if (isBidirectionalRange!R) swap(r.back, r.front); 1419 static if (isRandomAccessRange!R) swap(r[0], r.front); 1420 ---- 1421 */ 1422 template hasSwappableElements(R) 1423 { 1424 import std.algorithm.mutation : swap; 1425 enum bool hasSwappableElements = isInputRange!R 1426 && is(typeof((ref R r) => swap(r.front, r.front))) 1427 && (!isBidirectionalRange!R 1428 || is(typeof((ref R r) => swap(r.back, r.front)))) 1429 && (!isRandomAccessRange!R 1430 || is(typeof((ref R r) => swap(r[0], r.front)))); 1431 } 1432 1433 /// 1434 @safe unittest 1435 { 1436 static assert(!hasSwappableElements!(const int[])); 1437 static assert(!hasSwappableElements!(const(int)[])); 1438 static assert(!hasSwappableElements!(inout(int)[])); 1439 static assert( hasSwappableElements!(int[])); 1440 1441 static assert(!hasSwappableElements!( string)); 1442 static assert(!hasSwappableElements!(dstring)); 1443 static assert(!hasSwappableElements!( char[])); 1444 static assert( hasSwappableElements!(dchar[])); 1445 } 1446 1447 /** 1448 Returns `true` if `R` is an input range and has mutable 1449 elements. The following code should compile for any range 1450 with assignable elements. 1451 1452 ---- 1453 R r; 1454 static assert(isInputRange!R); 1455 r.front = r.front; 1456 static if (isBidirectionalRange!R) r.back = r.front; 1457 static if (isRandomAccessRange!R) r[0] = r.front; 1458 ---- 1459 */ 1460 enum bool hasAssignableElements(R) = isInputRange!R 1461 && is(typeof(lvalueOf!R.front = lvalueOf!R.front)) 1462 && (!isBidirectionalRange!R 1463 || is(typeof(lvalueOf!R.back = lvalueOf!R.back))) 1464 && (!isRandomAccessRange!R 1465 || is(typeof(lvalueOf!R[0] = lvalueOf!R.front))); 1466 1467 /// 1468 @safe unittest 1469 { 1470 static assert(!hasAssignableElements!(const int[])); 1471 static assert(!hasAssignableElements!(const(int)[])); 1472 static assert( hasAssignableElements!(int[])); 1473 static assert(!hasAssignableElements!(inout(int)[])); 1474 1475 static assert(!hasAssignableElements!( string)); 1476 static assert(!hasAssignableElements!(dstring)); 1477 static assert(!hasAssignableElements!( char[])); 1478 static assert( hasAssignableElements!(dchar[])); 1479 } 1480 1481 /** 1482 Tests whether the range `R` has lvalue elements. These are defined as 1483 elements that can be passed by reference and have their address taken. 1484 The following code should compile for any range with lvalue elements. 1485 ---- 1486 void passByRef(ref ElementType!R stuff); 1487 ... 1488 static assert(isInputRange!R); 1489 passByRef(r.front); 1490 static if (isBidirectionalRange!R) passByRef(r.back); 1491 static if (isRandomAccessRange!R) passByRef(r[0]); 1492 ---- 1493 */ 1494 enum bool hasLvalueElements(R) = isInputRange!R 1495 && is(typeof(isLvalue(lvalueOf!R.front))) 1496 && (!isBidirectionalRange!R 1497 || is(typeof(isLvalue(lvalueOf!R.back)))) 1498 && (!isRandomAccessRange!R 1499 || is(typeof(isLvalue(lvalueOf!R[0])))); 1500 1501 /* Compile successfully if argument of type T is an lvalue 1502 */ 1503 private void isLvalue(T)(T) 1504 if (0); 1505 1506 private void isLvalue(T)(ref T) 1507 if (1); 1508 1509 /// 1510 @safe unittest 1511 { 1512 import std.range : iota, chain; 1513 1514 static assert( hasLvalueElements!(int[])); 1515 static assert( hasLvalueElements!(const(int)[])); 1516 static assert( hasLvalueElements!(inout(int)[])); 1517 static assert( hasLvalueElements!(immutable(int)[])); 1518 static assert(!hasLvalueElements!(typeof(iota(3)))); 1519 1520 static assert(!hasLvalueElements!( string)); 1521 static assert( hasLvalueElements!(dstring)); 1522 static assert(!hasLvalueElements!( char[])); 1523 static assert( hasLvalueElements!(dchar[])); 1524 1525 auto c = chain([1, 2, 3], [4, 5, 6]); 1526 static assert( hasLvalueElements!(typeof(c))); 1527 } 1528 1529 @safe unittest 1530 { 1531 // bugfix 6336 1532 struct S { immutable int value; } 1533 static assert( isInputRange!(S[])); 1534 static assert( hasLvalueElements!(S[])); 1535 } 1536 1537 /** 1538 Yields `true` if `R` has a `length` member that returns a value of `size_t` 1539 type. `R` does not have to be a range. If `R` is a range, algorithms in the 1540 standard library are only guaranteed to support `length` with type `size_t`. 1541 1542 Note that `length` is an optional primitive as no range must implement it. Some 1543 ranges do not store their length explicitly, some cannot compute it without 1544 actually exhausting the range (e.g. socket streams), and some other ranges may 1545 be infinite. 1546 1547 Although narrow string types (`char[]`, `wchar[]`, and their qualified 1548 derivatives) do define a `length` property, `hasLength` yields `false` for them. 1549 This is because a narrow string's length does not reflect the number of 1550 characters, but instead the number of encoding units, and as such is not useful 1551 with range-oriented algorithms. To use strings as random-access ranges with 1552 length, use $(REF representation, std, string) or $(REF byCodeUnit, std, utf). 1553 */ 1554 template hasLength(R) 1555 { 1556 static if (is(typeof(((R* r) => r.length)(null)) Length)) 1557 enum bool hasLength = is(Length == size_t) && 1558 !(isAutodecodableString!R && !isAggregateType!R); 1559 else 1560 enum bool hasLength = false; 1561 } 1562 1563 /// 1564 @safe unittest 1565 { 1566 static assert(!hasLength!(char[])); 1567 static assert( hasLength!(int[])); 1568 static assert( hasLength!(inout(int)[])); 1569 1570 struct A { size_t length() { return 0; } } 1571 struct B { @property size_t length() { return 0; } } 1572 static assert( hasLength!(A)); 1573 static assert( hasLength!(B)); 1574 } 1575 1576 // test combinations which are invalid on some platforms 1577 @safe unittest 1578 { 1579 struct A { ulong length; } 1580 struct B { @property uint length() { return 0; } } 1581 1582 static if (is(size_t == uint)) 1583 { 1584 static assert(!hasLength!(A)); 1585 static assert(hasLength!(B)); 1586 } 1587 else static if (is(size_t == ulong)) 1588 { 1589 static assert(hasLength!(A)); 1590 static assert(!hasLength!(B)); 1591 } 1592 } 1593 1594 // test combinations which are invalid on all platforms 1595 @safe unittest 1596 { 1597 struct A { long length; } 1598 struct B { int length; } 1599 struct C { ubyte length; } 1600 struct D { char length; } 1601 static assert(!hasLength!(A)); 1602 static assert(!hasLength!(B)); 1603 static assert(!hasLength!(C)); 1604 static assert(!hasLength!(D)); 1605 } 1606 1607 /** 1608 Returns `true` if `R` is an infinite input range. An 1609 infinite input range is an input range that has a statically-defined 1610 enumerated member called `empty` that is always `false`, 1611 for example: 1612 1613 ---- 1614 struct MyInfiniteRange 1615 { 1616 enum bool empty = false; 1617 ... 1618 } 1619 ---- 1620 */ 1621 1622 template isInfinite(R) 1623 { 1624 static if (isInputRange!R && __traits(compiles, { enum e = R.empty; })) 1625 enum bool isInfinite = !R.empty; 1626 else 1627 enum bool isInfinite = false; 1628 } 1629 1630 /// 1631 @safe unittest 1632 { 1633 import std.range : Repeat; 1634 static assert(!isInfinite!(int[])); 1635 static assert( isInfinite!(Repeat!(int))); 1636 } 1637 1638 /** 1639 Returns `true` if `R` offers a slicing operator with integral boundaries 1640 that returns a forward range type. 1641 1642 For finite ranges, the result of `opSlice` must be of the same type as the 1643 original range type. If the range defines `opDollar`, then it must support 1644 subtraction. 1645 1646 For infinite ranges, when $(I not) using `opDollar`, the result of 1647 `opSlice` must be the result of $(LREF take) or $(LREF takeExactly) on the 1648 original range (they both return the same type for infinite ranges). However, 1649 when using `opDollar`, the result of `opSlice` must be that of the 1650 original range type. 1651 1652 The following expression must be true for `hasSlicing` to be `true`: 1653 1654 ---- 1655 isForwardRange!R 1656 && !isNarrowString!R 1657 && is(ReturnType!((R r) => r[1 .. 1].length) == size_t) 1658 && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R) 1659 && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R)) 1660 && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R 1661 || is(typeof(lvalueOf!R[0 .. $ - 1]) == R)) 1662 && is(typeof((ref R r) 1663 { 1664 static assert(isForwardRange!(typeof(r[1 .. 2]))); 1665 })); 1666 ---- 1667 */ 1668 enum bool hasSlicing(R) = isForwardRange!R 1669 && !(isAutodecodableString!R && !isAggregateType!R) 1670 && is(ReturnType!((R r) => r[1 .. 1].length) == size_t) 1671 && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R) 1672 && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R)) 1673 && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R 1674 || is(typeof(lvalueOf!R[0 .. $ - 1]) == R)) 1675 && is(typeof((ref R r) 1676 { 1677 static assert(isForwardRange!(typeof(r[1 .. 2]))); 1678 })); 1679 1680 /// 1681 @safe unittest 1682 { 1683 import std.range : takeExactly; 1684 static assert( hasSlicing!(int[])); 1685 static assert( hasSlicing!(const(int)[])); 1686 static assert(!hasSlicing!(const int[])); 1687 static assert( hasSlicing!(inout(int)[])); 1688 static assert(!hasSlicing!(inout int [])); 1689 static assert( hasSlicing!(immutable(int)[])); 1690 static assert(!hasSlicing!(immutable int[])); 1691 static assert(!hasSlicing!string); 1692 static assert( hasSlicing!dstring); 1693 1694 enum rangeFuncs = "@property int front();" ~ 1695 "void popFront();" ~ 1696 "@property bool empty();" ~ 1697 "@property auto save() { return this; }" ~ 1698 "@property size_t length();"; 1699 1700 struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); } 1701 struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); } 1702 struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); } 1703 struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); } 1704 static assert(!hasSlicing!(A)); 1705 static assert( hasSlicing!(B)); 1706 static assert( hasSlicing!(C)); 1707 static assert(!hasSlicing!(D)); 1708 1709 struct InfOnes 1710 { 1711 enum empty = false; 1712 void popFront() {} 1713 @property int front() { return 1; } 1714 @property InfOnes save() { return this; } 1715 auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); } 1716 auto opSlice(size_t i, Dollar d) { return this; } 1717 1718 struct Dollar {} 1719 Dollar opDollar() const { return Dollar.init; } 1720 } 1721 1722 static assert(hasSlicing!InfOnes); 1723 } 1724 1725 /** 1726 This is a best-effort implementation of `length` for any kind of 1727 range. 1728 1729 If `hasLength!Range`, simply returns `range.length` without 1730 checking `upTo` (when specified). 1731 1732 Otherwise, walks the range through its length and returns the number 1733 of elements seen. Performes $(BIGOH n) evaluations of `range.empty` 1734 and `range.popFront()`, where `n` is the effective length of $(D 1735 range). 1736 1737 The `upTo` parameter is useful to "cut the losses" in case 1738 the interest is in seeing whether the range has at least some number 1739 of elements. If the parameter `upTo` is specified, stops if $(D 1740 upTo) steps have been taken and returns `upTo`. 1741 1742 Infinite ranges are compatible, provided the parameter `upTo` is 1743 specified, in which case the implementation simply returns upTo. 1744 */ 1745 auto walkLength(Range)(Range range) 1746 if (isInputRange!Range && !isInfinite!Range) 1747 { 1748 static if (hasLength!Range) 1749 return range.length; 1750 else 1751 { 1752 size_t result; 1753 for ( ; !range.empty ; range.popFront() ) 1754 ++result; 1755 return result; 1756 } 1757 } 1758 /// ditto 1759 auto walkLength(Range)(Range range, const size_t upTo) 1760 if (isInputRange!Range) 1761 { 1762 static if (hasLength!Range) 1763 return range.length; 1764 else static if (isInfinite!Range) 1765 return upTo; 1766 else 1767 { 1768 size_t result; 1769 for ( ; result < upTo && !range.empty ; range.popFront() ) 1770 ++result; 1771 return result; 1772 } 1773 } 1774 1775 /// 1776 @safe unittest 1777 { 1778 import std.range : iota; 1779 1780 assert(10.iota.walkLength == 10); 1781 // iota has a length function, and therefore the 1782 // doesn't have to be walked, and the upTo 1783 // parameter is ignored 1784 assert(10.iota.walkLength(5) == 10); 1785 } 1786 1787 @safe unittest 1788 { 1789 import std.algorithm.iteration : filter; 1790 import std.range : recurrence, take; 1791 1792 //hasLength Range 1793 int[] a = [ 1, 2, 3 ]; 1794 assert(walkLength(a) == 3); 1795 assert(walkLength(a, 0) == 3); 1796 assert(walkLength(a, 2) == 3); 1797 assert(walkLength(a, 4) == 3); 1798 1799 //Forward Range 1800 auto b = filter!"true"([1, 2, 3, 4]); 1801 assert(b.walkLength() == 4); 1802 assert(b.walkLength(0) == 0); 1803 assert(b.walkLength(2) == 2); 1804 assert(b.walkLength(4) == 4); 1805 assert(b.walkLength(6) == 4); 1806 1807 //Infinite Range 1808 auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1); 1809 assert(!__traits(compiles, fibs.walkLength())); 1810 assert(fibs.take(10).walkLength() == 10); 1811 assert(fibs.walkLength(55) == 55); 1812 } 1813 1814 /** 1815 `popFrontN` eagerly advances `r` itself (not a copy) up to `n` times 1816 (by calling `r.popFront`). `popFrontN` takes `r` by `ref`, 1817 so it mutates the original range. Completes in $(BIGOH 1) steps for ranges 1818 that support slicing and have length. 1819 Completes in $(BIGOH n) time for all other ranges. 1820 1821 `popBackN` behaves the same as `popFrontN` but instead removes 1822 elements from the back of the (bidirectional) range instead of the front. 1823 1824 Returns: 1825 How much `r` was actually advanced, which may be less than `n` if 1826 `r` did not have at least `n` elements. 1827 1828 See_Also: $(REF drop, std, range), $(REF dropBack, std, range) 1829 */ 1830 size_t popFrontN(Range)(ref Range r, size_t n) 1831 if (isInputRange!Range) 1832 { 1833 static if (hasLength!Range) 1834 { 1835 n = cast(size_t) (n < r.length ? n : r.length); 1836 } 1837 1838 static if (hasSlicing!Range && is(typeof(r = r[n .. $]))) 1839 { 1840 r = r[n .. $]; 1841 } 1842 else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. 1843 { 1844 r = r[n .. r.length]; 1845 } 1846 else 1847 { 1848 static if (hasLength!Range) 1849 { 1850 foreach (i; 0 .. n) 1851 r.popFront(); 1852 } 1853 else 1854 { 1855 foreach (i; 0 .. n) 1856 { 1857 if (r.empty) return i; 1858 r.popFront(); 1859 } 1860 } 1861 } 1862 return n; 1863 } 1864 1865 /// ditto 1866 size_t popBackN(Range)(ref Range r, size_t n) 1867 if (isBidirectionalRange!Range) 1868 { 1869 static if (hasLength!Range) 1870 { 1871 n = cast(size_t) (n < r.length ? n : r.length); 1872 } 1873 1874 static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n]))) 1875 { 1876 r = r[0 .. $ - n]; 1877 } 1878 else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. 1879 { 1880 r = r[0 .. r.length - n]; 1881 } 1882 else 1883 { 1884 static if (hasLength!Range) 1885 { 1886 foreach (i; 0 .. n) 1887 r.popBack(); 1888 } 1889 else 1890 { 1891 foreach (i; 0 .. n) 1892 { 1893 if (r.empty) return i; 1894 r.popBack(); 1895 } 1896 } 1897 } 1898 return n; 1899 } 1900 1901 /// 1902 @safe unittest 1903 { 1904 int[] a = [ 1, 2, 3, 4, 5 ]; 1905 a.popFrontN(2); 1906 assert(a == [ 3, 4, 5 ]); 1907 a.popFrontN(7); 1908 assert(a == [ ]); 1909 } 1910 1911 /// 1912 @safe unittest 1913 { 1914 import std.algorithm.comparison : equal; 1915 import std.range : iota; 1916 auto LL = iota(1L, 7L); 1917 auto r = popFrontN(LL, 2); 1918 assert(equal(LL, [3L, 4L, 5L, 6L])); 1919 assert(r == 2); 1920 } 1921 1922 /// 1923 @safe unittest 1924 { 1925 int[] a = [ 1, 2, 3, 4, 5 ]; 1926 a.popBackN(2); 1927 assert(a == [ 1, 2, 3 ]); 1928 a.popBackN(7); 1929 assert(a == [ ]); 1930 } 1931 1932 /// 1933 @safe unittest 1934 { 1935 import std.algorithm.comparison : equal; 1936 import std.range : iota; 1937 auto LL = iota(1L, 7L); 1938 auto r = popBackN(LL, 2); 1939 assert(equal(LL, [1L, 2L, 3L, 4L])); 1940 assert(r == 2); 1941 } 1942 1943 /** 1944 Eagerly advances `r` itself (not a copy) exactly `n` times (by 1945 calling `r.popFront`). `popFrontExactly` takes `r` by `ref`, 1946 so it mutates the original range. Completes in $(BIGOH 1) steps for ranges 1947 that support slicing, and have either length or are infinite. 1948 Completes in $(BIGOH n) time for all other ranges. 1949 1950 Note: Unlike $(LREF popFrontN), `popFrontExactly` will assume that the 1951 range holds at least `n` elements. This makes `popFrontExactly` 1952 faster than `popFrontN`, but it also means that if `range` does 1953 not contain at least `n` elements, it will attempt to call `popFront` 1954 on an empty range, which is undefined behavior. So, only use 1955 `popFrontExactly` when it is guaranteed that `range` holds at least 1956 `n` elements. 1957 1958 `popBackExactly` will behave the same but instead removes elements from 1959 the back of the (bidirectional) range instead of the front. 1960 1961 See_Also: $(REF dropExactly, std, range), $(REF dropBackExactly, std, range) 1962 */ 1963 void popFrontExactly(Range)(ref Range r, size_t n) 1964 if (isInputRange!Range) 1965 { 1966 static if (hasLength!Range) 1967 assert(n <= r.length, "range is smaller than amount of items to pop"); 1968 1969 static if (hasSlicing!Range && is(typeof(r = r[n .. $]))) 1970 r = r[n .. $]; 1971 else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. 1972 r = r[n .. r.length]; 1973 else 1974 foreach (i; 0 .. n) 1975 r.popFront(); 1976 } 1977 1978 /// ditto 1979 void popBackExactly(Range)(ref Range r, size_t n) 1980 if (isBidirectionalRange!Range) 1981 { 1982 static if (hasLength!Range) 1983 assert(n <= r.length, "range is smaller than amount of items to pop"); 1984 1985 static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n]))) 1986 r = r[0 .. $ - n]; 1987 else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. 1988 r = r[0 .. r.length - n]; 1989 else 1990 foreach (i; 0 .. n) 1991 r.popBack(); 1992 } 1993 1994 /// 1995 @safe unittest 1996 { 1997 import std.algorithm.comparison : equal; 1998 import std.algorithm.iteration : filterBidirectional; 1999 2000 auto a = [1, 2, 3]; 2001 a.popFrontExactly(1); 2002 assert(a == [2, 3]); 2003 a.popBackExactly(1); 2004 assert(a == [2]); 2005 2006 string s = "日本語"; 2007 s.popFrontExactly(1); 2008 assert(s == "本語"); 2009 s.popBackExactly(1); 2010 assert(s == "本"); 2011 2012 auto bd = filterBidirectional!"true"([1, 2, 3]); 2013 bd.popFrontExactly(1); 2014 assert(bd.equal([2, 3])); 2015 bd.popBackExactly(1); 2016 assert(bd.equal([2])); 2017 } 2018 2019 /** 2020 Moves the front of `r` out and returns it. Leaves `r.front` in a 2021 destroyable state that does not allocate any resources (usually equal 2022 to its `.init` value). 2023 */ 2024 ElementType!R moveFront(R)(R r) 2025 { 2026 static if (is(typeof(&r.moveFront))) 2027 { 2028 return r.moveFront(); 2029 } 2030 else static if (!hasElaborateCopyConstructor!(ElementType!R)) 2031 { 2032 return r.front; 2033 } 2034 else static if (is(typeof(&(r.front())) == ElementType!R*)) 2035 { 2036 import std.algorithm.mutation : move; 2037 return move(r.front); 2038 } 2039 else 2040 { 2041 static assert(0, 2042 "Cannot move front of a range with a postblit and an rvalue front."); 2043 } 2044 } 2045 2046 /// 2047 @safe unittest 2048 { 2049 auto a = [ 1, 2, 3 ]; 2050 assert(moveFront(a) == 1); 2051 assert(a.length == 3); 2052 2053 // define a perfunctory input range 2054 struct InputRange 2055 { 2056 enum bool empty = false; 2057 enum int front = 7; 2058 void popFront() {} 2059 int moveFront() { return 43; } 2060 } 2061 InputRange r; 2062 // calls r.moveFront 2063 assert(moveFront(r) == 43); 2064 } 2065 2066 @safe unittest 2067 { 2068 struct R 2069 { 2070 @property ref int front() { static int x = 42; return x; } 2071 this(this){} 2072 } 2073 R r; 2074 assert(moveFront(r) == 42); 2075 } 2076 2077 /** 2078 Moves the back of `r` out and returns it. Leaves `r.back` in a 2079 destroyable state that does not allocate any resources (usually equal 2080 to its `.init` value). 2081 */ 2082 ElementType!R moveBack(R)(R r) 2083 { 2084 static if (is(typeof(&r.moveBack))) 2085 { 2086 return r.moveBack(); 2087 } 2088 else static if (!hasElaborateCopyConstructor!(ElementType!R)) 2089 { 2090 return r.back; 2091 } 2092 else static if (is(typeof(&(r.back())) == ElementType!R*)) 2093 { 2094 import std.algorithm.mutation : move; 2095 return move(r.back); 2096 } 2097 else 2098 { 2099 static assert(0, 2100 "Cannot move back of a range with a postblit and an rvalue back."); 2101 } 2102 } 2103 2104 /// 2105 @safe unittest 2106 { 2107 struct TestRange 2108 { 2109 int payload = 5; 2110 @property bool empty() { return false; } 2111 @property TestRange save() { return this; } 2112 @property ref int front() return { return payload; } 2113 @property ref int back() return { return payload; } 2114 void popFront() { } 2115 void popBack() { } 2116 } 2117 static assert(isBidirectionalRange!TestRange); 2118 TestRange r; 2119 auto x = moveBack(r); 2120 assert(x == 5); 2121 } 2122 2123 /** 2124 Moves element at index `i` of `r` out and returns it. Leaves $(D 2125 r[i]) in a destroyable state that does not allocate any resources 2126 (usually equal to its `.init` value). 2127 */ 2128 ElementType!R moveAt(R)(R r, size_t i) 2129 { 2130 static if (is(typeof(&r.moveAt))) 2131 { 2132 return r.moveAt(i); 2133 } 2134 else static if (!hasElaborateCopyConstructor!(ElementType!(R))) 2135 { 2136 return r[i]; 2137 } 2138 else static if (is(typeof(&r[i]) == ElementType!R*)) 2139 { 2140 import std.algorithm.mutation : move; 2141 return move(r[i]); 2142 } 2143 else 2144 { 2145 static assert(0, 2146 "Cannot move element of a range with a postblit and rvalue elements."); 2147 } 2148 } 2149 2150 /// 2151 @safe unittest 2152 { 2153 auto a = [1,2,3,4]; 2154 foreach (idx, it; a) 2155 { 2156 assert(it == moveAt(a, idx)); 2157 } 2158 } 2159 2160 @safe unittest 2161 { 2162 import std.internal.test.dummyrange; 2163 2164 foreach (DummyType; AllDummyRanges) 2165 { 2166 auto d = DummyType.init; 2167 assert(moveFront(d) == 1); 2168 2169 static if (isBidirectionalRange!DummyType) 2170 { 2171 assert(moveBack(d) == 10); 2172 } 2173 2174 static if (isRandomAccessRange!DummyType) 2175 { 2176 assert(moveAt(d, 2) == 3); 2177 } 2178 } 2179 } 2180 2181 /** 2182 Implements the range interface primitive `empty` for types that 2183 obey $(LREF hasLength) property and for narrow strings. Due to the 2184 fact that nonmember functions can be called with the first argument 2185 using the dot notation, `a.empty` is equivalent to `empty(a)`. 2186 */ 2187 @property bool empty(T)(auto ref scope T a) 2188 if (is(typeof(a.length) : size_t)) 2189 { 2190 return !a.length; 2191 } 2192 2193 /// 2194 @safe pure nothrow unittest 2195 { 2196 auto a = [ 1, 2, 3 ]; 2197 assert(!a.empty); 2198 assert(a[3 .. $].empty); 2199 2200 int[string] b; 2201 assert(b.empty); 2202 b["zero"] = 0; 2203 assert(!b.empty); 2204 } 2205 2206 /** 2207 Implements the range interface primitive `save` for built-in 2208 arrays. Due to the fact that nonmember functions can be called with 2209 the first argument using the dot notation, `array.save` is 2210 equivalent to `save(array)`. The function does not duplicate the 2211 content of the array, it simply returns its argument. 2212 */ 2213 @property inout(T)[] save(T)(return scope inout(T)[] a) @safe pure nothrow @nogc 2214 { 2215 return a; 2216 } 2217 2218 /// 2219 @safe pure nothrow unittest 2220 { 2221 auto a = [ 1, 2, 3 ]; 2222 auto b = a.save; 2223 assert(b is a); 2224 } 2225 2226 /** 2227 Implements the range interface primitive `popFront` for built-in 2228 arrays. Due to the fact that nonmember functions can be called with 2229 the first argument using the dot notation, `array.popFront` is 2230 equivalent to `popFront(array)`. For $(GLOSSARY narrow strings), 2231 `popFront` automatically advances to the next $(GLOSSARY code 2232 point). 2233 */ 2234 void popFront(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc 2235 if (!isAutodecodableString!(T[]) && !is(T[] == void[])) 2236 { 2237 assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof); 2238 a = a[1 .. $]; 2239 } 2240 2241 /// 2242 @safe pure nothrow unittest 2243 { 2244 auto a = [ 1, 2, 3 ]; 2245 a.popFront(); 2246 assert(a == [ 2, 3 ]); 2247 } 2248 2249 @safe unittest 2250 { 2251 static assert(!is(typeof({ int[4] a; popFront(a); }))); 2252 static assert(!is(typeof({ immutable int[] a; popFront(a); }))); 2253 static assert(!is(typeof({ void[] a; popFront(a); }))); 2254 } 2255 2256 /// ditto 2257 void popFront(C)(scope ref inout(C)[] str) @trusted pure nothrow 2258 if (isAutodecodableString!(C[])) 2259 { 2260 import std.algorithm.comparison : min; 2261 2262 assert(str.length, "Attempting to popFront() past the end of an array of " ~ C.stringof); 2263 2264 static if (is(immutable C == immutable char)) 2265 { 2266 static immutable ubyte[] charWidthTab = [ 2267 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2268 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2269 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2270 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 2271 ]; 2272 2273 immutable c = str[0]; 2274 immutable charWidth = c < 192 ? 1 : charWidthTab.ptr[c - 192]; 2275 str = str.ptr[min(str.length, charWidth) .. str.length]; 2276 } 2277 else static if (is(immutable C == immutable wchar)) 2278 { 2279 immutable u = str[0]; 2280 immutable seqLen = 1 + (u >= 0xD800 && u <= 0xDBFF); 2281 str = str.ptr[min(seqLen, str.length) .. str.length]; 2282 } 2283 else static assert(0, "Bad template constraint."); 2284 } 2285 2286 @safe pure unittest 2287 { 2288 import std.meta : AliasSeq; 2289 2290 static foreach (S; AliasSeq!(string, wstring, dstring)) 2291 {{ 2292 S s = "\xC2\xA9hello"; 2293 s.popFront(); 2294 assert(s == "hello"); 2295 2296 S str = "hello\U00010143\u0100\U00010143"; 2297 foreach (dchar c; ['h', 'e', 'l', 'l', 'o', '\U00010143', '\u0100', '\U00010143']) 2298 { 2299 assert(str.front == c); 2300 str.popFront(); 2301 } 2302 assert(str.empty); 2303 2304 static assert(!is(typeof({ immutable S a; popFront(a); }))); 2305 static assert(!is(typeof({ typeof(S.init[0])[4] a; popFront(a); }))); 2306 }} 2307 2308 C[] _eatString(C)(C[] str) 2309 { 2310 while (!str.empty) 2311 str.popFront(); 2312 2313 return str; 2314 } 2315 enum checkCTFE = _eatString("ウェブサイト@La_Verité.com"); 2316 static assert(checkCTFE.empty); 2317 enum checkCTFEW = _eatString("ウェブサイト@La_Verité.com"w); 2318 static assert(checkCTFEW.empty); 2319 } 2320 2321 // https://issues.dlang.org/show_bug.cgi?id=16090 2322 @safe unittest 2323 { 2324 string s = "\u00E4"; 2325 assert(s.length == 2); 2326 s = s[0 .. 1]; 2327 assert(s.length == 1); 2328 s.popFront; 2329 assert(s.empty); 2330 } 2331 2332 @safe unittest 2333 { 2334 wstring s = "\U00010000"; 2335 assert(s.length == 2); 2336 s = s[0 .. 1]; 2337 assert(s.length == 1); 2338 s.popFront; 2339 assert(s.empty); 2340 } 2341 2342 /** 2343 Implements the range interface primitive `popBack` for built-in 2344 arrays. Due to the fact that nonmember functions can be called with 2345 the first argument using the dot notation, `array.popBack` is 2346 equivalent to `popBack(array)`. For $(GLOSSARY narrow strings), $(D 2347 popFront) automatically eliminates the last $(GLOSSARY code point). 2348 */ 2349 void popBack(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc 2350 if (!isAutodecodableString!(T[]) && !is(T[] == void[])) 2351 { 2352 assert(a.length); 2353 a = a[0 .. $ - 1]; 2354 } 2355 2356 /// 2357 @safe pure nothrow unittest 2358 { 2359 auto a = [ 1, 2, 3 ]; 2360 a.popBack(); 2361 assert(a == [ 1, 2 ]); 2362 } 2363 2364 @safe unittest 2365 { 2366 static assert(!is(typeof({ immutable int[] a; popBack(a); }))); 2367 static assert(!is(typeof({ int[4] a; popBack(a); }))); 2368 static assert(!is(typeof({ void[] a; popBack(a); }))); 2369 } 2370 2371 /// ditto 2372 void popBack(T)(scope ref inout(T)[] a) @safe pure 2373 if (isAutodecodableString!(T[])) 2374 { 2375 import std.utf : strideBack; 2376 assert(a.length, "Attempting to popBack() past the front of an array of " ~ T.stringof); 2377 a = a[0 .. $ - strideBack(a, $)]; 2378 } 2379 2380 @safe pure unittest 2381 { 2382 import std.meta : AliasSeq; 2383 2384 static foreach (S; AliasSeq!(string, wstring, dstring)) 2385 {{ 2386 S s = "hello\xE2\x89\xA0"; 2387 s.popBack(); 2388 assert(s == "hello"); 2389 S s3 = "\xE2\x89\xA0"; 2390 auto c = s3.back; 2391 assert(c == cast(dchar)'\u2260'); 2392 s3.popBack(); 2393 assert(s3 == ""); 2394 2395 S str = "\U00010143\u0100\U00010143hello"; 2396 foreach (dchar ch; ['o', 'l', 'l', 'e', 'h', '\U00010143', '\u0100', '\U00010143']) 2397 { 2398 assert(str.back == ch); 2399 str.popBack(); 2400 } 2401 assert(str.empty); 2402 2403 static assert(!is(typeof({ immutable S a; popBack(a); }))); 2404 static assert(!is(typeof({ typeof(S.init[0])[4] a; popBack(a); }))); 2405 }} 2406 } 2407 2408 /** 2409 EXPERIMENTAL: to try out removing autodecoding, set the version 2410 `NoAutodecodeStrings`. Most things are expected to fail with this version 2411 currently. 2412 */ 2413 version (NoAutodecodeStrings) 2414 { 2415 enum autodecodeStrings = false; 2416 } 2417 else 2418 { 2419 /// 2420 enum autodecodeStrings = true; 2421 } 2422 2423 /** 2424 Implements the range interface primitive `front` for built-in 2425 arrays. Due to the fact that nonmember functions can be called with 2426 the first argument using the dot notation, `array.front` is 2427 equivalent to `front(array)`. For $(GLOSSARY narrow strings), $(D 2428 front) automatically returns the first $(GLOSSARY code point) as _a $(D 2429 dchar). 2430 */ 2431 @property ref inout(T) front(T)(return scope inout(T)[] a) @safe pure nothrow @nogc 2432 if (!isAutodecodableString!(T[]) && !is(T[] == void[])) 2433 { 2434 assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); 2435 return a[0]; 2436 } 2437 2438 /// 2439 @safe pure nothrow unittest 2440 { 2441 int[] a = [ 1, 2, 3 ]; 2442 assert(a.front == 1); 2443 } 2444 2445 @safe pure nothrow unittest 2446 { 2447 auto a = [ 1, 2 ]; 2448 a.front = 4; 2449 assert(a.front == 4); 2450 assert(a == [ 4, 2 ]); 2451 2452 immutable b = [ 1, 2 ]; 2453 assert(b.front == 1); 2454 2455 int[2] c = [ 1, 2 ]; 2456 assert(c.front == 1); 2457 } 2458 2459 /// ditto 2460 @property dchar front(T)(scope const(T)[] a) @safe pure 2461 if (isAutodecodableString!(T[])) 2462 { 2463 import std.utf : decode; 2464 assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); 2465 size_t i = 0; 2466 return decode(a, i); 2467 } 2468 2469 /** 2470 Implements the range interface primitive `back` for built-in 2471 arrays. Due to the fact that nonmember functions can be called with 2472 the first argument using the dot notation, `array.back` is 2473 equivalent to `back(array)`. For $(GLOSSARY narrow strings), $(D 2474 back) automatically returns the last $(GLOSSARY code point) as _a $(D 2475 dchar). 2476 */ 2477 @property ref inout(T) back(T)(return scope inout(T)[] a) @safe pure nothrow @nogc 2478 if (!isAutodecodableString!(T[]) && !is(T[] == void[])) 2479 { 2480 assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); 2481 return a[$ - 1]; 2482 } 2483 2484 /// 2485 @safe pure nothrow unittest 2486 { 2487 int[] a = [ 1, 2, 3 ]; 2488 assert(a.back == 3); 2489 a.back += 4; 2490 assert(a.back == 7); 2491 } 2492 2493 @safe pure nothrow unittest 2494 { 2495 immutable b = [ 1, 2, 3 ]; 2496 assert(b.back == 3); 2497 2498 int[3] c = [ 1, 2, 3 ]; 2499 assert(c.back == 3); 2500 } 2501 2502 /// ditto 2503 // Specialization for strings 2504 @property dchar back(T)(scope const(T)[] a) @safe pure 2505 if (isAutodecodableString!(T[])) 2506 { 2507 import std.utf : decode, strideBack; 2508 assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); 2509 size_t i = a.length - strideBack(a, a.length); 2510 return decode(a, i); 2511 }