
1 // 2 // Copyright (c) 2006, Brian Frank and Andy Frank 3 // Licensed under the Academic Free License version 3.0 4 // 5 // History: 6 // 30 Jan 06 Brian Frank Creation 7 // 8 9 ** 10 ** Map is a hash map of key/value pairs. 11 ** 12 final class Map 13 { 14 15 ////////////////////////////////////////////////////////////////////////// 16 // Constructor 17 ////////////////////////////////////////////////////////////////////////// 18 19 ** 20 ** Constructor with of type (must be Map type). 21 ** 22 new make(Type type) 23 24 ////////////////////////////////////////////////////////////////////////// 25 // Identity 26 ////////////////////////////////////////////////////////////////////////// 27 28 ** 29 ** Two Maps are equal if they have the same number of equal key/value pairs. 30 ** 31 override Bool equals(Obj that) 32 33 ** 34 ** Return platform dependent hashcode based on hash of the keys and values. 35 ** 36 override Int hash() 37 38 ////////////////////////////////////////////////////////////////////////// 39 // Methods 40 ////////////////////////////////////////////////////////////////////////// 41 42 ** 43 ** Return if size() == 0. This method is idempotent. 44 ** 45 Bool isEmpty() 46 47 ** 48 ** Get the number of key/value pairs in the list. This 49 ** method is idempotent. 50 ** 51 Int size() 52 53 ** 54 ** Get the value for the specified key. If key is not 55 ** mapped, then return the value of def (null by default). 56 ** This method is idempotent. Shortcut is a[key]. 57 ** 58 V get(K key, V def := null) 59 60 ** 61 ** Return if the specified key is mapped. 62 ** This method is idempotent. 63 ** 64 Bool containsKey(K key) 65 66 ** 67 ** Get a list of all the mapped keys. This method is idempotent. 68 ** 69 K[] keys() 70 71 ** 72 ** Get a list of all the mapped values. This method is idempotent. 73 ** 74 V[] values() 75 76 ** 77 ** Create a shallow duplicate copy of this Map. The keys and 78 ** values themselves are not duplicated. This method is idempotent. 79 ** 80 M dup() 81 82 ** 83 ** Set the value for the specified key. If the key is already 84 ** mapped, this overwrites the old value. If key is not yet mapped 85 ** this adds the key/value pair to the map. Return this. If key 86 ** does not return true for Obj.isImmutable, then throw NotImmutableErr. 87 ** If key is null throw NullErr. Throw ReadonlyErr if readonly. 88 ** 89 M set(K key, V val) 90 91 ** 92 ** Add the specified key/value pair to the map. If the key is 93 ** already mapped, then throw the ArgErr. Return this. If key 94 ** does not return true for Obj.isImmutable, then throw NotImmutableErr. 95 ** If key is null throw NullErr. Throw ReadonlyErr if readonly. 96 ** 97 M add(K key, V val) 98 99 ** 100 ** Append the specified map to this map by setting every key/value in 101 ** m in this map. Keys in m not yet mapped are added and keys already 102 ** mapped are overwritten. Return this. Throw ReadonlyErr if readonly. 103 ** This method is semanatically equivalent to: 104 ** m.each |K k, V v| { this.set(k, v) } 105 ** 106 M setAll(M m) 107 108 ** 109 ** Append the specified map to this map by adding every key/value in 110 ** m in this map. If any key in m is already mapped then this method 111 ** will fail (any previous keys will remain mapped potentially leaving 112 ** this map in an inconsistent state). Return this. Throw ReadonlyErr if 113 ** readonly. This method is semanatically equivalent to: 114 ** m.each |K k, V v| { this.add(k, v) } 115 ** 116 M addAll(M m) 117 118 ** 119 ** Remove the key/value pair identified by the specified key 120 ** from the map and return the value. If the key was not mapped 121 ** then return null. Throw ReadonlyErr if readonly. 122 ** 123 V remove(K key) 124 125 ** 126 ** Remove all key/value pairs from the map. Return this. 127 ** Throw ReadonlyErr if readonly. 128 ** 129 Void clear() 130 131 ** 132 ** This field configures case sensitivity for maps with Str keys. When 133 ** set to true, Str keys are compared without regard to case for the following 134 ** methods: get, containsKey, set, add, setAll, addAll, and remove methods. 135 ** Only ASCII character case is taken into account. The original case 136 ** is preserved (keys aren't made all lower or upper case). This field 137 ** defaults to false. 138 ** 139 ** Getting this field is idempotent. If you attempt to set this method 140 ** on a map which is not empty or not typed to use Str keys, then throw 141 ** UnsupportedOperation. Throw ReadonlyErr if set when readonly. 142 ** 143 Bool caseInsensitive := false 144 145 ////////////////////////////////////////////////////////////////////////// 146 // Conversion 147 ////////////////////////////////////////////////////////////////////////// 148 149 ** 150 ** Return a string representation the Map. This method is idempotent. 151 ** 152 override Str toStr() 153 154 ////////////////////////////////////////////////////////////////////////// 155 // Iterators 156 ////////////////////////////////////////////////////////////////////////// 157 158 ** 159 ** Call the specified function for every key/value in the list. 160 ** This method is idempotent. 161 ** 162 Void each(|V value, K key| c) 163 164 ** 165 ** Return the first value in the map for which c returns true. 166 ** If c returns false for every pair, then return null. This 167 ** method is idempotent. 168 ** 169 V find(|V value, K key->Bool| c) 170 171 ** 172 ** Return a new map containing the key/value pairs for which c 173 ** returns true. If c returns false for every item, then return 174 ** an empty map. The inverse of this method is exclude(). This 175 ** method is idempotent. 176 ** 177 M findAll(|V value, K key->Bool| c) 178 179 ** 180 ** Return a new map containing the key/value pairs for which c 181 ** returns false. If c returns true for every item, then return 182 ** an empty list. The inverse of this method is findAll(). This 183 ** method is idempotent. 184 ** 185 ** Example: 186 ** map := ["off":0, "slow":50, "fast":100] 187 ** map.exclude |Int v->Bool| { return v == 0 } -> ["slow":50, "fast":100] 188 ** 189 M exclude(|V item, K key->Bool| c) 190 191 ** 192 ** Reduce is used to iterate through every value in the map 193 ** to reduce the map into a single value called the reduction. 194 ** The initial value of the reduction is passed in as the init 195 ** parameter, then passed back to the closure along with each 196 ** item. This method is idempotent. 197 ** 198 ** Example: 199 ** m := ["2":2, "3":3, "4":4] 200 ** m.reduce(100) |Obj r, Int v->Obj| { return (Int)r + v } -> 109 201 ** 202 Obj reduce(Obj init, |Obj reduction, V item, K key->Obj| c) 203 204 ** 205 ** Create a new map with the same keys, but apply the specified 206 ** closure to generate new values. This method is idempotent. 207 ** 208 ** Example: 209 ** m := [2:2, 3:3, 4:4] 210 ** x := m.map(Str:Int[:]) |Int v->Obj| { return v*2 } 211 ** x -> [2:4, 3:6, 4:8] 212 ** 213 M map(Map acc, |V item, K key->Obj| c) 214 215 ////////////////////////////////////////////////////////////////////////// 216 // Readonly 217 ////////////////////////////////////////////////////////////////////////// 218 219 ** 220 ** Return if this Map is readonly. A readonly Map is guaranteed 221 ** to be immutable (although its values may be mutable themselves). 222 ** Any attempt to modify a readonly Map will result in ReadonlyErr. 223 ** Use rw() to get a read-write Map from a readonly Map. Methods 224 ** documented as idempotent may be used safely with a readonly Map. 225 ** This method is idempotent. 226 ** 227 Bool isRO() 228 229 ** 230 ** Return if this Map is read-write. A read-write Map is mutable 231 ** and may be modified. Use ro() to get a readonly Map from a 232 ** read-write Map. This method is idempotent. 233 ** 234 Bool isRW() 235 236 ** 237 ** Get a readonly, immutable Map instance with the same contents 238 ** as this Map (although its values may be mutable themselves). 239 ** If this Map is already readonly, then return this. Only methods 240 ** documented as idempotent may be used safely with a readonly 241 ** Map, all others will throw ReadonlyErr. This method is 242 ** idempotent. 243 ** 244 M ro() 245 246 ** 247 ** Get a read-write, mutable Map instance with the same contents 248 ** as this Map. If this Map is already read-write, then return this. 249 ** This method is idempotent. 250 ** 251 M rw() 252 253 ** 254 ** Return an immutable Map which returns true for Obj.isImmtable. 255 ** If this Map is already immutable, then return this. This method 256 ** is effectively a "deep ro()" which guarantees that if any values 257 ** are Lists or Maps, then they are made immutable by recursively calling 258 ** toImmutable. All other values must return true for Obj.isImmutable, 259 ** otherwise NotImmutableErr is thrown. This method must be used 260 ** whenever setting a const Map field. This method is idempotent. 261 ** 262 M toImmutable() 263 264 }