/* File: CheckedSeq.java.java Originally written by Doug Lea and released into the public domain. Thanks for the assistance and support of Sun Microsystems Labs, Agorics Inc, Loral, and everyone contributing, testing, and using this code. History: Date Who What 24Sep95 dl@cs.oswego.edu Create from collections.java working file 13Oct95 dl Misc clean-up 19Oct95 dl More misc clean-up */ package collections; import java.util.Enumeration; import java.util.NoSuchElementException; /** * * @author Doug Lea * @version 0.94 * *
For an introduction to this package see Overview . **/ public class CheckedSeq extends CheckedCollection implements UpdatableSeq { /** * Wrap Seq s inside a checker **/ public CheckedSeq(UpdatableSeq s) { super(s); } /** * Make a Checked clone of underlying collection **/ protected Object clone() throws CloneNotSupportedException { return new CheckedSeq((UpdatableSeq)(thys.duplicate())); } /** * return casted version of CheckedCollection.thys. **/ public UpdatableSeq thys() { return (UpdatableSeq)thys; } /** * return casted version of CheckedCollection.prev. **/ public UpdatableSeq prev() { return (UpdatableSeq)prev; } /** * Checks collections.Collection.elements according to its specification * @see collections.Collection#elements **/ public synchronized CollectionEnumeration elements() { // get one and make sure it is OK int c = thys.size(); CollectionEnumeration e = thys.elements(); int i = 0; while (e.hasMoreElements()) { assert(e.numberOfRemainingElements() == c); --c; Object v = e.nextElement(); // Make sure all forms of indexing v work assert(thys().at(i).equals(v)); assert(thys().firstIndexOf(v, i) == i); assert(thys().lastIndexOf(v, i) == i); assert(thys().firstIndexOf(v) <= i); assert(thys().lastIndexOf(v) >= i); ++i; } postCheck(); return thys.elements(); } /** * Checks collections.Seq.at according to its specification * @see collections.Seq#at **/ public synchronized Object at(int index) throws NoSuchElementException { preCheck(); try { Object result = thys().at(index); assert(result != null); assert(thys.includes(result)); assert(index >= 0 && index < thys.size()); assert(thys.sameStructure(prev)); postCheck(); return result; } catch (NoSuchElementException ex) { assert(index < 0 || index >= thys.size()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.Seq.first according to its specification * @see collections.Seq#first **/ public synchronized Object first() throws NoSuchElementException { preCheck(); try { Object result = thys().first(); assert(result.equals(thys().at(0))); assert(thys.sameStructure(prev)); postCheck(); return result; } catch (NoSuchElementException ex) { assert(thys.isEmpty()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.Seq.last according to its specification * @see collections.Seq#last **/ public synchronized Object last() throws NoSuchElementException { preCheck(); try { Object result = thys().last(); assert(result.equals(thys().at(thys.size()-1))); assert(thys.sameStructure(prev)); postCheck(); return result; } catch (NoSuchElementException ex) { assert(thys.isEmpty()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.Seq.firstIndexOf according to its specification * @see collections.Seq#firstIndexOf **/ public synchronized int firstIndexOf(Object element, int startingIndex) { preCheck(); int result = thys().firstIndexOf(element, startingIndex); int si = (startingIndex < 0)? 0 : startingIndex; int n = result; if (n < 0) n = thys.size(); for (int i = si; i < n; ++i) assert(!thys().at(i).equals(element)); if (result != -1) { assert(thys().at(result).equals(element)); assert(result >= startingIndex); assert(result < thys.size()); } assert(thys.sameStructure(prev)); postCheck(); return result; } /** * Checks collections.Seq.firstIndexOf according to its specification * @see collections.Seq#firstIndexOf **/ public synchronized int firstIndexOf(Object element) { preCheck(); int result = thys().firstIndexOf(element); assert(result == thys().firstIndexOf(element, 0)); assert(thys.sameStructure(prev)); postCheck(); return result; } /** * Checks collections.Seq.lastIndexOf according to its specification * @see collections.Seq#lastIndexOf **/ public synchronized int lastIndexOf(Object element, int startingIndex) { preCheck(); int result = thys().lastIndexOf(element, startingIndex); int n = result+1; if (result < 0) n = 0; for (int i = n; i <= startingIndex; ++i) assert(!thys().at(i).equals(element)); if (result != -1) { assert(thys().at(result).equals(element)); assert(result <= startingIndex); assert(result < thys.size()); } assert(thys.sameStructure(prev)); postCheck(); return result; } /** * Checks collections.Seq.lastIndexOf according to its specification * @see collections.Seq#lastIndexOf **/ public synchronized int lastIndexOf(Object element) { preCheck(); int result = thys().lastIndexOf(element); assert(result == thys().lastIndexOf(element, thys.size()-1)); assert(thys.sameStructure(prev)); postCheck(); return result; } /** * Checks collections.Seq.subseq according to its specification * @see collections.Seq#subseq **/ public synchronized Seq subseq(int index, int length) throws NoSuchElementException { preCheck(); Seq result = thys().subseq(index, length); if (length <= 0) assert(result.isEmpty()); else { assert(result.size() == length); for (int i = 0; i < length; ++i) { assert(result.at(i).equals(thys().at(i+index))); } } result.checkImplementation(); assert(thys.sameStructure(prev)); postCheck(); return result; } /** * Checks collections.UpdatableSeq.insertAt according to its specification * @see collections.UpdatableSeq#insertAt **/ public synchronized void insertAt(int index, Object element) throws IllegalElementException, NoSuchElementException { preCheck(); try { thys().insertAt(index, element); checkInsert(thys(), prev(), index, element, true); postCheck(); } catch (IllegalArgumentException ex) { assert(!thys.canInclude(element)); assert(thys.sameStructure(prev)); postCheck(); throw ex; } catch (NoSuchElementException ex) { assert(index < 0 || index >= thys.size()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.Seq.insertingAt. * @see collections.Seq#insertingAt **/ public synchronized Seq insertingAt(int index, Object element) throws IllegalElementException, NoSuchElementException { preCheck(); try { Seq nc = thys().insertingAt(index, element); checkInsert(nc, thys(), index, element, false); assert(thys.sameStructure(prev)); postCheck(); return nc; } catch (IllegalArgumentException ex) { assert(!thys.canInclude(element)); assert(thys.sameStructure(prev)); postCheck(); throw ex; } catch (NoSuchElementException ex) { assert(index < 0 || index >= thys.size()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.UpdatableSeq.replaceAt according to its specification * @see collections.UpdatableSeq#replaceAt **/ public synchronized void replaceAt(int index, Object element) throws IllegalElementException, NoSuchElementException { preCheck(); try { thys().replaceAt(index, element); checkReplaceAt(thys(), prev(), index, element, true); postCheck(); } catch (IllegalArgumentException ex) { assert(!thys.canInclude(element)); assert(thys.sameStructure(prev)); postCheck(); throw ex; } catch (NoSuchElementException ex) { assert(index < 0 || index >= thys.size()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.Seq.replacingAt * @see collections.Seq#replacingAt **/ public synchronized Seq replacingAt(int index, Object element) throws IllegalElementException, NoSuchElementException { preCheck(); try { Seq nc = thys().replacingAt(index, element); checkReplaceAt(nc, thys(), index, element, false); assert(thys.sameStructure(prev)); postCheck(); return nc; } catch (IllegalArgumentException ex) { assert(!thys.canInclude(element)); assert(thys.sameStructure(prev)); postCheck(); throw ex; } catch (NoSuchElementException ex) { assert(index < 0 || index >= thys.size()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.UpdatableSeq.removeAt according to its specification * @see collections.UpdatableSeq#removeAt **/ public synchronized void removeAt(int index) throws NoSuchElementException { preCheck(); try { thys().removeAt(index); checkRemoveAt(thys(), prev(), index, true); postCheck(); } catch (NoSuchElementException ex) { assert(index < 0 || index >= thys.size()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.Seq.removingAt. * @see collections.Seq#removingAt **/ public synchronized Seq removingAt(int index) throws NoSuchElementException { preCheck(); try { Seq nc = thys().removingAt(index); checkRemoveAt(nc, thys(), index, false); assert(thys.sameStructure(prev)); postCheck(); return nc; } catch (NoSuchElementException ex) { assert(index < 0 || index >= thys.size()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.UpdatableSeq.insertFirst according to its specification * @see collections.UpdatableSeq#insertFirst **/ public synchronized void insertFirst(Object element) throws IllegalElementException { preCheck(); IllegalElementException e = null; // make sure the two calls throw the same exceptions try { prev().insertAt(0, element); } catch (IllegalElementException ex) { e = ex; } catch (NoSuchElementException ex) { assert(false); // should not occur! } try { thys().insertFirst(element); } catch (IllegalElementException ex) { assert(e != null); } assert(thys.sameStructure(prev)); postCheck(); if (e != null) throw e; } /** * Checks collections.UpdatableSeq.replaceFirst according to its specification * @see collections.UpdatableSeq#replaceFirst **/ public synchronized void replaceFirst(Object element) throws IllegalElementException, NoSuchElementException { preCheck(); IllegalElementException e1 = null; NoSuchElementException e2 = null; try { prev().replaceAt(0, element); } catch (IllegalElementException ex) { e1 = ex; } catch (NoSuchElementException ex) { e2 = ex; } try { thys().replaceFirst(element); } catch (IllegalElementException ex) { assert(e1 != null); } catch (NoSuchElementException ex) { assert(e2 != null); } assert(thys.sameStructure(prev)); postCheck(); if (e1 != null) throw e1; if (e2 != null) throw e2; } /** * Checks collections.UpdatableSeq.removeFirst according to its specification * @see collections.UpdatableSeq#removeFirst **/ public synchronized void removeFirst() throws NoSuchElementException { preCheck(); NoSuchElementException e = null; // make sure the two calls throw the same exceptions try { prev().removeAt(0); } catch (NoSuchElementException ex) { e = ex; } try { thys().removeFirst(); } catch (IllegalElementException ex) { assert(e != null); } assert(thys.sameStructure(prev)); postCheck(); if (e != null) throw e; } /** * Checks collections.UpdatableSeq.insertLast according to its specification * @see collections.UpdatableSeq#insertLast **/ public synchronized void insertLast(Object element) throws IllegalElementException { preCheck(); IllegalElementException e = null; // make sure the two calls throw the same exceptions try { prev().insertAt(thys.size(), element); } catch (IllegalElementException ex) { e = ex; } catch (NoSuchElementException ex) { assert(false); // should not occur } try { thys().insertLast(element); } catch (IllegalElementException ex) { assert(e != null); } assert(thys.sameStructure(prev)); postCheck(); if (e != null) throw e; } /** * Checks collections.UpdatableSeq.replaceLast according to its specification * @see collections.UpdatableSeq#replaceLast **/ public synchronized void replaceLast(Object element) throws IllegalElementException, NoSuchElementException { preCheck(); IllegalElementException e1 = null; NoSuchElementException e2 = null; try { prev().replaceAt(thys.size()-1, element); } catch (IllegalElementException ex) { e1 = ex; } catch (NoSuchElementException ex) { e2 = ex; } try { thys().replaceLast(element); } catch (IllegalElementException ex) { assert(e1 != null); } catch (NoSuchElementException ex) { assert(e2 != null); } assert(thys.sameStructure(prev)); postCheck(); if (e1 != null) throw e1; if (e2 != null) throw e2; } /** * Checks collections.UpdatableSeq.removeLast according to its specification * @see collections.UpdatableSeq#removeLast **/ public synchronized void removeLast() throws NoSuchElementException { preCheck(); NoSuchElementException e = null; // make sure the two calls throw the same exceptions try { prev().removeAt(thys.size()-1); } catch (NoSuchElementException ex) { e = ex; } try { thys().removeLast(); } catch (IllegalElementException ex) { assert(e != null); } assert(thys.sameStructure(prev)); postCheck(); if (e != null) throw e; } /** * Checks collections.UpdatableSeq.removeFromTo according to its specification * @see collections.UpdatableSeq#removeFromTo **/ public synchronized void removeFromTo(int fromIndex, int toIndex) throws NoSuchElementException { preCheck(); try { thys().removeFromTo(fromIndex, toIndex); int n = toIndex - fromIndex + 1; if (n < 0) n = 0; assert(thys.size() == prev.size() - n); assert(fromIndex >= 0 && fromIndex < prev.size()); assert(toIndex >= 0 && toIndex < prev.size()); assert(!((thys.version() == prevVersion) && n > 0)); for (int i = 0; i < fromIndex; ++i) { assert(thys().at(i).equals(prev().at(i))); } for (int i = fromIndex; i < thys.size(); ++i) { assert(thys().at(i).equals(prev().at(i+n))); } postCheck(); } catch (NoSuchElementException ex) { assert(fromIndex < 0 || fromIndex >= thys.size() || toIndex < 0 || toIndex >= thys.size()); assert(thys.sameStructure(prev)); postCheck(); throw ex; } } /** * Checks collections.UpdatableSeq.insertElementsAt according to its specification * @see collections.UpdatableSeq#insertElementsAt **/ public synchronized void insertElementsAt(int index, Enumeration e) throws IllegalElementException, CorruptedEnumerationException, NoSuchElementException { preCheck(); try { int n = -1; if (e instanceof CollectionEnumeration) n = ((CollectionEnumeration)e).numberOfRemainingElements(); thys().insertElementsAt(index, e); if (n < 0) n = thys.size() - prev.size(); // best we can do assert(thys.size() == prev.size() + n); assert(!e.hasMoreElements()); assert(index >= 0 && index < prev.size()); assert(!((thys.version() == prevVersion) && n > 0)); for (int i = 0; i < index; ++i) { assert(thys().at(i).equals(prev().at(i))); } // We cannot check the inserted elements themselves // since e has been exhausted. We can't even // first clone it since Enumerations don't claim to be // usefully clonable. for (int i = index + n; i < thys.size(); ++i) { assert(thys().at(i).equals(prev().at(i-n))); } postCheck(); } catch (CorruptedEnumerationException ex) { postCheck(); throw ex; } catch (NoSuchElementException ex) { assert(index < 0 || index >= thys.size()); assert(thys.sameStructure(prev)); throw ex; } catch (IllegalElementException ex) { postCheck(); throw ex; } } /** * Checks collections.UpdatableSeq.prependElements according to its specification * @see collections.UpdatableSeq#prependElements **/ public synchronized void prependElements(Enumeration e) throws IllegalElementException, CorruptedEnumerationException { // too hard to check via behavioral equivalence, so // we just adapt insertElementsAt code preCheck(); try { int n = -1; if (e instanceof CollectionEnumeration) n = ((CollectionEnumeration)e).numberOfRemainingElements(); thys().prependElements(e); if (n < 0) n = thys.size() - prev.size(); // best we can do thys().prependElements(e); assert(thys.size() == prev.size() + n); assert(!e.hasMoreElements()); assert(!((thys.version() == prevVersion) && n > 0)); for (int i = n; i < thys.size(); ++i) { assert(thys().at(i).equals(prev().at(i-n))); } postCheck(); } catch (IllegalElementException ex) { postCheck(); throw ex; } catch (CorruptedEnumerationException ex) { postCheck(); throw ex; } } /** * Checks collections.UpdatableSeq.appendElements according to its specification * @see collections.UpdatableSeq#appendElements **/ public synchronized void appendElements(Enumeration e) throws IllegalElementException, CorruptedEnumerationException { // As above, too hard to check via behavioral equivalence, so // we just adapt insertElementsAt code preCheck(); try { int n = -1; if (e instanceof CollectionEnumeration) n = ((CollectionEnumeration)e).numberOfRemainingElements(); thys().appendElements(e); if (n < 0) n = thys.size() - prev.size(); // best we can do assert(thys.size() == prev.size() + n); assert(!e.hasMoreElements()); assert(!((thys.version() == prevVersion) && n > 0)); for (int i = 0; i < prev.size(); ++i) { assert(thys().at(i).equals(prev().at(i))); } postCheck(); } catch (IllegalElementException ex) { postCheck(); throw ex; } catch (CorruptedEnumerationException ex) { postCheck(); throw ex; } } /** * Helper for checking insert* **/ protected void checkInsert(Seq nc, Seq oc, int index, Object element, boolean verchk) { assert(nc.canInclude(element)); assert(nc.size() == oc.size() + 1); assert(index >= 0 && index < nc.size()); assert(nc.at(index).equals(element)); for (int i = 0; i < index; ++i) { assert(nc.at(i).equals(oc.at(i))); } for (int i = index+1; i < thys.size(); ++i) { assert(nc.at(i).equals(oc.at(i-1))); } if (verchk) { int nv = ((UpdatableCollection)nc).version(); assert(nv != prevVersion); } nc.checkImplementation(); } /** * Helper for checking replac* **/ protected void checkReplaceAt(Seq nc, Seq oc, int index, Object element, boolean verchk) { assert(nc.canInclude(element)); assert(nc.size() == oc.size()); assert(index >= 0 && index < nc.size()); assert(nc.at(index).equals(element)); for (int i = 0; i < index; ++i) assert(nc.at(i).equals(oc.at(i))); for (int i = index+1; i < nc.size(); ++i) assert(nc.at(i).equals(oc.at(i))); if (verchk) { int nv = ((UpdatableCollection)nc).version(); assert(!((nv == prevVersion) && !nc.at(index).equals(oc.at(index)))); } nc.checkImplementation(); } /** * Helper for checking remov* **/ protected void checkRemoveAt(Seq nc, Seq oc, int index, boolean verchk) { assert(nc.size() == oc.size() - 1); assert(index >= 0 && index < oc.size()); for (int i = 0; i < index; ++i) { assert(nc.at(i).equals(oc.at(i))); } for (int i = index; i < nc.size(); ++i) { assert(nc.at(i).equals(oc.at(i+1))); } if (verchk) { int nv = ((UpdatableCollection)nc).version(); assert(nv != prevVersion); } nc.checkImplementation(); } }