1 2(********************************************************************) 3(* *) 4(* hash.s7i Hash map support library *) 5(* Copyright (C) 1989 - 2012 Thomas Mertes *) 6(* *) 7(* This file is part of the Seed7 Runtime Library. *) 8(* *) 9(* The Seed7 Runtime Library is free software; you can *) 10(* redistribute it and/or modify it under the terms of the GNU *) 11(* Lesser General Public License as published by the Free Software *) 12(* Foundation; either version 2.1 of the License, or (at your *) 13(* option) any later version. *) 14(* *) 15(* The Seed7 Runtime Library is distributed in the hope that it *) 16(* will be useful, but WITHOUT ANY WARRANTY; without even the *) 17(* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *) 18(* PURPOSE. See the GNU Lesser General Public License for more *) 19(* details. *) 20(* *) 21(* You should have received a copy of the GNU Lesser General *) 22(* Public License along with this program; if not, write to the *) 23(* Free Software Foundation, Inc., 51 Franklin Street, *) 24(* Fifth Floor, Boston, MA 02110-1301, USA. *) 25(* *) 26(********************************************************************) 27 28 29(** 30 * Abstract data type, describing hash maps. 31 * A hash map stores key-value pairs. A hash map guarantees that a 32 * key can be mapped quickly to its corresponding value. The keys 33 * of a hash map have the type ''keyType'' and the value have the 34 * type ''baseType''. A hash map is only possible, if ''keyType'' 35 * supports the functions ''hashCode'' and ''compare''. 36 *) 37const func type: hash [ (in type: keyType) ] (in type: baseType) is func 38 result 39 var type: hashType is void; 40 begin 41 hashType := get_type(getfunc(hash [ (attr keyType) ] (attr baseType))); 42 if hashType = void then 43 global 44 hashType := newtype; 45 IN_PARAM_IS_REFERENCE(hashType); 46 const type: hash [ (attr keyType) ] (attr baseType) is hashType; 47 const type: key_type (attr hashType) is keyType; 48 const type: base_type (attr hashType) is baseType; 49 50 const reference: (attr hashType) . keyCreate is getfunc((ref keyType: dest) ::= (in keyType: source)); 51 const reference: (attr hashType) . keyDestroy is getfunc(destroy(ref keyType: aValue)); 52 const reference: (attr hashType) . keyCopy is getfunc((inout keyType: dest) := (in keyType: source)); 53 const reference: (attr hashType) . keyCompare is getfunc(compare(in keyType: key1, in keyType: key2)); 54 const reference: (attr hashType) . dataCreate is getfunc((ref baseType: dest) ::= (in baseType: source)); 55 const reference: (attr hashType) . dataDestroy is getfunc(destroy(ref baseType: aValue)); 56 const reference: (attr hashType) . dataCopy is getfunc((inout baseType: dest) := (in baseType:source)); 57 58 const proc: CREATE (ref hashType: dest, in hashType: source, 59 in reference: keyCreate, in reference: keyDestroy, 60 in reference: dataCreate, in reference: dataDestroy) is action "HSH_CREATE"; 61 const proc: DESTROY (ref hashType: aValue, in reference: keyDestroy, 62 in reference: dataDestroy) is action "HSH_DESTR"; 63 const proc: COPY (inout hashType: dest, in hashType: source, 64 in reference: keyCreate, in reference: keyDestroy, 65 in reference: dataCreate, in reference: dataDestroy) is action "HSH_CPY"; 66 const proc: FOR_DATA (inout baseType: forVar, in hashType: aHashMap, 67 in proc: statements, in reference: dataCopy) is action "HSH_FOR"; 68 const proc: FOR_KEY (inout keyType: keyVar, in hashType: aHashMap, 69 in proc: statements, in reference: keyCop) is action "HSH_FOR_KEY"; 70 const proc: FOR_DATA_KEY (inout baseType: forVar, inout keyType: keyVar, 71 in hashType: aHashMap, in proc: statements, 72 in reference: dataCopy, in reference: keyCopy) is action "HSH_FOR_DATA_KEY"; 73 const func array keyType: KEYS (in hashType: aHashMap, in reference: keyCreate, 74 in reference: keyDestroy) is action "HSH_KEYS"; 75 const func array baseType: VALUES (in hashType: aHashMap, in reference: dataCreate, 76 in reference: dataDestroy) is action "HSH_VALUES"; 77 78 const proc: (ref hashType: dest) ::= (in hashType: source) is func 79 begin 80 CREATE(dest, source, hashType.keyCreate, hashType.keyDestroy, 81 hashType.dataCreate, hashType.dataDestroy); 82 end func; 83 84 const proc: destroy (ref hashType: oldHash) is func 85 begin 86 DESTROY(oldHash, hashType.keyDestroy, hashType.dataDestroy); 87 end func; 88 89 const proc: (inout hashType: dest) := (in hashType: source) is func 90 begin 91 COPY(dest, source, hashType.keyCreate, hashType.keyDestroy, 92 hashType.dataCreate, hashType.dataDestroy); 93 end func; 94 95 (** 96 * Number of elements in the hash map ''aHashMap''. 97 * @return the number of elements in ''aHashMap''. 98 *) 99 const func integer: length (in hashType: aHashMap) is action "HSH_LNG"; 100 101 const func baseType: INDEX (in hashType: aHashMap, in keyType: aKey, 102 in integer: hashCode, 103 in reference: keyCompare) is action "HSH_IDX"; 104 const varfunc baseType: INDEX (inout hashType: aHashMap, in keyType: aKey, 105 in integer: hashCode, 106 in reference: keyCompare) is action "HSH_IDX"; 107 108 const func baseType: INDEX2 (in hashType: aHashMap, in keyType: aKey, 109 in integer: hashCode, in baseType: defaultValue, 110 in reference: keyCompare, 111 in reference: dataCreate) is action "HSH_IDX2"; 112 113 const func ptr baseType: REFINDEX (in hashType: aHashMap, in keyType: aKey, 114 in integer: hashCode, 115 in reference: keyCompare) is action "HSH_REFIDX"; 116 const proc: INCL (inout hashType: aHashMap, in keyType: aKey, 117 in baseType: anElem, in integer: hashCode, 118 in reference: keyCompare, in reference: keyCreate, 119 in reference: dataCreate, in reference: dataCopy) is action "HSH_INCL"; 120 const proc: EXCL (inout hashType: aHashMap, in keyType: aKey, 121 in integer: hashCode, in reference: keyCompare, 122 in reference: keyDestroy, in reference: dataDestroy) is action "HSH_EXCL"; 123 const func baseType: UPDATE (inout hashType: aHashMap, in keyType: aKey, 124 in baseType: anElem, in integer: hashCode, 125 in reference: keyCompare, in reference: keyCreate, 126 in reference: dataCreate) is action "HSH_UPDATE"; 127 const func boolean: CONTAINS (in hashType: aHashMap, in keyType: aKey, 128 in integer: hashCode, 129 in reference: keyCompare) is action "HSH_CONTAINS"; 130(* 131 const func hashType: (attr hashType) conv (in hashType: aHashMap) is action "HSH_CONV"; 132 const varfunc hashType: (attr hashType) conv (inout hashType: aHashMap) is action "TYP_VARCONV"; 133*) 134 const func hashType: (attr hashType) . _GENERATE_EMPTY_HASH is action "HSH_EMPTY"; 135 const hashType: (attr hashType) . EMPTY_HASH is hashType._GENERATE_EMPTY_HASH; 136 const hashType: (attr hashType) . value is hashType._GENERATE_EMPTY_HASH; 137 138 (** 139 * Access one value from the hash table ''aHashMap''. 140 * @return the element with the key ''aKey'' from ''aHashMap''. 141 * @exception RANGE_ERROR If ''aHashMap'' does not have an element 142 * with the key ''aKey''. 143 *) 144 const func baseType: (in hashType: aHashMap) [ (in keyType: aKey) ] is 145 return INDEX(aHashMap, aKey, hashCode(aKey), hashType.keyCompare); 146 147 const varfunc baseType: (inout hashType: aHashMap) [ (in keyType: aKey) ] is 148 return var INDEX(aHashMap, aKey, hashCode(aKey), hashType.keyCompare); 149 150 (** 151 * Access one value from the hash table ''aHashMap''. 152 * @return the element with the key ''aKey'' from ''aHashMap'' or 153 * ''defaultValue'' if ''aHashMap'' does not have an element 154 * with the key ''aKey''. 155 *) 156 const func baseType: (in hashType: aHashMap) [ (in keyType: aKey) default (in baseType: defaultValue) ] is 157 return INDEX2(aHashMap, aKey, hashCode(aKey), defaultValue, 158 hashType.keyCompare, hashType.dataCreate); 159 160 (** 161 * Hash membership test. 162 * Determine if ''aKey'' is a member of the hash map ''aHashMap''. 163 * @return TRUE if ''aKey'' is a member of ''aHashMap'', 164 * FALSE otherwise. 165 *) 166 const func boolean: (in keyType: aKey) in (in hashType: aHashMap) is 167 return CONTAINS(aHashMap, aKey, hashCode(aKey), hashType.keyCompare); 168 169 (** 170 * Negated hash membership test. 171 * Determine if ''aKey'' is not a member of the hash map ''aHashMap''. 172 * @return FALSE if ''aKey'' is a member of ''aHashMap'', 173 * TRUE otherwise. 174 *) 175 const func boolean: (in keyType: aKey) not in (in hashType: aHashMap) is 176 return not CONTAINS(aHashMap, aKey, hashCode(aKey), hashType.keyCompare); 177 178 (** 179 * Add ''anElem'' with the key ''aKey'' to the hash map ''aHashMap''. 180 * If an element with the key ''aKey'' already exists, 181 * it is overwritten with ''anElem''. 182 * @exception MEMORY_ERROR If there is not enough memory. 183 *) 184 const proc: incl (inout hashType: aHashMap, in keyType: aKey, in baseType: anElem) is func 185 begin 186 INCL(aHashMap, aKey, anElem, hashCode(aKey), hashType.keyCompare, 187 hashType.keyCreate, hashType.dataCreate, hashType.dataCopy); 188 end func; 189 190 (** 191 * Remove the element with the key ''aKey'' from the hash map ''aHashMap''. 192 *) 193 const proc: excl (inout hashType: aHashMap, in keyType: aKey) is func 194 begin 195 EXCL(aHashMap, aKey, hashCode(aKey), hashType.keyCompare, 196 hashType.keyDestroy, hashType.dataDestroy); 197 end func; 198 199 (** 200 * Add ''anElem'' with the key ''aKey'' to the hash map ''aHashMap''. 201 * If an element with the key ''aKey'' already exists, 202 * it is overwritten with ''anElem''. 203 * @exception MEMORY_ERROR If there is not enough memory. 204 *) 205 const proc: (inout hashType: aHashMap) @:= [ (in keyType: aKey) ] (in baseType: anElem) is func 206 begin 207 INCL(aHashMap, aKey, anElem, hashCode(aKey), hashType.keyCompare, 208 hashType.keyCreate, hashType.dataCreate, hashType.dataCopy); 209 end func; 210 211 const func baseType: update (inout hashType: aHashMap, in keyType: aKey, in baseType: anElem) is 212 return UPDATE(aHashMap, aKey, anElem, hashCode(aKey), hashType.keyCompare, 213 hashType.keyCreate, hashType.dataCreate); 214 215(* 216 const proc: clear (inout hashType: aHashMap) is func 217 local 218 var baseType: anElem is baseType.value; 219 begin 220 for anElem range source do 221 excl(dest, anElem); 222 end for; 223 end func; 224*) 225 226 (** 227 * For-loop where ''forVar'' loops over the values of the hash map ''aHashMap''. 228 *) 229 const proc: for (inout baseType: forVar) range (in hashType: aHashMap) do 230 (in proc: statements) 231 end for is func 232 begin 233 FOR_DATA(forVar, aHashMap, statements, hashType.dataCopy); 234 end func; 235 236 (** 237 * For-loop where ''keyVar'' loops over the keys of the hash map ''aHashMap''. 238 *) 239 const proc: for key (inout keyType: keyVar) range (in hashType: aHashMap) do 240 (in proc: statements) 241 end for is func 242 begin 243 FOR_KEY(keyVar, aHashMap, statements, hashType.keyCopy); 244 end func; 245 246 (** 247 * For-loop where ''forVar'' and ''keyVar' loop over the hash map ''aHashMap''. 248 *) 249 const proc: for (inout baseType: forVar) key (inout keyType: keyVar) range (in hashType: aHashMap) do 250 (in proc: statements) 251 end for is func 252 begin 253 FOR_DATA_KEY(forVar, keyVar, aHashMap, statements, hashType.dataCopy, hashType.keyCopy); 254 end func; 255 256 (** 257 * Obtain the keys of the hash map ''aHashMap''. 258 * @return the keys of the hash map. 259 *) 260 const func array keyType: keys (in hashType: aHashMap) is 261 return KEYS(aHashMap, hashType.keyCreate, hashType.keyDestroy); 262 263 (** 264 * Obtain the values of the hash map ''aHashMap''. 265 * @return the values of the hash map. 266 *) 267 const func array baseType: values (in hashType: aHashMap) is 268 return VALUES(aHashMap, hashType.dataCreate, hashType.dataDestroy); 269 270 if getfunc(hashCode(in baseType: anElem)) <> NIL and 271 getfunc(compare(in baseType: elem1, in baseType: elem2)) <> NIL then 272 273 (** 274 * Create a hash map from ''aHashMap'' where key and value are exchanged. 275 * Since a hash value can correspond to many keys the type returned 276 * is ''hash [baseType] array keyType''. 277 *) 278 const func hash [baseType] array keyType: flip (in hashType: aHashMap) is func 279 result 280 var hash [baseType] array keyType: inverseHash is (hash [baseType] array keyType).value; 281 local 282 var keyType: aKey is keyType.value; 283 var baseType: aValue is baseType.value; 284 begin 285 for aValue key aKey range aHashMap do 286 if aValue in inverseHash then 287 inverseHash[aValue] &:= aKey; 288 else 289 inverseHash @:= [aValue] [] (aKey); 290 end if; 291 end for; 292 end func; 293 end if; 294 295 end global; 296 end if; 297 end func; 298