Coverage Report - org.as3collections.AbstractHashMap
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractHashMap
100%
96/96
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.lists.ArrayList;
 33  
         import org.as3collections.utils.MapUtil;
 34  
         import org.as3coreaddendum.errors.CloneNotSupportedError;
 35  
         import org.as3coreaddendum.errors.UnsupportedOperationError;
 36  
         import org.as3coreaddendum.system.IEquatable;
 37  
         import org.as3utils.ReflectionUtil;
 38  
 
 39  
         import flash.errors.IllegalOperationError;
 40  
         import flash.utils.Dictionary;
 41  
 
 42  
         /**
 43  
          * This class provides a skeletal hash table based implementation of the <code>IMap</code> interface, to minimize the effort required to implement this interface.
 44  
          * <p>This is an abstract class and shouldn't be instantiated directly.</p>
 45  
          * <p>This class maintains a native <code>flash.utils.Dictionary</code> object as its source.</p>
 46  
          * <p>This class makes no guarantees as to the order of the map.
 47  
          * In particular, it does not guarantee that the order will remain constant over time.</p>
 48  
          * <p>The documentation for each non-abstract method in this class describes its implementation in detail.
 49  
          * Each of these methods may be overridden if the map being implemented admits a more efficient implementation.</p>
 50  
          * <p><b>IMPORTANT:</b></p>
 51  
          * <p>This class implements equality through <code>org.as3coreaddendum.system.IEquatable</code> interface in the <code>equals</code> method and in all methods that compares the elements inside this collection (i.e. <code>containsKey</code>, <code>containsValue</code>, <code>put</code>, <code>remove</code>, <code>removeAll</code> and <code>retainAll</code>).</p>
 52  
          * <p>In order to this map uses the <code>equals</code> method of its keys and/or values in comparisons (rather than default '==' operator), <b>all keys and/or values in this map must implement the</b> <code>org.as3coreaddendum.system.IEquatable</code> <b>interface and also the supplied key and/or value.</b></p>
 53  
          * <p>For example:</p>
 54  
          * <p>myMap.containsKey(myKey);</p>
 55  
          * <p>All keys (but in this case only keys) inside <code>myMap</code>, and <code>myKey</code>, must implement the <code>org.as3coreaddendum.system.IEquatable</code> interface so that <code>equals</code> method of each key can be used in the comparison.
 56  
          * Otherwise '==' operator is used. The same is true for values.
 57  
          * The use of equality for keys and values are independent.
 58  
          * It's possible to use only keys that implement <code>IEquatable</code>, only values, both, or none.
 59  
          * This usage varies according to application needs.</p>
 60  
          * <p>All subclasses of this class <em>must</em> conform with this behavior.</p>
 61  
          * <p>This documentation is partially based in the <em>Java Collections Framework</em> JavaDoc documentation.
 62  
          * 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>
 63  
          * 
 64  
          * @see         org.as3collections.IMap IMap
 65  
          * @see         org.as3collections.HashMap HashMap
 66  
          * @see         org.as3collections.AbstractListMap AbstractListMap
 67  
          * @see         http://as3coreaddendum.org/en-us/documentation/asdoc/org/as3coreaddendum/system/IEquatable.html        org.as3coreaddendum.system.IEquatable
 68  
          * @author Flávio Silva
 69  
          */
 70  
         public class AbstractHashMap implements IMap
 71  
         {
 72  
                 /**
 73  
                  * @private
 74  
                  */
 75  
                 private var _totalKeysEquatable: int;
 76  
                 private var _totalValuesEquatable: int;
 77  
 
 78  
                 /**
 79  
                  * @private
 80  
                  */
 81  
                 protected var _size: int;
 82  
 
 83  
                 private var _map: Dictionary;
 84  
                 private var _values: Dictionary;// used only by containsValue() IF allValuesEquatable = false
 85  
                 private var _weakKeys: Boolean;
 86  
 
 87  
                 /**
 88  
                  * @inheritDoc
 89  
                  */
 90  
                 public function get allKeysEquatable(): Boolean { return _totalKeysEquatable == size(); }
 91  
 
 92  
                 /**
 93  
                  * @inheritDoc
 94  
                  */
 95  
                 public function get allValuesEquatable(): Boolean { return _totalValuesEquatable == size(); }
 96  
 
 97  
                 /**
 98  
                  * @private
 99  
                  */
 100  
                 protected function get map(): Dictionary { return _map; }
 101  
 
 102  
                 /**
 103  
                  * @private
 104  
                  */
 105  
                 protected function get values(): Dictionary { return _values; }
 106  
 
 107  
                 /**
 108  
                  * Constructor, creates a new <code>AbstractHashMap</code> object.
 109  
                  * 
 110  
                  * @param         source                 a map with wich fill this map.
 111  
                  * @param         weakKeys         instructs the backed <code>Dictionary</code> object to use "weak" references on object keys. If the only reference to an object is in the specified <code>Dictionary</code> object, the key is eligible for garbage collection and is removed from the table when the object is collected.
 112  
                  * @throws         IllegalOperationError         If this class is instantiated directly, in other words, if there is <b>not</b> another class extending this class.
 113  
                  */
 114  
                 public function AbstractHashMap(source:IMap = null, weakKeys:Boolean = false)
 115  1
                 {
 116  1
                         if (ReflectionUtil.classPathEquals(this, AbstractHashMap))  throw new IllegalOperationError(ReflectionUtil.getClassName(this) + " is an abstract class and shouldn't be instantiated directly.");
 117  
                         
 118  1
                         _weakKeys = weakKeys;
 119  1
                         _init();
 120  
                         
 121  1
                         if (source && !source.isEmpty()) putAll(source);
 122  1
                 }
 123  
 
 124  
                 /**
 125  
                  * Removes all of the mappings from this map (optional operation).
 126  
                  * The map will be empty after this call returns.
 127  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 128  
                  * 
 129  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>clear</code> operation is not supported by this map.
 130  
                  */
 131  
                 public function clear(): void
 132  
                 {
 133  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 134  
                 }
 135  
 
 136  
                 /**
 137  
                  * Creates and return a shallow copy of this collection.
 138  
                  * <p>This implementation always throws a <code>CloneNotSupportedError</code>.</p>
 139  
                  * 
 140  
                  * @throws         org.as3coreaddendum.errors.CloneNotSupportedError          if this map doesn't support clone.
 141  
                  * @return         A new object that is a shallow copy of this instance.
 142  
                   */
 143  
                 public function clone(): *
 144  
                 {
 145  1
                         throw new CloneNotSupportedError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 146  
                 }
 147  
 
 148  
                 /**
 149  
                  * Returns <code>true</code> if this map contains a mapping for the specified key.
 150  
                  * <p>If all keys in this map and <code>key</code> argument implement <code>org.as3coreaddendum.system.IEquatable</code>, this implementation will iterate over this map using <code>equals</code> method of the keys.
 151  
                  * Otherwise this implementation uses <code>Dictionary[key] !== undefined</code>.</p>
 152  
                  * 
 153  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the type of the specified key is incompatible with this map (optional).
 154  
                  * @throws         ArgumentError          if the specified key is <code>null</code> and this map does not permit <code>null</code> keys (optional).
 155  
                  */
 156  
                 public function containsKey(key:*): Boolean
 157  
                 {
 158  1
                         if (allKeysEquatable && key is IEquatable) return containsKeyByEquality(key);
 159  1
                         return _map[key] !== undefined;
 160  
                 }
 161  
 
 162  
                 /**
 163  
                  * Returns <code>true</code> if this map maps one or more keys to the specified value.
 164  
                  * <p>If all values in this map and <code>value</code> argument implement <code>org.as3coreaddendum.system.IEquatable</code>, this implementation will iterate over this map using <code>equals</code> method of the values.
 165  
                  * Otherwise this implementation uses <code>Dictionary[value] !== undefined</code>.</p>
 166  
                  * 
 167  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the type of the specified value is incompatible with this map (optional).
 168  
                  * @throws         ArgumentError          if the specified value is <code>null</code> and this map does not permit <code>null</code> values (optional).
 169  
                  */
 170  
                 public function containsValue(value:*): Boolean
 171  
                 {
 172  1
                         if (allValuesEquatable && value is IEquatable) return containsValueByEquality(value);
 173  1
                         return _values[value] !== undefined;
 174  
                 }
 175  
 
 176  
                 /**
 177  
                  * Returns an <code>ArrayList</code> object that is a view of the mappings contained in this map.
 178  
                  * The type of the objects within the list is <code>IMapEntry</code>
 179  
                  * <p>There's no guarantee that the order will remain constant over time.</p>
 180  
                  * <p>Modifications in the <code>ArrayList</code> object doesn't affect this map.</p>
 181  
                  * 
 182  
                  * @return         an <code>ArrayList</code> object that is a view of the mappings contained in this map.
 183  
                  * @see org.as3collections.IMapEntry IMapEntry
 184  
                  * @see org.as3collections.IList IList
 185  
                  * @see org.as3collections.lists.ArrayList ArrayList
 186  
                   */
 187  
                 public function entryCollection(): ICollection
 188  
                 {
 189  1
                         var list:IList = new ArrayList();
 190  
                         var entry:IMapEntry;
 191  
                         
 192  1
                         for (var key:* in _map)
 193  
                         {
 194  1
                                 entry = new MapEntry(key, _map[key]);
 195  1
                                 list.add(entry);
 196  
                         }
 197  
                         
 198  1
                         return list;
 199  
                 }
 200  
                 
 201  
                 /**
 202  
                  * This method uses <code>MapUtil.equalNotConsideringOrder</code> method to perform equality, sending this map and <code>other</code> argument.
 203  
                  * 
 204  
                  * @param          other         the object to be compared for equality.
 205  
                  * @return         <code>true</code> if the arbitrary evaluation considers the objects equal.
 206  
                  * @see         org.as3collections.utils.MapUtil#equalNotConsideringOrder() MapUtil.equalNotConsideringOrder()
 207  
                  * @see         http://as3coreaddendum.org/en-us/documentation/asdoc/org/as3coreaddendum/system/IEquatable.html        org.as3coreaddendum.system.IEquatable
 208  
                  */
 209  
                 public function equals(other:*): Boolean
 210  
                 {
 211  1
                         return MapUtil.equalNotConsideringOrder(this, other);
 212  
                 }
 213  
 
 214  
                 /**
 215  
                  * Returns an <code>ArrayList</code> object that is a view of the keys contained in this map.
 216  
                  * <p>Modifications in the <code>ArrayList</code> object doesn't affect this map.</p>
 217  
                  * 
 218  
                  * @return         an <code>ArrayList</code> object that is a view of the keys contained in this map.
 219  
                  * @see org.as3collections.IList IList
 220  
                  * @see org.as3collections.lists.ArrayList ArrayList
 221  
                   */
 222  
                 public function getKeys(): ICollection
 223  
                 {
 224  1
                         var list:IList = new ArrayList();
 225  
                         
 226  1
                         for (var key:* in _map)
 227  
                         {
 228  1
                                 list.add(key);
 229  
                         }
 230  
                         
 231  1
                         return list;
 232  
                 }
 233  
 
 234  
                 /**
 235  
                  * Returns the value to which the specified key is mapped, or <code>null</code> if this map contains no mapping for the key.
 236  
                  * <p>If this map permits <code>null</code> values, then a return value of <code>null</code> does not <em>necessarily</em> indicate that the map contains no mapping for the key.
 237  
                  * It's possible that the map explicitly maps the key to <code>null</code>.
 238  
                  * The <code>containsKey</code> method may be used to distinguish these two cases.</p>
 239  
                  * <p>If all keys in this map and <code>key</code> argument implement <code>org.as3coreaddendum.system.IEquatable</code>, this implementation will iterate over this map using <code>equals</code> method of the keys.
 240  
                  * Otherwise this implementation returns <code>Dictionary[key]</code>.</p>
 241  
                  * 
 242  
                  * @param          key         the key whose associated value is to be returned.
 243  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                  if the type of the specified key is incompatible with this map (optional).
 244  
                  * @throws         ArgumentError          if the specified key is <code>null</code> and this map does not permit <code>null</code> keys (optional).
 245  
                  * @return         the value to which the specified key is mapped, or <code>null</code> if this map contains no mapping for the key.
 246  
                  */
 247  
                 public function getValue(key:*): *
 248  
                 {
 249  1
                         if (allKeysEquatable && key is IEquatable) return getValueByEquality(key);
 250  1
                         return _map[key];
 251  
                 }
 252  
 
 253  
                 /**
 254  
                  * Returns an <code>ArrayList</code> object that is a view of the values contained in this map.
 255  
                  * <p>Modifications in the <code>ArrayList</code> object doesn't affect this map.</p>
 256  
                  * 
 257  
                  * @return         an <code>ArrayList</code> object that is a view of the values contained in this map.
 258  
                  * @see org.as3collections.IList IList
 259  
                  * @see org.as3collections.lists.ArrayList ArrayList
 260  
                   */
 261  
                 public function getValues(): ICollection
 262  
                 {
 263  1
                         var list:IList = new ArrayList();
 264  
                         
 265  1
                         for each (var value:* in _map)
 266  
                         {
 267  1
                                 list.add(value);
 268  
                         }
 269  
                         
 270  1
                         return list;
 271  
                 }
 272  
 
 273  
                 /**
 274  
                  * @inheritDoc
 275  
                   */
 276  
                 public function isEmpty(): Boolean
 277  
                 {
 278  1
                         return _size == 0;
 279  
                 }
 280  
 
 281  
                 /**
 282  
                  * Returns an iterator over a set of mappings.
 283  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 284  
                  * 
 285  
                  * @return         an iterator over a set of values.
 286  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          this method must be overridden in subclass.
 287  
                   */
 288  
                 public function iterator(): IIterator
 289  
                 {
 290  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 291  
                 }
 292  
 
 293  
                 /**
 294  
                  * Associates the specified value with the specified key in this map (optional operation).
 295  
                  * If the map previously contained a mapping for the key, the old value is replaced by the specified value.
 296  
                  * (A map <code>m</code> is said to contain a mapping for a key <code>k</code> if and only if <code>m.containsKey(k)</code> would return <code>true</code>.) 
 297  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 298  
                  * 
 299  
                  * @param          key         key with which the specified value is to be associated.
 300  
                  * @param          value         value to be associated with the specified key.
 301  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>put</code> operation is not supported by this map.
 302  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the type of the specified key or value is incompatible with this map.
 303  
                  * @throws         ArgumentError                          if the specified key or value is <code>null</code> and this map does not permit <code>null</code> keys or values.
 304  
                  * @return         the previous value associated with key, or <code>null</code> if there was no mapping for key. (A <code>null</code> return can also indicate that the map previously associated <code>null</code> with key, if the implementation supports <code>null</code> values.)
 305  
                  */
 306  
                 public function put(key:*, value:*): *
 307  
                 {
 308  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 309  
                 }
 310  
 
 311  
                 /**
 312  
                  * Copies all of the mappings from the specified map to this map (optional operation).
 313  
                  * The effect of this call is equivalent to that of calling <code>put(k, v)</code> on this map once for each mapping from key <code>k</code> to value <code>v</code> in the specified map.
 314  
                  * <p>This implementation iterates over the specified map, and calls this map's <code>put</code> operation once for each entry returned by the iteration.</p>
 315  
                  * 
 316  
                  * @param          map         mappings to be stored in this map.
 317  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>putAll</code> operation is not supported by this map.
 318  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the type of a key or value in the specified map is incompatible with this map.
 319  
                  * @throws         ArgumentError                          if the specified map is <code>null</code>, or if this map does not permit <code>null</code> keys or values, and the specified map contains <code>null</code> keys or values.
 320  
                  */
 321  
                 public function putAll(map:IMap): void
 322  
                 {
 323  1
                         if (!map) throw new ArgumentError("The 'map' argument must not be 'null'.");
 324  
                         
 325  1
                         var it:IIterator = map.iterator();
 326  
                         var value:*;
 327  
                         
 328  1
                         while (it.hasNext())
 329  
                         {
 330  1
                                 value = it.next();
 331  1
                                 put(it.pointer(), value);
 332  
                         }
 333  1
                 }
 334  
 
 335  
                 /**
 336  
                  * This implementation performs a <code>for..in</code> in the specified object, calling <code>put</code> on this map once for each iteration (optional operation).
 337  
                  * 
 338  
                  * @param          o         the object to retrieve the properties.
 339  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>putAllByObject</code> operation is not supported by this map.
 340  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the type of a key or value in the specified object is incompatible with this map.
 341  
                  * @throws         ArgumentError                          if the specified object is <code>null</code>, or if this map does not permit <code>null</code> keys or values, and the specified object contains <code>null</code> keys or values.
 342  
                  */
 343  
                 public function putAllByObject(o:Object): void
 344  
                 {
 345  1
                         if (!o) throw new ArgumentError("The 'o' argument must not be 'null'.");
 346  
                         
 347  1
                         for (var key:* in o)
 348  
                         {
 349  1
                                 put(key, o[key]);
 350  
                         }
 351  1
                 }
 352  
 
 353  
                 /**
 354  
                  * Associates the specified <code>entry.value</code> with the specified <code>entry.key</code> in this map (optional operation).
 355  
                  * If the map previously contained a mapping for the <code>entry.key</code>, the old value is replaced by the specified <code>entry.value</code>. (A map <code>m</code> is said to contain a mapping for a key <code>k</code> if and only if <code>m.containsKey(k)</code> would return <code>true</code>.) 
 356  
                  * <p>This implementation calls <code>put(entry.key, entry.value)</code>.</p>
 357  
                  * 
 358  
                  * @param          entry         entry to put in this map.
 359  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>putEntry</code> operation is not supported by this map.
 360  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the type of the specified <code>entry.key</code> or <code>entry.value</code> is incompatible with this map.
 361  
                  * @throws         ArgumentError                          if the specified entry is <code>null</code>, or if the specified <code>entry.key</code> or <code>entry.value</code> is <code>null</code> and this map does not permit <code>null</code> keys or values.
 362  
                  * @return         the previous value associated with <code>entry.key</code>, or <code>null</code> if there was no mapping for <code>entry.key</code>. (A <code>null</code> return can also indicate that the map previously associated <code>null</code> with <code>entry.key</code>, if the implementation supports <code>null</code> values.)
 363  
                  */
 364  
                 public function putEntry(entry:IMapEntry): *
 365  
                 {
 366  1
                         if (!entry) throw new ArgumentError("The 'entry' argument must not be 'null'.");
 367  
                         
 368  1
                         return put(entry.key, entry.value);
 369  
                 }
 370  
 
 371  
                 /**
 372  
                  * Removes the mapping for a key from this map if it is present (optional operation).
 373  
                  * <p>Returns the value to which this map previously associated the key, or <code>null</code> if the map contained no mapping for the key.
 374  
                  * If this map permits <code>null</code> values, then a return value of <code>null</code> does not <em>necessarily</em> indicate that the map contained no mapping for the key. It's possible that the map explicitly mapped the key to <code>null</code>.</p>
 375  
                  * <p>The map will not contain a mapping for the specified key once the call returns.</p>
 376  
                  * <p>This implementation always throws an <code>UnsupportedOperationError</code>.</p>
 377  
                  * 
 378  
                  * @param          key         the key whose mapping is to be removed from the map.
 379  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>remove</code> operation is not supported by this map.
 380  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the type of the specified key is incompatible with this map (optional).
 381  
                  * @throws         ArgumentError                          if the specified key is <code>null</code> and this map does not permit <code>null</code> keys (optional).
 382  
                  * @return         the previous value associated with key, or <code>null</code> if there was no mapping for <code>key</code>.
 383  
                  */
 384  
                 public function remove(key:*): *
 385  
                 {
 386  1
                         throw new UnsupportedOperationError("Method must be overridden in subclass: " + ReflectionUtil.getClassPath(this));
 387  
                 }
 388  
 
 389  
                 /**
 390  
                  * Removes the mapping for a key from this map (if it is present) for each element in the specified collection (optional operation).
 391  
                  * The elements in the specified collection are interpreted as keys.
 392  
                  * <p>This implementation iterates over this map, checking each key returned by the iterator in turn to see if it's contained in the specified <code>keys</code> collection (using <code>contains</code> method of the <code>keys</code> argument).
 393  
                  * If it's so contained, it's removed from this map with the iterator's <code>remove</code> method.</p>
 394  
                  * <p>Note that this implementation will throw an <code>UnsupportedOperationError</code> if the iterator returned by the iterator method does not implement the <code>remove</code> method and this map contains one or more keys in common with the specified collection.</p>
 395  
                  * <p>The map will not contain mappings for the elements in the specified collection once the call returns.</p>
 396  
                  * 
 397  
                  * @param          keys         the collection whose elements are interpreted as keys to be removed from the map.
 398  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>removeAll</code> operation is not supported by this map.
 399  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the type of an element in the specified collection is incompatible with this map (optional).
 400  
                  * @throws         ArgumentError                                                                                          if the specified collection is <code>null</code>, or if this map does not permit <code>null</code> keys, and the specified collections contains <code>null</code> elements (optional).
 401  
                  * @return         <code>true</code> if this map changed as a result of the call.
 402  
                  */
 403  
                 public function removeAll(keys:ICollection): Boolean
 404  
                 {
 405  1
                         if (!keys) throw new ArgumentError("The 'keys' argument must not be 'null'.");
 406  1
                         if (keys.isEmpty()) return false;
 407  
                         
 408  1
                         var prevSize:int = size();
 409  1
                         var it:IIterator = iterator();
 410  
                         var e:*;
 411  
                         
 412  1
                         while (it.hasNext())
 413  
                         {
 414  1
                                 e = it.next();
 415  
                                 
 416  1
                                 if (keys.contains(it.pointer())) it.remove();
 417  
                         }
 418  
                         
 419  1
                         return prevSize != size();
 420  
                 }
 421  
 
 422  
                 /**
 423  
                  * Retains only the mappings in this map that the keys are contained (as elements) in the specified collection (optional operation).
 424  
                  * In other words, removes from this map all of its mappings whose keys are not contained (as elements) in the specified <code>keys</code> collection (using <code>contains</code> method of the <code>keys</code> argument).
 425  
                  * The elements in the specified collection are interpreted as keys.
 426  
                  * <p>This implementation iterates over this map and calls <code>IIterator.remove</code> once for each key that are not contained in the specified collection.</p>
 427  
                  * <p>Note that this implementation will throw an <code>UnsupportedOperationError</code> if the iterator returned by the iterator method does not implement the <code>remove</code> method and this map contains one or more keys not present in the specified collection.</p>
 428  
                  * 
 429  
                  * @param          keys         the collection whose elements are interpreted as keys to be retained in the map.
 430  
                  * @throws         org.as3coreaddendum.errors.UnsupportedOperationError          if the <code>retainAll</code> operation is not supported by this map.
 431  
                  * @throws         org.as3coreaddendum.errors.ClassCastError                                  if the types of one or more keys in this map are incompatible with the specified collection (optional).
 432  
                  * @throws         ArgumentError                           if the specified collection contains a <code>null</code> element and this collection does not permit <code>null</code> keys (optional), or if the specified collection is <code>null</code>.
 433  
                  * @return         <code>true</code> if this map changed as a result of the call.
 434  
                  */
 435  
                 public function retainAll(keys:ICollection): Boolean
 436  
                 {
 437  1
                         if (!keys) throw new ArgumentError("The 'keys' argument must not be 'null'.");
 438  1
                         if (keys.isEmpty()) return false;
 439  
                         
 440  1
                         var prevSize:int = size();
 441  1
                         var it:IIterator = iterator();
 442  
                         var value:*;
 443  
                         
 444  1
                         while (it.hasNext())
 445  
                         {
 446  1
                                 value = it.next();
 447  
                                 
 448  1
                                 if (!keys.contains(it.pointer())) it.remove();
 449  
                         }
 450  
                         
 451  1
                         return prevSize != size();
 452  
                 }
 453  
 
 454  
                 /**
 455  
                  * @inheritDoc
 456  
                   */
 457  
                 public function size(): int
 458  
                 {
 459  1
                         return _size;
 460  
                 }
 461  
 
 462  
                 /**
 463  
                  * Returns the string representation of this instance.
 464  
                  * <p>This method uses <code>MapUtil.toString</code> method.</p>
 465  
                  * 
 466  
                  * @return         the string representation of this instance.
 467  
                  * @see         org.as3collections.utils.MapUtil#toString() MapUtil.toString()
 468  
                   */
 469  
                 public function toString():String 
 470  
                 {
 471  1
                         return MapUtil.toString(this);
 472  
                 }
 473  
                 
 474  
                 /**
 475  
                  * @private
 476  
                  */
 477  
                 private function containsKeyByEquality(key:*): Boolean
 478  
                 {
 479  1
                         var it:IIterator = iterator();
 480  
                         var $key:IEquatable;
 481  
                         
 482  1
                         while (it.hasNext())
 483  
                         {
 484  1
                                 it.next();
 485  1
                                 $key = it.pointer();
 486  1
                                 if ($key.equals(key)) return true;
 487  
                         }
 488  
                         
 489  1
                         return false;
 490  
                 }
 491  
 
 492  
                 /**
 493  
                  * @private
 494  
                  */
 495  
                 private function containsValueByEquality(value:*): Boolean
 496  
                 {
 497  1
                         var it:IIterator = iterator();
 498  
                         var $value:IEquatable;
 499  
                         
 500  1
                         while (it.hasNext())
 501  
                         {
 502  1
                                 $value = it.next();
 503  1
                                 if ($value.equals(value)) return true;
 504  
                         }
 505  
                         
 506  1
                         return false;
 507  
                 }
 508  
 
 509  
                 /**
 510  
                  * @private
 511  
                  */
 512  
                 protected function getValueByEquality(key:*) :*
 513  
                 {
 514  1
                         var it:IIterator = iterator();
 515  
                         var $key:IEquatable;
 516  
                         var value:*;
 517  
                         var returnValue:*;
 518  
                         
 519  1
                         while (it.hasNext())
 520  
                         {
 521  1
                                 value = it.next();
 522  1
                                 $key = it.pointer();
 523  
                                 
 524  1
                                 if ($key.equals(key))
 525  
                                 {
 526  1
                                         returnValue = value;
 527  1
                                         break;
 528  
                                 }
 529  
                         }
 530  
                         
 531  1
                         return returnValue;
 532  
                 }
 533  
                 
 534  
                 /**
 535  
                  * @private
 536  
                  */
 537  
                 protected function keyAdded(key:*): void
 538  
                 {
 539  1
                         if (key && key is IEquatable) _totalKeysEquatable++;
 540  1
                 }
 541  
                 
 542  
                 /**
 543  
                  * @private
 544  
                  */
 545  
                 protected function keyRemoved(key:*): void
 546  
                 {
 547  1
                         if (key && key is IEquatable) _totalKeysEquatable--;
 548  1
                 }
 549  
                 
 550  
                 /**
 551  
                  * @private
 552  
                  */
 553  
                 protected function valueAdded(value:*): void
 554  
                 {
 555  1
                         if (value && value is IEquatable) _totalValuesEquatable++;
 556  1
                 }
 557  
                 
 558  
                 /**
 559  
                  * @private
 560  
                  */
 561  
                 protected function valueRemoved(value:*): void
 562  
                 {
 563  1
                         if (value && value is IEquatable) _totalValuesEquatable--;
 564  1
                 }
 565  
                 
 566  
                 /**
 567  
                  * @private
 568  
                  */
 569  
                 protected function _init(): void
 570  
                 {
 571  1
                         _map                 = new Dictionary(_weakKeys);
 572  1
                         _values         = new Dictionary(_weakKeys);
 573  1
                         _size                 = 0;
 574  1
                         _totalKeysEquatable = 0;
 575  1
                         _totalValuesEquatable = 0;
 576  1
                 }
 577  
 
 578  
         }
 579  
 
 580  
 }