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 Params: 1016 R = type to be tested 1017 E = if present, the elements of the range must be 1018 $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) 1019 to this type 1020 1021 Returns: 1022 `true` if R is a forward range (possibly with element type `E`), `false` if not 1023 */ 1024 enum bool isForwardRange(R) = isInputRange!R 1025 && is(typeof((R r) { return r.save; } (R.init)) == R); 1026 1027 /// ditto 1028 enum bool isForwardRange(R, E) = 1029 .isForwardRange!R && isQualifierConvertible!(ElementType!R, E); 1030 1031 /// 1032 @safe unittest 1033 { 1034 static assert(!isForwardRange!(int)); 1035 static assert( isForwardRange!(int[])); 1036 static assert( isForwardRange!(inout(int)[])); 1037 1038 static assert( isForwardRange!(int[], const int)); 1039 static assert(!isForwardRange!(int[], immutable int)); 1040 1041 static assert(!isForwardRange!(const(int)[], int)); 1042 static assert( isForwardRange!(const(int)[], const int)); 1043 static assert(!isForwardRange!(const(int)[], immutable int)); 1044 1045 static assert(!isForwardRange!(immutable(int)[], int)); 1046 static assert( isForwardRange!(immutable(int)[], const int)); 1047 static assert( isForwardRange!(immutable(int)[], immutable int)); 1048 } 1049 1050 @safe unittest 1051 { 1052 // BUG 14544 1053 struct R14544 1054 { 1055 int front() { return 0;} 1056 void popFront() {} 1057 bool empty() { return false; } 1058 R14544 save() {return this;} 1059 } 1060 1061 static assert( isForwardRange!R14544 ); 1062 } 1063 1064 /** 1065 Returns `true` if `R` is a bidirectional range. A bidirectional 1066 range is a forward range that also offers the primitives `back` and 1067 `popBack`. The following code should compile for any bidirectional 1068 range. 1069 1070 The semantics of a bidirectional range (not checkable during 1071 compilation) are assumed to be the following (`r` is an object of 1072 type `R`): 1073 1074 $(UL $(LI `r.back` returns (possibly a reference to) the last 1075 element in the range. Calling `r.back` is allowed only if calling 1076 `r.empty` has, or would have, returned `false`.)) 1077 1078 See_Also: 1079 The header of $(MREF std,range) for tutorials on ranges. 1080 1081 Params: 1082 R = type to be tested 1083 E = if present, the elements of the range must be 1084 $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) 1085 to this type 1086 1087 Returns: 1088 `true` if R is a bidirectional range (possibly with element type `E`), `false` if not 1089 */ 1090 enum bool isBidirectionalRange(R) = isForwardRange!R 1091 && is(typeof((R r) => r.popBack)) 1092 && (is(typeof((return ref R r) => r.back)) || is(typeof(ref (return ref R r) => r.back))) 1093 && is(typeof(R.init.back.init) == ElementType!R); 1094 1095 /// ditto 1096 enum bool isBidirectionalRange(R, E) = 1097 .isBidirectionalRange!R && isQualifierConvertible!(ElementType!R, E); 1098 1099 /// 1100 @safe unittest 1101 { 1102 alias R = int[]; 1103 R r = [0,1]; 1104 static assert(isForwardRange!R); // is forward range 1105 r.popBack(); // can invoke popBack 1106 auto t = r.back; // can get the back of the range 1107 auto w = r.front; 1108 static assert(is(typeof(t) == typeof(w))); // same type for front and back 1109 1110 // Checking the element type 1111 static assert( isBidirectionalRange!(int[], const int)); 1112 static assert(!isBidirectionalRange!(int[], immutable int)); 1113 1114 static assert(!isBidirectionalRange!(const(int)[], int)); 1115 static assert( isBidirectionalRange!(const(int)[], const int)); 1116 static assert(!isBidirectionalRange!(const(int)[], immutable int)); 1117 1118 static assert(!isBidirectionalRange!(immutable(int)[], int)); 1119 static assert( isBidirectionalRange!(immutable(int)[], const int)); 1120 static assert( isBidirectionalRange!(immutable(int)[], immutable int)); 1121 } 1122 1123 @safe unittest 1124 { 1125 struct A {} 1126 struct B 1127 { 1128 void popFront(); 1129 @property bool empty(); 1130 @property int front(); 1131 } 1132 struct C 1133 { 1134 @property bool empty(); 1135 @property C save(); 1136 void popFront(); 1137 @property int front(); 1138 void popBack(); 1139 @property int back(); 1140 } 1141 static assert(!isBidirectionalRange!(A)); 1142 static assert(!isBidirectionalRange!(B)); 1143 static assert( isBidirectionalRange!(C)); 1144 static assert( isBidirectionalRange!(int[])); 1145 static assert( isBidirectionalRange!(char[])); 1146 static assert( isBidirectionalRange!(inout(int)[])); 1147 } 1148 1149 /** 1150 Returns `true` if `R` is a random-access range. A random-access 1151 range is a bidirectional range that also offers the primitive $(D 1152 opIndex), OR an infinite forward range that offers `opIndex`. In 1153 either case, the range must either offer `length` or be 1154 infinite. The following code should compile for any random-access 1155 range. 1156 1157 The semantics of a random-access range (not checkable during 1158 compilation) are assumed to be the following (`r` is an object of 1159 type `R`): $(UL $(LI `r.opIndex(n)` returns a reference to the 1160 `n`th element in the range.)) 1161 1162 Although `char[]` and `wchar[]` (as well as their qualified 1163 versions including `string` and `wstring`) are arrays, $(D 1164 isRandomAccessRange) yields `false` for them because they use 1165 variable-length encodings (UTF-8 and UTF-16 respectively). These types 1166 are bidirectional ranges only. 1167 1168 See_Also: 1169 The header of $(MREF std,range) for tutorials on ranges. 1170 1171 Params: 1172 R = type to be tested 1173 E = if present, the elements of the range must be 1174 $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) 1175 to this type 1176 1177 Returns: 1178 `true` if R is a random-access range (possibly with element type `E`), `false` if not 1179 */ 1180 enum bool isRandomAccessRange(R) = 1181 is(typeof(lvalueOf!R[1]) == ElementType!R) 1182 && !(isAutodecodableString!R && !isAggregateType!R) 1183 && isForwardRange!R 1184 && (isBidirectionalRange!R || isInfinite!R) 1185 && (hasLength!R || isInfinite!R) 1186 && (isInfinite!R || !is(typeof(lvalueOf!R[$ - 1])) 1187 || is(typeof(lvalueOf!R[$ - 1]) == ElementType!R)); 1188 1189 /// ditto 1190 enum bool isRandomAccessRange(R, E) = 1191 .isRandomAccessRange!R && isQualifierConvertible!(ElementType!R, E); 1192 1193 /// 1194 @safe unittest 1195 { 1196 import std.traits : isAggregateType, isAutodecodableString; 1197 1198 alias R = int[]; 1199 1200 // range is finite and bidirectional or infinite and forward. 1201 static assert(isBidirectionalRange!R || 1202 isForwardRange!R && isInfinite!R); 1203 1204 R r = [0,1]; 1205 auto e = r[1]; // can index 1206 auto f = r.front; 1207 static assert(is(typeof(e) == typeof(f))); // same type for indexed and front 1208 static assert(!(isAutodecodableString!R && !isAggregateType!R)); // narrow strings cannot be indexed as ranges 1209 static assert(hasLength!R || isInfinite!R); // must have length or be infinite 1210 1211 // $ must work as it does with arrays if opIndex works with $ 1212 static if (is(typeof(r[$]))) 1213 { 1214 static assert(is(typeof(f) == typeof(r[$]))); 1215 1216 // $ - 1 doesn't make sense with infinite ranges but needs to work 1217 // with finite ones. 1218 static if (!isInfinite!R) 1219 static assert(is(typeof(f) == typeof(r[$ - 1]))); 1220 } 1221 1222 // Checking the element type 1223 static assert( isRandomAccessRange!(int[], const int)); 1224 static assert(!isRandomAccessRange!(int[], immutable int)); 1225 1226 static assert(!isRandomAccessRange!(const(int)[], int)); 1227 static assert( isRandomAccessRange!(const(int)[], const int)); 1228 static assert(!isRandomAccessRange!(const(int)[], immutable int)); 1229 1230 static assert(!isRandomAccessRange!(immutable(int)[], int)); 1231 static assert( isRandomAccessRange!(immutable(int)[], const int)); 1232 static assert( isRandomAccessRange!(immutable(int)[], immutable int)); 1233 } 1234 1235 @safe unittest 1236 { 1237 struct A {} 1238 struct B 1239 { 1240 void popFront(); 1241 @property bool empty(); 1242 @property int front(); 1243 } 1244 struct C 1245 { 1246 void popFront(); 1247 @property bool empty(); 1248 @property int front(); 1249 void popBack(); 1250 @property int back(); 1251 } 1252 struct D 1253 { 1254 @property bool empty(); 1255 @property D save(); 1256 @property int front(); 1257 void popFront(); 1258 @property int back(); 1259 void popBack(); 1260 ref int opIndex(uint); 1261 @property size_t length(); 1262 alias opDollar = length; 1263 //int opSlice(uint, uint); 1264 } 1265 struct E 1266 { 1267 bool empty(); 1268 E save(); 1269 int front(); 1270 void popFront(); 1271 int back(); 1272 void popBack(); 1273 ref int opIndex(uint); 1274 size_t length(); 1275 alias opDollar = length; 1276 //int opSlice(uint, uint); 1277 } 1278 static assert(!isRandomAccessRange!(A)); 1279 static assert(!isRandomAccessRange!(B)); 1280 static assert(!isRandomAccessRange!(C)); 1281 static assert( isRandomAccessRange!(D)); 1282 static assert( isRandomAccessRange!(E)); 1283 static assert( isRandomAccessRange!(int[])); 1284 static assert( isRandomAccessRange!(inout(int)[])); 1285 } 1286 1287 @safe unittest 1288 { 1289 // Test fix for bug 6935. 1290 struct R 1291 { 1292 @disable this(); 1293 1294 @property bool empty() const { return false; } 1295 @property int front() const { return 0; } 1296 void popFront() {} 1297 1298 @property R save() { return this; } 1299 1300 @property int back() const { return 0; } 1301 void popBack(){} 1302 1303 int opIndex(size_t n) const { return 0; } 1304 @property size_t length() const { return 0; } 1305 alias opDollar = length; 1306 1307 void put(int e){ } 1308 } 1309 static assert(isInputRange!R); 1310 static assert(isForwardRange!R); 1311 static assert(isBidirectionalRange!R); 1312 static assert(isRandomAccessRange!R); 1313 static assert(isOutputRange!(R, int)); 1314 } 1315 1316 /** 1317 Returns `true` iff `R` is an input range that supports the 1318 `moveFront` primitive, as well as `moveBack` and `moveAt` if it's a 1319 bidirectional or random access range. These may be explicitly implemented, or 1320 may work via the default behavior of the module level functions `moveFront` 1321 and friends. The following code should compile for any range 1322 with mobile elements. 1323 1324 ---- 1325 alias E = ElementType!R; 1326 R r; 1327 static assert(isInputRange!R); 1328 static assert(is(typeof(moveFront(r)) == E)); 1329 static if (isBidirectionalRange!R) 1330 static assert(is(typeof(moveBack(r)) == E)); 1331 static if (isRandomAccessRange!R) 1332 static assert(is(typeof(moveAt(r, 0)) == E)); 1333 ---- 1334 */ 1335 enum bool hasMobileElements(R) = 1336 isInputRange!R 1337 && is(typeof(moveFront(lvalueOf!R)) == ElementType!R) 1338 && (!isBidirectionalRange!R 1339 || is(typeof(moveBack(lvalueOf!R)) == ElementType!R)) 1340 && (!isRandomAccessRange!R 1341 || is(typeof(moveAt(lvalueOf!R, 0)) == ElementType!R)); 1342 1343 /// 1344 @safe unittest 1345 { 1346 import std.algorithm.iteration : map; 1347 import std.range : iota, repeat; 1348 1349 static struct HasPostblit 1350 { 1351 this(this) {} 1352 } 1353 1354 auto nonMobile = map!"a"(repeat(HasPostblit.init)); 1355 static assert(!hasMobileElements!(typeof(nonMobile))); 1356 static assert( hasMobileElements!(int[])); 1357 static assert( hasMobileElements!(inout(int)[])); 1358 static assert( hasMobileElements!(typeof(iota(1000)))); 1359 1360 static assert( hasMobileElements!( string)); 1361 static assert( hasMobileElements!(dstring)); 1362 static assert( hasMobileElements!( char[])); 1363 static assert( hasMobileElements!(dchar[])); 1364 } 1365 1366 /** 1367 The element type of `R`. `R` does not have to be a range. The 1368 element type is determined as the type yielded by `r.front` for an 1369 object `r` of type `R`. For example, `ElementType!(T[])` is 1370 `T` if `T[]` isn't a narrow string; if it is, the element type is 1371 `dchar`. If `R` doesn't have `front`, `ElementType!R` is 1372 `void`. 1373 */ 1374 template ElementType(R) 1375 { 1376 static if (is(typeof(R.init.front.init) T)) 1377 alias ElementType = T; 1378 else 1379 alias ElementType = void; 1380 } 1381 1382 /// 1383 @safe unittest 1384 { 1385 import std.range : iota; 1386 1387 // Standard arrays: returns the type of the elements of the array 1388 static assert(is(ElementType!(int[]) == int)); 1389 1390 // Accessing .front retrieves the decoded dchar 1391 static assert(is(ElementType!(char[]) == dchar)); // rvalue 1392 static assert(is(ElementType!(dchar[]) == dchar)); // lvalue 1393 1394 // Ditto 1395 static assert(is(ElementType!(string) == dchar)); 1396 static assert(is(ElementType!(dstring) == immutable(dchar))); 1397 1398 // For ranges it gets the type of .front. 1399 auto range = iota(0, 10); 1400 static assert(is(ElementType!(typeof(range)) == int)); 1401 } 1402 1403 @safe unittest 1404 { 1405 static assert(is(ElementType!(byte[]) == byte)); 1406 static assert(is(ElementType!(wchar[]) == dchar)); // rvalue 1407 static assert(is(ElementType!(wstring) == dchar)); 1408 } 1409 1410 @safe unittest 1411 { 1412 enum XYZ : string { a = "foo" } 1413 auto x = XYZ.a.front; 1414 immutable char[3] a = "abc"; 1415 int[] i; 1416 void[] buf; 1417 static assert(is(ElementType!(XYZ) == dchar)); 1418 static assert(is(ElementType!(typeof(a)) == dchar)); 1419 static assert(is(ElementType!(typeof(i)) == int)); 1420 static assert(is(ElementType!(typeof(buf)) == void)); 1421 static assert(is(ElementType!(inout(int)[]) == inout(int))); 1422 static assert(is(ElementType!(inout(int[])) == inout(int))); 1423 } 1424 1425 @safe unittest 1426 { 1427 static assert(is(ElementType!(int[5]) == int)); 1428 static assert(is(ElementType!(int[0]) == int)); 1429 static assert(is(ElementType!(char[5]) == dchar)); 1430 static assert(is(ElementType!(char[0]) == dchar)); 1431 } 1432 1433 // https://issues.dlang.org/show_bug.cgi?id=11336 1434 @safe unittest 1435 { 1436 static struct S 1437 { 1438 this(this) @disable; 1439 } 1440 static assert(is(ElementType!(S[]) == S)); 1441 } 1442 1443 // https://issues.dlang.org/show_bug.cgi?id=11401 1444 @safe unittest 1445 { 1446 // ElementType should also work for non-@propety 'front' 1447 struct E { ushort id; } 1448 struct R 1449 { 1450 E front() { return E.init; } 1451 } 1452 static assert(is(ElementType!R == E)); 1453 } 1454 1455 /** 1456 The encoding element type of `R`. For narrow strings (`char[]`, 1457 `wchar[]` and their qualified variants including `string` and 1458 `wstring`), `ElementEncodingType` is the character type of the 1459 string. For all other types, `ElementEncodingType` is the same as 1460 `ElementType`. 1461 */ 1462 template ElementEncodingType(R) 1463 { 1464 static if (is(StringTypeOf!R) && is(R : E[], E)) 1465 alias ElementEncodingType = E; 1466 else 1467 alias ElementEncodingType = ElementType!R; 1468 } 1469 1470 /// 1471 @safe unittest 1472 { 1473 import std.range : iota; 1474 // internally the range stores the encoded type 1475 static assert(is(ElementEncodingType!(char[]) == char)); 1476 1477 static assert(is(ElementEncodingType!(wstring) == immutable(wchar))); 1478 1479 static assert(is(ElementEncodingType!(byte[]) == byte)); 1480 1481 auto range = iota(0, 10); 1482 static assert(is(ElementEncodingType!(typeof(range)) == int)); 1483 } 1484 1485 @safe unittest 1486 { 1487 static assert(is(ElementEncodingType!(wchar[]) == wchar)); 1488 static assert(is(ElementEncodingType!(dchar[]) == dchar)); 1489 static assert(is(ElementEncodingType!(string) == immutable(char))); 1490 static assert(is(ElementEncodingType!(dstring) == immutable(dchar))); 1491 static assert(is(ElementEncodingType!(int[]) == int)); 1492 } 1493 1494 @safe unittest 1495 { 1496 enum XYZ : string { a = "foo" } 1497 auto x = XYZ.a.front; 1498 immutable char[3] a = "abc"; 1499 int[] i; 1500 void[] buf; 1501 static assert(is(ElementType!(XYZ) : dchar)); 1502 static assert(is(ElementEncodingType!(char[]) == char)); 1503 static assert(is(ElementEncodingType!(string) == immutable char)); 1504 static assert(is(ElementType!(typeof(a)) : dchar)); 1505 static assert(is(ElementType!(typeof(i)) == int)); 1506 static assert(is(ElementEncodingType!(typeof(i)) == int)); 1507 static assert(is(ElementType!(typeof(buf)) : void)); 1508 1509 static assert(is(ElementEncodingType!(inout char[]) : inout(char))); 1510 } 1511 1512 @safe unittest 1513 { 1514 static assert(is(ElementEncodingType!(int[5]) == int)); 1515 static assert(is(ElementEncodingType!(int[0]) == int)); 1516 static assert(is(ElementEncodingType!(char[5]) == char)); 1517 static assert(is(ElementEncodingType!(char[0]) == char)); 1518 } 1519 1520 /** 1521 Returns `true` if `R` is an input range and has swappable 1522 elements. The following code should compile for any range 1523 with swappable elements. 1524 1525 ---- 1526 R r; 1527 static assert(isInputRange!R); 1528 swap(r.front, r.front); 1529 static if (isBidirectionalRange!R) swap(r.back, r.front); 1530 static if (isRandomAccessRange!R) swap(r[0], r.front); 1531 ---- 1532 */ 1533 template hasSwappableElements(R) 1534 { 1535 import std.algorithm.mutation : swap; 1536 enum bool hasSwappableElements = isInputRange!R 1537 && is(typeof((ref R r) => swap(r.front, r.front))) 1538 && (!isBidirectionalRange!R 1539 || is(typeof((ref R r) => swap(r.back, r.front)))) 1540 && (!isRandomAccessRange!R 1541 || is(typeof((ref R r) => swap(r[0], r.front)))); 1542 } 1543 1544 /// 1545 @safe unittest 1546 { 1547 static assert(!hasSwappableElements!(const int[])); 1548 static assert(!hasSwappableElements!(const(int)[])); 1549 static assert(!hasSwappableElements!(inout(int)[])); 1550 static assert( hasSwappableElements!(int[])); 1551 1552 static assert(!hasSwappableElements!( string)); 1553 static assert(!hasSwappableElements!(dstring)); 1554 static assert(!hasSwappableElements!( char[])); 1555 static assert( hasSwappableElements!(dchar[])); 1556 } 1557 1558 /** 1559 Returns `true` if `R` is an input range and has mutable 1560 elements. The following code should compile for any range 1561 with assignable elements. 1562 1563 ---- 1564 R r; 1565 static assert(isInputRange!R); 1566 r.front = r.front; 1567 static if (isBidirectionalRange!R) r.back = r.front; 1568 static if (isRandomAccessRange!R) r[0] = r.front; 1569 ---- 1570 */ 1571 enum bool hasAssignableElements(R) = isInputRange!R 1572 && is(typeof(lvalueOf!R.front = lvalueOf!R.front)) 1573 && (!isBidirectionalRange!R 1574 || is(typeof(lvalueOf!R.back = lvalueOf!R.back))) 1575 && (!isRandomAccessRange!R 1576 || is(typeof(lvalueOf!R[0] = lvalueOf!R.front))); 1577 1578 /// 1579 @safe unittest 1580 { 1581 static assert(!hasAssignableElements!(const int[])); 1582 static assert(!hasAssignableElements!(const(int)[])); 1583 static assert( hasAssignableElements!(int[])); 1584 static assert(!hasAssignableElements!(inout(int)[])); 1585 1586 static assert(!hasAssignableElements!( string)); 1587 static assert(!hasAssignableElements!(dstring)); 1588 static assert(!hasAssignableElements!( char[])); 1589 static assert( hasAssignableElements!(dchar[])); 1590 } 1591 1592 /** 1593 Tests whether the range `R` has lvalue elements. These are defined as 1594 elements that can be passed by reference and have their address taken. 1595 The following code should compile for any range with lvalue elements. 1596 ---- 1597 void passByRef(ref ElementType!R stuff); 1598 ... 1599 static assert(isInputRange!R); 1600 passByRef(r.front); 1601 static if (isBidirectionalRange!R) passByRef(r.back); 1602 static if (isRandomAccessRange!R) passByRef(r[0]); 1603 ---- 1604 */ 1605 enum bool hasLvalueElements(R) = isInputRange!R 1606 && is(typeof(isLvalue(lvalueOf!R.front))) 1607 && (!isBidirectionalRange!R 1608 || is(typeof(isLvalue(lvalueOf!R.back)))) 1609 && (!isRandomAccessRange!R 1610 || is(typeof(isLvalue(lvalueOf!R[0])))); 1611 1612 /* Compile successfully if argument of type T is an lvalue 1613 */ 1614 private void isLvalue(T)(T) 1615 if (0); 1616 1617 private void isLvalue(T)(ref T) 1618 if (1); 1619 1620 /// 1621 @safe unittest 1622 { 1623 import std.range : iota, chain; 1624 1625 static assert( hasLvalueElements!(int[])); 1626 static assert( hasLvalueElements!(const(int)[])); 1627 static assert( hasLvalueElements!(inout(int)[])); 1628 static assert( hasLvalueElements!(immutable(int)[])); 1629 static assert(!hasLvalueElements!(typeof(iota(3)))); 1630 1631 static assert(!hasLvalueElements!( string)); 1632 static assert( hasLvalueElements!(dstring)); 1633 static assert(!hasLvalueElements!( char[])); 1634 static assert( hasLvalueElements!(dchar[])); 1635 1636 auto c = chain([1, 2, 3], [4, 5, 6]); 1637 static assert( hasLvalueElements!(typeof(c))); 1638 } 1639 1640 @safe unittest 1641 { 1642 // bugfix 6336 1643 struct S { immutable int value; } 1644 static assert( isInputRange!(S[])); 1645 static assert( hasLvalueElements!(S[])); 1646 } 1647 1648 /** 1649 Yields `true` if `R` has a `length` member that returns a value of `size_t` 1650 type. `R` does not have to be a range. If `R` is a range, algorithms in the 1651 standard library are only guaranteed to support `length` with type `size_t`. 1652 1653 Note that `length` is an optional primitive as no range must implement it. Some 1654 ranges do not store their length explicitly, some cannot compute it without 1655 actually exhausting the range (e.g. socket streams), and some other ranges may 1656 be infinite. 1657 1658 Although narrow string types (`char[]`, `wchar[]`, and their qualified 1659 derivatives) do define a `length` property, `hasLength` yields `false` for them. 1660 This is because a narrow string's length does not reflect the number of 1661 characters, but instead the number of encoding units, and as such is not useful 1662 with range-oriented algorithms. To use strings as random-access ranges with 1663 length, use $(REF representation, std, string) or $(REF byCodeUnit, std, utf). 1664 */ 1665 template hasLength(R) 1666 { 1667 static if (is(typeof(((R* r) => r.length)(null)) Length)) 1668 enum bool hasLength = is(Length == size_t) && 1669 !(isAutodecodableString!R && !isAggregateType!R); 1670 else 1671 enum bool hasLength = false; 1672 } 1673 1674 /// 1675 @safe unittest 1676 { 1677 static assert(!hasLength!(char[])); 1678 static assert( hasLength!(int[])); 1679 static assert( hasLength!(inout(int)[])); 1680 1681 struct A { size_t length() { return 0; } } 1682 struct B { @property size_t length() { return 0; } } 1683 static assert( hasLength!(A)); 1684 static assert( hasLength!(B)); 1685 } 1686 1687 // test combinations which are invalid on some platforms 1688 @safe unittest 1689 { 1690 struct A { ulong length; } 1691 struct B { @property uint length() { return 0; } } 1692 1693 static if (is(size_t == uint)) 1694 { 1695 static assert(!hasLength!(A)); 1696 static assert(hasLength!(B)); 1697 } 1698 else static if (is(size_t == ulong)) 1699 { 1700 static assert(hasLength!(A)); 1701 static assert(!hasLength!(B)); 1702 } 1703 } 1704 1705 // test combinations which are invalid on all platforms 1706 @safe unittest 1707 { 1708 struct A { long length; } 1709 struct B { int length; } 1710 struct C { ubyte length; } 1711 struct D { char length; } 1712 static assert(!hasLength!(A)); 1713 static assert(!hasLength!(B)); 1714 static assert(!hasLength!(C)); 1715 static assert(!hasLength!(D)); 1716 } 1717 1718 /** 1719 Returns `true` if `R` is an infinite input range. An 1720 infinite input range is an input range that has a statically-defined 1721 enumerated member called `empty` that is always `false`, 1722 for example: 1723 1724 ---- 1725 struct MyInfiniteRange 1726 { 1727 enum bool empty = false; 1728 ... 1729 } 1730 ---- 1731 */ 1732 1733 template isInfinite(R) 1734 { 1735 static if (isInputRange!R && __traits(compiles, { enum e = R.empty; })) 1736 enum bool isInfinite = !R.empty; 1737 else 1738 enum bool isInfinite = false; 1739 } 1740 1741 /// 1742 @safe unittest 1743 { 1744 import std.range : Repeat; 1745 static assert(!isInfinite!(int[])); 1746 static assert( isInfinite!(Repeat!(int))); 1747 } 1748 1749 /** 1750 Returns `true` if `R` offers a slicing operator with integral boundaries 1751 that returns a forward range type. 1752 1753 For finite ranges, the result of `opSlice` must be of the same type as the 1754 original range type. If the range defines `opDollar`, then it must support 1755 subtraction. 1756 1757 For infinite ranges, when $(I not) using `opDollar`, the result of `opSlice` 1758 may be a forward range of any type. However, when using `opDollar`, the result 1759 of `opSlice` must be of the same type as the original range type. 1760 1761 The following expression must be true for `hasSlicing` to be `true`: 1762 1763 ---- 1764 isForwardRange!R 1765 && !(isAutodecodableString!R && !isAggregateType!R) 1766 && is(typeof((R r) { return r[1 .. 1].length; } (R.init)) == size_t) 1767 && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R) 1768 && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R)) 1769 && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R 1770 || is(typeof(lvalueOf!R[0 .. $ - 1]) == R)) 1771 && is(typeof((ref R r) 1772 { 1773 static assert(isForwardRange!(typeof(r[1 .. 2]))); 1774 })); 1775 ---- 1776 */ 1777 enum bool hasSlicing(R) = isForwardRange!R 1778 && !(isAutodecodableString!R && !isAggregateType!R) 1779 && is(typeof((R r) { return r[1 .. 1].length; } (R.init)) == size_t) 1780 && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R) 1781 && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R)) 1782 && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R 1783 || is(typeof(lvalueOf!R[0 .. $ - 1]) == R)) 1784 && is(typeof((ref R r) 1785 { 1786 static assert(isForwardRange!(typeof(r[1 .. 2]))); 1787 })); 1788 1789 /// 1790 @safe unittest 1791 { 1792 import std.range : takeExactly; 1793 static assert( hasSlicing!(int[])); 1794 static assert( hasSlicing!(const(int)[])); 1795 static assert(!hasSlicing!(const int[])); 1796 static assert( hasSlicing!(inout(int)[])); 1797 static assert(!hasSlicing!(inout int [])); 1798 static assert( hasSlicing!(immutable(int)[])); 1799 static assert(!hasSlicing!(immutable int[])); 1800 static assert(!hasSlicing!string); 1801 static assert( hasSlicing!dstring); 1802 1803 enum rangeFuncs = "@property int front();" ~ 1804 "void popFront();" ~ 1805 "@property bool empty();" ~ 1806 "@property auto save() { return this; }" ~ 1807 "@property size_t length();"; 1808 1809 struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); } 1810 struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); } 1811 struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); } 1812 struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); } 1813 static assert(!hasSlicing!(A)); 1814 static assert( hasSlicing!(B)); 1815 static assert( hasSlicing!(C)); 1816 static assert(!hasSlicing!(D)); 1817 1818 struct InfOnes 1819 { 1820 enum empty = false; 1821 void popFront() {} 1822 @property int front() { return 1; } 1823 @property InfOnes save() { return this; } 1824 auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); } 1825 auto opSlice(size_t i, Dollar d) { return this; } 1826 1827 struct Dollar {} 1828 Dollar opDollar() const { return Dollar.init; } 1829 } 1830 1831 static assert(hasSlicing!InfOnes); 1832 } 1833 1834 // https://issues.dlang.org/show_bug.cgi?id=24348 1835 @safe unittest 1836 { 1837 static struct Slice 1838 { 1839 size_t length; 1840 bool empty() => length == 0; 1841 int front() => 0; 1842 void popFront() { --length; } 1843 Slice save() => this; 1844 } 1845 1846 static struct InfZeros 1847 { 1848 enum empty = false; 1849 int front() => 0; 1850 void popFront() {} 1851 InfZeros save() => this; 1852 1853 Slice opIndex(size_t[2] bounds) 1854 { 1855 size_t i = bounds[0], j = bounds[1]; 1856 size_t length = i <= j ? j - i : 0; 1857 return Slice(length); 1858 } 1859 1860 size_t[2] opSlice(size_t dim : 0)(size_t i, size_t j) => [i, j]; 1861 } 1862 1863 static assert(hasSlicing!InfZeros); 1864 } 1865 1866 /** 1867 This is a best-effort implementation of `length` for any kind of 1868 range. 1869 1870 If `hasLength!Range`, simply returns `range.length` without 1871 checking `upTo` (when specified). 1872 1873 Otherwise, walks the range through its length and returns the number 1874 of elements seen. Performes $(BIGOH n) evaluations of `range.empty` 1875 and `range.popFront()`, where `n` is the effective length of $(D 1876 range). 1877 1878 The `upTo` parameter is useful to "cut the losses" in case 1879 the interest is in seeing whether the range has at least some number 1880 of elements. If the parameter `upTo` is specified, stops if $(D 1881 upTo) steps have been taken and returns `upTo`. 1882 1883 Infinite ranges are compatible, provided the parameter `upTo` is 1884 specified, in which case the implementation simply returns upTo. 1885 */ 1886 auto walkLength(Range)(Range range) 1887 if (isInputRange!Range && !isInfinite!Range) 1888 { 1889 static if (hasLength!Range) 1890 return range.length; 1891 else 1892 { 1893 size_t result; 1894 static if (autodecodeStrings && isNarrowString!Range) 1895 { 1896 import std.utf : codeUnitLimit; 1897 result = range.length; 1898 foreach (const i, const c; range) 1899 { 1900 if (c >= codeUnitLimit!Range) 1901 { 1902 result = i; 1903 break; 1904 } 1905 } 1906 range = range[result .. $]; 1907 } 1908 for ( ; !range.empty ; range.popFront() ) 1909 ++result; 1910 return result; 1911 } 1912 } 1913 /// ditto 1914 auto walkLength(Range)(Range range, const size_t upTo) 1915 if (isInputRange!Range) 1916 { 1917 static if (hasLength!Range) 1918 return range.length; 1919 else static if (isInfinite!Range) 1920 return upTo; 1921 else 1922 { 1923 size_t result; 1924 static if (autodecodeStrings && isNarrowString!Range) 1925 { 1926 import std.utf : codeUnitLimit; 1927 result = upTo > range.length ? range.length : upTo; 1928 foreach (const i, const c; range[0 .. result]) 1929 { 1930 if (c >= codeUnitLimit!Range) 1931 { 1932 result = i; 1933 break; 1934 } 1935 } 1936 range = range[result .. $]; 1937 } 1938 for ( ; result < upTo && !range.empty ; range.popFront() ) 1939 ++result; 1940 return result; 1941 } 1942 } 1943 1944 /// 1945 @safe unittest 1946 { 1947 import std.range : iota; 1948 1949 assert(10.iota.walkLength == 10); 1950 // iota has a length function, and therefore the 1951 // doesn't have to be walked, and the upTo 1952 // parameter is ignored 1953 assert(10.iota.walkLength(5) == 10); 1954 } 1955 1956 @safe unittest 1957 { 1958 import std.algorithm.iteration : filter; 1959 import std.range : recurrence, take; 1960 1961 //hasLength Range 1962 int[] a = [ 1, 2, 3 ]; 1963 assert(walkLength(a) == 3); 1964 assert(walkLength(a, 0) == 3); 1965 assert(walkLength(a, 2) == 3); 1966 assert(walkLength(a, 4) == 3); 1967 1968 //Forward Range 1969 auto b = filter!"true"([1, 2, 3, 4]); 1970 assert(b.walkLength() == 4); 1971 assert(b.walkLength(0) == 0); 1972 assert(b.walkLength(2) == 2); 1973 assert(b.walkLength(4) == 4); 1974 assert(b.walkLength(6) == 4); 1975 1976 //Infinite Range 1977 auto fibs = recurrence!"a[n-1] + a[n-2]"(1, 1); 1978 assert(!__traits(compiles, fibs.walkLength())); 1979 assert(fibs.take(10).walkLength() == 10); 1980 assert(fibs.walkLength(55) == 55); 1981 } 1982 1983 /** 1984 `popFrontN` eagerly advances `r` itself (not a copy) up to `n` times 1985 (by calling `r.popFront`). `popFrontN` takes `r` by `ref`, 1986 so it mutates the original range. Completes in $(BIGOH 1) steps for ranges 1987 that support slicing and have length. 1988 Completes in $(BIGOH n) time for all other ranges. 1989 1990 `popBackN` behaves the same as `popFrontN` but instead removes 1991 elements from the back of the (bidirectional) range instead of the front. 1992 1993 Returns: 1994 How much `r` was actually advanced, which may be less than `n` if 1995 `r` did not have at least `n` elements. 1996 1997 See_Also: $(REF drop, std, range), $(REF dropBack, std, range) 1998 */ 1999 size_t popFrontN(Range)(ref Range r, size_t n) 2000 if (isInputRange!Range) 2001 { 2002 static if (hasLength!Range) 2003 { 2004 n = cast(size_t) (n < r.length ? n : r.length); 2005 } 2006 2007 static if (hasSlicing!Range && is(typeof(r = r[n .. $]))) 2008 { 2009 r = r[n .. $]; 2010 } 2011 else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. 2012 { 2013 r = r[n .. r.length]; 2014 } 2015 else 2016 { 2017 static if (hasLength!Range) 2018 { 2019 foreach (i; 0 .. n) 2020 r.popFront(); 2021 } 2022 else 2023 { 2024 foreach (i; 0 .. n) 2025 { 2026 if (r.empty) return i; 2027 r.popFront(); 2028 } 2029 } 2030 } 2031 return n; 2032 } 2033 2034 /// ditto 2035 size_t popBackN(Range)(ref Range r, size_t n) 2036 if (isBidirectionalRange!Range) 2037 { 2038 static if (hasLength!Range) 2039 { 2040 n = cast(size_t) (n < r.length ? n : r.length); 2041 } 2042 2043 static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n]))) 2044 { 2045 r = r[0 .. $ - n]; 2046 } 2047 else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. 2048 { 2049 r = r[0 .. r.length - n]; 2050 } 2051 else 2052 { 2053 static if (hasLength!Range) 2054 { 2055 foreach (i; 0 .. n) 2056 r.popBack(); 2057 } 2058 else 2059 { 2060 foreach (i; 0 .. n) 2061 { 2062 if (r.empty) return i; 2063 r.popBack(); 2064 } 2065 } 2066 } 2067 return n; 2068 } 2069 2070 /// 2071 @safe unittest 2072 { 2073 int[] a = [ 1, 2, 3, 4, 5 ]; 2074 a.popFrontN(2); 2075 assert(a == [ 3, 4, 5 ]); 2076 a.popFrontN(7); 2077 assert(a == [ ]); 2078 } 2079 2080 /// 2081 @safe unittest 2082 { 2083 import std.algorithm.comparison : equal; 2084 import std.range : iota; 2085 auto LL = iota(1L, 7L); 2086 auto r = popFrontN(LL, 2); 2087 assert(equal(LL, [3L, 4L, 5L, 6L])); 2088 assert(r == 2); 2089 } 2090 2091 /// 2092 @safe unittest 2093 { 2094 int[] a = [ 1, 2, 3, 4, 5 ]; 2095 a.popBackN(2); 2096 assert(a == [ 1, 2, 3 ]); 2097 a.popBackN(7); 2098 assert(a == [ ]); 2099 } 2100 2101 /// 2102 @safe unittest 2103 { 2104 import std.algorithm.comparison : equal; 2105 import std.range : iota; 2106 auto LL = iota(1L, 7L); 2107 auto r = popBackN(LL, 2); 2108 assert(equal(LL, [1L, 2L, 3L, 4L])); 2109 assert(r == 2); 2110 } 2111 2112 /** 2113 Eagerly advances `r` itself (not a copy) exactly `n` times (by 2114 calling `r.popFront`). `popFrontExactly` takes `r` by `ref`, 2115 so it mutates the original range. Completes in $(BIGOH 1) steps for ranges 2116 that support slicing, and have either length or are infinite. 2117 Completes in $(BIGOH n) time for all other ranges. 2118 2119 Note: Unlike $(LREF popFrontN), `popFrontExactly` will assume that the 2120 range holds at least `n` elements. This makes `popFrontExactly` 2121 faster than `popFrontN`, but it also means that if `range` does 2122 not contain at least `n` elements, it will attempt to call `popFront` 2123 on an empty range, which is undefined behavior. So, only use 2124 `popFrontExactly` when it is guaranteed that `range` holds at least 2125 `n` elements. 2126 2127 `popBackExactly` will behave the same but instead removes elements from 2128 the back of the (bidirectional) range instead of the front. 2129 2130 See_Also: $(REF dropExactly, std, range), $(REF dropBackExactly, std, range) 2131 */ 2132 void popFrontExactly(Range)(ref Range r, size_t n) 2133 if (isInputRange!Range) 2134 { 2135 static if (hasLength!Range) 2136 assert(n <= r.length, "range is smaller than amount of items to pop"); 2137 2138 static if (hasSlicing!Range && is(typeof(r = r[n .. $]))) 2139 r = r[n .. $]; 2140 else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. 2141 r = r[n .. r.length]; 2142 else 2143 foreach (i; 0 .. n) 2144 r.popFront(); 2145 } 2146 2147 /// ditto 2148 void popBackExactly(Range)(ref Range r, size_t n) 2149 if (isBidirectionalRange!Range) 2150 { 2151 static if (hasLength!Range) 2152 assert(n <= r.length, "range is smaller than amount of items to pop"); 2153 2154 static if (hasSlicing!Range && is(typeof(r = r[0 .. $ - n]))) 2155 r = r[0 .. $ - n]; 2156 else static if (hasSlicing!Range && hasLength!Range) //TODO: Remove once hasSlicing forces opDollar. 2157 r = r[0 .. r.length - n]; 2158 else 2159 foreach (i; 0 .. n) 2160 r.popBack(); 2161 } 2162 2163 /// 2164 @safe unittest 2165 { 2166 import std.algorithm.comparison : equal; 2167 import std.algorithm.iteration : filterBidirectional; 2168 2169 auto a = [1, 2, 3]; 2170 a.popFrontExactly(1); 2171 assert(a == [2, 3]); 2172 a.popBackExactly(1); 2173 assert(a == [2]); 2174 2175 string s = "日本語"; 2176 s.popFrontExactly(1); 2177 assert(s == "本語"); 2178 s.popBackExactly(1); 2179 assert(s == "本"); 2180 2181 auto bd = filterBidirectional!"true"([1, 2, 3]); 2182 bd.popFrontExactly(1); 2183 assert(bd.equal([2, 3])); 2184 bd.popBackExactly(1); 2185 assert(bd.equal([2])); 2186 } 2187 2188 /** 2189 Moves the front of `r` out and returns it. 2190 2191 If `r.front` is a struct with a destructor or copy constructor defined, it 2192 is reset to its `.init` value after its value is moved. Otherwise, it is 2193 left unchanged. 2194 2195 In either case, `r.front` is left in a destroyable state that does not 2196 allocate any resources. 2197 */ 2198 ElementType!R moveFront(R)(R r) 2199 { 2200 static if (is(typeof(&r.moveFront))) 2201 { 2202 return r.moveFront(); 2203 } 2204 else static if (!hasElaborateCopyConstructor!(ElementType!R)) 2205 { 2206 return r.front; 2207 } 2208 else static if (is(typeof(&(r.front())) == ElementType!R*)) 2209 { 2210 import std.algorithm.mutation : move; 2211 return move(r.front); 2212 } 2213 else 2214 { 2215 static assert(0, 2216 "Cannot move front of a range with a postblit and an rvalue front."); 2217 } 2218 } 2219 2220 /// 2221 @safe unittest 2222 { 2223 auto a = [ 1, 2, 3 ]; 2224 assert(moveFront(a) == 1); 2225 assert(a.length == 3); 2226 2227 // define a perfunctory input range 2228 struct InputRange 2229 { 2230 enum bool empty = false; 2231 enum int front = 7; 2232 void popFront() {} 2233 int moveFront() { return 43; } 2234 } 2235 InputRange r; 2236 // calls r.moveFront 2237 assert(moveFront(r) == 43); 2238 } 2239 2240 @safe unittest 2241 { 2242 struct R 2243 { 2244 @property ref int front() { static int x = 42; return x; } 2245 this(this){} 2246 } 2247 R r; 2248 assert(moveFront(r) == 42); 2249 } 2250 2251 /** 2252 Moves the back of `r` out and returns it. Leaves `r.back` in a 2253 destroyable state that does not allocate any resources (usually equal 2254 to its `.init` value). 2255 */ 2256 ElementType!R moveBack(R)(R r) 2257 { 2258 static if (is(typeof(&r.moveBack))) 2259 { 2260 return r.moveBack(); 2261 } 2262 else static if (!hasElaborateCopyConstructor!(ElementType!R)) 2263 { 2264 return r.back; 2265 } 2266 else static if (is(typeof(&(r.back())) == ElementType!R*)) 2267 { 2268 import std.algorithm.mutation : move; 2269 return move(r.back); 2270 } 2271 else 2272 { 2273 static assert(0, 2274 "Cannot move back of a range with a postblit and an rvalue back."); 2275 } 2276 } 2277 2278 /// 2279 @safe unittest 2280 { 2281 struct TestRange 2282 { 2283 int payload = 5; 2284 @property bool empty() { return false; } 2285 @property TestRange save() { return this; } 2286 @property ref int front() return { return payload; } 2287 @property ref int back() return { return payload; } 2288 void popFront() { } 2289 void popBack() { } 2290 } 2291 static assert(isBidirectionalRange!TestRange); 2292 TestRange r; 2293 auto x = moveBack(r); 2294 assert(x == 5); 2295 } 2296 2297 /** 2298 Moves element at index `i` of `r` out and returns it. Leaves $(D 2299 r[i]) in a destroyable state that does not allocate any resources 2300 (usually equal to its `.init` value). 2301 */ 2302 ElementType!R moveAt(R)(R r, size_t i) 2303 { 2304 static if (is(typeof(&r.moveAt))) 2305 { 2306 return r.moveAt(i); 2307 } 2308 else static if (!hasElaborateCopyConstructor!(ElementType!(R))) 2309 { 2310 return r[i]; 2311 } 2312 else static if (is(typeof(&r[i]) == ElementType!R*)) 2313 { 2314 import std.algorithm.mutation : move; 2315 return move(r[i]); 2316 } 2317 else 2318 { 2319 static assert(0, 2320 "Cannot move element of a range with a postblit and rvalue elements."); 2321 } 2322 } 2323 2324 /// 2325 @safe unittest 2326 { 2327 auto a = [1,2,3,4]; 2328 foreach (idx, it; a) 2329 { 2330 assert(it == moveAt(a, idx)); 2331 } 2332 } 2333 2334 @safe unittest 2335 { 2336 import std.internal.test.dummyrange; 2337 2338 foreach (DummyType; AllDummyRanges) 2339 { 2340 auto d = DummyType.init; 2341 assert(moveFront(d) == 1); 2342 2343 static if (isBidirectionalRange!DummyType) 2344 { 2345 assert(moveBack(d) == 10); 2346 } 2347 2348 static if (isRandomAccessRange!DummyType) 2349 { 2350 assert(moveAt(d, 2) == 3); 2351 } 2352 } 2353 } 2354 2355 /** 2356 Implements the range interface primitive `empty` for types that 2357 obey $(LREF hasLength) property and for narrow strings. Due to the 2358 fact that nonmember functions can be called with the first argument 2359 using the dot notation, `a.empty` is equivalent to `empty(a)`. 2360 */ 2361 @property bool empty(T)(auto ref scope T a) 2362 if (is(typeof(a.length) : size_t)) 2363 { 2364 return !a.length; 2365 } 2366 2367 /// 2368 @safe pure nothrow unittest 2369 { 2370 auto a = [ 1, 2, 3 ]; 2371 assert(!a.empty); 2372 assert(a[3 .. $].empty); 2373 2374 int[string] b; 2375 assert(b.empty); 2376 b["zero"] = 0; 2377 assert(!b.empty); 2378 } 2379 2380 /** 2381 Implements the range interface primitive `save` for built-in 2382 arrays. Due to the fact that nonmember functions can be called with 2383 the first argument using the dot notation, `array.save` is 2384 equivalent to `save(array)`. The function does not duplicate the 2385 content of the array, it simply returns its argument. 2386 */ 2387 @property inout(T)[] save(T)(return scope inout(T)[] a) @safe pure nothrow @nogc 2388 { 2389 return a; 2390 } 2391 2392 /// 2393 @safe pure nothrow unittest 2394 { 2395 auto a = [ 1, 2, 3 ]; 2396 auto b = a.save; 2397 assert(b is a); 2398 } 2399 2400 /** 2401 Implements the range interface primitive `popFront` for built-in 2402 arrays. Due to the fact that nonmember functions can be called with 2403 the first argument using the dot notation, `array.popFront` is 2404 equivalent to `popFront(array)`. For $(GLOSSARY narrow strings), 2405 `popFront` automatically advances to the next $(GLOSSARY code 2406 point). 2407 */ 2408 void popFront(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc 2409 if (!isAutodecodableString!(T[]) && !is(T[] == void[])) 2410 { 2411 assert(a.length, "Attempting to popFront() past the end of an array of " ~ T.stringof); 2412 a = a[1 .. $]; 2413 } 2414 2415 /// 2416 @safe pure nothrow unittest 2417 { 2418 auto a = [ 1, 2, 3 ]; 2419 a.popFront(); 2420 assert(a == [ 2, 3 ]); 2421 } 2422 2423 @safe unittest 2424 { 2425 static assert(!is(typeof({ int[4] a; popFront(a); }))); 2426 static assert(!is(typeof({ immutable int[] a; popFront(a); }))); 2427 static assert(!is(typeof({ void[] a; popFront(a); }))); 2428 } 2429 2430 /// ditto 2431 void popFront(C)(scope ref inout(C)[] str) @trusted pure nothrow 2432 if (isAutodecodableString!(C[])) 2433 { 2434 import std.algorithm.comparison : min; 2435 2436 assert(str.length, "Attempting to popFront() past the end of an array of " ~ C.stringof); 2437 2438 static if (is(immutable C == immutable char)) 2439 { 2440 static immutable ubyte[] charWidthTab = [ 2441 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2442 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2443 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2444 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 2445 ]; 2446 2447 immutable c = str[0]; 2448 immutable charWidth = c < 192 ? 1 : charWidthTab.ptr[c - 192]; 2449 str = str.ptr[min(str.length, charWidth) .. str.length]; 2450 } 2451 else static if (is(immutable C == immutable wchar)) 2452 { 2453 immutable u = str[0]; 2454 immutable seqLen = 1 + (u >= 0xD800 && u <= 0xDBFF); 2455 str = str.ptr[min(seqLen, str.length) .. str.length]; 2456 } 2457 else static assert(0, "Bad template constraint."); 2458 } 2459 2460 @safe pure unittest 2461 { 2462 import std.meta : AliasSeq; 2463 2464 static foreach (S; AliasSeq!(string, wstring, dstring)) 2465 {{ 2466 S s = "\xC2\xA9hello"; 2467 s.popFront(); 2468 assert(s == "hello"); 2469 2470 S str = "hello\U00010143\u0100\U00010143"; 2471 foreach (dchar c; ['h', 'e', 'l', 'l', 'o', '\U00010143', '\u0100', '\U00010143']) 2472 { 2473 assert(str.front == c); 2474 str.popFront(); 2475 } 2476 assert(str.empty); 2477 2478 static assert(!is(typeof({ immutable S a; popFront(a); }))); 2479 static assert(!is(typeof({ typeof(S.init[0])[4] a; popFront(a); }))); 2480 }} 2481 2482 C[] _eatString(C)(C[] str) 2483 { 2484 while (!str.empty) 2485 str.popFront(); 2486 2487 return str; 2488 } 2489 enum checkCTFE = _eatString("ウェブサイト@La_Verité.com"); 2490 static assert(checkCTFE.empty); 2491 enum checkCTFEW = _eatString("ウェブサイト@La_Verité.com"w); 2492 static assert(checkCTFEW.empty); 2493 } 2494 2495 // https://issues.dlang.org/show_bug.cgi?id=16090 2496 @safe unittest 2497 { 2498 string s = "\u00E4"; 2499 assert(s.length == 2); 2500 s = s[0 .. 1]; 2501 assert(s.length == 1); 2502 s.popFront; 2503 assert(s.empty); 2504 } 2505 2506 @safe unittest 2507 { 2508 wstring s = "\U00010000"; 2509 assert(s.length == 2); 2510 s = s[0 .. 1]; 2511 assert(s.length == 1); 2512 s.popFront; 2513 assert(s.empty); 2514 } 2515 2516 /** 2517 Implements the range interface primitive `popBack` for built-in 2518 arrays. Due to the fact that nonmember functions can be called with 2519 the first argument using the dot notation, `array.popBack` is 2520 equivalent to `popBack(array)`. For $(GLOSSARY narrow strings), $(D 2521 popFront) automatically eliminates the last $(GLOSSARY code point). 2522 */ 2523 void popBack(T)(scope ref inout(T)[] a) @safe pure nothrow @nogc 2524 if (!isAutodecodableString!(T[]) && !is(T[] == void[])) 2525 { 2526 assert(a.length); 2527 a = a[0 .. $ - 1]; 2528 } 2529 2530 /// 2531 @safe pure nothrow unittest 2532 { 2533 auto a = [ 1, 2, 3 ]; 2534 a.popBack(); 2535 assert(a == [ 1, 2 ]); 2536 } 2537 2538 @safe unittest 2539 { 2540 static assert(!is(typeof({ immutable int[] a; popBack(a); }))); 2541 static assert(!is(typeof({ int[4] a; popBack(a); }))); 2542 static assert(!is(typeof({ void[] a; popBack(a); }))); 2543 } 2544 2545 /// ditto 2546 void popBack(T)(scope ref inout(T)[] a) @safe pure 2547 if (isAutodecodableString!(T[])) 2548 { 2549 import std.utf : strideBack; 2550 assert(a.length, "Attempting to popBack() past the front of an array of " ~ T.stringof); 2551 a = a[0 .. $ - strideBack(a, $)]; 2552 } 2553 2554 @safe pure unittest 2555 { 2556 import std.meta : AliasSeq; 2557 2558 static foreach (S; AliasSeq!(string, wstring, dstring)) 2559 {{ 2560 S s = "hello\xE2\x89\xA0"; 2561 s.popBack(); 2562 assert(s == "hello"); 2563 S s3 = "\xE2\x89\xA0"; 2564 auto c = s3.back; 2565 assert(c == cast(dchar)'\u2260'); 2566 s3.popBack(); 2567 assert(s3 == ""); 2568 2569 S str = "\U00010143\u0100\U00010143hello"; 2570 foreach (dchar ch; ['o', 'l', 'l', 'e', 'h', '\U00010143', '\u0100', '\U00010143']) 2571 { 2572 assert(str.back == ch); 2573 str.popBack(); 2574 } 2575 assert(str.empty); 2576 2577 static assert(!is(typeof({ immutable S a; popBack(a); }))); 2578 static assert(!is(typeof({ typeof(S.init[0])[4] a; popBack(a); }))); 2579 }} 2580 } 2581 2582 /** 2583 EXPERIMENTAL: to try out removing autodecoding, set the version 2584 `NoAutodecodeStrings`. Most things are expected to fail with this version 2585 currently. 2586 */ 2587 version (NoAutodecodeStrings) 2588 { 2589 enum autodecodeStrings = false; 2590 } 2591 else 2592 { 2593 /// 2594 enum autodecodeStrings = true; 2595 } 2596 2597 /** 2598 Implements the range interface primitive `front` for built-in 2599 arrays. Due to the fact that nonmember functions can be called with 2600 the first argument using the dot notation, `array.front` is 2601 equivalent to `front(array)`. For $(GLOSSARY narrow strings), $(D 2602 front) automatically returns the first $(GLOSSARY code point) as _a $(D 2603 dchar). 2604 */ 2605 @property ref inout(T) front(T)(return scope inout(T)[] a) @safe pure nothrow @nogc 2606 if (!isAutodecodableString!(T[]) && !is(T[] == void[])) 2607 { 2608 assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); 2609 return a[0]; 2610 } 2611 2612 /// 2613 @safe pure nothrow unittest 2614 { 2615 int[] a = [ 1, 2, 3 ]; 2616 assert(a.front == 1); 2617 } 2618 2619 @safe pure nothrow unittest 2620 { 2621 auto a = [ 1, 2 ]; 2622 a.front = 4; 2623 assert(a.front == 4); 2624 assert(a == [ 4, 2 ]); 2625 2626 immutable b = [ 1, 2 ]; 2627 assert(b.front == 1); 2628 2629 int[2] c = [ 1, 2 ]; 2630 assert(c.front == 1); 2631 } 2632 2633 /// ditto 2634 @property dchar front(T)(scope const(T)[] a) @safe pure 2635 if (isAutodecodableString!(T[])) 2636 { 2637 import std.utf : decode; 2638 assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof); 2639 size_t i = 0; 2640 return decode(a, i); 2641 } 2642 2643 /** 2644 Implements the range interface primitive `back` for built-in 2645 arrays. Due to the fact that nonmember functions can be called with 2646 the first argument using the dot notation, `array.back` is 2647 equivalent to `back(array)`. For $(GLOSSARY narrow strings), $(D 2648 back) automatically returns the last $(GLOSSARY code point) as _a $(D 2649 dchar). 2650 */ 2651 @property ref inout(T) back(T)(return scope inout(T)[] a) @safe pure nothrow @nogc 2652 if (!isAutodecodableString!(T[]) && !is(T[] == void[])) 2653 { 2654 assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); 2655 return a[$ - 1]; 2656 } 2657 2658 /// 2659 @safe pure nothrow unittest 2660 { 2661 int[] a = [ 1, 2, 3 ]; 2662 assert(a.back == 3); 2663 a.back += 4; 2664 assert(a.back == 7); 2665 } 2666 2667 @safe pure nothrow unittest 2668 { 2669 immutable b = [ 1, 2, 3 ]; 2670 assert(b.back == 3); 2671 2672 int[3] c = [ 1, 2, 3 ]; 2673 assert(c.back == 3); 2674 } 2675 2676 /// ditto 2677 // Specialization for strings 2678 @property dchar back(T)(scope const(T)[] a) @safe pure 2679 if (isAutodecodableString!(T[])) 2680 { 2681 import std.utf : decode, strideBack; 2682 assert(a.length, "Attempting to fetch the back of an empty array of " ~ T.stringof); 2683 size_t i = a.length - strideBack(a, a.length); 2684 return decode(a, i); 2685 } 2686 2687 /* 2688 Implements `length` for a range by forwarding it to `member`. 2689 */ 2690 package(std) mixin template ImplementLength(alias member) 2691 { 2692 static if (hasLength!(typeof(member))) 2693 { 2694 @property auto length() 2695 { 2696 return member.length; 2697 } 2698 alias opDollar = length; 2699 } 2700 } 2701 2702 @safe unittest 2703 { 2704 import std.meta : AliasSeq; 2705 2706 foreach (alias E; AliasSeq!(noreturn, const(noreturn), immutable(noreturn) )) 2707 { 2708 alias R = E[]; 2709 2710 static assert(isInputRange!R); 2711 static assert(isForwardRange!R); 2712 static assert(isBidirectionalRange!R); 2713 static assert(isRandomAccessRange!R); 2714 } 2715 2716 static assert(isOutputRange!(noreturn[], noreturn)); 2717 }