@effekt-lang/effekt 0.76.0 → 0.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/effekt CHANGED
Binary file
@@ -63,9 +63,10 @@ extern def unsafeAllocate[T](size: Int) at global: Array[T] =
63
63
 
64
64
  /// Fills a given array in-place.
65
65
  def fill[T](arr: Array[T], filler: T): Unit = {
66
- arr.foreachIndex { (idx, _) =>
67
- arr.set(idx, filler)
68
- }
66
+ val n = arr.size
67
+ def go(i: Int): Unit =
68
+ if (i < n) { arr.set(i, filler); go(i + 1) }
69
+ go(0)
69
70
  }
70
71
 
71
72
  /// Creates a new Array of size `size` filled with the value `init`
@@ -113,17 +113,35 @@ def build(size: Int) { index: Int => Byte }: ByteArray = {
113
113
  arr
114
114
  }
115
115
 
116
+ /// Copies `length`-many bytes from `from` to `to`
117
+ /// starting at `start` (in `from`) and `offset` (in `to`).
118
+ /// The ranges may overlap, even within the same bytearray: the source bytes are
119
+ /// read before any are written. Panics if out of bounds.
120
+ ///
121
+ /// O(N)
122
+ def copy(from: ByteArray, start: Int, to: ByteArray, offset: Int, length: Int): Unit =
123
+ if (length < 0 || start < 0 || offset < 0
124
+ || start + length > from.size || offset + length > to.size) {
125
+ <{ "bytearray::copy: range out of bounds" }>
126
+ } else {
127
+ unsafeCopy(from, start, to, offset, length)
128
+ }
129
+
130
+ /// `copy` without its bounds check.
131
+ /// Corrupts memory if misused; prefer `copy`.
132
+ extern def unsafeCopy(from: ByteArray, start: Int, to: ByteArray, offset: Int, length: Int) at global: Unit =
133
+ js "bytearray$copy(${from}, ${start}, ${to}, ${offset}, ${length})"
134
+ chez "(bytevector-copy! ${from} ${start} ${to} ${offset} ${length})"
135
+ llvm """
136
+ %z = call %Pos @c_bytearray_copy(%Pos ${from}, %Int ${start}, %Pos ${to}, %Int ${offset}, %Int ${length})
137
+ ret %Pos %z
138
+ """
139
+
116
140
  def resize(source: ByteArray, size: Int): ByteArray = {
117
141
  val target = allocate(size)
118
- val n = min(source.size, target.size)
119
- def go(i: Int): ByteArray =
120
- if (i < n) {
121
- target.set(i, source.get(i))
122
- go(i + 1)
123
- } else {
124
- target
125
- }
126
- go(0)
142
+ // safe: `min` establishes the bound for both ranges ~> no check is needed
143
+ unsafeCopy(source, 0, target, 0, min(source.size, size))
144
+ target
127
145
  }
128
146
 
129
147
  /// Sorts a given bytearray `arr` in-place using a counting sort,
@@ -190,6 +208,21 @@ extern def toString(arr: ByteArray) at {}: String =
190
208
  chez "(utf8->string ${arr})"
191
209
 
192
210
  extern js """
211
+ function bytearray$copy(src, srcOff, dst, dstOff, n) {
212
+ // for small `n`, it's faster to copy manually to avoid allocating `subarray`
213
+ if (n < 40) {
214
+ if (srcOff < dstOff) {
215
+ for (let i = n - 1; i >= 0; --i) dst[dstOff + i] = src[srcOff + i];
216
+ } else {
217
+ for (let i = 0; i < n; ++i) dst[dstOff + i] = src[srcOff + i];
218
+ }
219
+ } else {
220
+ // safe: `set` clones the source region first when both share a buffer
221
+ dst.set(src.subarray(srcOff, srcOff + n), dstOff);
222
+ }
223
+ return $effekt.unit;
224
+ }
225
+
193
226
  function bytearray$set(bytes, index, value) {
194
227
  bytes[index] = value;
195
228
  return $effekt.unit;
@@ -242,22 +275,8 @@ extern def compareByteArrayImpl(b1: ByteArray, b2: ByteArray) at {}: Int =
242
275
  """
