001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.collections.primitives;
018    
019    import java.util.ConcurrentModificationException;
020    import java.util.NoSuchElementException;
021    
022    /**
023     * Abstract base class for {@link DoubleList}s backed 
024     * by random access structures like arrays.
025     * <p />
026     * Read-only subclasses must override {@link #get}
027     * and {@link #size}.  Mutable subclasses
028     * should also override {@link #set}.  Variably-sized
029     * subclasses should also override {@link #add(double)} 
030     * and {@link #removeElementAt}.  All other methods
031     * have at least some base implementation derived from 
032     * these.  Subclasses may choose to override these methods
033     * to provide a more efficient implementation.
034     * 
035     * @since Commons Primitives 1.0
036     * @version $Revision: 480460 $ $Date: 2006-11-29 09:14:21 +0100 (Wed, 29 Nov 2006) $
037     * 
038     * @author Rodney Waldhoff 
039     */
040    public abstract class RandomAccessDoubleList extends AbstractDoubleCollection implements DoubleList {
041    
042        // constructors
043        //-------------------------------------------------------------------------
044    
045        /** Constructs an empty list. */
046        protected RandomAccessDoubleList() { 
047        }    
048    
049        // fully abstract methods
050        //-------------------------------------------------------------------------
051        
052        public abstract double get(int index);
053        public abstract int size();
054    
055        // unsupported in base
056        //-------------------------------------------------------------------------
057        
058        /** 
059         * Unsupported in this implementation. 
060         * @throws UnsupportedOperationException since this method is not supported
061         */
062        public double removeElementAt(int index) {
063            throw new UnsupportedOperationException();
064        }
065        
066        /** 
067         * Unsupported in this implementation. 
068         * @throws UnsupportedOperationException since this method is not supported
069         */
070        public double set(int index, double element) {
071            throw new UnsupportedOperationException();
072        }
073            
074        /** 
075         * Unsupported in this implementation. 
076         * @throws UnsupportedOperationException since this method is not supported
077         */
078        public void add(int index, double element) {
079            throw new UnsupportedOperationException();
080        }
081    
082        //-------------------------------------------------------------------------
083    
084        // javadocs here are inherited
085        
086        public boolean add(double element) {
087            add(size(),element);
088            return true;
089        }
090    
091        public boolean addAll(int index, DoubleCollection collection) {
092            boolean modified = false;
093            for(DoubleIterator iter = collection.iterator(); iter.hasNext(); ) {
094                add(index++,iter.next());
095                modified = true;
096            }
097            return modified;
098        }
099    
100        public int indexOf(double element) {
101            int i = 0;
102            for(DoubleIterator 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(double element) {
113            for(DoubleListIterator iter = listIterator(size()); iter.hasPrevious(); ) {
114                if(iter.previous() == element) {
115                    return iter.nextIndex();
116                }
117            }
118            return -1;
119        }
120    
121        public DoubleIterator iterator() {
122            return listIterator();
123        }
124    
125        public DoubleListIterator listIterator() {
126            return listIterator(0);
127        }
128    
129        public DoubleListIterator listIterator(int index) {
130            return new RandomAccessDoubleListIterator(this,index);            
131        }
132    
133        public DoubleList subList(int fromIndex, int toIndex) {
134            return new RandomAccessDoubleSubList(this,fromIndex,toIndex);
135        }
136    
137        public boolean equals(Object that) {
138            if(this == that) { 
139                return true; 
140            } else if(that instanceof DoubleList) {
141                DoubleList thatList = (DoubleList)that;
142                if(size() != thatList.size()) {
143                    return false;
144                }
145                for(DoubleIterator 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(DoubleIterator iter = iterator(); iter.hasNext(); ) {
159                long bits = Double.doubleToLongBits(iter.next());
160                hash = 31*hash + ((int)(bits ^ (bits >>> 32)));
161            }
162            return hash;
163        }
164        
165        public String toString() {
166            StringBuffer buf = new StringBuffer();
167            buf.append("[");
168            for(DoubleIterator iter = iterator(); iter.hasNext();) {
169                buf.append(iter.next());
170                if(iter.hasNext()) {
171                    buf.append(", ");
172                }
173            }
174            buf.append("]");
175            return buf.toString();
176        }
177        
178        // protected utilities
179        //-------------------------------------------------------------------------
180        
181        /** Get my count of structural modifications. */
182        protected int getModCount() {
183            return _modCount;
184        }
185    
186        /** Increment my count of structural modifications. */
187        protected void incrModCount() {
188            _modCount++;
189        }
190    
191        // attributes
192        //-------------------------------------------------------------------------
193        
194        private int _modCount = 0;
195    
196        // inner classes
197        //-------------------------------------------------------------------------
198        
199        private static class ComodChecker {
200            ComodChecker(RandomAccessDoubleList source) {
201                _source = source;  
202                resyncModCount();             
203            }
204            
205            protected RandomAccessDoubleList getList() {
206                return _source;
207            }
208            
209            protected void assertNotComodified() throws ConcurrentModificationException {
210                if(_expectedModCount != getList().getModCount()) {
211                    throw new ConcurrentModificationException();
212                }
213            }
214                
215            protected void resyncModCount() {
216                _expectedModCount = getList().getModCount();
217            }
218            
219            private RandomAccessDoubleList _source = null;
220            private int _expectedModCount = -1;
221        }
222        
223        protected static class RandomAccessDoubleListIterator extends ComodChecker implements DoubleListIterator {
224            RandomAccessDoubleListIterator(RandomAccessDoubleList list, int index) {
225                super(list);
226                if(index < 0 || index > getList().size()) {
227                    throw new IndexOutOfBoundsException("Index " + index + " not in [0," + getList().size() + ")");
228                } else {
229                    _nextIndex = index;
230                    resyncModCount();
231                }
232            }
233                
234            public boolean hasNext() {
235                assertNotComodified();
236                return _nextIndex < getList().size();
237            }
238            
239            public boolean hasPrevious() {
240                assertNotComodified();
241                return _nextIndex > 0;
242            }
243            
244            public int nextIndex() {
245                assertNotComodified();
246                return _nextIndex;
247            }
248            
249            public int previousIndex() {
250                assertNotComodified();
251                return _nextIndex - 1;
252            }
253            
254            public double next() {
255                assertNotComodified();
256                if(!hasNext()) {
257                    throw new NoSuchElementException();
258                } else {
259                    double val = getList().get(_nextIndex);
260                    _lastReturnedIndex = _nextIndex;
261                    _nextIndex++;
262                    return val;
263                }
264            }
265            
266            public double previous() {
267                assertNotComodified();
268                if(!hasPrevious()) {
269                    throw new NoSuchElementException();
270                } else {
271                    double val = getList().get(_nextIndex-1);
272                    _lastReturnedIndex = _nextIndex-1;
273                    _nextIndex--;
274                    return val;
275                }
276            }
277            
278            public void add(double value) {
279                assertNotComodified();
280                getList().add(_nextIndex,value);
281                _nextIndex++;
282                _lastReturnedIndex = -1;
283                resyncModCount();
284            }
285        
286            public void remove() {
287                assertNotComodified();
288                if (_lastReturnedIndex == -1) {
289                    throw new IllegalStateException();
290                }
291                if (_lastReturnedIndex == _nextIndex) {
292                    // remove() following previous()
293                    getList().removeElementAt(_lastReturnedIndex);
294                } else {
295                    // remove() following next()
296                    getList().removeElementAt(_lastReturnedIndex);
297                    _nextIndex--;
298                }
299                _lastReturnedIndex = -1;
300                resyncModCount();
301            }
302            
303            public void set(double value) {
304                assertNotComodified();
305                if(-1 == _lastReturnedIndex) {
306                    throw new IllegalStateException();
307                } else {
308                    getList().set(_lastReturnedIndex,value);
309                    resyncModCount();
310                }
311            }
312            
313            private int _nextIndex = 0;
314            private int _lastReturnedIndex = -1;        
315        }   
316    
317        protected static class RandomAccessDoubleSubList extends RandomAccessDoubleList implements DoubleList {
318            RandomAccessDoubleSubList(RandomAccessDoubleList list, int fromIndex, int toIndex) {
319                if(fromIndex < 0 || toIndex > list.size()) {
320                    throw new IndexOutOfBoundsException();
321                } else if(fromIndex > toIndex) {
322                    throw new IllegalArgumentException();                
323                } else {
324                    _list = list;
325                    _offset = fromIndex;
326                    _limit = toIndex - fromIndex;
327                    _comod = new ComodChecker(list);
328                    _comod.resyncModCount();
329                }            
330            }
331        
332            public double get(int index) {
333                checkRange(index);
334                _comod.assertNotComodified();
335                return _list.get(toUnderlyingIndex(index));
336            }
337        
338            public double removeElementAt(int index) {
339                checkRange(index);
340                _comod.assertNotComodified();
341                double val = _list.removeElementAt(toUnderlyingIndex(index));
342                _limit--;
343                _comod.resyncModCount();
344                incrModCount();
345                return val;
346            }
347        
348            public double set(int index, double element) {
349                checkRange(index);
350                _comod.assertNotComodified();
351                double val = _list.set(toUnderlyingIndex(index),element);
352                incrModCount();
353                _comod.resyncModCount();
354                return val;
355            }
356        
357            public void add(int index, double element) {
358                checkRangeIncludingEndpoint(index);
359                _comod.assertNotComodified();
360                 _list.add(toUnderlyingIndex(index),element);
361                _limit++;
362                _comod.resyncModCount();
363                incrModCount();
364            }
365        
366            public int size() {
367                _comod.assertNotComodified();
368                return _limit;
369            }
370        
371            private void checkRange(int index) {
372                if(index < 0 || index >= size()) {
373                    throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + ")");
374                }
375            }
376              
377            private void checkRangeIncludingEndpoint(int index) {
378                if(index < 0 || index > size()) {
379                    throw new IndexOutOfBoundsException("index " + index + " not in [0," + size() + "]");
380                }
381            }
382              
383            private int toUnderlyingIndex(int index) {
384                return (index + _offset);
385            }
386            
387            private int _offset = 0;        
388            private int _limit = 0; 
389            private RandomAccessDoubleList _list = null;
390            private ComodChecker _comod = null;
391        
392        }
393    }
394