@effekt-lang/effekt 0.78.0 → 0.79.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 +1 -1
- package/libraries/common/bytearray.effekt +1 -1
- package/libraries/common/dictionary.effekt +243 -53
- package/libraries/common/effekt.effekt +1 -1
- package/libraries/common/io/filesystem.effekt +7 -7
- package/libraries/common/io/network.effekt +6 -6
- package/libraries/common/io/signal.effekt +10 -10
- package/libraries/common/io/time.effekt +1 -1
- package/libraries/common/io.effekt +4 -4
- package/libraries/common/map.effekt +194 -100
- package/libraries/common/process.effekt +3 -2
- package/libraries/common/random.effekt +14 -1
- package/libraries/common/set.effekt +9 -19
- package/libraries/llvm/bytearray.c +1 -1
- package/libraries/llvm/rts.ll +14 -14
- package/licenses/mit license - mit-license.html +14 -14
- package/licenses/the bsd license - bsd-license.html +14 -14
- package/licenses/the mit license - mit.html +14 -14
- package/package.json +1 -1
|
@@ -80,19 +80,13 @@ def get[K, V](m: Map[K, V], k: K): Option[V] = internal::get(m.tree, m.compare,
|
|
|
80
80
|
///
|
|
81
81
|
/// O(log N)
|
|
82
82
|
def getOrElse[K, V](m: Map[K, V], k: K) { default: => V }: V =
|
|
83
|
-
internal::
|
|
84
|
-
case None() => default()
|
|
85
|
-
case Some(v) => v
|
|
86
|
-
}
|
|
83
|
+
internal::getOrElse(m.tree, m.compare, k) {default}
|
|
87
84
|
|
|
88
85
|
/// Check if map `m` contains a key `k`.
|
|
89
86
|
///
|
|
90
87
|
/// O(log N)
|
|
91
88
|
def contains[K, V](m: Map[K, V], k: K): Bool =
|
|
92
|
-
internal::
|
|
93
|
-
case None() => false
|
|
94
|
-
case Some(_) => true
|
|
95
|
-
}
|
|
89
|
+
internal::contains(m.tree, m.compare, k)
|
|
96
90
|
|
|
97
91
|
/// Get minimum in the map `m`.
|
|
98
92
|
///
|
|
@@ -354,15 +348,10 @@ def collect[K, V](?compare: (K, K) => Ordering at {}) { stream: () => Unit / emi
|
|
|
354
348
|
namespace returning {
|
|
355
349
|
/// Collects `(key, value)` pairs from a push stream producer `stream` into a new `map`,
|
|
356
350
|
/// 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
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
} with emit[(K, V)] { case (k, v) =>
|
|
362
|
-
map = map.put(k, v)
|
|
363
|
-
resume(())
|
|
364
|
-
}
|
|
365
|
-
(r, map)
|
|
351
|
+
def collect[K, V, R](?compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Map[K, V]) = {
|
|
352
|
+
val (r, tree) = internal::collect[K, V, R](compare) {stream}
|
|
353
|
+
(r, Map(tree, compare))
|
|
354
|
+
}
|
|
366
355
|
}
|
|
367
356
|
|
|
368
357
|
// Internal tree representation
|
|
@@ -417,6 +406,33 @@ namespace internal {
|
|
|
417
406
|
case Bin(size, _, _, _, _) => size
|
|
418
407
|
}
|
|
419
408
|
|
|
409
|
+
/// Look up `k` in the tree `m`, handing the value it is bound to to `found`,
|
|
410
|
+
/// or running `missing` if there is none.
|
|
411
|
+
///
|
|
412
|
+
/// O(log N)
|
|
413
|
+
def getWith[K, V, R](m: Tree[K, V], compare: (K, K) => Ordering at {}, k: K) { found: V => R } { missing: => R }: R =
|
|
414
|
+
m match {
|
|
415
|
+
case Tip() => missing()
|
|
416
|
+
case Bin(_, k2, v, l, r) =>
|
|
417
|
+
compare(k, k2) match {
|
|
418
|
+
case Less() => getWith(l, compare, k) {found} {missing}
|
|
419
|
+
case Greater() => getWith(r, compare, k) {found} {missing}
|
|
420
|
+
case Equal() => found(v)
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/// Whether the tree `m` binds the key `k`.
|
|
425
|
+
///
|
|
426
|
+
/// O(log N)
|
|
427
|
+
def contains[K, V](m: Tree[K, V], compare: (K, K) => Ordering at {}, k: K): Bool =
|
|
428
|
+
getWith(m, compare, k) { _v => true } { false }
|
|
429
|
+
|
|
430
|
+
/// The value bound to `k` in the tree `m`, or `default` if there is none.
|
|
431
|
+
///
|
|
432
|
+
/// O(log N)
|
|
433
|
+
def getOrElse[K, V](m: Tree[K, V], compare: (K, K) => Ordering at {}, k: K) { default: => V }: V =
|
|
434
|
+
getWith(m, compare, k) { v => v } {default}
|
|
435
|
+
|
|
420
436
|
/// Insert a new key `k` and value `v` into the tree `m`.
|
|
421
437
|
/// If the key `k` is already present in `m`, its associated value is replaced with `v`.
|
|
422
438
|
///
|
|
@@ -451,15 +467,7 @@ namespace internal {
|
|
|
451
467
|
///
|
|
452
468
|
/// O(log N)
|
|
453
469
|
def get[K, V](m: Tree[K, V], compare: (K, K) => Ordering at {}, k: K): Option[V] =
|
|
454
|
-
m
|
|
455
|
-
case Tip() => None()
|
|
456
|
-
case Bin(size, k2, v, l, r) =>
|
|
457
|
-
compare(k, k2) match {
|
|
458
|
-
case Less() => get(l, compare, k)
|
|
459
|
-
case Greater() => get(r, compare, k)
|
|
460
|
-
case Equal() => Some(v)
|
|
461
|
-
}
|
|
462
|
-
}
|
|
470
|
+
getWith(m, compare, k) { v => Some(v) } { None() }
|
|
463
471
|
|
|
464
472
|
/// Get minimum in the tree `m`.
|
|
465
473
|
///
|
|
@@ -600,98 +608,184 @@ namespace internal {
|
|
|
600
608
|
go(m)
|
|
601
609
|
}
|
|
602
610
|
|
|
611
|
+
/// A balanced subtree waiting to be joined, and the key separating it from the pairs collected after it.
|
|
612
|
+
///
|
|
613
|
+
/// A list of these is the *right* spine of the tree being built.
|
|
614
|
+
/// Their sizes strictly increase towards the back, so the list is the digits of a binary counter.
|
|
615
|
+
record Waiting[K, V](size: Int, key: K, value: V, tree: Tree[K, V])
|
|
616
|
+
|
|
617
|
+
/// Collect `(key, value)` pairs from a push stream producer `stream` into a tree,
|
|
618
|
+
/// returning the result of the producer as well.
|
|
619
|
+
/// Consider using `map::fromList` if you know the full list.
|
|
620
|
+
///
|
|
621
|
+
/// O(N) if the stream is sorted by key (in _either_ direction),
|
|
622
|
+
/// O(N log N) otherwise
|
|
623
|
+
def collect[K, V, R](compare: (K, K) => Ordering at {}) { stream: () => R / emit[(K, V)] }: (R, Tree[K, V]) = {
|
|
624
|
+
// Note that `fromList` is always better since it knows the whole list of pairs in advance,
|
|
625
|
+
// whereas we have to be streaming here. Otherwise the functions are very similar...
|
|
626
|
+
|
|
627
|
+
// The lowest digit of the binary counter is a lone pair, kept as the leaf it will one day become. :)
|
|
628
|
+
var lowest: Tree[K, V] = Tip()
|
|
629
|
+
var spine: List[Waiting[K, V]] = Nil()
|
|
630
|
+
var tree = Tip()
|
|
631
|
+
// which way the current run is going; is `Equal` once a monotone run is over
|
|
632
|
+
var direction: Ordering = Less()
|
|
633
|
+
|
|
634
|
+
// How the currently collected pair compares with the one collected last.
|
|
635
|
+
def compareLast(k: K): Ordering =
|
|
636
|
+
lowest match {
|
|
637
|
+
case Bin(_, previous, _, _, _) => compare(previous, k)
|
|
638
|
+
case Tip() => spine match {
|
|
639
|
+
case Nil() => Less()
|
|
640
|
+
case Cons(Waiting(_, previous, _, _), _) => compare(previous, k)
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// Give the pair collected last a new value, overwriting the existing one.
|
|
645
|
+
def rebind(v: V): Unit =
|
|
646
|
+
lowest match {
|
|
647
|
+
case Bin(_, k, _, _, _) =>
|
|
648
|
+
lowest = singleton(k, v)
|
|
649
|
+
case Tip() => spine match {
|
|
650
|
+
case Nil() => ()
|
|
651
|
+
case Cons(Waiting(size, k, _, tree), more) =>
|
|
652
|
+
spine = Cons(Waiting(size, k, v, tree), more)
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// Increment the binary counter: carry while the next subtree has the same size.
|
|
657
|
+
def extend(k: K, v: V): Unit = {
|
|
658
|
+
def carry(size: Int, subtree: Tree[K, V], rest: List[Waiting[K, V]]): List[Waiting[K, V]] =
|
|
659
|
+
rest match {
|
|
660
|
+
case Nil() => [Waiting(size, k, v, subtree)]
|
|
661
|
+
case Cons(Waiting(s, k2, v2, t), more) =>
|
|
662
|
+
if (s == size) {
|
|
663
|
+
val merged = if (direction is Greater()) bin(k2, v2, subtree, t) else bin(k2, v2, t, subtree)
|
|
664
|
+
carry(2 * size + 1, merged, more)
|
|
665
|
+
} else {
|
|
666
|
+
Cons(Waiting(size, k, v, subtree), rest)
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
lowest match {
|
|
671
|
+
case Tip() => lowest = singleton(k, v)
|
|
672
|
+
case Bin(_, _, _, _, _) =>
|
|
673
|
+
val leaf = lowest
|
|
674
|
+
lowest = Tip()
|
|
675
|
+
spine = carry(1, leaf, spine)
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
def joinSpineWith(spine: List[Waiting[K, V]], whole: Tree[K, V]): Tree[K, V] =
|
|
680
|
+
spine match {
|
|
681
|
+
case Nil() => whole
|
|
682
|
+
case Cons(Waiting(_, k, v, subtree), more) =>
|
|
683
|
+
val joined = if (direction is Greater()) link(k, v, whole, subtree) else link(k, v, subtree, whole)
|
|
684
|
+
more.joinSpineWith(joined)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
val result = try {
|
|
688
|
+
stream()
|
|
689
|
+
} with emit[(K, V)] { case (k, v) =>
|
|
690
|
+
// as long as the keys all keep going the same way, we can build a tree in O(N) time
|
|
691
|
+
direction match {
|
|
692
|
+
// the run is over, so we have to insert each new pair without a shortcut
|
|
693
|
+
case Equal() => tree = tree.put(compare, k, v)
|
|
694
|
+
case _ =>
|
|
695
|
+
(compareLast(k), direction) match {
|
|
696
|
+
case (Equal(), _) => rebind(v)
|
|
697
|
+
case (Less(), Less()) => extend(k, v)
|
|
698
|
+
case (Greater(), Greater()) => extend(k, v)
|
|
699
|
+
case (ordering, _) =>
|
|
700
|
+
// the new key goes against the run:
|
|
701
|
+
if (spine is Nil()) {
|
|
702
|
+
// - if it's the first pair, we just set the direction
|
|
703
|
+
direction = ordering
|
|
704
|
+
extend(k, v)
|
|
705
|
+
} else {
|
|
706
|
+
// - if it's not the first pair, we have to join up the run and use the slow path
|
|
707
|
+
tree = spine.joinSpineWith(lowest).put(compare, k, v)
|
|
708
|
+
direction = Equal()
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
resume(())
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
(result, if (direction is Equal()) tree else spine.joinSpineWith(lowest))
|
|
717
|
+
}
|
|
718
|
+
|
|
603
719
|
/// Create a tree from a list of (key, value) pairs.
|
|
604
720
|
/// If the list contains more than one value for the same key,
|
|
605
721
|
/// only the last value is used in the tree.
|
|
606
722
|
///
|
|
607
|
-
/// O(N) if the list is sorted by key,
|
|
723
|
+
/// O(N) if the list is sorted by key (in _either_ direction),
|
|
608
724
|
/// O(N log N) otherwise
|
|
609
|
-
def fromList[K, V](pairs: List[(K, V)], compare: (K, K) => Ordering at {}): Tree[K, V] =
|
|
725
|
+
def fromList[K, V](pairs: List[(K, V)], compare: (K, K) => Ordering at {}): Tree[K, V] =
|
|
610
726
|
pairs match {
|
|
611
727
|
case Nil() => Tip()
|
|
612
728
|
case Cons((k, v), Nil()) => singleton(k, v)
|
|
613
|
-
case Cons(
|
|
614
|
-
//
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
729
|
+
case Cons(_, _) =>
|
|
730
|
+
// the first pair not yet taken, and whether the run repeated a key
|
|
731
|
+
var rest = pairs
|
|
732
|
+
var repeated = false
|
|
733
|
+
// which way the current run is going; is `Equal` once a monotone run is over
|
|
734
|
+
var direction: Ordering = Equal()
|
|
735
|
+
|
|
736
|
+
// How many distinct keys the non-decreasing run at the front of `ps` holds.
|
|
737
|
+
def runLength(ps: List[(K, V)], count: Int): Int =
|
|
738
|
+
ps match {
|
|
739
|
+
case Nil() => count
|
|
740
|
+
case Cons((k, _), tail) => tail match { // note: tail is effectivelly an @-pattern!
|
|
741
|
+
case Nil() => count + 1
|
|
742
|
+
case Cons((next, _), _) => (compare(k, next), direction) match {
|
|
743
|
+
case (Less() , Less() ) => runLength(tail, count + 1)
|
|
744
|
+
case (Greater(), Greater()) => runLength(tail, count + 1)
|
|
745
|
+
case (Equal(), _) => repeated = true; runLength(tail, count)
|
|
746
|
+
|
|
747
|
+
// the first comparison that is not `Equal` settles which way we go
|
|
748
|
+
case (ordering, Equal()) => direction = ordering; runLength(tail, count + 1)
|
|
749
|
+
case _ => count + 1
|
|
623
750
|
}
|
|
751
|
+
}
|
|
624
752
|
}
|
|
625
|
-
}
|
|
626
753
|
|
|
627
|
-
//
|
|
628
|
-
def
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
754
|
+
// Advance `rest` past any repeats of `k`, giving back the last binding of it.
|
|
755
|
+
def lastBinding(k: K, v: V): V =
|
|
756
|
+
if (rest is Cons((next, value), tail) and compare(k, next) is Equal()) {
|
|
757
|
+
rest = tail
|
|
758
|
+
lastBinding(k, value)
|
|
759
|
+
} else {
|
|
760
|
+
v
|
|
632
761
|
}
|
|
633
|
-
treeSoFar
|
|
634
|
-
}
|
|
635
762
|
|
|
636
|
-
//
|
|
637
|
-
//
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
(one, [], rest)
|
|
651
|
-
} else {
|
|
652
|
-
(one, rest, [])
|
|
653
|
-
}
|
|
654
|
-
} else {
|
|
655
|
-
val res = create(level.bitwiseShr(1), pairs)
|
|
656
|
-
res match {
|
|
657
|
-
case (_, Nil(), _) => res
|
|
658
|
-
case (l, Cons((k2, v2), Nil()), zs) => (l.putMax(k2, v2), [], zs)
|
|
659
|
-
case (l, Cons((k2, v2), rest2), _) =>
|
|
660
|
-
// @-pattern
|
|
661
|
-
val xs = Cons((k2, v2), rest2)
|
|
662
|
-
|
|
663
|
-
if (notOrdered(k2, rest2)) { (l, [], xs) }
|
|
664
|
-
else {
|
|
665
|
-
val (r, zs, ws) = create(level.bitwiseShr(1), rest2);
|
|
666
|
-
(link(k2, v2, l, r), zs, ws)
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
763
|
+
// Shape `count` distinct keys from `rest` into a balanced tree, leaving `rest` on the first pair not taken.
|
|
764
|
+
// The order is established already, so knowing the size lays the tree out from the root down, one node per key.
|
|
765
|
+
def fromSorted(count: Int): Tree[K, V] =
|
|
766
|
+
if (count <= 0) Tip() else {
|
|
767
|
+
val half = (count - 1) / 2
|
|
768
|
+
val front = half.fromSorted
|
|
769
|
+
rest match {
|
|
770
|
+
case Nil() => <{ "fromList: fewer pairs than counted" }>
|
|
771
|
+
case Cons((k, v), tail) =>
|
|
772
|
+
rest = tail
|
|
773
|
+
val value = if (repeated) lastBinding(k, v) else v
|
|
774
|
+
val back = (count - 1 - half).fromSorted
|
|
775
|
+
if (direction is Greater()) bin(k, value, back, front) else bin(k, value, front, back)
|
|
776
|
+
}
|
|
670
777
|
}
|
|
671
|
-
}
|
|
672
778
|
|
|
673
|
-
|
|
674
|
-
|
|
779
|
+
// Whatever is left, once the run has stopped, goes through `put`.
|
|
780
|
+
def insertMany(m: Tree[K, V], ps: List[(K, V)]): Tree[K, V] =
|
|
781
|
+
ps match {
|
|
675
782
|
case Nil() => m
|
|
676
|
-
case Cons((k, v),
|
|
677
|
-
case Cons((k, v), rest) =>
|
|
678
|
-
if (notOrdered(k, rest)) { insertMany(m, pairs) }
|
|
679
|
-
else {
|
|
680
|
-
val l = m; // m is the left subtree here
|
|
681
|
-
val cr = create(level, rest)
|
|
682
|
-
cr match {
|
|
683
|
-
case (r, xs, Nil()) => go(level.bitwiseShl(1), link(k, v, l, r), xs)
|
|
684
|
-
case (r, Nil(), ys) => insertMany(link(k, v, l, r), ys)
|
|
685
|
-
case _ => <{ "create: go: cannot happen, invariant broken!" }>
|
|
686
|
-
}
|
|
687
|
-
}
|
|
783
|
+
case Cons((k, v), tail) => m.put(compare, k, v).insertMany(tail)
|
|
688
784
|
}
|
|
689
|
-
}
|
|
690
785
|
|
|
691
|
-
|
|
692
|
-
|
|
786
|
+
val sorted = runLength(pairs, 0).fromSorted
|
|
787
|
+
sorted.insertMany(rest)
|
|
693
788
|
}
|
|
694
|
-
}
|
|
695
789
|
|
|
696
790
|
/// Remove a key `k` from a tree `m`.
|
|
697
791
|
/// If `k` is not in `m`, `m` is returned.
|
|
@@ -1053,4 +1147,4 @@ namespace internal {
|
|
|
1053
1147
|
|
|
1054
1148
|
"[" ++ res ++ "]"
|
|
1055
1149
|
}
|
|
1056
|
-
}
|
|
1150
|
+
}
|
|
@@ -4,7 +4,8 @@ import array
|
|
|
4
4
|
extern def exit(errorCode: Int) at io: Nothing =
|
|
5
5
|
js "(function() { process.exit(${errorCode}) })()"
|
|
6
6
|
llvm """
|
|
7
|
-
|
|
7
|
+
%exitCode = trunc i64 ${errorCode} to i32
|
|
8
|
+
call void @exit(i32 %exitCode)
|
|
8
9
|
ret %Pos zeroinitializer
|
|
9
10
|
"""
|
|
10
11
|
chez "(exit ${errorCode})"
|
|
@@ -107,6 +108,6 @@ extern def spawn(cmd: String, args: Array[String], options: SpawnOptions) at asy
|
|
|
107
108
|
return p;
|
|
108
109
|
})"""
|
|
109
110
|
llvm """
|
|
110
|
-
call void @c_spawn(%Pos ${cmd}, %Pos ${args}, %Pos ${options}, %Stack %stack)
|
|
111
|
+
notail call void @c_spawn(%Pos ${cmd}, %Pos ${args}, %Pos ${options}, %Stack %stack)
|
|
111
112
|
ret void
|
|
112
113
|
"""
|
|
@@ -114,11 +114,24 @@ def randomInt32s(): Unit / {emit[Int], random} =
|
|
|
114
114
|
|
|
115
115
|
/// `max` is _inclusive_!
|
|
116
116
|
def randomInt(min: Int, max: Int): Int / random = {
|
|
117
|
+
// How many bytes it takes to represent `range` distinct values.
|
|
118
|
+
// Each bound is a power of two, so it's exact even as a JS 'number'.
|
|
119
|
+
def bytesFor(range: Int): Int =
|
|
120
|
+
if (range <= 1) 0
|
|
121
|
+
else if (range <= 256) 1
|
|
122
|
+
else if (range <= 65536) 2
|
|
123
|
+
else if (range <= 16777216) 3
|
|
124
|
+
else if (range <= 4294967296) 4
|
|
125
|
+
else if (range <= 1099511627776) 5
|
|
126
|
+
else if (range <= 281474976710656) 6
|
|
127
|
+
else if (range <= 72057594037927936) 7
|
|
128
|
+
else 8
|
|
129
|
+
|
|
117
130
|
if (min > max) {
|
|
118
131
|
randomInt(max, min)
|
|
119
132
|
} else {
|
|
120
133
|
val range = max - min + 1
|
|
121
|
-
val bytesNeeded = (
|
|
134
|
+
val bytesNeeded = bytesFor(range)
|
|
122
135
|
|
|
123
136
|
var result = 0
|
|
124
137
|
repeat(bytesNeeded) {
|
|
@@ -79,22 +79,19 @@ def toMap[K, V](keys: Set[K]) { valueOf: K => V }: Map[K, V] = {
|
|
|
79
79
|
|
|
80
80
|
/// Create a set from a given list and a pure, first-class comparison function.
|
|
81
81
|
///
|
|
82
|
-
/// O(N log N)
|
|
83
82
|
/// O(N) if the list is sorted
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
83
|
+
/// O(N log N)
|
|
84
|
+
def fromList[A](list: List[A], ?compare: (A, A) => Ordering at {}): Set[A] =
|
|
85
|
+
set::collect(compare) { list.each }
|
|
88
86
|
|
|
89
87
|
/// Create a set from a given list with a generic comparison function.
|
|
90
88
|
/// Works only on the JavaScript backends!
|
|
91
89
|
///
|
|
92
|
-
/// O(N log N)
|
|
93
90
|
/// O(N) if the list is sorted
|
|
91
|
+
/// O(N log N)
|
|
94
92
|
def fromListGeneric[A](list: List[A]): Set[A] = {
|
|
95
93
|
val compare: (A, A) => Ordering at {} = box { (left, right) => genericCompare(left, right) }
|
|
96
|
-
|
|
97
|
-
Set(tree, compare)
|
|
94
|
+
set::collect(compare) { list.each }
|
|
98
95
|
}
|
|
99
96
|
|
|
100
97
|
/// Traverse all elements in order, running the function `action` on each element.
|
|
@@ -150,10 +147,7 @@ def any[A](s: Set[A]) { predicate: A => Bool }: Bool = {
|
|
|
150
147
|
///
|
|
151
148
|
/// O(log N)
|
|
152
149
|
def contains[A](s: Set[A], a: A): Bool =
|
|
153
|
-
internal::
|
|
154
|
-
case None() => false
|
|
155
|
-
case Some(v) => true
|
|
156
|
-
}
|
|
150
|
+
internal::contains(s.tree, s.compare, a)
|
|
157
151
|
|
|
158
152
|
|
|
159
153
|
/// Check if set `s1` is a subset of set `s2`.
|
|
@@ -260,13 +254,9 @@ namespace returning {
|
|
|
260
254
|
/// Collects elements emitted by a push stream producer `stream` into a new set
|
|
261
255
|
/// using provided `compare` function, returning the result of the producer as well as the collected set.
|
|
262
256
|
def collect[A, R](?compare: (A, A) => Ordering at {}) { stream: () => R / emit[A] }: (R, Set[A]) = {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
stream()
|
|
266
|
-
} with emit[A] { (v) =>
|
|
267
|
-
set = set.insert(v)
|
|
268
|
-
resume(())
|
|
257
|
+
val (r, tree) = internal::collect[A, Unit, R](compare) {
|
|
258
|
+
stream::returning::for[A, R] {stream} { (v: A) => do emit((v, ())) }
|
|
269
259
|
}
|
|
270
|
-
(r,
|
|
260
|
+
(r, Set(tree, compare))
|
|
271
261
|
}
|
|
272
262
|
}
|
|
@@ -77,7 +77,7 @@ struct Pos c_bytearray_construct(const uint64_t n, const uint8_t *data) {
|
|
|
77
77
|
|
|
78
78
|
struct Pos c_bytearray_from_nullterminated_string(const char *data) {
|
|
79
79
|
uint64_t n = 0;
|
|
80
|
-
while (data[
|
|
80
|
+
while (data[n]) n++;
|
|
81
81
|
|
|
82
82
|
return c_bytearray_construct(n, (uint8_t*)data);
|
|
83
83
|
}
|
package/libraries/llvm/rts.ll
CHANGED
|
@@ -101,7 +101,7 @@ declare ptr @malloc(i64)
|
|
|
101
101
|
declare void @free(ptr)
|
|
102
102
|
declare ptr @realloc(ptr, i64)
|
|
103
103
|
declare noalias ptr @calloc(i64, i64)
|
|
104
|
-
declare
|
|
104
|
+
declare ptr @memcpy(ptr, ptr, i64)
|
|
105
105
|
declare i64 @llvm.ctlz.i64 (i64 , i1)
|
|
106
106
|
declare i64 @llvm.fshr.i64(i64, i64, i64)
|
|
107
107
|
declare double @llvm.sqrt.f64(double)
|
|
@@ -117,8 +117,7 @@ declare double @log1p(double)
|
|
|
117
117
|
; Intrinsic versions of the following two only added in LLVM 19
|
|
118
118
|
declare double @atan(double)
|
|
119
119
|
declare double @tan(double)
|
|
120
|
-
declare void @
|
|
121
|
-
declare void @exit(i64)
|
|
120
|
+
declare void @exit(i32)
|
|
122
121
|
declare void @llvm.assume(i1)
|
|
123
122
|
|
|
124
123
|
|
|
@@ -162,7 +161,7 @@ define private void @shareObject(%Object %object) alwaysinline {
|
|
|
162
161
|
|
|
163
162
|
next:
|
|
164
163
|
%objectReferenceCount = getelementptr %Header, ptr %object, i64 0, i32 0
|
|
165
|
-
%referenceCount = load %ReferenceCount, ptr %objectReferenceCount, !alias.scope !14, !noalias !24
|
|
164
|
+
%referenceCount = load %ReferenceCount, ptr %objectReferenceCount, !alias.scope !14, !noalias !24, !range !41
|
|
166
165
|
%referenceCount.1 = add %ReferenceCount %referenceCount, 1
|
|
167
166
|
store %ReferenceCount %referenceCount.1, ptr %objectReferenceCount, !alias.scope !14, !noalias !24
|
|
168
167
|
br label %done
|
|
@@ -189,7 +188,7 @@ define private void @eraseObject(%Object %object) alwaysinline {
|
|
|
189
188
|
|
|
190
189
|
next:
|
|
191
190
|
%objectReferenceCount = getelementptr %Header, ptr %object, i64 0, i32 0
|
|
192
|
-
%referenceCount = load %ReferenceCount, ptr %objectReferenceCount, !alias.scope !14, !noalias !24
|
|
191
|
+
%referenceCount = load %ReferenceCount, ptr %objectReferenceCount, !alias.scope !14, !noalias !24, !range !41
|
|
193
192
|
switch %ReferenceCount %referenceCount, label %decr [%ReferenceCount 0, label %free]
|
|
194
193
|
|
|
195
194
|
decr:
|
|
@@ -334,10 +333,8 @@ realloc:
|
|
|
334
333
|
|
|
335
334
|
define private %StackPointer @stackAllocate(%Stack %stack, i64 %n) alwaysinline {
|
|
336
335
|
%stackPointer_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 1
|
|
337
|
-
%limit_pointer = getelementptr %StackValue, %Stack %stack, i64 0, i32 2
|
|
338
336
|
|
|
339
337
|
%currentStackPointer = load %StackPointer, ptr %stackPointer_pointer, !alias.scope !11, !noalias !21
|
|
340
|
-
%limit = load %Limit, ptr %limit_pointer, !alias.scope !11, !noalias !21
|
|
341
338
|
%nextStackPointer = getelementptr i8, %StackPointer %currentStackPointer, i64 %n
|
|
342
339
|
|
|
343
340
|
store %StackPointer %nextStackPointer, ptr %stackPointer_pointer, !alias.scope !11, !noalias !21
|
|
@@ -486,7 +483,7 @@ define private {%Resumption, %Stack} @shift(%Stack %stack, %Prompt %prompt) {
|
|
|
486
483
|
|
|
487
484
|
define private void @erasePrompt(%Prompt %prompt) alwaysinline {
|
|
488
485
|
%referenceCount_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 0
|
|
489
|
-
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23
|
|
486
|
+
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23, !range !41
|
|
490
487
|
switch %ReferenceCount %referenceCount, label %decrement [%ReferenceCount 0, label %free]
|
|
491
488
|
|
|
492
489
|
decrement:
|
|
@@ -501,7 +498,7 @@ free:
|
|
|
501
498
|
|
|
502
499
|
define private void @sharePrompt(%Prompt %prompt) alwaysinline {
|
|
503
500
|
%referenceCount_pointer = getelementptr %PromptValue, %Prompt %prompt, i64 0, i32 0
|
|
504
|
-
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23
|
|
501
|
+
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23, !range !41
|
|
505
502
|
%newReferenceCount = add %ReferenceCount %referenceCount, 1
|
|
506
503
|
store %ReferenceCount %newReferenceCount, ptr %referenceCount_pointer, !alias.scope !13, !noalias !23
|
|
507
504
|
ret void
|
|
@@ -544,7 +541,7 @@ define private %Stack @copyStack(%Stack %stack) alwaysinline {
|
|
|
544
541
|
%newStackPointer = getelementptr i8, %Stack %newStack, i64 %used
|
|
545
542
|
%newLimit = getelementptr i8, %Stack %newStack, i64 %size
|
|
546
543
|
|
|
547
|
-
call
|
|
544
|
+
%copied = call ptr @memcpy(ptr %newStack, ptr %stack, i64 %used)
|
|
548
545
|
|
|
549
546
|
%newStackPointer_pointer = getelementptr %StackValue, %Stack %newStack, i64 0, i32 1
|
|
550
547
|
%newLimit_pointer = getelementptr %StackValue, %Stack %newStack, i64 0, i32 2
|
|
@@ -569,7 +566,7 @@ define private %Resumption @uniqueStack(%Resumption %resumption) alwaysinline {
|
|
|
569
566
|
|
|
570
567
|
entry:
|
|
571
568
|
%referenceCount_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 0
|
|
572
|
-
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21
|
|
569
|
+
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21, !range !41
|
|
573
570
|
switch %ReferenceCount %referenceCount, label %copy [%ReferenceCount 0, label %done]
|
|
574
571
|
|
|
575
572
|
done:
|
|
@@ -613,7 +610,7 @@ stop:
|
|
|
613
610
|
|
|
614
611
|
define void @shareResumption(%Resumption %resumption) alwaysinline {
|
|
615
612
|
%referenceCount_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 0
|
|
616
|
-
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21
|
|
613
|
+
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21, !range !41
|
|
617
614
|
%referenceCount.1 = add %ReferenceCount %referenceCount, 1
|
|
618
615
|
store %ReferenceCount %referenceCount.1, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21
|
|
619
616
|
ret void
|
|
@@ -621,7 +618,7 @@ define void @shareResumption(%Resumption %resumption) alwaysinline {
|
|
|
621
618
|
|
|
622
619
|
define void @eraseResumption(%Resumption %resumption) alwaysinline {
|
|
623
620
|
%referenceCount_pointer = getelementptr %StackValue, %Resumption %resumption, i64 0, i32 0
|
|
624
|
-
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21
|
|
621
|
+
%referenceCount = load %ReferenceCount, ptr %referenceCount_pointer, !alias.scope !11, !noalias !21, !range !41
|
|
625
622
|
switch %ReferenceCount %referenceCount, label %decr [%ReferenceCount 0, label %free]
|
|
626
623
|
|
|
627
624
|
decr:
|
|
@@ -914,4 +911,7 @@ define ccc %CObject @coercePosObj(%Pos %input) {
|
|
|
914
911
|
!22 = !{!1, !3, !4, !5} ; not stackPointer
|
|
915
912
|
!23 = !{!1, !2, !4, !5} ; not prompt
|
|
916
913
|
!24 = !{!1, !2, !3, !5} ; not object
|
|
917
|
-
!25 = !{!1, !2, !3, !4 } ; not vtable
|
|
914
|
+
!25 = !{!1, !2, !3, !4 } ; not vtable
|
|
915
|
+
|
|
916
|
+
; Ranges
|
|
917
|
+
!41 = !{i64 0, i64 9223372036854775807} ; positive i64
|