/* * Copyright 2025 Magnus Madsen * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */pubmod MutHashMap {////// Represents a mutable hash map that preserves insertion order.////// Uses a hash table with separate chaining for collisions and a doubly-linked list/// to maintain insertion order.///pubstructMutHashMap[k: Type, v: Type, r: Region] { rc: Region[r],mut buckets: Array[Option[Node[k, v, r]], r], // Hash table bucketsmut head: Option[Node[k, v, r]], // First entry in insertion ordermut tail: Option[Node[k, v, r]], // Last entry in insertion ordermut size: Int32// Number of entries }instanceIterable[MutHashMap[k, v, r]] {typeElm = (k, v)typeAef = rpubdefiterator(rc: Region[r1], m: MutHashMap[k, v, r]): Iterator[(k, v), r + r1, r1] \ (r + r1) =MutHashMap.iterator(rc, m) }instanceForEach[MutHashMap[k, v, r]] {typeElm = (k, v)typeAef = rpubdefforEach(f: ((k, v)) -> Unit \ ef, m: MutHashMap[k, v, r]): Unit \ ef + r =MutHashMap.forEach((k, v) -> f((k, v)), m) }instanceIndexable[MutHashMap[k, v, r]] withEq[k], Hash[k] {typeElm = vtypeIdx = ktypeAef = r + KeyNotFoundpubdefget(t: MutHashMap[k, v, r], i: k): v \ r + KeyNotFound = {matchMutHashMap.get(i, t) {case Some(v) => vcase None => KeyNotFound.keyNotFound("key not found") } } }instanceIndexableMut[MutHashMap[k, v, r]] withEq[k], Hash[k] {typeAef = rpubdefput(t: MutHashMap[k, v, r], i: k, v: v): Unit \ r = MutHashMap.put(i, v, t) }instanceFormattable[MutHashMap[k, v, r]] withFormattable[k], Formattable[v] {typeAef = Formattable.Aef[k] + Formattable.Aef[v] + rpubdefformat(x: MutHashMap[k, v, r]): RichString \ (Formattable.Aef[k] + Formattable.Aef[v] + r) =use RichString.{fromString, joinWith};letkvs = MutHashMap.toList(x) |> List.map(match (k, v) -> Formattable.format(k) +fromString(" => ") +Formattable.format(v));fromString("MutHashMap#{") +joinWith(identity, fromString(", "), kvs) +fromString("}") }////// Constant denoting the minimum allowed capacity of the bucket array.///defminCapacity(): Int32 = 8////// Constant denoting the smallest valid load factor.///defminLoadFactor(): Float32 = 0.25f32////// Constant denoting the largest valid load factor.///defmaxLoadFactor(): Float32 = 0.75f32////// Represents an internal entry node for the hash map.////// Each entry is part of both a hash bucket chain and the insertion order chain.///structNode[k: Type, v: Type, r: Region] { key: k, // The key for this entry hash: Int32, // Cached hash code for the keymut value: v, // The value associated with the keymut bucketNext: Option[Node[k, v, r]], // Next entry in the same bucketmut orderPrev: Option[Node[k, v, r]], // Previous entry in insertion ordermut orderNext: Option[Node[k, v, r]] // Next entry in insertion order }mod Node {pubdefgetKey(e: Node[k, v, r]): k = e->keypubdefgetValue(e: Node[k, v, r]): v \ r = e->valuepubdefsetValue(v: v, e: Node[k, v, r]): Unit \ r = e->value = vpubdefgetHash(e: Node[k, v, r]): Int32 = e->hashpubdefgetBucketNext(e: Node[k, v, r]): Option[Node[k, v, r]] \ r = e->bucketNextpubdefsetBucketNext(next: Option[Node[k, v, r]], e: Node[k, v, r]): Unit \ r = e->bucketNext = nextpubdefgetOrderPrev(e: Node[k, v, r]): Option[Node[k, v, r]] \ r = e->orderPrevpubdefsetOrderPrev(prev: Option[Node[k, v, r]], e: Node[k, v, r]): Unit \ r = e->orderPrev = prevpubdefgetOrderNext(e: Node[k, v, r]): Option[Node[k, v, r]] \ r = e->orderNextpubdefsetOrderNext(next: Option[Node[k, v, r]], e: Node[k, v, r]): Unit \ r = e->orderNext = next }////// Returns `true` if `m` is empty.///pubdefisEmpty(m: MutHashMap[k, v, r]): Bool \ r =m->size ==0////// Returns `true` if `m` is non-empty.///pubdefnonEmpty(m: MutHashMap[k, v, r]): Bool \ r =notisEmpty(m)////// Returns the number of entries in `m`.///pubdefsize(m: MutHashMap[k, v, r]): Int32 \ r =m->size////// Returns an empty MutHashMap.///pubdefempty(rc: Region[r]): MutHashMap[k, v, r] \ r =emptyWithCapacity(rc, minCapacity())////// Returns an empty mutable hash map with the given capacity.////// The capacity is rounded up to the minimum capacity.///pubdefemptyWithCapacity(rc: Region[r], capacity: Int32): MutHashMap[k, v, r] \ r =letcap = Int32.max(capacity, minCapacity());letbuckets = Array.repeat(rc, cap, None);new MutHashMap @ rc {rc = rc, buckets = buckets, head = None, tail = None, size = 0}////// Returns a mutable hash map with a single key-value pair `k => v`.///pubdefsingleton(rc: Region[r], k: k, v: v): MutHashMap[k, v, r] \ rwithEq[k], Hash[k] =letm = empty(rc);put(k, v, m);m////// Returns the set of all keys in `m`.///pubdefkeysOf(m: MutHashMap[k, v, r]): Set[k] \ rwithOrder[k] =foldLeftWithKey((acc, k, _) -> Set.insert(k, acc), Set.empty(), m)////// Returns a list of all values in `m` in insertion order.///pubdefvaluesOf(m: MutHashMap[k, v, r]): List[v] \ r =foldRight((v, acc) -> v :: acc, Nil, m)////// Returns `Some(v)` if key `k` exists in `m`, otherwise `None`.///pubdefget(k: k, m: MutHashMap[k, v, r]): Option[v] \ rwithEq[k], Hash[k] =lethash = Hash.hash(k);letidx = indexOfBucket(hash, Array.length(m->buckets));matchfindInBucket(k, Array.get(idx, m->buckets)) {case None => Nonecase Some(entry) => Some(Node.getValue(entry)) }////// Returns the value associated with key `k` in `m`.////// If `k` does not exist, inserts `k` with value `default` and returns `default`.///pubdefgetOrElsePut(k: k, default: v, m: MutHashMap[k, v, r]): v \ rwithEq[k], Hash[k] =matchget(k, m) {case Some(v) => vcase None =>put(k, default, m);default }////// Returns the value associated with key `k`, or `default` if not found.///pubdefgetWithDefault(k: k, default: v, m: MutHashMap[k, v, r]): v \ rwithEq[k], Hash[k] =Option.getWithDefault(default, get(k, m))////// Returns the value associated with key `k` in the mutable hash map `m`.////// Aborts if the key is not present.///pubdefgetOrAbort(k: k, m: MutHashMap[k, v, r]): v \ (Abort + r) withEq[k], Hash[k] =matchMutHashMap.get(k, m) {case None => Abort.abortWithTrace("MutHashMap.getOrAbort(): key not found")case Some(v) => v }////// Converts hash code to a valid bucket index.///defindexOfBucket(hash: Int32, numBuckets: Int32): Int32 =// Note: Modulo ensures that the result cannot be negative.// So there is no risk that we index into the array with a negative index.Int32.modulo(hash, numBuckets)////// Searches for an entry with the given key in the bucket chain.///deffindInBucket(k: k, bucket: Option[Node[k, v, r]]): Option[Node[k, v, r]] \ rwithEq[k] =matchbucket {case None => Nonecase Some(entry) =>if (k==Node.getKey(entry)) Some(entry)elsefindInBucket(k, Node.getBucketNext(entry)) }////// Returns `true` if key `k` exists in `m`.///pubdefmemberOf(k: k, m: MutHashMap[k, v, r]): Bool \ rwithEq[k], Hash[k] =lethash = Hash.hash(k);letidx = indexOfBucket(hash, Array.length(m->buckets));matchfindInBucket(k, Array.get(idx, m->buckets)) {case None => falsecase Some(_) => true }////// Returns the first key-value pair that was inserted into the mutable map `m`.////// Returns `None` if the map is empty.///pubdeffirst(m: MutHashMap[k, v, r]): Option[(k, v)] \ r =matchm->head {case None => Nonecase Some(entry) => Some((Node.getKey(entry), Node.getValue(entry))) }////// Returns the last key-value pair that was inserted into the mutable map `m`.////// Returns `None` if the map is empty.///pubdeflast(m: MutHashMap[k, v, r]): Option[(k, v)] \ r =matchm->tail {case None => Nonecase Some(entry) => Some((Node.getKey(entry), Node.getValue(entry))) }////// Returns the first key that was inserted into the mutable map `m`.////// Returns `None` if the map is empty.///pubdeffirstKey(m: MutHashMap[k, v, r]): Option[k] \ r =first(m) |> Option.map(fst)////// Returns the last key that was inserted into the mutable map `m`.////// Returns `None` if the map is empty.///pubdeflastKey(m: MutHashMap[k, v, r]): Option[k] \ r =last(m) |> Option.map(fst)////// Returns the first value that was inserted into the mutable map `m`.////// Returns `None` if the map is empty.///pubdeffirstValue(m: MutHashMap[k, v, r]): Option[v] \ r =first(m) |> Option.map(snd)////// Returns the last value that was inserted into the mutable map `m`.////// Returns `None` if the map is empty.///pubdeflastValue(m: MutHashMap[k, v, r]): Option[v] \ r =last(m) |> Option.map(snd)////// Inserts key `k` with value `v` into `m`.////// If the key already exists, updates its value (does not change insertion order).///pubdefput(k: k, v: v, m: MutHashMap[k, v, r]): Unit \ rwithEq[k], Hash[k] =putWithKey((_, newV, _) -> newV, k, v, m)////// Adds all key-value pairs in the collection `kvs` to the mutable map `m`.///pubdefputAll(kvs: f[(k, v)], m: MutHashMap[k, v, r]): Unit \ (r + Foldable.Aef[f]) withEq[k], Hash[k], Foldable[f] =Foldable.forEach(match (k, v) -> put(k, v, m), kvs)////// Inserts key `k` with value `v` into `m`, using combiner function `f` if key exists.////// If key exists with value `oldV`, updates to `f(v, oldV)`.////// Otherwise, inserts `k => v`.///pubdefputWith(f: (v, v) -> v \ ef, k: k, v: v, m: MutHashMap[k, v, r]): Unit \ { ef, r } withEq[k], Hash[k] =putWithKey((_, newV, oldV) -> f(newV, oldV), k, v, m)////// Inserts key `k` with value `v` into `m`, using combiner function `f` with key if key exists.////// If key exists with value `oldV`, updates to `f(k, v, oldV)`.////// Otherwise, inserts `k => v`.///pubdefputWithKey(f: (k, v, v) -> v \ ef, k: k, v: v, m: MutHashMap[k, v, r]): Unit \ { ef, r } withEq[k], Hash[k] =lethash = Hash.hash(k);letnumBuckets = Array.length(m->buckets);letidx = indexOfBucket(hash, numBuckets);letbucket = Array.get(idx, m->buckets);matchfindInBucket(k, bucket) {case Some(entry) =>// Key exists, combine values with keyNode.setValue(f(k, v, Node.getValue(entry)), entry)case None =>// Key doesn't exist, insert normallyletentry = new Node @ m->rc { key = k, value = v, hash = hash, bucketNext = bucket, orderPrev = m->tail, orderNext = None };Array.put(Some(entry), idx, m->buckets);matchm->tail {case None =>m->head = Some(entry);m->tail = Some(entry)case Some(tailEntry) =>Node.setOrderNext(Some(entry), tailEntry);m->tail = Some(entry) };m->size = m->size +1;expand(m) }////// Updates the value at key `k` using function `f` if the key exists.////// Does nothing if the key does not exist.///pubdefadjust(f: v -> v \ ef, k: k, m: MutHashMap[k, v, r]): Unit \ { ef, r } withEq[k], Hash[k] =adjustWithKey((_, v) -> f(v), k, m)////// Updates the value at key `k` using function `f` with key if the key exists.////// Does nothing if the key does not exist.///pubdefadjustWithKey(f: (k, v) -> v \ ef, k: k, m: MutHashMap[k, v, r]): Unit \ { ef, r } withEq[k], Hash[k] =lethash = Hash.hash(k);letidx = indexOfBucket(hash, Array.length(m->buckets));matchfindInBucket(k, Array.get(idx, m->buckets)) {case Some(entry) => Node.setValue(f(k, Node.getValue(entry)), entry)case None => () }////// Updates or removes the value at key `k` based on function `f`.////// If key exists and `f(oldValue) = Some(newValue)`, updates to newValue.////// If key exists and `f(oldValue) = None`, removes the entry.////// Does nothing if the key does not exist.///pubdefupdate(f: v -> Option[v] \ ef, k: k, m: MutHashMap[k, v, r]): Unit \ { ef, r } withEq[k], Hash[k] =updateWithKey((_, v) -> f(v), k, m)////// Updates or removes the value at key `k` based on function `f` with key.////// If key exists and `f(k, oldValue) = Some(newValue)`, updates to newValue.////// If key exists and `f(k, oldValue) = None`, removes the entry.////// Does nothing if the key does not exist.///pubdefupdateWithKey(f: (k, v) -> Option[v] \ ef, k: k, m: MutHashMap[k, v, r]): Unit \ { ef, r } withEq[k], Hash[k] =lethash = Hash.hash(k);letidx = indexOfBucket(hash, Array.length(m->buckets));matchfindInBucket(k, Array.get(idx, m->buckets)) {case Some(entry) =>matchf(k, Node.getValue(entry)) {case Some(newValue) => Node.setValue(newValue, entry)case None => remove(k, m) }case None => () }////// Removes key `k` from `m`.///pubdefremove(k: k, m: MutHashMap[k, v, r]): Unit \ rwithEq[k], Hash[k] =// Removal is a two-phase process:// 1. Remove the entry from its bucket chain (hash table structure)// 2. Remove the entry from the insertion order chain (doubly-linked list)// Phase 1: Find and remove from bucket chainlethash = Hash.hash(k);letnumBuckets = Array.length(m->buckets);letidx = indexOfBucket(hash, numBuckets);letbucket = Array.get(idx, m->buckets);// Helper to traverse bucket chain and remove matching entry// Returns Some(entry) if found and removed, None otherwisedefremoveFromBucket(curr, prev) = matchcurr {case None => Nonecase Some(entry) =>if (k==Node.getKey(entry)) {// Found the entry - remove it from bucket chainmatchprev {case None =>// Node is first in bucket - update bucket headArray.put(Node.getBucketNext(entry), idx, m->buckets)case Some(prevEntry) =>// Node is in middle/end - bypass it in the chainNode.setBucketNext(Node.getBucketNext(entry), prevEntry) }; Some(entry) } else {// Keep searchingremoveFromBucket(Node.getBucketNext(entry), Some(entry)) } };// Phase 2: If entry was found, also remove from insertion order chainmatchremoveFromBucket(bucket, None) {case None => () // Key not found, nothing to docase Some(entry) =>// Update the previous entry's next pointer (or map head if no previous)matchNode.getOrderPrev(entry) {case None =>// Removing the head of insertion orderm->head = Node.getOrderNext(entry)case Some(prevEntry) =>// Bypass this entry in the order chainNode.setOrderNext(Node.getOrderNext(entry), prevEntry) };// Update the next entry's previous pointer (or map tail if no next)matchNode.getOrderNext(entry) {case None =>// Removing the tail of insertion orderm->tail = Node.getOrderPrev(entry)case Some(nextEntry) =>// Bypass this entry in the order chainNode.setOrderPrev(Node.getOrderPrev(entry), nextEntry) };// Update size and potentially shrink the bucket arraym->size = m->size -1;shrink(m) }////// Removes all entries from `m`.///pubdefclear(m: MutHashMap[k, v, r]): Unit \ r =letnumBuckets = Array.length(m->buckets);Array.updateSequence(0, Array.repeat(m->rc, numBuckets, None), m->buckets);m->head = None;m->tail = None;m->size = 0////// Returns the load factor of `m`.///defloadFactor(m: MutHashMap[k, v, r]): Float32 \ r =Int32.toFloat32(m->size) /Int32.toFloat32(Array.length(m->buckets))////// Doubles the bucket array size if load factor >= maxLoadFactor.///defexpand(m: MutHashMap[k, v, r]): Unit \ r =if (loadFactor(m) >=maxLoadFactor())resize(m, Array.length(m->buckets) *2)else()////// Halves the bucket array size if load factor <= minLoadFactor.///defshrink(m: MutHashMap[k, v, r]): Unit \ r =letcurrentCapacity = Array.length(m->buckets);letnewCapacity = currentCapacity/2;if (loadFactor(m) <=minLoadFactor()andnewCapacity>=minCapacity())resize(m, newCapacity)else()////// Resizes the bucket array to `newCapacity` and rehashes all entries.///defresize(m: MutHashMap[k, v, r], newCapacity: Int32): Unit \ r =// Create new bucket arrayletnewBuckets = Array.repeat(m->rc, newCapacity, None);// Rehash all entries by walking the order chaindefrehashEntry(curr) = matchcurr {case None => ()case Some(entry) =>// Compute new bucket indexletidx = indexOfBucket(Node.getHash(entry), newCapacity);letbucket = Array.get(idx, newBuckets);// Insert into new bucket chainNode.setBucketNext(bucket, entry);Array.put(Some(entry), idx, newBuckets);// Continue with next entry in order chainrehashEntry(Node.getOrderNext(entry)) };rehashEntry(m->head);m->buckets = newBuckets////// Applies `f` to each key-value pair in `m` in insertion order.///pubdefforEach(f: (k, v) -> Unit \ ef, m: MutHashMap[k, v, r]): Unit \ { ef, r } =defloop(curr) = matchcurr {case None => ()case Some(entry) =>f(Node.getKey(entry), Node.getValue(entry));loop(Node.getOrderNext(entry)) };loop(m->head)////// Applies `f` to each key-value pair in `m` along with its index in insertion order.///pubdefforEachWithIndex(f: (Int32, k, v) -> Unit \ ef, m: MutHashMap[k, v, r]): Unit \ { ef, r } = regionrc {letix = Ref.fresh(rc, 0);forEach( (k, v) -> {leti = Ref.get(ix);f(i, k, v);Ref.put(i+1, ix) },m ) }////// Returns an iterator over key-value pairs in `m` in insertion order.///pubdefiterator(rc: Region[r2], m: MutHashMap[k, v, r]): Iterator[(k, v), r2 + r, r2] \ { r, r2 } =letcurr = Ref.fresh(rc, m->head);defnext() = matchRef.get(curr) {case None => Nonecase Some(entry) =>Ref.put(Node.getOrderNext(entry), curr); Some((Node.getKey(entry), Node.getValue(entry))) };Iterator.unfoldWithIter(rc, next)////// Returns an iterator over keys in `m` in insertion order.///pubdefiteratorKeys(rc: Region[r2], m: MutHashMap[k, v, r]): Iterator[k, r2 + r, r2] \ { r, r2 } =iterator(rc, m) |> Iterator.map(fst)////// Returns an iterator over values in `m` in insertion order.///pubdefiteratorValues(rc: Region[r2], m: MutHashMap[k, v, r]): Iterator[v, r2 + r, r2] \ { r, r2 } =iterator(rc, m) |> Iterator.map(snd)////// Returns a new mutable hash map with values transformed by function `f`.////// Keys and insertion order are preserved.///pubdefmap(rc: Region[r2], f: v1 -> v2 \ ef, m: MutHashMap[k, v1, r1]): MutHashMap[k, v2, r2] \ { ef, r1, r2 } withEq[k], Hash[k] =letresult = emptyWithCapacity(rc, size(m));forEach((k, v) -> put(k, f(v), result), m);result////// Returns a new mutable hash map with values transformed by function `f` with access to keys.////// Keys and insertion order are preserved.///pubdefmapWithKey(rc: Region[r2], f: (k, v1) -> v2 \ ef, m: MutHashMap[k, v1, r1]): MutHashMap[k, v2, r2] \ { ef, r1, r2 } withEq[k], Hash[k] =letresult = emptyWithCapacity(rc, size(m));forEach((k, v) -> put(k, f(k, v), result), m);result////// Transforms all values in `m` in-place using function `f`.///pubdeftransform(f: v -> v \ ef, m: MutHashMap[k, v, r]): Unit \ { ef, r } =transformWithKey((_, v) -> f(v), m)////// Transforms all values in `m` in-place using function `f` with access to keys.///pubdeftransformWithKey(f: (k, v) -> v \ ef, m: MutHashMap[k, v, r]): Unit \ { ef, r } =defloop(curr) = matchcurr {case None => ()case Some(entry) =>Node.setValue(f(Node.getKey(entry), Node.getValue(entry)), entry);loop(Node.getOrderNext(entry)) };loop(m->head)////// Removes all entries from `m` where `f(value)` returns false.///pubdefrefine(f: v -> Bool \ ef, m: MutHashMap[k, v, r]): Unit \ { ef, r } withEq[k], Hash[k] =refineWithKey((_, v) -> f(v), m)////// Removes all entries from `m` where `f(key, value)` returns false.///pubdefrefineWithKey(f: (k, v) -> Bool \ ef, m: MutHashMap[k, v, r]): Unit \ { ef, r } withEq[k], Hash[k] =// Two-pass: collect keys to remove, then remove themdefcollectKeys(curr, acc) = matchcurr {case None => acccase Some(entry) =>letk = Node.getKey(entry);letv = Node.getValue(entry);letnewAcc = if (f(k, v)) accelsek :: acc;collectKeys(Node.getOrderNext(entry), newAcc) };letkeysToRemove = collectKeys(m->head, Nil);List.forEach(k -> remove(k, m), keysToRemove)////// Applies `f` to a start value `s` and all values in `m` going from left to right (insertion order).///pubdeffoldLeft(f: (b, v) -> b \ ef, s: b, m: MutHashMap[k, v, r]): b \ { ef, r } =defloop(curr, acc) = matchcurr {case None => acccase Some(entry) =>loop(Node.getOrderNext(entry), f(acc, Node.getValue(entry))) };loop(m->head, s)////// Applies `f` to a start value `s` and all key-value pairs in `m` going from left to right (insertion order).///pubdeffoldLeftWithKey(f: (b, k, v) -> b \ ef, s: b, m: MutHashMap[k, v, r]): b \ { ef, r } =defloop(curr, acc) = matchcurr {case None => acccase Some(entry) =>loop(Node.getOrderNext(entry), f(acc, Node.getKey(entry), Node.getValue(entry))) };loop(m->head, s)////// Applies `f` to a start value `s` and all values in `m` going from right to left (reverse insertion order).///pubdeffoldRight(f: (v, b) -> b \ ef, s: b, m: MutHashMap[k, v, r]): b \ { ef, r } =defloop(curr, acc) = matchcurr {case None => acccase Some(entry) =>loop(Node.getOrderPrev(entry), f(Node.getValue(entry), acc)) };loop(m->tail, s)////// Applies `f` to a start value `s` and all key-value pairs in `m` going from right to left (reverse insertion order).///pubdeffoldRightWithKey(f: (k, v, b) -> b \ ef, s: b, m: MutHashMap[k, v, r]): b \ { ef, r } =defloop(curr, acc) = matchcurr {case None => acccase Some(entry) =>loop(Node.getOrderPrev(entry), f(Node.getKey(entry), Node.getValue(entry), acc)) };loop(m->tail, s)////// Returns the result of mapping each value and combining the results using a monoid.///pubdeffoldMap(f: v -> b \ ef, m: MutHashMap[k, v, r]): b \ { ef, r } withMonoid[b] =foldLeft((acc, x) -> Monoid.combine(acc, f(x)), Monoid.empty(), m)////// Returns `true` if at least one key-value pair in `m` satisfies the predicate `f`.///pubdefexists(f: (k, v) -> Bool \ ef, m: MutHashMap[k, v, r]): Bool \ { ef, r } =defloop(curr) = matchcurr {case None => falsecase Some(entry) =>if (f(Node.getKey(entry), Node.getValue(entry)))trueelseloop(Node.getOrderNext(entry)) };loop(m->head)////// Returns `true` if all key-value pairs in `m` satisfy the predicate `f`.///pubdefforAll(f: (k, v) -> Bool \ ef, m: MutHashMap[k, v, r]): Bool \ { ef, r } =defloop(curr) = matchcurr {case None => truecase Some(entry) =>if (f(Node.getKey(entry), Node.getValue(entry)))loop(Node.getOrderNext(entry))elsefalse };loop(m->head)////// Returns the number of key-value pairs in `m` that satisfy the predicate `f`.///pubdefcount(f: (k, v) -> Bool \ ef, m: MutHashMap[k, v, r]): Int32 \ { ef, r } =defloop(curr, acc) = matchcurr {case None => acccase Some(entry) =>letnewAcc = if (f(Node.getKey(entry), Node.getValue(entry))) acc+1elseacc;loop(Node.getOrderNext(entry), newAcc) };loop(m->head, 0)////// Returns the first key-value pair in `m` (in insertion order) that satisfies the predicate `f`.////// Alias for `findLeft`.///pubdeffind(f: (k, v) -> Bool \ ef, m: MutHashMap[k, v, r]): Option[(k, v)] \ { ef, r } =findLeft(f, m)////// Returns the first key-value pair in `m` (from left, in insertion order) that satisfies the predicate `f`.///pubdeffindLeft(f: (k, v) -> Bool \ ef, m: MutHashMap[k, v, r]): Option[(k, v)] \ { ef, r } =defloop(curr) = matchcurr {case None => Nonecase Some(entry) =>letk = Node.getKey(entry);letv = Node.getValue(entry);if (f(k, v)) Some((k, v))elseloop(Node.getOrderNext(entry)) };loop(m->head)////// Returns the first key-value pair in `m` (from right, in reverse insertion order) that satisfies the predicate `f`.///pubdeffindRight(f: (k, v) -> Bool \ ef, m: MutHashMap[k, v, r]): Option[(k, v)] \ { ef, r } =defloop(curr) = matchcurr {case None => Nonecase Some(entry) =>letk = Node.getKey(entry);letv = Node.getValue(entry);if (f(k, v)) Some((k, v))elseloop(Node.getOrderPrev(entry)) };loop(m->tail)////// Returns a shallow copy of `m` in region `rc2`.////// All key-value pairs are copied in insertion order.///pubdefcopy(rc: Region[r2], m: MutHashMap[k, v, r1]): MutHashMap[k, v, r2] \ { r1, r2 } withEq[k], Hash[k] =letresult = emptyWithCapacity(rc, size(m));forEach((k, v) -> put(k, v, result), m);result////// Returns an array of all key-value pairs in `m` in insertion order.///pubdeftoArray(rc: Region[r2], m: MutHashMap[k, v, r]): Array[(k, v), r2] \ { r, r2 } =letlen = size(m);letarr = Array.empty(rc, len);forEachWithIndex((i, k, v) -> Array.put((k, v), i, arr), m);arr////// Returns a list of all key-value pairs in `m` in insertion order.///pubdeftoList(m: MutHashMap[k, v, r]): List[(k, v)] \ r =foldRightWithKey((k, v, acc) -> (k, v) :: acc, Nil, m)////// Returns an immutable map containing all key-value pairs from `m`.///pubdeftoMap(m: MutHashMap[k, v, r]): Map[k, v] \ rwithOrder[k] =foldLeftWithKey((acc, k, v) -> Map.insert(k, v, acc), Map.empty(), m)////// Returns a set containing all key-value pairs from `m`.///pubdeftoSet(m: MutHashMap[k, v, r]): Set[(k, v)] \ rwithOrder[k], Order[v] =foldLeftWithKey((acc, k, v) -> Set.insert((k, v), acc), Set.empty(), m)////// Returns a vector of all key-value pairs in `m` in insertion order.///pubdeftoVector(m: MutHashMap[k, v, r]): Vector[(k, v)] \ r = regionrc {letarr = toArray(rc, m);Array.toVector(arr) }////// Returns a new mutable hash map containing all key-value pairs from list `l`./// If the list contains duplicate keys, the last occurrence wins.///pubdeffromList(rc: Region[r], l: List[(k, v)]): MutHashMap[k, v, r] \ rwithEq[k], Hash[k] =letresult = empty(rc);List.forEach(match (k, v) -> put(k, v, result), l);result////// Returns a new mutable hash map containing all key-value pairs from immutable map `m`.///pubdeffromMap(rc: Region[r], m: Map[k, v]): MutHashMap[k, v, r] \ rwithOrder[k], Hash[k] =letresult = empty(rc);Map.forEach((k, v) -> put(k, v, result), m);result////// Returns a string formed by joining all keys in `m` with `sep`.///pubdefjoinKeys(sep: String, m: MutHashMap[k, v, r]): String \ rwithToString[k] =letstrs = foldRightWithKey((k, _v, acc) -> "${k}" :: acc, Nil, m);String.intercalate(sep, strs)////// Returns a string formed by joining all values in `m` with `sep`.///pubdefjoinValues(sep: String, m: MutHashMap[k, v, r]): String \ rwithToString[v] =letstrs = foldRight((v, acc) -> "${v}" :: acc, Nil, m);String.intercalate(sep, strs)////// Returns a string formed by applying `f` to each key-value pair and joining with `sep`.///pubdefjoinWith(f: (k, v) -> String \ ef, sep: String, m: MutHashMap[k, v, r]): String \ { ef, r } =letstrs = foldRightWithKey((k, v, acc) -> f(k, v) :: acc, Nil, m);String.intercalate(sep, strs)////// Returns a string representation of `m`.///pubdeftoString(m: MutHashMap[k, v, r]): String \ rwithToString[k], ToString[v] =letkvs = foldRightWithKey((k, v, acc) -> "${k} -> ${v}" :: acc, Nil, m);letinner = String.intercalate(", ", kvs);"MutHashMap#{${inner}}"}