Coverage Report - org.as3collections.iterators.ListIterator
 
Classes in this File Line Coverage Branch Coverage Complexity
ListIterator
100%
47/47
N/A
0
 
 1  
 /*
 2  
  * Licensed under the MIT License
 3  
  * 
 4  
  * Copyright 2010 (c) Flávio Silva, http://flsilva.com
 5  
  *
 6  
  * Permission is hereby granted, free of charge, to any person
 7  
  * obtaining a copy of this software and associated documentation
 8  
  * files (the "Software"), to deal in the Software without
 9  
  * restriction, including without limitation the rights to use,
 10  
  * copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  
  * copies of the Software, and to permit persons to whom the
 12  
  * Software is furnished to do so, subject to the following
 13  
  * conditions:
 14  
  *
 15  
  * The above copyright notice and this permission notice shall be
 16  
  * included in all copies or substantial portions of the Software.
 17  
  *
 18  
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 19  
  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 20  
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 21  
  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 22  
  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 23  
  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 24  
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 25  
  * OTHER DEALINGS IN THE SOFTWARE.
 26  
  * 
 27  
  * http://www.opensource.org/licenses/mit-license.php
 28  
  */
 29  
 
 30  1
 package org.as3collections.iterators 
 31  
 {
 32  
         import org.as3collections.IList;
 33  
         import org.as3collections.IListIterator;
 34  
         import org.as3collections.errors.ConcurrentModificationError;
 35  
         import org.as3collections.errors.IndexOutOfBoundsError;
 36  
         import org.as3collections.errors.NoSuchElementError;
 37  
         import org.as3coreaddendum.errors.IllegalStateError;
 38  
 
 39  
         /**
 40  
          * An iterator to iterate over lists (implementations of the <code>IList</code> interface).
 41  
          * <code>ListIterator</code> allows to traverse the list in either direction.
 42  
          * <p><b>IMPORTANT:</b></p>
 43  
          * <p>A <code>ListIterator</code> has no current element; its cursor position always lies between the element that would be returned by a call to <code>previous()</code> and the element that would be returned by a call to <code>next()</code>.
 44  
          * An iterator for a list of length <code>n</code> has <code>n+1</code> possible cursor positions, as illustrated by the carets (^) below:</p>
 45  
          * <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 46  
          * Element(0)&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 47  
          * Element(1)&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 48  
          * Element(2)&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 49  
          * ... Element(n-1)</p>
 50  
          * <p>cursor positions:
 51  
          * &#160;&#160;&#160;
 52  
          * ^&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 53  
          * ^&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 54  
          * ^&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 55  
          * ^&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;
 56  
          * ^</p>
 57  
          * <p>Note that the <code>remove()</code> and <code>set()</code> methods are <em>not</em> defined in terms of the cursor position; they are defined to operate on the last element returned by a call to <code>next()</code> or <code>previous()</code>.</p>
 58  
          * <p>For further information do not hesitate to see the examples at the end of the page.</p>
 59  
          * <p>This documentation is partially based in the <em>Java Collections Framework</em> JavaDoc documentation.
 60  
          * For further information see <a href="http://download.oracle.com/javase/6/docs/technotes/guides/collections/index.html" target="_blank">Java Collections Framework</a></p>
 61  
          * 
 62  
          * @example
 63  
          * 
 64  
          * <b>Example 1</b>
 65  
          * 
 66  
          * <listing version="3.0">
 67  
          * import org.as3collections.IList;
 68  
          * import org.as3collections.IListIterator;
 69  
          * import org.as3collections.lists.ArrayList;
 70  
          * 
 71  
          * var list1:IList = new ArrayList([1, 3, 5]);
 72  
          * 
 73  
          * list1                             // [1,3,5]
 74  
          * 
 75  
          * var it:IListIterator = list1.listIterator();
 76  
          * var e:int;
 77  
          * 
 78  
          * while (it.hasNext())
 79  
          * {
 80  
          * 
 81  
          *     ITERATION N.1
 82  
          * 
 83  
          *     it.pointer()                  // -1
 84  
          *     it.nextIndex()                // 0
 85  
          *     it.previousIndex()            // -1
 86  
          * 
 87  
          *     e = it.next();
 88  
          *     e                             // 1
 89  
          * 
 90  
          *     it.pointer()                  // 0
 91  
          *     it.nextIndex()                // 1
 92  
          *     it.previousIndex()            // 0
 93  
          * 
 94  
          *     ITERATION N.2
 95  
          * 
 96  
          *     it.pointer()                  // 0
 97  
          *     it.nextIndex()                // 1
 98  
          *     it.previousIndex()            // 0
 99  
          * 
 100  
          *     e = it.next();
 101  
          *     e                             // 3
 102  
          * 
 103  
          *     it.pointer()                  // 1
 104  
          *     it.nextIndex()                // 2
 105  
          *     it.previousIndex()            // 1
 106  
          * 
 107  
          *     if (e == 3)
 108  
          *     {
 109  
          *         //list1.add(4)            // ConcurrentModificationError: During the iteration, the list was changed directly (without use the iterator).
 110  
          *         it.add(4);
 111  
          *         list1                     // [1,3,4,5]
 112  
          *     }
 113  
          * 
 114  
          *     ITERATION N.3
 115  
          * 
 116  
          *     it.pointer()                  // 2
 117  
          *     it.nextIndex()                // 3
 118  
          *     it.previousIndex()            // 2
 119  
          * 
 120  
          *     e = it.next();
 121  
          *     e                             // 5
 122  
          * 
 123  
          *     it.pointer()                  // 3
 124  
          *     it.nextIndex()                // 4
 125  
          *     it.previousIndex()            // 3
 126  
          * 
 127  
          *     if (e == 5)
 128  
          *     {
 129  
          *         it.remove();
 130  
          *         list1                     // [1,3,4]
 131  
          *     }
 132  
          * }
 133  
          * </listing>
 134  
          * 
 135  
          * <b>Example 2</b>
 136  
          * 
 137  
          * <listing version="3.0">
 138  
          * import org.as3collections.IList;
 139  
          * import org.as3collections.IListIterator;
 140  
          * import org.as3collections.lists.ArrayList;
 141  
          * 
 142  
          * var list1:IList = new ArrayList([1, 3, 5]);
 143  
          * 
 144  
          * list1                             // [1,3,5]
 145  
          * 
 146  
          * var it:IListIterator = list1.listIterator(list1.size());
 147  
          * var e:int;
 148  
          * 
 149  
          * while (it.hasPrevious())
 150  
          * 
 151  
          * {
 152  
          * 
 153  
          *     ITERATION N.1
 154  
          * 
 155  
          *     it.pointer()                  // 2
 156  
          *     it.nextIndex()                // 3
 157  
          *     it.previousIndex()            // 2
 158  
          * 
 159  
          *     e = it.previous();
 160  
          *     e                             // 5
 161  
          * 
 162  
          *     it.pointer()                  // 1
 163  
          *     it.nextIndex()                // 2
 164  
          *     it.previousIndex()            // 1
 165  
          * 
 166  
          *     if (e == 5)
 167  
          *     {
 168  
          *         it.remove()
 169  
          *         list1                     // [1,3]
 170  
          *     }
 171  
          * 
 172  
          *     ITERATION N.2
 173  
          * 
 174  
          *     it.pointer()                  // 1
 175  
          *     it.nextIndex()                // 2
 176  
          *     it.previousIndex()            // 1
 177  
          * 
 178  
          *     e = it.previous();
 179  
          *     e                             // 3
 180  
          * 
 181  
          *     it.pointer()                  // 0
 182  
          *     it.nextIndex()                // 1
 183  
          *     it.previousIndex()            // 0
 184  
          * 
 185  
          *     if (e == 3)
 186  
          *     {
 187  
          *         //list1.add(4)            // ConcurrentModificationError: During the iteration, the list was changed directly (without use the iterator).
 188  
          *         it.add(4);
 189  
          *         list1                     // [1,4,3]
 190  
          *     }
 191  
          * 
 192  
          *     ITERATION N.3
 193  
          * 
 194  
          *     it.pointer()                  // 1
 195  
          *     it.nextIndex()                // 2
 196  
          *     it.previousIndex()            // 1
 197  
          * 
 198  
          *     e = it.previous();
 199  
          *     e                             // 4
 200  
          * 
 201  
          *     it.pointer()                  // 0
 202  
          *     it.nextIndex()                // 1
 203  
          *     it.previousIndex()            // 0
 204  
          * 
 205  
          *     ITERATION N.4
 206  
          * 
 207  
          *     it.pointer()                  // 0
 208  
          *     it.nextIndex()                // 1
 209  
          *     it.previousIndex()            // 0
 210  
          * 
 211  
          *     e = it.previous();
 212  
          *     e                             // 1
 213  
          * 
 214  
          *     it.pointer()                  // -1
 215  
          *     it.nextIndex()                // 0
 216  
          *     it.previousIndex()            // -1
 217  
          * }
 218  
          * </listing>
 219  
          * 
 220  
          * @author Flávio Silva
 221  
          */
 222  
         public class ListIterator implements IListIterator
 223  
         {
 224  
                 private var _allowModification: Boolean;
 225  
                 private var _modCount: int;
 226  
                 private var _pointer: int = -1;
 227  
                 private var _removePointer: int;
 228  
                 private var _source: IList;
 229  
 
 230  
                 /**
 231  
                  * Constructor, creates a new <code>ListIterator</code> object.
 232  
                  * 
 233  
                  * @param          source                 the source <code>ListIterator</code> to iterate over.
 234  
                  * @param          position         indicates the first element that would be returned by an initial call to <code>next</code>. An initial call to <code>previous</code> would return the element with the specified position minus one. 
 235  
                  * @throws         ArgumentError  if the <code>source</code> argument is <code>null</code>.
 236  
                  */
 237  
                 public function ListIterator(source:IList, position:int = 0)
 238  1
                 {
 239  1
                         if (!source) throw new ArgumentError("The 'source' argument must not be 'null'.");
 240  1
                         if (position < 0 || position > source.size()) throw new IndexOutOfBoundsError("The 'position' argument is out of bounds: " + position + " (min: 0, max: " + source.size() + ")"); 
 241  
                         
 242  1
                         _source = source;
 243  1
                         _modCount = _source.modCount;
 244  1
                         _pointer += position;
 245  1
                 }
 246  
 
 247  
                 /**
 248  
                  * @inheritDoc
 249  
                  * @throws         org.as3collections.errors.ConcurrentModificationError         if the list was changed directly (without using the iterator) during iteration.
 250  
                  */
 251  
                 public function add(element:*): Boolean
 252  
                 {
 253  1
                         checkConcurrentModificationError();
 254  
                         
 255  1
                         var added:Boolean = _source.addAt(_pointer + 1, element);
 256  
                         
 257  1
                         if (_modCount != _source.modCount) _pointer++;
 258  1
                         _modCount = _source.modCount;
 259  1
                         _allowModification = false;
 260  
                         
 261  1
                         return added;
 262  
                 }
 263  
 
 264  
                 /**
 265  
                  * @inheritDoc
 266  
                  */
 267  
                 public function hasNext(): Boolean
 268  
                 {
 269  1
                         return _pointer < _source.size() - 1;
 270  
                 }
 271  
 
 272  
                 /**
 273  
                  * @inheritDoc
 274  
                  */
 275  
                 public function hasPrevious(): Boolean
 276  
                 {
 277  1
                         return _pointer >= 0;
 278  
                 }
 279  
 
 280  
                 /**
 281  
                  * @inheritDoc
 282  
                  * @throws         org.as3collections.errors.NoSuchElementError         if the iteration has no more elements.
 283  
                  * @throws         org.as3collections.errors.ConcurrentModificationError         if the list was changed directly (without using the iterator) during iteration.
 284  
                  */
 285  
                 public function next(): *
 286  
                 {
 287  1
                         if (!hasNext()) throw new NoSuchElementError("Iterator has no next element. Call hasNext() method before.");
 288  
                         
 289  1
                         checkConcurrentModificationError();
 290  1
                         _allowModification = true;
 291  1
                         _pointer++;
 292  1
                         _removePointer = _pointer;
 293  1
                         return _source.getAt(_pointer);
 294  
                 }
 295  
 
 296  
                 /**
 297  
                  * @inheritDoc
 298  
                  */
 299  
                 public function nextIndex(): int
 300  
                 {
 301  1
                         return _pointer + 1;
 302  
                 }
 303  
 
 304  
                 /**
 305  
                  * Returns the internal pointer of the iteration.
 306  
                  * <p>In this implementation the pointer is the index (position) of the iteration, typically an <code>int</code>.</p>
 307  
                  * 
 308  
                  * @return         the internal pointer of the iteration.
 309  
                   */
 310  
                 public function pointer(): *
 311  
                 {
 312  1
                         return _pointer;
 313  
                 }
 314  
 
 315  
                 /**
 316  
                  * @inheritDoc
 317  
                  * @throws         org.as3collections.errors.NoSuchElementError         if the iteration has no previous elements.
 318  
                  * @throws         org.as3collections.errors.ConcurrentModificationError         if the list was changed directly (without using the iterator) during iteration.
 319  
                  */
 320  
                 public function previous(): *
 321  
                 {
 322  1
                         if (!hasPrevious()) throw new NoSuchElementError("Iterator has no previous element. Call hasPrevious() method before.");
 323  
                         
 324  1
                         checkConcurrentModificationError();
 325  1
                         _allowModification = true;
 326  1
                         _removePointer = _pointer;
 327  1
                         return _source.getAt(_pointer--);
 328  
                 }
 329  
 
 330  
                 /**
 331  
                  * @inheritDoc
 332  
                  */
 333  
                 public function previousIndex(): int
 334  
                 {
 335  1
                         return _pointer;
 336  
                 }
 337  
 
 338  
                 /**
 339  
                  * Removes from the list the last element that was returned by <code>next</code> or <code>previous</code>. This call can only be made once per call to <code>next</code> or <code>previous</code>. It can be made only if <code>IListIterator.add</code> has not been called after the last call to <code>next</code> or <code>previous</code>. 
 340  
                  * 
 341  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>remove</code> operation is not supported by this iterator.
 342  
                  * @throws         org.as3coreaddendum.errors.IllegalStateError                          if the <code>next</code> method has not yet been called, or the <code>remove</code> method has already been called after the last call to the <code>next</code> method.
 343  
                  * @throws         org.as3collections.errors.ConcurrentModificationError         if the list was changed directly (without using the iterator) during iteration.
 344  
                  */
 345  
                 public function remove(): void
 346  
                 {
 347  1
                         checkConcurrentModificationError();
 348  
                         
 349  1
                         if (!_allowModification) throw new IllegalStateError("The next or previous method has not yet been called or the add or remove method has already been called after the last call to the next or previous method.");
 350  
                         
 351  1
                         _source.removeAt(_removePointer);
 352  1
                         _modCount = _source.modCount;
 353  1
                         _allowModification = false;
 354  1
                         if (_removePointer == _pointer) _pointer--;
 355  1
                 }
 356  
 
 357  
                 /**
 358  
                  * @inheritDoc
 359  
                  */
 360  
                 public function reset(): void
 361  
                 {
 362  1
                         _pointer = -1;
 363  1
                 }
 364  
 
 365  
                 /**
 366  
                  * Replaces the last element returned by <code>next</code> or <code>previous</code> with the specified element (optional operation). This call can be made only if neither <code>IListIterator.remove</code> nor <code>IListIterator.add</code> have been called after the last call to <code>next</code> or <code>previous</code>. 
 367  
                  * 
 368  
                  * @param element         the element with which to replace the last element returned by <code>next</code> or <code>previous</code>.
 369  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>set</code> operation is not supported by this iterator.
 370  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the class of the specified element prevents it from being added to this list.
 371  
                  * @throws         org.as3coreaddendum.errors.IllegalStateError                          if neither <code>next</code> or <code>previous</code> have been called, or <code>remove</code> or <code>add</code> have been called after the last call to <code>next</code> or <code>previous</code>.
 372  
                  */
 373  
                 public function set(element:*): void
 374  
                 {
 375  1
                         checkConcurrentModificationError();
 376  
                         
 377  1
                         if (!_allowModification) throw new IllegalStateError("The next or previous method has not yet been called or the add or remove method has already been called after the last call to the next or previous method.");
 378  
                         
 379  1
                         var setIndex:int = (_removePointer > _pointer) ? _pointer + 1 : _pointer;
 380  
                         
 381  1
                         _source.setAt(setIndex, element);
 382  1
                         _modCount = _source.modCount;
 383  1
                 }
 384  
 
 385  
                 /**
 386  
                  * @private
 387  
                  */
 388  
                 public function checkConcurrentModificationError(): void
 389  
                 {
 390  1
                         if (_modCount != _source.modCount) throw new ConcurrentModificationError("During the iteration, the list was changed directly (without use the iterator).");
 391  1
                 }
 392  
 
 393  
         }
 394  
 
 395  
 }