Author: desruisseaux Date: Tue Nov 6 17:29:02 2012 New Revision: 1406235 URL: http://svn.apache.org/viewvc?rev=1406235&view=rev Log: Ported UnmodifiableArrayList, which will be needed for TreeTable default implementation (and in lot of other places to come).
Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java (with props) Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/LineFormatter.java sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/LineFormatter.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/LineFormatter.java?rev=1406235&r1=1406234&r2=1406235&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/LineFormatter.java (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/LineFormatter.java Tue Nov 6 17:29:02 2012 @@ -305,6 +305,22 @@ public class LineFormatter extends Filte } /** + * Writes pending non-white characters, discards trailing whitespaces, and resets column + * position to zero. This method does <strong>not</strong> write the line separator and + * does not modify the status of the {@link #skipLF} flag; those tasks are caller's + * responsibility. + */ + private void endOfLine() throws IOException { + buffer.setLength(printableLength); // Reduce the amount of work for StringBuilder.deleteCharAt(int). + deleteSoftHyphen(); + transfer(printableLength); + printableLength = 0; + codePointCount = 0; + isEscapeSequence = false; // Handle line-breaks as "end of escape sequence". + isNewLine = true; + } + + /** * Removes the soft hyphen characters from the given buffer. This is invoked * when the buffer is about to be written without being split on two lines. */ @@ -355,13 +371,7 @@ public class LineFormatter extends Filte default: skip = false; skipLF = false; break; } if (!skip) { - buffer.setLength(printableLength); // Reduce the amount of work for StringBuilder.deleteCharAt(int). - deleteSoftHyphen(); - transfer(printableLength); - printableLength = 0; - codePointCount = 0; - isEscapeSequence = false; // Handle line-breaks as "end of escape sequence". - isNewLine = true; + endOfLine(); } if (!isEndOfLineReplaced) { appendCodePoint(c); // Forward EOL sequences "as-is". @@ -516,15 +526,29 @@ searchHyp: for (int i=buffer.length(); } /** - * Sends pending characters to the underlying stream. Note that this method should - * preferably be invoked at the end of a word, sentence or line, since invoking it - * may prevent {@code LineFormatter} to properly wrap the current line if it is - * in the middle of a word. - * - * <p>Invoking this method also flushes the {@linkplain #out underlying stream}. - * A cheaper way to send pending characters is to make sure that the last character - * is a {@linkplain org.apache.sis.util.Characters#isLineOrParagraphSeparator(int) - * line or paragraph terminator}.</p> + * Resets the {@code LineFormatter} internal state as if a new line was beginning. + * Trailing whitespaces not yet sent to the {@linkplain #out underlying appendable} + * are discarded, and the column position (for tabulation expansion calculation) is + * reset to 0. This method does not write any line separator. + * + * @throws IOException If an error occurred while sending the trailing non-white + * characters to the underlying stream. + */ + public void clear() throws IOException { + endOfLine(); + skipLF = false; + } + + /** + * Sends all pending characters to the {@linkplain #out underlying appendable}, including + * trailing whitespaces. Note that this method should preferably be invoked at the end of + * a word, sentence or line, since invoking this method may prevent {@code LineFormatter} + * to properly wrap the current line if the current position is in the middle of a word. + * + * <p>Invoking this method also flushes the underlying stream, if {@linkplain Flushable flushable}. + * A cheaper way to send pending characters is to make sure that the last character is a + * {@linkplain Characters#isLineOrParagraphSeparator(int) line or paragraph terminator}, + * or to invoke {@link #clear()}.</p> * * @throws IOException If an I/O error occurs. */ Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java?rev=1406235&r1=1406234&r2=1406235&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java Tue Nov 6 17:29:02 2012 @@ -73,6 +73,8 @@ import static org.apache.sis.util.Charac * @since 0.3 (derived from geotk-1.0) * @version 0.3 * @module + * + * @see org.apache.sis.util.tree.TreeTableFormat */ @Decorator(Appendable.class) public class TableFormatter extends FilteredAppendable implements Flushable { Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java?rev=1406235&view=auto ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java (added) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java Tue Nov 6 17:29:02 2012 @@ -0,0 +1,334 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.util.collection; + +import java.io.Serializable; +import java.util.AbstractList; +import org.apache.sis.util.ArgumentChecks; + +// Related to JDK7 +import java.util.Objects; + + +/** + * An unmodifiable view of an array. Invoking + * + * {@preformat java + * List<?> list = UnmodifiableArrayList.wrap(array); + * } + * + * is equivalent to + * + * {@preformat java + * List<?> list = Collections.unmodifiableList(Arrays.asList(array)); + * } + * + * except that this class uses one less level of indirection. Despite that advantage being minor, + * this class is defined because extensively used in the SIS library. + * + * @param <E> The type of elements in the list. + * + * @author Martin Desruisseaux (IRD) + * @since 0.3 (derived from geotk-2.1) + * @version 0.3 + * @module + */ +public class UnmodifiableArrayList<E> extends AbstractList<E> implements CheckedContainer<E>, Serializable { + /** + * For compatibility with different versions. + */ + private static final long serialVersionUID = -3605810209653785967L; + + /** + * The wrapped array. + */ + private final E[] array; + + /** + * Creates a new instance wrapping the given array. A direct reference to the given array is + * retained (i.e. the array is <strong>not</strong> cloned). Consequently the given array + * shall not be modified after construction if this list is intended to be immutable. + * + * <p>This constructor is for sub-classing only. Users should invoke the {@link #wrap(E[])} + * static method instead.</p> + * + * @param array The array to wrap. + */ + @SafeVarargs + protected UnmodifiableArrayList(final E... array) { + ArgumentChecks.ensureNonNull("array", array); + this.array = array; + } + + /** + * Creates a new instance wrapping the given array. A direct reference to the given array is + * retained (i.e. the array is <strong>not</strong> cloned). Consequently the given array + * shall not be modified after construction if the returned list is intended to be immutable. + * + * @param <E> The type of elements in the list. + * @param array The array to wrap, or {@code null} if none. + * @return The given array wrapped in an unmodifiable list, or {@code null} if the given + * array was null. + */ + @SafeVarargs + public static <E> UnmodifiableArrayList<E> wrap(final E... array) { + return (array != null) ? new UnmodifiableArrayList<>(array) : null; + } + + /** + * Creates a new instance wrapping a subregion of the given array. A direct reference to the + * given array is retained (i.e. the array is <strong>not</strong> cloned). Consequently the + * specified sub-region of the given array shall not be modified after construction if the + * returned list is intended to be immutable. + * + * @param <E> The type of elements in the list. + * @param array The array to wrap. + * @param lower Low endpoint (inclusive) of the sublist. + * @param upper High endpoint (exclusive) of the sublist. + * @return The given array wrapped in an unmodifiable list. + * @throws IndexOutOfBoundsException If the lower or upper value are out of bounds. + */ + public static <E> UnmodifiableArrayList<E> wrap(final E[] array, final int lower, final int upper) + throws IndexOutOfBoundsException + { + ArgumentChecks.ensureNonNull("array", array); + ArgumentChecks.ensureValidIndexRange(array.length, lower, upper); + if (lower == 0 && upper == array.length) { + return new UnmodifiableArrayList<>(array); + } + return new UnmodifiableArrayList.SubList<>(array, lower, upper - lower); + } + + /** + * Returns the element type of the wrapped array. The default implementation returns + * <code>array.getClass().{@linkplain Class#getComponentType() getComponentType()}</code>. + * + * @return The type of elements in the list. + */ + @Override + @SuppressWarnings("unchecked") // Safe if this instance was created safely with wrap(E[]). + public Class<E> getElementType() { + return (Class<E>) array.getClass().getComponentType(); + } + + /** + * Returns the index of the first valid element. + * To be overridden by {@link SubList} only. + */ + int lower() { + return 0; + } + + /** + * Returns the list size. + */ + @Override + public int size() { + return array.length; + } + + /** + * Returns the element at the specified index. + */ + @Override + public E get(final int index) { + return array[index]; + } + + /** + * Returns the index in this list of the first occurrence of the specified element, + * or -1 if the list does not contain the element. + * + * @param object The element to search for. + * @return The index of the first occurrence of the given object, or {@code -1}. + */ + @Override + public int indexOf(final Object object) { + final int lower = lower(); + final int upper = lower + size(); + if (object == null) { + for (int i=lower; i<upper; i++) { + if (array[i] == null) { + return i - lower; + } + } + } else { + for (int i=lower; i<upper; i++) { + if (object.equals(array[i])) { + return i - lower; + } + } + } + return -1; + } + + /** + * Returns the index in this list of the last occurrence of the specified element, + * or -1 if the list does not contain the element. + * + * @param object The element to search for. + * @return The index of the last occurrence of the given object, or {@code -1}. + */ + @Override + public int lastIndexOf(final Object object) { + final int lower = lower(); + int i = lower + size(); + if (object == null) { + while (--i >= lower) { + if (array[i] == null) { + break; + } + } + } else { + while (--i >= lower) { + if (object.equals(array[i])) { + break; + } + } + } + return i - lower; + } + + /** + * Returns {@code true} if this list contains the specified element. + * + * @param object The element to check for existence. + * @return {@code true} if this collection contains the given element. + */ + @Override + public boolean contains(final Object object) { + final int lower = lower(); + int i = lower + size(); + if (object == null) { + while (--i >= lower) { + if (array[i] == null) { + return true; + } + } + } else { + while (--i >= lower) { + if (object.equals(array[i])) { + return true; + } + } + } + return false; + } + + /** + * Returns a view of the portion of this list between the specified + * {@code lower}, inclusive, and {@code upper}, exclusive. + * + * @param lower Low endpoint (inclusive) of the sublist. + * @param upper High endpoint (exclusive) of the sublist. + * @return A view of the specified range within this list. + * @throws IndexOutOfBoundsException If the lower or upper value are out of bounds. + * + * @see #wrap(E[], int, int) + */ + @Override + public UnmodifiableArrayList<E> subList(final int lower, final int upper) + throws IndexOutOfBoundsException + { + ArgumentChecks.ensureValidIndexRange(size(), lower, upper); + return new SubList<>(array, lower + lower(), upper - lower); + } + + /** + * A view over a portion of {@link UnmodifiableArrayList}. + * + * @param <E> The type of elements in the list. + * + * @author Martin Desruisseaux (Geomatys) + * @since 0.3 (derived from geotk-3.00) + * @version 0.3 + * @module + */ + private static final class SubList<E> extends UnmodifiableArrayList<E> { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = -6297280390649627532L; + + /** + * Index of the first element and size of this list. + */ + private final int lower, size; + + /** + * Creates a new sublist. + */ + SubList(final E[] array, final int lower, final int size) { + super(array); + this.lower = lower; + this.size = size; + } + + /** + * Returns the index of the first element. + */ + @Override + int lower() { + return lower; + } + + /** + * Returns the size of this list. + */ + @Override + public int size() { + return size; + } + + /** + * Returns the element at the given index. + */ + @Override + public E get(final int index) { + ArgumentChecks.ensureValidIndex(size, index); + return super.get(index + lower); + } + } + + /** + * Compares this list with the given object for equality. + * + * @param object The object to compare with this list. + * @return {@code true} if the given object is equal to this list. + */ + @Override + public boolean equals(final Object object) { + if (object != this) { + if (!(object instanceof UnmodifiableArrayList<?>)) { + return super.equals(object); + } + final UnmodifiableArrayList<?> that = (UnmodifiableArrayList<?>) object; + int size = this.size(); + if (size != that.size()) { + return false; + } + int i = this.lower(); + int j = that.lower(); + while (--size >= 0) { + if (!Objects.equals(this.array[i++], that.array[j++])) { + return false; + } + } + } + return true; + } +} Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/UnmodifiableArrayList.java ------------------------------------------------------------------------------ svn:mime-type = text/plain