001: /*
002: Copyright (c) 2000-2005, Dennis M. Sosnoski
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.runtime.impl;
030:
031: import java.lang.reflect.Array;
032:
033: /**
034: * Growable <code>String</code> array with type specific access methods. This
035: * implementation is unsynchronized in order to provide the best possible
036: * performance for typical usage scenarios, so explicit synchronization must
037: * be implemented by a wrapper class or directly by the application in cases
038: * where instances are modified in a multithreaded environment.
039: *
040: * @author Dennis M. Sosnoski
041: * @version 1.0
042: */
043: public class StringArray {
044: /** Default initial array size. */
045: public static final int DEFAULT_SIZE = 8;
046:
047: /** Size of the current array. */
048: private int m_countLimit;
049:
050: /** The number of values currently present in the array. */
051: private int m_countPresent;
052:
053: /** Maximum size increment for growing array. */
054: private int m_maximumGrowth;
055:
056: /** The underlying array used for storing the data. */
057: private String[] m_baseArray;
058:
059: /**
060: * Constructor with full specification.
061: *
062: * @param size number of <code>String</code> values initially allowed in
063: * array
064: * @param growth maximum size increment for growing array
065: */
066: public StringArray(int size, int growth) {
067: String[] array = new String[size];
068: m_countLimit = size;
069: m_maximumGrowth = growth;
070: m_baseArray = array;
071: }
072:
073: /**
074: * Constructor with initial size specified.
075: *
076: * @param size number of <code>String</code> values initially allowed in
077: * array
078: */
079: public StringArray(int size) {
080: this (size, Integer.MAX_VALUE);
081: }
082:
083: /**
084: * Default constructor.
085: */
086: public StringArray() {
087: this (DEFAULT_SIZE);
088: }
089:
090: /**
091: * Copy (clone) constructor.
092: *
093: * @param base instance being copied
094: */
095: public StringArray(StringArray base) {
096: this (base.m_countLimit, base.m_maximumGrowth);
097: System.arraycopy(base.m_baseArray, 0, m_baseArray, 0,
098: base.m_countPresent);
099: m_countPresent = base.m_countPresent;
100: }
101:
102: /**
103: * Copy data after array resize. This just copies the entire contents of the
104: * old array to the start of the new array. It should be overridden in cases
105: * where data needs to be rearranged in the array after a resize.
106: *
107: * @param base original array containing data
108: * @param grown resized array for data
109: */
110: private void resizeCopy(Object base, Object grown) {
111: System.arraycopy(base, 0, grown, 0, Array.getLength(base));
112: }
113:
114: /**
115: * Discards values for a range of indices in the array. Clears references to
116: * removed values.
117: *
118: * @param from index of first value to be discarded
119: * @param to index past last value to be discarded
120: */
121: private void discardValues(int from, int to) {
122: for (int i = from; i < to; i++) {
123: m_baseArray[i] = null;
124: }
125: }
126:
127: /**
128: * Increase the size of the array to at least a specified size. The array
129: * will normally be at least doubled in size, but if a maximum size
130: * increment was specified in the constructor and the value is less than
131: * the current size of the array, the maximum increment will be used
132: * instead. If the requested size requires more than the default growth,
133: * the requested size overrides the normal growth and determines the size
134: * of the replacement array.
135: *
136: * @param required new minimum size required
137: */
138: private void growArray(int required) {
139: int size = Math.max(required, m_countLimit
140: + Math.min(m_countLimit, m_maximumGrowth));
141: String[] grown = new String[size];
142: resizeCopy(m_baseArray, grown);
143: m_countLimit = size;
144: m_baseArray = grown;
145: }
146:
147: /**
148: * Ensure that the array has the capacity for at least the specified
149: * number of values.
150: *
151: * @param min minimum capacity to be guaranteed
152: */
153: public final void ensureCapacity(int min) {
154: if (min > m_countLimit) {
155: growArray(min);
156: }
157: }
158:
159: /**
160: * Add a value at the end of the array.
161: *
162: * @param value value to be added
163: */
164: public void add(String value) {
165: int index = getAddIndex();
166: m_baseArray[index] = value;
167: }
168:
169: /**
170: * Remove some number of values from the end of the array.
171: *
172: * @param count number of values to be removed
173: * @exception ArrayIndexOutOfBoundsException on attempt to remove more than
174: * the count present
175: */
176: public void remove(int count) {
177: int start = m_countPresent - count;
178: if (start >= 0) {
179: discardValues(start, m_countPresent);
180: m_countPresent = start;
181: } else {
182: throw new ArrayIndexOutOfBoundsException(
183: "Attempt to remove too many values from array");
184: }
185: }
186:
187: /**
188: * Get a value from the array.
189: *
190: * @param index index of value to be returned
191: * @return value from stack
192: * @exception ArrayIndexOutOfBoundsException on attempt to access outside
193: * valid range
194: */
195: public String get(int index) {
196: if (m_countPresent > index) {
197: return m_baseArray[index];
198: } else {
199: throw new ArrayIndexOutOfBoundsException(
200: "Attempt to access past end of array");
201: }
202: }
203:
204: /**
205: * Constructs and returns a simple array containing the same data as held
206: * in this array.
207: *
208: * @return array containing a copy of the data
209: */
210: public String[] toArray() {
211: String[] copy = new String[m_countPresent];
212: System.arraycopy(m_baseArray, 0, copy, 0, m_countPresent);
213: return copy;
214: }
215:
216: /**
217: * Duplicates the object with the generic call.
218: *
219: * @return a copy of the object
220: */
221: public Object clone() {
222: return new StringArray(this );
223: }
224:
225: /**
226: * Gets the array offset for appending a value to those in the array. If the
227: * underlying array is full, it is grown by the appropriate size increment
228: * so that the index value returned is always valid for the array in use by
229: * the time of the return.
230: *
231: * @return index position for added element
232: */
233: private int getAddIndex() {
234: int index = m_countPresent++;
235: if (m_countPresent > m_countLimit) {
236: growArray(m_countPresent);
237: }
238: return index;
239: }
240:
241: /**
242: * Get the number of values currently present in the array.
243: *
244: * @return count of values present
245: */
246: public int size() {
247: return m_countPresent;
248: }
249:
250: /**
251: * Check if array is empty.
252: *
253: * @return <code>true</code> if array empty, <code>false</code> if not
254: */
255: public boolean isEmpty() {
256: return m_countPresent == 0;
257: }
258:
259: /**
260: * Set the array to the empty state.
261: */
262: public void clear() {
263: discardValues(0, m_countPresent);
264: m_countPresent = 0;
265: }
266: }
|