Coverage Report - org.as3collections.maps.HashMap
 
Classes in this File Line Coverage Branch Coverage Complexity
HashMap
100%
44/44
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.maps
 31  
 {
 32  
         import org.as3collections.AbstractHashMap;
 33  
         import org.as3collections.IIterator;
 34  
         import org.as3collections.IMap;
 35  
         import org.as3collections.iterators.MapIterator;
 36  
         import org.as3coreaddendum.system.IEquatable;
 37  
 
 38  
         /**
 39  
          * Hash table based implementation of the <code>IMap</code> interface.
 40  
          * This implementation provides all of the optional map operations, and permits <code>null</code> values and the <code>null</code> key.
 41  
          * <p>This class makes no guarantees as to the order of the map.
 42  
          * In particular, it does not guarantee that the order will remain constant over time.</p>
 43  
          * <p>It's possible to create typed maps.
 44  
          * You just sends the <code>HashMap</code> object to the wrapper <code>TypedMap</code> or uses the <code>MapUtil.getTypedMap</code>.</p>
 45  
          * 
 46  
          * @example
 47  
          * 
 48  
          * <listing version="3.0">
 49  
          * import org.as3collections.IMap;
 50  
          * import org.as3collections.IList;
 51  
          * import org.as3collections.maps.HashMap;
 52  
          * import org.as3collections.maps.MapEntry;
 53  
          * 
 54  
          * var map1:IMap = new HashMap();
 55  
          * var tf1:TextField = new TextField();
 56  
          * var tf2:TextField = new TextField();
 57  
          * 
 58  
          * map1                            // {}
 59  
          * map1.containsKey("a")           // false
 60  
          * map1.containsKey(tf2)           // false
 61  
          * map1.containsValue(2)           // false
 62  
          * map1.containsValue(tf1)         // false
 63  
          * map1.isEmpty()                  // true
 64  
          * map1.size()                     // 0
 65  
          * 
 66  
          * map1.put("a", 1)                // null
 67  
          * map1                            // {a=1}
 68  
          * map1.isEmpty()                  // false
 69  
          * map1.size()                     // 1
 70  
          * map1.containsKey("a")           // true
 71  
          * map1.containsKey(tf2)           // false
 72  
          * map1.containsValue(2)           // false
 73  
          * map1.containsValue(tf1)         // false
 74  
          * 
 75  
          * map1.put("b", 2)                // null
 76  
          * map1                            // {b=2,a=1}
 77  
          * map1.isEmpty()                  // false
 78  
          * map1.size()                     // 2
 79  
          * map1.containsKey("a")           // true
 80  
          * map1.containsKey("b")           // true
 81  
          * map1.containsKey(tf2)           // false
 82  
          * map1.containsValue(2)           // true
 83  
          * 
 84  
          * map1.put("c", 3)                // null
 85  
          * map1                            // {b=2,a=1,c=3}
 86  
          * map1.size()                     // 3
 87  
          * 
 88  
          * map1.put("tf1", tf1)            // null
 89  
          * map1                            // {b=2,a=1,c=3,tf1=[object TextField]}
 90  
          * map1.size()                     // 4
 91  
          * map1.containsValue(tf1)         // true
 92  
          * 
 93  
          * map1.put(tf2, "tf2")            // null
 94  
          * map1                            // {b=2,[object TextField]=tf2,a=1,c=3,tf1=[object TextField]}
 95  
          * map1.size()                     // 5
 96  
          * map1.containsKey(tf2)           // true
 97  
          * 
 98  
          * map1.put("a", 1.1)              // 1
 99  
          * map1                            // {b=2,[object TextField]=tf2,a=1.1,c=3,tf1=[object TextField]}
 100  
          * map1.size()                     // 5
 101  
          * 
 102  
          * map1.put("tf1", String)         // [object TextField]
 103  
          * map1                            // {b=2,[object TextField]=tf2,a=1.1,c=3,tf1=[class String]}
 104  
          * map1.size()                     // 5
 105  
          * 
 106  
          * map1.put(tf2, "tf2.1")          // tf2
 107  
          * map1                            // {b=2,[object TextField]=tf2.1,a=1.1,c=3,tf1=[class String]}
 108  
          * map1.size()                     // 5
 109  
          * 
 110  
          * map1.put(Number, 999)           // null
 111  
          * map1                            // {b=2,[object TextField]=tf2.1,[class Number]=999,a=1.1,c=3,tf1=[class String]}
 112  
          * map1.size(): 6
 113  
          * 
 114  
          * map1.getValue("b")              // 2
 115  
          * 
 116  
          * map1.getValue(tf2)              // tf2.1
 117  
          * 
 118  
          * map1.putAllByObject({fa:"fb",ga:"gb",ha:"hb"});
 119  
          * 
 120  
          * map1                            // {b=2,[object TextField]=tf2.1,fa=fb,[class Number]=999,c=3,ha=hb,a=1.1,tf1=[class String],ga=gb}
 121  
          * 
 122  
          * map1.size()                     // 9
 123  
          * 
 124  
          * map1.getValue("fa")             // fb
 125  
          * 
 126  
          * map1.remove("ga")               // gb
 127  
          * map1                            // {b=2,[object TextField]=tf2.1,fa=fb,[class Number]=999,c=3,ha=hb,a=1.1,tf1=[class String]}
 128  
          * map1.size()                     // 8
 129  
          * 
 130  
          * map1.remove("fa")               // fb
 131  
          * map1                            // {b=2,[object TextField]=tf2.1,[class Number]=999,c=3,ha=hb,a=1.1,tf1=[class String]}
 132  
          * map1.size()                     // 7
 133  
          * 
 134  
          * map1.remove(tf2)                // tf2.1
 135  
          * map1                            // {b=2,[class Number]=999,c=3,ha=hb,a=1.1,tf1=[class String]}
 136  
          * map1.size()                     // 6
 137  
          * 
 138  
          * map1.getValue("fa")             // null
 139  
          * map1.getValue(tf2)              // null
 140  
          * 
 141  
          * var map2:IMap = map1.clone();
 142  
          * 
 143  
          * map2                            // {b=2,a=1.1,[class Number]=999,c=3,tf1=[class String],ha=hb}
 144  
          * map2.size()                     // 6
 145  
          * map2.isEmpty()                  // false
 146  
          * 
 147  
          * map1.equals(map2)               // true
 148  
          * map2.equals(map1)               // true
 149  
          * map2.equals(map2)               // true
 150  
          * 
 151  
          * map2.remove("b")                // 2
 152  
          * map2                            // {a=1.1,[class Number]=999,c=3,tf1=[class String],ha=hb}
 153  
          * map2.equals(map2)               // true
 154  
          * map2.size()                     // 5
 155  
          * 
 156  
          * map1.equals(map2)               // false
 157  
          * map2.equals(map1)               // false
 158  
          * 
 159  
          * map2.getValues()                // [1.1,999,3,[class String],hb]
 160  
          * 
 161  
          * var keysMap2:IList = map2.getKeys();
 162  
          * 
 163  
          * keysMap2                        // [a,[class Number],c,tf1,ha]
 164  
          * 
 165  
          * keysMap2.remove("c")            // true
 166  
          * keysMap2                        // [a,[class Number],tf1,ha]
 167  
          * map2                            // {a=1.1,[class Number]=999,c=3,tf1=[class String],ha=hb}
 168  
          * map2.size()                     // 5
 169  
          * 
 170  
          * map2.removeAll(keysMap2)        // true
 171  
          * map2                            // {c=3}
 172  
          * map2.size()                     // 1
 173  
          * map2.isEmpty()                  // false
 174  
          * 
 175  
          * map2.clear();
 176  
          * 
 177  
          * map2                            // {}
 178  
          * map2.size()                     // 0
 179  
          * map2.isEmpty()                  // true
 180  
          * 
 181  
          * var entry:IMapEntry = new MapEntry("c", 3);
 182  
          * 
 183  
          * entry                           // c=3
 184  
          * map2.putEntry(entry)            // null
 185  
          * map2                            // {c=3}
 186  
          * map2.size()                     // 1
 187  
          * 
 188  
          * map1                            // {b=2,[class Number]=999,c=3,ha=hb,a=1.1,tf1=[class String]}
 189  
          * map1.retainAll(map2)            // true
 190  
          * map1                            // {c=3}
 191  
          * map1.size()                     // 1
 192  
          * map1.isEmpty()                  // false
 193  
          * 
 194  
          * map1.put("d", 4)                // null
 195  
          * map1.put("e", 5)                // null
 196  
          * map1.put("f", 6)                // null
 197  
          * 
 198  
          * map1                            // {c=3,d=4,f=6,e=5}
 199  
          * map1.size()                     // 4
 200  
          * 
 201  
          * var it:IIterator = map1.iterator();
 202  
          * 
 203  
          * var e:&#42;;
 204  
          * 
 205  
          * while (it.hasNext())
 206  
          * {
 207  
          * 
 208  
          *     e = it.next();
 209  
          *     trace(it.pointer() + "=" + e)    // c=3
 210  
          * 
 211  
          *     e = it.next();
 212  
          *     trace(it.pointer() + "=" + e)    // d=4
 213  
          * 
 214  
          *     if (e == 4)
 215  
          *     {
 216  
          *         it.remove();
 217  
          *     }
 218  
          * 
 219  
          *     e = it.next();
 220  
          *     trace(it.pointer() + "=" + e)    // f=6
 221  
          * 
 222  
          *     e = it.next();
 223  
          *     trace(it.pointer() + "=" + e)    // e=5
 224  
          * }
 225  
          * 
 226  
          * map1                            // {c=3,f=6,e=5}
 227  
          * map1.size()                     // 3
 228  
          * </listing>
 229  
          * 
 230  
          * @see org.as3collections.utils.MapUtil#getTypedMap() MapUtil.getTypedMap()
 231  
          * @author Flávio Silva
 232  
          */
 233  
         public class HashMap extends AbstractHashMap
 234  
         {
 235  
                 /**
 236  
                  * Constructor, creates a new <code>HashMap</code> object.
 237  
                  * 
 238  
                  * @param         source                 a map with wich fill this map.
 239  
                  * @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.
 240  
                  */
 241  
                 public function HashMap(source:IMap = null, weakKeys:Boolean = false)
 242  
                 {
 243  1
                         super(source, weakKeys);
 244  1
                 }
 245  
 
 246  
                 /**
 247  
                  * Removes all of the mappings from this map.
 248  
                  * The map will be empty after this call returns.
 249  
                  */
 250  
                 override public function clear(): void
 251  
                 {
 252  1
                         _init();
 253  1
                 }
 254  
 
 255  
                 /**
 256  
                  * Creates and return a new <code>HashMap</code> object containing all mappings in this map.
 257  
                  * 
 258  
                  * @return         a new <code>HashMap</code> object containing all mappings in this map.
 259  
                   */
 260  
                 override public function clone(): *
 261  
                 {
 262  1
                         return new HashMap(this);
 263  
                 }
 264  
 
 265  
                 /**
 266  
                  * Returns an iterator over a set of mappings.
 267  
                  * <p>This implementation returns a <code>MapIterator</code> object.</p>
 268  
                  * 
 269  
                  * @return         an iterator over a set of values.
 270  
                  * @see         org.as3collections.iterators.MapIterator MapIterator
 271  
                   */
 272  
                 override public function iterator(): IIterator
 273  
                 {
 274  1
                         return new MapIterator(this);
 275  
                 }
 276  
 
 277  
                 /**
 278  
                  * Associates the specified value with the specified key in this map.
 279  
                  * If the map previously contained a mapping for the key, the old value is replaced by the specified value. (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>.) 
 280  
                  * 
 281  
                  * @param          key         key with which the specified value is to be associated.
 282  
                  * @param          value         value to be associated with the specified key.
 283  
                  * @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, because this implementation supports <code>null</code> values.)
 284  
                  */
 285  
                 override public function put(key:*, value:*): *
 286  
                 {
 287  
                         var oldValue:*;
 288  
                         
 289  1
                         if (containsKey(key)) oldValue = remove(key);
 290  
                         
 291  1
                         _size++;
 292  1
                         map[key] = value;
 293  
                         
 294  1
                         var countValues:int = values[value];
 295  1
                         if (countValues < 1) countValues = 0;
 296  1
                         values[value] = ++countValues;
 297  
                         
 298  1
                         keyAdded(key);
 299  1
                         valueAdded(value);
 300  
                         
 301  1
                         return oldValue;
 302  
                 }
 303  
 
 304  
                 /**
 305  
                  * Removes the mapping for a key from this map if it is present.
 306  
                  * <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.
 307  
                  * A return value of <code>null</code> does not <em>necessarily</em> indicate that the map contained no mapping for the key.
 308  
                  * It's possible that the map explicitly mapped the key to <code>null</code>.</p>
 309  
                  * <p>The map will not contain a mapping for the specified key once the call returns.</p>
 310  
                  * 
 311  
                  * @param          key         the key whose mapping is to be removed from the map.
 312  
                  * @return         the previous value associated with key, or <code>null</code> if there was no mapping for <code>key</code>.
 313  
                  */
 314  
                 override public function remove(key:*): *
 315  
                 {
 316  1
                         if (allKeysEquatable && key is IEquatable)
 317  
                         {
 318  1
                                 return removeByEquality(key);
 319  
                         }
 320  
                         else
 321  
                         {
 322  1
                                 return removeByInstance(key);
 323  
                         }
 324  
                 }
 325  
                 
 326  
                 /**
 327  
                  * @private
 328  
                  */
 329  
                 override protected function valueRemoved(value:*): void
 330  
                 {
 331  1
                         super.valueRemoved(value);
 332  
                         
 333  1
                         var countValues:int = values[value];
 334  
                         
 335  1
                         if (countValues > 1)
 336  
                         {
 337  1
                                 values[value] = --countValues;
 338  
                         }
 339  
                         else
 340  
                         {
 341  1
                                 delete values[value];
 342  
                         }
 343  1
                 }
 344  
                 
 345  
                 /**
 346  
                  * @private
 347  
                  */
 348  
                 private function removeByEquality(key:*): *
 349  
                 {
 350  1
                         var it:IIterator = iterator();
 351  
                         var $key:IEquatable;
 352  
                         var value:*;
 353  
                         var returnValue:*;
 354  
                         
 355  1
                         while (it.hasNext())
 356  
                         {
 357  1
                                 value = it.next();
 358  1
                                 $key = it.pointer();
 359  
                                 
 360  1
                                 if ($key.equals(key))
 361  
                                 {
 362  1
                                         returnValue = value;
 363  1
                                         delete map[$key];
 364  1
                                         _size--;
 365  
                                         
 366  1
                                         keyRemoved(key);
 367  1
                                         valueRemoved(value);
 368  
                                         
 369  1
                                         break;
 370  
                                 }
 371  
                         }
 372  
                         
 373  1
                         return returnValue;
 374  
                 }
 375  
                 
 376  
                 /**
 377  
                  * @private
 378  
                  */
 379  
                 private function removeByInstance(key:*): *
 380  
                 {
 381  1
                         if (map[key] === undefined) return null;
 382  
                         
 383  1
                         var old:* = map[key];
 384  1
                         delete map[key];
 385  1
                         _size--;
 386  
                         
 387  1
                         keyRemoved(key);
 388  1
                         valueRemoved(old);
 389  
                         
 390  1
                         return old;
 391  
                 }
 392  
                 
 393  
         }
 394  
 
 395  
 }