243
276
  chez "(bytearray$compare ${b1} ${b2})"
244
277
 
245
- def compareByteArray(b1: ByteArray, b2: ByteArray): Ordering = {
246
- val ret = compareByteArrayImpl(b1, b2)
247
- if (ret == 0) {
248
- Equal()
249
- } else if (ret < 0) {
250
- Less()
251
- } else { // ret > 0
252
- Greater()
253
- }
254
- }
255
-
256
- def compareStringBytes(left: String, right: String): Ordering = {
257
- val l = left.fromString
258
- val r = right.fromString
259
- compareByteArray(l, r)
260
- }
278
+ def compareByteArray(b1: ByteArray, b2: ByteArray): Ordering =
279
+ compareByteArrayImpl(b1, b2).fromInt
261
280
 
262
281
 
263
282
  // Streaming
@@ -144,6 +144,10 @@ extern def infixGte(x: Char, y: Char) at {}: Bool =
144
144
  ret %Pos %adt_boolean
145
145
  """
146
146
 
147
+ def compareChar(x: Char, y: Char): Ordering =
148
+ if (x == y) Equal()
149
+ else if (x < y) Less()
150
+ else Greater()
147
151
 
148
152
  /**
149
153
  * Determines the number of bytes needed by a codepoint
@@ -155,18 +159,21 @@ def utf8ByteCount(codepoint: Char): Int = codepoint match {
155
159
  case c and c >= '\u0080' and c <= '\u07FF' => 2
156
160
  case c and c >= '\u0800' and c <= '\uFFFF' => 3
157
161
  case c and c >= '\u10000' and c <= '\u10FFFF' => 4
158
- case c => panic("Not a valid code point")
162
+ case c => <{ "Not a valid code point" }>
159
163
  }
160
164
 
161
165
  def utf16UnitCount(codepoint: Char): Int = codepoint match {
162
166
  case c and c >= '\u0000' and c <= '\uFFFF' => 1
163
- case c and c >= '\u10000' and c <= '\u10FFFF' => 4
164
- case c => panic("Not a valid code point")
167
+ case c and c >= '\u10000' and c <= '\u10FFFF' => 2
168
+ case c => <{ "Not a valid code point" }>
165
169
  }
166
170
 
171
+ /// How many index units `c` occupies in the unit that `length` and `unsafeCharAt`
172
+ /// use on this backend. Adding it to a code-point boundary gives the next character.
167
173
  extern def charWidth(c: Char) at {}: Int =
168
- // JavaScript strings are UTF-16 where every unicode character after 0xffff takes two units
169
- js "(${c} > 0xffff) ? 2 : 1"
174
+ js { utf16UnitCount(c) }
175
+ chez { 1 }
176
+ llvm { utf8ByteCount(c) }
170
177
 
171
178
 
172
179
  def decodeChar(): Char / {next[Byte], stop} = {
@@ -191,20 +191,25 @@ extern def random() at io: Double =
191
191
  // extern io def freshGlobal[T](t: T): Ref[T] at global = js "$effekt.fresh(${t})"
192
192
 
193
193
 
194
- // Equality
194
+ // Comparison
195
195
  // ========
196
196
 
197
197
  /// Result of comparison between two objects according to some order:
198
198
  ///
199
199
  /// - `Less()` means that the first object is *before* the first in the order,
200
- /// - `Equal()` means that the two objects are the same in the order,
201
- /// - and `Greater()` means that the second object is *before* the first in the order.
200
+ /// - `Equal()` means that the two objects are the same in the order, and
201
+ /// - `Greater()` means that the second object is *before* the first in the order.
202
202
  type Ordering {
203
203
  Less();
204
204
  Equal();
205
205
  Greater()
206
206
  }
207
207
 
208
+ def ordering::fromInt(n: Int): Ordering =
209
+ if (n == 0) Equal()
210
+ else if (n < 0) Less()
211
+ else Greater()
212
+
208
213
  def compareInt(n: Int, m: Int) =
209
214
  if (n == m) Equal()
210
215
  else if (n < m) Less()
@@ -215,16 +220,8 @@ extern def genericCompareImpl[R](x: R, y: R) at {}: Int =
215
220
 
216
221
  /// Compares two values of the same type, returning an `Ordering`.
217
222
  /// Only available on the JavaScript backend.
218
- def genericCompare[R](x: R, y: R): Ordering = {
219
- val ret = genericCompareImpl(x, y)
220
- if (ret == 0) {
221
- Equal()
222
- } else if (ret < 0) {
223
- Less()
224
- } else { // ret > 0
225
- Greater()
226
- }
227
- }
223
+ def genericCompare[R](x: R, y: R): Ordering =
224
+ genericCompareImpl(x, y).fromInt
228
225
 
229
226
  def println(o: Ordering): Unit = println(o.show)
230
227
 
@@ -820,6 +820,28 @@ def partition[A](l: List[A]) { pred: A => Bool }: (List[A], List[A]) = {
820
820
  (lefts.reverse, rights.reverse)
821
821
  }
822
822
 
823
+ /// List functions that we discourage to use, but should still be available
824
+ namespace slow {
825
+ /// Find the first element in a list which satisfies a given predicate.
826
+ /// If there is no such element, returns None.
827
+ ///
828
+ /// Examples:
829
+ /// ```
830
+ /// > [].slow::find{ x => x.mod(2) == 0 }
831
+ /// None()
832
+ /// > [1, 3, 6].slow::find{ x => x.mod(2) == 0 }
833
+ /// Some(6)
834
+ /// > [2, 4, 6].slow::find{ x => x.mod(2) == 0 }
835
+ /// Some(2)
836
+ /// ```
837
+ ///
838
+ /// O(N)
839
+ def find[A](list: List[A]){ pred: A => Bool }: Option[A] = list match {
840
+ case Cons(x, xs) => if (pred(x)) Some(x) else find(xs){pred}
841
+ case Nil() => None()
842
+ }
843
+ }
844
+
823
845
  /// Utilities for sorting, see 'sortBy' for more details.
824
846
  namespace sort {
825
847
  /// Splits the given list into monotonic segments (so a list of lists).
@@ -8,7 +8,7 @@ record Map[K, V](tree: internal::Tree[K, V], compare: (K, K) => Ordering at {})
8
8
  /// Create a new empty map using a pure, first-class comparison function.
9
9
  ///
10
10
  /// O(1)
11
- def empty[K, V](compare: (K, K) => Ordering at {}): Map[K, V] =
11
+ def empty[K, V](?compare: (K, K) => Ordering at {}): Map[K, V] =
12
12
  Map(internal::empty(), compare)
13
13
 
14
14
  /// Create a new empty map using a generic comparison function.
@@ -34,7 +34,7 @@ def nonEmpty[K, V](m: Map[K, V]): Bool = internal::nonEmpty(m.tree)
34
34
  /// Create a new map containing the mapping from `k` to `v` and a pure, first-class comparison function.
35
35
  ///
36
36
  /// O(1)
37
- def singleton[K, V](k: K, v: V, compare: (K, K) => Ordering at {}): Map[K, V] =
37
+ def singleton[K, V](k: K, v: V, ?compare: (K, K) => Ordering at {}): Map[K, V] =
38
38
  Map(internal::singleton(k, v), compare)
39
39
 
40
40
  /// Create a new map containing the mapping from `k` to `v` using a generic comparison function.
@@ -91,7 +91,7 @@ def getOrElse[K, V](m: Map[K, V], k: K) { default: => V }: V =
91
91
  def contains[K, V](m: Map[K, V], k: K): Bool =
92
92
  internal::get(m.tree, m.compare, k) match {
93
93
  case None() => false
94
- case Some(v) => true
94
+ case Some(_) => true
95
95
  }
96
96
 
97
97
  /// Get minimum in the map `m`.
@@ -156,15 +156,26 @@ def filter[K, V](m: Map[K, V]) { shouldKeep: V => Bool }: Map[K, V] =
156
156
  def foreach[K, V](m: Map[K, V]) { action: (K, V) => Unit }: Unit =
157
157
  internal::foreach(m.tree) {action}
158
158
 
159
+ /// Traverse all keys and their associated values in map `m` in *reverse*order,
160
+ /// running the function `action` on a key and its associated value.
161
+ ///
162
+ /// Law: `m.foreachReversed { action } === m.toList.reverse.foreach { action }`
163
+ ///
164
+ /// O(N)
165
+ ///
166
+ /// TODO: Support {Control} for early exits.
167
+ def foreachReversed[K, V](m: Map[K, V]) { action: (K, V) => Unit }: Unit =
168
+ internal::foreachReversed(m.tree) {action}
169
+
159
170
  /// Convert a map `m` into a list of (key, value) pairs.
160
171
  ///
161
172
  /// O(N)
162
173
  def toList[K, V](m: Map[K, V]): List[(K, V)] = {
163
174
  var acc = Nil()
164
- m.foreach { (k, v) =>
175
+ m.foreachReversed { (k, v) =>
165
176
  acc = Cons((k, v), acc)
166
177
  }
167
- acc.reverse
178
+ acc
168
179
  }
169
180
 
170
181
  /// Get a list of keys of the map `m`.
@@ -172,10 +183,10 @@ def toList[K, V](m: Map[K, V]): List[(K, V)] = {
172
183
  /// O(N)
173
184
  def keys[K, V](m: Map[K, V]): List[K] = {
174
185
  var acc = Nil()
175
- m.foreach { (k, _v) =>
186
+ m.foreachReversed { (k, _v) =>
176
187
  acc = Cons(k, acc)
177
188
  }
178
- acc.reverse
189
+ acc
179
190
  }
180
191
 
181
192
  /// Get a list of values of the map `m`.
@@ -183,10 +194,10 @@ def keys[K, V](m: Map[K, V]): List[K] = {
183
194
  /// O(N)
184
195
  def values[K, V](m: Map[K, V]): List[V] = {
185
196
  var acc = Nil()
186
- m.foreach { (_k, v) =>
197
+ m.foreachReversed { (_k, v) =>
187
198
  acc = Cons(v, acc)
188
199
  }
189
- acc.reverse
200
+ acc
190
201
  }
191
202
 
192
203
  /// Create a map from a list of (key, value) pairs and a pure, first-class comparison function.
@@ -195,7 +206,7 @@ def values[K, V](m: Map[K, V]): List[V] = {
195
206
  ///
196
207
  /// O(N) if the list is sorted by key,
197
208
  /// O(N log N) otherwise
198
- def fromList[K, V](pairs: List[(K, V)], compare: (K, K) => Ordering at {}): Map[K, V] =
209
+ def fromList[K, V](pairs: List[(K, V)], ?compare: (K, K) => Ordering at {}): Map[K, V] =
199
210
  Map(internal::fromList(pairs, compare), compare)
200
211
 
201
212
  /// Create a map from a list of (key, value) pairs and a generic comparison function.
@@ -253,7 +264,7 @@ def getIndex[K, V](m: Map[K, V], n: Int): Option[(K, V)] =
253
264
  /// Uses an explicit pure, first-class comparison function.
254
265
  ///
255
266
  /// O(???)
256
- def difference[K, V](m1: Map[K, V], m2: Map[K, V], compare: (K, K) => Ordering at {}) = {
267
+ def difference[K, V](m1: Map[K, V], m2: Map[K, V], ?compare: (K, K) => Ordering at {}) = {
257
268
  val newTree = internal::difference(m1.tree, m2.tree, compare)
258
269
  Map(newTree, compare)
259
270
  }
@@ -273,7 +284,7 @@ def difference[K, V](m1: Map[K, V], m2: Map[K, V]) = {
273
284
  /// Uses an explicit pure, first-class comparison function.
274
285
  ///
275
286
  /// O(???)
276
- def union[K, V](m1: Map[K, V], m2: Map[K, V], compare: (K, K) => Ordering at {}) { combine: (K, V, V) => V }: Map[K, V] = {
287
+ def union[K, V](m1: Map[K, V], m2: Map[K, V], ?compare: (K, K) => Ordering at {}) { combine: (K, V, V) => V }: Map[K, V] = {
277
288
  val newTree = internal::union(m1.tree, m2.tree, compare) {combine}
278
289
  Map(newTree, compare)
279
290
  }
@@ -283,7 +294,7 @@ def union[K, V](m1: Map[K, V], m2: Map[K, V], compare: (K, K) => Ordering at {})
283
294
  /// Uses an explicit pure, first-class comparison function.
284
295
  ///
285
296
  /// O(???)
286
- def union[K, V](m1: Map[K, V], m2: Map[K, V], compare: (K, K) => Ordering at {}) { combine: (V, V) => V }: Map[K, V] =
297
+ def union[K, V](m1: Map[K, V], m2: Map[K, V], ?compare: (K, K) => Ordering at {}) { combine: (V, V) => V }: Map[K, V] =
287
298
  union(m1, m2, compare) { (k, v1, v2) => combine(v1, v2) }
288
299
 
289
300
  /// Construct a new map which contains the elements of both `m1` and `m2`.
@@ -297,7 +308,7 @@ def union[K, V](m1: Map[K, V], m2: Map[K, V]): Map[K, V] =
297
308
  /// Construct a new map which combines all elements that are in both `m1` and `m2` using the `combine` function.
298
309
  ///
299
310
  /// O(???)
300
- def intersection[K, A, B, C](m1: Map[K, A], m2: Map[K, B], compare: (K, K) => Ordering at {}) { combine: (K, A, B) => C }: Map[K, C] = {
311
+ def intersection[K, A, B, C](m1: Map[K, A], m2: Map[K, B], ?compare: (K, K) => Ordering at {}) { combine: (K, A, B) => C }: Map[K, C] = {
301
312
  val newTree = internal::intersection(m1.tree, m2.tree, compare) {combine}
302
313
  Map(newTree, compare)
303
314
  }
@@ -305,7 +316,7 @@ def intersection[K, A, B, C](m1: Map[K, A], m2: Map[K, B], compare: (K, K) => Or
305
316
  /// Construct a new map which combines all elements that are in both `m1` and `m2` using the `combine` function.
306
317
  ///
307
318
  /// O(???)
308
- def intersection[K, A, B, C](m1: Map[K, A], m2: Map[K, B], compare: (K, K) => Ordering at {}) { combine: (A, B) => C }: Map[K, C] =
319
+ def intersection[K, A, B, C](m1: Map[K, A], m2: Map[K, B], ?compare: (K, K) => Ordering at {}) { combine: (A, B) => C }: Map[K, C] =
309
320
  m1.intersection[K, A, B, C](m2, compare) { (k, v1, v2) => combine(v1, v2) }
310
321
 
311
322
  /// Construct a new map which combines all elements that are in both `m1` and `m2`.
@@ -315,6 +326,47 @@ def intersection[K, A, B, C](m1: Map[K, A], m2: Map[K, B], compare: (K, K) => Or
315
326
  def intersection[K, A, B](m1: Map[K, A], m2: Map[K, B]): Map[K, A] =
316
327
  m1.intersection[K, A, B, A](m2, m1.compare) { (k, v1, v2) => v1 }
317
328
 
329
+
330
+
331
+ // Streaming
332
+ // ---------
333
+
334
+ /// Turns a `map` into a producer of a push stream
335
+ /// of `(key, value)` pairs by emitting each contained *in order*.
336
+ def each[K, V](map: Map[K, V]): Unit / emit[(K, V)] =
337
+ map.foreach { (k, v) => do emit((k, v)) }
338
+
339
+ /// Turns a `map` into a producer of a push stream
340
+ /// of its keys by emitting each contained *in order*.
341
+ def eachKey[K, V](map: Map[K, V]): Unit / emit[K] =
342
+ map.foreach { (k, _v) => do emit(k) }
343
+
344
+ /// Turns a `map` into a producer of a push stream
345
+ /// of its values by emitting each contained.
346
+ def eachValue[K, V](map: Map[K, V]): Unit / emit[V] =
347
+ map.foreach { (_k, v) => do emit(v) }
348
+
349
+ /// Collects `(key, value)` pairs from a push stream producer `stream` into a new `map`
350
+ /// using the provided `compare` function, discarding the result of the producer.
351
+ def collect[K, V](?compare: (K, K) => Ordering at {}) { stream: () => Unit / emit[(K, V)] }: Map[K, V] =
352
+ returning::collect[K, V, Unit](compare){stream}.second
353
+
354
+ namespace returning {
355
+ /// Collects `(key, value)` pairs from a push stream producer `stream` into a new `map`,
356
+ /// using the provided `compare` function, returning the result of the producer as well as the collected map.
357
+ def collect[K, V, R](?compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Map[K, V]) =
358
+ var map = map::empty[K, V](compare)
359
+ val r = try {
360
+ stream()
361
+ } with emit[(K, V)] { case (k, v) =>
362
+ map = map.put(k, v)
363
+ resume(())
364
+ }
365
+ (r, map)
366
+ }
367
+
368
+ // Internal tree representation
369
+
318
370
  /// Please don't directly use:
319
371
  /// - the `Tree` type
320
372
  /// - its internal constructors `Bin` & `Tip`,
@@ -527,6 +579,27 @@ namespace internal {
527
579
  go(m)
528
580
  }
529
581
 
582
+ /// Traverse all keys and their associated values in tree `m` in *reverse* order,
583
+ /// running the function `action` on a key and its associated value.
584
+ ///
585
+ /// Law: `m.foreachReversed { action } === m.toList.reverse.foreach { action }`
586
+ ///
587
+ /// O(N)
588
+ ///
589
+ /// TODO: Support {Control} for early exits.
590
+ def foreachReversed[K, V](m: Tree[K, V]) { action: (K, V) => Unit }: Unit = {
591
+ def go(m: Tree[K, V]): Unit = {
592
+ m match {
593
+ case Tip() => ()
594
+ case Bin(_, k, v, l, r) =>
595
+ go(r)
596
+ action(k, v)
597
+ go(l)
598
+ }
599
+ }
600
+ go(m)
601
+ }
602
+
530
603
  /// Create a tree from a list of (key, value) pairs.
531
604
  /// If the list contains more than one value for the same key,
532
605
  /// only the last value is used in the tree.
@@ -572,11 +645,11 @@ namespace internal {
572
645
  case Nil() => (Tip(), [], [])
573
646
  case Cons((k, v), rest) =>
574
647
  if (level == 1) {
575
- val singleton = Bin(1, k, v, Tip(), Tip())
648
+ val one = singleton(k, v)
576
649
  if (notOrdered(k, rest)) {
577
- (singleton, [], rest)
650
+ (one, [], rest)
578
651
  } else {
579
- (singleton, rest, [])
652
+ (one, rest, [])
580
653
  }
581
654
  } else {
582
655
  val res = create(level.bitwiseShr(1), pairs)
@@ -584,7 +657,8 @@ namespace internal {
584
657
  case (_, Nil(), _) => res
585
658
  case (l, Cons((k2, v2), Nil()), zs) => (l.putMax(k2, v2), [], zs)
586
659
  case (l, Cons((k2, v2), rest2), _) =>
587
- val xs = Cons((k2, v2), rest2) // @-pattern
660
+ // @-pattern
661
+ val xs = Cons((k2, v2), rest2)
588
662
 
589
663
  if (notOrdered(k2, rest2)) { (l, [], xs) }
590
664
  else {
@@ -608,7 +682,7 @@ namespace internal {
608
682
  cr match {
609
683
  case (r, xs, Nil()) => go(level.bitwiseShl(1), link(k, v, l, r), xs)
610
684
  case (r, Nil(), ys) => insertMany(link(k, v, l, r), ys)
611
- case _ => panic("create: go: cannot happen, invariant broken!")
685
+ case _ => <{ "create: go: cannot happen, invariant broken!" }>
612
686
  }
613
687
  }
614
688
  }
@@ -763,9 +837,8 @@ namespace internal {
763
837
  val ratio = 2
764
838
  val delta = 3
765
839
 
766
- def bin[K, V](k: K, v: V, l: Tree[K, V], r: Tree[K, V]): Tree[K, V] = {
840
+ def bin[K, V](k: K, v: V, l: Tree[K, V], r: Tree[K, V]): Tree[K, V] =
767
841
  Bin(l.size() + r.size() + 1, k, v, l, r)
768
- }
769
842
 
770
843
  def balance[K, V](k: K, v: V, l: Tree[K, V], r: Tree[K, V]): Tree[K, V] = {
771
844
  /*
@@ -778,10 +851,8 @@ namespace internal {
778
851
  t2 t3 t1 t2
779
852
  */
780
853
  def singleL[A, B](k1: A, v1: B, t1: Tree[A, B], m: Tree[A, B]): Tree[A, B] = {
781
- m match {
782
- case Bin(_, k2, v2, t2, t3) => bin(k2, v2, bin(k1, v1, t1, t2), t3)
783
- case _ => panic("impossible: singleL: Tip")
784
- }
854
+ val Bin(_, k2, v2, t2, t3) = m else <{ "impossible: singleL: Tip" }>
855
+ bin(k2, v2, bin(k1, v1, t1, t2), t3)
785
856
  }
786
857
 
787
858
  /*
@@ -794,10 +865,8 @@ namespace internal {
794
865
  t1 t2 t1 t2 t3
795
866
  */
796
867
  def singleR[A, B](k1: A, v1: B, m: Tree[A, B], t3: Tree[A, B]): Tree[A, B] = {
797
- m match {
798
- case Bin(_, k2, v2, t1, t2) => bin(k2, v2, t1, bin(k1, v1, t2, t3))
799
- case _ => panic("impossible: singleR: Tip")
800
- }
868
+ val Bin(_, k2, v2, t1, t2) = m else <{ "impossible: singleR: Tip" }>
869
+ bin(k2, v2, t1, bin(k1, v1, t2, t3))
801
870
  }
802
871
 
803
872
  /*
@@ -812,11 +881,8 @@ namespace internal {
812
881
  t2 t3
813
882
  */
814
883
  def doubleL[A, B](k1: A, v1: B, t1: Tree[A, B], m: Tree[A, B]): Tree[A, B] = {
815
- m match {
816
- case Bin(_, k2, v2, Bin(_, k3, v3, t2, t3), t4) =>
817
- bin(k3, v3, bin(k1, v1, t1, t2), bin(k2, v2, t3, t4))
818
- case _ => panic("impossible: doubleL: Tip")
819
- }
884
+ val Bin(_, k2, v2, Bin(_, k3, v3, t2, t3), t4) = m else <{ "impossible: doubleL: Tip" }>
885
+ bin(k3, v3, bin(k1, v1, t1, t2), bin(k2, v2, t3, t4))
820
886
  }
821
887
 
822
888
  /*
@@ -831,12 +897,8 @@ namespace internal {
831
897
  t2 t3
832
898
  */
833
899
  def doubleR[A, B](k1: A, v1: B, m: Tree[A, B], t4: Tree[A, B]): Tree[A, B] = {
834
- m match {
835
- case Bin(_, k2, v2, t1, Bin(_, k3, v3, t2, t3)) =>
836
- bin(k3, v3, bin(k2, v2, t1, t2), bin(k1, v1, t3, t4))
837
- case _ =>
838
- panic("impossible: doubleR: Tip")
839
- }
900
+ val Bin(_, k2, v2, t1, Bin(_, k3, v3, t2, t3)) = m else <{ "impossible: doubleR: Tip" }>
901
+ bin(k3, v3, bin(k2, v2, t1, t2), bin(k1, v1, t3, t4))
840
902
  }
841
903
 
842
904
  def rotateL[A, B](k: A, v: B, l: Tree[A, B], r: Tree[A, B]): Tree[A, B] = {
@@ -859,7 +921,7 @@ namespace internal {
859
921
  if ((sizeL + sizeR) <= 1) { Bin(sizeCombined, k, v, l, r) }
860
922
  else if (sizeR > (delta * sizeL)) { rotateL(k, v, l, r) }
861
923
  else if (sizeL > (delta * sizeR)) { rotateR(k, v, l, r) }
862
- else { Bin(sizeCombined, k, v, l, r)}
924
+ else { Bin(sizeCombined, k, v, l, r) }
863
925
  }
864
926
 
865
927
  record MaxView[K, V](k: K, v: V, m: Tree[K, V])
@@ -963,13 +1025,13 @@ namespace internal {
963
1025
  // Section: prettyprinting for trees:
964
1026
 
965
1027
  /// Works only on the backends that support `genericShow` (JavaScript)!
966
- def prettyTree[K, V](m: Tree[K, V]): String = {
1028
+ def prettyTree[K, V](m: Tree[K, V]) { ?key::show: K => String } { ?value::show: V => String }: String = {
967
1029
  // Helper function to recursively build the string representation of the tree
968
1030
  def go(t: Tree[K, V], prefix: String, isTail: Bool): String = {
969
1031
  t match {
970
1032
  case Tip() => ""
971
1033
  case Bin(_, k, v, l, r) =>
972
- val pair = k.show ++ " → " ++ v.show
1034
+ val pair = key::show(k) ++ " → " ++ value::show(v)
973
1035
  val currentLine = prefix ++ (if (isTail) "└── " else "├── ") ++ pair ++ "\n"
974
1036
 
975
1037
  val newPrefix = prefix ++ (if (isTail) " " else "│ ")
@@ -984,47 +1046,11 @@ namespace internal {
984
1046
  go(m, "", true)
985
1047
  }
986
1048
 
987
- def prettyPairs[K, V](list: List[(K, V)]) { showLeft: K => String } { showRight: V => String }: String = {
1049
+ def prettyPairs[K, V](list: List[(K, V)]) { ?key::show: K => String } { ?value::show: V => String }: String = {
988
1050
  val res: String =
989
- list.map { case (k, v) => showLeft(k) ++ " → " ++ showRight(v) }
1051
+ list.map { case (k, v) => key::show(k) ++ " → " ++ value::show(v) }
990
1052
  .join(", ")
991
1053
 
992
1054
  "[" ++ res ++ "]"
993
1055
  }
994
- }
995
-
996
-
997
- // Streaming
998
- // ---------
999
-
1000
- /// Turns a `map` into a producer of a push stream
1001
- /// of `(key, value)` pairs by emitting each contained *in order*.
1002
- def each[K, V](map: Map[K, V]): Unit / emit[(K, V)] =
1003
- map.foreach { (k, v) => do emit((k, v)) }
1004
-
1005
- /// Turns a `map` into a producer of a push stream
1006
- /// of its keys by emitting each contained *in order*.
1007
- def eachKey[K, V](map: Map[K, V]): Unit / emit[K] =
1008
- map.foreach { (k, _v) => do emit(k) }
1009
-
1010
- /// Turns a `map` into a producer of a push stream
1011
- /// of its values by emitting each contained.
1012
- def eachValue[K, V](map: Map[K, V]): Unit / emit[V] =
1013
- map.foreach { (_k, v) => do emit(v) }
1014
-
1015
- /// Collects `(key, value)` pairs from a push stream producer `stream` into a new `map`
1016
- /// using the provided `compare` function, discarding the result of the producer.
1017
- def collect[K, V](compare: (K, K) => Ordering at {}) { stream: () => Unit / emit[(K, V)] }: Map[K, V] =
1018
- returning::collect[K, V, Unit](compare){stream}.second
1019
-
1020
- namespace returning {
1021
- /// Collects `(key, value)` pairs from a push stream producer `stream` into a new `map`,
1022
- /// using the provided `compare` function, returning the result of the producer as well as the collected map.
1023
- def collect[K, V, R](compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Map[K, V]) =
1024
- try {
1025
- (stream(), empty(compare))
1026
- } with emit[(K, V)] { case (k, v) =>
1027
- val (r, map) = resume(());
1028
- (r, map.put(k, v))
1029
- }
1030
- }
1056
+ }