001: /*
002: * Copyright 2005-2006 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.collections.list;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Collections;
021: import java.util.List;
022:
023: /**
024: * Decorates another <code>List</code> to make it seamlessly grow when
025: * indices larger than the list size are used on add and set,
026: * avoiding most IndexOutOfBoundsExceptions.
027: * <p>
028: * This class avoids errors by growing when a set or add method would
029: * normally throw an IndexOutOfBoundsException.
030: * Note that IndexOutOfBoundsException IS returned for invalid negative indices.
031: * <p>
032: * Trying to set or add to an index larger than the size will cause the list
033: * to grow (using <code>null</code> elements). Clearly, care must be taken
034: * not to use excessively large indices, as the internal list will grow to
035: * match.
036: * <p>
037: * Trying to use any method other than add or set with an invalid index will
038: * call the underlying list and probably result in an IndexOutOfBoundsException.
039: * <p>
040: * Take care when using this list with <code>null</code> values, as
041: * <code>null</code> is the value added when growing the list.
042: * <p>
043: * All sub-lists will access the underlying list directly, and will throw
044: * IndexOutOfBoundsExceptions.
045: * <p>
046: * This class differs from {@link LazyList} because here growth occurs on
047: * set and add, where <code>LazyList</code> grows on get. However, they
048: * can be used together by decorating twice.
049: *
050: * @see LazyList
051: * @since Commons Collections 3.2
052: * @version $Revision: 155406 $ $Date: 2006-05-12 23:57:03 +0100 (Fri, 12 May 2006) $
053: *
054: * @author Stephen Colebourne
055: * @author Paul Legato
056: */
057: public class GrowthList extends AbstractSerializableListDecorator {
058:
059: /** Serialization version */
060: private static final long serialVersionUID = -3620001881672L;
061:
062: /**
063: * Factory method to create a growth list.
064: *
065: * @param list the list to decorate, must not be null
066: * @throws IllegalArgumentException if list is null
067: */
068: public static List decorate(List list) {
069: return new GrowthList(list);
070: }
071:
072: //-----------------------------------------------------------------------
073: /**
074: * Constructor that uses an ArrayList internally.
075: */
076: public GrowthList() {
077: super (new ArrayList());
078: }
079:
080: /**
081: * Constructor that uses an ArrayList internally.
082: *
083: * @param initialSize the initial size of the ArrayList
084: * @throws IllegalArgumentException if initial size is invalid
085: */
086: public GrowthList(int initialSize) {
087: super (new ArrayList(initialSize));
088: }
089:
090: /**
091: * Constructor that wraps (not copies).
092: *
093: * @param list the list to decorate, must not be null
094: * @throws IllegalArgumentException if list is null
095: */
096: protected GrowthList(List list) {
097: super (list);
098: }
099:
100: //-----------------------------------------------------------------------
101: /**
102: * Decorate the add method to perform the growth behaviour.
103: * <p>
104: * If the requested index is greater than the current size, the list will
105: * grow to the new size. Indices between the old size and the requested
106: * size will be filled with <code>null</code>.
107: * <p>
108: * If the index is less than the current size, the value will be added to
109: * the underlying list directly.
110: * If the index is less than zero, the underlying list is called, which
111: * will probably throw an IndexOutOfBoundsException.
112: *
113: * @param index the index to add at
114: * @param element the object to add at the specified index
115: * @throws UnsupportedOperationException if the underlying list doesn't implement set
116: * @throws ClassCastException if the underlying list rejects the element
117: * @throws IllegalArgumentException if the underlying list rejects the element
118: */
119: public void add(int index, Object element) {
120: int size = getList().size();
121: if (index > size) {
122: getList().addAll(Collections.nCopies(index - size, null));
123: }
124: getList().add(index, element);
125: }
126:
127: //-----------------------------------------------------------------------
128: /**
129: * Decorate the addAll method to perform the growth behaviour.
130: * <p>
131: * If the requested index is greater than the current size, the list will
132: * grow to the new size. Indices between the old size and the requested
133: * size will be filled with <code>null</code>.
134: * <p>
135: * If the index is less than the current size, the values will be added to
136: * the underlying list directly.
137: * If the index is less than zero, the underlying list is called, which
138: * will probably throw an IndexOutOfBoundsException.
139: *
140: * @param index the index to add at
141: * @param coll the collection to add at the specified index
142: * @return true if the list changed
143: * @throws UnsupportedOperationException if the underlying list doesn't implement set
144: * @throws ClassCastException if the underlying list rejects the element
145: * @throws IllegalArgumentException if the underlying list rejects the element
146: */
147: public boolean addAll(int index, Collection coll) {
148: int size = getList().size();
149: boolean result = false;
150: if (index > size) {
151: getList().addAll(Collections.nCopies(index - size, null));
152: result = true;
153: }
154: return (getList().addAll(index, coll) | result);
155: }
156:
157: //-----------------------------------------------------------------------
158: /**
159: * Decorate the set method to perform the growth behaviour.
160: * <p>
161: * If the requested index is greater than the current size, the list will
162: * grow to the new size. Indices between the old size and the requested
163: * size will be filled with <code>null</code>.
164: * <p>
165: * If the index is less than the current size, the value will be set onto
166: * the underlying list directly.
167: * If the index is less than zero, the underlying list is called, which
168: * will probably throw an IndexOutOfBoundsException.
169: *
170: * @param index the index to set
171: * @param element the object to set at the specified index
172: * @return the object previously at that index
173: * @throws UnsupportedOperationException if the underlying list doesn't implement set
174: * @throws ClassCastException if the underlying list rejects the element
175: * @throws IllegalArgumentException if the underlying list rejects the element
176: */
177: public Object set(int index, Object element) {
178: int size = getList().size();
179: if (index >= size) {
180: getList().addAll(
181: Collections.nCopies((index - size) + 1, null));
182: }
183: return getList().set(index, element);
184: }
185:
186: }
|