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