OMCompiler/Compiler/Util/UnorderedSet.mo
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of OpenModelica. | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), | ||
| 5 | * c/o Linköpings universitet, Department of Computer and Information Science, | ||
| 6 | * SE-58183 Linköping, Sweden. | ||
| 7 | * | ||
| 8 | * All rights reserved. | ||
| 9 | * | ||
| 10 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR | ||
| 11 | * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. | ||
| 12 | * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES | ||
| 13 | * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL | ||
| 14 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. | ||
| 15 | * | ||
| 16 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium) | ||
| 17 | * Public License (OSMC-PL) are obtained from OSMC, either from the above | ||
| 18 | * address, from the URLs: | ||
| 19 | * http://www.openmodelica.org or | ||
| 20 | * https://github.com/OpenModelica/ or | ||
| 21 | * http://www.ida.liu.se/projects/OpenModelica, | ||
| 22 | * and in the OpenModelica distribution. | ||
| 23 | * | ||
| 24 | * GNU AGPL version 3 is obtained from: | ||
| 25 | * https://www.gnu.org/licenses/licenses.html#GPL | ||
| 26 | * | ||
| 27 | * This program is distributed WITHOUT ANY WARRANTY; without | ||
| 28 | * even the implied warranty of MERCHANTABILITY or FITNESS | ||
| 29 | * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH | ||
| 30 | * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. | ||
| 31 | * | ||
| 32 | * See the full OSMC Public License conditions for more details. | ||
| 33 | * | ||
| 34 | */ | ||
| 35 | |||
| 36 | encapsulated uniontype UnorderedSet<T> | ||
| 37 | "An implementation of a generic unordered set, a.k.a. hash set. | ||
| 38 | |||
| 39 | This implementation uses separate chaining and automatically rehashes the set | ||
| 40 | when the load factor becomes too large to keep the performance up." | ||
| 41 | |||
| 42 | import Mutable; | ||
| 43 | |||
| 44 | protected | ||
| 45 | import Array; | ||
| 46 | import List; | ||
| 47 | import MetaModelica.Dangerous.*; | ||
| 48 | import Util; | ||
| 49 | |||
| 50 | public | ||
| 51 | partial function Hash | ||
| 52 | input T key; | ||
| 53 | output Integer hash; | ||
| 54 | end Hash; | ||
| 55 | |||
| 56 | partial function KeyEq | ||
| 57 | input T key1; | ||
| 58 | input T key2; | ||
| 59 | output Boolean equal; | ||
| 60 | end KeyEq; | ||
| 61 | |||
| 62 | record UNORDERED_SET | ||
| 63 | Mutable<array<list<T>>> buckets; | ||
| 64 | Mutable<Integer> size; | ||
| 65 | Hash hashFn; | ||
| 66 | KeyEq eqFn; | ||
| 67 | end UNORDERED_SET; | ||
| 68 | |||
| 69 | function new<T> | ||
| 70 | "Creates a new set given a hash function, equality function, and optional | ||
| 71 | desired bucket count. An approriate bucket count is | ||
| 72 | Util.nextPrime(number of elements that will be added), but starting with a | ||
| 73 | low bucket count is also fine if the number of elements is unknown since the | ||
| 74 | set rehashes as needed." | ||
| 75 | input Hash hash; | ||
| 76 | input KeyEq keyEq; | ||
| 77 | input Integer bucketCount = 13; | ||
| 78 | output UnorderedSet<T> set; | ||
| 79 | protected | ||
| 80 | Mutable<array<list<T>>> buckets; | ||
| 81 | algorithm | ||
| 82 | 448986 | buckets := Mutable.create(arrayCreate(bucketCount, {})); | |
| 83 | 448986 | set := UNORDERED_SET(buckets, Mutable.create(0), hash, keyEq); | |
| 84 | end new; | ||
| 85 | |||
| 86 | function fromList | ||
| 87 | input list<T> elements; | ||
| 88 | input Hash hash; | ||
| 89 | input KeyEq keyEq; | ||
| 90 | output UnorderedSet<T> set; | ||
| 91 | algorithm | ||
| 92 | 192462 | set := new<T>(hash, keyEq, Util.nextPrime(listLength(elements))); | |
| 93 | |||
| 94 |
2/2✓ Branch 0 taken 712902 times.
✓ Branch 1 taken 192462 times.
|
905364 | for e in elements loop |
| 95 | 712902 | add(e, set); | |
| 96 | end for; | ||
| 97 | end fromList; | ||
| 98 | |||
| 99 | function copy | ||
| 100 | "Returns a copy of the given set." | ||
| 101 | input UnorderedSet<T> set; | ||
| 102 | output UnorderedSet<T> outSet; | ||
| 103 | algorithm | ||
| 104 | 13494 | outSet := UNORDERED_SET( | |
| 105 | Mutable.create(arrayCopy(Mutable.access(set.buckets))), | ||
| 106 | Mutable.create(Mutable.access(set.size)), | ||
| 107 | set.hashFn, | ||
| 108 | set.eqFn | ||
| 109 | ); | ||
| 110 | end copy; | ||
| 111 | |||
| 112 | function add | ||
| 113 | "Adds a key to the set unless the key already exists in the set, in which | ||
| 114 | case nothing is done. Might trigger a rehash." | ||
| 115 | input T key; | ||
| 116 | input UnorderedSet<T> set; | ||
| 117 | output Boolean added; | ||
| 118 | protected | ||
| 119 | Integer hash; | ||
| 120 | Option<T> okey; | ||
| 121 | algorithm | ||
| 122 | 1299083 | (okey, hash) := find(key, set); | |
| 123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1299083 times.
|
1299083 | added := isNone(okey); |
| 124 |
2/2✓ Branch 0 taken 294617 times.
✓ Branch 1 taken 1004466 times.
|
1299083 | if added then |
| 125 | 1004466 | addKey(key, hash, set); | |
| 126 | end if; | ||
| 127 | end add; | ||
| 128 | |||
| 129 | function addNew | ||
| 130 | "Adds a key to the set without checking if it already exists. Faster than | ||
| 131 | add since it doesn't need to check if the key exists, but will lead to | ||
| 132 | duplicate keys if it actually does exist in the set already. Might trigger | ||
| 133 | a rehash." | ||
| 134 | input T key; | ||
| 135 | input UnorderedSet<T> set; | ||
| 136 | protected | ||
| 137 | Hash hashfn = set.hashFn; | ||
| 138 | Integer hash; | ||
| 139 | algorithm | ||
| 140 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
|
92 | hash := intMod(hashfn(key), arrayLength(Mutable.access(set.buckets))); |
| 141 | 46 | addKey(key, hash, set); | |
| 142 | end addNew; | ||
| 143 | |||
| 144 | function addUnique | ||
| 145 | "Adds a key to the set, but fails if the key already exists. | ||
| 146 | Might trigger a rehash." | ||
| 147 | input T key; | ||
| 148 | input UnorderedSet<T> set; | ||
| 149 | protected | ||
| 150 | Integer hash; | ||
| 151 | algorithm | ||
| 152 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 2560 times.
✓ Branch 3 taken 2560 times.
✗ Branch 4 not taken.
|
2560 | (NONE(), hash) := find(key, set); |
| 153 | 2560 | addKey(key, hash, set); | |
| 154 | end addUnique; | ||
| 155 | |||
| 156 | function remove | ||
| 157 | "Removes a key from the set. Returns true if the key existed in the set and | ||
| 158 | was removed, or false if the key did not exist in the set. | ||
| 159 | |||
| 160 | Will not trigger a rehash, so rehash must be called manually if shrinking | ||
| 161 | the set is desirable (probably not a good idea unless the load factor is | ||
| 162 | very low, i.e. less than 0.25 or so)." | ||
| 163 | input T key; | ||
| 164 | input UnorderedSet<T> set; | ||
| 165 | output Boolean removed; | ||
| 166 | protected | ||
| 167 | array<list<T>> buckets = Mutable.access(set.buckets); | ||
| 168 | Hash hashfn = set.hashFn; | ||
| 169 | KeyEq eqfn = set.eqFn; | ||
| 170 | Integer hash; | ||
| 171 | list<T> bucket; | ||
| 172 | Option<T> okey; | ||
| 173 | algorithm | ||
| 174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34341 times.
|
34341 | hash := intMod(hashfn(key), arrayLength(buckets)); |
| 175 | 34341 | bucket := arrayGet(buckets, hash + 1); | |
| 176 | |||
| 177 | 34341 | (bucket, okey) := List.deleteMemberOnTrue(key, bucket, eqfn); | |
| 178 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 34341 times.
✓ Branch 2 taken 262 times.
✓ Branch 3 taken 34079 times.
|
34341 | removed := isSome(okey); |
| 179 | |||
| 180 | if removed then | ||
| 181 | arrayUpdateNoBoundsChecking(buckets, hash + 1, bucket); | ||
| 182 | 262 | Mutable.update(set.size, Mutable.access(set.size) - 1); | |
| 183 | end if; | ||
| 184 | end remove; | ||
| 185 | |||
| 186 | function get | ||
| 187 | "Returns SOME(key) if the key exists in the set, otherwise NONE()." | ||
| 188 | input T key; | ||
| 189 | input UnorderedSet<T> set; | ||
| 190 | output Option<T> outKey; | ||
| 191 | algorithm | ||
| 192 | 30 | outKey := find(key, set); | |
| 193 | end get; | ||
| 194 | |||
| 195 | function getOrFail | ||
| 196 | "Returns a key if it exists in the set, otherwise fails." | ||
| 197 | input T key; | ||
| 198 | input UnorderedSet<T> set; | ||
| 199 | output T outKey; | ||
| 200 | protected | ||
| 201 | Option<T> okey; | ||
| 202 | algorithm | ||
| 203 | ✗ | okey := find(key, set); | |
| 204 | ✗ | SOME(outKey) := okey; | |
| 205 | end getOrFail; | ||
| 206 | |||
| 207 | function contains | ||
| 208 | "Returns whether the given key exists in the set or not." | ||
| 209 | input T key; | ||
| 210 | input UnorderedSet<T> set; | ||
| 211 | output Boolean res; | ||
| 212 | algorithm | ||
| 213 |
3/4✗ Branch 1 not taken.
✓ Branch 2 taken 5726227 times.
✓ Branch 5 taken 664476 times.
✓ Branch 6 taken 5061751 times.
|
5726227 | res := isSome(find(key, set)); |
| 214 | end contains; | ||
| 215 | |||
| 216 | function first | ||
| 217 | "Returns the first element in the set, or fails if the set is empty. | ||
| 218 | Since the set is unordered there isn't really any 'first' element though, | ||
| 219 | it will just return the first element in the first non-empty bucket." | ||
| 220 | input UnorderedSet<T> set; | ||
| 221 | output T val; | ||
| 222 | algorithm | ||
| 223 |
1/2✓ Branch 2 taken 11861 times.
✗ Branch 3 not taken.
|
13701 | for b in Mutable.access(set.buckets) loop |
| 224 |
2/2✓ Branch 0 taken 1840 times.
✓ Branch 1 taken 10021 times.
|
11861 | if not listEmpty(b) then |
| 225 | 1840 | val := listHead(b); | |
| 226 | 1840 | return; | |
| 227 | end if; | ||
| 228 | end for; | ||
| 229 | |||
| 230 | ✗ | fail(); | |
| 231 | end first; | ||
| 232 | |||
| 233 | function isEqual | ||
| 234 | "Returns true if the sets have the same size and contain the same elements, | ||
| 235 | otherwise false." | ||
| 236 | input UnorderedSet<T> set1; | ||
| 237 | input UnorderedSet<T> set2; | ||
| 238 | output Boolean equal = true; | ||
| 239 | algorithm | ||
| 240 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
|
240 | if Mutable.access(set1.size) <> Mutable.access(set2.size) then |
| 241 | equal := false; | ||
| 242 | ✗ | return; | |
| 243 | end if; | ||
| 244 | |||
| 245 |
2/2✓ Branch 2 taken 736 times.
✓ Branch 3 taken 240 times.
|
1216 | for b in Mutable.access(set1.buckets) loop |
| 246 |
2/2✓ Branch 0 taken 640 times.
✓ Branch 1 taken 736 times.
|
1376 | for k in b loop |
| 247 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 640 times.
|
640 | if not contains(k, set2) then |
| 248 | equal := false; | ||
| 249 | ✗ | return; | |
| 250 | end if; | ||
| 251 | end for; | ||
| 252 | end for; | ||
| 253 | end isEqual; | ||
| 254 | |||
| 255 | function toList | ||
| 256 | "Returns the elements in the set as a list in no particular order." | ||
| 257 | input UnorderedSet<T> set; | ||
| 258 | output list<T> outList = {}; | ||
| 259 | algorithm | ||
| 260 |
2/2✓ Branch 2 taken 1086616 times.
✓ Branch 3 taken 210287 times.
|
1507190 | for b in Mutable.access(set.buckets) loop |
| 261 |
2/2✓ Branch 1 taken 534782 times.
✓ Branch 2 taken 1086616 times.
|
1621398 | for k in b loop |
| 262 | outList := k :: outList; | ||
| 263 | end for; | ||
| 264 | end for; | ||
| 265 | end toList; | ||
| 266 | |||
| 267 | function toArray | ||
| 268 | "Returns the elements in the set as an array in no particular order." | ||
| 269 | input UnorderedSet<T> set; | ||
| 270 | output array<T> outArray; | ||
| 271 | protected | ||
| 272 | T dummy = dummy; // Fool the compiler into thinking dummy is initialized. | ||
| 273 | Integer i = 1; | ||
| 274 | algorithm | ||
| 275 | 16467 | outArray := arrayCreateNoInit(Mutable.access(set.size), dummy); | |
| 276 | |||
| 277 |
2/2✓ Branch 2 taken 197142 times.
✓ Branch 3 taken 16467 times.
|
230076 | for b in Mutable.access(set.buckets) loop |
| 278 |
2/2✓ Branch 0 taken 26465 times.
✓ Branch 1 taken 197142 times.
|
223607 | for k in b loop |
| 279 | arrayUpdateNoBoundsChecking(outArray, i, k); | ||
| 280 | 26465 | i := i + 1; | |
| 281 | end for; | ||
| 282 | end for; | ||
| 283 | end toArray; | ||
| 284 | |||
| 285 | function fold<FT> | ||
| 286 | "Folds over the keys in the set." | ||
| 287 | input UnorderedSet<T> set; | ||
| 288 | input FoldFn fn; | ||
| 289 | input FT startValue; | ||
| 290 | output FT result = startValue; | ||
| 291 | |||
| 292 | partial function FoldFn | ||
| 293 | input T key; | ||
| 294 | input output FT arg; | ||
| 295 | end FoldFn; | ||
| 296 | algorithm | ||
| 297 |
2/2✓ Branch 2 taken 225992 times.
✓ Branch 3 taken 17384 times.
|
260760 | for b in Mutable.access(set.buckets) loop |
| 298 |
2/2✓ Branch 0 taken 8518 times.
✓ Branch 1 taken 225992 times.
|
234510 | for k in b loop |
| 299 |
2/2✓ Branch 0 taken 4721 times.
✓ Branch 1 taken 3797 times.
|
8518 | result := fn(k, result); |
| 300 | end for; | ||
| 301 | end for; | ||
| 302 | end fold; | ||
| 303 | |||
| 304 | /* | ||
| 305 | function map<OT> | ||
| 306 | "Applies a function to all keys in the given set and returns a new set | ||
| 307 | with the new keys." | ||
| 308 | input UnorderedSet<T> set; | ||
| 309 | input MapFn fn; | ||
| 310 | input OutHash hashFn; | ||
| 311 | input OutKeyEq eqFn; | ||
| 312 | output UnorderedSet<OT> outSet; | ||
| 313 | |||
| 314 | partial function MapFn | ||
| 315 | input T key; | ||
| 316 | output OT outKey; | ||
| 317 | end MapFn; | ||
| 318 | partial function OutHash | ||
| 319 | input OT key; | ||
| 320 | input Integer mod; | ||
| 321 | output Integer hash; | ||
| 322 | end OutHash; | ||
| 323 | partial function OutKeyEq | ||
| 324 | input OT key1; | ||
| 325 | input OT key2; | ||
| 326 | output Boolean equal; | ||
| 327 | end OutKeyEq; | ||
| 328 | algorithm | ||
| 329 | outSet := new<OT>(hashFn, eqFn, Util.nextPrime(Mutable.access(set.size))); | ||
| 330 | for b in Mutable.access(set.buckets) loop | ||
| 331 | for k in b loop | ||
| 332 | add(fn(k), outSet); | ||
| 333 | end for; | ||
| 334 | end for; | ||
| 335 | end map; | ||
| 336 | */ | ||
| 337 | |||
| 338 | function selfMap | ||
| 339 | "Applies a self-mapping function to all keys in the given set and returns a new set | ||
| 340 | with the new keys of same type as input set." | ||
| 341 | input UnorderedSet<T> set; | ||
| 342 | input MapFn fn; | ||
| 343 | output UnorderedSet<T> outSet = new<T>(set.hashFn, set.eqFn); | ||
| 344 | |||
| 345 | partial function MapFn | ||
| 346 | input output T key; | ||
| 347 | end MapFn; | ||
| 348 | algorithm | ||
| 349 |
2/2✓ Branch 2 taken 1807 times.
✓ Branch 3 taken 139 times.
|
2085 | for b in Mutable.access(set.buckets) loop |
| 350 |
2/2✓ Branch 0 taken 138 times.
✓ Branch 1 taken 1807 times.
|
1945 | for k in b loop |
| 351 |
1/2✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
|
138 | add(fn(k), outSet); |
| 352 | end for; | ||
| 353 | end for; | ||
| 354 | end selfMap; | ||
| 355 | |||
| 356 | function apply | ||
| 357 | "Applies function fn to all elements in set. | ||
| 358 | fn is expected to have side effects." | ||
| 359 | input UnorderedSet<T> set; | ||
| 360 | input ApplyFn fn; | ||
| 361 | |||
| 362 | partial function ApplyFn | ||
| 363 | input T key; | ||
| 364 | end ApplyFn; | ||
| 365 | algorithm | ||
| 366 | ✗ | for b in Mutable.access(set.buckets) loop | |
| 367 | ✗ | for k in b loop | |
| 368 | ✗ | fn(k); | |
| 369 | end for; | ||
| 370 | end for; | ||
| 371 | end apply; | ||
| 372 | |||
| 373 | function all | ||
| 374 | "Returns true if the given function returns true for all elements in the set, | ||
| 375 | otherwise false." | ||
| 376 | input UnorderedSet<T> set; | ||
| 377 | input PredFn fn; | ||
| 378 | output Boolean res; | ||
| 379 | |||
| 380 | partial function PredFn | ||
| 381 | input T key; | ||
| 382 | output Boolean res; | ||
| 383 | end PredFn; | ||
| 384 | algorithm | ||
| 385 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3359 times.
|
3359 | if isEmpty(set) then |
| 386 | res := true; | ||
| 387 | ✗ | return; | |
| 388 | end if; | ||
| 389 | |||
| 390 |
2/2✓ Branch 2 taken 28523 times.
✓ Branch 3 taken 3283 times.
|
35165 | for b in Mutable.access(set.buckets) loop |
| 391 |
2/2✓ Branch 0 taken 5745 times.
✓ Branch 1 taken 28447 times.
|
34192 | for k in b loop |
| 392 |
3/4✓ Branch 0 taken 5745 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 76 times.
✓ Branch 5 taken 5669 times.
|
5745 | if not fn(k) then |
| 393 | res := false; | ||
| 394 | 76 | return; | |
| 395 | end if; | ||
| 396 | end for; | ||
| 397 | end for; | ||
| 398 | |||
| 399 | res := true; | ||
| 400 | end all; | ||
| 401 | |||
| 402 | function any | ||
| 403 | "Returns true if the given function returns true for any elements in the set, | ||
| 404 | otherwise false." | ||
| 405 | input UnorderedSet<T> set; | ||
| 406 | input PredFn fn; | ||
| 407 | output Boolean res; | ||
| 408 | |||
| 409 | partial function PredFn | ||
| 410 | input T key; | ||
| 411 | output Boolean res; | ||
| 412 | end PredFn; | ||
| 413 | algorithm | ||
| 414 |
2/2✓ Branch 1 taken 127 times.
✓ Branch 2 taken 187 times.
|
314 | if isEmpty(set) then |
| 415 | res := false; | ||
| 416 | 127 | return; | |
| 417 | end if; | ||
| 418 | |||
| 419 |
2/2✓ Branch 2 taken 1697 times.
✓ Branch 3 taken 7 times.
|
1891 | for b in Mutable.access(set.buckets) loop |
| 420 |
2/2✓ Branch 0 taken 187 times.
✓ Branch 1 taken 1517 times.
|
1704 | for k in b loop |
| 421 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 187 times.
✓ Branch 4 taken 180 times.
✓ Branch 5 taken 7 times.
|
187 | if fn(k) then |
| 422 | res := true; | ||
| 423 | 180 | return; | |
| 424 | end if; | ||
| 425 | end for; | ||
| 426 | end for; | ||
| 427 | |||
| 428 | res := false; | ||
| 429 | end any; | ||
| 430 | |||
| 431 | function none | ||
| 432 | "Returns true if the given function returns true for none of the elements in | ||
| 433 | the set, otherwise false." | ||
| 434 | input UnorderedSet<T> set; | ||
| 435 | input PredFn fn; | ||
| 436 | output Boolean res; | ||
| 437 | |||
| 438 | partial function PredFn | ||
| 439 | input T key; | ||
| 440 | output Boolean res; | ||
| 441 | end PredFn; | ||
| 442 | algorithm | ||
| 443 | ✗ | if isEmpty(set) then | |
| 444 | res := true; | ||
| 445 | ✗ | return; | |
| 446 | end if; | ||
| 447 | |||
| 448 | ✗ | for b in Mutable.access(set.buckets) loop | |
| 449 | ✗ | for k in b loop | |
| 450 | ✗ | if fn(k) then | |
| 451 | res := false; | ||
| 452 | ✗ | return; | |
| 453 | end if; | ||
| 454 | end for; | ||
| 455 | end for; | ||
| 456 | |||
| 457 | res := true; | ||
| 458 | end none; | ||
| 459 | |||
| 460 | function filterOnFalse | ||
| 461 | "Returns new set containing elements for which fn returns false" | ||
| 462 | input UnorderedSet<T> set; | ||
| 463 | input PredFn fn; | ||
| 464 | output UnorderedSet<T> falseSet = new<T>(set.hashFn, set.eqFn); | ||
| 465 | |||
| 466 | partial function PredFn | ||
| 467 | input T key; | ||
| 468 | output Boolean res; | ||
| 469 | end PredFn; | ||
| 470 | algorithm | ||
| 471 |
2/2✓ Branch 2 taken 46202 times.
✓ Branch 3 taken 3554 times.
|
53310 | for b in Mutable.access(set.buckets) loop |
| 472 |
2/2✓ Branch 0 taken 575 times.
✓ Branch 1 taken 46202 times.
|
46777 | for k in b loop |
| 473 |
2/4✓ Branch 0 taken 575 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 575 times.
✗ Branch 5 not taken.
|
575 | if not fn(k) then |
| 474 | 575 | add(k, falseSet); | |
| 475 | end if; | ||
| 476 | end for; | ||
| 477 | end for; | ||
| 478 | end filterOnFalse; | ||
| 479 | |||
| 480 | function splitOnTrue | ||
| 481 | "Splits a set into two subsets depending on predicate function." | ||
| 482 | input UnorderedSet<T> set; | ||
| 483 | input PredFn fn; | ||
| 484 | output UnorderedSet<T> trueSet = new<T>(set.hashFn, set.eqFn); | ||
| 485 | output UnorderedSet<T> falseSet = new<T>(set.hashFn, set.eqFn); | ||
| 486 | |||
| 487 | partial function PredFn | ||
| 488 | input T key; | ||
| 489 | output Boolean res; | ||
| 490 | end PredFn; | ||
| 491 | algorithm | ||
| 492 |
2/2✓ Branch 2 taken 46202 times.
✓ Branch 3 taken 3554 times.
|
53310 | for b in Mutable.access(set.buckets) loop |
| 493 |
2/2✓ Branch 0 taken 575 times.
✓ Branch 1 taken 46202 times.
|
46777 | for k in b loop |
| 494 |
3/4✓ Branch 0 taken 575 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 501 times.
✓ Branch 5 taken 74 times.
|
1076 | add(k, if fn(k) then trueSet else falseSet); |
| 495 | end for; | ||
| 496 | end for; | ||
| 497 | end splitOnTrue; | ||
| 498 | |||
| 499 | function size | ||
| 500 | "Returns the number of elements the set contains." | ||
| 501 | input UnorderedSet<T> set; | ||
| 502 | output Integer s = Mutable.access(set.size); | ||
| 503 | end size; | ||
| 504 | |||
| 505 | function isEmpty | ||
| 506 | "Returns whether the set is empty or not." | ||
| 507 | input UnorderedSet<T> set; | ||
| 508 | output Boolean empty = Mutable.access(set.size) == 0; | ||
| 509 | end isEmpty; | ||
| 510 | |||
| 511 | function bucketCount | ||
| 512 | "Returns the number of buckets used by the set." | ||
| 513 | input UnorderedSet<T> set; | ||
| 514 | output Integer count = arrayLength(Mutable.access(set.buckets)); | ||
| 515 | end bucketCount; | ||
| 516 | |||
| 517 | function loadFactor | ||
| 518 | "Returns the load factor, defined as the number of entries divided by the | ||
| 519 | number of buckets." | ||
| 520 | input UnorderedSet<T> set; | ||
| 521 | output Real load = intReal(Mutable.access(set.size)) / bucketCount(set); | ||
| 522 | end loadFactor; | ||
| 523 | |||
| 524 | function rehash | ||
| 525 | "Changes the number of buckets to an appropriate number based on the number | ||
| 526 | of elements in the set and rehashes all the keys." | ||
| 527 | input UnorderedSet<T> set; | ||
| 528 | protected | ||
| 529 | array<list<T>> old_buckets = Mutable.access(set.buckets); | ||
| 530 | array<list<T>> new_buckets; | ||
| 531 | Integer bucket_count, hash; | ||
| 532 | Hash hashfn = set.hashFn; | ||
| 533 | algorithm | ||
| 534 | // Make a new bucket array. | ||
| 535 | 3336 | bucket_count := Util.nextPrime(Mutable.access(set.size) * 2); | |
| 536 | 3336 | new_buckets := arrayCreate(bucket_count, {}); | |
| 537 | |||
| 538 | // Rehash all the keys in the old buckets and add them to the new. | ||
| 539 |
2/2✓ Branch 1 taken 110981 times.
✓ Branch 2 taken 3336 times.
|
114317 | for b in old_buckets loop |
| 540 |
2/2✓ Branch 0 taken 114317 times.
✓ Branch 1 taken 110981 times.
|
225298 | for k in b loop |
| 541 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 114317 times.
|
114317 | hash := intMod(hashfn(k), bucket_count); |
| 542 | 228634 | arrayUpdate(new_buckets, hash + 1, k :: arrayGet(new_buckets, hash + 1)); | |
| 543 | end for; | ||
| 544 | end for; | ||
| 545 | |||
| 546 | // Replace the old bucket array with the new one. | ||
| 547 | 3336 | Mutable.update(set.buckets, new_buckets); | |
| 548 | end rehash; | ||
| 549 | |||
| 550 | function toString | ||
| 551 | input UnorderedSet<T> set; | ||
| 552 | input StringFn stringFn; | ||
| 553 | input String delimiter = "\n"; | ||
| 554 | output String str; | ||
| 555 | |||
| 556 | partial function StringFn | ||
| 557 | input T key; | ||
| 558 | output String str; | ||
| 559 | end StringFn; | ||
| 560 | algorithm | ||
| 561 |
5/6✓ Branch 1 taken 7248 times.
✓ Branch 2 taken 748 times.
✓ Branch 4 taken 7248 times.
✓ Branch 5 taken 748 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7248 times.
|
15992 | str := stringDelimitList(list(stringFn(k) for k in toArray(set)), delimiter); |
| 562 | end toString; | ||
| 563 | |||
| 564 | function dump | ||
| 565 | "Prints the set to standard output using the given string function." | ||
| 566 | input UnorderedSet<T> set; | ||
| 567 | input StringFn stringFn; | ||
| 568 | |||
| 569 | partial function StringFn | ||
| 570 | input T key; | ||
| 571 | output String str; | ||
| 572 | end StringFn; | ||
| 573 | algorithm | ||
| 574 | ✗ | print(toString(set, stringFn)); | |
| 575 | ✗ | print("\n"); | |
| 576 | end dump; | ||
| 577 | |||
| 578 | function unique_list<T> | ||
| 579 | "Takes a list of elements and returns a list with duplicates removed, so that | ||
| 580 | each element in the new list is unique." | ||
| 581 | input list<T> inList; | ||
| 582 | input Hash hashFunc; | ||
| 583 | input KeyEq keyEqFunc; | ||
| 584 | output list<T> outList = if List.hasSeveralElements(inList) then toList(fromList(inList, hashFunc, keyEqFunc)) else inList; | ||
| 585 | end unique_list; | ||
| 586 | |||
| 587 | function union | ||
| 588 | "set1 U set2" | ||
| 589 | input UnorderedSet<T> set1; | ||
| 590 | input UnorderedSet<T> set2; | ||
| 591 | output UnorderedSet<T> set; | ||
| 592 | protected | ||
| 593 | Integer sz1, sz2, small_sz; | ||
| 594 | UnorderedSet<T> small_set; | ||
| 595 | algorithm | ||
| 596 | 32757 | sz1 := Mutable.access(set1.size); | |
| 597 | 32757 | sz2 := Mutable.access(set2.size); | |
| 598 | |||
| 599 |
2/2✓ Branch 0 taken 19038 times.
✓ Branch 1 taken 13719 times.
|
32757 | if sz1 > sz2 then |
| 600 | set := set1; | ||
| 601 | small_set := set2; | ||
| 602 | small_sz := sz2; | ||
| 603 | else | ||
| 604 | set := set2; | ||
| 605 | small_set := set1; | ||
| 606 | small_sz := sz1; | ||
| 607 | end if; | ||
| 608 | |||
| 609 |
2/2✓ Branch 0 taken 17545 times.
✓ Branch 1 taken 15212 times.
|
32757 | if small_sz > 0 then |
| 610 |
2/2✓ Branch 2 taken 30533 times.
✓ Branch 3 taken 15212 times.
|
60957 | for b in Mutable.access(small_set.buckets) loop |
| 611 |
2/2✓ Branch 0 taken 16241 times.
✓ Branch 1 taken 30533 times.
|
46774 | for k in b loop |
| 612 | 16241 | add(k, set); | |
| 613 | end for; | ||
| 614 | end for; | ||
| 615 | end if; | ||
| 616 | end union; | ||
| 617 | |||
| 618 | function union_list | ||
| 619 | "set1 U set2 U set3 ... U setn | ||
| 620 | pass the hash and equality function if the list is empty" | ||
| 621 | input list<UnorderedSet<T>> set_lst; | ||
| 622 | input Hash hashFunc; | ||
| 623 | input KeyEq keyEqFunc; | ||
| 624 | output UnorderedSet<T> set; | ||
| 625 | protected | ||
| 626 | list<UnorderedSet<T>> rest; | ||
| 627 | algorithm | ||
| 628 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 14646 times.
|
14667 | if listEmpty(set_lst) then |
| 629 | 21 | set := new<T>(hashFunc, keyEqFunc); | |
| 630 | else | ||
| 631 | // determine the biggest set to make sure we always add to it | ||
| 632 | 14646 | (set, rest) := extractFromLst(set_lst, intGt); | |
| 633 |
2/2✓ Branch 0 taken 15833 times.
✓ Branch 1 taken 14646 times.
|
30479 | for tmp in rest loop |
| 634 | 15833 | set := union(set, tmp); | |
| 635 | end for; | ||
| 636 | end if; | ||
| 637 | end union_list; | ||
| 638 | |||
| 639 | function merge | ||
| 640 | "set1 U set2 | ||
| 641 | like union, but always merges the second into the first set" | ||
| 642 | input output UnorderedSet<T> set1; | ||
| 643 | input UnorderedSet<T> set2; | ||
| 644 | algorithm | ||
| 645 |
2/2✓ Branch 1 taken 27 times.
✓ Branch 2 taken 59 times.
|
86 | if isEmpty(set2) then |
| 646 | 27 | return; | |
| 647 | end if; | ||
| 648 | |||
| 649 |
2/2✓ Branch 2 taken 767 times.
✓ Branch 3 taken 59 times.
|
885 | for b in Mutable.access(set2.buckets) loop |
| 650 |
2/2✓ Branch 0 taken 59 times.
✓ Branch 1 taken 767 times.
|
826 | for k in b loop |
| 651 | 59 | add(k, set1); | |
| 652 | end for; | ||
| 653 | end for; | ||
| 654 | end merge; | ||
| 655 | |||
| 656 | function intersection | ||
| 657 | "set1 n set2" | ||
| 658 | input UnorderedSet<T> set1; | ||
| 659 | input UnorderedSet<T> set2; | ||
| 660 | output UnorderedSet<T> set; | ||
| 661 | protected | ||
| 662 | UnorderedSet<T> set_small, set_big; | ||
| 663 | list<T> acc = {}; | ||
| 664 | algorithm | ||
| 665 | ✗ | if Mutable.access(set1.size) > Mutable.access(set2.size) then | |
| 666 | set_small := set2; | ||
| 667 | set_big := set1; | ||
| 668 | else | ||
| 669 | set_small := set1; | ||
| 670 | set_big := set2; | ||
| 671 | end if; | ||
| 672 | |||
| 673 | ✗ | if not isEmpty(set_small) then | |
| 674 | ✗ | for b in Mutable.access(set_small.buckets) loop | |
| 675 | ✗ | for k in b loop | |
| 676 | ✗ | if contains(k, set_big) then | |
| 677 | acc := k :: acc; | ||
| 678 | end if; | ||
| 679 | end for; | ||
| 680 | end for; | ||
| 681 | end if; | ||
| 682 | |||
| 683 | ✗ | set := fromList(acc, set1.hashFn, set1.eqFn); | |
| 684 | end intersection; | ||
| 685 | |||
| 686 | function intersection_list | ||
| 687 | "set1 n set2 n set3 ... n setn | ||
| 688 | pass the hash and equality function to create an empty list" | ||
| 689 | input list<UnorderedSet<T>> set_lst; | ||
| 690 | input Hash hashFunc; | ||
| 691 | input KeyEq keyEqFunc; | ||
| 692 | output UnorderedSet<T> set; | ||
| 693 | protected | ||
| 694 | UnorderedSet<T> set_small; | ||
| 695 | list<UnorderedSet<T>> rest; | ||
| 696 | list<T> acc = {}; | ||
| 697 | algorithm | ||
| 698 | ✗ | if not listEmpty(set_lst) then | |
| 699 | // determine the smallest set to make sure we traverse the fewest elements | ||
| 700 | ✗ | (set_small, rest) := extractFromLst(set_lst, intLt); | |
| 701 | ✗ | for b in Mutable.access(set_small.buckets) loop | |
| 702 | ✗ | for k in b loop | |
| 703 | ✗ | if List.all(rest, function contains(key = k)) then | |
| 704 | acc := k :: acc; | ||
| 705 | end if; | ||
| 706 | end for; | ||
| 707 | end for; | ||
| 708 | end if; | ||
| 709 | ✗ | set := fromList(acc, hashFunc, keyEqFunc); | |
| 710 | end intersection_list; | ||
| 711 | |||
| 712 | function difference_list | ||
| 713 | "lst1 / lst2, assuming unique lists" | ||
| 714 | input list<T> inList1; | ||
| 715 | input list<T> inList2; | ||
| 716 | input Hash hashFunc; | ||
| 717 | input KeyEq keyEqFunc; | ||
| 718 | output list<T> acc = {}; | ||
| 719 | protected | ||
| 720 | UnorderedSet<T> set2; | ||
| 721 | list<T> lst1 = inList1, lst2 = inList2; | ||
| 722 | algorithm | ||
| 723 | // remove common start, since this seems to be very common | ||
| 724 |
6/10✓ Branch 0 taken 9899 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6969 times.
✓ Branch 3 taken 2930 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6969 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 14 taken 1332 times.
✓ Branch 15 taken 5637 times.
|
9899 | while not (listEmpty(lst1) or listEmpty(lst2)) and keyEqFunc(listHead(lst1), listHead(lst2)) loop |
| 725 | 1332 | lst1 := listRest(lst1); | |
| 726 | 1332 | lst2 := listRest(lst2); | |
| 727 | end while; | ||
| 728 | |||
| 729 | // {} - B = {} | ||
| 730 | // A - {} = A | ||
| 731 |
3/4✓ Branch 0 taken 8567 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2930 times.
✓ Branch 3 taken 5637 times.
|
8567 | if listEmpty(lst1) or listEmpty(lst2) then |
| 732 | acc := lst1; | ||
| 733 | 2930 | return; | |
| 734 | end if; | ||
| 735 | |||
| 736 | 5637 | set2 := fromList(lst2, hashFunc, keyEqFunc); | |
| 737 |
2/2✓ Branch 0 taken 36100 times.
✓ Branch 1 taken 5637 times.
|
41737 | for k in lst1 loop |
| 738 |
2/2✓ Branch 1 taken 26389 times.
✓ Branch 2 taken 9711 times.
|
36100 | if not contains(k, set2) then |
| 739 | acc := k :: acc; | ||
| 740 | end if; | ||
| 741 | end for; | ||
| 742 | end difference_list; | ||
| 743 | |||
| 744 | function difference_list_set | ||
| 745 | "difference_list(inList1, inList2) with set2 = fromList(inList2) built by | ||
| 746 | the caller, for reducing several lists by the same inList2." | ||
| 747 | input list<T> inList1; | ||
| 748 | input list<T> inList2; | ||
| 749 | input UnorderedSet<T> set2; | ||
| 750 | output list<T> acc = {}; | ||
| 751 | protected | ||
| 752 | list<T> lst1 = inList1, lst2 = inList2; | ||
| 753 | KeyEq eqFn = set2.eqFn; | ||
| 754 | algorithm | ||
| 755 |
7/10✓ Branch 0 taken 742 times.
✓ Branch 1 taken 149 times.
✓ Branch 2 taken 682 times.
✓ Branch 3 taken 60 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 682 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 14 taken 613 times.
✓ Branch 15 taken 69 times.
|
891 | while not (listEmpty(lst1) or listEmpty(lst2)) and eqFn(listHead(lst1), listHead(lst2)) loop |
| 756 | 613 | lst1 := listRest(lst1); | |
| 757 | 613 | lst2 := listRest(lst2); | |
| 758 | end while; | ||
| 759 | |||
| 760 |
4/4✓ Branch 0 taken 129 times.
✓ Branch 1 taken 149 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 60 times.
|
278 | if listEmpty(lst1) or listEmpty(lst2) then |
| 761 | acc := lst1; | ||
| 762 | 209 | return; | |
| 763 | end if; | ||
| 764 | |||
| 765 |
2/2✓ Branch 0 taken 200 times.
✓ Branch 1 taken 69 times.
|
269 | for k in lst1 loop |
| 766 |
2/2✓ Branch 1 taken 109 times.
✓ Branch 2 taken 91 times.
|
200 | if not contains(k, set2) then |
| 767 | acc := k :: acc; | ||
| 768 | end if; | ||
| 769 | end for; | ||
| 770 | end difference_list_set; | ||
| 771 | |||
| 772 | function equal_list | ||
| 773 | "Takes two lists and returns true if they contain the same elements. | ||
| 774 | Ignores duplicates." | ||
| 775 | input list<T> inList1; | ||
| 776 | input list<T> inList2; | ||
| 777 | input Hash hashFunc; | ||
| 778 | input KeyEq keyEqFunc; | ||
| 779 | output Boolean b = false; | ||
| 780 | protected | ||
| 781 | UnorderedSet<T> set1 = fromList(inList1, hashFunc, keyEqFunc); | ||
| 782 | UnorderedSet<T> set2 = fromList(inList2, hashFunc, keyEqFunc); | ||
| 783 | algorithm | ||
| 784 |
1/2✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
|
70 | if Mutable.access(set1.size) <> Mutable.access(set2.size) then |
| 785 | ✗ | return; | |
| 786 | end if; | ||
| 787 | |||
| 788 |
2/2✓ Branch 0 taken 1161 times.
✓ Branch 1 taken 56 times.
|
1217 | for k in inList1 loop |
| 789 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1147 times.
|
1161 | if not contains(k, set2) then |
| 790 | 14 | return; | |
| 791 | end if; | ||
| 792 | end for; | ||
| 793 | b := true; | ||
| 794 | end equal_list; | ||
| 795 | |||
| 796 | function difference | ||
| 797 | "set1 / set2" | ||
| 798 | input UnorderedSet<T> set1; | ||
| 799 | input UnorderedSet<T> set2; | ||
| 800 | output UnorderedSet<T> set; | ||
| 801 | protected | ||
| 802 | list<T> acc = {}; | ||
| 803 | algorithm | ||
| 804 |
2/2✓ Branch 1 taken 17 times.
✓ Branch 2 taken 109 times.
|
126 | if not isEmpty(set1) then |
| 805 |
2/2✓ Branch 2 taken 34 times.
✓ Branch 3 taken 17 times.
|
68 | for b in Mutable.access(set1.buckets) loop |
| 806 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 34 times.
|
61 | for k in b loop |
| 807 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | if not contains(k, set2) then |
| 808 | acc := k :: acc; | ||
| 809 | end if; | ||
| 810 | end for; | ||
| 811 | end for; | ||
| 812 | end if; | ||
| 813 | |||
| 814 | 126 | set := fromList(acc, set1.hashFn, set1.eqFn); | |
| 815 | end difference; | ||
| 816 | |||
| 817 | function sym_difference | ||
| 818 | "set1 / set2 U set2 / set1" | ||
| 819 | input UnorderedSet<T> set1; | ||
| 820 | input UnorderedSet<T> set2; | ||
| 821 | output UnorderedSet<T> set; | ||
| 822 | protected | ||
| 823 | list<T> acc = {}; | ||
| 824 | algorithm | ||
| 825 |
2/2✓ Branch 1 taken 140 times.
✓ Branch 2 taken 147 times.
|
287 | if not isEmpty(set1) then |
| 826 |
2/2✓ Branch 2 taken 280 times.
✓ Branch 3 taken 140 times.
|
560 | for b in Mutable.access(set1.buckets) loop |
| 827 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 280 times.
|
424 | for k in b loop |
| 828 |
2/2✓ Branch 1 taken 94 times.
✓ Branch 2 taken 50 times.
|
144 | if not contains(k, set2) then |
| 829 | acc := k :: acc; | ||
| 830 | end if; | ||
| 831 | end for; | ||
| 832 | end for; | ||
| 833 | end if; | ||
| 834 | |||
| 835 |
2/2✓ Branch 1 taken 187 times.
✓ Branch 2 taken 100 times.
|
287 | if not isEmpty(set2) then |
| 836 |
2/2✓ Branch 2 taken 374 times.
✓ Branch 3 taken 187 times.
|
748 | for b in Mutable.access(set2.buckets) loop |
| 837 |
2/2✓ Branch 0 taken 216 times.
✓ Branch 1 taken 374 times.
|
590 | for k in b loop |
| 838 |
2/2✓ Branch 1 taken 166 times.
✓ Branch 2 taken 50 times.
|
216 | if not contains(k, set1) then |
| 839 | acc := k :: acc; | ||
| 840 | end if; | ||
| 841 | end for; | ||
| 842 | end for; | ||
| 843 | end if; | ||
| 844 | |||
| 845 | 287 | set := fromList(acc, set1.hashFn, set1.eqFn); | |
| 846 | end sym_difference; | ||
| 847 | |||
| 848 | function isDisjoint | ||
| 849 | input UnorderedSet<T> set1; | ||
| 850 | input UnorderedSet<T> set2; | ||
| 851 | output Boolean b = true; | ||
| 852 | protected | ||
| 853 | UnorderedSet<T> set_small, set_big; | ||
| 854 | algorithm | ||
| 855 |
1/2✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
|
19 | if Mutable.access(set1.size) > Mutable.access(set2.size) then |
| 856 | set_small := set2; | ||
| 857 | set_big := set1; | ||
| 858 | else | ||
| 859 | set_small := set1; | ||
| 860 | set_big := set2; | ||
| 861 | end if; | ||
| 862 | |||
| 863 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | if not isEmpty(set_small) then |
| 864 | ✗ | for buckets in Mutable.access(set_small.buckets) loop | |
| 865 | ✗ | for k in buckets loop | |
| 866 | ✗ | if contains(k, set_big) then | |
| 867 | b := false; | ||
| 868 | ✗ | return; | |
| 869 | end if; | ||
| 870 | end for; | ||
| 871 | end for; | ||
| 872 | end if; | ||
| 873 | end isDisjoint; | ||
| 874 | |||
| 875 | protected | ||
| 876 | function find | ||
| 877 | "Tries to find a key in the set, returning the key as an option, and the | ||
| 878 | key's hash." | ||
| 879 | input T key; | ||
| 880 | input UnorderedSet<T> set; | ||
| 881 | output Option<T> outKey = NONE(); | ||
| 882 | output Integer hash; | ||
| 883 | protected | ||
| 884 | Hash hashfn = set.hashFn; | ||
| 885 | KeyEq eqfn = set.eqFn; | ||
| 886 | array<list<T>> buckets = Mutable.access(set.buckets); | ||
| 887 | list<T> bucket; | ||
| 888 | algorithm | ||
| 889 |
2/2✓ Branch 0 taken 4644 times.
✓ Branch 1 taken 12749483 times.
|
12754127 | hash := intMod(hashfn(key), arrayLength(buckets)); |
| 890 | 12754127 | bucket := arrayGet(buckets, hash + 1); | |
| 891 | |||
| 892 |
2/2✓ Branch 0 taken 3435302 times.
✓ Branch 1 taken 11130553 times.
|
14565855 | for k in bucket loop |
| 893 |
4/4✓ Branch 0 taken 4178 times.
✓ Branch 1 taken 3431124 times.
✓ Branch 4 taken 1623574 times.
✓ Branch 5 taken 1811728 times.
|
3435302 | if eqfn(k, key) then |
| 894 | outKey := SOME(k); | ||
| 895 | 1623574 | break; | |
| 896 | end if; | ||
| 897 | end for; | ||
| 898 | end find; | ||
| 899 | |||
| 900 | function addKey | ||
| 901 | "Adds a key to the set given its hash." | ||
| 902 | input T key; | ||
| 903 | input Integer hash; | ||
| 904 | input UnorderedSet<T> set; | ||
| 905 | protected | ||
| 906 | array<list<T>> buckets; | ||
| 907 | Integer h; | ||
| 908 | Hash hashfn; | ||
| 909 | algorithm | ||
| 910 |
2/2✓ Branch 1 taken 3336 times.
✓ Branch 2 taken 1003736 times.
|
1007072 | if loadFactor(set) > 1 then |
| 911 | // Rehash if the load factor is too high to keep performance up. | ||
| 912 | 3336 | rehash(set); | |
| 913 | 3336 | hashfn := set.hashFn; | |
| 914 | 3336 | buckets := Mutable.access(set.buckets); | |
| 915 | // The bucket count has changed so we need to rehash the key we're going | ||
| 916 | // to add too. | ||
| 917 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3336 times.
|
3336 | h := intMod(hashfn(key), arrayLength(buckets)); |
| 918 | else | ||
| 919 | 1003736 | buckets := Mutable.access(set.buckets); | |
| 920 | h := hash; | ||
| 921 | end if; | ||
| 922 | |||
| 923 | // Add the key to the bucket indicated by the hash. | ||
| 924 | 2014144 | arrayUpdate(buckets, h + 1, key :: arrayGet(buckets, h + 1)); | |
| 925 | // Update the size of the set. | ||
| 926 | 1007072 | Mutable.update(set.size, Mutable.access(set.size) + 1); | |
| 927 | end addKey; | ||
| 928 | |||
| 929 | function extractFromLst | ||
| 930 | "extracts a set from a list with smallest or biggest size | ||
| 931 | (use with intGt or intLt) | ||
| 932 | Note: input lst cannot be empty or else this fails!" | ||
| 933 | input list<UnorderedSet<T>> lst; | ||
| 934 | input size_compare func; | ||
| 935 | output UnorderedSet<T> single; | ||
| 936 | output list<UnorderedSet<T>> rest = {}; | ||
| 937 | protected | ||
| 938 | partial function size_compare | ||
| 939 | input Integer i1; | ||
| 940 | input Integer i2; | ||
| 941 | output Boolean b; | ||
| 942 | end size_compare; | ||
| 943 | Integer size; | ||
| 944 | list<UnorderedSet<T>> tmp_lst; | ||
| 945 | algorithm | ||
| 946 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14646 times.
|
14646 | single :: tmp_lst := lst; |
| 947 | 14646 | size := Mutable.access(single.size); | |
| 948 |
2/2✓ Branch 0 taken 15833 times.
✓ Branch 1 taken 14646 times.
|
30479 | for tmp in tmp_lst loop |
| 949 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 15833 times.
✓ Branch 6 taken 2095 times.
✓ Branch 7 taken 13738 times.
|
15833 | if func(Mutable.access(tmp.size), size) then |
| 950 | 2095 | size := Mutable.access(tmp.size); | |
| 951 | rest := single :: rest; | ||
| 952 | single := tmp; | ||
| 953 | else | ||
| 954 | rest := tmp :: rest; | ||
| 955 | end if; | ||
| 956 | end for; | ||
| 957 | end extractFromLst; | ||
| 958 | |||
| 959 | annotation(__OpenModelica_Interface="util"); | ||
| 960 | end UnorderedSet; | ||
| 961 |