1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.collection.LinkedList; 13 14 import hunt.collection.AbstractList; 15 import hunt.collection.AbstractSequentialList; 16 import hunt.collection.Collection; 17 import hunt.collection.Deque; 18 import hunt.collection.List; 19 20 import hunt.Exceptions; 21 import hunt.Object; 22 import hunt.util.Common; 23 24 import std.conv; 25 import std.container; 26 import std.range; 27 28 29 30 /** 31 * Doubly-linked list implementation of the {@code List} and {@code Deque} 32 * interfaces. Implements all optional list operations, and permits all 33 * elements (including {@code null}). 34 * 35 * <p>All of the operations perform as could be expected for a doubly-linked 36 * list. Operations that index into the list will traverse the list from 37 * the beginning or the end, whichever is closer to the specified index. 38 * 39 * <p><strong>Note that this implementation is not synchronized.</strong> 40 * If multiple threads access a linked list concurrently, and at least 41 * one of the threads modifies the list structurally, it <i>must</i> be 42 * synchronized externally. (A structural modification is any operation 43 * that adds or deletes one or more elements; merely setting the value of 44 * an element is not a structural modification.) This is typically 45 * accomplished by synchronizing on some object that naturally 46 * encapsulates the list. 47 * 48 * If no such object exists, the list should be "wrapped" using the 49 * {@link Collections#synchronizedList Collections.synchronizedList} 50 * method. This is best done at creation time, to prevent accidental 51 * unsynchronized access to the list:<pre> 52 * List list = Collections.synchronizedList(new LinkedList(...));</pre> 53 * 54 * <p>The iterators returned by this class's {@code iterator} and 55 * {@code listIterator} methods are <i>fail-fast</i>: if the list is 56 * structurally modified at any time after the iterator is created, in 57 * any way except through the Iterator's own {@code remove} or 58 * {@code add} methods, the iterator will throw a {@link 59 * ConcurrentModificationException}. Thus, in the face of concurrent 60 * modification, the iterator fails quickly and cleanly, rather than 61 * risking arbitrary, non-deterministic behavior at an undetermined 62 * time in the future. 63 * 64 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 65 * as it is, generally speaking, impossible to make any hard guarantees in the 66 * presence of unsynchronized concurrent modification. Fail-fast iterators 67 * throw {@code ConcurrentModificationException} on a best-effort basis. 68 * Therefore, it would be wrong to write a program that depended on this 69 * exception for its correctness: <i>the fail-fast behavior of iterators 70 * should be used only to detect bugs.</i> 71 * 72 * <p>This class is a member of the 73 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 74 * Java Collections Framework</a>. 75 * 76 * @author Josh Bloch 77 * @see List 78 * @see ArrayList 79 * @param E the type of elements held in this collection 80 */ 81 82 class LinkedList(E) : AbstractSequentialList!E, Deque!E { //, Cloneable 83 // alias remove = AbstractSequentialList!E.remove; 84 85 DList!E _dlist; 86 int _size = 0; 87 88 /** 89 * Constructs an empty list. 90 */ 91 this() { 92 } 93 94 /** 95 * Constructs a list containing the elements of the specified 96 * collection, in the order they are returned by the collection's 97 * iterator. 98 * 99 * @param c the collection whose elements are to be placed into this list 100 * @throws NullPointerException if the specified collection is null 101 */ 102 this(Collection!E c) { 103 this(); 104 addAll(c); 105 } 106 107 108 this(E[] c) { 109 this(); 110 addAll(c); 111 } 112 113 /** 114 * Links e as first element. 115 */ 116 private void linkFirst(E e) { 117 _dlist.insertFront(e); 118 _size++; 119 modCount++; 120 } 121 122 /** 123 * Links e as last element. 124 */ 125 void linkLast(E e) { 126 _dlist.insertBack(e); 127 _size++; 128 modCount++; 129 } 130 131 /** 132 * Inserts element e before non-null Node succ. 133 */ 134 // void linkBefore(E e, Node!E succ) { 135 // // assert succ !is null; 136 // final Node!E pred = succ.prev; 137 // final Node!E newNode = new Node<>(pred, e, succ); 138 // succ.prev = newNode; 139 // if (pred is null) 140 // first = newNode; 141 // else 142 // pred.next = newNode; 143 // _size++; 144 // modCount++; 145 // } 146 147 /** 148 * Unlinks non-null first node f. 149 */ 150 private E unlinkFirst() { 151 E element = _dlist.front; 152 _dlist.removeFront(); 153 _size--; 154 modCount++; 155 return element; 156 } 157 158 /** 159 * Unlinks non-null last node l. 160 */ 161 private E unlinkLast() { 162 E element = _dlist.back; 163 _dlist.removeBack; 164 _size--; 165 modCount++; 166 return element; 167 } 168 169 170 /** 171 * Returns the first element in this list. 172 * 173 * @return the first element in this list 174 * @throws NoSuchElementException if this list is empty 175 */ 176 E getFirst() { 177 return _dlist.front; 178 } 179 180 /** 181 * Returns the last element in this list. 182 * 183 * @return the last element in this list 184 * @throws NoSuchElementException if this list is empty 185 */ 186 E getLast() { 187 return _dlist.back; 188 } 189 190 /** 191 * Removes and returns the first element from this list. 192 * 193 * @return the first element from this list 194 * @throws NoSuchElementException if this list is empty 195 */ 196 E removeFirst() { 197 if(_size<=0) return E.init; 198 return unlinkFirst(); 199 } 200 201 /** 202 * Removes and returns the last element from this list. 203 * 204 * @return the last element from this list 205 * @throws NoSuchElementException if this list is empty 206 */ 207 E removeLast() { 208 if(_size<=0) return E.init; 209 return unlinkLast(); 210 } 211 212 /** 213 * Inserts the specified element at the beginning of this list. 214 * 215 * @param e the element to add 216 */ 217 void addFirst(E e) { 218 linkFirst(e); 219 } 220 221 /** 222 * Appends the specified element to the end of this list. 223 * 224 * <p>This method is equivalent to {@link #add}. 225 * 226 * @param e the element to add 227 */ 228 void addLast(E e) { 229 linkLast(e); 230 } 231 232 /** 233 * Returns {@code true} if this list contains the specified element. 234 * More formally, returns {@code true} if and only if this list contains 235 * at least one element {@code e} such that 236 * <tt>(o==null ? e==null : o.equals(e))</tt>. 237 * 238 * @param o element whose presence in this list is to be tested 239 * @return {@code true} if this list contains the specified element 240 */ 241 override bool contains(E o) { 242 return indexOf(o) != -1; 243 } 244 245 /** 246 * Returns the number of elements in this list. 247 * 248 * @return the number of elements in this list 249 */ 250 override int size() { 251 return _size; 252 } 253 254 /** 255 * Appends the specified element to the end of this list. 256 * 257 * <p>This method is equivalent to {@link #addLast}. 258 * 259 * @param e element to be appended to this list 260 * @return {@code true} (as specified by {@link Collection#add}) 261 */ 262 override bool add(E e) { 263 linkLast(e); 264 return true; 265 } 266 267 /** 268 * Removes the first occurrence of the specified element from this list, 269 * if it is present. If this list does not contain the element, it is 270 * unchanged. More formally, removes the element with the lowest index 271 * {@code i} such that 272 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt> 273 * (if such an element exists). Returns {@code true} if this list 274 * contained the specified element (or equivalently, if this list 275 * changed as a result of the call). 276 * 277 * @param o element to be removed from this list, if present 278 * @return {@code true} if this list contained the specified element 279 */ 280 override bool remove(E o) { 281 static if(CompilerHelper.isLessThan(2077)) { 282 auto range = _dlist[]; 283 for ( ; !range.empty; range.popFront()) 284 { 285 if (range.front == o) 286 { 287 _dlist.stableLinearRemove(take(range, 1)); 288 _size--; 289 modCount++; 290 return true; 291 } 292 } 293 return false; 294 } else { 295 if(_dlist.linearRemoveElement(o)) { 296 _size--; 297 modCount++; 298 return true; 299 } else { 300 return false; 301 } 302 } 303 } 304 305 // /** 306 // * Appends all of the elements in the specified collection to the end of 307 // * this list, in the order that they are returned by the specified 308 // * collection's iterator. The behavior of this operation is undefined if 309 // * the specified collection is modified while the operation is in 310 // * progress. (Note that this will occur if the specified collection is 311 // * this list, and it's nonempty.) 312 // * 313 // * @param c collection containing elements to be added to this list 314 // * @return {@code true} if this list changed as a result of the call 315 // * @throws NullPointerException if the specified collection is null 316 // */ 317 // override bool addAll(Collection!E c) { 318 319 // bool modified = c.size() > 0; 320 // foreach (E e ; c) { 321 // linkLast(e); 322 // } 323 // return modified; 324 325 // // return addAll(_size, c); 326 // } 327 328 // bool addAll(E[] c) { 329 330 // bool modified = c.length > 0; 331 // foreach (E e ; c) { 332 // linkLast(e); 333 // } 334 // return modified; 335 // } 336 337 // /** 338 // * Inserts all of the elements in the specified collection into this 339 // * list, starting at the specified position. Shifts the element 340 // * currently at that position (if any) and any subsequent elements to 341 // * the right (increases their indices). The new elements will appear 342 // * in the list in the order that they are returned by the 343 // * specified collection's iterator. 344 // * 345 // * @param index index at which to insert the first element 346 // * from the specified collection 347 // * @param c collection containing elements to be added to this list 348 // * @return {@code true} if this list changed as a result of the call 349 // * @throws IndexOutOfBoundsException {@inheritDoc} 350 // * @throws NullPointerException if the specified collection is null 351 // */ 352 353 // bool addAll(int index, Collection!E c) { 354 // throw new NotImplementedException(); 355 // } 356 // bool addAll(int index, Collection<E> c) { 357 // checkPositionIndex(index); 358 359 // Object[] a = c.toArray(); 360 // int numNew = a.length; 361 // if (numNew == 0) 362 // return false; 363 364 // Node!E pred, succ; 365 // if (index == _size) { 366 // succ = null; 367 // pred = last; 368 // } else { 369 // succ = node(index); 370 // pred = succ.prev; 371 // } 372 373 // for (Object o : a) { 374 // E e = (E) o; 375 // Node!E newNode = new Node<>(pred, e, null); 376 // if (pred is null) 377 // first = newNode; 378 // else 379 // pred.next = newNode; 380 // pred = newNode; 381 // } 382 383 // if (succ is null) { 384 // last = pred; 385 // } else { 386 // pred.next = succ; 387 // succ.prev = pred; 388 // } 389 390 // _size += numNew; 391 // modCount++; 392 // return true; 393 // } 394 395 /** 396 * Removes all of the elements from this list. 397 * The list will be empty after this call returns. 398 */ 399 override void clear() { 400 _dlist.clear(); 401 _size = 0; 402 modCount++; 403 } 404 405 406 // Positional Access Operations 407 408 /** 409 * Returns the element at the specified position in this list. 410 * 411 * @param index index of the element to return 412 * @return the element at the specified position in this list 413 * @throws IndexOutOfBoundsException {@inheritDoc} 414 */ 415 override E get(int index) { 416 checkElementIndex(index); 417 418 int i=0; 419 foreach(v; _dlist) 420 { 421 if(i == index) 422 return v; 423 i++; 424 } 425 return E.init; 426 } 427 428 /** 429 * Replaces the element at the specified position in this list with the 430 * specified element. 431 * 432 * @param index index of the element to replace 433 * @param element element to be stored at the specified position 434 * @return the element previously at the specified position 435 * @throws IndexOutOfBoundsException {@inheritDoc} 436 */ 437 override E set(int index, E element) { 438 checkElementIndex(index); 439 440 int i= 0; 441 auto range = _dlist[]; 442 range.popFrontN(index); 443 E oldVal = range.front; 444 range.front = element; 445 446 // for ( ; !range.empty; range.popFront()) 447 // { 448 // if(i == index) 449 // { 450 // oldVal = range.front; 451 // range.front = element; 452 // break; 453 // } 454 // i++; 455 // } 456 457 return oldVal; 458 } 459 460 /** 461 * Inserts the specified element at the specified position in this list. 462 * Shifts the element currently at that position (if any) and any 463 * subsequent elements to the right (adds one to their indices). 464 * 465 * @param index index at which the specified element is to be inserted 466 * @param element element to be inserted 467 * @throws IndexOutOfBoundsException {@inheritDoc} 468 */ 469 override void add(int index, E element) { 470 checkPositionIndex(index); 471 472 if (index == _size) 473 linkLast(element); 474 else 475 { 476 auto range = _dlist[]; 477 range.popFrontN(index); 478 _dlist.insertBefore(range, element); 479 _size++; 480 modCount++; 481 } 482 // linkBefore(element, node(index)); 483 } 484 485 /** 486 * Removes the element at the specified position in this list. Shifts any 487 * subsequent elements to the left (subtracts one from their indices). 488 * Returns the element that was removed from the list. 489 * 490 * @param index the index of the element to be removed 491 * @return the element previously at the specified position 492 * @throws IndexOutOfBoundsException {@inheritDoc} 493 */ 494 override E removeAt(int index) { 495 checkElementIndex(index); 496 auto range = _dlist[]; 497 range.popFrontN(index); 498 auto temp = take(range, 1); 499 _dlist.linearRemove(temp); 500 501 _size--; 502 modCount++; 503 return temp.front; 504 } 505 506 /** 507 * Tells if the argument is the index of an existing element. 508 */ 509 private bool isElementIndex(int index) { 510 return index >= 0 && index < _size; 511 } 512 513 /** 514 * Tells if the argument is the index of a valid position for an 515 * iterator or an add operation. 516 */ 517 private bool isPositionIndex(int index) { 518 return index >= 0 && index <= _size; 519 } 520 521 /** 522 * Constructs an IndexOutOfBoundsException detail message. 523 * Of the many possible refactorings of the error handling code, 524 * this "outlining" performs best with both server and client VMs. 525 */ 526 private string outOfBoundsMsg(int index) { 527 return "Index: " ~ index.to!string() ~ ", Size: " ~ _size.to!string(); 528 } 529 530 private void checkElementIndex(int index) { 531 if (!isElementIndex(index)) 532 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 533 } 534 535 private void checkPositionIndex(int index) { 536 if (!isPositionIndex(index)) 537 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 538 } 539 540 /** 541 * Returns the (non-null) Node at the specified element index. 542 */ 543 544 // Node!E node(int index) { 545 // // assert isElementIndex(index); 546 547 // if (index < (_size >> 1)) { 548 // Node!E x = first; 549 // for (int i = 0; i < index; i++) 550 // x = x.next; 551 // return x; 552 // } else { 553 // Node!E x = last; 554 // for (int i = _size - 1; i > index; i--) 555 // x = x.prev; 556 // return x; 557 // } 558 // } 559 560 // Search Operations 561 562 /** 563 * Returns the index of the first occurrence of the specified element 564 * in this list, or -1 if this list does not contain the element. 565 * More formally, returns the lowest index {@code i} such that 566 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, 567 * or -1 if there is no such index. 568 * 569 * @param o element to search for 570 * @return the index of the first occurrence of the specified element in 571 * this list, or -1 if this list does not contain the element 572 */ 573 override int indexOf(E o) { 574 int index = 0; 575 foreach(v; _dlist) 576 { 577 static if( is(E == class)) 578 { 579 if(v == o) 580 return index; 581 } 582 else 583 { 584 if(v == o) 585 return index; 586 } 587 index++; 588 } 589 return -1; 590 } 591 592 /** 593 * Returns the index of the last occurrence of the specified element 594 * in this list, or -1 if this list does not contain the element. 595 * More formally, returns the highest index {@code i} such that 596 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, 597 * or -1 if there is no such index. 598 * 599 * @param o element to search for 600 * @return the index of the last occurrence of the specified element in 601 * this list, or -1 if this list does not contain the element 602 */ 603 override int lastIndexOf(E o) { 604 int index = _size; 605 auto range = _dlist[]; 606 for(; !range.empty; range.popBack()) 607 { 608 index--; 609 if(range.back == o) 610 return index; 611 } 612 return -1; 613 } 614 615 // Queue operations. 616 617 /** 618 * Retrieves, but does not remove, the head (first element) of this list. 619 * 620 * @return the head of this list, or {@code null} if this list is empty 621 */ 622 E peek() { 623 return getFirst(); 624 } 625 626 /** 627 * Retrieves, but does not remove, the head (first element) of this list. 628 * 629 * @return the head of this list 630 * @throws NoSuchElementException if this list is empty 631 */ 632 E element() { 633 return getFirst(); 634 } 635 636 /** 637 * Retrieves and removes the head (first element) of this list. 638 * 639 * @return the head of this list, or {@code null} if this list is empty 640 */ 641 E poll() { 642 return removeFirst(); 643 } 644 645 /** 646 * Retrieves and removes the head (first element) of this list. 647 * 648 * @return the head of this list 649 * @throws NoSuchElementException if this list is empty 650 */ 651 E remove() { 652 return removeFirst(); 653 } 654 655 /** 656 * Adds the specified element as the tail (last element) of this list. 657 * 658 * @param e the element to add 659 * @return {@code true} (as specified by {@link Queue#offer}) 660 */ 661 bool offer(E e) { 662 return add(e); 663 } 664 665 // Deque operations 666 /** 667 * Inserts the specified element at the front of this list. 668 * 669 * @param e the element to insert 670 * @return {@code true} (as specified by {@link Deque#offerFirst}) 671 */ 672 bool offerFirst(E e) { 673 addFirst(e); 674 return true; 675 } 676 677 /** 678 * Inserts the specified element at the end of this list. 679 * 680 * @param e the element to insert 681 * @return {@code true} (as specified by {@link Deque#offerLast}) 682 */ 683 bool offerLast(E e) { 684 addLast(e); 685 return true; 686 } 687 688 /** 689 * Retrieves, but does not remove, the first element of this list, 690 * or returns {@code null} if this list is empty. 691 * 692 * @return the first element of this list, or {@code null} 693 * if this list is empty 694 */ 695 E peekFirst() { 696 return getFirst(); 697 } 698 699 /** 700 * Retrieves, but does not remove, the last element of this list, 701 * or returns {@code null} if this list is empty. 702 * 703 * @return the last element of this list, or {@code null} 704 * if this list is empty 705 */ 706 E peekLast() { 707 return getLast(); 708 } 709 710 /** 711 * Retrieves and removes the first element of this list, 712 * or returns {@code null} if this list is empty. 713 * 714 * @return the first element of this list, or {@code null} if 715 * this list is empty 716 */ 717 E pollFirst() { 718 return removeFirst(); 719 } 720 721 /** 722 * Retrieves and removes the last element of this list, 723 * or returns {@code null} if this list is empty. 724 * 725 * @return the last element of this list, or {@code null} if 726 * this list is empty 727 */ 728 E pollLast() { 729 return removeLast(); 730 } 731 732 /** 733 * Pushes an element onto the stack represented by this list. In other 734 * words, inserts the element at the front of this list. 735 * 736 * <p>This method is equivalent to {@link #addFirst}. 737 * 738 * @param e the element to push 739 */ 740 void push(E e) { 741 addFirst(e); 742 } 743 744 /** 745 * Pops an element from the stack represented by this list. In other 746 * words, removes and returns the first element of this list. 747 * 748 * <p>This method is equivalent to {@link #removeFirst()}. 749 * 750 * @return the element at the front of this list (which is the top 751 * of the stack represented by this list) 752 * @throws NoSuchElementException if this list is empty 753 */ 754 E pop() { 755 return removeFirst(); 756 } 757 758 /** 759 * Removes the first occurrence of the specified element in this 760 * list (when traversing the list from head to tail). If the list 761 * does not contain the element, it is unchanged. 762 * 763 * @param o element to be removed from this list, if present 764 * @return {@code true} if the list contained the specified element 765 */ 766 bool removeFirstOccurrence(E o) { 767 return remove(o); 768 } 769 770 /** 771 * Removes the last occurrence of the specified element in this 772 * list (when traversing the list from head to tail). If the list 773 * does not contain the element, it is unchanged. 774 * 775 * @param o element to be removed from this list, if present 776 * @return {@code true} if the list contained the specified element 777 */ 778 // bool removeLastOccurrence(E o) { 779 780 // // if (o is null) { 781 // // for (Node!E x = last; x !is null; x = x.prev) { 782 // // if (x.item is null) { 783 // // unlink(x); 784 // // return true; 785 // // } 786 // // } 787 // // } else { 788 // // for (Node!E x = last; x !is null; x = x.prev) { 789 // // if (o.equals(x.item)) { 790 // // unlink(x); 791 // // return true; 792 // // } 793 // // } 794 // // } 795 // // return false; 796 // } 797 798 799 // 800 // private LinkedList!E superClone() { 801 // try { 802 // return (LinkedList!E) super.clone(); 803 // } catch (CloneNotSupportedException e) { 804 // throw new InternalError(e); 805 // } 806 // } 807 808 // /** 809 // * Returns a shallow copy of this {@code LinkedList}. (The elements 810 // * themselves are not cloned.) 811 // * 812 // * @return a shallow copy of this {@code LinkedList} instance 813 // */ 814 // // Object clone() { 815 // // LinkedList!E clone = superClone(); 816 817 // // // Put clone into "virgin" state 818 // // clone.first = clone.last = null; 819 // // clone.size = 0; 820 // // clone.modCount = 0; 821 822 // // // Initialize clone with our elements 823 // // for (Node!E x = first; x !is null; x = x.next) 824 // // clone.add(x.item); 825 826 // // return clone; 827 // // } 828 829 /** 830 * Returns an array containing all of the elements in this list 831 * in proper sequence (from first to last element). 832 * 833 * <p>The returned array will be "safe" in that no references to it are 834 * maintained by this list. (In other words, this method must allocate 835 * a new array). The caller is thus free to modify the returned array. 836 * 837 * <p>This method acts as bridge between array-based and collection-based 838 * APIs. 839 * 840 * @return an array containing all of the elements in this list 841 * in proper sequence 842 */ 843 override E[] toArray() { 844 // E[] result = new E[_size]; 845 // int i = 0; 846 // for (Node!E x = first; x !is null; x = x.next) 847 // result[i++] = x.item; 848 return _dlist[].array; 849 } 850 851 override int opApply(scope int delegate(ref E) dg) 852 { 853 int result = 0; 854 foreach(E v; _dlist) 855 { 856 result = dg(v); 857 if(result != 0) return result; 858 } 859 return result; 860 } 861 862 override bool opEquals(IObject o) { 863 return opEquals(cast(Object) o); 864 } 865 866 override bool opEquals(Object o) { 867 return super.opEquals(o); 868 } 869 870 override size_t toHash() @trusted nothrow { 871 return super.toHash(); 872 } 873 874 override string toString() { 875 return super.toString(); 876 } 877 878 InputRange!E descendingIterator() { 879 throw new NotImplementedException(); 880 } 881 }