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