@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 +0 -0
- package/libraries/common/array.effekt +4 -3
- package/libraries/common/bytearray.effekt +44 -25
- package/libraries/common/char.effekt +12 -5
- package/libraries/common/effekt.effekt +10 -13
- package/libraries/common/list.effekt +22 -0
- package/libraries/common/map.effekt +109 -83
- package/libraries/common/set.effekt +25 -14
- package/libraries/common/string.effekt +28 -0
- package/libraries/common/stringbuffer.effekt +5 -5
- package/libraries/llvm/bytearray.c +14 -5
- package/libraries/llvm/forward-declare-c.ll +1 -0
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +3 -3
- package/licenses/mit license - mit-license.html +61 -53
- package/licenses/the bsd license - bsd-license.html +60 -52
- package/licenses/the mit license - mit.html +60 -52
- package/package.json +1 -1
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
|
-
|
|
67
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
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 =>
|
|
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' =>
|
|
164
|
-
case c =>
|
|
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
|
-
|
|
169
|
-
|
|
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
|
-
//
|
|
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
|
-
/// -
|
|
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
|
-
|
|
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(
|
|
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.
|
|
175
|
+
m.foreachReversed { (k, v) =>
|
|
165
176
|
acc = Cons((k, v), acc)
|
|
166
177
|
}
|
|
167
|
-
acc
|
|
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.
|
|
186
|
+
m.foreachReversed { (k, _v) =>
|
|
176
187
|
acc = Cons(k, acc)
|
|
177
188
|
}
|
|
178
|
-
acc
|
|
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.
|
|
197
|
+
m.foreachReversed { (_k, v) =>
|
|
187
198
|
acc = Cons(v, acc)
|
|
188
199
|
}
|
|
189
|
-
acc
|
|
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
|
|
648
|
+
val one = singleton(k, v)
|
|
576
649
|
if (notOrdered(k, rest)) {
|
|
577
|
-
(
|
|
650
|
+
(one, [], rest)
|
|
578
651
|
} else {
|
|
579
|
-
(
|
|
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
|
-
|
|
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 _ =>
|
|
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
|
|
782
|
-
|
|
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
|
|
798
|
-
|
|
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
|
|
816
|
-
|
|
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
|
|
835
|
-
|
|
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
|
|
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)]) {
|
|
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) =>
|
|
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
|
+
}
|