View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections.primitives;
18  
19  import java.util.ConcurrentModificationException;
20  import java.util.NoSuchElementException;
21  
22  /**
23   * Abstract base class for {@link CharList}s backed 
24   * by random access structures like arrays.
25   * <p />
26   * Read-only subclasses must override {@link #get}
27   * and {@link #size}.  Mutable subclasses
28   * should also override {@link #set}.  Variably-sized
29   * subclasses should also override {@link #add(char)} 
30   * and {@link #removeElementAt}.  All other methods
31   * have at least some base implementation derived from 
32   * these.  Subclasses may choose to override these methods
33   * to provide a more efficient implementation.
34   * 
35   * @since Commons Primitives 1.0
36   * @version $Revision: 480460 $ $Date: 2006-11-29 03:14:21 -0500 (Wed, 29 Nov 2006) $
37   * 
38   * @author Rodney Waldhoff 
39   */
40  public abstract class RandomAccessCharList extends AbstractCharCollection implements CharList {
41  
42      // constructors
43      //-------------------------------------------------------------------------
44  
45      /** Constructs an empty list. */
46      protected RandomAccessCharList() { 
47      }    
48  
49      // fully abstract methods
50      //-------------------------------------------------------------------------
51      
52      public abstract char get(int index);
53      public abstract int size();
54  
55      // unsupported in base
56      //-------------------------------------------------------------------------
57      
58      /** 
59       * Unsupported in this implementation. 
60       * @throws UnsupportedOperationException since this method is not supported
61       */
62      public char removeElementAt(int index) {
63          throw new UnsupportedOperationException();
64      }
65      
66      /** 
67       * Unsupported in this implementation. 
68       * @throws UnsupportedOperationException since this method is not supported
69       */
70      public char set(int index, char element) {
71          throw new UnsupportedOperationException();
72      }
73          
74      /** 
75       * Unsupported in this implementation. 
76       * @throws UnsupportedOperationException since this method is not supported
77       */
78      public void add(int index, char element) {
79          throw new UnsupportedOperationException();
80      }
81  
82      //-------------------------------------------------------------------------
83  
84      // javadocs here are inherited
85      
86      public boolean add(char element) {
87          add(size(),element);
88          return true;
89      }
90  
91      public boolean addAll(int index, CharCollection collection) {
92          boolean modified = false;
93          for(CharIterator iter = collection.iterator(); iter.hasNext(); ) {
94              add(index++,iter.next());
95              modified = true;
96          }
97          return modified;
98      }
99  
100     public int indexOf(char element) {
101         int i = 0;
102         for(CharIterator iter = iterator(); iter.hasNext(); ) {
103             if(iter.next() == element) { 
104                 return i;
105             } else {
106                 i++;
107             }
108         }
109         return -1;
110     }
111 
112     public int lastIndexOf(char element) {
113         for(CharListIterator iter = listIterator(size()); iter.hasPrevious(); ) {
114             if(iter.previous() == element) {
115                 return iter.nextIndex();
116             }
117         }
118         return -1;
119     }
120 
121     public CharIterator iterator() {
122         return listIterator();
123     }
124 
125     public CharListIterator listIterator() {
126         return listIterator(0);
127     }
128 
129     public CharListIterator listIterator(int index) {
130         return new RandomAccessCharListIterator(this,index);            
131     }
132 
133     public CharList subList(int fromIndex, int toIndex) {
134         return new RandomAccessCharSubList(this,fromIndex,toIndex);
135     }
136 
137     public boolean equals(Object that) {
138         if(this == that) { 
139             return true; 
140         } else if(that instanceof CharList) {
141             CharList thatList = (CharList)that;
142             if(size() != thatList.size()) {
143                 return false;
144             }
145             for(CharIterator thatIter = thatList.iterator(), thisIter = iterator(); thisIter.hasNext();) {
146                 if(thisIter.next() != thatIter.next()) { 
147                     return false; 
148                 }
149             }
150             return true;
151         } else {
152             return false;
153         }        
154     }
155     
156     public int hashCode() {
157         int hash = 1;
158         for(CharIterator iter = iterator(); iter.hasNext(); ) {
159             hash = 31*hash + iter.next();
160         }
161         return hash;
162     }
163     
164     public String toString() {
165         // could cache these like StringBuffer does
166         return new String(toArray());
167     }
168     
169     // protected utilities
170     //-------------------------------------------------------------------------
171     
172     /** Get my count of structural modifications. */
173     protected int getModCount() {
174         return _modCount;
175     }
176 
177     /** Increment my count of structural modifications. */
178     protected void incrModCount() {
179         _modCount++;
180     }
181 
182     // attributes
183     //-------------------------------------------------------------------------
184     
185     private int _modCount = 0;
186 
187     // inner classes
188     //-------------------------------------------------------------------------
189     
190     private static class ComodChecker {
191         ComodChecker(RandomAccessCharList source) {
192             _source = source;  
193             resyncModCount();             
194         }
195         
196         protected RandomAccessCharList getList() {
197             return _source;
198         }
199         
200         protected void assertNotComodified() throws ConcurrentModificationException {
201             if(_expectedModCount != getList().getModCount()) {
202                 throw new ConcurrentModificationException();
203             }
204         }
205             
206         protected void resyncModCount() {
207             _expectedModCount = getList().getModCount();
208         }
209         
210         private RandomAccessCharList _source = null;
211         private int _expectedModCount = -1;
212     }
213     
214     protected static class RandomAccessCharListIterator extends ComodChecker implements CharListIterator {
215         RandomAccessCharListIterator(RandomAccessCharList list, int index) {
216             super(list);
217             if(index < 0 || index > getList().size()) {
218                 throw new IndexOutOfBoundsException("Index " + index + " not in [0," + getList().size() + ")");
219             } else {
220                 _nextIndex = index;
221                 resyncModCount();
222             }
223         }
224             
225         public boolean hasNext() {
226             assertNotComodified();
227             return _nextIndex < getList().size();
228         }
229         
230         public boolean hasPrevious() {
231             assertNotComodified();
232             return _nextIndex > 0;
233         }
234         
235         public int nextIndex() {
236             assertNotComodified();
237             return _nextIndex;
238         }
239         
240         public int previousIndex() {
241             assertNotComodified();
242             return _nextIndex - 1;
243         }
244         
245         public char next() {
246             assertNotComodified();
247             if(!hasNext()) {
248                 throw new NoSuchElementException();
249             } else {
250                 char val = getList().get(_nextIndex);
251                 _lastReturnedIndex = _nextIndex;
252                 _nextIndex++;
253                 return val;
254             }
255         }
256         
257         public char previous() {
258             assertNotComodified();
259             if(!hasPrevious()) {
260                 throw new NoSuchElementException();
261             } else {
262                 char val = getList().get(_nextIndex-1);
263                 _lastReturnedIndex = _nextIndex-1;
264                 _nextIndex--;
265                 return val;
266             }
267         }
268         
269         public void add(char value) {
270             assertNotComodified();
271             getList().add(_nextIndex,value);
272             _nextIndex++;
273             _lastReturnedIndex = -1;
274             resyncModCount();
275         }
276     
277         public void remove() {
278             assertNotComodified();
279             if (_lastReturnedIndex == -1) {
280                 throw new IllegalStateException();
281             }
282             if (_lastReturnedIndex == _nextIndex) {
283                 // remove() following previous()
284                 getList().removeElementAt(_lastReturnedIndex);
285             } else {
286                 // remove() following next()
287                 getList().removeElementAt(_lastReturnedIndex);
288                 _nextIndex--;
289             }
290             _lastReturnedIndex = -1;
291             resyncModCount();
292         }
293         
294         public void set(char value) {
295             assertNotComodified();
296             if(-1 == _lastReturnedIndex) {
297                 throw new IllegalStateException();
298             } else {
299                 getList().set(_lastReturnedIndex,value);
300                 resyncModCount();
301             }
302         }
303         
304         private int _nextIndex = 0;
305         private int _lastReturnedIndex = -1;        
306     }   
307 
308     protected static class RandomAccessCharSubList extends RandomAccessCharList implements CharList {
309         RandomAccessCharSubList(RandomAccessCharList list, int fromIndex, int toIndex) {
310             if(fromIndex < 0 || toIndex > list.size()) {
311                 throw new IndexOutOfBoundsException();
312             } else if(fromIndex > toIndex) {
313                 throw new IllegalArgumentException();                
314             } else {
315                 _list = list;
316                 _offset = fromIndex;
317                 _limit = toIndex - fromIndex;
318                 _comod = new ComodChecker(list);
319                 _comod.resyncModCount();
320             }            
321         }
322     
323         public char get(int index) {
324             checkRange(index);
325             _comod.assertNotComodified();
326             return _list.get(toUnderlyingIndex(index));
327         }
328     
329         public char removeElementAt(int index) {
330             checkRange(index);
331             _comod.assertNotComodified();
332             char val = _list.removeElementAt(toUnderlyingIndex(index));
333             _limit--;
334             _comod.resyncModCount();
335             incrModCount();
336             return val;
337         }
338     
339         public char set(int index, char element) {
340             checkRange(index);
341             _comod.assertNotComodified();
342             char val = _list.set(toUnderlyingIndex(index),element);
343             incrModCount();
344             _comod.resyncModCount();
345             return val;
346         }
347     
348         public void add(int index, char element) {
349             checkRangeIncludingEndpoint(index);
350             _comod.assertNotComodified();
351              _list.add(toUnderlyingIndex(index),element);
352             _limit++;
353             _comod.resyncModCount();
354             incrModCount();
355         }
356     
357         public int size() {
358             _comod.assertNotComodified();
359             return _limit;
360         }
361     
362         private void checkRange(int index) {
363             if(index < 0 || index >= size()) {
364                 throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + ")");
365             }
366         }
367           
368         private void checkRangeIncludingEndpoint(int index) {
369             if(index < 0 || index > size()) {
370                 throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + "]");
371             }
372         }
373           
374         private int toUnderlyingIndex(int index) {
375             return (index + _offset);
376         }
377         
378         private int _offset = 0;        
379         private int _limit = 0; 
380         private RandomAccessCharList _list = null;
381         private ComodChecker _comod = null;
382     
383     }
384 }
385