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