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