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