1 /** 2 Implementation of linked list `List` (similar to c++ `std::list` and `std::forward_list`). 3 4 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 5 Authors: Adam Búš 6 */ 7 module btl.list; 8 9 import btl.traits.common; 10 11 import std.traits : Unqual, Unconst, isSomeChar, isSomeString, CopyTypeQualifiers; 12 import std.meta : AliasSeq; 13 import std.traits : Select; 14 15 import btl.traits.range; 16 import btl.lifetime; 17 18 import btl.internal.traits; 19 import btl.internal.allocator; 20 import btl.internal.gc; 21 22 23 /** 24 Type used in forward constructors. 25 */ 26 alias Forward = btl.traits.common.Forward; 27 28 29 /** 30 Default allcoator for `List`. 31 */ 32 public alias DefaultAllocator = Mallocator; 33 34 35 /** 36 True if `T` is a `List` or implicitly converts to one, otherwise false. 37 */ 38 template isList(T...) 39 if(T.length == 1){ 40 enum bool isList = is(Unqual!(T[0]) == List!Args, Args...); 41 } 42 43 private struct ListNode(Type, bool _bidirectional){ 44 public alias ElementType = Type; 45 public enum bool bidirectional = _bidirectional; 46 47 private Type element; 48 private ListNode* next; 49 static if(bidirectional) 50 private ListNode* prev; 51 52 } 53 54 public template ListRange(Type, bool _bidirectional, bool _reverse = false){ 55 alias Node = ListNode!(Type, _bidirectional); 56 57 struct ListRange{ 58 59 private Node* node; 60 61 public alias Reverse = ListRange!(Type, _bidirectional, !_reverse); 62 63 package this(N)(N* node)pure nothrow @nogc @trusted 64 if(is(immutable N : immutable ListNode!(T, bd), T : const Type, bool bd)){ 65 static assert(is(CopyTypeQualifiers!(N, N.ElementType) : Type)); 66 static assert(N.bidirectional >= _bidirectional); 67 this.node = cast(Node*)node; 68 } 69 70 static if(_bidirectional) 71 public Reverse reverse()scope pure nothrow @safe @nogc{ 72 return typeof(return)(node); 73 74 } 75 76 public bool opEquals(const typeof(null))scope const pure nothrow @safe @nogc{ 77 return (this.node is null); 78 } 79 80 public bool opEquals(N)(scope const N* node)scope const pure nothrow @safe @nogc 81 if(is(immutable N : immutable ListNode!(T, bd), T, bool bd)){ 82 return (this.node is node); 83 } 84 85 public bool opEquals(R)(scope auto ref R rhs)scope const pure nothrow @safe @nogc 86 if(is(immutable R : immutable ListRange!(T, bd, r), T, bool bd, bool r)){ 87 return (this.node is rhs.node); 88 } 89 90 public bool empty()scope const pure nothrow @nogc @safe{ 91 return (node is null); 92 } 93 94 public ref inout(Type) front()inout scope return pure nothrow @nogc @safe{ 95 assert(node !is null); 96 return node.element; 97 } 98 99 public Type moveFront()(){ 100 assert(node !is null); 101 return move(node.element); 102 } 103 104 public template opUnary(string op : "*") 105 if(op == "*"){ //doc 106 alias opUnary = front; 107 } 108 109 public void popFront()()scope pure nothrow @nogc @safe{ 110 assert(node !is null); 111 static if(_reverse){ 112 static assert(_bidirectional); 113 node = node.prev; 114 } 115 else 116 node = node.next; 117 } 118 119 public template opBinary(string op : "++") 120 if(op == "++"){ //doc 121 alias opBinary = popFront; 122 } 123 124 static if(_bidirectional){ 125 public void popBack()scope pure nothrow @nogc @safe{ 126 assert(node !is null); 127 static if(_reverse) 128 node = node.next; 129 else 130 node = node.prev; 131 } 132 133 134 public template opBinary(string op : "--") 135 if(op == "--"){ //doc 136 alias opBinary = popBack; 137 } 138 } 139 140 } 141 } 142 143 144 145 /** 146 `List` is a container that supports constant time insertion and removal of elements from anywhere in the container. 147 148 Fast random access is not supported. It is usually implemented as a linked list 149 150 Template parameters: 151 152 `_Type` = element type. 153 154 `_Allocator` = Type of the allocator object used to define the storage allocation model. By default `DefaultAllocator` is used. 155 156 `_supportGC` 157 158 `_bidirectional` 159 */ 160 public template List( 161 _Type, 162 _Allocator = DefaultAllocator, 163 bool _supportGC = shouldAddGCRange!_Type, 164 bool _bidirectional = true, 165 ){ 166 167 import core.lifetime : emplace, forward, move; 168 import std.range : empty, front, popFront, ElementEncodingType, hasLength; 169 import std.traits : Unqual, hasElaborateDestructor, hasIndirections, isDynamicArray, isSafe; 170 171 alias ListNode = .ListNode!(_Type, _bidirectional); 172 alias ListRange = .ListRange!(_Type, _bidirectional); 173 174 enum bool _hasStatelessAllocator = isStatelessAllocator!_Allocator; 175 176 struct List{ 177 178 private alias Node = ListNode; 179 180 181 182 /** 183 True if allocator doesn't have state. 184 */ 185 public alias hasStatelessAllocator = _hasStatelessAllocator; 186 187 188 189 /** 190 Type of elements. 191 */ 192 public alias ElementType = _Type; 193 194 195 196 /** 197 Type of reference to elements. 198 */ 199 public alias ElementReferenceType = ElementReferenceTypeImpl!_Type; 200 201 202 203 /** 204 Type of the allocator object used to define the storage allocation model. By default `DefaultAllocator` is used. 205 */ 206 public alias AllocatorType = _Allocator; 207 208 209 210 /** 211 */ 212 public alias supportGC = _supportGC; 213 214 215 216 /** 217 */ 218 public alias bidirectional = _bidirectional; 219 220 221 222 /** 223 Iterator for list. 224 */ 225 public alias Iterator = .ListRange!(ElementType, bidirectional); 226 227 228 229 /** 230 Const iterator for list. 231 */ 232 public alias ConstIterator = .ListRange!(const(ElementType), bidirectional); 233 234 235 236 /** 237 Returns copy of allocator. 238 */ 239 public @property CopyTypeQualifiers!(This, AllocatorType) allocator(this This)()scope{ 240 return *(()@trusted => &this._allocator )(); 241 } 242 243 244 245 /** 246 Returns whether the list is empty (i.e. whether its length is 0). 247 248 Examples: 249 -------------------- 250 List!(int) list; 251 assert(list.empty); 252 253 list.append(42); 254 assert(!list.empty); 255 -------------------- 256 */ 257 public @property bool empty()const scope pure nothrow @safe @nogc{ 258 assert((this._first is null) == (this._last is null)); 259 return (this._first is null); 260 } 261 262 263 264 /** 265 Returns the length of the list, in terms of number of elements. 266 267 Examples: 268 -------------------- 269 List!(int) list = null; 270 assert(list.length == 0); 271 272 list.append(42); 273 assert(list.length == 1); 274 275 list.append(123); 276 assert(list.length == 2); 277 278 list.clear(); 279 assert(list.length == 0); 280 -------------------- 281 */ 282 public @property size_t length()const scope pure nothrow @safe @nogc{ 283 return this._length; 284 } 285 286 287 288 /** 289 */ 290 public @property auto begin(this This)()scope pure nothrow @system @nogc{ 291 alias Range = .ListRange!(GetElementType!This, bidirectional); 292 return Range(this._first); 293 } 294 295 296 297 /** 298 */ 299 public @property ConstIterator cbegin()const scope pure nothrow @system @nogc{ 300 return ConstIterator(this._first); 301 } 302 303 304 305 /** 306 */ 307 public enum typeof(null) end = null; 308 309 310 311 /** 312 Destroys the `List` object. 313 314 This deallocates all the storage capacity allocated by the `List` using its allocator. 315 */ 316 public ~this()scope{ 317 debug{ 318 this.release(); 319 } 320 else{ 321 this._release_impl(); 322 } 323 } 324 325 326 327 /** 328 Constructs a empty `List` with allocator `a`. 329 330 Examples: 331 -------------------- 332 { 333 List!(int) list = DefaultAllocator.init; 334 assert(list.empty); 335 } 336 -------------------- 337 338 */ 339 public this(AllocatorType a)scope pure nothrow @safe @nogc{ 340 static if(!hasStatelessAllocator) 341 this._allocator = forward!a; 342 } 343 344 345 346 /** 347 Constructs a empty `List` 348 349 Examples: 350 -------------------- 351 { 352 List!(int) list = null; 353 assert(list.empty); 354 } 355 -------------------- 356 357 */ 358 public this(typeof(null) nil, Forward = Forward.init)scope pure nothrow @safe @nogc{ 359 } 360 361 362 363 /** 364 Constructs a `List` object from other list. 365 366 Parameters: 367 `rhs` other list of `List` type. 368 369 `allocator` optional allocator parameter. 370 371 Examples: 372 -------------------- 373 { 374 List!(int) list = List!(int).build(1, 2); 375 assert(list == [1, 2]); 376 } 377 { 378 auto tmp = List!(int).build(1, 2); 379 List!(int) list = tmp; 380 assert(list == [1, 2]); 381 } 382 383 384 { 385 List!(int) list = List!(int).build(1, 2); 386 assert(list == [1, 2]); 387 } 388 { 389 auto tmp = List!(int).build(1, 2); 390 List!(int) list = tmp; 391 assert(list == [1, 2]); 392 } 393 -------------------- 394 */ 395 public this(Rhs, this This)(scope auto ref Rhs rhs)scope 396 if( isList!Rhs 397 && isConstructable!(Rhs, This) 398 && (isRef!Rhs || !is(immutable This == immutable Rhs)) 399 ){ 400 this(forward!rhs, Forward.init); 401 } 402 403 404 405 /** 406 Forward constructor. 407 */ 408 public this(Rhs, this This)(scope auto ref Rhs rhs, Forward)scope 409 if(isList!Rhs && isConstructable!(Rhs, This)){ 410 411 //move: 412 static if(isMoveConstructable!(rhs, This)){ 413 414 static if(!hasStatelessAllocator) 415 this._allocator = move(rhs._allocator); 416 417 this._length = rhs.length; 418 rhs.length = 0; 419 420 static if(backwardList){ 421 this._last = rhs._last; 422 rhs._last = null; 423 } 424 static if(forwardList){ 425 this._first = rhs._first; 426 rhs._first = null; 427 } 428 } 429 //move elements: 430 else static if(!isRef!rhs && isMoveConstructableElement!(GetElementType!Rhs, ElementType)){ 431 static if(!hasStatelessAllocator) 432 this._allocator = rhs._allocator; 433 434 Node* node = this._first; 435 auto range = rhs._op_slice(); 436 437 while(node !is null && !range.empty){ 438 node.element = move(range.front); 439 node = node.next; 440 range.popFront; 441 } 442 443 while(!range.empty){ 444 node = this._make_node(move(range.front)); 445 446 this._push_back_node!true(node); 447 448 this._length += 1; 449 range.popFront; 450 } 451 } 452 //copy: 453 else{ 454 static if(hasStatelessAllocator || Rhs.hasStatelessAllocator) 455 this(rhs._op_slice); 456 else 457 this(rhs._op_slice, rhs._allocator); 458 } 459 } 460 461 462 463 /** 464 Constructs a bidirectional `List` object from range of elements. 465 466 Parameters: 467 `range` input reange of `ElementType` elements. 468 469 `allocator` optional allocator parameter. 470 471 Examples: 472 -------------------- 473 import std.range : iota; 474 { 475 List!(int) list = iota(0, 5); 476 assert(list == [0, 1, 2, 3, 4]); 477 } 478 -------------------- 479 */ 480 public this(R, this This)(R range, Forward = Forward.init)scope 481 if(isBtlInputRange!R && is(ElementEncodingType!R : GetElementType!This)){ 482 this._init_from_range(forward!range); 483 } 484 485 /// ditto 486 public this(R, this This)(R range, AllocatorType allcoator)return 487 if(isBtlInputRange!R && is(ElementEncodingType!R : GetElementType!This)){ 488 static if(!hasStatelessAllocator) 489 this._allocator = forward!allcoator; 490 491 this._init_from_range(forward!range); 492 } 493 494 private void _init_from_range(R, this This)(R range)scope 495 if(isBtlInputRange!R && is(ElementEncodingType!R : GetElementType!This)){ 496 auto self = (()@trusted => (cast(Unqual!This*)&this) )(); 497 498 self.pushBack(forward!range); 499 } 500 501 502 503 /** 504 Copy constructors 505 */ 506 static foreach(alias From; AliasSeq!( 507 typeof(this), 508 const typeof(this), 509 immutable typeof(this), 510 )){ 511 512 static if(hasCopyConstructor!(From, typeof(this))) 513 this(scope ref return From rhs)scope{this(rhs, Forward.init);} 514 else 515 @disable this(scope ref return From rhs)scope pure nothrow @safe; 516 517 static if(hasCopyConstructor!(From, const typeof(this))) 518 this(scope ref return From rhs)const scope{this(rhs, Forward.init);} 519 else 520 @disable this(scope ref return From rhs)const scope pure nothrow @safe; 521 522 static if(hasCopyConstructor!(From, immutable typeof(this))) 523 this(scope ref return From rhs)immutable scope{this(rhs, Forward.init);} 524 else 525 @disable this(scope ref return From rhs)immutable scope pure nothrow @safe; 526 527 static if(hasCopyConstructor!(From, shared typeof(this))) 528 this(scope ref return From rhs)shared scope{this(rhs, Forward.init);} 529 else 530 @disable this(scope ref return From rhs)shared scope pure nothrow @safe; 531 532 static if(hasCopyConstructor!(From, const shared typeof(this))) 533 this(scope ref return From rhs)const shared scope{this(rhs, Forward.init);} 534 else 535 @disable this(scope ref return From rhs)const shared scope pure nothrow @safe; 536 } 537 538 539 540 /** 541 Assigns a new value `rhs` to the list, replacing its current contents. 542 543 Parameter `rhs` can by type of `null`, `List` or input range of ElementType elements. 544 545 Examples: 546 -------------------- 547 List!(int) list = List!(int).build(1, 2, 3); 548 assert(!list.empty); 549 550 list = null; 551 assert(list.empty); 552 553 list = List!(int).build(3, 2, 1); 554 assert(list == [3, 2, 1]); 555 556 list = List!(int).build(4, 2); 557 assert(list == [4, 2]); 558 -------------------- 559 */ 560 public void opAssign()(typeof(null) rhs)scope{ 561 this.clear(); 562 } 563 564 /// ditto 565 public void opAssign(R)(R range)scope 566 if(!isList!R && isBtlInputRange!R && is(ElementEncodingType!R : ElementType)){ 567 Node* node = this._first; 568 while(node !is null && !range.empty){ 569 node.element = range.front; 570 node = node.next; 571 range.popFront; 572 } 573 574 this.pushBack(forward!range); 575 } 576 577 /// ditto 578 public void opAssign(Rhs)(scope auto ref Rhs rhs)scope 579 if(isList!Rhs && isAssignable!(Rhs, typeof(this)) ){ 580 ///move: 581 static if(isMoveAssignable!(rhs, typeof(this))){ 582 static if(!hasStatelessAllocator) 583 this._allocator = move(rhs._allocator); 584 585 this._length = rhs._length; 586 rhs._length = 0; 587 588 this._last = rhs._last; 589 rhs._last = null; 590 591 this._first = rhs._first; 592 rhs._first = null; 593 594 } 595 else static if(!isRef!rhs 596 && isMoveAssignableElement!(GetElementType!Rhs, ElementType) 597 ){ 598 Node* node = this._first; 599 auto range = rhs._op_slice(); 600 601 while(node !is null && !range.empty){ 602 node.element = move(range.front); 603 node = node.next; 604 range.popFront; 605 } 606 607 while(!range.empty){ 608 node = this._make_node(move(range.front)); 609 610 this._push_back_node!true(node); 611 612 this._length += 1; 613 range.popFront; 614 } 615 } 616 else{ 617 this.opAssign(rhs._op_slice); 618 } 619 } 620 621 622 623 /** 624 Erases and deallocate the contents of the `List`, which becomes an empty list (with a length of 0 elements). 625 626 Same as `clear`. 627 628 Examples: 629 -------------------- 630 List!(int) list = List!(int).build(1, 2, 3); 631 assert(list.length == 3); 632 633 list.release(); 634 assert(list.length == 0); 635 -------------------- 636 */ 637 public void release()()scope nothrow{ 638 this._release_impl(); 639 640 this._first = null; 641 this._last = null; 642 643 this._length = 0; 644 } 645 646 private void _release_impl()()scope nothrow{ 647 ListNode* node = this._first; 648 649 while(node !is null){ 650 ListNode* tmp = node; 651 node = node.next; 652 this._destroy_node(tmp); 653 } 654 } 655 656 657 658 /** 659 Erases and deallocate the contents of the `List`, which becomes an empty list (with a length of 0 elements). 660 661 Same as `release`. 662 663 Examples: 664 -------------------- 665 List!(int) list = List!(int).build(1, 2, 3); 666 assert(list.length == 3); 667 668 list.clear(); 669 assert(list.length == 0); 670 -------------------- 671 */ 672 public alias clear = release; 673 674 675 676 /** 677 Same as operator `in` 678 679 Examples: 680 -------------------- 681 List!(int) list = List!(int).build(1, 2, 3); 682 683 assert(list.contains(1)); 684 assert(!list.contains(42L)); 685 -------------------- 686 */ 687 public bool contains(Elm)(scope auto ref Elm elm)scope const{ 688 foreach(ref e; this._op_slice ){ 689 if(e == elm) 690 return true; 691 } 692 693 return false; 694 } 695 696 697 698 /** 699 Operator `in` 700 701 702 Examples: 703 -------------------- 704 List!(int) list = List!(int).build(1, 2, 3); 705 706 assert(1 in list); 707 assert(42L !in list); 708 -------------------- 709 */ 710 public bool opBinaryRight(string op, Elm)(scope auto ref Elm elm)scope const 711 if(op == "in"){ 712 return this.contains(forward!elm); 713 } 714 715 716 717 /** 718 Compares the contents of a list with another list, range or null. 719 720 Returns `true` if they are equal, `false` otherwise 721 722 Examples: 723 -------------------- 724 List!(int) list = List!(int).build(1, 2, 3); 725 726 assert(list != null); 727 assert(null != list); 728 729 assert(list == [1, 2, 3]); 730 assert([1, 2, 3] == list); 731 732 assert(list == typeof(list).build(1, 2, 3)); 733 assert(typeof(list).build(1, 2, 3) == list); 734 735 import std.range : only; 736 assert(list == only(1, 2, 3)); 737 assert(only(1, 2, 3) == list); 738 -------------------- 739 */ 740 public bool opEquals(typeof(null) nil)const scope pure nothrow @safe @nogc{ 741 return this.empty; 742 } 743 744 /// ditto 745 public bool opEquals(R)(scope R rhs)const scope nothrow 746 if(isBtlInputRange!R && !isList!R){ 747 import std.algorithm.comparison : equal; 748 749 return equal(this._op_slice, forward!rhs); 750 } 751 752 /// ditto 753 public bool opEquals(L)(scope const auto ref L rhs)const scope nothrow 754 if(isList!L){ 755 import std.algorithm.comparison : equal; 756 757 return equal(this._op_slice, rhs._op_slice); 758 } 759 760 761 762 763 /** 764 Compares the contents of a list with another list or range. 765 766 Examples: 767 -------------------- 768 auto a1 = List!(int).build(1, 2, 3); 769 auto a2 = List!(int).build(1, 2, 3, 4); 770 auto b = List!(int).build(3, 2, 1); 771 772 assert(a1 < b); 773 assert(a1 < a2); 774 assert(a2 < b); 775 assert(a1 <= a1); 776 -------------------- 777 */ 778 public int opCmp(R)(scope R rhs)const scope nothrow 779 if(isBtlInputRange!R && !isList!R){ 780 import std.algorithm.comparison : cmp; 781 782 return cmp(this._op_slice, forward!rhs); 783 } 784 785 /// ditto 786 public int opCmp(L)(scope const auto ref L rhs)const scope nothrow 787 if(isList!L){ 788 import std.algorithm.comparison : cmp; 789 790 return cmp(this._op_slice, rhs._op_slice); 791 } 792 793 794 795 /** 796 Return slice of all elements. 797 798 The slice returned may be invalidated by further calls to other member functions that modify the object. 799 800 Examples: 801 -------------------- 802 List!(int) list = List!(int).build(1, 2, 3); 803 -------------------- 804 */ 805 public auto opIndex(this This)()return pure nothrow @system @nogc{ 806 return this._op_slice(); 807 } 808 809 private @property _op_slice(this This)()return pure nothrow @trusted @nogc{ 810 alias Range = .ListRange!(GetElementType!This, bidirectional); 811 return Range(this._first); 812 } 813 814 815 816 /** 817 Returns the length of the list, in terms of number of elements. 818 819 Same as `length()`. 820 */ 821 public size_t opDollar()const scope pure nothrow @safe @nogc{ 822 return this.length; 823 } 824 825 826 827 /** 828 Swaps the contents of `this` and `rhs`. 829 830 Examples: 831 -------------------- 832 auto a = List!(int).build(1, 2, 3); 833 auto b = List!(int).build(4, 5, 6); 834 835 a.proxySwap(b); 836 assert(a == [4, 5, 6]); 837 assert(b == [1, 2, 3]); 838 839 import std.algorithm.mutation : swap; 840 841 swap(a, b); 842 assert(a == [1, 2, 3]); 843 assert(b == [4, 5, 6]); 844 -------------------- 845 */ 846 public void proxySwap()(ref scope typeof(this) rhs)scope{ 847 import std.algorithm.mutation : swap; 848 849 (ref typeof(this) a, ref typeof(this) b){ 850 static if(!hasStatelessAllocator) 851 swap(a._allocator, b._allocator); 852 853 swap(a._length, b._length); 854 swap(a._first, b._first); 855 swap(a._last, b._last); 856 }( 857 *(()@trusted => &this )(), 858 *(()@trusted => &rhs )() 859 ); 860 861 /*static if(!hasStatelessAllocator) 862 swap(this._allocator, rhs._allocator); 863 864 swap(this._length, rhs._length); 865 swap(this._first, rhs._first); 866 swap(this._last, rhs._last);*/ 867 } 868 869 870 871 /** 872 Returns a reference to the first element in the list. 873 874 Calling this function on an empty container causes null dereference. 875 */ 876 public ref inout(ElementType) front()inout return pure nothrow @system @nogc{ 877 assert(this._first !is null); 878 return this._first.element; 879 } 880 881 882 883 /** 884 Returns a copy of the first element in the list. 885 886 Calling this function on an empty container causes null dereference. 887 888 Examples: 889 -------------------- 890 auto list = List!(int).build(1, 2, 3); 891 892 assert(list.frontCopy == 1); 893 assert(list == [1, 2, 3]); 894 -------------------- 895 */ 896 public auto frontCopy(this This)()scope{ 897 assert(this._first !is null); 898 899 return this._first.element; 900 } 901 902 903 904 /** 905 Move of the first element in the list and return it. 906 907 Calling this function on an empty container causes null dereference. 908 909 Examples: 910 -------------------- 911 auto list = List!(int).build(1, 2, 3); 912 913 assert(list.moveFront == 1); 914 list.popFront; 915 assert(list == [2, 3]); 916 -------------------- 917 */ 918 public ElementType moveFront()scope pure nothrow @safe @nogc{ 919 assert(this._first !is null); 920 921 return move(this._first.element); 922 } 923 924 925 926 /** 927 Pop the last element of the bidirectional list, effectively reducing its length by 1. 928 929 Return erased element. 930 931 Examples: 932 -------------------- 933 List!(int) list = List!(int).build(30, 20, 10); 934 assert(list.length == 3); 935 936 assert(list.popFront == 30); 937 assert(list.length == 2); 938 939 assert(list.popFront == 20); 940 assert(list.length == 1); 941 942 assert(list.popFront == 10); 943 assert(list.empty); 944 945 assert(list.popFront(int.init) == int.init); 946 assert(list.empty); 947 948 assert(list.popFront(42) == 42); 949 assert(list.empty); 950 -------------------- 951 */ 952 public auto popFront(T = Unqual!ElementType)()scope nothrow 953 if(is(T == Unqual!ElementType) || is(T == void)){ 954 assert(!this.empty); 955 return _pop_front_impl!T(); 956 } 957 958 ///ditto 959 public ElementType popFront(T : Unqual!ElementType = Unqual!ElementType)(ElementType def)scope nothrow{ 960 return (this.empty) 961 ? forward!def 962 : _pop_front_impl!T(); 963 } 964 965 private auto _pop_front_impl(T)()scope nothrow 966 if(is(T == Unqual!ElementType) || is(T == void)){ 967 ListNode* node = this._first; 968 this._first = this._first.next; 969 970 if(this._first is null){ 971 this._last = null; 972 } 973 else{ 974 static if(bidirectional) 975 this._first.prev = null; 976 } 977 978 979 static if(is(T == void)){ 980 destructImpl(*node); 981 this._length -= 1; 982 } 983 else{ 984 ElementType result = move(node.element); 985 destructImpl(*node); 986 987 this._length -= 1; 988 return move(result); 989 } 990 } 991 992 993 994 /** 995 Appends a new element to the begin of the list. The element is constructed through `emplace`. 996 997 Parameters: 998 `args` arguments to forward to the constructor of the element. 999 1000 Examples: 1001 -------------------- 1002 { 1003 auto list = List!(int).build(1, 2, 3); 1004 1005 list.emplaceFront(42); 1006 assert(list == [42, 1, 2, 3]); 1007 1008 list.emplaceFront(); 1009 assert(list == [0, 42, 1, 2, 3]); 1010 } 1011 1012 { 1013 static struct Foo{ 1014 int i; 1015 string str; 1016 } 1017 1018 auto list = List!(Foo).build(Foo(1, "A")); 1019 1020 list.emplaceFront(2, "B"); 1021 assert(list == only(Foo(2, "B"), Foo(1, "A"))); 1022 } 1023 -------------------- 1024 */ 1025 public void emplaceFront(Args...)(auto ref Args args)scope{ 1026 ListNode* node = this._make_node(forward!args); 1027 1028 this._push_front_node(node); 1029 this._length += 1; 1030 } 1031 1032 1033 1034 /** 1035 Extends the `List` by appending additional elements at the end of list. 1036 1037 Parameters: 1038 `val` appended value. 1039 1040 `list` appended list. 1041 1042 `range` appended input renge. 1043 1044 `count` Number of times `val` is appended. 1045 1046 Examples: 1047 -------------------- 1048 { 1049 auto list = List!(int).build(1, 2, 3); 1050 1051 list.pushFront(42); 1052 assert(list == [42, 1, 2, 3]); 1053 } 1054 1055 { 1056 auto list = List!(int).build(1, 2, 3); 1057 1058 list.pushFront(only(4, 5, 6)); 1059 assert(list == [6, 5, 4, 1, 2, 3]); 1060 } 1061 1062 { 1063 auto a = List!(int).build(1, 2, 3); 1064 auto b = List!(int).build(4, 5, 6); 1065 1066 a.pushFront(b); 1067 assert(a == [6, 5, 4, 1, 2, 3]); 1068 } 1069 1070 { 1071 List!(int) list = List!(int).build(1, 2, 3); 1072 int[3] tmp = [4, 5, 6]; 1073 list.pushFront(tmp[]); 1074 assert(list == [6, 5, 4, 1, 2, 3]); 1075 } 1076 1077 { 1078 struct Range{ 1079 int i; 1080 1081 bool empty()(){return i == 0;} 1082 int front()(){return i;} 1083 void popFront()(){i -= 1;} 1084 //size_t length(); //no length 1085 } 1086 1087 List!(int) list = List!(int).build(6, 5, 4); 1088 list.pushFront(Range(3)); 1089 assert(list == [1, 2, 3, 6, 5, 4]); 1090 } 1091 -------------------- 1092 */ 1093 public size_t pushFront(R)(R range)scope 1094 if(isBtlInputRange!R && is(ElementEncodingType!R : ElementType)){ 1095 size_t len = 0; 1096 1097 if(!range.empty){ 1098 scope(exit){ 1099 this._length += len; 1100 } 1101 1102 { 1103 auto node = this._make_node(range.front); 1104 1105 this._push_front_node(node); 1106 1107 len += 1; 1108 range.popFront; 1109 } 1110 1111 1112 while(!range.empty){ 1113 auto node = this._make_node(range.front); 1114 1115 this._push_front_node!true(node); 1116 1117 len += 1; 1118 range.popFront; 1119 } 1120 } 1121 1122 return len; 1123 } 1124 1125 /// ditto 1126 public size_t pushFront(L)(scope auto ref L list)scope 1127 if(isList!L && is(GetElementType!L : ElementType)){ 1128 return this.pushFront(list._op_slice); 1129 } 1130 1131 /// ditto 1132 public size_t pushFront(Val)(auto ref Val val)scope 1133 if(is(Val : ElementType)){ 1134 auto node = this._make_node(forward!val); 1135 1136 this._push_front_node(node); 1137 1138 this._length += 1; 1139 return 1; 1140 1141 } 1142 1143 /// ditto 1144 public size_t pushFront(Val)(auto ref Val val, const size_t count)scope 1145 if(is(Val : ElementType)){ 1146 size_t len = 0; 1147 1148 scope(exit){ 1149 this._length += len; 1150 } 1151 1152 if(count != 0){ 1153 auto node = this._make_node(val); 1154 1155 this._push_front_node(node); 1156 len += 1; 1157 } 1158 1159 if(count != len){ 1160 for(; len < count; ++len){ 1161 auto node = this._make_node(val); 1162 1163 this._push_front_node!true(node); 1164 } 1165 } 1166 1167 return len; 1168 } 1169 1170 1171 1172 /** 1173 Alias to pushFront 1174 */ 1175 public alias prepend = pushFront; 1176 1177 1178 1179 1180 /** 1181 Returns a reference to the last element in the list. 1182 1183 Calling this function on an empty container causes null dereference. 1184 */ 1185 public ref inout(ElementType) back()inout return pure nothrow @system @nogc{ 1186 assert(this._last !is null); 1187 return this._last.element; 1188 } 1189 1190 1191 1192 /** 1193 Returns a copy of the first element in the list. 1194 1195 Calling this function on an empty container causes null dereference. 1196 1197 Examples: 1198 -------------------- 1199 auto list = List!(int).build(1, 2, 3); 1200 1201 assert(list.backCopy == 3); 1202 assert(list == [1, 2, 3]); 1203 -------------------- 1204 */ 1205 public auto backCopy(this This)()scope { 1206 assert(this._last !is null); 1207 1208 return this._last.element; 1209 } 1210 1211 1212 1213 /** 1214 Move of the first element in the list and return it. 1215 1216 Calling this function on an empty container causes null dereference. 1217 1218 Examples: 1219 -------------------- 1220 auto list = List!(int).build(1, 2, 3); 1221 1222 assert(list.moveBack == 3); 1223 list.popBack; 1224 assert(list == [1, 2]); 1225 -------------------- 1226 */ 1227 public ElementType moveBack()scope pure nothrow @safe @nogc{ 1228 assert(this._last !is null); 1229 1230 return move(this._last.element); 1231 } 1232 1233 1234 1235 /** 1236 Pop the last element of the bidirectional list, effectively reducing its length by 1. 1237 1238 Return erased element. 1239 1240 Examples: 1241 -------------------- 1242 List!(int) list = List!(int).build(10, 20, 30); 1243 assert(list.length == 3); 1244 1245 assert(list.popBack == 30); 1246 assert(list.length == 2); 1247 1248 assert(list.popBack == 20); 1249 assert(list.length == 1); 1250 1251 assert(list.popBack == 10); 1252 assert(list.empty); 1253 1254 assert(list.popBack(int.init) == int.init); 1255 assert(list.empty); 1256 1257 assert(list.popBack(42) == 42); 1258 assert(list.empty); 1259 -------------------- 1260 */ 1261 public auto popBack(T = Unqual!ElementType)()scope nothrow 1262 if(is(T == Unqual!ElementType) || is(T == void)){ 1263 assert(!this.empty); 1264 return _pop_back_impl!T(); 1265 } 1266 1267 ///ditto 1268 public auto popBack(T : Unqual!ElementType = Unqual!ElementType)(ElementType def)scope nothrow{ 1269 return this.empty 1270 ? move(def) 1271 : _pop_back_impl!T(); 1272 } 1273 1274 private auto _pop_back_impl(T)()scope nothrow 1275 if(is(T == Unqual!ElementType) || is(T == void)){ 1276 assert(!this.empty); 1277 1278 ListNode* node = this._last; 1279 this._last = this._last.prev; 1280 1281 if(this._last is null) 1282 this._first = null; 1283 else 1284 this._last.next = null; 1285 1286 static if(is(T == void)){ 1287 destructImpl(*node); 1288 this._length -= 1; 1289 } 1290 else{ 1291 ElementType result = move(node.element); 1292 destructImpl(*node); 1293 1294 this._length -= 1; 1295 return move(result); 1296 } 1297 } 1298 1299 1300 1301 /** 1302 Appends a new element to the end of the bidirectional list. The element is constructed through `emplace`. 1303 1304 Parameters: 1305 `args` arguments to forward to the constructor of the element. 1306 1307 Examples: 1308 -------------------- 1309 { 1310 auto list = List!(int).build(1, 2, 3); 1311 1312 list.emplaceBack(42); 1313 assert(list == [1, 2, 3, 42]); 1314 1315 list.emplaceBack(); 1316 assert(list == [1, 2, 3, 42, 0]); 1317 } 1318 1319 { 1320 static struct Foo{ 1321 int i; 1322 string str; 1323 } 1324 1325 auto list = List!(Foo).build(Foo(1, "A")); 1326 1327 list.emplaceBack(2, "B"); 1328 assert(list == only(Foo(1, "A"), Foo(2, "B"))); 1329 } 1330 -------------------- 1331 */ 1332 public void emplaceBack(Args...)(auto ref Args args)scope return{ 1333 ListNode* node = this._make_node(forward!args); 1334 1335 this._push_back_node(node); 1336 this._length += 1; 1337 } 1338 1339 1340 1341 /** 1342 Extends the `List` by appending additional elements at the end of list. 1343 1344 Parameters: 1345 `val` appended value. 1346 1347 `list` appended list. 1348 1349 `range` appended input renge. 1350 1351 `count` Number of times `val` is appended. 1352 1353 Examples: 1354 -------------------- 1355 { 1356 auto list = List!(int).build(1, 2, 3); 1357 1358 list.pushBack(42); 1359 assert(list == [1, 2, 3, 42]); 1360 } 1361 1362 { 1363 auto list = List!(int).build(1, 2, 3); 1364 1365 list.pushBack(only(4, 5, 6)); 1366 assert(list == [1, 2, 3, 4, 5, 6]); 1367 } 1368 1369 { 1370 auto a = List!(int).build(1, 2, 3); 1371 auto b = List!(int).build(4, 5, 6); 1372 1373 a.pushBack(b); 1374 assert(a == [1, 2, 3, 4, 5, 6]); 1375 } 1376 1377 { 1378 List!(int) list = List!(int).build(1, 2, 3); 1379 int[3] tmp = [4, 5, 6]; 1380 list.pushBack(tmp[]); 1381 assert(list == [1, 2, 3, 4, 5, 6]); 1382 } 1383 1384 { 1385 struct Range{ 1386 int i; 1387 1388 bool empty()(){return i == 0;} 1389 int front()(){return i;} 1390 void popFront()(){i -= 1;} 1391 //size_t length(); //no length 1392 } 1393 1394 List!(int) list = List!(int).build(6, 5, 4); 1395 list.pushBack(Range(3)); 1396 assert(list == [6, 5, 4, 3, 2, 1]); 1397 } 1398 -------------------- 1399 */ 1400 public size_t pushBack(R)(R range)scope 1401 if(!isList!R && isBtlInputRange!R && is(ElementEncodingType!R : ElementType)){ 1402 size_t len = 0; 1403 1404 if(!range.empty){ 1405 scope(exit){ 1406 this._length += len; 1407 } 1408 1409 { 1410 auto node = this._make_node(range.front); 1411 1412 this._push_back_node(node); 1413 1414 len += 1; 1415 range.popFront; 1416 } 1417 1418 1419 while(!range.empty){ 1420 auto node = this._make_node(range.front); 1421 1422 this._push_back_node!true(node); 1423 1424 len += 1; 1425 range.popFront; 1426 } 1427 } 1428 1429 return len; 1430 } 1431 1432 /// ditto 1433 public size_t pushBack(L)(scope auto ref L list)scope 1434 if(isList!L && is(GetElementType!L : ElementType)){ 1435 return this.pushBack(list._op_slice); 1436 } 1437 1438 /// ditto 1439 public size_t pushBack(Val)(auto ref Val val)scope 1440 if(is(Val : ElementType)){ 1441 auto node = this._make_node(forward!val); 1442 1443 this._push_back_node(node); 1444 1445 this._length += 1; 1446 return 1; 1447 1448 } 1449 1450 /// ditto 1451 public size_t pushBack(Val)(auto ref Val val, const size_t count)scope 1452 if(is(Val : ElementType)){ 1453 size_t len = 0; 1454 scope(exit){ 1455 this._length += len; 1456 } 1457 1458 if(count != 0){ 1459 auto node = this._make_node(val); 1460 1461 this._push_back_node(node); 1462 len += 1; 1463 } 1464 1465 if(count != len){ 1466 for(; len < count; ++len){ 1467 auto node = this._make_node(val); 1468 1469 this._push_back_node!true(node); 1470 } 1471 } 1472 1473 return len; 1474 } 1475 1476 1477 1478 /** 1479 Alias to pushBack 1480 */ 1481 public alias append = pushBack; 1482 1483 1484 1485 /** 1486 Operator `~=` is same as append/pushBack 1487 */ 1488 public template opOpAssign(string op) 1489 if(op == "~"){ 1490 alias opOpAssign = pushBack; 1491 } 1492 1493 1494 1495 /** 1496 Alias to pushBack 1497 */ 1498 public alias put = pushBack; 1499 1500 1501 1502 /** 1503 Static function which return `List` construct from arguments `args`. 1504 1505 Parameters: 1506 `allocator` exists only if template parameter `_Allocator` has state. 1507 1508 `args` values of type `ElementType`, input range or `List`. 1509 1510 Examples: 1511 -------------------- 1512 import std.range : only; 1513 1514 int[2] tmp = [3, 4]; 1515 auto list = List!(int).build(1, 2, tmp[], only(5, 6), List!(int).build(7, 8)); 1516 assert(list == [1, 2, 3, 4, 5, 6, 7, 8]); 1517 -------------------- 1518 */ 1519 public static typeof(this) build(Args...)(auto ref Args args){ 1520 import core.lifetime : forward; 1521 1522 auto result = List.init; 1523 1524 result._build_impl(forward!args); 1525 1526 return ()@trusted{ 1527 return *&result; 1528 }(); 1529 } 1530 1531 /// ditto 1532 public static typeof(this) build(Args...)(AllocatorType allocator, auto ref Args args){ 1533 import core.lifetime : forward; 1534 1535 auto result = (()@trusted => List(forward!allocator))(); 1536 1537 result._build_impl(forward!args); 1538 1539 return ()@trusted{ 1540 return *&result; 1541 }(); 1542 } 1543 1544 private void _build_impl(Args...)(auto ref Args args)scope{ 1545 import std.traits : isArray; 1546 1547 static foreach(alias arg; args) 1548 this.pushBack(forward!arg); 1549 } 1550 1551 1552 1553 1554 1555 //internals: 1556 static if(hasStatelessAllocator){ 1557 public alias _allocator = statelessAllcoator!AllocatorType; 1558 1559 private enum safeAllocate = isSafe!((){ 1560 size_t capacity = size_t.max; 1561 1562 cast(void)_allocator.allocate(capacity); 1563 }); 1564 } 1565 else{ 1566 public AllocatorType _allocator; 1567 1568 private enum safeAllocate = isSafe!((ref AllocatorType a){ 1569 size_t capacity = size_t.max; 1570 1571 cast(void)a.allocate(capacity); 1572 }); 1573 } 1574 1575 private size_t _length; 1576 private ListNode* _first; 1577 private ListNode* _last; 1578 1579 private ListNode* _make_node(Args...)(auto ref Args args)scope{ 1580 1581 ListNode* node = ()@trusted{ 1582 return cast(ListNode*)_allocator.allocate(ListNode.sizeof).ptr; 1583 }(); 1584 1585 _enforce(node !is null, "allocation fail"); 1586 1587 static if(supportGC) 1588 gcAddRange(node, ListNode.sizeof); 1589 1590 emplaceImpl(node.element, forward!args); 1591 node.next = null; 1592 static if(bidirectional) 1593 node.prev = null; 1594 1595 return node; 1596 } 1597 1598 private void _destroy_node()(ListNode* node)scope nothrow{ 1599 assert(node !is null); 1600 1601 destructImpl(node.element); 1602 1603 void[] data = ()@trusted{ 1604 return (cast(void*)node)[0 .. ListNode.sizeof]; 1605 }(); 1606 1607 static if(supportGC) 1608 gcRemoveRange(data); 1609 1610 static if(safeAllcoate!(typeof(_allocator))) 1611 const d = ()@trusted{ 1612 return _allocator.deallocate(data); 1613 }(); 1614 1615 else 1616 const d = _allocator.deallocate(data); 1617 1618 _enforce(d, "deallocation fail"); 1619 } 1620 1621 1622 //enforce: 1623 private void _enforce(bool con, string msg)const pure nothrow @safe @nogc{ 1624 if(!con)assert(0, msg); 1625 } 1626 1627 private void _push_front_node(bool not_empty = false)(scope ListNode* node)scope pure nothrow @trusted @nogc{ 1628 assert(node !is null); 1629 static if(not_empty) 1630 assert(!this.empty); 1631 1632 const bool is_empty = not_empty 1633 ? false 1634 : (this._first is null); 1635 1636 if(is_empty){ 1637 this._last = node; 1638 } 1639 else{ 1640 node.next = this._first; 1641 static if(bidirectional) 1642 this._first.prev = node; 1643 } 1644 1645 this._first = node; 1646 } 1647 1648 private void _push_back_node(bool not_empty = false)(scope ListNode* node)scope pure nothrow @trusted @nogc{ 1649 assert(node !is null); 1650 static if(not_empty) 1651 assert(!this.empty); 1652 1653 const bool is_empty = not_empty 1654 ? false 1655 : (this._first is null); 1656 1657 if(is_empty){ 1658 this._first = node; 1659 } 1660 else{ 1661 static if(bidirectional) 1662 node.prev = this._last; 1663 1664 this._last.next = node; 1665 } 1666 1667 this._last = node; 1668 } 1669 1670 } 1671 } 1672 1673 1674 /// 1675 unittest{ 1676 import std.range : only; 1677 import std.algorithm : map, equal; 1678 1679 static struct Foo{ 1680 int i; 1681 string str; 1682 } 1683 1684 List!(Foo) list; 1685 1686 assert(list.empty); 1687 1688 list.append(Foo(1, "A")); 1689 assert(list.length == 1); 1690 1691 list.append(only(Foo(2, "B"), Foo(3, "C"))); 1692 assert(list.length == 3); 1693 1694 list.emplaceBack(4, "D"); 1695 assert(list.length == 4); 1696 1697 1698 list = List!(Foo).build(Foo(-1, "X"), Foo(-2, "Y")); 1699 assert(equal(list[].map!(e => e.str), only("X", "Y"))); 1700 1701 list.release(); 1702 assert(list.length == 0); 1703 1704 } 1705 1706 1707 /// Alias to `List` with parameter `_bidirectional = true` (single linked list) 1708 public template ForwardList( 1709 _Type, 1710 _Allocator = DefaultAllocator, 1711 bool _supportGC = shouldAddGCRange!_Type 1712 ){ 1713 alias ForwardList = .List!(_Type, _Allocator, _supportGC, false); 1714 } 1715 1716 //local traits: 1717 private{ 1718 1719 enum bool safeAllcoate(A) = __traits(compiles, (ref A allcoator)@safe{ 1720 const size_t size; 1721 allcoator.allocate(size); 1722 }(*cast(A*)null)); 1723 1724 1725 //copy ctor: 1726 template hasCopyConstructor(From, To) 1727 if(is(immutable From == immutable To)){ 1728 1729 enum bool hasCopyConstructor = true 1730 && !is(From == shared) 1731 && isConstructable!(From, To) 1732 && isCopyConstructableElement!( 1733 GetElementType!From, 1734 GetElementType!To 1735 ) 1736 && (From.hasStatelessAllocator 1737 || isCopyConstructableElement!( 1738 GetAllocatorType!From, 1739 GetAllocatorType!To 1740 ) 1741 ) 1742 && (From.hasStatelessAllocator 1743 || isCopyConstructableElement!( 1744 GetAllocatorType!From, 1745 To.AllocatorType 1746 ) 1747 ); 1748 } 1749 1750 //Move Constructable: 1751 template isMoveConstructable(alias from, To){ 1752 alias From = typeof(from); 1753 1754 enum isMoveConstructable = true 1755 && !isRef!from 1756 && isConstructable!(From, To) 1757 && (From.bidirectional == To.bidirectional) 1758 && is(GetElementReferenceType!From : GetElementReferenceType!To) 1759 && is(immutable From.AllocatorType == immutable To.AllocatorType) 1760 && (From.hasStatelessAllocator 1761 || isMoveConstructableElement!( 1762 GetAllocatorType!From, 1763 GetAllocatorType!To 1764 ) 1765 ); 1766 } 1767 1768 //Move Assignable: 1769 template isMoveAssignable(alias from, To){ 1770 alias From = typeof(from); 1771 1772 enum isMoveAssignable = true 1773 && !isRef!from 1774 && isAssignable!(From, To) 1775 && (From.bidirectional == To.bidirectional) 1776 && is(GetElementReferenceType!From : GetElementReferenceType!To) 1777 && is(immutable From.AllocatorType == immutable To.AllocatorType) 1778 && (From.hasStatelessAllocator 1779 || isMoveAssignableElement!( 1780 GetAllocatorType!From, 1781 GetAllocatorType!To 1782 ) 1783 ); 1784 } 1785 1786 //Constructable: 1787 template isConstructable(From, To){ 1788 1789 enum isConstructable = true 1790 && !is(From == shared) 1791 && (From.supportGC == To.supportGC) 1792 && is(GetElementType!From : GetElementType!To) 1793 && (From.hasStatelessAllocator 1794 ? is(immutable From.AllocatorType == immutable To.AllocatorType) 1795 : is(immutable From.AllocatorType : immutable To.AllocatorType) 1796 ); 1797 } 1798 1799 //Assignable: 1800 template isAssignable(From, To){ 1801 import std.traits : isMutable; 1802 1803 enum isAssignable = true 1804 && isMutable!To 1805 && !is(From == shared) && !is(To == shared) 1806 && (From.supportGC == To.supportGC) 1807 && is(GetElementType!From : GetElementType!To); 1808 } 1809 1810 1811 1812 template GetElementType(Container){ 1813 alias GetElementType = CopyTypeQualifiers!(Container, Container.ElementType); 1814 } 1815 1816 template GetAllocatorType(Container){ 1817 alias GetAllocatorType = CopyTypeQualifiers!(Container, Container.AllocatorType); 1818 } 1819 1820 template GetElementReferenceType(Container){ 1821 alias GetElementReferenceType = ElementReferenceTypeImpl!(GetElementType!Container); 1822 } 1823 1824 template ElementReferenceTypeImpl(T){ 1825 import std.traits : Select, isDynamicArray; 1826 import std.range : ElementEncodingType; 1827 1828 static if(false 1829 || is(T == class) || is(T == interface) 1830 || is(T == function) || is(T == delegate) 1831 || is(T : U*, U) 1832 ){ 1833 alias ElementReferenceTypeImpl = T; 1834 } 1835 else static if(isDynamicArray!T){ 1836 alias ElementReferenceTypeImpl = ElementEncodingType!T[]; 1837 } 1838 else{ 1839 alias ElementReferenceTypeImpl = T*; 1840 } 1841 } 1842 1843 1844 } 1845 1846 //List examples: 1847 version(unittest){ 1848 1849 import std.range : only; 1850 static foreach(alias List; AliasSeq!(.List)){ 1851 1852 //List.empty 1853 pure nothrow @safe @nogc unittest{ 1854 List!(int) list; 1855 assert(list.empty); 1856 1857 list.append(42); 1858 assert(!list.empty); 1859 } 1860 1861 //List.length 1862 pure nothrow @safe @nogc unittest{ 1863 List!(int) list = null; 1864 assert(list.length == 0); 1865 1866 list.append(42); 1867 assert(list.length == 1); 1868 1869 list.append(123); 1870 assert(list.length == 2); 1871 1872 list.clear(); 1873 assert(list.length == 0); 1874 } 1875 1876 //List.ctor(allocator) 1877 pure nothrow @safe @nogc unittest{ 1878 { 1879 List!(int) list = DefaultAllocator.init; 1880 assert(list.empty); 1881 } 1882 } 1883 1884 //List.ctor(null) 1885 pure nothrow @safe @nogc unittest{ 1886 { 1887 List!(int) list = null; 1888 assert(list.empty); 1889 } 1890 } 1891 1892 //List.ctor(list) 1893 pure nothrow @safe @nogc unittest{ 1894 { 1895 List!(int) list = List!(int).build(1, 2); 1896 assert(list == [1, 2]); 1897 } 1898 { 1899 auto tmp = List!(int).build(1, 2); 1900 List!(int) list = tmp; 1901 assert(list == [1, 2]); 1902 } 1903 1904 1905 { 1906 List!(int) list = List!(int).build(1, 2); 1907 assert(list == [1, 2]); 1908 } 1909 { 1910 auto tmp = List!(int).build(1, 2); 1911 List!(int) list = tmp; 1912 assert(list == [1, 2]); 1913 } 1914 } 1915 1916 //List.ctor(range) 1917 pure nothrow @safe @nogc unittest{ 1918 import std.range : iota; 1919 { 1920 List!(int) list = iota(0, 5); 1921 assert(list == [0, 1, 2, 3, 4]); 1922 } 1923 } 1924 1925 //List.opAssign 1926 pure nothrow @safe @nogc unittest{ 1927 List!(int) list = List!(int).build(1, 2, 3); 1928 assert(!list.empty); 1929 1930 list = null; 1931 assert(list.empty); 1932 1933 list = List!(int).build(3, 2, 1); 1934 assert(list == [3, 2, 1]); 1935 1936 list = List!(int).build(4, 2); 1937 assert(list == [4, 2]); 1938 } 1939 1940 //List.release 1941 pure nothrow @safe @nogc unittest{ 1942 List!(int) list = List!(int).build(1, 2, 3); 1943 assert(list.length == 3); 1944 1945 list.release(); 1946 assert(list.length == 0); 1947 } 1948 1949 //List.clear 1950 pure nothrow @safe @nogc unittest{ 1951 List!(int) list = List!(int).build(1, 2, 3); 1952 assert(list.length == 3); 1953 1954 list.clear(); 1955 assert(list.length == 0); 1956 } 1957 1958 //List.contains 1959 pure nothrow @safe @nogc unittest{ 1960 List!(int) list = List!(int).build(1, 2, 3); 1961 1962 assert(list.contains(1)); 1963 assert(!list.contains(42L)); 1964 } 1965 1966 //List.opBinaryRight!"in" 1967 pure nothrow @safe @nogc unittest{ 1968 List!(int) list = List!(int).build(1, 2, 3); 1969 1970 assert(1 in list); 1971 assert(42L !in list); 1972 } 1973 1974 //List.opEquals 1975 pure nothrow @safe @nogc unittest{ 1976 List!(int) list = List!(int).build(1, 2, 3); 1977 1978 assert(list != null); 1979 assert(null != list); 1980 1981 assert(list == [1, 2, 3]); 1982 assert([1, 2, 3] == list); 1983 1984 assert(list == typeof(list).build(1, 2, 3)); 1985 assert(typeof(list).build(1, 2, 3) == list); 1986 1987 import std.range : only; 1988 assert(list == only(1, 2, 3)); 1989 assert(only(1, 2, 3) == list); 1990 } 1991 1992 //List.opCmp 1993 pure nothrow @safe @nogc unittest{ 1994 auto a1 = List!(int).build(1, 2, 3); 1995 auto a2 = List!(int).build(1, 2, 3, 4); 1996 auto b = List!(int).build(3, 2, 1); 1997 1998 assert(a1 < b); 1999 assert(a1 < a2); 2000 assert(a2 < b); 2001 assert(a1 <= a1); 2002 } 2003 2004 //List.opIndex 2005 pure nothrow @safe @nogc unittest{ 2006 List!(int) list = List!(int).build(1, 2, 3); 2007 } 2008 2009 //List.proxySwap 2010 pure nothrow @safe @nogc unittest{ 2011 auto a = List!(int).build(1, 2, 3); 2012 auto b = List!(int).build(4, 5, 6); 2013 2014 a.proxySwap(b); 2015 assert(a == [4, 5, 6]); 2016 assert(b == [1, 2, 3]); 2017 2018 import std.algorithm.mutation : swap; 2019 2020 swap(a, b); 2021 assert(a == [1, 2, 3]); 2022 assert(b == [4, 5, 6]); 2023 } 2024 2025 //List.frontCopy 2026 pure nothrow @safe @nogc unittest{ 2027 auto list = List!(int).build(1, 2, 3); 2028 2029 assert(list.frontCopy == 1); 2030 assert(list == [1, 2, 3]); 2031 } 2032 2033 //List.moveFront 2034 pure nothrow @safe @nogc unittest{ 2035 auto list = List!(int).build(1, 2, 3); 2036 2037 assert(list.moveFront == 1); 2038 list.popFront; 2039 assert(list == [2, 3]); 2040 } 2041 2042 //List.popFront 2043 pure nothrow @safe @nogc unittest{ 2044 List!(int) list = List!(int).build(30, 20, 10); 2045 assert(list.length == 3); 2046 2047 assert(list.popFront == 30); 2048 assert(list.length == 2); 2049 2050 assert(list.popFront == 20); 2051 assert(list.length == 1); 2052 2053 assert(list.popFront == 10); 2054 assert(list.empty); 2055 2056 assert(list.popFront(int.init) == int.init); 2057 assert(list.empty); 2058 2059 assert(list.popFront(42) == 42); 2060 assert(list.empty); 2061 } 2062 2063 //List.emplaceFront 2064 pure nothrow @safe @nogc unittest{ 2065 { 2066 auto list = List!(int).build(1, 2, 3); 2067 2068 list.emplaceFront(42); 2069 assert(list == [42, 1, 2, 3]); 2070 2071 list.emplaceFront(); 2072 assert(list == [0, 42, 1, 2, 3]); 2073 } 2074 2075 { 2076 static struct Foo{ 2077 int i; 2078 string str; 2079 } 2080 2081 auto list = List!(Foo).build(Foo(1, "A")); 2082 2083 list.emplaceFront(2, "B"); 2084 assert(list == only(Foo(2, "B"), Foo(1, "A"))); 2085 } 2086 } 2087 2088 //List.pushFront 2089 pure nothrow @safe @nogc unittest{ 2090 { 2091 auto list = List!(int).build(1, 2, 3); 2092 2093 list.pushFront(42); 2094 assert(list == [42, 1, 2, 3]); 2095 } 2096 2097 { 2098 auto list = List!(int).build(1, 2, 3); 2099 2100 list.pushFront(only(4, 5, 6)); 2101 assert(list == [6, 5, 4, 1, 2, 3]); 2102 } 2103 2104 { 2105 auto a = List!(int).build(1, 2, 3); 2106 auto b = List!(int).build(4, 5, 6); 2107 2108 a.pushFront(b); 2109 assert(a == [6, 5, 4, 1, 2, 3]); 2110 } 2111 2112 { 2113 List!(int) list = List!(int).build(1, 2, 3); 2114 int[3] tmp = [4, 5, 6]; 2115 list.pushFront(tmp[]); 2116 assert(list == [6, 5, 4, 1, 2, 3]); 2117 } 2118 2119 { 2120 struct Range{ 2121 int i; 2122 2123 bool empty()(){return i == 0;} 2124 int front()(){return i;} 2125 void popFront()(){i -= 1;} 2126 //size_t length(); //no length 2127 } 2128 2129 List!(int) list = List!(int).build(6, 5, 4); 2130 list.pushFront(Range(3)); 2131 assert(list == [1, 2, 3, 6, 5, 4]); 2132 } 2133 } 2134 2135 //List.backCopy 2136 pure nothrow @safe @nogc unittest{ 2137 auto list = List!(int).build(1, 2, 3); 2138 2139 assert(list.backCopy == 3); 2140 assert(list == [1, 2, 3]); 2141 } 2142 2143 //List.moveBack 2144 pure nothrow @safe @nogc unittest{ 2145 auto list = List!(int).build(1, 2, 3); 2146 2147 assert(list.moveBack == 3); 2148 list.popBack; 2149 assert(list == [1, 2]); 2150 } 2151 2152 //List.popBack 2153 pure nothrow @safe @nogc unittest{ 2154 List!(int) list = List!(int).build(10, 20, 30); 2155 assert(list.length == 3); 2156 2157 assert(list.popBack == 30); 2158 assert(list.length == 2); 2159 2160 assert(list.popBack == 20); 2161 assert(list.length == 1); 2162 2163 assert(list.popBack == 10); 2164 assert(list.empty); 2165 2166 assert(list.popBack(int.init) == int.init); 2167 assert(list.empty); 2168 2169 assert(list.popBack(42) == 42); 2170 assert(list.empty); 2171 } 2172 2173 //List.emplaceBack 2174 pure nothrow @safe @nogc unittest{ 2175 { 2176 auto list = List!(int).build(1, 2, 3); 2177 2178 list.emplaceBack(42); 2179 assert(list == [1, 2, 3, 42]); 2180 2181 list.emplaceBack(); 2182 assert(list == [1, 2, 3, 42, 0]); 2183 } 2184 2185 { 2186 static struct Foo{ 2187 int i; 2188 string str; 2189 } 2190 2191 auto list = List!(Foo).build(Foo(1, "A")); 2192 2193 list.emplaceBack(2, "B"); 2194 assert(list == only(Foo(1, "A"), Foo(2, "B"))); 2195 } 2196 } 2197 2198 //List.pushBack 2199 pure nothrow @safe @nogc unittest{ 2200 { 2201 auto list = List!(int).build(1, 2, 3); 2202 2203 list.pushBack(42); 2204 assert(list == [1, 2, 3, 42]); 2205 } 2206 2207 { 2208 auto list = List!(int).build(1, 2, 3); 2209 2210 list.pushBack(only(4, 5, 6)); 2211 assert(list == [1, 2, 3, 4, 5, 6]); 2212 } 2213 2214 { 2215 auto a = List!(int).build(1, 2, 3); 2216 auto b = List!(int).build(4, 5, 6); 2217 2218 a.pushBack(b); 2219 assert(a == [1, 2, 3, 4, 5, 6]); 2220 } 2221 2222 { 2223 List!(int) list = List!(int).build(1, 2, 3); 2224 int[3] tmp = [4, 5, 6]; 2225 list.pushBack(tmp[]); 2226 assert(list == [1, 2, 3, 4, 5, 6]); 2227 } 2228 2229 { 2230 struct Range{ 2231 int i; 2232 2233 bool empty()(){return i == 0;} 2234 int front()(){return i;} 2235 void popFront()(){i -= 1;} 2236 //size_t length(); //no length 2237 } 2238 2239 List!(int) list = List!(int).build(6, 5, 4); 2240 list.pushBack(Range(3)); 2241 assert(list == [6, 5, 4, 3, 2, 1]); 2242 } 2243 } 2244 2245 //List.build 2246 pure nothrow @safe @nogc unittest{ 2247 import std.range : only; 2248 2249 int[2] tmp = [3, 4]; 2250 auto list = List!(int).build(1, 2, tmp[], only(5, 6), List!(int).build(7, 8)); 2251 assert(list == [1, 2, 3, 4, 5, 6, 7, 8]); 2252 } 2253 } 2254 2255 2256 }