@effekt-lang/effekt 0.18.0 → 0.20.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/buffer.effekt +3 -3
- package/libraries/common/bytearray.effekt +64 -1
- package/libraries/common/effekt.effekt +45 -10
- package/libraries/common/heap.effekt +103 -0
- package/libraries/common/io/filesystem.effekt +49 -66
- package/libraries/common/io/network.effekt +8 -5
- package/libraries/common/json.effekt +30 -22
- package/libraries/common/map.effekt +992 -0
- package/libraries/common/regex.effekt +64 -0
- package/libraries/common/resizable_array.effekt +235 -0
- package/libraries/common/set.effekt +234 -0
- package/libraries/common/stream.effekt +47 -2
- package/libraries/common/string.effekt +7 -0
- package/libraries/common/stringbuffer.effekt +65 -0
- package/libraries/common/union_find.effekt +113 -0
- package/libraries/llvm/bytearray.c +36 -7
- package/libraries/llvm/forward-declare-c.ll +2 -0
- package/libraries/llvm/io.c +17 -43
- package/libraries/llvm/main.c +2 -1
- package/libraries/llvm/panic.c +20 -0
- package/libraries/llvm/rts.ll +141 -142
- package/licenses/eclipse public license, version 2.0 - epl-2.0.html +4 -4
- package/licenses/mit license - mit-license.html +82 -18
- package/licenses/the bsd license - bsd-license.html +81 -17
- package/licenses/the mit license - mit.html +81 -17
- package/package.json +1 -1
- package/libraries/chez/common/text/regex.effekt +0 -31
- package/libraries/js/text/regex.effekt +0 -33
- package/libraries/llvm/hole.c +0 -11
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module regex
|
|
2
|
+
|
|
3
|
+
import string
|
|
4
|
+
|
|
5
|
+
extern include chez "text/pregexp.scm"
|
|
6
|
+
|
|
7
|
+
extern type Regex
|
|
8
|
+
|
|
9
|
+
record Match(matched: String, index: Int)
|
|
10
|
+
|
|
11
|
+
extern pure def regex(str: String): Regex =
|
|
12
|
+
js "new RegExp(${str})"
|
|
13
|
+
chez "(pregexp ${str})"
|
|
14
|
+
vm "regex::regex(String)"
|
|
15
|
+
|
|
16
|
+
def exec(reg: Regex, str: String): Option[Match] = {
|
|
17
|
+
val v = internal::exec(reg, str)
|
|
18
|
+
if (v.isUndefined)
|
|
19
|
+
None()
|
|
20
|
+
else
|
|
21
|
+
Some(Match(internal::matched(v), internal::index(v)))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
namespace internal {
|
|
25
|
+
|
|
26
|
+
/// The type RegexMatch is used internally to represent platform
|
|
27
|
+
/// dependent results of matching a regex.
|
|
28
|
+
extern type RegexMatch
|
|
29
|
+
// js: { matched: String, index: Int } | undefined
|
|
30
|
+
// vm: scala.util.matching.Regex.Match | null
|
|
31
|
+
|
|
32
|
+
extern pure def matched(r: RegexMatch): String =
|
|
33
|
+
js "${r}.matched"
|
|
34
|
+
chez "(vector-ref ${r} 0)"
|
|
35
|
+
vm "regex::matched(RegexMatch)"
|
|
36
|
+
|
|
37
|
+
extern pure def index(r: RegexMatch): Int =
|
|
38
|
+
js "${r}.index"
|
|
39
|
+
chez "(vector-ref ${r} 1)"
|
|
40
|
+
vm "regex::index(RegexMatch)"
|
|
41
|
+
|
|
42
|
+
extern js """
|
|
43
|
+
function regex$exec(reg, str) {
|
|
44
|
+
var res = reg.exec(str);
|
|
45
|
+
if (res === null) { return undefined }
|
|
46
|
+
else { return { matched: res[0], index: res.index } }
|
|
47
|
+
}
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
extern chez """
|
|
51
|
+
(define regex-exec
|
|
52
|
+
(lambda (regex str)
|
|
53
|
+
(let* ([positions (pregexp-match-positions regex str)]
|
|
54
|
+
[match (pregexp-match regex str)])
|
|
55
|
+
(if (and positions match)
|
|
56
|
+
(vector (car match) (caar positions))
|
|
57
|
+
#f))))
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
extern io def exec(reg: Regex, str: String): RegexMatch =
|
|
61
|
+
js "regex$exec(${reg}, ${str})"
|
|
62
|
+
chez "(regex-exec ${reg} ${str})"
|
|
63
|
+
vm "regex::exec(Regex, String)"
|
|
64
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
module resizable_array
|
|
2
|
+
|
|
3
|
+
import ref
|
|
4
|
+
import array
|
|
5
|
+
|
|
6
|
+
record ResizableArray[T](rawSizePtr: Ref[Int], rawContentPtr: Ref[Array[T]])
|
|
7
|
+
|
|
8
|
+
// These numbers should be optimized based on benchmarking
|
|
9
|
+
// According to https://en.wikipedia.org/wiki/Dynamic_array most use 1.5 or 2
|
|
10
|
+
|
|
11
|
+
/// Factor by which to grow the capacity when it becomes too small
|
|
12
|
+
val growFactor = 1.5
|
|
13
|
+
/// shrink array when size / capacity falls below this threshold
|
|
14
|
+
/// should be < 1/growFactor
|
|
15
|
+
val shrinkThreshold = 0.4
|
|
16
|
+
|
|
17
|
+
/// Number of elements in the dynamic array
|
|
18
|
+
///
|
|
19
|
+
/// O(1)
|
|
20
|
+
def size[T](arr: ResizableArray[T]) = arr.rawSizePtr.get
|
|
21
|
+
|
|
22
|
+
/// Allocate a new, empty dynamic array with given initial capacity
|
|
23
|
+
def resizableArray[T](capacity: Int): ResizableArray[T] = {
|
|
24
|
+
ResizableArray(ref(0), ref(allocate(capacity)))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/// Allocate a new, empty dynamic array
|
|
28
|
+
def resizableArray[T](): ResizableArray[T] = resizableArray(8)
|
|
29
|
+
|
|
30
|
+
/// Throw an OutOfBounds exception if index is not a valid index into arr
|
|
31
|
+
def boundsCheck[T](arr: ResizableArray[T], index: Int): Unit / Exception[OutOfBounds] = {
|
|
32
|
+
if (index < 0 && index >= arr.size) {
|
|
33
|
+
do raise(OutOfBounds(), "Array index out of bounds: " ++ show(index))
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// get the element at position index in the array
|
|
38
|
+
///
|
|
39
|
+
/// precondition: index is a valid index into the array
|
|
40
|
+
///
|
|
41
|
+
/// O(1)
|
|
42
|
+
def unsafeGet[T](arr: ResizableArray[T], index: Int): T = {
|
|
43
|
+
arr.rawContentPtr.get.unsafeGet(index)
|
|
44
|
+
}
|
|
45
|
+
/// get the element at position index in the array
|
|
46
|
+
///
|
|
47
|
+
/// O(1)
|
|
48
|
+
def get[T](arr: ResizableArray[T], index: Int): T / Exception[OutOfBounds] = {
|
|
49
|
+
arr.boundsCheck(index);
|
|
50
|
+
arr.unsafeGet(index)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// set the element at position index in the array
|
|
54
|
+
///
|
|
55
|
+
/// precondition: index is a valid index into the array
|
|
56
|
+
///
|
|
57
|
+
/// O(1)
|
|
58
|
+
def unsafeSet[T](arr: ResizableArray[T], index: Int, value: T): Unit = {
|
|
59
|
+
arr.rawContentPtr.get.unsafeSet(index, value)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/// set the element at position index in the array
|
|
63
|
+
///
|
|
64
|
+
/// O(1)
|
|
65
|
+
def set[T](arr: ResizableArray[T], index: Int, value: T): Unit / Exception[OutOfBounds] = {
|
|
66
|
+
arr.boundsCheck(index);
|
|
67
|
+
arr.unsafeSet(index, value)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// swap the elements at the given positions in the array
|
|
71
|
+
///
|
|
72
|
+
/// precondition: both are valid indices into the array
|
|
73
|
+
///
|
|
74
|
+
/// O(1)
|
|
75
|
+
def unsafeSwap[T](arr: ResizableArray[T], index1: Int, index2: Int): Unit = {
|
|
76
|
+
val raw = arr.rawContentPtr.get
|
|
77
|
+
val tmp = raw.unsafeGet(index1)
|
|
78
|
+
raw.unsafeSet(index1, raw.unsafeGet(index2))
|
|
79
|
+
raw.unsafeSet(index2, tmp)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// swap the elements at the given positions in the array
|
|
83
|
+
///
|
|
84
|
+
/// O(1)
|
|
85
|
+
def swap[T](arr: ResizableArray[T], index1: Int, index2: Int): Unit / Exception[OutOfBounds] = {
|
|
86
|
+
arr.boundsCheck(max(index1, index2))
|
|
87
|
+
arr.unsafeSwap(index1, index2)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/// Change the dynamic to have exactly the given capacity
|
|
91
|
+
///
|
|
92
|
+
/// precondition: given capacity is at least the size of the array
|
|
93
|
+
///
|
|
94
|
+
/// O(n)
|
|
95
|
+
def unsafeSetCapacity[T](arr: ResizableArray[T], capacity: Int): Unit = {
|
|
96
|
+
with on[OutOfBounds].panic
|
|
97
|
+
val oldRaw = arr.rawContentPtr.get
|
|
98
|
+
if (oldRaw.size != capacity) {
|
|
99
|
+
val newRaw = array::allocate(capacity)
|
|
100
|
+
oldRaw.copy(0, newRaw, 0, arr.size)
|
|
101
|
+
arr.rawContentPtr.set(newRaw)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// Change the resizable array to have exactly the given capacity.
|
|
106
|
+
/// This only changes the size of the backing array, not the `size`.
|
|
107
|
+
///
|
|
108
|
+
/// O(n)
|
|
109
|
+
def setCapacity[T](arr: ResizableArray[T], capacity: Int): Unit / Exception[OutOfBounds] = {
|
|
110
|
+
if (arr.size > capacity) {
|
|
111
|
+
do raise(OutOfBounds(), "Cannot change capacity of ResizableArray to " ++ capacity.show ++ " below size " ++ arr.size.show)
|
|
112
|
+
}
|
|
113
|
+
arr.unsafeSetCapacity(capacity)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// If the shrinkThreshold is reached, shrink by growFactor, otherwise do nothing
|
|
117
|
+
///
|
|
118
|
+
/// O(n)
|
|
119
|
+
def maybeShrink[T](arr: ResizableArray[T]): Unit = {
|
|
120
|
+
if(arr.size.toDouble < arr.rawContentPtr.get.size.toDouble * shrinkThreshold) {
|
|
121
|
+
val newCap = max(arr.size, (arr.rawContentPtr.get.size.toDouble / growFactor).ceil)
|
|
122
|
+
arr.unsafeSetCapacity(newCap)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/// makes sure capacity is at least the given one
|
|
127
|
+
///
|
|
128
|
+
/// O(given capacity - current capacity) amortized, O(n) worst case // TODO ?
|
|
129
|
+
def ensureCapacity[T](arr: ResizableArray[T], capacity: Int): Unit / Exception[OutOfBounds] = {
|
|
130
|
+
if (arr.rawContentPtr.get.size < capacity) {
|
|
131
|
+
val curCapd: Double = arr.rawContentPtr.get.size.toDouble
|
|
132
|
+
val minGrowCapacity: Int = (curCapd * growFactor + 1.0).toInt
|
|
133
|
+
val newCapacity = max(capacity, minGrowCapacity)
|
|
134
|
+
arr.setCapacity(newCapacity)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/// Set the value at given position, resizing if necessary
|
|
139
|
+
/// Note: New elements might be uninitialized!!!
|
|
140
|
+
///
|
|
141
|
+
/// O(max(1,index - n)) amortized, O(n) worst case if index > capacity
|
|
142
|
+
def setResizing[T](arr: ResizableArray[T], index: Int, value: T): Unit / Exception[OutOfBounds] = {
|
|
143
|
+
if (index < 0) {
|
|
144
|
+
do raise(OutOfBounds(), "Negative index " ++ index.show)
|
|
145
|
+
}
|
|
146
|
+
if (index < arr.size) {
|
|
147
|
+
arr.rawContentPtr.get.unsafeSet(index, value)
|
|
148
|
+
}
|
|
149
|
+
ensureCapacity(arr, index + 1)
|
|
150
|
+
arr.rawContentPtr.get.unsafeSet(index, value)
|
|
151
|
+
arr.rawSizePtr.set(index + 1)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/// Add a new element at the end of the resizable array.
|
|
155
|
+
/// Return the index of the new element
|
|
156
|
+
///
|
|
157
|
+
/// O(1) amortized, O(n) worst case
|
|
158
|
+
def add[T](arr: ResizableArray[T], value: T): Int = {
|
|
159
|
+
with on[OutOfBounds].panic();
|
|
160
|
+
val idx = arr.size
|
|
161
|
+
arr.setResizing(idx, value)
|
|
162
|
+
idx
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// Remove and return the rightmost element in the resizable array.
|
|
166
|
+
///
|
|
167
|
+
/// O(1) amortized, O(n) worst case
|
|
168
|
+
def popRight[T](arr: ResizableArray[T]): T / Exception[OutOfBounds] = {
|
|
169
|
+
arr.boundsCheck(arr.size - 1)
|
|
170
|
+
arr.rawSizePtr.set(arr.size - 1)
|
|
171
|
+
val r = arr.unsafeGet(arr.size)
|
|
172
|
+
arr.maybeShrink()
|
|
173
|
+
r
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def foreachIndex[T](arr: ResizableArray[T]){ body: (Int, T) => Unit }: Unit = {
|
|
178
|
+
each(0, arr.size) { i =>
|
|
179
|
+
body(i, arr.rawContentPtr.get.unsafeGet(i))
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
def foreachIndex[T](arr: ResizableArray[T]){ body: (Int, T) {Control} => Unit }: Unit = {
|
|
183
|
+
each(0, arr.size) { (i){label} =>
|
|
184
|
+
body(i, arr.rawContentPtr.get.unsafeGet(i)){label}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
def foreach[T](arr: ResizableArray[T]){ body: T => Unit }: Unit = {
|
|
188
|
+
each(0, arr.size) { i =>
|
|
189
|
+
body(arr.rawContentPtr.get.unsafeGet(i))
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
def foreach[T](arr: ResizableArray[T]){ body: (T) {Control} => Unit }: Unit = {
|
|
193
|
+
each(0, arr.size) { (i){label} =>
|
|
194
|
+
body(arr.rawContentPtr.get.unsafeGet(i)){label}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
def foreachIndexReversed[T](arr: ResizableArray[T]){ body: (Int, T){Control} => Unit }: Unit = {
|
|
198
|
+
var i = arr.size - 1
|
|
199
|
+
loop { {l} =>
|
|
200
|
+
if (i < 0) { l.break() }
|
|
201
|
+
body(i, arr.rawContentPtr.get.unsafeGet(i)){l}
|
|
202
|
+
i = i - 1
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
def foreachIndexReversed[T](arr: ResizableArray[T]){ body: (Int, T) => Unit }: Unit = {
|
|
206
|
+
var i = arr.size - 1
|
|
207
|
+
while(i >= 0) {
|
|
208
|
+
body(i, arr.rawContentPtr.get.unsafeGet(i))
|
|
209
|
+
i = i - 1
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
def foreachReversed[T](arr: ResizableArray[T]){ body: (T){Control} => Unit }: Unit = {
|
|
213
|
+
var i = arr.size - 1
|
|
214
|
+
loop { {l} =>
|
|
215
|
+
if (i < 0) { l.break() }
|
|
216
|
+
body(arr.rawContentPtr.get.unsafeGet(i)){l}
|
|
217
|
+
i = i - 1
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
def foreachReversed[T](arr: ResizableArray[T]){ body: T => Unit }: Unit = {
|
|
221
|
+
var i = arr.size - 1
|
|
222
|
+
while (i >= 0) {
|
|
223
|
+
body(arr.rawContentPtr.get.unsafeGet(i))
|
|
224
|
+
i = i - 1
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
def toList[T](arr: ResizableArray[T]): List[T] = {
|
|
229
|
+
def go(i: Int, acc: List[T]): List[T] = {
|
|
230
|
+
if (i < 0) { acc } else {
|
|
231
|
+
go(i - 1, Cons(arr.unsafeGet(i), acc))
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
go(arr.size - 1, Nil())
|
|
235
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
module set
|
|
2
|
+
|
|
3
|
+
import map
|
|
4
|
+
|
|
5
|
+
/// Ordered finite immutable set, backed by balanced binary trees of logarithmic depth.
|
|
6
|
+
record Set[A](tree: internal::Tree[A, Unit], compare: (A, A) => Ordering at {})
|
|
7
|
+
|
|
8
|
+
/// Create a new empty set using a pure, first-class comparison function.
|
|
9
|
+
///
|
|
10
|
+
/// O(1)
|
|
11
|
+
def empty[A](compare: (A, A) => Ordering at {}): Set[A] =
|
|
12
|
+
Set(internal::empty(), compare)
|
|
13
|
+
|
|
14
|
+
/// Create a new empty set using a generic comparison function.
|
|
15
|
+
/// Only available on JavaScript backends!
|
|
16
|
+
///
|
|
17
|
+
/// O(1)
|
|
18
|
+
def emptyGeneric[A](): Set[A] =
|
|
19
|
+
Set(
|
|
20
|
+
internal::empty(),
|
|
21
|
+
box { (left: A, right: A) => genericCompare(left, right) }
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
/// Check if set `s` is empty.
|
|
25
|
+
///
|
|
26
|
+
/// O(1)
|
|
27
|
+
def isEmpty[A](s: Set[A]): Bool = internal::isEmpty(s.tree)
|
|
28
|
+
|
|
29
|
+
/// Check if set `s` is nonempty.
|
|
30
|
+
///
|
|
31
|
+
/// O(1)
|
|
32
|
+
def nonEmpty[A](s: Set[A]): Bool = internal::nonEmpty(s.tree)
|
|
33
|
+
|
|
34
|
+
/// Create a new set containing a single `element`.
|
|
35
|
+
/// Requires a pure, first-class comparison function.
|
|
36
|
+
///
|
|
37
|
+
/// O(1)
|
|
38
|
+
def singleton[A](element: A, compare: (A, A) => Ordering at {}): Set[A] =
|
|
39
|
+
Set(internal::singleton(element, ()), compare)
|
|
40
|
+
|
|
41
|
+
/// Create a new set containing a single `element` and a generic comparison function.
|
|
42
|
+
/// Only available on the JavaScript backends!
|
|
43
|
+
///
|
|
44
|
+
/// O(1)
|
|
45
|
+
def singletonGeneric[A](element: A): Set[A] =
|
|
46
|
+
Set(
|
|
47
|
+
internal::singleton(element, ()),
|
|
48
|
+
box { (left: A, right: A) => genericCompare(left, right) }
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
/// Get the size of the set (the number of its elements).
|
|
52
|
+
///
|
|
53
|
+
/// O(1)
|
|
54
|
+
def size[A](s: Set[A]): Int = internal::size(s.tree)
|
|
55
|
+
|
|
56
|
+
/// Insert a new element `a` into the set `s`.
|
|
57
|
+
///
|
|
58
|
+
/// O(log N)
|
|
59
|
+
def insert[A](s: Set[A], a: A): Set[A] = {
|
|
60
|
+
val newTree = internal::put(s.tree, s.compare, a, ())
|
|
61
|
+
Set(newTree, s.compare)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// Create a set from a given map by ignoring the values.
|
|
65
|
+
///
|
|
66
|
+
/// O(N)
|
|
67
|
+
def fromMapKeys[K, V](map: Map[K, V]): Set[K] =
|
|
68
|
+
Set(internal::forget(map.tree), map.compare)
|
|
69
|
+
|
|
70
|
+
/// Create a map from a set and a function,
|
|
71
|
+
/// reusing the set's comparison.
|
|
72
|
+
///
|
|
73
|
+
/// O(N)
|
|
74
|
+
def toMap[K, V](keys: Set[K]) { valueOf: K => V }: Map[K, V] = {
|
|
75
|
+
val newTree: internal::Tree[K, V] = internal::map(keys.tree) { (k, _v) => valueOf(k) }
|
|
76
|
+
Map(newTree, keys.compare)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Create a set from a given list and a pure, first-class comparison function.
|
|
80
|
+
///
|
|
81
|
+
/// O(N log N)
|
|
82
|
+
/// O(N) if the list is sorted
|
|
83
|
+
def fromList[A](list: List[A], compare: (A, A) => Ordering at {}): Set[A] = {
|
|
84
|
+
val tree: internal::Tree[A, Unit] = internal::fromList(list.map { k => (k, ()) }, compare)
|
|
85
|
+
Set(tree, compare)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Create a set from a given list with a generic comparison function.
|
|
89
|
+
/// Works only on the JavaScript backends!
|
|
90
|
+
///
|
|
91
|
+
/// O(N log N)
|
|
92
|
+
/// O(N) if the list is sorted
|
|
93
|
+
def fromListGeneric[A](list: List[A]): Set[A] = {
|
|
94
|
+
val compare: (A, A) => Ordering at {} = box { (left, right) => genericCompare(left, right) }
|
|
95
|
+
val tree: internal::Tree[A, Unit] = internal::fromList(list.map { k => (k, ()) }, compare)
|
|
96
|
+
Set(tree, compare)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// Traverse all elements in order, running the function `action` on each element.
|
|
100
|
+
///
|
|
101
|
+
/// Law: `s.foreach { action } === s.toList.foreach { action }`
|
|
102
|
+
///
|
|
103
|
+
/// O(N)
|
|
104
|
+
def foreach[A](s: Set[A]) { action: A => Unit }: Unit =
|
|
105
|
+
internal::foreach(s.tree) { (k, _v) => action(k) }
|
|
106
|
+
|
|
107
|
+
/// Create a list from a given set.
|
|
108
|
+
///
|
|
109
|
+
/// O(N)
|
|
110
|
+
def toList[A](s: Set[A]): List[A] = {
|
|
111
|
+
var acc = Nil()
|
|
112
|
+
s.foreach { a =>
|
|
113
|
+
acc = Cons(a, acc)
|
|
114
|
+
}
|
|
115
|
+
acc.reverse
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/// Check if a predicate holds for all elements in a given set.
|
|
119
|
+
///
|
|
120
|
+
/// O(N)
|
|
121
|
+
def all[A](s: Set[A]) { predicate : A => Bool }: Bool = {
|
|
122
|
+
var result = true
|
|
123
|
+
s.foreach { a =>
|
|
124
|
+
if (not(predicate(a))) { result = false }
|
|
125
|
+
}
|
|
126
|
+
result
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/// Check if a predicate holds for at least one element in a given set.
|
|
130
|
+
///
|
|
131
|
+
/// O(N)
|
|
132
|
+
def any[A](s: Set[A]) { predicate: A => Bool }: Bool = {
|
|
133
|
+
var result = false
|
|
134
|
+
s.foreach { a =>
|
|
135
|
+
if (predicate(a)) { result = true }
|
|
136
|
+
}
|
|
137
|
+
result
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/// Check if a set contains a given element.
|
|
141
|
+
///
|
|
142
|
+
/// O(log N)
|
|
143
|
+
def contains[A](s: Set[A], a: A): Bool =
|
|
144
|
+
internal::get(s.tree, s.compare, a) match {
|
|
145
|
+
case None() => false
|
|
146
|
+
case Some(v) => true
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
/// Check if set `s1` is a subset of set `s2`.
|
|
151
|
+
///
|
|
152
|
+
/// O(N log N)
|
|
153
|
+
def subset[A](s1: Set[A], s2: Set[A]): Bool = {
|
|
154
|
+
s1.all { a =>
|
|
155
|
+
s2.contains(a)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/// Check if set `s1` is a superset of set `s2`.
|
|
160
|
+
///
|
|
161
|
+
/// O(N log N)
|
|
162
|
+
def superset[A](s1: Set[A], s2: Set[A]): Bool = {
|
|
163
|
+
s2.subset(s1)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// Remove an element from a set.
|
|
167
|
+
/// If the element is not in the set, the original set is returned.
|
|
168
|
+
///
|
|
169
|
+
/// O(log N)
|
|
170
|
+
def delete[A](s: Set[A], a: A): Set[A] = {
|
|
171
|
+
val newTree = internal::delete(s.tree, s.compare, a)
|
|
172
|
+
Set(newTree, s.compare)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/// Remove many elements from a set.
|
|
176
|
+
///
|
|
177
|
+
/// O(M log N) where M is the size of the list.
|
|
178
|
+
def deleteMany[A](s: Set[A], list: List[A]): Set[A] = {
|
|
179
|
+
var tmp = s
|
|
180
|
+
list.foreach { a =>
|
|
181
|
+
tmp = tmp.delete(a)
|
|
182
|
+
}
|
|
183
|
+
tmp
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/// Construct a new set which contains all elements of `s1`
|
|
187
|
+
/// except those where the element is in `s2`.
|
|
188
|
+
/// Uses an explicit comparison function.
|
|
189
|
+
///
|
|
190
|
+
/// O(???)
|
|
191
|
+
def difference[A](s1: Set[A], s2: Set[A], compare: (A, A) => Ordering at {}): Set[A] = {
|
|
192
|
+
val newTree = internal::difference(s1.tree, s2.tree, compare)
|
|
193
|
+
Set(newTree, compare)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/// Construct a new set which contains all elements of `s1`
|
|
197
|
+
/// except those where the element is in `s2`.
|
|
198
|
+
/// Uses a comparison function from `s1`.
|
|
199
|
+
///
|
|
200
|
+
/// O(???)
|
|
201
|
+
def difference[A](s1: Set[A], s2: Set[A]): Set[A] =
|
|
202
|
+
s1.difference(s2, s1.compare)
|
|
203
|
+
|
|
204
|
+
/// Construct a new set which contains both elements of `s1` and `s2`.
|
|
205
|
+
/// Uses an explicit comparison function.
|
|
206
|
+
///
|
|
207
|
+
/// O(???)
|
|
208
|
+
def union[A](s1: Set[A], s2: Set[A], compare: (A, A) => Ordering at {}): Set[A] = {
|
|
209
|
+
val newTree = internal::union(s1.tree, s2.tree, compare) { (_k, _v1, _v2) => () }
|
|
210
|
+
Set(newTree, compare)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/// Construct a new set which contains both elements of `s1` and `s2`.
|
|
214
|
+
/// Uses a comparison function from `s1`.
|
|
215
|
+
///
|
|
216
|
+
/// O(???)
|
|
217
|
+
def union[A](s1: Set[A], s2: Set[A]): Set[A] =
|
|
218
|
+
s1.union(s2, s1.compare)
|
|
219
|
+
|
|
220
|
+
/// Construct a new set which contains only elements which are in both of `s1` and `s2`.
|
|
221
|
+
/// Uses an explicit comparison function.
|
|
222
|
+
///
|
|
223
|
+
/// O(???)
|
|
224
|
+
def intersection[A](s1: Set[A], s2: Set[A], compare: (A, A) => Ordering at {}): Set[A] = {
|
|
225
|
+
val newTree = internal::intersection(s1.tree, s2.tree, compare) { (_k, _v1, _v2) => () }
|
|
226
|
+
Set(newTree, compare)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/// Construct a new set which contains only elements which are in both of `s1` and `s2`.
|
|
230
|
+
/// Uses a comparison function from `s1`.
|
|
231
|
+
///
|
|
232
|
+
/// O(???)
|
|
233
|
+
def intersection[A](s1: Set[A], s2: Set[A]): Set[A] =
|
|
234
|
+
s1.intersection(s2, s1.compare)
|
|
@@ -2,6 +2,9 @@ module stream
|
|
|
2
2
|
|
|
3
3
|
import array
|
|
4
4
|
import bytearray
|
|
5
|
+
import map
|
|
6
|
+
import set
|
|
7
|
+
|
|
5
8
|
import io/filesystem
|
|
6
9
|
import io/error
|
|
7
10
|
|
|
@@ -63,6 +66,26 @@ def each(bytes: ByteArray): Unit / emit[Byte] = {
|
|
|
63
66
|
go(0)
|
|
64
67
|
}
|
|
65
68
|
|
|
69
|
+
/// Turns a `map` into a producer of a push stream
|
|
70
|
+
/// of `(key, value)` pairs by emitting each contained *in order*.
|
|
71
|
+
def each[K, V](map: Map[K, V]): Unit / emit[(K, V)] =
|
|
72
|
+
map.foreach { (k, v) => do emit((k, v)) }
|
|
73
|
+
|
|
74
|
+
/// Turns a `map` into a producer of a push stream
|
|
75
|
+
/// of its keys by emitting each contained *in order*.
|
|
76
|
+
def eachKey[K, V](map: Map[K, V]): Unit / emit[K] =
|
|
77
|
+
map.foreach { (k, _v) => do emit(k) }
|
|
78
|
+
|
|
79
|
+
/// Turns a `map` into a producer of a push stream
|
|
80
|
+
/// of its values by emitting each contained.
|
|
81
|
+
def eachValue[K, V](map: Map[K, V]): Unit / emit[V] =
|
|
82
|
+
map.foreach { (_k, v) => do emit(v) }
|
|
83
|
+
|
|
84
|
+
/// Turns a `set` into a producer of a push stream
|
|
85
|
+
/// by emitting each contained *in order*.
|
|
86
|
+
def each[A](set: Set[A]): Unit / emit[A] =
|
|
87
|
+
set.foreach { x => do emit(x) }
|
|
88
|
+
|
|
66
89
|
// not option
|
|
67
90
|
// not dequeue
|
|
68
91
|
// not queue
|
|
@@ -168,6 +191,28 @@ def feed[T, R](list: List[T]) { reader: () => R / read[T] }: R = {
|
|
|
168
191
|
}
|
|
169
192
|
}
|
|
170
193
|
|
|
194
|
+
def collectMap[K, V, R](compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Map[K, V]) =
|
|
195
|
+
try {
|
|
196
|
+
(stream(), map::empty(compare))
|
|
197
|
+
} with emit[(K, V)] { case (k, v) =>
|
|
198
|
+
val (r, map) = resume(());
|
|
199
|
+
(r, map.put(k, v))
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
def collectMap[K, V](compare: (K, K) => Ordering at {}) { stream: () => Any / emit[(K, V)] }: Map[K, V] =
|
|
203
|
+
collectMap[K, V, Any](compare){stream}.second
|
|
204
|
+
|
|
205
|
+
def collectSet[A, R](compare: (A, A) => Ordering at {}) { stream: () => R / emit[A] }: (R, Set[A]) =
|
|
206
|
+
try {
|
|
207
|
+
(stream(), set::empty(compare))
|
|
208
|
+
} with emit[A] { (v) =>
|
|
209
|
+
val (r, set) = resume(());
|
|
210
|
+
(r, set.insert(v))
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
def collectSet[A](compare: (A, A) => Ordering at {}) { stream: () => Any / emit[A] }: Set[A] =
|
|
214
|
+
collectSet[A, Any](compare){stream}.second
|
|
215
|
+
|
|
171
216
|
def feed[T, R](array: Array[T]) { reader: () => R / read[T] }: R = {
|
|
172
217
|
var i = 0
|
|
173
218
|
try {
|
|
@@ -218,7 +263,7 @@ def zip[A, B] { stream1: () => Unit / emit[A] } { stream2: () => Unit / emit[B]
|
|
|
218
263
|
|
|
219
264
|
def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[IOError] = {
|
|
220
265
|
|
|
221
|
-
val file =
|
|
266
|
+
val file = openForWriting(path);
|
|
222
267
|
with on[IOError].finalize { close(file) }
|
|
223
268
|
|
|
224
269
|
val chunkSize = 1048576 // 1MB
|
|
@@ -246,7 +291,7 @@ def writeFile[R](path: String) { stream: () => R / emit[Byte] }: R / Exception[I
|
|
|
246
291
|
|
|
247
292
|
def readFile[R](path: String) { reader: () => R / read[Byte] }: R / Exception[IOError] = {
|
|
248
293
|
|
|
249
|
-
val file =
|
|
294
|
+
val file = openForReading(path);
|
|
250
295
|
with on[IOError].finalize { close(file) }
|
|
251
296
|
|
|
252
297
|
val chunkSize = 1048576 // 1MB
|
|
@@ -243,11 +243,13 @@ extern pure def toInt(ch: Char): Int =
|
|
|
243
243
|
js "${ch}"
|
|
244
244
|
chez "${ch}"
|
|
245
245
|
llvm "ret %Int ${ch}"
|
|
246
|
+
vm "string::toInt(Char)"
|
|
246
247
|
|
|
247
248
|
extern pure def toChar(codepoint: Int): Char =
|
|
248
249
|
js "${codepoint}"
|
|
249
250
|
chez "${codepoint}"
|
|
250
251
|
llvm "ret %Int ${codepoint}"
|
|
252
|
+
vm "string::toChar(Int)"
|
|
251
253
|
|
|
252
254
|
|
|
253
255
|
extern pure def infixLt(x: Char, y: Char): Bool =
|
|
@@ -259,6 +261,7 @@ extern pure def infixLt(x: Char, y: Char): Bool =
|
|
|
259
261
|
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
260
262
|
ret %Pos %adt_boolean
|
|
261
263
|
"""
|
|
264
|
+
vm "string::infixLt(Char, Char)"
|
|
262
265
|
|
|
263
266
|
extern pure def infixLte(x: Char, y: Char): Bool =
|
|
264
267
|
js "(${x} <= ${y})"
|
|
@@ -269,6 +272,7 @@ extern pure def infixLte(x: Char, y: Char): Bool =
|
|
|
269
272
|
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
270
273
|
ret %Pos %adt_boolean
|
|
271
274
|
"""
|
|
275
|
+
vm "string::infixLte(Char, Char)"
|
|
272
276
|
|
|
273
277
|
extern pure def infixGt(x: Char, y: Char): Bool =
|
|
274
278
|
js "(${x} > ${y})"
|
|
@@ -279,6 +283,7 @@ extern pure def infixGt(x: Char, y: Char): Bool =
|
|
|
279
283
|
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
280
284
|
ret %Pos %adt_boolean
|
|
281
285
|
"""
|
|
286
|
+
vm "string::infixGt(Char, Char)"
|
|
282
287
|
|
|
283
288
|
extern pure def infixGte(x: Char, y: Char): Bool =
|
|
284
289
|
js "(${x} >= ${y})"
|
|
@@ -289,6 +294,7 @@ extern pure def infixGte(x: Char, y: Char): Bool =
|
|
|
289
294
|
%adt_boolean = insertvalue %Pos zeroinitializer, i64 %fat_z, 0
|
|
290
295
|
ret %Pos %adt_boolean
|
|
291
296
|
"""
|
|
297
|
+
vm "string::infixGte(Char, Char)"
|
|
292
298
|
|
|
293
299
|
|
|
294
300
|
/**
|
|
@@ -327,3 +333,4 @@ extern pure def unsafeCharAt(str: String, n: Int): Char =
|
|
|
327
333
|
%x = call %Int @c_bytearray_character_at(%Pos ${str}, %Int ${n})
|
|
328
334
|
ret %Int %x
|
|
329
335
|
"""
|
|
336
|
+
vm "string::unsafeCharAt(String, Int)"
|