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 23 import std.conv; 24 import std.container; 25 import std.range; 26 27 28 29 /** 30 * Doubly-linked list implementation of the {@code List} and {@code Deque} 31 * interfaces. Implements all optional list operations, and permits all 32 * elements (including {@code null}). 33 * 34 * <p>All of the operations perform as could be expected for a doubly-linked 35 * list. Operations that index into the list will traverse the list from 36 * the beginning or the end, whichever is closer to the specified index. 37 * 38 * <p><strong>Note that this implementation is not synchronized.</strong> 39 * If multiple threads access a linked list concurrently, and at least 40 * one of the threads modifies the list structurally, it <i>must</i> be 41 * synchronized externally. (A structural modification is any operation 42 * that adds or deletes one or more elements; merely setting the value of 43 * an element is not a structural modification.) This is typically 44 * accomplished by synchronizing on some object that naturally 45 * encapsulates the list. 46 * 47 * If no such object exists, the list should be "wrapped" using the 48 * {@link Collections#synchronizedList Collections.synchronizedList} 49 * method. This is best done at creation time, to prevent accidental 50 * unsynchronized access to the list:<pre> 51 * List list = Collections.synchronizedList(new LinkedList(...));</pre> 52 * 53 * <p>The iterators returned by this class's {@code iterator} and 54 * {@code listIterator} methods are <i>fail-fast</i>: if the list is 55 * structurally modified at any time after the iterator is created, in 56 * any way except through the Iterator's own {@code remove} or 57 * {@code add} methods, the iterator will throw a {@link 58 * ConcurrentModificationException}. Thus, in the face of concurrent 59 * modification, the iterator fails quickly and cleanly, rather than 60 * risking arbitrary, non-deterministic behavior at an undetermined 61 * time in the future. 62 * 63 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed 64 * as it is, generally speaking, impossible to make any hard guarantees in the 65 * presence of unsynchronized concurrent modification. Fail-fast iterators 66 * throw {@code ConcurrentModificationException} on a best-effort basis. 67 * Therefore, it would be wrong to write a program that depended on this 68 * exception for its correctness: <i>the fail-fast behavior of iterators 69 * should be used only to detect bugs.</i> 70 * 71 * <p>This class is a member of the 72 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 73 * Java Collections Framework</a>. 74 * 75 * @author Josh Bloch 76 * @see List 77 * @see ArrayList 78 * @since 1.2 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 _size--; 282 modCount++; 283 import hunt.util.Common; 284 static if(CompilerHelper.isLessThan(2077)) { 285 auto range = _dlist[]; 286 for ( ; !range.empty; range.popFront()) 287 { 288 if (range.front == o) 289 { 290 _dlist.stableLinearRemove(take(range, 1)); 291 return true; 292 } 293 } 294 return false; 295 } else { 296 return _dlist.linearRemoveElement(o); 297 } 298 } 299 300 // /** 301 // * Appends all of the elements in the specified collection to the end of 302 // * this list, in the order that they are returned by the specified 303 // * collection's iterator. The behavior of this operation is undefined if 304 // * the specified collection is modified while the operation is in 305 // * progress. (Note that this will occur if the specified collection is 306 // * this list, and it's nonempty.) 307 // * 308 // * @param c collection containing elements to be added to this list 309 // * @return {@code true} if this list changed as a result of the call 310 // * @throws NullPointerException if the specified collection is null 311 // */ 312 // override bool addAll(Collection!E c) { 313 314 // bool modified = c.size() > 0; 315 // foreach (E e ; c) { 316 // linkLast(e); 317 // } 318 // return modified; 319 320 // // return addAll(_size, c); 321 // } 322 323 // bool addAll(E[] c) { 324 325 // bool modified = c.length > 0; 326 // foreach (E e ; c) { 327 // linkLast(e); 328 // } 329 // return modified; 330 // } 331 332 // /** 333 // * Inserts all of the elements in the specified collection into this 334 // * list, starting at the specified position. Shifts the element 335 // * currently at that position (if any) and any subsequent elements to 336 // * the right (increases their indices). The new elements will appear 337 // * in the list in the order that they are returned by the 338 // * specified collection's iterator. 339 // * 340 // * @param index index at which to insert the first element 341 // * from the specified collection 342 // * @param c collection containing elements to be added to this list 343 // * @return {@code true} if this list changed as a result of the call 344 // * @throws IndexOutOfBoundsException {@inheritDoc} 345 // * @throws NullPointerException if the specified collection is null 346 // */ 347 348 // bool addAll(int index, Collection!E c) { 349 // throw new NotImplementedException(); 350 // } 351 // bool addAll(int index, Collection<E> c) { 352 // checkPositionIndex(index); 353 354 // Object[] a = c.toArray(); 355 // int numNew = a.length; 356 // if (numNew == 0) 357 // return false; 358 359 // Node!E pred, succ; 360 // if (index == _size) { 361 // succ = null; 362 // pred = last; 363 // } else { 364 // succ = node(index); 365 // pred = succ.prev; 366 // } 367 368 // for (Object o : a) { 369 // E e = (E) o; 370 // Node!E newNode = new Node<>(pred, e, null); 371 // if (pred is null) 372 // first = newNode; 373 // else 374 // pred.next = newNode; 375 // pred = newNode; 376 // } 377 378 // if (succ is null) { 379 // last = pred; 380 // } else { 381 // pred.next = succ; 382 // succ.prev = pred; 383 // } 384 385 // _size += numNew; 386 // modCount++; 387 // return true; 388 // } 389 390 /** 391 * Removes all of the elements from this list. 392 * The list will be empty after this call returns. 393 */ 394 override void clear() { 395 _dlist.clear(); 396 _size = 0; 397 modCount++; 398 } 399 400 401 // Positional Access Operations 402 403 /** 404 * Returns the element at the specified position in this list. 405 * 406 * @param index index of the element to return 407 * @return the element at the specified position in this list 408 * @throws IndexOutOfBoundsException {@inheritDoc} 409 */ 410 override E get(int index) { 411 checkElementIndex(index); 412 413 int i=0; 414 foreach(v; _dlist) 415 { 416 if(i == index) 417 return v; 418 i++; 419 } 420 return E.init; 421 } 422 423 /** 424 * Replaces the element at the specified position in this list with the 425 * specified element. 426 * 427 * @param index index of the element to replace 428 * @param element element to be stored at the specified position 429 * @return the element previously at the specified position 430 * @throws IndexOutOfBoundsException {@inheritDoc} 431 */ 432 override E set(int index, E element) { 433 checkElementIndex(index); 434 435 int i= 0; 436 auto range = _dlist[]; 437 range.popFrontN(index); 438 E oldVal = range.front; 439 range.front = element; 440 441 // for ( ; !range.empty; range.popFront()) 442 // { 443 // if(i == index) 444 // { 445 // oldVal = range.front; 446 // range.front = element; 447 // break; 448 // } 449 // i++; 450 // } 451 452 return oldVal; 453 } 454 455 /** 456 * Inserts the specified element at the specified position in this list. 457 * Shifts the element currently at that position (if any) and any 458 * subsequent elements to the right (adds one to their indices). 459 * 460 * @param index index at which the specified element is to be inserted 461 * @param element element to be inserted 462 * @throws IndexOutOfBoundsException {@inheritDoc} 463 */ 464 override void add(int index, E element) { 465 checkPositionIndex(index); 466 467 if (index == _size) 468 linkLast(element); 469 else 470 { 471 auto range = _dlist[]; 472 range.popFrontN(index); 473 _dlist.insertBefore(range, element); 474 _size++; 475 modCount++; 476 } 477 // linkBefore(element, node(index)); 478 } 479 480 /** 481 * Removes the element at the specified position in this list. Shifts any 482 * subsequent elements to the left (subtracts one from their indices). 483 * Returns the element that was removed from the list. 484 * 485 * @param index the index of the element to be removed 486 * @return the element previously at the specified position 487 * @throws IndexOutOfBoundsException {@inheritDoc} 488 */ 489 override E removeAt(int index) { 490 checkElementIndex(index); 491 auto range = _dlist[]; 492 range.popFrontN(index); 493 auto temp = take(range, 1); 494 _dlist.linearRemove(temp); 495 496 _size--; 497 modCount++; 498 return temp.front; 499 } 500 501 /** 502 * Tells if the argument is the index of an existing element. 503 */ 504 private bool isElementIndex(int index) { 505 return index >= 0 && index < _size; 506 } 507 508 /** 509 * Tells if the argument is the index of a valid position for an 510 * iterator or an add operation. 511 */ 512 private bool isPositionIndex(int index) { 513 return index >= 0 && index <= _size; 514 } 515 516 /** 517 * Constructs an IndexOutOfBoundsException detail message. 518 * Of the many possible refactorings of the error handling code, 519 * this "outlining" performs best with both server and client VMs. 520 */ 521 private string outOfBoundsMsg(int index) { 522 return "Index: " ~ index.to!string() ~ ", Size: " ~ _size.to!string(); 523 } 524 525 private void checkElementIndex(int index) { 526 if (!isElementIndex(index)) 527 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 528 } 529 530 private void checkPositionIndex(int index) { 531 if (!isPositionIndex(index)) 532 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 533 } 534 535 /** 536 * Returns the (non-null) Node at the specified element index. 537 */ 538 539 // Node!E node(int index) { 540 // // assert isElementIndex(index); 541 542 // if (index < (_size >> 1)) { 543 // Node!E x = first; 544 // for (int i = 0; i < index; i++) 545 // x = x.next; 546 // return x; 547 // } else { 548 // Node!E x = last; 549 // for (int i = _size - 1; i > index; i--) 550 // x = x.prev; 551 // return x; 552 // } 553 // } 554 555 // Search Operations 556 557 /** 558 * Returns the index of the first occurrence of the specified element 559 * in this list, or -1 if this list does not contain the element. 560 * More formally, returns the lowest index {@code i} such that 561 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, 562 * or -1 if there is no such index. 563 * 564 * @param o element to search for 565 * @return the index of the first occurrence of the specified element in 566 * this list, or -1 if this list does not contain the element 567 */ 568 override int indexOf(E o) { 569 int index = 0; 570 foreach(v; _dlist) 571 { 572 static if( is(E == class)) 573 { 574 if(v == o) 575 return index; 576 } 577 else 578 { 579 if(v == o) 580 return index; 581 } 582 index++; 583 } 584 return -1; 585 } 586 587 /** 588 * Returns the index of the last occurrence of the specified element 589 * in this list, or -1 if this list does not contain the element. 590 * More formally, returns the highest index {@code i} such that 591 * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, 592 * or -1 if there is no such index. 593 * 594 * @param o element to search for 595 * @return the index of the last occurrence of the specified element in 596 * this list, or -1 if this list does not contain the element 597 */ 598 override int lastIndexOf(E o) { 599 int index = _size; 600 auto range = _dlist[]; 601 for(; !range.empty; range.popBack()) 602 { 603 index--; 604 if(range.back == o) 605 return index; 606 } 607 return -1; 608 } 609 610 // Queue operations. 611 612 /** 613 * Retrieves, but does not remove, the head (first element) of this list. 614 * 615 * @return the head of this list, or {@code null} if this list is empty 616 * @since 1.5 617 */ 618 E peek() { 619 return getFirst(); 620 } 621 622 /** 623 * Retrieves, but does not remove, the head (first element) of this list. 624 * 625 * @return the head of this list 626 * @throws NoSuchElementException if this list is empty 627 * @since 1.5 628 */ 629 E element() { 630 return getFirst(); 631 } 632 633 /** 634 * Retrieves and removes the head (first element) of this list. 635 * 636 * @return the head of this list, or {@code null} if this list is empty 637 * @since 1.5 638 */ 639 E poll() { 640 return removeFirst(); 641 } 642 643 /** 644 * Retrieves and removes the head (first element) of this list. 645 * 646 * @return the head of this list 647 * @throws NoSuchElementException if this list is empty 648 * @since 1.5 649 */ 650 E remove() { 651 return removeFirst(); 652 } 653 654 /** 655 * Adds the specified element as the tail (last element) of this list. 656 * 657 * @param e the element to add 658 * @return {@code true} (as specified by {@link Queue#offer}) 659 * @since 1.5 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 * @since 1.6 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 * @since 1.6 684 */ 685 bool offerLast(E e) { 686 addLast(e); 687 return true; 688 } 689 690 /** 691 * Retrieves, but does not remove, the first element of this list, 692 * or returns {@code null} if this list is empty. 693 * 694 * @return the first element of this list, or {@code null} 695 * if this list is empty 696 * @since 1.6 697 */ 698 E peekFirst() { 699 return getFirst(); 700 } 701 702 /** 703 * Retrieves, but does not remove, the last element of this list, 704 * or returns {@code null} if this list is empty. 705 * 706 * @return the last element of this list, or {@code null} 707 * if this list is empty 708 * @since 1.6 709 */ 710 E peekLast() { 711 return getLast(); 712 } 713 714 /** 715 * Retrieves and removes the first element of this list, 716 * or returns {@code null} if this list is empty. 717 * 718 * @return the first element of this list, or {@code null} if 719 * this list is empty 720 * @since 1.6 721 */ 722 E pollFirst() { 723 return removeFirst(); 724 } 725 726 /** 727 * Retrieves and removes the last element of this list, 728 * or returns {@code null} if this list is empty. 729 * 730 * @return the last element of this list, or {@code null} if 731 * this list is empty 732 * @since 1.6 733 */ 734 E pollLast() { 735 return removeLast(); 736 } 737 738 /** 739 * Pushes an element onto the stack represented by this list. In other 740 * words, inserts the element at the front of this list. 741 * 742 * <p>This method is equivalent to {@link #addFirst}. 743 * 744 * @param e the element to push 745 * @since 1.6 746 */ 747 void push(E e) { 748 addFirst(e); 749 } 750 751 /** 752 * Pops an element from the stack represented by this list. In other 753 * words, removes and returns the first element of this list. 754 * 755 * <p>This method is equivalent to {@link #removeFirst()}. 756 * 757 * @return the element at the front of this list (which is the top 758 * of the stack represented by this list) 759 * @throws NoSuchElementException if this list is empty 760 * @since 1.6 761 */ 762 E pop() { 763 return removeFirst(); 764 } 765 766 /** 767 * Removes the first occurrence of the specified element in this 768 * list (when traversing the list from head to tail). If the list 769 * does not contain the element, it is unchanged. 770 * 771 * @param o element to be removed from this list, if present 772 * @return {@code true} if the list contained the specified element 773 * @since 1.6 774 */ 775 bool removeFirstOccurrence(E o) { 776 return remove(o); 777 } 778 779 /** 780 * Removes the last occurrence of the specified element in this 781 * list (when traversing the list from head to tail). If the list 782 * does not contain the element, it is unchanged. 783 * 784 * @param o element to be removed from this list, if present 785 * @return {@code true} if the list contained the specified element 786 * @since 1.6 787 */ 788 // bool removeLastOccurrence(E o) { 789 790 // // if (o is null) { 791 // // for (Node!E x = last; x !is null; x = x.prev) { 792 // // if (x.item is null) { 793 // // unlink(x); 794 // // return true; 795 // // } 796 // // } 797 // // } else { 798 // // for (Node!E x = last; x !is null; x = x.prev) { 799 // // if (o.equals(x.item)) { 800 // // unlink(x); 801 // // return true; 802 // // } 803 // // } 804 // // } 805 // // return false; 806 // } 807 808 809 // 810 // private LinkedList!E superClone() { 811 // try { 812 // return (LinkedList!E) super.clone(); 813 // } catch (CloneNotSupportedException e) { 814 // throw new InternalError(e); 815 // } 816 // } 817 818 // /** 819 // * Returns a shallow copy of this {@code LinkedList}. (The elements 820 // * themselves are not cloned.) 821 // * 822 // * @return a shallow copy of this {@code LinkedList} instance 823 // */ 824 // // Object clone() { 825 // // LinkedList!E clone = superClone(); 826 827 // // // Put clone into "virgin" state 828 // // clone.first = clone.last = null; 829 // // clone.size = 0; 830 // // clone.modCount = 0; 831 832 // // // Initialize clone with our elements 833 // // for (Node!E x = first; x !is null; x = x.next) 834 // // clone.add(x.item); 835 836 // // return clone; 837 // // } 838 839 /** 840 * Returns an array containing all of the elements in this list 841 * in proper sequence (from first to last element). 842 * 843 * <p>The returned array will be "safe" in that no references to it are 844 * maintained by this list. (In other words, this method must allocate 845 * a new array). The caller is thus free to modify the returned array. 846 * 847 * <p>This method acts as bridge between array-based and collection-based 848 * APIs. 849 * 850 * @return an array containing all of the elements in this list 851 * in proper sequence 852 */ 853 override E[] toArray() { 854 // E[] result = new E[_size]; 855 // int i = 0; 856 // for (Node!E x = first; x !is null; x = x.next) 857 // result[i++] = x.item; 858 return _dlist[].array; 859 } 860 861 override int opApply(scope int delegate(ref E) dg) 862 { 863 int result = 0; 864 foreach(E v; _dlist) 865 { 866 result = dg(v); 867 if(result != 0) return result; 868 } 869 return result; 870 } 871 872 override bool opEquals(IObject o) { 873 return opEquals(cast(Object) o); 874 } 875 876 override bool opEquals(Object o) { 877 return super.opEquals(o); 878 } 879 880 override size_t toHash() @trusted nothrow { 881 return super.toHash(); 882 } 883 884 override string toString() { 885 return super.toString(); 886 } 887 }