vec.bend
bend-kit-collections@0.1.2.0 · 136 lines · 0 definitions
1# Vec: a growable array. push is amortized O(1): a full buffer doubles.
2#
3# get, set and pop are one Array access. An index at or past the length
4# answers None (get, pop) or leaves the vector as it was (set).
5import Base
6
7type Vec<-T: Data> is Type:
8 VNil{}
9 Vec{len: U32, buf: Array<T>}
10
11def Vec.new(~T: Data) -> Vec<T>:
12 VNil{}
13
14def Vec.len(~T: Data, v: Vec<T>) -> Vec<T> & U32:
15 match v:
16 case VNil{}:
17 (VNil{}, 0)
18 case Vec{+n, buf}:
19 (Vec{n, buf}, n)
20
21def Vec.copy(
22 ~T: Data, fuel: Nat, +i: U32, dst: Array<T>, r: Array<T> & T
23) -> Array<T>:
24 match fuel:
25 case 0n:
26 dst
27 case 1n+p:
28 (src, x) = r
29 +j = U32.inc(i)
30 Vec.copy(~T, p, j, Array.set(T, dst, i, x), Array.get(T, src, j))
31
32def Vec.push.grow(
33 ~T: Data, full: Bool, +n: U32, +x: T, buf: Array<T>, +cap: U32
34) -> Vec<T>:
35 match full:
36 case False{}:
37 Vec{U32.inc(n), Array.set(T, buf, n, x)}
38 case True{}:
39 # Every slot of big starts as x, so slot n needs no write.
40 big = Array.new(T, 1n+U32.log2(cap), x)
41 Vec{U32.inc(n), Vec.copy(~T, U32.to_nat(n), 0, big, Array.get(T, buf, 0))}
42
43def Vec.push.at(~T: Data, +n: U32, +x: T, bc: Array<T> & U32) -> Vec<T>:
44 (buf, +cap) = bc
45 Vec.push.grow(~T, U32.is_eq(n, cap), n, x, buf, cap)
46
47def Vec.push(~T: Data, v: Vec<T>, +x: T) -> Vec<T>:
48 match v:
49 case VNil{}:
50 Vec{1, ALeaf{x}}
51 case Vec{+n, buf}:
52 Vec.push.at(~T, n, x, Array.size(T, buf))
53
54def Vec.get.fin(~T: Data, n: U32, r: Array<T> & T) -> Vec<T> & Maybe<&2, T>:
55 (buf, x) = r
56 (Vec{n, buf}, Some{x})
57
58def Vec.get.if(
59 ~T: Data, ok: Bool, +n: U32, buf: Array<T>, +i: U32
60) -> Vec<T> & Maybe<&2, T>:
61 match ok:
62 case True{}:
63 Vec.get.fin(~T, n, Array.get(T, buf, i))
64 case False{}:
65 (Vec{n, buf}, None{})
66
67def Vec.get(~T: Data, v: Vec<T>, +i: U32) -> Vec<T> & Maybe<&2, T>:
68 match v:
69 case VNil{}:
70 (VNil{}, None{})
71 case Vec{+n, buf}:
72 Vec.get.if(~T, U32.is_lt(i, n), n, buf, i)
73
74def Vec.set.if(
75 ~T: Data, ok: Bool, n: U32, buf: Array<T>, i: U32, x: T
76) -> Vec<T>:
77 match ok:
78 case True{}:
79 Vec{n, Array.set(T, buf, i, x)}
80 case False{}:
81 Vec{n, buf}
82
83def Vec.set(~T: Data, v: Vec<T>, +i: U32, x: T) -> Vec<T>:
84 match v:
85 case VNil{}:
86 VNil{}
87 case Vec{+n, buf}:
88 Vec.set.if(~T, U32.is_lt(i, n), n, buf, i, x)
89
90def Vec.pop.if(
91 ~T: Data, empty: Bool, +n: U32, buf: Array<T>
92) -> Vec<T> & Maybe<&2, T>:
93 match empty:
94 case True{}:
95 (Vec{n, buf}, None{})
96 case False{}:
97 +m = (n - 1 : U32)
98 Vec.get.fin(~T, m, Array.get(T, buf, m))
99
100# The last element, and the vector without it. The buffer keeps its size.
101def Vec.pop(~T: Data, v: Vec<T>) -> Vec<T> & Maybe<&2, T>:
102 match v:
103 case VNil{}:
104 (VNil{}, None{})
105 case Vec{+n, buf}:
106 Vec.pop.if(~T, U32.is_zero(n), n, buf)
107
108def Vec.to_list.go(
109 ~T: Data, fuel: Nat, +i: U32, acc: List<&2, T>, r: Array<T> & T
110) -> List<&2, T>:
111 match fuel:
112 case 0n:
113 acc
114 case 1n+p:
115 (buf, x) = r
116 +j = (i - 1 : U32)
117 Vec.to_list.go(~T, p, j, x <> acc, Array.get(T, buf, j))
118
119# The elements, first to last.
120def Vec.to_list(~T: Data, v: Vec<T>) -> List<&2, T>:
121 match v:
122 case VNil{}:
123 Nil{}
124 case Vec{+n, buf}:
125 +last = (n - 1 : U32)
126 Vec.to_list.go(~T, U32.to_nat(n), last, Nil{}, Array.get(T, buf, last))
127
128def Vec.from_list.go(~T: Data, xs: List<&2, T>, v: Vec<T>) -> Vec<T>:
129 match xs:
130 case Nil{}:
131 v
132 case h <> t:
133 Vec.from_list.go(~T, t, Vec.push(~T, v, h))
134
135def Vec.from_list(~T: Data, xs: List<&2, T>) -> Vec<T>:
136 Vec.from_list.go(~T, xs, VNil{})