/* * Copyright 2023 Xavier deSouza * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */pubmod MutPriorityQueue {////// Represents a mutable priority queue./// Explanation of component types (left to right):/// Component 1: The region capability the queue is associated with./// Component 2: A reference to the backing array./// Component 3: A reference to the number of elements in the mutable priority queue.////// The maximum element (if it exists) can always be accessed in constant time.///pubstructMutPriorityQueue[a: Type, r: Region] { r: Region[r],mut values: Array[a, r],mut size: Int32 }instanceIterable[MutPriorityQueue[a, r]] {typeElm = atypeAef = rpubdefiterator(rc: Region[r1], q: MutPriorityQueue[a, r]): Iterator[a, r + r1, r1] \ (r + r1) = MutPriorityQueue.iterator(rc, q) }instanceForEach[MutPriorityQueue[a, r]] {typeElm = atypeAef = rpubdefforEach(f: a -> Unit \ ef, q: MutPriorityQueue[a, r]): Unit \ ef + r = MutPriorityQueue.forEach(f, q) }instanceFormattable[MutPriorityQueue[a, r]] withFormattable[a], Order[a] {typeAef = Formattable.Aef[a] + rpubdefformat(x: MutPriorityQueue[a, r]): RichString \ (Formattable.Aef[a] + r) =use RichString.{fromString, joinWith};fromString("MutPriorityQueue#{") +joinWith(Formattable.format, fromString(", "), MutPriorityQueue.toList(x)) +fromString("}") }////// Constant which stores the minimum capacity of a MutPriorityQueue.///pubdefminCapacity(): Int32 = 8////// Returns a String representation of the mutable priority queue `mq`.///pubdeftoString(mq: MutPriorityQueue[a, r]): String \ rwithToString[a] = regionrc {"MutPriorityQueue {"+ (MutPriorityQueue.iterator(rc, mq) |> Iterator.join(", ")) +"}" }////// Returns an empty MutPriorityQueue with a default capacity.///pubdefempty(rc: Region[r]): MutPriorityQueue[a, r] \ r =emptyWithCapacity(rc, minCapacity())////// Returns an empty MutPriorityQueue with the given capacity rounded up to the/// default capacity.///pubdefemptyWithCapacity(rc: Region[r], capacity: Int32): MutPriorityQueue[a, r] \ r = {letflooredCapacity = Int32.max(capacity, minCapacity());new MutPriorityQueue @ rc {r = rc, values = Array.empty(rc, flooredCapacity), size = 0} }////// Returns the number of elements in `mq`.///pubdefsize(mq: MutPriorityQueue[a, r]): Int32 \ r =mq->size////// Returns whether `mq` is empty.///pubdefisEmpty(mq: MutPriorityQueue[a, r]): Bool \ r =mq->size ==0////// Returns whether `mq` is non-empty.///pubdefnonEmpty(mq: MutPriorityQueue[a, r]): Bool \ r = notisEmpty(mq)////// Optionally returns the top element of `mq`.///pubdefpeek(mq: MutPriorityQueue[a, r]): Option[a] \ r =if (mq->size ==0) Noneelse Some(Array.get(0, mq->values))////// Enqueues an element `x` into a `mq`.///pubdefenqueue(x: a, mq: MutPriorityQueue[a, r]): Unit \ rwithOrder[a] = {expand(mq);Array.put(x, mq->size, mq->values);heapifyUp(mq->size, mq);mq->size = mq->size +1 }////// Removes and optionally returns the top element of `mq`.///pubdefdequeue(mq: MutPriorityQueue[a, r]): Option[a] \ rwithOrder[a] =if (mq->size >0) {lettop = peek(mq);Array.put(Array.get(mq->size -1, mq->values), 0, mq->values);heapifyDown(0, mq);mq->size = mq->size -1;top } else None////// Enqueues each element in `m` into `mq`.///pubdefenqueueAll(m: m, mq: MutPriorityQueue[elt, r]): Unit \ (r + ForEach.Aef[m]) withForEach[m], Order[elt] whereForEach.Elm[m] ~ elt =foreach (x <- m) {enqueue(x, mq) }////// Applies `f` to every element of `q`.///pubdefforEach(f: a -> Unit \ ef, q: MutPriorityQueue[a, r]): Unit \ ef + r = {letarr = q->values;letsize = q->size;defloop(i) = {if (i<size) {f(Array.get(i, arr));loop(i+1) } };loop(0) }////// Returns an iterator over `mq`.////// Modifying `mq` during iteration is undefined and not recommended.///pubdefiterator(rc: Region[r1], mq: MutPriorityQueue[a, r2]): Iterator[a, r1 + r2, r1] \ { r1, r2 } =letit1 = Iterator.range(rc, 0, mq->size);Iterator.map(x -> Array.get(x, mq->values), it1)////// Returns a List representation of `mq`.////// Note that a MutPriorityQueue's element order depends on the order in which the elements were enqueued.///pubdeftoList(mq: MutPriorityQueue[a, r]): List[a] \ rwithOrder[a] =List.take(mq->size, Array.foldRight((x, acc) -> x :: acc, Nil, mq->values))////// Optionally returns a Nel representation of `mq`.///pubdeftoNel(mq: MutPriorityQueue[a, r]): Option[Nel[a]] \ rwithOrder[a] =List.toNel(toList(mq))////// Returns an Array representation of `mq`.////// Note that a MutPriorityQueue's element order depends on the order in which the elements were enqueued.///pubdeftoArray(rc: Region[r1], mq: MutPriorityQueue[a, r2]): Array[a, r1] \ { r1, r2 } =Array.takeLeft(rc, mq->size, mq->values)////// Returns an Vector representation of `mq`.////// Note that a MutPriorityQueue's element order depends on the order in which the elements were enqueued.///pubdeftoVector(mq: MutPriorityQueue[a, r]): Vector[a] \ r = regionrc {toArray(rc, mq) |> Array.toVector }////// Reinforces the max heap invariant from `idx` after an element is added to `mq`.///defheapifyUp(idx: Int32, mq: MutPriorityQueue[a, r]): Unit \ rwithOrder[a] =if (idx!=0) {letparentIdx = (idx-1) /2;letcur = Array.get(idx, mq->values);letparent = Array.get(parentIdx, mq->values);if (cur>parent) {Array.put(parent, idx, mq->values);Array.put(cur, parentIdx, mq->values);heapifyUp(parentIdx, mq) } }////// Reinforces the max heap invariant from `idx` after an element is removed from `mq`.///defheapifyDown(idx: Int32, mq: MutPriorityQueue[a, r]): Unit \ rwithOrder[a] =letsize = mq->size;letlChildIdx = idx*2+1;letrChildIdx = idx*2+2;letcur = Array.get(idx, mq->values);if (size>=rChildIdx) {if (size==rChildIdx) {letchild = Array.get(lChildIdx, mq->values);if (cur<child) {Array.put(child, idx, mq->values);Array.put(cur, lChildIdx, mq->values) } } else {letlChild = Array.get(lChildIdx, mq->values);letrChild = Array.get(rChildIdx, mq->values);if ((lChild>cur) or (rChild>cur)) {if (lChild>rChild) {Array.put(cur, lChildIdx, mq->values);Array.put(lChild, idx, mq->values);heapifyDown(lChildIdx, mq) } else {Array.put(cur, rChildIdx, mq->values);Array.put(rChild, idx, mq->values);heapifyDown(rChildIdx, mq) } } } }////// Expands the internal array of `mq` if its capacity is full.///defexpand(mq: MutPriorityQueue[a, r]): Unit \ r =letoldCapacity = Array.length(mq->values);if (oldCapacity==mq->size) {letnewCapacity = 2+ (oldCapacity*2);letnewArr = Array.empty(mq->r, newCapacity);Array.forEachWithIndex((idx, x) -> Array.put(x, idx, newArr), mq->values);mq->values = newArr }}