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 ByteList}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(byte)} 
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 RandomAccessByteList extends AbstractByteCollection implements ByteList {
41  
42      // constructors
43      //-------------------------------------------------------------------------
44  
45      /** Constructs an empty list. */
46      protected RandomAccessByteList() { 
47      }    
48  
49      // fully abstract methods
50      //-------------------------------------------------------------------------
51      
52      public abstract byte 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 byte 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 byte set(int index, byte 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, byte element) {
79          throw new UnsupportedOperationException();
80      }
81  
82      //-------------------------------------------------------------------------
83  
84      // javadocs here are inherited
85      
86      public boolean add(byte element) {
87          add(size(),element);
88          return true;
89      }
90  
91      public boolean addAll(int index, ByteCollection collection) {
92          boolean modified = false;
93          for(ByteIterator iter = collection.iterator(); iter.hasNext(); ) {
94              add(index++,iter.next());
95              modified = true;
96          }
97          return modified;
98      }
99  
100     public int indexOf(byte element) {
101         int i = 0;
102         for(ByteIterator 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(byte element) {
113         for(ByteListIterator iter = listIterator(size()); iter.hasPrevious(); ) {
114             if(iter.previous() == element) {
115                 return iter.nextIndex();
116             }
117         }
118         return -1;
119     }
120 
121     public ByteIterator iterator() {
122         return listIterator();
123     }
124 
125     public ByteListIterator listIterator() {
126         return listIterator(0);
127     }
128 
129     public ByteListIterator listIterator(int index) {
130         return new RandomAccessByteListIterator(this,index);            
131     }
132 
133     public ByteList subList(int fromIndex, int toIndex) {
134         return new RandomAccessByteSubList(this,fromIndex,toIndex);
135     }
136 
137     public boolean equals(Object that) {
138         if(this == that) { 
139             return true; 
140         } else if(that instanceof ByteList) {
141             ByteList thatList = (ByteList)that;
142             if(size() != thatList.size()) {
143                 return false;
144             }
145             for(ByteIterator 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(ByteIterator iter = iterator(); iter.hasNext(); ) {
159             hash = 31*hash + iter.next();
160         }
161         return hash;
162     }
163     
164     public String toString() {
165         StringBuffer buf = new StringBuffer();
166         buf.append("[");
167         for(ByteIterator iter = iterator(); iter.hasNext();) {
168             buf.append(iter.next());
169             if(iter.hasNext()) {
170                 buf.append(", ");
171             }
172         }
173         buf.append("]");
174         return buf.toString();
175     }
176     
177     // protected utilities
178     //-------------------------------------------------------------------------
179     
180     /** Get my count of structural modifications. */
181     protected int getModCount() {
182         return _modCount;
183     }
184 
185     /** Increment my count of structural modifications. */
186     protected void incrModCount() {
187         _modCount++;
188     }
189 
190     // attributes
191     //-------------------------------------------------------------------------
192     
193     private int _modCount = 0;
194 
195     // inner classes
196     //-------------------------------------------------------------------------
197     
198     private static class ComodChecker {
199         ComodChecker(RandomAccessByteList source) {
200             _source = source;  
201             resyncModCount();             
202         }
203         
204         protected RandomAccessByteList getList() {
205             return _source;
206         }
207         
208         protected void assertNotComodified() throws ConcurrentModificationException {
209             if(_expectedModCount != getList().getModCount()) {
210                 throw new ConcurrentModificationException();
211             }
212         }
213             
214         protected void resyncModCount() {
215             _expectedModCount = getList().getModCount();
216         }
217         
218         private RandomAccessByteList _source = null;
219         private int _expectedModCount = -1;
220     }
221     
222     protected static class RandomAccessByteListIterator extends ComodChecker implements ByteListIterator {
223         RandomAccessByteListIterator(RandomAccessByteList list, int index) {
224             super(list);
225             if(index < 0 || index > getList().size()) {
226                 throw new IndexOutOfBoundsException("Index " + index + " not in [0," + getList().size() + ")");
227             } else {
228                 _nextIndex = index;
229                 resyncModCount();
230             }
231         }
232             
233         public boolean hasNext() {
234             assertNotComodified();
235             return _nextIndex < getList().size();
236         }
237         
238         public boolean hasPrevious() {
239             assertNotComodified();
240             return _nextIndex > 0;
241         }
242         
243         public int nextIndex() {
244             assertNotComodified();
245             return _nextIndex;
246         }
247         
248         public int previousIndex() {
249             assertNotComodified();
250             return _nextIndex - 1;
251         }
252         
253         public byte next() {
254             assertNotComodified();
255             if(!hasNext()) {
256                 throw new NoSuchElementException();
257             } else {
258                 byte val = getList().get(_nextIndex);
259                 _lastReturnedIndex = _nextIndex;
260                 _nextIndex++;
261                 return val;
262             }
263         }
264         
265         public byte previous() {
266             assertNotComodified();
267             if(!hasPrevious()) {
268                 throw new NoSuchElementException();
269             } else {
270                 byte val = getList().get(_nextIndex-1);
271                 _lastReturnedIndex = _nextIndex-1;
272                 _nextIndex--;
273                 return val;
274             }
275         }
276         
277         public void add(byte value) {
278             assertNotComodified();
279             getList().add(_nextIndex,value);
280             _nextIndex++;
281             _lastReturnedIndex = -1;
282             resyncModCount();
283         }
284     
285         public void remove() {
286             assertNotComodified();
287             if (_lastReturnedIndex == -1) {
288                 throw new IllegalStateException();
289             }
290             if (_lastReturnedIndex == _nextIndex) {
291                 // remove() following previous()
292                 getList().removeElementAt(_lastReturnedIndex);
293             } else {
294                 // remove() following next()
295                 getList().removeElementAt(_lastReturnedIndex);
296                 _nextIndex--;
297             }
298             _lastReturnedIndex = -1;
299             resyncModCount();
300         }
301         
302         public void set(byte value) {
303             assertNotComodified();
304             if(-1 == _lastReturnedIndex) {
305                 throw new IllegalStateException();
306             } else {
307                 getList().set(_lastReturnedIndex,value);
308                 resyncModCount();
309             }
310         }
311         
312         private int _nextIndex = 0;
313         private int _lastReturnedIndex = -1;        
314     }   
315 
316     protected static class RandomAccessByteSubList extends RandomAccessByteList implements ByteList {
317         RandomAccessByteSubList(RandomAccessByteList list, int fromIndex, int toIndex) {
318             if(fromIndex < 0 || toIndex > list.size()) {
319                 throw new IndexOutOfBoundsException();
320             } else if(fromIndex > toIndex) {
321                 throw new IllegalArgumentException();                
322             } else {
323                 _list = list;
324                 _offset = fromIndex;
325                 _limit = toIndex - fromIndex;
326                 _comod = new ComodChecker(list);
327                 _comod.resyncModCount();
328             }            
329         }
330     
331         public byte get(int index) {
332             checkRange(index);
333             _comod.assertNotComodified();
334             return _list.get(toUnderlyingIndex(index));
335         }
336     
337         public byte removeElementAt(int index) {
338             checkRange(index);
339             _comod.assertNotComodified();
340             byte val = _list.removeElementAt(toUnderlyingIndex(index));
341             _limit--;
342             _comod.resyncModCount();
343             incrModCount();
344             return val;
345         }
346     
347         public byte set(int index, byte element) {
348             checkRange(index);
349             _comod.assertNotComodified();
350             byte val = _list.set(toUnderlyingIndex(index),element);
351             incrModCount();
352             _comod.resyncModCount();
353             return val;
354         }
355     
356         public void add(int index, byte element) {
357             checkRangeIncludingEndpoint(index);
358             _comod.assertNotComodified();
359              _list.add(toUnderlyingIndex(index),element);
360             _limit++;
361             _comod.resyncModCount();
362             incrModCount();
363         }
364     
365         public int size() {
366             _comod.assertNotComodified();
367             return _limit;
368         }
369     
370         private void checkRange(int index) {
371             if(index < 0 || index >= size()) {
372                 throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + ")");
373             }
374         }
375           
376         private void checkRangeIncludingEndpoint(int index) {
377             if(index < 0 || index > size()) {
378                 throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + "]");
379             }
380         }
381           
382         private int toUnderlyingIndex(int index) {
383             return (index + _offset);
384         }
385         
386         private int _offset = 0;        
387         private int _limit = 0; 
388         private RandomAccessByteList _list = null;
389         private ComodChecker _comod = null;
390     
391     }
392 }
393