1 package eu.simuline.util;
2
3 import java.util.List;
4 import java.util.Collection;
5 import java.util.ListIterator;
6 import java.util.Iterator;
7 import java.util.ArrayList;
8
9 /**
10 * Compared to a classical list,
11 * the first index of this list may well be positive
12 * and negative indices are allowed as well.
13 * <p>
14 * As a consequence, one can add elements not only at the end of this list
15 * but also at its beginning.
16 * For details consider {@link #add(Object)}, {@link #addFirst(Object)}
17 * and {@link #addLast(Object)}.
18 * Method {@link #add(int ind, Object obj)} is not supported
19 * because inserting an element
20 * requires either shift of subsequent elements to the right
21 * or preceeding elements to the left.
22 * To determine the direction of the shift
23 * use {@link #add(int ind, Object obj, Direction dir)} instead.
24 * Similar considerations apply to methods removing elements.
25 * Also affected are the corresponding collections operations
26 * like <code>addAll</code>.
27 * <p>
28 * Methods {@link #toArray()} and {@link #toArray(Object[])}
29 * satisfy a generalized contract
30 * based on the additional method {@link #firstIndex()}.
31 * <p>
32 * Essentially this two sided list wrapps a classical list.
33 * Various constructors allow to pass that list.
34 * This allows to determine the performance behavior.
35 * The signatures of the constructors
36 * generalize the constructors known
37 * from implementations of classical <code>List</code>s.
38 * The observant reader observes
39 * that the generics are slightly more restrictive than for classical lists.
40 * This is for performance reasons.
41 * Note that the constructors do not create a copy of the wrapped list
42 * which may cause hidden dependencies.
43 * If full generality is needed
44 * the user is asked to use the corresponding factory methods.
45 * <p>
46 * Additionally methods concerning indices are provided
47 * like {@link #firstIndex()}, {@link #minFreeIndex()}
48 * and it is possible to shift a list using {@link #shiftRight(int)}.
49 *
50 * @param <E>
51 * the class of the elements of this list.
52 *
53 * Created: Sun Aug 26 23:25:26 2007
54 *
55 * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
56 * @version 1.0
57 */
58 public final class TwoSidedList<E> implements List<E> {
59
60 /* -------------------------------------------------------------------- *
61 * inner classes. *
62 * -------------------------------------------------------------------- */
63
64 /**
65 * Used as an argument for methods adding or removing elements
66 * from this list
67 * to determine in which direction this list has to shrink or grow.
68 */
69 public enum Direction {
70 Left2Right {
71 // api-docs provided by javadoc
72 void checkRange(int ind, TwoSidedList<?> list) {
73 list.checkRange("",
74 ind,
75 list.firstIndex(),
76 list.minFreeIndex() + 1);
77 }
78 // api-docs provided by javadoc
79 void checkAdd1(TwoSidedList<?> list) {
80 list.checkIncMinFreeIndex();
81 }
82 void checkAddAll(int size, TwoSidedList<?> list) {
83 list.checkMinFreeIndex(size);
84 }
85 }, Right2Left {
86 // api-docs provided by javadoc
87 void checkRange(int ind, TwoSidedList<?> list) {
88 list.checkRange("",
89 ind,
90 list.firstIndex() - 1,
91 list.minFreeIndex());
92 }
93 // api-docs provided by javadoc
94 void checkAdd1(TwoSidedList<?> list) {
95 list.decFirstIndex();
96 }
97 void checkAddAll(int size, TwoSidedList<?> list) {
98 list.subFirstIndex(size);
99 }
100 };
101
102 /**
103 * Checks whether index <code>ind</code>
104 * is in the range of <code>list</code>
105 * and throws an appropriate exception if not.
106 *
107 * @param ind
108 * the index to be checked.
109 * @param list
110 * the twosided list under consideration.
111 * @throws IndexOutOfBoundsException
112 * <ul>
113 * <li> for <code>this == Left2Right</code>if not
114 * <code>list.firstIndex() <= ind<list.minFreeIndex()+1</code>.
115 * <li> for <code>this == Right2Left</code>if not
116 * <code>list.firstIndex()-1 <= ind<list.minFreeIndex() </code>.
117 * </ul>
118 * The message is always the same:
119 * <code>
120 * "Index: <ind> Range: <firstIndex>
121 * - <minFreeIndex()> exclusively. "
122 * </code>.
123 * @see #add (int, Object, Direction)
124 * @see #addAll(int, Collection, Direction)
125 *
126 * <!--used by
127 * add (int, Object obj, Direction)
128 * addAll(int, Collection, Direction)
129 * -->
130 */
131 abstract void checkRange(int ind, TwoSidedList<?> list);
132
133 /**
134 * Checks in {@link TwoSidedList#add(int, Object, Direction)}
135 * whether by adding elements
136 * causes underrun in {@link TwoSidedList#firstIndex()}
137 * or overrun in {@link TwoSidedList#minFreeIndex()}.
138 *
139 * @param list
140 * the twosided list under consideration.
141 * @throws IllegalStateException
142 * if adding an object to this list would
143 * cause underrun in {@link TwoSidedList#firstIndex()}
144 * or overrun in {@link TwoSidedList#minFreeIndex()}
145 * depending on this direction.
146 * @see TwoSidedList#decFirstIndex()
147 * @see TwoSidedList#checkIncMinFreeIndex()
148 * <!-- used only in add(int, E, Direction) -->
149 */
150 abstract void checkAdd1(TwoSidedList<?> list);
151
152 /**
153 * Checks in {@link TwoSidedList#addAll(int, Collection, Direction)}
154 * whether by adding elements
155 * causes underrun in {@link TwoSidedList#firstIndex()}
156 * or overrun in {@link TwoSidedList#minFreeIndex()}.
157 *
158 * @param size
159 * the number of elements to be added.
160 * @param list
161 * the twosided list under consideration.
162 * @throws IllegalStateException
163 * if adding <code>size</code> objects to this list would
164 * cause underrun in {@link TwoSidedList#firstIndex()}
165 * or overrun in {@link TwoSidedList#minFreeIndex()}
166 * depending on this direction.
167 */
168 abstract void checkAddAll(int size, TwoSidedList<?> list);
169
170 } // enum Direction
171
172 /* -------------------------------------------------------------------- *
173 * fields. *
174 * -------------------------------------------------------------------- */
175
176 /**
177 * The list backed by this two-sided list.
178 */
179 private List<E> list;
180
181 /**
182 * The first index in this <code>TwoSidedList</code>.
183 * Note that this integer may well be negative.
184 * The inequality
185 * <code>{@link #minFreeIndex()} >= {@link #firstIndex}</code>
186 * is guaranteed.
187 * Casually, methods adding objects have to reject them
188 * in order not to hurt this
189 * alhough the backed list {@link #list}
190 * would allow adding further elements.
191 */
192 private int firstIndex;
193
194 /* -------------------------------------------------------------------- *
195 * constructors and static factory methods. *
196 * -------------------------------------------------------------------- */
197
198 /**
199 * Creates a new <code>TwoSidedList</code>
200 * containing the elements of {@link #list} in proper sequence
201 * with first index given by {@link #firstIndex}.
202 * <p>
203 * Note the difference to reference implementations such as
204 * <code>java.util.ArrayList</code> where the type of the list argument
205 * is <code>List<? extends E></code>.
206 * We deviate from this solution for performance reason
207 * and provide as an alternative
208 * the factory method {@link #create(List,int)}.
209 * <p>
210 * CAUTION:
211 * This list backs {@link #list} and so changes to one of the list
212 * affect the other list.
213 *
214 * @param list
215 * the list wrapped by this twosided list.
216 * @param firstIndex
217 * the index where this list starts growing.
218 * @throws IllegalStateException
219 * if <code>list</code> is so long
220 * and <code>firstIndex</code> is so large
221 * that {@link #minFreeIndex()} would overrun.
222 */
223 public TwoSidedList(List<E> list, int firstIndex) {
224 this.list = list;
225 this.firstIndex = firstIndex;
226 checkMinFreeIndex(list.size());
227 }
228
229 /**
230 * Creates a new <code>TwoSidedList</code>
231 * containing the elements of <code>list</code> in proper sequence
232 * with first index given by <code>firstIndex</code>.
233 *
234 * @param list
235 * the list wrapped by this twosided list.
236 * Changes to <code>list</code> do not influence this twosided list.
237 * @param firstIndex
238 * the index where this list starts growing.
239 * @throws IllegalStateException
240 * if <code>list</code> is so long
241 * and <code>firstIndex</code> is so large
242 * that {@link #minFreeIndex()} would overrun.
243 */
244 public static <E> TwoSidedList<E> create(List<? extends E> list,
245 int firstIndex) {
246 return new TwoSidedList<E>(new ArrayList<E>(list), firstIndex);
247 }
248
249 /**
250 * Creates a new <code>TwoSidedList</code>
251 * from a <code>List</code> with <code>firstIndex == 0</code>.
252 * This is the canonical generalization of lists
253 * as mentioned in the documentation
254 * of {@link #indexOf(Object)} and of {@link #lastIndexOf(Object)}.
255 * <p>
256 * Note the difference to reference implementations such as
257 * <code>java.util.ArrayList</code> where the type of the list argument
258 * is <code> List<? extends E></code>.
259 * We deviate from this solution for performance reason
260 * and provide as an alternative
261 * the factory method {@link #create(List,int)}.
262 * <p>
263 * CAUTION:
264 * Changes to <code>list</code> influence this twosided list
265 * and may cause malfunction.
266 * Note that unlike {@link #TwoSidedList(List, int)}
267 * this constructor cannot throw an <code>IllegalStateException</code>.
268 *
269 * @param list
270 * the list wrapped by this twosided list.
271 */
272 public TwoSidedList(List<E> list) {
273 this(list, 0);
274 }
275
276 /**
277 * Creates a new <code>TwoSidedList</code>
278 * containing the elements of <code>list</code> in proper sequence.
279 *
280 * @param list
281 * the list wrapped by this twosided list.
282 * Changes to <code>list</code> do not influence this twosided list.
283 */
284 public static <E> TwoSidedList<E> create(List<? extends E> list) {
285 return new TwoSidedList<E>(new ArrayList<E>(list));
286 }
287
288 /**
289 * Copy constructor with shallow copy of the wrapped list {@link #list}.
290 * As a consequence, modifications of the list created
291 * may affect the original one and the other way round.
292 * Note that unlike {@link #TwoSidedList(List, int)}
293 * this constructor cannot throw an <code>IllegalStateException</code>.
294 *
295 * @param other
296 * another <code>TwoSidedList</code>.
297 */
298 public TwoSidedList(TwoSidedList<E> other) {
299 this(other.list, other.firstIndex);
300
301 }
302
303 /**
304 * Creates a new <code>TwoSidedList</code>
305 * as a copy of <code>other</code>
306 * copying also the wrapped list {@link #list}.
307 * As a consequence, the list created and the original one
308 * act independently.
309 * Note that unlike {@link #TwoSidedList(List, int)}
310 * this constructor cannot throw an <code>IllegalStateException</code>.
311 *
312 * @param other
313 * another <code>TwoSidedList</code>.
314 */
315 public static <E> TwoSidedList<E> create(TwoSidedList<? extends E> other) {
316 return new TwoSidedList<E>(new ArrayList<E>(other.list),
317 other.firstIndex);
318 }
319
320 /**
321 * Creates a new empty <code>TwoSidedList</code> which starts growing
322 * with index <code>firstIndex</code>.
323 * Note that unlike {@link #TwoSidedList(List, int)}
324 * this constructor cannot throw an <code>IllegalStateException</code>.
325 *
326 * @param firstIndex
327 * the index where this list starts growing.
328 */
329 public TwoSidedList(int firstIndex) {
330 this(new ArrayList<E>(), firstIndex);
331 }
332
333 /* -------------------------------------------------------------------- *
334 * methods. *
335 * -------------------------------------------------------------------- */
336
337 /**
338 * Checks whether index <code>ind</code> is in range
339 * and throws an appropriate exception if not.
340 *
341 * @param ind
342 * the index to be checked.
343 * @throws IndexOutOfBoundsException
344 * if not <code>firstIndex() <= ind < minFreeIndex()</code>
345 * with message
346 * <code>
347 * "Index: <ind> Range: <firstIndex>
348 * - <minFreeIndex()> exclusively. "
349 * </code>.
350 * <!-- used by
351 * get(int),
352 * set(int, obj),
353 * remove(int ind, Direction) **** is this correct?
354 * -->
355 */
356 void checkRange(int ind) {
357 checkRange("", ind, this.firstIndex, minFreeIndex());
358 }
359
360 /**
361 * Checks whether index <code>ind</code> is in range
362 * and throws an appropriate exception if not.
363 *
364 * @param ind
365 * the index to be checked.
366 * @param dir
367 * the direction in which this twosided list may grow.
368 * @throws IndexOutOfBoundsException
369 * <ul>
370 * <li> for <code>dir == Left2Right</code>
371 * if not <code>firstIndex() <= ind < minFreeIndex()+1</code>.
372 * <li> for <code>dir == Right2Left</code>
373 * if not <code>firstIndex()-1 <= ind < minFreeIndex()</code>.
374 * </ul>
375 * The message is always the same:
376 * <code>
377 * "Index: <ind>Range:<firstIndex>
378 * - <minFreeIndex()>exclusively. "
379 * </code>.
380 * @see #add(int, Object, Direction)
381 * @see #addAll(int, Collection, Direction)
382 *
383 * <!--used by
384 * add (int, Object obj, Direction)
385 * addAll(int, Collection, Direction)
386 * -->
387 */
388 private void checkRange(int ind, Direction dir) {
389 dir.checkRange(ind, this);
390 }
391
392 /**
393 * Checks whether index <code>ind</code> is in range
394 * and throws an appropriate exception if not.
395 *
396 * @param fromToNothing
397 * either <code>""</code>, <code>"from"</code> or <code>"to"</code>.
398 * The latter two cases are used only in {@link #subList(int,int)}
399 * to check the range of the start index and of the end index
400 * of the sublist to be created.
401 * @param ind
402 * the index to be checked.
403 * @param min
404 * the minimal value for <code>ind</code> accepted.
405 * @param maxP
406 * <em>one plus</em> the maximal value for <code>ind</code> accepted.
407 * @throws IndexOutOfBoundsException
408 * if not <code>min >= ind < maxP</code>.
409 * The message is
410 * <code>
411 * "Index: <ind> Range: <firstIndex>
412 * - <minFreeIndex()> exclusively. "
413 * </code> preceeded by <code>fromToNothing</code>.
414 *
415 * <!--used by
416 * Direction.checkRange(int, TwoSidedList)
417 * checkRange(int)
418 * listIterator(int)
419 * subList(int, int)
420 * -->
421 */
422 private void checkRange(String fromToNothing,
423 int ind,
424 int min,
425 int maxP) {
426 if (ind < min || ind >= maxP) {
427 throw new IndexOutOfBoundsException
428 (fromToNothing + "Index: " + ind +
429 " Range: " + this.firstIndex +
430 " - " + minFreeIndex() + " exclusively. ");
431 }
432 }
433
434 /**
435 * Decrements {@link #firstIndex} if possible;
436 * otherwise throws an exception.
437 * This method is used by methods adding objects at the head of this list.
438 * The error message is tailored to this usage.
439 *
440 * @throws IllegalStateException
441 * if <code>{@link #firstIndex} == Integer.MIN_VALUE</code>
442 * adding an element would cause index underrun.
443 */
444 private void decFirstIndex() {
445 if (this.firstIndex == Integer.MIN_VALUE) {
446 throw new IllegalStateException
447 ("Adding an object at top of this list " +
448 "would cause index underrun. ");
449 }
450 this.firstIndex--;
451 }
452
453 /**
454 * Increments {@link #firstIndex} if possible;
455 * otherwise throws an exception.
456 * This method is used by methods removing objects
457 * from the head of this list.
458 * The error message is tailored to this usage.
459 *
460 * @throws IllegalStateException
461 * if <code>{@link #firstIndex} == Integer.MAX_VALUE</code>
462 * removing an element would cause index overrun.
463 */
464 private void incFirstIndex() {
465 if (this.firstIndex == Integer.MAX_VALUE) {
466 throw new IllegalStateException
467 ("Removing an object at top of this list " +
468 "would cause index overrun. ");
469 }
470 this.firstIndex++;
471 }
472
473 /**
474 * Checks whether incrementing {@link #minFreeIndex()}
475 * would cause overrun of {@link #minFreeIndex()}.
476 *
477 * @throws IllegalStateException
478 * if incrementing {@link #minFreeIndex()}
479 * would cause overrun of {@link #minFreeIndex()}.
480 */
481 void checkIncMinFreeIndex() {
482 if (minFreeIndex() == Integer.MAX_VALUE) {
483 throw new IllegalStateException
484 ("Adding an object at the tail of this list " +
485 "would cause index overrun. ");
486 }
487 }
488
489 /**
490 * Subtracts <code>numAdded</code> from {@link #firstIndex} if possible;
491 * otherwise throws an exception.
492 * This method is used by methods adding objects at the head of this list.
493 * The error message is tailored to this usage.
494 *
495 * @throws IllegalStateException
496 * if adding <code>numAdded</code> objects
497 * at the head of this list
498 * would cause underrun of {@link #firstIndex}.
499 */
500 private void subFirstIndex(int numAdded) {
501 if (this.firstIndex < this.firstIndex - numAdded) {
502 throw new IllegalStateException
503 ("Adding " + numAdded + " objects at top of this list " +
504 "would cause index underrun. ");
505 }
506 this.firstIndex -= numAdded;
507 }
508
509 /**
510 * Checks whether adding <code>numAdded</code> objects
511 * to this list **** or at the tail of this list
512 * would cause overrun of {@link #minFreeIndex()}.
513 *
514 * @throws IllegalStateException
515 * if adding <code>numAdded</code> objects
516 * to this list **** or at the tail of this list
517 * would cause overrun of {@link #minFreeIndex()}.
518 */
519 void checkMinFreeIndex(int numAdded) {
520 assert numAdded >= 0;
521 if (minFreeIndex() > minFreeIndex() + numAdded) {
522 throw new IllegalStateException
523 ("Adding " + numAdded + " objects at the tail of this list " +
524 "would cause index overrun. ");
525 }
526 }
527
528 /**
529 * Returns {@link #firstIndex}.
530 */
531 public int firstIndex() {
532 return this.firstIndex;
533 }
534
535 /**
536 * Sets {@link #firstIndex} according to the parameter.
537 */
538 public void firstIndex(int firstIndex) {
539 this.firstIndex = firstIndex;
540 }
541
542 //
543 public int minFreeIndex() {
544 return this.list.size() + this.firstIndex;
545 }
546
547 /**
548 * Shifts this list <code>num</code> indices to the right.
549 *
550 * @param num
551 * the number of shifts to the right
552 * to be performed on this list.
553 * A negative sign signifies a shift to the left.
554 * @return
555 * The new first index.
556 * @throws IllegalStateException
557 * if shifting would cause overrun of {@link #minFreeIndex()}
558 * (occuring for proper shift to the right)
559 * or underrun of {@link #firstIndex()}
560 * (occuring for proper shift to the left).
561 */
562 public int shiftRight(int num) {
563 if (num > 0) {
564 if (minFreeIndex() > minFreeIndex() + num) {
565 throw new IllegalStateException
566 ("Shifting this list by " + num +
567 " would cause index overrun. ");
568 }
569 } else {
570 assert num <= 0;
571 if (this.firstIndex < this.firstIndex + num) {
572 throw new IllegalStateException
573 ("Shifting this list by " + num +
574 " would cause index underrun. ");
575 }
576 }
577
578 this.firstIndex += num;
579 return this.firstIndex;
580 }
581
582 // caution: not wrapped.
583 public List<E> list() {
584 return this.list;
585 }
586
587 /* -------------------------------------------------------------------- *
588 * methods implementing List. *
589 * -------------------------------------------------------------------- */
590
591 /**
592 * Returns the number of elements in this list.
593 * If this list
594 * contains more than <code>Integer.MAX_VALUE</code> elements,
595 * returns <code>Integer.MAX_VALUE</code>.
596 * **** gives rise to malfunction. ****
597 *
598 * @return
599 * an <code>int</code> value
600 */
601 public int size() {
602 return this.list.size();
603 }
604
605 /**
606 * Returns true if this list contains no elements.
607 *
608 * @return
609 * whether this list contains no elements
610 * as a <code>boolean</code> value.
611 */
612 public boolean isEmpty() {
613 return this.list.isEmpty();
614 }
615
616 /**
617 * Returns whether this list contains the specified element.
618 * More formally, returns <code>true</code>
619 * if and only if this list contains at least one element <code>obj</code>
620 * such that <code>(o==null ? e==null : o.equals(e))</code>.
621 *
622 * @param obj
623 * an <code>Object</code> value
624 * @return
625 * a <code>boolean</code> value
626 * @throws ClassCastException
627 * if the class of <code>obj</code>
628 * is incompatible with {@link #list}.
629 * @throws NullPointerException
630 * if <code>obj == null</code>
631 * and {@link #list} does not permit <code>null</code> elements.
632 */
633 public boolean contains(final Object obj) {
634 return this.list.contains(obj);
635 }
636
637 /**
638 * Returns the index of the first occurrence
639 * of the specified element <code>obj</code> in this list,
640 * or {@link #firstIndex()}-1 if this list does not contain the element.
641 * More formally, returns the lowest index <code>i</code>
642 * such that <code>(obj==null ? get(i)==null : obj.equals(get(i)))</code>,
643 * or {@link #firstIndex()}-1 if there is no such index.
644 * <p>
645 * CAUTION:
646 * <ul>
647 * <li>
648 * This breaks **** "extends" contract for the interface List:
649 * Test for "element <code>obj</code> not in list"
650 * is no longer <code>this.indexOf(obj) == -1</code> but
651 * <code>this.indexOf(obj) < this.firstIndex()-1</code>.
652 * This is an extension in that
653 * wrapping an ordinary list in a twosided list
654 * is by specifying <code>firstIndex() == 0</code>
655 * (see {@link #TwoSidedList(List list)}).
656 * <li>
657 * Note that for <code>firstIndex() == {@link Integer#MIN_VALUE}</code>
658 * <code>firstIndex()-1 > firstIndex()</code>.
659 * </ul>
660 *
661 * @param obj
662 * an <code>Object</code> value
663 * @return
664 * <ul>
665 * <li>
666 * the index of the first occurrence of <code>obj</code>
667 * if this object is in this list.
668 * In this case, the return value is within the range
669 * <code>firstIndex()..firstFreeIndex()-1</code>.
670 * <li>
671 * <code>firstIndex()-1</code> if <code>obj</code> is not in this list.
672 * </ul>
673 */
674 public int indexOf(final Object obj) {
675 return this.list.indexOf(obj) + this.firstIndex;
676 }
677
678 /**
679 * Returns the index of the last occurrence
680 * of the specified element <code>obj</code> in this list,
681 * or {@link #firstIndex()}-1 if this list does not contain the element.
682 * More formally, returns the highest index <code>i</code>
683 * such that <code>(obj==null ? get(i)==null : obj.equals(get(i)))</code>,
684 * or {@link #firstIndex()}-1 if there is no such index.
685 * <p>
686 * CAUTION:
687 * <ul>
688 * <li>
689 * This breaks **** "extends" contract for the interface List:
690 * Test for "element <code>obj</code> not in list"
691 * is no longer <code>this.indexOf(obj) == -1</code> but
692 * <code>this.indexOf(obj) < this.firstIndex()-1</code>.
693 * This is an extension in that
694 * wrapping an ordinary list in a twosided list
695 * is by specifying <code>firstIndex() == 0</code>
696 * (see {@link #TwoSidedList(List list)}).
697 * <li>
698 * Note that for <code>firstIndex() == {@link Integer#MIN_VALUE}</code>
699 * <code>firstIndex()-1 > firstIndex()</code>.
700 * </ul>
701 * **** one may expect
702 * that in case the specified object in not in the list
703 * 1+ the highest index is returned.
704 * this is in general not the case.
705 *
706 * @param obj
707 * an <code>Object</code> value
708 * @return
709 * <ul>
710 * <li>
711 * the index of the last occurrence of <code>obj</code>
712 * if this object is in this list.
713 * In this case, the return value is within the range
714 * <code>firstIndex()..firstFreeIndex()-1</code>.
715 * <li>
716 * <code>firstIndex()-1</code> if <code>obj</code> is not in this list.
717 * </ul>
718 */
719 public int lastIndexOf(final Object obj) {
720 return this.list.lastIndexOf(obj) + this.firstIndex;
721 }
722
723 /**
724 * Note that this generalizes the contract of the underlying interface:
725 * Instead of <code>this.toArray[i] == this.get(i)</code>
726 * now only <code>this.toArray[i] == this.get(i-firstIndex())</code>.
727 * Equality includes that the left hand side throws an exception
728 * if and only if so does te right hand side.
729 *
730 * @return
731 * an <code>Object[]</code> containing all elements in proper sequence.
732 */
733 // api-docs provided by javadoc.
734 public Object[] toArray() {
735 return this.list.toArray();
736 }
737
738 /**
739 * Note that this generalizes the contract of the underlying interface:
740 * Instead of <code>this.toArray[i] == this.get(i)</code>
741 * now only <code>this.toArray[i] == this.get(i-firstIndex())</code>.
742 * Equality includes that the left hand side throws an exception
743 * if and only if so does te right hand side.
744 *
745 * @param objArr
746 * an <code>Object[]</code> value
747 * @return
748 * an <code>Object[]</code> value
749 */
750 // api-docs provided by javadoc.
751 public <E> E[] toArray(final E[] objArr) {
752 return this.list.toArray(objArr);
753 }
754
755 /**
756 * Returns the element at the specified position in this list.
757 *
758 * @param ind
759 * the index of the element to return as an <code>int</code> value.
760 * @return
761 * the element at the specified position in this list.
762 * @throws IndexOutOfBoundsException
763 * as described for {@link #checkRange(int)}
764 */
765 public E get(final int ind) {
766 checkRange(ind);
767 return this.list.get(ind - this.firstIndex);
768 }
769
770 /**
771 * Replaces the element at the <code>ind</code>th position
772 * in this list with the specified element (optional operation).
773 *
774 * @param ind
775 * the index of the element to replace as an <code>int</code> value.
776 * @param obj
777 * the element to be stored at the specified position.
778 * @return
779 * the element previously at the <code>ind</code>th position
780 * @throws UnsupportedOperationException
781 * if the <code>set</code> operation is not supported
782 * by {@link #list}.
783 * @throws ClassCastException
784 * if the class of <code>obj</code>
785 * prevents it from being added to {@link #list}.
786 * @throws NullPointerException
787 * if <code>obj == null</code>
788 * and {@link #list} does not permit <code>null</code> elements.
789 * @throws IllegalArgumentException
790 * if some property of <code>obj</code>
791 * prevents it from being added to {@link #list}.
792 * @throws IndexOutOfBoundsException
793 * as described for {@link #checkRange(int)}
794 */
795 public E set(final int ind, final E obj) {
796 checkRange(ind);
797 return this.list.set(ind - this.firstIndex, obj);
798 }
799
800
801 /**
802 * Not supported by this implementation. **** breaks contract
803 *
804 * @throws UnsupportedOperationException
805 * use {@link #addFirst} and {@link #addLast} instead.
806 */
807 public boolean add(final E obj) {
808 throw new UnsupportedOperationException
809 ("Use addFirst(Object) or addLast(E) instead. ");
810 }
811
812 /**
813 * Adds <code>obj</code> at the beginning of this list.
814 * The first index returned by {@link #firstIndex()}
815 * is decremented.
816 *
817 * @param obj
818 * the <code>E</code> object to be added.
819 * @return
820 * <code>true</code> by specification.
821 * @throws UnsupportedOperationException
822 * if the <code>add(int,E)</code> operation is not supported
823 * by {@link #list}.
824 * @throws ClassCastException
825 * if the class of <code>obj</code>
826 * prevents it from being added to {@link #list}.
827 * @throws NullPointerException
828 * if <code>obj == null</code>
829 * and {@link #list} does not permit <code>null</code> elements.
830 * @throws IllegalArgumentException
831 * if some property of <code>obj</code>
832 * prevents it from being added to {@link #list}.
833 * @throws IllegalStateException
834 * if <code>{@link #firstIndex} == Integer.MIN_VALUE</code>
835 * adding an element would cause index underrun.
836 */
837 public boolean addFirst(final E obj) {
838 // may throw an IllegalStateException
839 decFirstIndex();
840 this.list.add(0, obj);
841 return true;
842 }
843
844 /**
845 * Adds <code>obj</code> at the end of this list.
846 * The first index returned by {@link #firstIndex()} remains unchanged.
847 *
848 * @param obj
849 * the <code>E</code> object to be added.
850 * @return
851 * <code>true</code> by specification.
852 * @throws UnsupportedOperationException
853 * if the <code>add(E)</code> operation is not supported
854 * by {@link #list}.
855 * @throws ClassCastException
856 * if the class of <code>obj</code>
857 * prevents it from being added to {@link #list}.
858 * @throws NullPointerException
859 * if <code>obj == null</code>
860 * and {@link #list} does not permit <code>null</code> elements.
861 * @throws IllegalArgumentException
862 * if some property of <code>obj</code>
863 * prevents it from being added to {@link #list}.
864 * @throws IllegalStateException
865 * if adding objects to this list
866 * would cause overrun of {@link #minFreeIndex()}.
867 */
868 public boolean addLast(final E obj) {
869 checkIncMinFreeIndex();
870 return this.list.add(obj);
871 }
872
873 /**
874 * Not supported by this implementation. **** breaks contract
875 *
876 * @throws UnsupportedOperationException
877 * use {@link #add(int,Object,Direction)} instead.
878 */
879 public void add(final int ind, final E obj) {
880 throw new UnsupportedOperationException
881 ("Use add(int,E,Direction) instead. ");
882 }
883
884 /**
885 * Inserts <code>obj</code> at the specified position <code>ind</code>
886 * in this list (optional operation).
887 * Shifts the element currently at that position (if any)
888 * and any following/preceeding elements to the direction <code>dir</code>
889 * (increments/decrements their indices).
890 *
891 * @param ind
892 * the index where to insert <code>obj</code>.
893 * After having performed this operation,
894 * <code>ind</code> is the index of <code>obj</code>.
895 * @param obj
896 * the <code>E</code> element to be inserted.
897 * @param dir
898 * determines the direction to shift the list.
899 * <ul>
900 * <li><code>Left2Right</code>:
901 * shifts all subsequent objects in this list
902 * starting with index <code>ind</code> to the right
903 * adding one to their indices.
904 * <li><code>Right2Left</code>:
905 * shifts all objects in this list
906 * to index <code>ind</code> to the left
907 * subtracting one from their indices.
908 * </ul>
909 * @throws UnsupportedOperationException
910 * if the <code>add</code> operation
911 * is not supported by {@link #list}.
912 * @throws ClassCastException
913 * if the class of <code>obj</code>
914 * prevents it from being added to {@link #list}.
915 * @throws NullPointerException
916 * if <code>obj == null</code>
917 * and {@link #list} does not permit <code>null</code> elements.
918 * @throws IllegalArgumentException
919 * if some property of <code>obj</code>
920 * prevents it from being added to {@link #list}.
921 * @throws IndexOutOfBoundsException
922 * as described for {@link #checkRange(int,Direction)}
923 */
924 public void add(final int ind, final E obj, final Direction dir) {
925 checkRange(ind, dir);
926 dir.checkAdd1(this);
927 this.list.add(ind - this.firstIndex, obj);
928 }
929
930 /**
931 * Not supported by this implementation. **** breaks contract
932 *
933 * @throws UnsupportedOperationException
934 * use {@link #remove(int,Direction)} instead.
935 */
936 public E remove(final int ind) {
937 throw new UnsupportedOperationException
938 ("Use remove(int,Direction) instead. ");
939 }
940
941 /**
942 * Removes the element at the specified position in this list
943 * (optional operation).
944 * Shifts any following/preceeding elements
945 * to the direction <code>dir</code>
946 * (decrements/increments their indices).
947 * Returns the element that was removed from the list.
948 *
949 * @param ind
950 * the index of the element to be removed
951 * as an <code>int</code> value.
952 * @return
953 * the element previously at the specified position.
954 * @throws UnsupportedOperationException
955 * if the <code>remove(int)</code> operation
956 * is not supported by {@link #list}.
957 * @throws IndexOutOfBoundsException
958 * as described for {@link #checkRange(int)}
959 */
960 public E remove(final int ind, Direction dir) {
961 checkRange(ind);
962 E res = this.list.remove(ind - this.firstIndex);
963 if (dir == Direction.Right2Left) {
964 // Note that this may not throw any exception in this case.
965 incFirstIndex();
966 }
967
968 return res;
969 }
970
971 /**
972 * Not supported by this implementation. **** breaks contract
973 *
974 * @throws UnsupportedOperationException
975 * use {@link #removeFirst(Object)}
976 * and {@link #removeLast(Object)} instead.
977 */
978 public boolean remove(final Object obj) {
979 throw new UnsupportedOperationException
980 ("Use removeFirst(E) or removeLast(E) instead. ");
981 }
982
983 /**
984 * Removes the first occurrence of <code>obj</code> from this list,
985 * if present (optional operation).
986 * If this list does not contain <code>obj</code>, it is unchanged.
987 * More formally, removes the element with the lowest index <code>i</code>
988 * such that <code>(obj==null ? get(i)==null : obj.equals(get(i)))</code>
989 * (if such an element exists).
990 * Returns <code>true</code> if this list contained the specified element
991 * (or equivalently, if this list changed as a result of the call).
992 * The first index returned by {@link #firstIndex()} remains unchanged.
993 *
994 * @param obj
995 * the element to be removed from this list, if present.
996 * @return
997 * whether this list contained the specified element
998 * @throws UnsupportedOperationException
999 * if the <code>remove(Object)</code> operation is not supported
1000 * by {@link #list}.
1001 */
1002 public boolean removeFirst(final Object obj) {
1003 return this.list.remove(obj);
1004 }
1005
1006 /**
1007 * Removes the last occurrence of <code>obj</code> from this list,
1008 * if present (optional operation).
1009 * If this list does not contain <code>obj</code>, it is unchanged.
1010 * More formally,
1011 * removes the element with the highest index <code>i</code>
1012 * such that <code>(obj==null ? get(i)==null : obj.equals(get(i)))</code>
1013 * (if such an element exists).
1014 * Returns <code>true</code> if this list contained the specified element
1015 * (or equivalently, if this list changed as a result of the call).
1016 * The first index returned by {@link #firstIndex()} is incremented
1017 * if really an object was removed.
1018 *
1019 * @param obj
1020 * the element to be removed from this list, if present.
1021 * @return
1022 * whether this list contained the specified element
1023 * @throws UnsupportedOperationException
1024 * if the <code>remove(int)</code> **** not remove(Object)
1025 * operation is not supported
1026 * by {@link #list}.
1027 */
1028 public boolean removeLast(final Object obj) {
1029 int ind = this.list.lastIndexOf(obj);
1030 if (ind == -1) {
1031 // obj \notin this
1032 return false;
1033 } else {
1034 // obj \in this
1035 // Note that this may not throw any exception in this case.
1036 incFirstIndex();
1037 this.list.remove(ind);
1038 return true;
1039 }
1040 }
1041
1042 /**
1043 * Removes all of the elements from this list (optional operation).
1044 * The list will be empty after this call returns
1045 * and {@link #firstIndex} is unmodified.
1046 *
1047 * @throws UnsupportedOperationException
1048 * if the clear operation is not supported by {@link #list}.
1049 */
1050 public void clear() {
1051 this.list.clear();
1052 }
1053
1054 /**
1055 * Not supported by this implementation.
1056 *
1057 * @throws UnsupportedOperationException
1058 * use {@link #addAllFirst} and {@link #addAllLast} instead.
1059 */
1060 public boolean addAll(final Collection<? extends E> coll) {
1061 throw new UnsupportedOperationException
1062 ("Use addAllFirst or addAllLast instead. ");
1063 }
1064
1065 /**
1066 * Adds <code>obj</code> at the beginning of this list.
1067 * in the order that they are returned
1068 * by <code>coll</code>'s iterator (optional operation).
1069 * The behavior of this operation is undefined
1070 * if the specified collection is modified
1071 * while the operation is in progress.
1072 * (Note that this will occur if <code>coll</code> is this list,
1073 * and it's nonempty.)
1074 * The first index returned by {@link #firstIndex()}
1075 * is reduced by <code>coll</code>'s size.
1076 *
1077 * @param coll
1078 * a <code>Collection</code> value
1079 * @return
1080 * whether this list changed as a result of the call
1081 * as a <code>boolean</code> value.
1082 * @throws UnsupportedOperationException
1083 * if the addAll operation is not supported by this {@link #list}.
1084 * @throws ClassCastException
1085 * if the class of an element of the specified collection
1086 * prevents it from being added to {@link #list}.
1087 * @throws NullPointerException
1088 * if the specified collection contains
1089 * one or more <code>null</code> elements
1090 * and {@link #list} does not permit <code>null</code> elements
1091 * or if the specified collection is <code>null</code>
1092 * @throws IllegalArgumentException
1093 * if some property of an element of the specified collection
1094 * prevents it from being added to {@link #list}.
1095 * @throws IllegalStateException
1096 * if adding <code>numAdded</code> objects
1097 * at the head of this list
1098 * would cause underrun of {@link #firstIndex}.
1099 */
1100 public boolean addAllFirst(final Collection<? extends E> coll) {
1101 subFirstIndex(coll.size());
1102 return this.list.addAll(0, coll);
1103 }
1104
1105 /**
1106 * Appends all of the elements in <code>coll</code>
1107 * to the end of this list,
1108 * in the order that they are returned
1109 * by <code>coll</code>'s iterator (optional operation).
1110 * The behavior of this operation is undefined
1111 * if the specified collection is modified
1112 * while the operation is in progress.
1113 * (Note that this will occur if <code>coll</code> is this list,
1114 * and it's nonempty.)
1115 * The first index returned by {@link #firstIndex()} remains unchanged.
1116 *
1117 * @param coll
1118 * another <code>Collection</code>.
1119 * @return
1120 * whether this list changed as a result of the call
1121 * as a <code>boolean</code> value.
1122 * @throws UnsupportedOperationException
1123 * if the addAll operation is not supported by this {@link #list}.
1124 * @throws ClassCastException
1125 * if the class of an element of the specified collection
1126 * prevents it from being added to {@link #list}.
1127 * @throws NullPointerException
1128 * if the specified collection contains
1129 * one or more <code>null</code> elements
1130 * and {@link #list} does not permit <code>null</code> elements
1131 * or if the specified collection is <code>null</code>
1132 * @throws IllegalArgumentException
1133 * if some property of an element of the specified collection
1134 * prevents it from being added to {@link #list}.
1135 * @throws IllegalStateException
1136 * if adding <code>numAdded</code> objects
1137 * to this list **** or at the tail of this list
1138 * would cause overrun of {@link #minFreeIndex()}.
1139 */
1140 public boolean addAllLast(final Collection<? extends E> coll) {
1141 checkMinFreeIndex(coll.size());
1142 return this.list.addAll(coll);
1143 }
1144
1145 /**
1146 * Not supported by this implementation.
1147 *
1148 * @throws UnsupportedOperationException
1149 * use {@link #addAll(int,Collection,Direction)} instead.
1150 */
1151 public boolean addAll(final int ind,
1152 final Collection<? extends E> coll) {
1153 throw new UnsupportedOperationException
1154 ("Use addAll(int,Collection,Direction) instead. ");
1155 }
1156
1157 /**
1158 * Inserts all of the elements in <code>coll</code> into this list
1159 * at the specified position (optional operation).
1160 * Shifts the elements currently at that positions (if any)
1161 * and any following/preceeding elements to the direction <code>dir</code>
1162 * (increasing/decreasing their indices by <code>coll</code>'s size).
1163 * The new elements will appear in this list in the order
1164 * that they are returned by the specified collection's iterator.
1165 * The behavior of this operation is undefined
1166 * if the specified collection is modified
1167 * while the operation is in progress.
1168 * (Note that this will occur if the specified collection is this list,
1169 * and it's nonempty.)
1170 *
1171 * @param ind
1172 * index at which to insert the first element from <code>coll</code>
1173 * as an <code>int</code> value.
1174 * CAUTION: Note that <code>ind</code>
1175 * always references the first element in <code>coll</code>
1176 * independent from <code>dir</code>.
1177 * @param coll
1178 * a <code>Collection</code>
1179 * containing elements to be added to this list.
1180 * @param dir
1181 * determines the direction to shift the list.
1182 * <ul>
1183 * <li><code>Left2Right</code>:
1184 * shifts all subsequent objects in this list
1185 * starting with index <code>ind</code> to the right
1186 * adding one to their indices.
1187 * <li><code>Right2Left</code>:
1188 * shifts all objects in this list
1189 * to index <code>ind</code> to the left
1190 * subtracting one from their indices.
1191 * </ul>
1192 * @return
1193 * whether this list changed as a result of the call
1194 * as a <code>boolean</code> value.
1195 * @throws UnsupportedOperationException
1196 * if the <code>addAll</code> operation
1197 * is not supported by this {@link #list}.
1198 * @throws ClassCastException
1199 * if the class of an element of <code>coll</code>
1200 * prevents it from being added to {@link #list}.
1201 * @throws NullPointerException
1202 * if the <code>coll</code> contains
1203 * at least one <code>null</code> element
1204 * and {@link #list} does not permit <code>null</code> elements
1205 * or if <code>coll == null</code>.
1206 * @throws IllegalArgumentException
1207 * if some property of an element of the specified collection
1208 * prevents it from being added to {@link #list}.
1209 * @throws IndexOutOfBoundsException
1210 * as described for {@link #checkRange(int,Direction)}
1211 * @throws IllegalStateException
1212 * if adding <code>coll</code> to this list
1213 * would cause underrun of {@link #firstIndex}
1214 * or overrun of {@link #minFreeIndex}.
1215 */
1216 public boolean addAll(final int ind,
1217 final Collection<? extends E> coll,
1218 final Direction dir) {
1219 checkRange(ind, dir);
1220 dir.checkAddAll(coll.size(), this);
1221 return this.list.addAll(ind - this.firstIndex, coll);
1222 }
1223
1224 /*
1225 * Returns an iterator over the elements in this list in proper sequence.
1226 *
1227 * @return
1228 * an iterator over the elements in this list in proper sequence.
1229 */
1230 // api-docs provided by javadoc.
1231 public Iterator<E> iterator() {
1232 return this.list.iterator();
1233 }
1234
1235 /*
1236 * Returns a list iterator over the elements in this list
1237 * (in proper sequence).
1238 *
1239 * @return
1240 * a <code>ListIterator</code>
1241 */
1242 // api-docs provided by javadoc
1243 public ListIterator<E> listIterator() {
1244 return this.list.listIterator();
1245 }
1246
1247 /**
1248 * ****maybe to be endowed with a direction.
1249 *
1250 * @param ind
1251 * an <code>int</code> value
1252 * @return
1253 * a <code>ListIterator</code> value
1254 * @throws IndexOutOfBoundsException
1255 * if not <code>firstIndex() <= ind <= minFreeIndex()</code>
1256 * with message
1257 * <code>
1258 * "Index: <ind> Range: <firstIndex> -
1259 * <minFreeIndex()> exclusively. "
1260 * </code>.
1261 */
1262 public ListIterator<E> listIterator(final int ind) {
1263 checkRange("", ind, this.firstIndex, minFreeIndex() + 1);
1264 return this.list.listIterator(ind - this.firstIndex);
1265 }
1266
1267 /**
1268 * Replaces the element at the <code>ind</code>th position
1269 * in this list with the specified element (optional operation).
1270 *
1271 * @param coll
1272 * a <code>Collection</code> value
1273 * @return
1274 * a <code>boolean</code> value
1275 * @throws ClassCastException
1276 * if the class of one or more elements of <code>coll</code>
1277 * is incompatible with {@link #list}.
1278 * @throws NullPointerException
1279 * if <code>coll</code> contains at least one <code>null</code> element
1280 * and {@link #list} is incompatible with <code>null</code> elements
1281 * or if <code>coll == null</code>.
1282 */
1283 public boolean containsAll(final Collection<?> coll) {
1284 return this.list.containsAll(coll);
1285 }
1286
1287 /**
1288 * Not supported by this implementation.
1289 *
1290 * @throws UnsupportedOperationException
1291 * use {@link #removeAll(Collection,Direction)} instead.
1292 */
1293 public boolean removeAll(final Collection<?> coll) {
1294 throw new UnsupportedOperationException
1295 ("Use removeAll(Collection,Direction) instead. ");
1296 }
1297
1298 /**
1299 * Removes from this list all of its elements
1300 * that are contained in <code>coll</code> (optional operation).
1301 * Shifts the elements currently at that position (if any)
1302 * and any following/preceeding elements to the direction <code>dir</code>
1303 * (decreasing/increasing their indices
1304 * by the number of elements removed).
1305 *
1306 * @param coll
1307 * a <code>Collection</code>
1308 * containing elements to be removed from this list.
1309 * @param dir
1310 * determines the direction to shift the list.
1311 * <ul>
1312 * <li><code>Left2Right</code>:
1313 * to close gaps by removing elements
1314 * shifts all objects preceeding gaps to the right
1315 * adding one to their indices.
1316 * <li><code>Right2Left</code>:
1317 * to close gaps by removing elements
1318 * shifts all objects following gaps to the left
1319 * subtracting one from their indices.
1320 * </ul>
1321 * @return
1322 * whether this list changed as a result of the call
1323 * as a <code>boolean</code> value.
1324 * @throws UnsupportedOperationException
1325 * if the <code>removeAll</code> operation
1326 * is not supported by this {@link #list}.
1327 * @throws ClassCastException
1328 * if the class of an element of <code>coll</code>
1329 * is incompatible with {@link #list}.
1330 * @throws NullPointerException
1331 * if the <code>coll</code> contains
1332 * at least one <code>null</code> element
1333 * and {@link #list} does not permit <code>null</code> elements
1334 * or if <code>coll == null</code>.
1335 */
1336 public boolean removeAll(final Collection<?> coll, Direction dir) {
1337 switch (dir) {
1338 case Left2Right:
1339 return this.list.removeAll(coll);
1340 case Right2Left:
1341 int oldSize = this.list.size();
1342 boolean ret = this.list.removeAll(coll);
1343 // This retains the inequality
1344 // firstIndex() <= firstFreeIndex()
1345 this.firstIndex += oldSize - this.list.size();
1346 return ret;
1347 default:
1348 throw new IllegalStateException();
1349 }
1350 }
1351
1352 /**
1353 * Not supported by this implementation.
1354 *
1355 * @throws UnsupportedOperationException
1356 * use {@link #retainAll(Collection,Direction)} instead.
1357 */
1358 public boolean retainAll(final Collection<?> coll) {
1359 throw new UnsupportedOperationException
1360 ("Use retainAll(Collection,Direction) instead. ");
1361 }
1362
1363 /**
1364 * Retains only the elements in this list
1365 * that are contained in <code>coll</code> (optional operation).
1366 * In other words, removes from this list all the elements
1367 * that are not contained in <code>coll</code>.
1368 * Shifts the elements currently at that position (if any)
1369 * and any following/preceeding elements to the direction <code>dir</code>
1370 * (decreasing/increasing their indices
1371 * by the number of elements removed).
1372 *
1373 * @param coll
1374 * a <code>Collection</code>
1375 * containing elements to be retained in this list.
1376 * @param dir
1377 * determines the direction to shift the list.
1378 * <ul>
1379 * <li><code>Left2Right</code>:
1380 * to close gaps by removing elements
1381 * shifts all objects preceeding gaps to the right
1382 * adding one to their indices.
1383 * <li><code>Right2Left</code>:
1384 * to close gaps by removing elements
1385 * shifts all objects following gaps to the left
1386 * subtracting one from their indices.
1387 * </ul>
1388 * @return
1389 * whether this list changed as a result of the call
1390 * as a <code>boolean</code> value.
1391 * @throws UnsupportedOperationException
1392 * if the <code>retainAll</code> operation
1393 * is not supported by this {@link #list}.
1394 * @throws ClassCastException
1395 * if the class of an element of <code>coll</code>
1396 * is incompatible with {@link #list}.
1397 * @throws NullPointerException
1398 * if the <code>coll</code> contains
1399 * at least one <code>null</code> element
1400 * and {@link #list} does not permit <code>null</code> elements
1401 * or if <code>coll == null</code>.
1402 */
1403 public boolean retainAll(final Collection<?> coll, Direction dir) {
1404 switch (dir) {
1405 case Left2Right:
1406 return this.list.retainAll(coll);
1407 case Right2Left:
1408 int oldSize = this.list.size();
1409 boolean ret = this.list.retainAll(coll);
1410 // This retains the inequality
1411 // firstIndex() <= firstFreeIndex()
1412 this.firstIndex += oldSize - this.list.size();
1413 return ret;
1414 default:
1415 throw new IllegalStateException();
1416 }
1417 }
1418
1419 /**
1420 * Returns a view of the portion of this twosided list as a list
1421 * between the specified <code>fromIndex</code>, inclusive,
1422 * and <code>toIndex</code>, exclusive.
1423 *
1424 * @param indStart
1425 * low endpoint (inclusive) of the subList to be returned.
1426 * @param indEnd
1427 * high endpoint (exclusive) of the subList to be returned.
1428 * @return
1429 * view of the specified range within this list.
1430 * The returned list is backed by this list,
1431 * so non-structural changes in the returned list
1432 * are reflected in this list, and vice-versa.
1433 * @throws IndexOutOfBoundsException
1434 * if not
1435 * <code>firstIndex() <= indStart <= indEnd <= minFreeIndex()</code>
1436 */
1437 public List<E> subList(final int indStart, final int indEnd) {
1438 if (indStart > indEnd) {
1439 throw new IndexOutOfBoundsException
1440 ("fromIndex(" + indStart + ") > toIndex(" + indEnd + ")");
1441 }
1442 // only one invocation can throw an exception.
1443 checkRange("from", indStart, this.firstIndex, minFreeIndex() + 1);
1444 checkRange("to", indEnd, this.firstIndex, minFreeIndex() + 1);
1445 return this.list.subList(indStart - this.firstIndex,
1446 indEnd - this.firstIndex);
1447 }
1448
1449 /**
1450 * Returns a view of the portion of this twosided list
1451 * between the specified <code>fromIndex</code>, inclusive,
1452 * and <code>toIndex</code>, exclusive.
1453 *
1454 * @param indStart
1455 * low endpoint (inclusive) of the subList to be returned.
1456 * @param indEnd
1457 * high endpoint (exclusive) of the subList to be returned.
1458 * @return
1459 * view of the specified range within this list.
1460 * The returned list is backed by this list,
1461 * so non-structural changes in the returned list
1462 * are reflected in this list, and vice-versa.
1463 * @throws IndexOutOfBoundsException
1464 * see {@link #subList(int,int)}
1465 */
1466 public TwoSidedList<E> subList2(final int indStart,
1467 final int indEnd) {
1468 return new TwoSidedList<E>(subList(indStart, indEnd), indStart);
1469 }
1470
1471 /**
1472 * The given object equals this twosided list
1473 * if and only if it is as well a <code>TwoSidedList</code>,
1474 * the two lists wrapped {@link #list} coincide
1475 * and either as well the first indices {@link #firstIndex} coincide.
1476 * CAUTION:
1477 * Note that two empty lists with different first index are not equal.
1478 * This is justified by the fact,
1479 * that these two become different when the same first element is added
1480 * to both lists.
1481 *
1482 * @param obj
1483 * an <code>Object</code> value
1484 * @return
1485 * a <code>boolean</code> value
1486 */
1487 public boolean equals(final Object obj) {
1488 if (!(obj instanceof TwoSidedList)) {
1489 return false;
1490 }
1491 TwoSidedList<?> other = (TwoSidedList<?>) obj;
1492
1493 return this.list.equals(other.list)
1494 && this.firstIndex == other.firstIndex;
1495 }
1496
1497 /**
1498 * Returns a hash code which conforms with {@link #equals(Object)}.
1499 *
1500 * @return
1501 * the hash code as an <code>int</code> value.
1502 */
1503 public int hashCode() {
1504 return this.list.hashCode() + this.firstIndex;
1505 }
1506
1507 // api-docs provided by javadoc
1508 public String toString() {
1509 StringBuilder res = new StringBuilder();
1510 res.append("<TwoSidedList firstIndex=\"");
1511 res.append(this.firstIndex);
1512 res.append("\">");
1513 res.append(this.list);
1514 res.append("</TwoSidedList>");
1515 return res.toString();
1516 }
1517
1518 public static void main(String[] args) {
1519 }
1520 }