Coverage Report - org.as3collections.AbstractList
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractList
100%
53/53
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
 31  
 {
 32  
         import org.as3collections.errors.IndexOutOfBoundsError;
 33  
         import org.as3collections.utils.CollectionUtil;
 34  
         import org.as3coreaddendum.errors.UnsupportedOperationError;
 35  
         import org.as3coreaddendum.system.IEquatable;
 36  
         import org.as3utils.ReflectionUtil;
 37  
 
 38  
         import flash.errors.IllegalOperationError;
 39  
 
 40  
         /**
 41  
          * This class provides a skeletal implementation of the <code>IList</code> interface, to minimize the effort required to implement this interface.
 42  
          * <p>This is an abstract class and shouldn't be instantiated directly.</p>
 43  
          * <p>The documentation for each non-abstract method in this class describes its implementation in detail.
 44  
          * Each of these methods may be overridden if the collection being implemented admits a more efficient implementation.</p>
 45  
          * <p>This documentation is partially based in the <em>Java Collections Framework</em> JavaDoc documentation.
 46  
          * 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> 
 47  
          * 
 48  
          * @see         org.as3collections.IList IList
 49  
          * @see         org.as3collections.lists.ArrayList ArrayList
 50  
          * @author Flávio Silva
 51  
          */
 52  
         public class AbstractList extends AbstractArrayCollection implements IList
 53  
         {
 54  
                 /**
 55  
                  * @private
 56  
                  */
 57  
                 protected var _modCount: int;
 58  
                 
 59  
                 /**
 60  
                  * @inheritDoc
 61  
                  */
 62  
                 public function get modCount(): int { return _modCount; }
 63  
                 
 64  
                 /**
 65  
                  * This is an abstract class and shouldn't be instantiated directly.
 66  
                  * 
 67  
                  * @param         source         an array to fill the list.
 68  
                  * @throws         IllegalOperationError         If this class is instantiated directly, in other words, if there is <b>not</b> another class extending this class.
 69  
                  */
 70  
                 public function AbstractList(source:Array = null)
 71  
                 {
 72  1
                         super(source);
 73  1
                         if (ReflectionUtil.classPathEquals(this, AbstractList)) throw new IllegalOperationError(ReflectionUtil.getClassName(this) + " is an abstract class and shouldn't be instantiated directly.");
 74  1
                 }
 75  
 
 76  
                 /**
 77  
                  * Appends the specified element to the end of this list (optional operation).
 78  
                  * <p>Lists that support this operation may place limitations on what elements may be added to this list.
 79  
                  * In particular, some lists will refuse to add <code>null</code> elements, and others will impose restrictions on the type of elements that may be added.
 80  
                  * Lists classes should clearly specify in their documentation any restrictions on what elements may be added.</p>
 81  
                  * <p>If a list refuses to add a particular element for any reason other than that it already contains the element, it <em>must</em> throw an error (rather than returning <code>false</code>).
 82  
                  * This preserves the invariant that a list always contains the specified element after this call returns.</p>
 83  
                  * <p>This implementation calls <code>addAt(size(), element)</code>.</p>
 84  
                  * <p>Note that this implementation throws an <code>UnsupportedOperationError</code> unless <code>addAt</code> is overridden.</p>
 85  
                  * 
 86  
                  * @param          element         the element to be added.
 87  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>add</code> operation is not supported by this list.
 88  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the class of the specified element prevents it from being added to this list.
 89  
                  * @throws         ArgumentError                           if the specified element is <code>null</code> and this list does not permit <code>null</code> elements.
 90  
                  * @return         <code>true</code> if this list changed as a result of the call. Returns <code>false</code> if this list does not permit duplicates and already contains the specified element.
 91  
                  */
 92  
                 override public function add(element:*): Boolean
 93  
                 {
 94  1
                         return addAt(size(), element);
 95  
                 }
 96  
 
 97  
                 /**
 98  
                  * Adds all of the elements in the specified collection to this list (optional operation).
 99  
                  * <p>This implementation calls <code>addAllAt(size(), collection)</code>.</p>
 100  
                  * <p>Note that this implementation will throw an <code>UnsupportedOperationError</code> unless <code>addAt</code> is overridden (assuming the specified collection is non-empty).</p>
 101  
                  * 
 102  
                  * @param          collection         the collection containing elements to be added to this list.
 103  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>addAll</code> operation is not supported by this list.
 104  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the class of an element of the specified collection prevents it from being added to this list.
 105  
                  * @throws         ArgumentError                                                                                           if the specified collection contains a <code>null</code> element and this list does not permit <code>null</code> elements, or if the specified collection is <code>null</code>.
 106  
                  * @return         <code>true</code> if this list changed as a result of the call.
 107  
                  */
 108  
                 override public function addAll(collection:ICollection): Boolean
 109  
                 {
 110  1
                         return addAllAt(size(), collection);
 111  
                 }
 112  
 
 113  
                 /**
 114  
                  * Inserts all of the elements in the specified collection into this list at the specified position (optional operation).
 115  
                  * Shifts the element currently at that position (if any) and any subsequent elements to the right (increases their indices).
 116  
                  * The new elements will appear in this list in the order that they are returned by the specified collection's iterator.
 117  
                  * <p>This implementation gets an iterator over the specified collection and iterates over it, inserting the elements obtained from the iterator into this list at the appropriate position, one at a time, using <code>addAt</code>.
 118  
                  * Other implementations can override this method for efficiency.</p>
 119  
                  * <p>Note that this implementation throws an <code>UnsupportedOperationError</code> unless <code>addAt</code> is overridden.</p>
 120  
                  * 
 121  
                  * @param          index                 index at which to insert the first element from the specified collection.
 122  
                  * @param          collection         the collection containing elements to be added to this list.
 123  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>addAllAt</code> operation is not supported by this list.
 124  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the class of an element of the specified collection prevents it from being added to this list.
 125  
                  * @throws         ArgumentError                           if the specified collection contains a <code>null</code> element and this list does not permit <code>null</code> elements, or if the specified collection is <code>null</code>. 
 126  
                  * @throws         org.as3collections.errors.IndexOutOfBoundsError                 if the index is out of range <code>(index &lt; 0 || index &gt; size())</code>.
 127  
                  * @return         <code>true</code> if this list changed as a result of the call.
 128  
                  */
 129  
                 public function addAllAt(index:int, collection:ICollection): Boolean
 130  
                 {
 131  1
                         if (!collection) throw new ArgumentError("The 'collection' argument must not be 'null'.");
 132  1
                         if (collection.isEmpty()) return false;
 133  1
                         checkIndex(index, size());
 134  
                         
 135  1
                         var prevSize:int = size();
 136  1
                         var it:IIterator = collection.iterator();
 137  
                         
 138  1
                         while (it.hasNext())
 139  
                         {
 140  1
                                 if (addAt(index, it.next())) index++;
 141  
                         }
 142  
                         
 143  1
                         return prevSize != size();
 144  
                 }
 145  
 
 146  
                 /**
 147  
                  * Inserts the specified element at the specified position in this list (optional operation).
 148  
                  * Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
 149  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 150  
                  * 
 151  
                  * @param          index                 index at which the specified element is to be inserted.
 152  
                  * @param          element         the element to be added.
 153  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>addAt</code> operation is not supported by this list.
 154  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the class of the specified element prevents it from being added to this list.
 155  
                  * @throws         ArgumentError                           if the specified element is <code>null</code> and this list does not permit <code>null</code> elements.
 156  
                  * @throws         org.as3collections.errors.IndexOutOfBoundsError                 if the index is out of range <code>(index &lt; 0 || index &gt; size())</code>. 
 157  
                  * @return         <code>true</code> if this list changed as a result of the call. Returns <code>false</code> if this list does not permit duplicates and already contains the specified element.
 158  
                  */
 159  
                 public function addAt(index:int, element:*): Boolean
 160  
                 {
 161  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 162  
                 }
 163  
 
 164  
                 /**
 165  
                  * This method uses <code>CollectionUtil.equalConsideringOrder</code> method to perform equality, sending this list and <code>other</code> argument.
 166  
                  * 
 167  
                  * @param          other         the object to be compared for equality.
 168  
                  * @return         <code>true</code> if the arbitrary evaluation considers the objects equal.
 169  
                  * @see         org.as3collections.utils.CollectionUtil#equalConsideringOrder() CollectionUtil.equalConsideringOrder()
 170  
                  */
 171  
                 override public function equals(other:*): Boolean
 172  
                 {
 173  1
                         return CollectionUtil.equalConsideringOrder(this, other);
 174  
                 }
 175  
 
 176  
                 /**
 177  
                  * @inheritDoc
 178  
                  * @throws         org.as3collections.errors.IndexOutOfBoundsError         if the index is out of range <code>(index &lt; 0 || index &gt;= size())</code>.
 179  
                  */
 180  
                 public function getAt(index:int): *
 181  
                 {
 182  1
                         if (isEmpty()) throw new IndexOutOfBoundsError("This list is empty.");
 183  
                         
 184  1
                         checkIndex(index, size() - 1);
 185  1
                         return data[index];
 186  
                 }
 187  
 
 188  
                 /**
 189  
                  * Returns the index of the <em>first occurrence</em> of the specified element in this list, or -1 if this list does not contain the element.
 190  
                  * <p>If all elements in this list and <code>element</code> argument implement <code>org.as3coreaddendum.system.IEquatable</code>, this implementation will iterate over this list using <code>equals</code> method of the elements.
 191  
                  * Otherwise this implementation uses native <code>Array.indexOf</code> method.</p>
 192  
                  * 
 193  
                  * @param         element         the element to search for.
 194  
                  * @param         fromIndex         the position in the list from which to start searching for the element.
 195  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the class of the specified element is incompatible with this list (optional).
 196  
                  * @throws         ArgumentError          if the specified element is <code>null</code> and this list does not permit <code>null</code> elements (optional).
 197  
                  * @return         the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element.
 198  
                  */
 199  
                 public function indexOf(element:*, fromIndex:int = 0): int
 200  
                 {
 201  1
                         if (allEquatable && element is IEquatable)
 202  
                         {
 203  1
                                 return indexOfByEquality(element, fromIndex);
 204  
                         }
 205  
                         else
 206  
                         {
 207  1
                                 return data.indexOf(element, fromIndex);
 208  
                         }
 209  
                 }
 210  
 
 211  
                 /**
 212  
                  * Returns the index of the <em>last occurrence</em> of the specified element in this list, or -1 if this list does not contain the element.
 213  
                  * <p>If all elements in this list and <code>element</code> argument implement <code>org.as3coreaddendum.system.IEquatable</code>, this implementation will iterate over this list using <code>equals</code> method of the elements.
 214  
                  * Otherwise this implementation uses native <code>Array.lastIndexOf</code> method.</p>
 215  
                  * 
 216  
                  * @param element                 the element to search for.
 217  
                  * @param fromIndex         the position in the list from which to start searching for the element. The default is the maximum value allowed for an index. If you do not specify <code>fromIndex</code>, the search starts at the last item in the list.
 218  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the class of the specified element is incompatible with this list (optional).
 219  
                  * @throws         ArgumentError          if the specified element is <code>null</code> and this list does not permit <code>null</code> elements (optional).
 220  
                  * @return         the index of the last occurrence of the specified element in this list, or -1 if this list does not contain the element.
 221  
                  */
 222  
                 public function lastIndexOf(element:*, fromIndex:int = 0x7fffffff): int
 223  
                 {
 224  1
                         if (allEquatable && element is IEquatable)
 225  
                         {
 226  1
                                 return lastIndexOfByEquality(element, fromIndex);
 227  
                         }
 228  
                         else
 229  
                         {
 230  1
                                 return data.lastIndexOf(element, fromIndex);
 231  
                         }
 232  
                 }
 233  
 
 234  
                 /**
 235  
                  * Returns a list iterator of the elements in this list (in proper sequence), starting at the specified position in this list.
 236  
                  * The specified index indicates the first element that would be returned by an initial call to <code>next</code>.
 237  
                  * An initial call to <code>previous</code> would return the element with the specified index minus one.
 238  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 239  
                  * 
 240  
                  * @param          index         index of first element to be returned from the list iterator (by a call to the <code>next</code> method) 
 241  
                  * @return         a list iterator of the elements in this list (in proper sequence), starting at the specified position in this list.
 242  
                  * @see         org.as3collections.IListIterator IListIterator
 243  
                  */
 244  
                 public function listIterator(index:int = 0): IListIterator
 245  
                 {
 246  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 247  
                 }
 248  
 
 249  
                 /**
 250  
                  * Removes the element at the specified position in this list (optional operation).
 251  
                  * Shifts any subsequent elements to the left (subtracts one from their indices).
 252  
                  * Returns the element that was removed from the list. 
 253  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 254  
                  * 
 255  
                  * @param          index         the index of the element to be removed.
 256  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>removeAt</code> operation is not supported by this list.
 257  
                  * @throws         org.as3collections.errors.IndexOutOfBoundsError                 if the index is out of range <code>(index &lt; 0 || index &gt;= size())</code>.
 258  
                  * @return         the element previously at the specified position.
 259  
                  */
 260  
                 public function removeAt(index:int): *
 261  
                 {
 262  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 263  
                 }
 264  
 
 265  
                 /**
 266  
                  * Removes all of the elements whose index is between <code>fromIndex</code>, inclusive, and <code>toIndex</code>, exclusive (optional operation).
 267  
                  * Shifts any subsequent elements to the left (subtracts their indices).
 268  
                  * <p>If <code>toIndex == fromIndex</code>, this operation has no effect.</p>
 269  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 270  
                  * 
 271  
                  * @param          fromIndex         the index to start removing elements (inclusive).
 272  
                  * @param          toIndex         the index to stop removing elements (exclusive).
 273  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>removeRange</code> operation is not supported by this list.
 274  
                  * @throws         org.as3collections.errors.IndexOutOfBoundsError                 if <code>fromIndex</code> or <code>toIndex</code> is out of range <code>(index &lt; 0 || index &gt; size())</code>.
 275  
                  * @return         a new collection containing all the removed elements.
 276  
                  */
 277  
                 public function removeRange(fromIndex:int, toIndex:int): ICollection
 278  
                 {
 279  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 280  
                 }
 281  
 
 282  
                 /**
 283  
                  * Reverses the order of the elements in this list.
 284  
                  * This implementation uses native <code>Array.reverse</code> method.
 285  
                  */
 286  
                 public function reverse(): void
 287  
                 {
 288  1
                         if (size() < 2) return;
 289  1
                         data.reverse();
 290  1
                 }
 291  
 
 292  
                 /**
 293  
                  * Replaces the element at the specified position in this list with the specified element (optional operation).
 294  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 295  
                  * 
 296  
                  * @param          index                 index of the element to replace.
 297  
                  * @param          element         element to be stored at the specified position.
 298  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>setAt</code> operation is not supported by this list.
 299  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the class of the specified element prevents it from being added to this list.
 300  
                  * @throws         ArgumentError                           if the specified element is <code>null</code> and this list does not permit <code>null</code> elements.
 301  
                  * @throws         org.as3collections.errors.IndexOutOfBoundsError                 if the index is out of range <code>(index &lt; 0 || index &gt;= size())</code>.
 302  
                  * @return         the element previously at the specified position.
 303  
                  */
 304  
                 public function setAt(index:int, element:*): *
 305  
                 {
 306  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 307  
                 }
 308  
 
 309  
                 /**
 310  
                  * Returns a new list that is a view of the portion of this list between the specified <code>fromIndex</code>, inclusive, and <code>toIndex</code>, exclusive.
 311  
                  * <p>This list should not be modified.</p>
 312  
                  * <p>The returned list should support all of the optional list operations supported by this list.</p>
 313  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 314  
                  * 
 315  
                  * @param          fromIndex         the index to start retrieving elements (inclusive).
 316  
                  * @param          toIndex         the index to stop retrieving elements (exclusive).
 317  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>subList</code> operation is not supported by this list.
 318  
                  * @throws         org.as3collections.errors.IndexOutOfBoundsError                 if <code>fromIndex</code> or <code>toIndex</code> is out of range <code>(index &lt; 0 || index &gt; size())</code>.
 319  
                  * @return         a new list that is a view of the specified range within this list.
 320  
                  */
 321  
                 public function subList(fromIndex:int, toIndex:int): IList
 322  
                 {
 323  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 324  
                 }
 325  
 
 326  
                 /**
 327  
                  * @private
 328  
                  */
 329  
                 protected function checkIndex(index:int, max:int):void
 330  
                 {
 331  1
                         if (index < 0 || index > max) throw new IndexOutOfBoundsError("The 'index' argument is out of bounds: " + index + " (min: 0, max: " + max + ")");
 332  1
                 }
 333  
                 
 334  
                 /**
 335  
                  * @private
 336  
                  */
 337  
                 override protected function elementAdded(element:*): void
 338  
                 {
 339  1
                         super.elementAdded(element);
 340  1
                         _modCount++;
 341  1
                 }
 342  
                 
 343  
                 /**
 344  
                  * @private
 345  
                  */
 346  
                 override protected function elementRemoved(element:*): void
 347  
                 {
 348  1
                         super.elementRemoved(element);
 349  1
                         _modCount++;
 350  1
                 }
 351  
 
 352  
                 /**
 353  
                  * @private
 354  
                  */
 355  
                 private function indexOfByEquality(element:*, fromIndex:int = 0): int
 356  
                 {
 357  1
                         var it:IListIterator = listIterator(fromIndex);
 358  
                         var e:IEquatable;
 359  
                         
 360  1
                         while (it.hasNext())
 361  
                         {
 362  1
                                 e = it.next();
 363  1
                                 if (e.equals(element)) return it.pointer();
 364  
                         }
 365  
                         
 366  1
                         return -1;
 367  
                 }
 368  
                 
 369  
                 /**
 370  
                  * @private
 371  
                  */
 372  
                 private function lastIndexOfByEquality(element:*, fromIndex:int = 0x7fffffff): int
 373  
                 {
 374  1
                         if (fromIndex < 0x7fffffff) fromIndex++;
 375  1
                         if (fromIndex > size()) fromIndex = size();
 376  
                         
 377  1
                         var it:IListIterator = listIterator(fromIndex);
 378  
                         var e:IEquatable;
 379  
                         
 380  1
                         while (it.hasPrevious())
 381  
                         {
 382  1
                                 e = it.previous();
 383  1
                                 if (e.equals(element)) return it.nextIndex();
 384  
                         }
 385  
                         
 386  1
                         return -1;
 387  
                 }
 388  
 
 389  
         }
 390  
 
 391  
 }