1 /** 2 * Copyright: Copyright (c) 2008-2012 Jacob Carlborg. All rights reserved. 3 * Authors: Jacob Carlborg 4 * Version: Initial created: 2008 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module mambo.core.AssociativeArray; 8 9 import tango.core.Exception : NoSuchElementException; 10 11 import mambo.util.Traits; 12 13 /** 14 * Returns the value to which the specified key is mapped, 15 * or ($D_CODE null) if this associative array contains no mapping for the key. 16 * 17 * $(P More formally, if the specified associative array contains a mapping from a key 18 * $(D_CODE k) to a value $(D_CODE v) such that $(D_CODE (key==null ? k==null : 19 * key.equals(k))), then this method returns $(D_CODE v); otherwise 20 * it returns $(D_CODE null). (There can be at most one such mapping.)) 21 * 22 * Params: 23 * aa = the associative array to get the value from 24 * key = the key whose associated value is to be returned 25 * 26 * 27 * Returns: the value to which the specified key is mapped, or 28 * $(D_CODE null) if this map contains no mapping for the key 29 * 30 * Throws: AssertException if any paramter is invalid 31 * NoSuchElementException if the given key could not be found 32 */ 33 V get (K, V) (V[K] aa, K key) 34 in 35 { 36 assert(aa.length > 0, "mambo.collection.AssociativeArray.get: The length of the associative array was 0"); 37 } 38 body 39 { 40 if (key in aa) 41 return aa[key]; 42 43 else 44 throw new NoSuchElementException("The give key could not be found", __FILE__, __LINE__); 45 } 46 47 /** 48 * Associates the specified value with the specified key in the specified 49 * associative array. If the associative array previously contained a mapping for 50 * the key, the old value is replaced by the specified value. (An associative array 51 * <tt>aa</tt> is said to contain a mapping for a key <tt>k</tt> if and only 52 * if $(LINK2 #containsKey(Object), m.containsKey(k)) would return 53 * <tt>true</tt>.) 54 * 55 * Params: 56 * aa = the associative array to add the key/value pair to 57 * key = key with which the specified value is to be associated 58 * value = value to be associated with the specified key 59 * 60 * Returns: the previous value associated with <tt>key</tt>, or 61 * or the newly associated value. 62 */ 63 V put (K, V) (V[K] aa, K key, V value) 64 { 65 if (key in aa) 66 { 67 V prevValue = aa[key]; 68 aa[key] = value; 69 70 return prevValue; 71 } 72 73 return aa[key] = value; 74 } 75 76 /** 77 * Associates the specified value with the specified key in the specified 78 * associative array. If the associative array previously contained a mapping for 79 * the key, the existing value associated for the given key will be return and the 80 * associative array is unchanged. (An associative array <tt>aa</tt> is said 81 * to contain a mapping for a key <tt>k</tt> if and only if 82 * $(LINK2 #containsKey(Object), m.containsKey(k)) would return <tt>true</tt>.) 83 * 84 * Params: 85 * aa = the associative array to add the key/value pair to 86 * key = key with which the specified value is to be associated 87 * value = value to be associated with the specified key 88 * 89 * Returns: the previous value associated with <tt>key</tt>, or 90 * or the newly associated value. 91 */ 92 V insert (K, V) (V[K] aa, K key, V value) 93 { 94 if (key in aa) 95 return aa[key]; 96 97 return aa[key] = value; 98 } 99 100 /** 101 * Associates the specified value with the specified key in the specified 102 * multimap. If the multimap previously contained a mapping for 103 * the key, the existing value associated for the given key will be return and the 104 * multimap is unchanged. (An multimap <tt>mm</tt> is said 105 * to contain a mapping for a key <tt>k</tt> if and only if 106 * $(LINK2 #containsKey(Object), m.containsKey(k)) would return <tt>true</tt>.) 107 * 108 * Params: 109 * mm = the multimap to add the key/value pair to 110 * key = key with which the specified value is to be associated 111 * value = value to be associated with the specified key 112 * 113 * Returns: the previous value associated with <tt>key</tt>, or 114 * or the newly associated value. 115 */ 116 V insert (K, V) (V[][K] mm, K key, V value) 117 { 118 if (key in aa) 119 return aa[key]; 120 121 return aa[key] ~= value; 122 } 123 124 /** 125 * Removes the mapping for a key from the specified 126 * associative array if it is present. More formally, 127 * if the associative array contains a mapping 128 * from key <tt>k</tt> to value <tt>v</tt> such that 129 * $(D_CODE (key==null ? k==null : key.equals(k))), that mapping 130 * is removed. (The associative array can contain at most one such mapping.) 131 * 132 * $(P Returns the value to which the associative array previously associated the key, 133 * or <tt>null</tt> if the map contained no mapping for the key.) 134 * 135 * Params: 136 * aa = the associative array to remove the key/value pair from 137 * key = key whose mapping is to be removed from the associative array 138 * 139 * Returns: 140 */ 141 V remove (K, V) (V[K] aa, K key) 142 { 143 if (key in aa) 144 { 145 V v = aa[key]; 146 aa.remove(k); 147 148 return v; 149 } 150 151 else 152 throw new NoSuchElementException("The give key could not be found", __FILE__, __LINE__); 153 } 154 155 /** 156 * Returns <tt>true</tt> if the specified 157 * associative array contains no key-value mappings. 158 * 159 * Params: 160 * aa = the associative array to check if it's empty 161 * 162 * Returns: <tt>true</tt> if the specified 163 * associative array contains no key-value mappings 164 */ 165 bool isEmpty (K, V) (V[K] aa) 166 { 167 return aa.length == 0; 168 } 169 170 /** 171 * Returns the number of key-value mappings in 172 * the specified associative array 173 * 174 * Params: 175 * aa = the associative array to get the number of key-value mappings from 176 * 177 * Returns: the number of key-value mappings in the associative array 178 */ 179 int size (K, V) (V[K] aa) 180 { 181 aa.length; 182 } 183 184 /** 185 * Returns value to lower bound 186 * 187 * associative array. If the associative array previously contained a mapping for 188 * 189 * Returns the value of the key pointing to the first element in the container 190 * whose key does not compare less than key, i.e. it is either equal or greater. 191 * 192 * Params: 193 * aa = the associative array to get the lower bound of 194 * key = the key to be compared 195 * 196 * Returns: the value of the key of the first element in the container whose 197 * key does not compare less than key. 198 * 199 * Throws: NoSuchElementException if the given key could not be found 200 */ 201 V lowerBound (K, V) (V[K] aa, K key) 202 { 203 foreach (k, v ; aa) 204 if (!(k < key)) 205 return v; 206 207 throw new NoSuchElementException("The give key could not be found", __FILE__, __LINE__); 208 } 209 210 /** 211 * Returns the bounds of a range that includes all the elements in the 212 * container with a key that compares equal to key. 213 * 214 * In map containers, where no duplicate keys are allowed, the range 215 * will include one element at most. If key does not match any key in 216 * the container, the range returned has a length of zero. 217 * 218 * Params: 219 * mm = the multimap to get the range from 220 * key = the key value to be compared 221 * 222 * Returns: an array containing all the values the matched the key 223 */ 224 V[] equalRange (K, V) (V[][K] mm, K key) 225 { 226 if (key in mm) 227 return mm[key]; 228 229 else 230 return []; 231 } 232 233 /** 234 * Returns the bounds of a range that includes all the elements in the 235 * container with a key that compares equal to key. 236 * 237 * In map containers, 238 * where no duplicate keys are allowed, the range will include one 239 * element at most. If key does not match any key in the container, the range 240 * returned has a length of zero. 241 * 242 * Params: 243 * aa = the associative array to get the range from 244 * key = the key value to be compared 245 * 246 * Returns: an array containing all the values the matched the key 247 */ 248 V[] equalRange (K, V) (V[K] aa, K key) 249 { 250 if (key in aa) 251 return [aa[key]]; 252 253 else 254 return []; 255 } 256 257 // This is a function private to this package. From some reason it cannot be accessible if 258 // it's marked with "package". 259 bool _anyAA (alias predicate, AA) (AA aa) 260 if (isAssociativeArray!(AA) && isAssociativeArrayPredicate!(predicate, AA)) 261 { 262 foreach (k, v ; aa) 263 if (predicate(k, v)) 264 return true; 265 266 return false; 267 } 268 269 // This is a function private to this package. From some reason it cannot be accessible if 270 // it's marked with "package". 271 auto _findAA (alias predicate, AA) (AA aa) 272 if (isAssociativeArray!(AA) && isAssociativeArrayPredicate!(predicate, AA)) 273 { 274 alias KeyTypeOfAssociativeArray!(AA) K; 275 alias ValueTypeOfAssociativeArray!(AA) V; 276 alias KeyValue!(K, V) Pair; 277 278 foreach (k, v ; aa) 279 if (predicate(k, v)) 280 return Pair(k, v, false); 281 282 return Pair.init; 283 } 284 285 struct KeyValue (K, V) 286 { 287 K key; 288 V value; 289 private bool isEmpty_ = true; 290 291 alias any this; 292 293 @property bool isEmpty () 294 { 295 return isEmpty_; 296 } 297 298 @property bool any () 299 { 300 return !isEmpty; 301 } 302 } 303 304 auto _mapAA (alias func, AA) (AA aa) if (isAssociativeArray!(AA)) 305 { 306 alias KeyTypeOfAssociativeArray!(AA) K; 307 alias ValueTypeOfAssociativeArray!(AA) V; 308 309 alias typeof(func(K.init, V.init)) ReturnType; 310 311 ReturnType[] result; 312 result.reserve(aa.length); 313 314 foreach (k, v ; aa) 315 result ~= func(k, v); 316 317 return result; 318 }