1
2 package eu.simuline.util;
3
4 import java.util.List;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Iterator;
8 import java.util.Collection;
9 import java.util.NoSuchElementException;
10 import java.util.Objects;
11
12 /**
13 * Resizable-array implementation of the <code>CyclicList</code> interface.
14 * Implements all optional operations, and permits all elements,
15 * including<code>null</code>.
16 * In addition to implementing the <code>CyclicList</code> interface,
17 * this class provides methods to manipulate the size of the array that is
18 * used internally to store the list.
19 * <p>
20 * The <code>size</code>, <code>isEmpty</code>,
21 * <code>get</code>, <code>set</code>,
22 * and <code>iterator</code> operations run in constant time.
23 * The <code>add</code> operation runs in <i>amortized constant time</i>,
24 * that is, adding n elements requires O(n) time.
25 * All of the other operations run in linear time (roughly speaking).
26 * <!--The constant factor is low compared
27 * to that for the <code>LinkedList</code> implementation. -->
28 *<p>
29 * Each <code>CyclicArrayList</code> instance has a <i>capacity</i>.
30 * The capacity is the size of the array
31 * used to store the elements in the list.
32 * It is always at least as large as the list size.
33 * As elements are added an ArrayList, its capacity grows automatically.
34 * The details of the growth policy are not specified beyond the fact
35 * that adding an element has constant amortized time cost.
36 * <p>
37 * An application can increase the capacity
38 * of a <code>CyclicArrayList</code> instance
39 * before adding a large number of elements
40 * using the <code>ensureCapacity</code> operation.
41 * This may reduce the amount of incremental reallocation.
42 * <p>
43 * <strong>Note that this implementation is not synchronized.</strong>
44 * if Multiple threads access an <code>CyclicArrayList</code> instance
45 * concurrently,
46 * and at least one of the threads modifies the list structurally,
47 * it <i>must</i> be synchronized externally.
48 * (A structural modification is any operation
49 * that adds or deletes one or more elements,
50 * or explicitly resizes the backing array;
51 * merely setting the value of an element is not a structural modification.)
52 * This is typically accomplished by synchronizing on some object
53 * that naturally encapsulates the list.
54 * <!--If no such object exists, the list should be "wrapped"
55 * using the <code>Collections.synchronizedList</code>
56 * method. This is best done at creation time, to prevent accidental
57 * unsynchronized access to the list:
58 * <pre>
59 * List list = Collections.synchronizedList(new ArrayList(...));
60 * </pre>-->
61 * <p>
62 * The iterator returned by this class's <code>iterator</code> and
63 * <code>iterator(int)</code> methods are <i>fail-fast</i>:
64 * if list is structurally modified
65 * at any time after the iterator is created,
66 * in any way except through the iterator's own remove or add methods,
67 * the iterator will throw a <code>ConcurrentModificationException</code>.
68 * Thus, in the face of concurrent modification,
69 * the iterator fails quickly and cleanly, rather than risking arbitrary,
70 * non-deterministic behavior at an undetermined time in the future.
71 *
72 * @param <E>
73 * the class of the elements in this list.
74 *
75 * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
76 * @version 1.0
77 */
78 public final class CyclicArrayList<E>
79 implements CyclicList<E>, Cloneable { // NOPMD
80
81 /*----------------------------------------------------------------------*/
82 /* Inner classes */
83 /*----------------------------------------------------------------------*/
84
85 /**
86 * Enumeration of the state of an iterator.
87 */
88 enum StateIter {
89
90 /**
91 * The condition <code>calledLast == CALLED_NOTHING</code> means
92 * that neither of the methods
93 * {@link CyclicIterator#next}, {@link CyclicIterator#previous},
94 * {@link CyclicIterator#add} and {@link CyclicIterator#remove}
95 * was ever successfully invoked
96 * since this iterator was created or refreshed.
97 *
98 * @see CyclicIterator#refresh
99 */
100 CALLED_NOTHING(),
101
102 /**
103 * The condition <code>calledLast == CALLED_PREVIOUS</code> means
104 * that among the methods
105 * {@link CyclicIterator#next}, {@link CyclicIterator#previous},
106 * {@link CyclicIterator#add} and {@link CyclicIterator#remove}
107 * the method {@link CyclicIterator#previous}
108 * was the last successfully invoked
109 * since this iterator was created or refreshed.
110 */
111 CALLED_PREVIOUS(),
112
113 /**
114 * The condition <code>calledLast == CALLED_NEXT</code> means
115 * that among the methods
116 * {@link CyclicIterator#next}, {@link CyclicIterator#previous},
117 * {@link CyclicIterator#add} and {@link CyclicIterator#remove}
118 * the method {@link CyclicIterator#next}
119 * was the last successfully invoked
120 * since this iterator was created or refreshed.
121 */
122 CALLED_NEXT(),
123
124 /**
125 * The condition <code>calledLast == CALLED_ADD</code> means
126 * that among the methods
127 * {@link CyclicIterator#next}, {@link CyclicIterator#previous},
128 * {@link CyclicIterator#add} and {@link CyclicIterator#remove}
129 * the method {@link CyclicIterator#add}
130 * was the last successfully invoked
131 * since this iterator was created or refreshed.
132 */
133 CALLED_ADD(),
134
135 /**
136 * The condition <code>calledLast == CALLED_REMOVE</code> means
137 * that among the methods
138 * {@link CyclicIterator#next}, {@link CyclicIterator#previous},
139 * {@link CyclicIterator#add} and {@link CyclicIterator#remove}
140 * the method {@link CyclicIterator#previous} was the last invoked
141 * since this iterator was created or refreshed.
142 */
143 CALLED_REMOVE();
144
145 } // enum StateIter
146
147 /**
148 * An iterator over a {@link CyclicList}.
149 * <code>CyclicIterator</code> corresponds with <code>CyclicList</code>s
150 * as <code>Iterator</code>s or <code>ListIterator</code>s does
151 * with <code>List</code>s.
152 * Nevertheless, <code>CyclicIterator</code>
153 * does not implement <code>java.util.Iterator</code>.
154 *
155 * @param <E>
156 * the class of the elements to be iterated over.
157 *
158 * @see CyclicList
159 * @author <a href="mailto:Ernst.Reissner@eu.simuline.de">Ernst Reissner</a>
160 * @version 1.0
161 */
162 public static final class CyclicArrayIterator<E>
163 implements CyclicIterator<E> {
164
165 /*------------------------------------------------------------------*/
166 /* Fields */
167 /*------------------------------------------------------------------*/
168
169
170 /**
171 * Indicates the last method invoked.
172 *
173 * @see #refresh
174 */
175 private StateIter calledLast;
176
177 /**
178 * A non-negative index which points,
179 * modulo <code>list.size()-1</code>,
180 * to the <code>0,...,list.size()-1</code>th element
181 * of <code>list</code>
182 * provided {@link #list} is not empty;
183 * if it is empty, <code>index == -1</code>.
184 */
185 private int index;
186
187 /**
188 * Points to the beginning of this cyclic list:
189 * <code>this.hasPrev() == false</code>
190 * iff <code>index == startIndex</code>.
191 * It also determines the end of this list implicitly:
192 * <code>this.hasNext() == false</code>
193 * iff <code>this.index < this.startIndex+this.list.size()</code>.
194 * This is true also for <code>{@link #list}.isEmpty()</code>.
195 *
196 * @see #hasNext
197 * @see #hasPrev
198 * @see #index
199 */
200 private int startIndex;
201
202 private CyclicArrayList<E> cal;
203
204 /*------------------------------------------------------------------*/
205 /* Constructors */
206 /*------------------------------------------------------------------*/
207
208 /**
209 * Creates a new <code>CyclicIterator</code>
210 * for the given list,
211 * pointing to the element with the position given.
212 * This position is modulo <code>list.size()</code>
213 * and may also be negative.
214 * <p>
215 * Note that this list may be empty
216 * (in which case the indices are -1)
217 * but by construction it may not be <code>null</code>.
218 *
219 * @param index
220 * an index modulo <code>list.size()</code>,
221 * provided <code>list</code> is not empty.
222 * In the latter case, <code>index</code> is ignored
223 */
224 public CyclicArrayIterator(CyclicArrayList<E> cal,
225 int index) {
226 this.cal = cal;
227 // Initialize indices.
228 this.index =
229 this.cal.isEmpty()
230 ? -1
231 : this.cal.shiftIndex(index);
232 this.startIndex = this.index;
233 this.calledLast = StateIter.CALLED_NOTHING;
234 }
235
236 /**
237 * Creates a fresh <code>CyclicPtIterator</code>
238 * with the same list and the same pointer
239 * as the <code>CyclicPtIterator</code> given.
240 * <p>
241 * An iterator is called "fresh"
242 * if it delivers all elements of its list.
243 * Equivalently, it is called fresh, if after having created it,
244 * no getNext-method has been invoked.
245 *
246 * @param iter
247 * some <code>CyclicPtItererator</code>.
248 */
249 public CyclicArrayIterator(CyclicArrayList<E> cal,
250 CyclicArrayIterator<E> iter) {
251 this(cal, iter.index);
252 }
253
254 public int getFirstIndex() {
255 return this.startIndex;
256 }
257
258 /**
259 * Reinitializes this iterator without changing the cursor
260 * (i.e. modulo <code>list.size()</code>)
261 * but such that all elements of the corresponding cyclic list
262 * may be accessed successively through {@link #next}.
263 * On the other hand, {@link #previous} throws an exception.
264 */
265 public void refresh() {
266 if (this.cal.isEmpty()) {
267 return;
268 }
269 // Here, the underlying list is not empty.
270 this.index = this.cal.shiftIndex(this.index);
271 this.startIndex = this.index;
272 this.calledLast = StateIter.CALLED_NOTHING;
273 }
274
275 /**
276 * Sets the pointer to the given index modulo the length of the list.
277 * For empty list: no change.
278 *
279 * @param index
280 * an <code>int</code>
281 * representing a pointer on the underlying list.
282 * This may also be negative.
283 */
284 public void setIndex(int index) {
285 if (this.cal.isEmpty()) {
286 return;
287 }
288
289 this.index = this.cal.shiftIndex(index);
290 // Here, this.index = -list.size(), ..., list.size()-1.
291 while (this.index < this.startIndex) {
292 this.index += this.cal.size();
293 }
294 // Here, this.index = 0, ..., list.size()-1.
295 }
296
297 /**
298 * Returns the current index of this iterator.
299 *
300 * @return an <code>int</code> value
301 * <!--deprecated replaced by nextIndex-->
302 */
303 public int getIndex() {
304 return this.cal.size() == 0
305 ? this.index
306 : this.index % this.cal.size();
307 }
308
309 /*
310 * Returns the index of the element
311 * that would be returned by a subsequent call to <code>next</code>.
312 *
313 * @return
314 * the index of the element
315 * that would be returned by a subsequent call to <code>next</code>.
316 * The range is <code>0,...,size()-1</code>.
317 */
318 //public int nextIndex() {
319 // return this.index%this.cal.size();
320 //}
321
322
323 /**
324 * Returns the <code>CyclicList</code> this iterator points to.
325 *
326 * @return
327 * the <code>CyclicList</code> this iterator points to.
328 */
329 public CyclicList<E> getCyclicList() {
330 return this.cal;
331 }
332
333 /*------------------------------------------------------------------*/
334 /* Methods for queries (boolean and others) */
335 /*------------------------------------------------------------------*/
336
337
338 /**
339 * Returns whether a subsequent call to {@link #next}
340 * would return an element rather than throwing an exception.
341 *
342 * @return
343 * whether a subsequent call to <code>next()</code>
344 * would return an element rather than throwing an exception.
345 */
346 public boolean hasNext() {
347 return this.index < this.startIndex + this.cal.size();
348 }
349
350 /**
351 * Returns the next element in the interation.
352 * This method may be called repeatedly to iterate through the list,
353 * or intermixed with calls to <code>previous</code>
354 * to go back and forth.
355 * (Note that alternating calls
356 * to <code>next</code> and <code>previous</code>
357 * will return the same element repeatedly.)
358 *
359 * @return
360 * the next element in the interation.
361 * @exception NoSuchElementException
362 * iteration has no more elements.
363 */
364 public E next() throws NoSuchElementException {
365
366 if (!hasNext()) {
367 throw new NoSuchElementException();
368 }
369 this.calledLast = StateIter.CALLED_NEXT;
370 return this.cal.get(this.index++);
371 }
372
373 /**
374 * Returns whether a subsequent call to {@link #previous}
375 * does not throw an exception.
376 *
377 * @return
378 * Returns whether a subsequent call to {@link #previous}
379 * does not throw an exception.
380 */
381 public boolean hasPrev() {
382 return this.index > this.startIndex;
383 }
384
385 /**
386 * Returns the previous element in the cyclic list.
387 * This method may be called repeatedly
388 * to iterate through the list backwards,
389 * or intermixed with calls to <code>next</code> to go back and forth.
390 * (Note that alternating calls
391 * to <code>next</code> and <code>previous</code>
392 * will return the same element repeatedly.)
393 *
394 * @return
395 * the previous element in the list.
396 *
397 * @exception NoSuchElementException
398 * if the iteration has no previous element.
399 */
400 public E previous() throws NoSuchElementException {
401 if (!hasPrev()) {
402 throw new NoSuchElementException();
403 }
404 this.calledLast = StateIter.CALLED_PREVIOUS;
405 return this.cal.get(--this.index);
406 }
407
408 /**
409 * Returns the (non-negative) index
410 * of the next object returned by <code>next</code>
411 * which equals the given one, if possible;
412 * otherwise returns <code>-1</code>.
413 *
414 * @param obj
415 * an object.
416 * @return
417 * <ul>
418 * <li>
419 * the index minimal index
420 * <code>ind in {0,...,this.cal.size()-1}</code>
421 * satisfying
422 * <code>obj.equals(this.cal.get(ind))</code>
423 * if possible;
424 * <li>
425 * <code>-1</code> if there is no such index.
426 * </ul>
427 */
428 public int getNextIndexOf(E obj) {
429 if (this.cal.isEmpty()) {
430 return -1;
431 }
432 // Here, the underlying list is nontrivial.
433
434 // store current pointer, to restore it afterwards.
435 int oldPointer = getIndex();
436 if (obj == null) {
437 // Here, obj == null.
438 while (this.hasNext()) {
439 if (next() == null) {
440 previous();
441 return getIndex();
442 }
443 }
444 } else {
445 // Here, obj != null.
446 while (this.hasNext()) {
447 if (obj.equals(next())) {
448 previous();
449 return getIndex();
450 }
451 }
452 }
453 // Here, no such element is found.
454
455 setIndex(oldPointer);
456 return -1;
457 }
458
459 /*------------------------------------------------------------------*/
460 /* Methods for modifications */
461 /*------------------------------------------------------------------*/
462
463 /* **** old docu:
464 * Inserts the given object at the current position.
465 * As a result of this,
466 * method <code>next</code> will return this object next
467 * even if formerly <code>hasNext()</code> was false.
468 *
469 * @param obj
470 * An object to be inserted in the list this iterator points to.
471 */
472 /**
473 * Inserts the specified element into the cyclic list.
474 * The element is inserted immediately before the next element
475 * that would be returned by <code>next</code>, if any,
476 * and after the next element
477 * that would be returned by <code>previous</code>, if any.
478 * (If the cyclic list is empty,
479 * the new element becomes the sole element on the cyclic list.)
480 * <p>
481 * The new element is inserted before the implicit cursor:
482 * a subsequent call to <code>next</code> would be unaffected,
483 * and a subsequent call to <code>previous</code>
484 * would return the new element.
485 * (This call increases by one the value
486 * that would be returned by a call
487 * to <code>nextIndex</code> or to <code>previousIndex</code>.)
488 *
489 * @param obj
490 * An object to be inserted in the list this iterator points to.
491 */
492 public void add(E obj) {
493 this.cal.add(this.index, obj);
494 if (this.index % this.cal.size() <
495 this.startIndex % this.cal.size()) {
496 this.startIndex++;
497 }
498
499 this.index++;
500 this.calledLast = StateIter.CALLED_ADD;
501 }
502
503 /**
504 * Inserts the specified list into the underlying cyclic list.
505 * The list is inserted immediately before the next element
506 * that would be returned by <code>next</code>, if any,
507 * and after the next element
508 * that would be returned by <code>previous</code>, if any.
509 * (If the cyclic list is empty,
510 * the new cyclic list comprises the given list.)
511 * <p>
512 * The given list is inserted before the implicit cursor:
513 * a subsequent call to <code>next</code> would be unaffected,
514 * and a subsequent call to <code>previous</code>
515 * would return the given list in reversed order.
516 * (This call increases by <code>list.size()</code>
517 * the value that would be returned by a call
518 * to <code>nextIndex</code> or <code>previousIndex</code>.)
519 * <p>
520 * If <code>list.size()</code>
521 * contains a single element <code>e</code>,
522 * <code>addAll(list)</code> is equivalent with <code>add(e)</code>.
523 *
524 * @param addList
525 * the list to be inserted.
526 */
527 public void addAll(List<? extends E> addList) {
528 this.cal.addAll(this.index, addList);
529 if (this.cal.isEmpty()) {
530 this.index = -1;
531 this.startIndex = -1;
532 return;
533 }
534 // Here, the result is not an empty list.
535 if (this.index % this.cal.size() <
536 this.startIndex % this.cal.size()) {
537 this.startIndex += addList.size();
538 }
539
540 this.index += addList.size();
541 this.calledLast = StateIter.CALLED_ADD;
542 }
543
544 /**
545 * Replaces the last element
546 * returned by <code>next</code> or <code>previous</code>
547 * with the specified element (optional operation).
548 * This call can be made only
549 * if neither <code>ListIterator.remove</code> nor <code>add</code>
550 * have been called after the last call to
551 * <code>next</code> or <code>previous</code>.
552 *
553 * @param obj
554 * the element with which to replace the last element
555 * returned by next or previous.
556 * @exception IllegalStateException
557 * if neither <code>next</code> nor <code>previous</code>
558 * have been called,
559 * or <code>remove</code> or <code>add</code> have been called
560 * after the last call
561 * to <code>next</code> or <code>previous</code>.
562 */
563 public void set(E obj) {
564 switch (this.calledLast) {
565 case CALLED_ADD:
566 // fall through.
567 case CALLED_REMOVE:
568 // fall through.
569 case CALLED_NOTHING:
570 throw new IllegalStateException
571 ("No pointer to set object <" + obj + ">. ");
572 case CALLED_NEXT:
573 this.cal.set(this.index - 1, obj);
574 break;
575 case CALLED_PREVIOUS:
576 this.cal.set(this.index, obj);
577 break;
578 default:
579 throw new IllegalStateException("****");
580 }
581 }
582
583 /**
584 * Removes from the underlying <code>CyclicList</code>
585 * the last element returned by the iterator.
586 * This method can be called only once
587 * per call to <code>next</code> or to <code>previous</code>.
588 * The behavior of an iterator is unspecified
589 * if the underlying collection is modified
590 * while the iteration is in progress in any way other
591 * than by calling this method.
592 *
593 * @exception IllegalStateException
594 * if the <code>next</code> method has not yet been called,
595 * or the <code>remove</code> method has already been called
596 * after the last call to the <code>next</code> method.
597 */
598 public void remove() {
599
600 switch (calledLast) {
601 case CALLED_REMOVE:
602 // fall through
603 case CALLED_ADD:
604 // fall through.
605 case CALLED_NOTHING:
606 //this.calledLast = CALLED_REMOVE;
607 throw new IllegalStateException
608 ("No pointer to remove object. ");
609
610 case CALLED_NEXT:
611 this.index--;
612 this.cal.remove(this.index);
613 // **** what if this.cal.size() == 0: impossible
614 if (this.index <= this.startIndex % this.cal.size()) {
615 this.startIndex--;
616 }
617 break;
618 case CALLED_PREVIOUS:
619 this.cal.remove(this.index);
620 break;
621 default:
622 throw new IllegalStateException("****");
623 }
624 this.calledLast = StateIter.CALLED_REMOVE;
625 }
626
627
628 /* ------------------------------------------------------------------*/
629 /* Methods visualization and for tests */
630 /* ------------------------------------------------------------------*/
631
632 /**
633 * Returns whether <code>other</code>
634 * is also an instance of <code>CyclicIterator</code>
635 * and, if so, whether the underlying list and the indices coincide.
636 *
637 * @param other
638 * another <code>Object</code>; possibly <code>null</code>.
639 * @return
640 * Returns <code>false</code>
641 * if <code>other</code> is not an instance
642 * of <code>CyclicIterator</code>.
643 * Otherwise returns <code>true</code>
644 * if all of the following methods return equal values:
645 * {@link #getIndex}, {@link #getFirstIndex}
646 * and {@link #getCyclicList}.
647 */
648 public boolean equals(Object other) {
649 if (!(other instanceof CyclicIterator)) {
650 return false;
651 }
652 CyclicIterator<?> otherIter = (CyclicIterator<?>) other;
653 return this.cal.equals(otherIter.getCyclicList()) &&
654 this.getFirstIndex() == otherIter.getFirstIndex() &&
655 this.getIndex() == otherIter.getIndex();
656 }
657
658 public int hashCode() {
659 return this.cal.hashCode() + getIndex() + getFirstIndex();
660 }
661
662 /**
663 * Returns whether the two cyclic iterators given
664 * return the same elements in the same order
665 * if method {@link #next} is invoked sequentially.
666 *
667 * @param other
668 * another <code>CyclicIterator</code>.
669 * @return
670 * whether the two cyclic iterators given
671 * return the same elements in the same order
672 * if method {@link #next} is invoked sequentially
673 * as long as possible.
674 * This imposes that the lengths of the sequences coincide.
675 * The elements in the sequence may well be <code>null</code>.
676 */
677 public boolean retEquals(CyclicIterator<?> other) {
678 while (this.hasNext() && other.hasNext()) {
679 // Here, this.hasNext() and other.hasNext().
680 Object thi = this.next();
681 Object obj = other.next();
682 if (thi == null) {
683 if (obj != null) {
684 // Here, there the current elements are not equal.
685 return false;
686 }
687 } else {
688 // Here, thi != null.
689 if (!thi.equals(obj)) {
690 // Here, there the current elements are not equal.
691 return false;
692 }
693 }
694 } // while
695 // Here, !this.hasNext() || !other.hasNext().
696
697 if (this.hasNext() ^ other.hasNext()) { // NOPMD
698 // Here, exactly one ot the iterators has a next element.
699 // Thus the number of elements is not equal.
700 //System.out.println("!eq len: ");
701 return false;
702 }
703 // Here, !this.hasNext() and !other.hasNext().
704 // Moreover, up to now, this.next().equals(other.next()).
705 return true;
706 }
707
708 public double dist(CyclicIterator<E> other) {
709 throw new NotYetImplementedException();
710 }
711
712 /**
713 * Returns a string representation consisting of
714 * <ul>
715 * <li>
716 * the cyclic list corresponding with this iterator .
717 * <li>
718 * The current pointer.
719 * <li>
720 * The first index i of this iterator.
721 * and the last one (which is i+size()-1).
722 * ******* empty list?!?
723 * </ul>
724 *
725 * @return
726 * a <code>String</code> representing this iterator.
727 */
728 public String toString() {
729 StringBuffer ret = new StringBuffer();
730 ret.append("<CyclicIterator firstIndex=\"");
731 ret.append(Integer.toString(this.startIndex));
732 ret.append("\" index=\"");
733 ret.append(Integer.toString(this.index));
734 ret.append("\">\n");
735 ret.append(getCyclicList().toString());
736 ret.append("</CyclicIterator>\n");
737
738 return ret.toString();
739 }
740
741 } // class CyclicArrayIterator
742
743 // ***** required for reimplementation of method {@link #cycle(int)
744 // static abstract class CycledList<E> implements CyclicList<E>, Cloneable {
745 // CyclicList<E> wrapped;
746 // int numCycled;
747
748 // public int size() {
749 // return this.wrapped.size();
750 // }
751 // public boolean isEmpty() {
752 // return this.wrapped.isEmpty();
753 // }
754 // public CyclicList<E> getInverse() {
755 // throw new NotYetImplementedException();
756 // }
757 // public boolean contains(Object obj) {
758 // return this.wrapped.contains(obj);
759 // }
760 // // public Iterator<E> iterator() {
761 // // throw new NotYetImplementedException();
762 // // }
763 // public CyclicIterator<E> cyclicIterator(int index) {
764 // return this.wrapped.cyclicIterator(index+this.numCycled);
765 // }
766 // public Object[] toArray(int index) {
767 // throw new NotYetImplementedException();
768 // }
769 // public <E> E[] toArray(int index,E[] array) {
770 // throw new NotYetImplementedException();
771 // }
772 // public List<E> asList(int index) {
773 // throw new NotYetImplementedException();
774 // }
775 // // public
776 // // //List<E> asList() {
777 // // throw new NotYetImplementedException();
778 // // }
779 // public CyclicList<E> cycle(int num) {
780 // throw new NotYetImplementedException();
781 // }
782 // public void clear() {
783 // this.wrapped.clear();
784 // }
785 // public boolean equals(Object obj) {
786 // throw new NotYetImplementedException();
787 // }
788 // public int hashCode() {
789 // throw new NotYetImplementedException();
790 // }
791 // public E set(int index, E element) {
792 // return this.wrapped.set(index+this.numCycled, element);
793 // }
794 // public void replace(int index, Iterator<E> iter) {
795 // throw new NotYetImplementedException();
796 // }
797 // public void replace(int index, List<E> list) {
798 // this.wrapped.replace(index+this.numCycled, list);
799 // }
800 // public void add(int index, E element) {
801 // this.wrapped.add(index+this.numCycled, element);
802 // }
803 // public void addAll(int index, Iterator<E> iter) {
804 // throw new NotYetImplementedException();
805 // }
806 // public void addAll(int index, List<? extends E> list) {
807 // throw new NotYetImplementedException();
808 // }
809 // public E remove(int index) throws EmptyCyclicListException {
810 // return this.wrapped.remove(index+this.numCycled);
811 // }
812 // public int getIndexOf(int idx, Object obj) {
813 // return this.wrapped.getIndexOf(idx+this.numCycled, obj);
814 // }
815 // public CyclicList<E> getCopy(int len) {
816 // throw new NotYetImplementedException();
817 // }
818 //} // class CycledList
819
820 /*----------------------------------------------------------------------*/
821 /* Fields */
822 /*----------------------------------------------------------------------*/
823
824 /**
825 * The array this implementation of CyclicList is based on.
826 * it satisfies <code>this.get(i) == list.get(i)</code>
827 * for all indices <code>i</code> for which the right hand side is valid.
828 */
829 private final List<E> list;
830
831
832 /*----------------------------------------------------------------------*/
833 /* Constructors */
834 /*----------------------------------------------------------------------*/
835
836 /**
837 * Creates a new empty <code>CyclicArrayList</code>.
838 */
839 public CyclicArrayList() {
840 this(new ArrayList<E>());
841 }
842
843 /**
844 * Creates a new <code>CyclicArrayList</code>
845 * such that <code>new CyclicArrayList(list).get(i) == list.get(i)</code>
846 * for all indices <code>i</code> for which the right hand side is valid.
847 *
848 * @param list
849 * some array of objects.
850 */
851 public CyclicArrayList(E[] list) {
852 this(Arrays.asList(list));
853 }
854
855 /**
856 * Creates a new <code>CyclicArrayList</code>
857 * such that <code>new CyclicArrayList(list).get(i) == list.get(i)</code>
858 * for all indices <code>i</code> for which the right hand side is valid.
859 *
860 * @param list
861 * some list of objects.
862 */
863 public CyclicArrayList(List<? extends E> list) {
864 this.list = new ArrayList<E>(list);
865 }
866
867 /**
868 * Copy constructor.
869 *
870 * @param other
871 * some cyclic list of objects.
872 */
873 public CyclicArrayList(CyclicList<? extends E> other) {
874 this(other.asList());
875 }
876
877 /*----------------------------------------------------------------------*/
878 /* methods implementing CyclicList */
879 /*----------------------------------------------------------------------*/
880
881 /**
882 * Returns the number of elements in this list.
883 * If this list contains more than <code>Integer.MAX_VALUE</code> elements,
884 * returns <code>Integer.MAX_VALUE</code>.
885 *
886 * @return
887 * the number of elements in this list.
888 */
889 public int size() {
890 return this.list.size();
891 }
892
893 /**
894 * Returns <code>true</code> iff this list contains no elements.
895 *
896 * @return <code>true</code> iff this list contains no elements.
897 */
898 public boolean isEmpty() {
899 return size() == 0;
900 }
901
902 /**
903 * Returns the inverse of this cyclic list:
904 * the list with inverse order.
905 *
906 * @return
907 * The list with the same entries but inverse order.
908 */
909 public CyclicList<E> getInverse() {
910 CyclicList<E> result = new CyclicArrayList<E>();
911 for (int i = this.size() - 1; i >= 0; i--) {
912 result.add(this.get(i));
913 }
914 return result;
915 }
916
917 /**
918 *
919 * Returns <code>true</code> if this list contains the specified element.
920 * More formally, returns <code>true</code>
921 * if and only if this list contains at least one element <code>e</code>
922 * such that
923 * <code>(o==null ? e==null : o.equals(e))</code>.
924 *
925 * @param obj
926 * element whose presence in this list is to be tested.
927 * @return
928 * <code>true</code> if this list contains the specified element.
929 */
930 public boolean contains(Object obj) {
931 return this.list.contains(obj);
932 }
933
934 public boolean containsAll(Collection<?> coll) {
935 return this.list.containsAll(coll);
936 }
937
938 /**
939 * Returns a <code>CyclicIterator</code>
940 * of the elements in this list (in proper sequence),
941 * starting at the specified position in this list.
942 * The specified index indicates the first element
943 * that would be returned by an initial call
944 * to the <code>next</code> method.
945 * An initial call to the <code>previous</code> method
946 * would return the element with the specified index minus one
947 * (modulo the length of this cyclic list).
948 *
949 * @param index
950 * index of first element to be returned from the list iterator
951 * (by a call to the <code>next</code> method).
952 * This is interpreted modulo the length of this cyclic list.
953 * Any index (even a negative one) is valid.
954 * @return
955 * a cyclic iterator of the elements in this list
956 * (in proper sequence),
957 * starting at the specified position in this list.
958 */
959 public CyclicIterator<E> cyclicIterator(int index) {
960 return new CyclicArrayIterator<E>(this, index);
961 }
962
963 // api-docs provided by Collection
964 public Iterator<E> iterator() {
965 return cyclicIterator(0);
966 }
967
968 // **** unspecified order
969 public Object[] toArray() {
970 return toArray(0);
971 }
972
973 public <E> E[] toArray(E[] ret) {
974 return toArray(0, ret);
975 }
976
977 /**
978 * Returns an array containing all of the elements in this list
979 * in proper sequence.
980 * Modifying the return value does not modify this CyclicList.
981 *
982 * @param index
983 * index of the element in the cyclic list
984 * which comes first in the array returned.
985 * This is interpreted modulo the length of this cyclic list.
986 * Any index (even negative ones) are valid.
987 * @return
988 * an array containing all of the elements in this list
989 * in proper sequence.
990 */
991 public Object[] toArray(int index) {
992 return toArray(index, new Object[0]);
993 }
994
995 /**
996 * Returns an array containing all of the elements in this list
997 * in proper sequence;
998 * the runtime type of the returned array is that of the specified array.
999 * Modifying the return value does not modify this CyclicList.
1000 *
1001 * @param index
1002 * index of the element in the cyclic list
1003 * which comes first in the array returned.
1004 * This is interpreted modulo the length of this cyclic list.
1005 * Any index (even negative ones) are valid.
1006 * @param ret
1007 * the array into which the elements of this list are to be stored,
1008 * if it is big enough;
1009 * otherwise, a new array of the same runtime type
1010 * is allocated for this purpose.
1011 * @return
1012 * an array containing all of the elements in this list
1013 * in proper sequence.
1014 * @throws ArrayStoreException
1015 * if the runtime type of the specified array
1016 * is not a supertype of the runtime type
1017 * of every element in this list.
1018 */
1019 public <E> E[] toArray(int index, E[] ret) {
1020 return cycle(index).list.toArray(ret);
1021 }
1022
1023 public List<E> asList(int index) {
1024 return cycle(index).asList();
1025 }
1026
1027 public List<E> asList() {
1028 return new ArrayList<E>(this.list);
1029 }
1030
1031 /**
1032 * Returns a cyclic permutation <code>p</code> of this cyclic list.
1033 *
1034 * @param index
1035 * index of the element in the cyclic list
1036 * which comes first in the cyclic list returned.
1037 * This is interpreted modulo the length of this cyclic list.
1038 * Any index (even negative ones) are valid.
1039 * @return
1040 * a cyclic permutation <code>p</code> of this cyclic list.
1041 * It satisfies <code>p.size() == this.size()</code> and
1042 * <code>p.get(i) == this.get(i+num)</code>.
1043 */
1044 public CyclicArrayList<E> cycle(int index) {
1045 // maybe better: a view. ****
1046 // to that end use inner class CycledList
1047 if (size() == 0) {
1048 return new CyclicArrayList<E>(this);
1049 }
1050
1051 index = shiftIndex(index);
1052 ArrayList<E> ret = new ArrayList<E>(size());
1053 ret.addAll(this.list.subList(index, size()));
1054 ret.addAll(this.list.subList(0, index));
1055 return new CyclicArrayList<E>(ret);
1056 }
1057
1058 // Modification Operations
1059
1060 /**
1061 * Removes all of the elements from this list (optional operation).
1062 * This list will be empty after this call returns
1063 * (unless it throws an exception).
1064 */
1065 public void clear() {
1066 this.list.clear();
1067 }
1068
1069 /**
1070 * Compares the specified object with this cyclic list for equality.
1071 * Returns <code>true</code>
1072 * if and only if the specified object is also a cyclic list,
1073 * both lists have the same size and
1074 * all corresponding pairs of elements the two lists are <i>equal</i>.
1075 * (Two elements <code>e1</code> and <code>e2</code> are <i>equal</i>
1076 * if <code>(e1==null ? e2==null : e1.equals(e2))</code>.)
1077 * In other words, two cyclic lists are defined to be
1078 * equal if they contain the same elements in the same order
1079 * according to their iterators.
1080 * This definition ensures that the equals method works properly
1081 * across different implementations
1082 * of the <code>CyclicList</code> interface.
1083 *
1084 * @param obj
1085 * the object to be compared for equality with this list.
1086 * @return
1087 * <code>true</code> if the specified object is equal to this list.
1088 * @see #equalsCyclic(Object)
1089 */
1090 public boolean equals(Object obj) {
1091 if (!(obj instanceof CyclicList)) {
1092 return false;
1093 }
1094
1095 CyclicList<?> other = (CyclicList<?>) obj;
1096 return this.asList().equals(other.asList());
1097 }
1098
1099 /**
1100 * Compares the specified object with this cyclic list for equality.
1101 * Returns <code>true</code>
1102 * if and only if the specified object is also a cyclic list,
1103 * both lists have the same size,
1104 * and, up to a cyclic permutation,
1105 * all corresponding pairs of elements the two lists are <i>equal</i>.
1106 * (Two elements <code>e1</code> and <code>e2</code> are <i>equal</i>
1107 * if <code>(e1==null ? e2==null : e1.equals(e2))</code>.)
1108 * In other words, two lists are defined to be
1109 * equal if they contain the same elements in the same order
1110 * up to a cyclic permutation.
1111 * This definition ensures that the equals method works properly
1112 * across different implementations
1113 * of the <code>CyclicList</code> interface.
1114 *
1115 * @param obj
1116 * the object to be compared for equality with this list.
1117 * @return
1118 * <code>true</code> if the specified object is equal to this list.
1119 * @see #equals(Object)
1120 */
1121 public boolean equalsCyclic(Object obj) {
1122 //System.out.println("CyclicList.eq(: ");
1123
1124 if (!(obj instanceof CyclicList)) {
1125 return false;
1126 }
1127
1128 CyclicList<?> other = (CyclicList<?>) obj;
1129 if (this.size() != other.size()) {
1130 return false;
1131 }
1132 // Here, the two lists of points have the same size.
1133
1134 if (size() == 0) {
1135 return true;
1136 }
1137 // Here, the two lists of points have the same, positive size.
1138
1139 CyclicIterator<?> thisIt;
1140 CyclicIterator<?> otherIt;
1141 for (int i = 0; i < this.size(); i++) {
1142 thisIt = this .cyclicIterator(i);
1143 otherIt = other.cyclicIterator(0);
1144 if (thisIt.retEquals(otherIt)) {
1145 return true;
1146 }
1147 }
1148 // Here, no index was found that thisIt and otherIt
1149 //return the same sequence.
1150 return false;
1151 }
1152
1153 /**
1154 * Returns the hash code value for this cyclic list.
1155 * The hash code of a list
1156 * is defined to be the result of the following calculation:
1157 * <pre>
1158 * hashCode = 1;
1159 * Iterator i = list.iterator();
1160 * while (i.hasNext()) {
1161 * Object obj = i.next();
1162 * hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
1163 * }
1164 * </pre>
1165 * This ensures that <code>list1.equals(list2)</code> implies that
1166 * <code>list1.hashCode()==list2.hashCode()</code> for any two lists,
1167 * <code>list1</code> and <code>list2</code>,
1168 * as required by the general contract of <code>Object.hashCode</code>.
1169 *
1170 * @return
1171 * the hash code value for this list.
1172 * @see List#hashCode()
1173 * @see Object#equals(Object)
1174 * @see #equals(Object)
1175 */
1176 // Note that the magic number comes from the spec of List.hashCode
1177 @SuppressWarnings("checkstyle:magicnumber")
1178 public int hashCode() {
1179 int hashCode = 1;
1180 for (Object obj : this) {
1181 hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
1182 }
1183 return hashCode;
1184 }
1185
1186 public int hashCodeCyclic() {
1187 int hashCode = 0;
1188 for (E element : this.list) {
1189 hashCode += (element == null ? 0 : element.hashCode());
1190 }
1191 return hashCode;
1192 }
1193
1194 // Positional Access Operations
1195
1196 /**
1197 * Returns the number which equals <code>index</code>
1198 * modulo {@link #size this.size()},
1199 * provided this list is not empty.
1200 *
1201 * @param index
1202 * This is interpreted modulo the length of this cyclic list.
1203 * Any index (even negative ones) are valid.
1204 * @return
1205 * the number which equals <code>index</code>
1206 * modulo {@link #size this.size()},
1207 * provided this list is not empty.
1208 * @throws EmptyCyclicListException
1209 * if this list is empty.
1210 */
1211 public int shiftIndex(int index) throws EmptyCyclicListException {
1212 return shiftIndex(index, size());
1213 }
1214
1215 public int shiftIndex(int index, int size) throws EmptyCyclicListException {
1216 if (size == 0) {
1217 throw new EmptyCyclicListException();
1218 }
1219 index %= size;
1220 if (index < 0) {
1221 index += size;
1222 }
1223 assert 0 <= index && index < size;
1224
1225 return index;
1226 }
1227
1228 /**
1229 * Returns the element at the specified position in this list,
1230 * provided this list is not empty.
1231 *
1232 * @param index
1233 * index of element to return.
1234 * This is interpreted modulo the length of this cyclic list.
1235 * Any index (even negative ones) are valid.
1236 * @return
1237 * the element at the specified position in this list.
1238 * @throws EmptyCyclicListException
1239 * if this list is empty.
1240 */
1241 public E get(int index) throws EmptyCyclicListException {
1242 return this.list.get(shiftIndex(index));
1243 }
1244
1245 /**
1246 * Replaces the element at the specified position in this list
1247 * with the specified element (optional operation),
1248 * provided this list is not empty.
1249 *
1250 * @param index
1251 * index of the element to replace.
1252 * This is interpreted modulo the length of this cyclic list.
1253 * Any index (even negative ones) are valid.
1254 * @param element
1255 * element to be stored at the specified position.
1256 * This is interpreted modulo the length of this cyclic list.
1257 * Any index (even negative ones) are valid.
1258 * @return
1259 * the element previously at the specified position.
1260 * @throws EmptyCyclicListException
1261 * if this list is empty.
1262 */
1263 public E set(int index, E element) throws EmptyCyclicListException {
1264 index = shiftIndex(index);
1265 return this.list.set(index, element);
1266 }
1267
1268 /**
1269 * Replaces the element at the specified position in this list
1270 * with the cyclic list of the specified iterator (optional operation).
1271 * Places the elements of that list as returned by <code>iter.next</code>
1272 * in this list.
1273 *
1274 * @param index index
1275 * index of element to replace.
1276 * @param iter
1277 * a <code>CyclicIterator</code> which determines an index in a list
1278 * which replaces <code>this.get(i)</code>.
1279 * @throws EmptyCyclicListException
1280 * if this list is empty.
1281 * @throws IllegalArgumentException
1282 * if the specified iterator is empty.
1283 */
1284 public void replace(int index, Iterator<E> iter) {
1285 // *** why not simply leave unchanged?
1286 if (!iter.hasNext()) {
1287 throw new IllegalArgumentException
1288 ("Could not replace " + index +
1289 "th element because of void iterator " + iter + ". ");
1290 }
1291 set(index++, iter.next());
1292 addAll(index, iter);
1293 }
1294
1295 public void replace(int index, List<E> list) {
1296 if (list.isEmpty()) {
1297 throw new IllegalArgumentException
1298 ("Could not replace " + index +
1299 "th element with empty list. ");
1300 }
1301 set(index++, list.get(0));
1302 addAll(index, list.subList(1, list.size()));
1303 }
1304
1305 /**
1306 * Inserts the cyclic list of the specified iterator
1307 * at the specified position in this list (optional operation).
1308 * In contrast to {@link #replace(int, Iterator)},
1309 * the element currently at the specified position is not lost.
1310 *
1311 * @param index
1312 * index at which the specified list is to be inserted.
1313 * This is interpreted modulo the length of this cyclic list.
1314 * Any index (even negative ones) are valid.
1315 * @param iter
1316 * iterator delivering the elements to be inserted.
1317 */
1318 public void addAll(int index, Iterator<E> iter) {
1319 // ***** very bad implementation. ****
1320 while (iter.hasNext()) {
1321 add(index++, iter.next());
1322 }
1323 }
1324
1325 /**
1326 * Inserts the specified list at the given position
1327 * in this cyclic list.
1328 * ***** done for collections!
1329 * Shifts the element currently at that position (if any)
1330 * and any subsequent elements to the right (increases their indices).
1331 * The new elements will appear in this list
1332 * in the order that they are returned
1333 * by the specified collection's iterator.
1334 * The behavior of this operation is unspecified
1335 * if the specified collection is modified
1336 * while the operation is in progress.
1337 * (Note that this will occur
1338 * if the specified collection is this list, and it's nonempty.)
1339 * Contract:
1340 * <code>list.addAll(i, l);
1341 * return list.get(i+k)</code> yields <code>list.get(k)</code>,
1342 * for all <code>k</code> in <code>0,..,l.size()-1</code>.
1343 * <p>
1344 * Note that for <code>l</code> containing a single element <code>e</code>,
1345 * <code>list.addAll(i, l)</code>
1346 * is equivalent with <code>list.add(i, e)</code>.
1347 *
1348 * @param index
1349 * index at which the specified list is to be inserted.
1350 * This is interpreted modulo the length of this cyclic list.
1351 * Any index (even negative ones) are valid.
1352 * @param addList
1353 * the list to be inserted.
1354 * **** this is much more complicated! ****
1355 */
1356 public void addAll(int index, List<? extends E> addList) {
1357 // this.list.addAll(shiftIndex(index,size()+1), addList);
1358
1359 if (addList.isEmpty()) {
1360 // nothing to do.
1361 return;
1362 }
1363 // Here, addList is not empty.
1364
1365
1366 List<E> oldList = new ArrayList<E>(this.list);
1367 this.list.clear();
1368 // this.list = new ArrayList<E>(size()+addList.size());
1369 //System.out.println("oldList[0]: "+oldList[0]);
1370 // since addList is not empty, size() != 0
1371 // and so shiftIndex is defined.
1372 int newSize = oldList.size() + addList.size();
1373 index = shiftIndex(index, newSize);
1374 System.out.println("newSize: " + newSize);
1375 System.out.println("index: " + index);
1376
1377 // Two cases:
1378 //
1379 // | cyclic list part 1 | list | cyclic list part 2
1380 // index
1381 // and
1382 // | list part 2 | cyclic list | list part 1
1383 // ind1 index
1384 // ind1 = (index+addList.size())%size();
1385
1386 if (index + addList.size() <= newSize) {
1387 // Here, the second copy procedure works.
1388 // | cyclic list part 1 | list | cyclic list part 2
1389 // index
1390
1391
1392 this.list.addAll(oldList.subList(0, index));
1393 this.list.addAll(addList);
1394 this.list.addAll(oldList.subList(index, newSize - addList.size()));
1395 /*
1396 System.arraycopy(oldList, 0, this.list, 0, index);
1397 // copy indices index-1,...,index+addList.length-1
1398 // (addList.length entries).
1399 System.arraycopy(addList, 0, this.list, index, addList.size());
1400 // copy indices the rest of the old entries
1401 // (this.list.size()-index entries).
1402 System.arraycopy(oldList, index, this.list, index+addList.size(),
1403 size()-index-addList.length);
1404 */
1405 } else {
1406 // | list part 2 | cyclic list | list part 1
1407 // ind1 index
1408 int ind1 = (index + addList.size()) % newSize;
1409 int addLen1 = addList.size() - ind1;
1410 assert ind1 <= index;
1411 this.list.addAll(addList.subList(addLen1, addLen1 + ind1));
1412 this.list.addAll(oldList);
1413 this.list.addAll(addList.subList(0, addLen1));
1414 /*
1415 System.arraycopy(oldList, 0, this.list, ind1,
1416 oldList.length);
1417 System.arraycopy(addList, 0, this.list, index, addLen1);
1418 System.arraycopy(addList, addLen1, this.list, 0, ind1);
1419 */
1420 }
1421 }
1422
1423 public boolean addAll(Collection<? extends E> coll) {
1424 throw new UnsupportedOperationException();
1425 }
1426
1427 /**
1428 * Inserts the specified element at the specified position in this list.
1429 * Contract:
1430 * <code>list.add(i,o);return list.get(i)</code> yields <code>o</code>.
1431 * In contrast to {@link #set},
1432 * the element currently at the specified position is not lost.
1433 * Also note that this operation is allowed for empty cyclic lists.
1434 * In this case, <code>index</code> is irrelevant.
1435 *
1436 * @param index
1437 * index at which the specified element is to be inserted.
1438 * This is interpreted modulo the length of this cyclic list plus one
1439 * (The list emerging after the insertion).
1440 * In contrast to {@link java.util.List#add(int,Object)}
1441 * any index (even a negative one) is valid.
1442 * @param element
1443 * element to be inserted.
1444 */
1445 public void add(int index, E element) {
1446 this.list.add(shiftIndex(index, size() + 1), element);
1447 }
1448
1449 public boolean add(E element) {
1450 return this.list.add(element); // always returns true.
1451 }
1452
1453 /**
1454 * Removes the element at the specified position in this list
1455 * (optional operation).
1456 * Returns the element that was removed from the list,
1457 * provided this list is not empty.
1458 *
1459 *
1460 * @param index
1461 * the index of the element to removed.
1462 * This is interpreted modulo the length of this cyclic list.
1463 * Any index (even negative ones) are valid.
1464 * @return
1465 * the element previously at the specified position.
1466 *
1467 * @throws EmptyCyclicListException
1468 * if this list is empty.
1469 */
1470 public E remove(int index) throws EmptyCyclicListException {
1471 return this.list.remove(shiftIndex(index));
1472 }
1473
1474 public boolean remove(Object obj) {
1475 return this.list.remove(obj);
1476 }
1477
1478 public boolean removeAll(Collection<?> coll) {
1479 boolean result = false;
1480 Iterator<?> iter = coll.iterator();
1481 while (iter.hasNext()) {
1482 result |= remove(iter.next());
1483 }
1484 return result;
1485 }
1486
1487
1488 public boolean retainAll(Collection<?> coll) {
1489 boolean result = false;
1490 Iterator<?> iter = this.iterator();
1491 Object cand;
1492 while (iter.hasNext()) {
1493 cand = iter.next();
1494 if (!coll.contains(cand)) {
1495 remove(cand);
1496 result = true;
1497 }
1498 }
1499 return result;
1500 }
1501
1502 /**
1503 * Returns the non-negative index in this cyclic list
1504 * of the first occurrence of the specified element,
1505 * or <code>-1</code> if this cyclic list does not contain this element.
1506 * More formally, returns the lowest index <code>i</code> such that
1507 * <code>(o==null ? get(i)==null : o.equals(get(i)))</code>,
1508 * or some negative index if there is no such index.
1509 * <p>
1510 * Note that this specification slightly differs from
1511 * {@link java.util.List#indexOf(Object)}.
1512 *
1513 * @param idx
1514 * the index to start search with.
1515 * Independently of this,
1516 * the search comprises all entries of this cyclic list.
1517 * @param obj
1518 * element to search for or <code>null</code>.
1519 * @return
1520 * the index in this cyclic list
1521 * of the first occurrence of the specified
1522 * element, or <code>-1</code>
1523 * if this list does not contain this element.
1524 */
1525 public int getIndexOf(int idx, Object obj) {
1526 for (int i = idx; i < this.list.size() + idx; i++) {
1527 if (Objects.equals(this.list.get(i), obj)) {
1528 return i;
1529 }
1530 }
1531 // Here, obj is not found in this cyclic list.
1532 return -1;
1533 }
1534
1535 /**
1536 * Returns a <code>CyclicList</code>
1537 * which is by copying this list step by step
1538 * such that the length of the result is <code>len</code>.
1539 * For example <code>len == size()*n</code>
1540 * yields an n-fold copy of this cyclic list.
1541 *
1542 * @param len
1543 * a non-negative <code>int</code> value.
1544 * @return
1545 * a <code>CyclicList</code>
1546 * which is by copying this list step by step
1547 * such that the length of the result is as specified.
1548 * @throws IllegalArgumentException
1549 * if <code>len</code> is negative.
1550 * @throws EmptyCyclicListException
1551 * if this list is empty and <code>len > 0</code>.
1552 */
1553 public CyclicList<E> getCopy(int len) {
1554
1555 if (len < 0) {
1556 throw new IllegalArgumentException
1557 ("Positive length expected; found: " + len + ". ");
1558 }
1559 if (this.isEmpty()) {
1560 if (len == 0) {
1561 return new CyclicArrayList<E>();
1562 } else {
1563 throw new EmptyCyclicListException();
1564 }
1565 }
1566 // Here, len >= 0 and !this.isEmpty().
1567
1568 List<E> newList = new ArrayList<E>(len);
1569 for (int i = 0; i < len / size(); i++) {
1570 newList.addAll(this.list);
1571 //System.arraycopy(this.list, 0, newList, i*size(), size());
1572 }
1573 newList.addAll(this.list.subList(0, len % size()));
1574 return new CyclicArrayList<E>(newList);
1575 }
1576
1577 public String toString() {
1578 StringBuffer res = new StringBuffer();
1579 res.append("<CyclicList>\n");
1580 for (int i = 0; i < this.size(); i++) {
1581 res.append("" + this.get(i) + " ");
1582 }
1583 res.append("</CyclicList>\n");
1584 return res.toString();
1585 }
1586
1587 /*----------------------------------------------------------------------*/
1588 /* methods implementing Cloneable */
1589 /*----------------------------------------------------------------------*/
1590
1591 // not supported by CyclicList interface either
1592 /**
1593 * Returns a clone of this <code>CyclicArrayList</code>.
1594 * This includes copying<code>vertices</code>.
1595 *
1596 * @return
1597 * a clone of this <code>CyclicArrayList</code>.
1598 * This includes copying <code>vertices</code>.
1599 */
1600 // **** problem with PMD: should use super.clone()
1601 // learn from sources of ArrayList
1602 public CyclicArrayList<E> clone() // NOPMD
1603 throws CloneNotSupportedException {
1604 // CyclicArrayList<E> res = (CyclicArrayList<E>)super.clone();
1605 // res.list.clear();// = (List<E>)((ArrayList<E>)this.list).clone();
1606 // res.list.addAll((List<E>)((ArrayList<E>)this.list).clone());
1607 // return res;
1608 return new CyclicArrayList<E>
1609 ((List<E>) ((ArrayList<E>) this.list).clone());
1610 }
1611 }
1612
1613 // CyclicArrayList.java:1608: warning: [unchecked] unchecked cast
1614 // ((List<E>) ((ArrayList<E>)this.list).clone());
1615 // ^
1616 // required: List<E>
1617 // found: Object
1618 // where E is a type-variable:
1619 // E extends Object declared in class CyclicArrayList