@shd101wyy/yo 0.1.26 → 0.1.27
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/.github/skills/yo-async-effects/SKILL.md +4 -4
- package/.github/skills/yo-async-effects/async-effects-recipes.md +34 -34
- package/.github/skills/yo-core-patterns/SKILL.md +1 -1
- package/.github/skills/yo-core-patterns/core-patterns-cheatsheet.md +26 -26
- package/.github/skills/yo-project-workflow/SKILL.md +6 -3
- package/.github/skills/yo-project-workflow/workflow-cheatsheet.md +34 -11
- package/.github/skills/yo-syntax/SKILL.md +7 -6
- package/.github/skills/yo-syntax/syntax-cheatsheet.md +73 -60
- package/.github/skills/yo-wasm-integration/wasm-integration-cheatsheet.md +3 -3
- package/README.md +10 -8
- package/out/cjs/index.cjs +456 -438
- package/out/cjs/yo-cli.cjs +576 -543
- package/out/cjs/yo-lsp.cjs +559 -532
- package/out/esm/index.mjs +281 -263
- package/out/types/src/formatter.d.ts +11 -0
- package/out/types/src/lsp/formatting.d.ts +2 -0
- package/out/types/src/tests/formatter.test.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/std/alg/hash.yo +13 -21
- package/std/allocator.yo +25 -40
- package/std/async.yo +3 -7
- package/std/build.yo +105 -151
- package/std/cli/arg_parser.yo +184 -169
- package/std/collections/array_list.yo +350 -314
- package/std/collections/btree_map.yo +142 -131
- package/std/collections/deque.yo +132 -128
- package/std/collections/hash_map.yo +542 -566
- package/std/collections/hash_set.yo +623 -687
- package/std/collections/linked_list.yo +275 -293
- package/std/collections/ordered_map.yo +113 -85
- package/std/collections/priority_queue.yo +73 -73
- package/std/crypto/md5.yo +191 -95
- package/std/crypto/random.yo +56 -64
- package/std/crypto/sha256.yo +151 -107
- package/std/encoding/base64.yo +87 -81
- package/std/encoding/hex.yo +43 -50
- package/std/encoding/html.yo +56 -81
- package/std/encoding/html_char_utils.yo +7 -13
- package/std/encoding/html_entities.yo +2248 -2253
- package/std/encoding/json.yo +316 -224
- package/std/encoding/punycode.yo +86 -116
- package/std/encoding/toml.yo +67 -66
- package/std/encoding/utf16.yo +37 -44
- package/std/env.yo +62 -91
- package/std/error.yo +7 -15
- package/std/fmt/display.yo +5 -9
- package/std/fmt/index.yo +8 -14
- package/std/fmt/to_string.yo +330 -315
- package/std/fmt/writer.yo +58 -87
- package/std/fs/dir.yo +83 -102
- package/std/fs/file.yo +147 -180
- package/std/fs/metadata.yo +45 -78
- package/std/fs/temp.yo +55 -65
- package/std/fs/types.yo +27 -40
- package/std/fs/walker.yo +53 -68
- package/std/gc.yo +5 -8
- package/std/glob.yo +30 -43
- package/std/http/client.yo +107 -120
- package/std/http/http.yo +106 -96
- package/std/http/index.yo +4 -6
- package/std/imm/list.yo +88 -93
- package/std/imm/map.yo +528 -464
- package/std/imm/set.yo +52 -57
- package/std/imm/sorted_map.yo +340 -286
- package/std/imm/sorted_set.yo +57 -63
- package/std/imm/string.yo +404 -345
- package/std/imm/vec.yo +173 -181
- package/std/io/reader.yo +3 -6
- package/std/io/writer.yo +4 -8
- package/std/libc/assert.yo +5 -9
- package/std/libc/ctype.yo +32 -22
- package/std/libc/dirent.yo +26 -25
- package/std/libc/errno.yo +164 -90
- package/std/libc/fcntl.yo +52 -45
- package/std/libc/float.yo +66 -44
- package/std/libc/limits.yo +42 -33
- package/std/libc/math.yo +53 -82
- package/std/libc/signal.yo +72 -47
- package/std/libc/stdatomic.yo +217 -188
- package/std/libc/stdint.yo +5 -29
- package/std/libc/stdio.yo +5 -29
- package/std/libc/stdlib.yo +32 -39
- package/std/libc/string.yo +5 -23
- package/std/libc/sys/stat.yo +58 -56
- package/std/libc/time.yo +5 -19
- package/std/libc/unistd.yo +5 -20
- package/std/libc/wctype.yo +6 -9
- package/std/libc/windows.yo +26 -30
- package/std/log.yo +41 -55
- package/std/net/addr.yo +102 -97
- package/std/net/dns.yo +27 -28
- package/std/net/errors.yo +50 -49
- package/std/net/tcp.yo +113 -124
- package/std/net/udp.yo +55 -66
- package/std/os/env.yo +35 -33
- package/std/os/signal.yo +15 -25
- package/std/path.yo +276 -311
- package/std/prelude.yo +6304 -4315
- package/std/process/command.yo +87 -103
- package/std/process/index.yo +12 -31
- package/std/regex/compiler.yo +196 -95
- package/std/regex/flags.yo +58 -39
- package/std/regex/index.yo +157 -173
- package/std/regex/match.yo +20 -31
- package/std/regex/node.yo +134 -152
- package/std/regex/parser.yo +283 -259
- package/std/regex/unicode.yo +172 -202
- package/std/regex/vm.yo +155 -171
- package/std/string/index.yo +5 -7
- package/std/string/rune.yo +45 -55
- package/std/string/string.yo +937 -964
- package/std/string/string_builder.yo +94 -104
- package/std/string/unicode.yo +46 -64
- package/std/sync/channel.yo +72 -73
- package/std/sync/cond.yo +31 -36
- package/std/sync/mutex.yo +30 -32
- package/std/sync/once.yo +13 -16
- package/std/sync/rwlock.yo +26 -31
- package/std/sync/waitgroup.yo +20 -25
- package/std/sys/advise.yo +16 -24
- package/std/sys/bufio/buf_reader.yo +77 -93
- package/std/sys/bufio/buf_writer.yo +52 -65
- package/std/sys/clock.yo +4 -9
- package/std/sys/constants.yo +77 -61
- package/std/sys/copy.yo +4 -10
- package/std/sys/dir.yo +26 -43
- package/std/sys/dns.yo +41 -61
- package/std/sys/errors.yo +95 -103
- package/std/sys/events.yo +45 -57
- package/std/sys/externs.yo +319 -267
- package/std/sys/fallocate.yo +7 -11
- package/std/sys/fcntl.yo +14 -22
- package/std/sys/file.yo +26 -40
- package/std/sys/future.yo +5 -8
- package/std/sys/iov.yo +12 -25
- package/std/sys/lock.yo +12 -13
- package/std/sys/mmap.yo +38 -43
- package/std/sys/path.yo +3 -8
- package/std/sys/perm.yo +7 -21
- package/std/sys/pipe.yo +5 -12
- package/std/sys/process.yo +23 -29
- package/std/sys/seek.yo +10 -12
- package/std/sys/signal.yo +7 -13
- package/std/sys/signals.yo +52 -35
- package/std/sys/socket.yo +63 -58
- package/std/sys/socketpair.yo +3 -6
- package/std/sys/sockinfo.yo +11 -20
- package/std/sys/statfs.yo +11 -34
- package/std/sys/statx.yo +25 -52
- package/std/sys/sysinfo.yo +15 -20
- package/std/sys/tcp.yo +62 -92
- package/std/sys/temp.yo +5 -9
- package/std/sys/time.yo +5 -15
- package/std/sys/timer.yo +6 -11
- package/std/sys/tty.yo +10 -18
- package/std/sys/udp.yo +22 -39
- package/std/sys/umask.yo +3 -6
- package/std/sys/unix.yo +33 -52
- package/std/testing/bench.yo +49 -52
- package/std/thread.yo +10 -15
- package/std/time/datetime.yo +105 -89
- package/std/time/duration.yo +43 -56
- package/std/time/instant.yo +13 -18
- package/std/time/sleep.yo +5 -9
- package/std/url/index.yo +184 -209
- package/std/worker.yo +6 -10
package/std/imm/sorted_map.yo
CHANGED
|
@@ -17,230 +17,266 @@
|
|
|
17
17
|
//! m = m.insert(i32(2), i32(20));
|
|
18
18
|
//! // keys are always sorted: 1, 2, 3
|
|
19
19
|
//! ```
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
{ Pair } :: import "./map.yo";
|
|
23
|
-
|
|
20
|
+
{ List } :: import("./list.yo");
|
|
21
|
+
{ Pair } :: import("./map.yo");
|
|
24
22
|
/// Color of a red-black tree node.
|
|
25
23
|
Color :: enum(Red, Black);
|
|
26
|
-
|
|
27
24
|
/// Internal LLRB tree node — an `atomic object` for thread-safe sharing.
|
|
28
|
-
RBNode :: (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
25
|
+
RBNode :: (
|
|
26
|
+
fn(
|
|
27
|
+
comptime(K) : Type,
|
|
28
|
+
comptime(V) : Type,
|
|
29
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
30
|
+
) -> comptime(Type)
|
|
31
|
+
)(
|
|
32
|
+
atomic(
|
|
33
|
+
object(
|
|
34
|
+
_key : K,
|
|
35
|
+
_value : V,
|
|
36
|
+
_color : Color,
|
|
37
|
+
_left : Option(Self),
|
|
38
|
+
_right : Option(Self)
|
|
39
|
+
)
|
|
39
40
|
)
|
|
40
41
|
);
|
|
41
|
-
|
|
42
42
|
// Manual Acyclic impl — RBNode is self-referential, so auto-derivation skips it.
|
|
43
43
|
// This is safe because RBNode is immutable: all tree operations create new nodes
|
|
44
44
|
// and never mutate existing ones, making it impossible to form cycles at runtime.
|
|
45
45
|
impl(forall(K : Type, V : Type), where(K <: (Eq(K), Ord(K), Send), V <: Send), RBNode(K, V), Acyclic());
|
|
46
|
-
|
|
47
46
|
/// Persistent immutable sorted map backed by a left-leaning red-black tree.
|
|
48
|
-
SortedMap :: (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
SortedMap :: (
|
|
48
|
+
fn(
|
|
49
|
+
comptime(K) : Type,
|
|
50
|
+
comptime(V) : Type,
|
|
51
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
52
|
+
) -> comptime(Type)
|
|
53
|
+
)(
|
|
53
54
|
struct(
|
|
54
55
|
_root : Option(RBNode(K, V)),
|
|
55
56
|
_len : usize
|
|
56
57
|
)
|
|
57
58
|
);
|
|
58
|
-
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
60
60
|
// Helper standalone functions
|
|
61
61
|
// ---------------------------------------------------------------------------
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
) -> bool
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
_is_red :: (
|
|
63
|
+
fn(
|
|
64
|
+
comptime(K) : Type,
|
|
65
|
+
comptime(V) : Type,
|
|
66
|
+
node : Option(RBNode(K, V)),
|
|
67
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
68
|
+
) -> bool
|
|
69
|
+
)(
|
|
70
|
+
match(
|
|
71
|
+
node,
|
|
72
|
+
.Some(n) => match(
|
|
73
|
+
n._color,
|
|
71
74
|
.Red => true,
|
|
72
75
|
.Black => false
|
|
73
76
|
),
|
|
74
77
|
.None => false
|
|
75
78
|
)
|
|
76
79
|
);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
) -> RBNode(K, V)
|
|
80
|
+
_new_node :: (
|
|
81
|
+
fn(
|
|
82
|
+
comptime(K) : Type,
|
|
83
|
+
comptime(V) : Type,
|
|
84
|
+
key : K,
|
|
85
|
+
value : V,
|
|
86
|
+
color : Color,
|
|
87
|
+
left : Option(RBNode(K, V)),
|
|
88
|
+
right : Option(RBNode(K, V)),
|
|
89
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
90
|
+
) -> RBNode(K, V)
|
|
91
|
+
)(
|
|
88
92
|
RBNode(K, V)(
|
|
89
|
-
_key: key,
|
|
90
|
-
_value: value,
|
|
91
|
-
_color: color,
|
|
92
|
-
_left: left,
|
|
93
|
-
_right: right
|
|
93
|
+
_key : key,
|
|
94
|
+
_value : value,
|
|
95
|
+
_color : color,
|
|
96
|
+
_left : left,
|
|
97
|
+
_right : right
|
|
94
98
|
)
|
|
95
99
|
);
|
|
96
|
-
|
|
97
100
|
/// Rotate left: h.right becomes the new root.
|
|
98
|
-
_rotate_left :: (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
_rotate_left :: (
|
|
102
|
+
fn(
|
|
103
|
+
comptime(K) : Type,
|
|
104
|
+
comptime(V) : Type,
|
|
105
|
+
h : RBNode(K, V),
|
|
106
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
107
|
+
) -> RBNode(K, V)
|
|
108
|
+
)({
|
|
104
109
|
// x = h.right (must be Some)
|
|
105
|
-
(x : RBNode(K, V)) = match(
|
|
110
|
+
(x : RBNode(K, V)) = match(
|
|
111
|
+
h._right,
|
|
106
112
|
.Some(n) => n,
|
|
107
|
-
.None => h
|
|
113
|
+
.None => h // unreachable
|
|
108
114
|
);
|
|
109
115
|
new_h := _new_node(K, V, h._key, h._value, x._color, h._left, x._left);
|
|
110
|
-
_new_node(K, V, x._key, x._value, h._color
|
|
116
|
+
_new_node(K, V, x._key, x._value, h._color,.Some(new_h), x._right)
|
|
111
117
|
});
|
|
112
|
-
|
|
113
118
|
/// Rotate right: h.left becomes the new root.
|
|
114
|
-
_rotate_right :: (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
_rotate_right :: (
|
|
120
|
+
fn(
|
|
121
|
+
comptime(K) : Type,
|
|
122
|
+
comptime(V) : Type,
|
|
123
|
+
h : RBNode(K, V),
|
|
124
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
125
|
+
) -> RBNode(K, V)
|
|
126
|
+
)({
|
|
127
|
+
(x : RBNode(K, V)) = match(
|
|
128
|
+
h._left,
|
|
121
129
|
.Some(n) => n,
|
|
122
|
-
.None => h
|
|
130
|
+
.None => h // unreachable
|
|
123
131
|
);
|
|
124
132
|
new_h := _new_node(K, V, h._key, h._value, x._color, x._right, h._right);
|
|
125
|
-
_new_node(K, V, x._key, x._value, h._color, x._left
|
|
133
|
+
_new_node(K, V, x._key, x._value, h._color, x._left,.Some(new_h))
|
|
126
134
|
});
|
|
127
|
-
|
|
128
135
|
/// Flip colors of a node and its children.
|
|
129
|
-
_flip_colors :: (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
_flip_colors :: (
|
|
137
|
+
fn(
|
|
138
|
+
comptime(K) : Type,
|
|
139
|
+
comptime(V) : Type,
|
|
140
|
+
h : RBNode(K, V),
|
|
141
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
142
|
+
) -> RBNode(K, V)
|
|
143
|
+
)({
|
|
144
|
+
new_color := match(
|
|
145
|
+
h._color,
|
|
136
146
|
.Red => Color.Black,
|
|
137
147
|
.Black => Color.Red
|
|
138
148
|
);
|
|
139
|
-
(new_left : Option(RBNode(K, V))) = match(
|
|
149
|
+
(new_left : Option(RBNode(K, V))) = match(
|
|
150
|
+
h._left,
|
|
140
151
|
.Some(l) => {
|
|
141
|
-
lc := match(
|
|
152
|
+
lc := match(
|
|
153
|
+
l._color,
|
|
142
154
|
.Red => Color.Black,
|
|
143
155
|
.Black => Color.Red
|
|
144
156
|
);
|
|
145
|
-
|
|
157
|
+
Option(RBNode(K, V)).Some(_new_node(K, V, l._key, l._value, lc, l._left, l._right))
|
|
146
158
|
},
|
|
147
|
-
.None =>
|
|
159
|
+
.None => Option(RBNode(K, V)).None
|
|
148
160
|
);
|
|
149
|
-
(new_right : Option(RBNode(K, V))) = match(
|
|
161
|
+
(new_right : Option(RBNode(K, V))) = match(
|
|
162
|
+
h._right,
|
|
150
163
|
.Some(r) => {
|
|
151
|
-
rc := match(
|
|
164
|
+
rc := match(
|
|
165
|
+
r._color,
|
|
152
166
|
.Red => Color.Black,
|
|
153
167
|
.Black => Color.Red
|
|
154
168
|
);
|
|
155
|
-
|
|
169
|
+
Option(RBNode(K, V)).Some(_new_node(K, V, r._key, r._value, rc, r._left, r._right))
|
|
156
170
|
},
|
|
157
|
-
.None =>
|
|
171
|
+
.None => Option(RBNode(K, V)).None
|
|
158
172
|
);
|
|
159
173
|
_new_node(K, V, h._key, h._value, new_color, new_left, new_right)
|
|
160
174
|
});
|
|
161
|
-
|
|
162
175
|
/// Fix-up after insertion: enforce LLRB invariants.
|
|
163
|
-
_fixup :: (
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
176
|
+
_fixup :: (
|
|
177
|
+
fn(
|
|
178
|
+
comptime(K) : Type,
|
|
179
|
+
comptime(V) : Type,
|
|
180
|
+
h : RBNode(K, V),
|
|
181
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
182
|
+
) -> RBNode(K, V)
|
|
183
|
+
)({
|
|
169
184
|
(node : RBNode(K, V)) = h;
|
|
170
185
|
// Right-leaning red link → rotate left
|
|
171
|
-
if(
|
|
186
|
+
if(_is_red(K, V, node._right) && !(_is_red(K, V, node._left)), {
|
|
172
187
|
node = _rotate_left(K, V, node);
|
|
173
188
|
});
|
|
174
189
|
// Two consecutive red left links → rotate right
|
|
175
190
|
left_red := _is_red(K, V, node._left);
|
|
176
|
-
left_left_red := match(
|
|
191
|
+
left_left_red := match(
|
|
192
|
+
node._left,
|
|
177
193
|
.Some(l) => _is_red(K, V, l._left),
|
|
178
194
|
.None => false
|
|
179
195
|
);
|
|
180
|
-
if(
|
|
196
|
+
if(left_red && left_left_red, {
|
|
181
197
|
node = _rotate_right(K, V, node);
|
|
182
198
|
});
|
|
183
199
|
// Both children red → flip colors
|
|
184
|
-
if(
|
|
200
|
+
if(_is_red(K, V, node._left) && _is_red(K, V, node._right), {
|
|
185
201
|
node = _flip_colors(K, V, node);
|
|
186
202
|
});
|
|
187
203
|
node
|
|
188
204
|
});
|
|
189
|
-
|
|
190
205
|
/// Insert into subtree rooted at node. Returns new subtree root.
|
|
191
|
-
_node_insert :: (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
206
|
+
_node_insert :: (
|
|
207
|
+
fn(
|
|
208
|
+
comptime(K) : Type,
|
|
209
|
+
comptime(V) : Type,
|
|
210
|
+
node : Option(RBNode(K, V)),
|
|
211
|
+
key : K,
|
|
212
|
+
value : V,
|
|
213
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
214
|
+
) -> RBNode(K, V)
|
|
215
|
+
)(
|
|
216
|
+
match(
|
|
217
|
+
node,
|
|
218
|
+
.None => _new_node(K, V, key, value,.Red,.None,.None),
|
|
201
219
|
.Some(h) => {
|
|
202
220
|
(n : RBNode(K, V)) = cond(
|
|
203
221
|
(key < h._key) =>
|
|
204
|
-
_new_node(
|
|
205
|
-
|
|
222
|
+
_new_node(
|
|
223
|
+
K,
|
|
224
|
+
V,
|
|
225
|
+
h._key,
|
|
226
|
+
h._value,
|
|
227
|
+
h._color,
|
|
228
|
+
.Some(recur(K, V, h._left, key, value)),
|
|
229
|
+
h._right
|
|
230
|
+
),
|
|
206
231
|
(key == h._key) =>
|
|
207
232
|
_new_node(K, V, h._key, value, h._color, h._left, h._right),
|
|
208
233
|
true =>
|
|
209
|
-
_new_node(
|
|
210
|
-
|
|
234
|
+
_new_node(
|
|
235
|
+
K,
|
|
236
|
+
V,
|
|
237
|
+
h._key,
|
|
238
|
+
h._value,
|
|
239
|
+
h._color,
|
|
240
|
+
h._left,
|
|
241
|
+
.Some(recur(K, V, h._right, key, value))
|
|
242
|
+
)
|
|
211
243
|
);
|
|
212
244
|
_fixup(K, V, n)
|
|
213
245
|
}
|
|
214
246
|
)
|
|
215
247
|
);
|
|
216
|
-
|
|
217
248
|
/// Get value associated with key from subtree.
|
|
218
|
-
_node_get :: (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
|
|
249
|
+
_node_get :: (
|
|
250
|
+
fn(
|
|
251
|
+
comptime(K) : Type,
|
|
252
|
+
comptime(V) : Type,
|
|
253
|
+
node : Option(RBNode(K, V)),
|
|
254
|
+
key : K,
|
|
255
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
256
|
+
) -> Option(V)
|
|
257
|
+
)(
|
|
258
|
+
match(
|
|
259
|
+
node,
|
|
260
|
+
.None =>.None,
|
|
227
261
|
.Some(h) => cond(
|
|
228
262
|
(key < h._key) => recur(K, V, h._left, key),
|
|
229
|
-
(key == h._key)
|
|
263
|
+
(key == h._key) =>.Some(h._value),
|
|
230
264
|
true => recur(K, V, h._right, key)
|
|
231
265
|
)
|
|
232
266
|
)
|
|
233
267
|
);
|
|
234
|
-
|
|
235
268
|
/// Check if key exists in subtree.
|
|
236
|
-
_node_contains :: (
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
)
|
|
243
|
-
|
|
269
|
+
_node_contains :: (
|
|
270
|
+
fn(
|
|
271
|
+
comptime(K) : Type,
|
|
272
|
+
comptime(V) : Type,
|
|
273
|
+
node : Option(RBNode(K, V)),
|
|
274
|
+
key : K,
|
|
275
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
276
|
+
) -> bool
|
|
277
|
+
)(
|
|
278
|
+
match(
|
|
279
|
+
node,
|
|
244
280
|
.None => false,
|
|
245
281
|
.Some(h) => cond(
|
|
246
282
|
(key < h._key) => recur(K, V, h._left, key),
|
|
@@ -249,27 +285,29 @@ _node_contains :: (fn(
|
|
|
249
285
|
)
|
|
250
286
|
)
|
|
251
287
|
);
|
|
252
|
-
|
|
253
288
|
// ---------------------------------------------------------------------------
|
|
254
289
|
// Remove helpers for LLRB delete
|
|
255
290
|
// ---------------------------------------------------------------------------
|
|
256
|
-
|
|
257
291
|
/// Move red left: used during delete-min
|
|
258
|
-
_move_red_left :: (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
292
|
+
_move_red_left :: (
|
|
293
|
+
fn(
|
|
294
|
+
comptime(K) : Type,
|
|
295
|
+
comptime(V) : Type,
|
|
296
|
+
h : RBNode(K, V),
|
|
297
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
298
|
+
) -> RBNode(K, V)
|
|
299
|
+
)({
|
|
264
300
|
(node : RBNode(K, V)) = _flip_colors(K, V, h);
|
|
265
|
-
right_left_red := match(
|
|
301
|
+
right_left_red := match(
|
|
302
|
+
node._right,
|
|
266
303
|
.Some(r) => _is_red(K, V, r._left),
|
|
267
304
|
.None => false
|
|
268
305
|
);
|
|
269
306
|
if(right_left_red, {
|
|
270
|
-
(new_right : Option(RBNode(K, V))) = match(
|
|
307
|
+
(new_right : Option(RBNode(K, V))) = match(
|
|
308
|
+
node._right,
|
|
271
309
|
.Some(r) => Option(RBNode(K, V)).Some(_rotate_right(K, V, r)),
|
|
272
|
-
.None =>
|
|
310
|
+
.None => Option(RBNode(K, V)).None
|
|
273
311
|
);
|
|
274
312
|
node = _new_node(K, V, node._key, node._value, node._color, node._left, new_right);
|
|
275
313
|
node = _rotate_left(K, V, node);
|
|
@@ -277,16 +315,18 @@ _move_red_left :: (fn(
|
|
|
277
315
|
});
|
|
278
316
|
node
|
|
279
317
|
});
|
|
280
|
-
|
|
281
318
|
/// Move red right: used during delete
|
|
282
|
-
_move_red_right :: (
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
319
|
+
_move_red_right :: (
|
|
320
|
+
fn(
|
|
321
|
+
comptime(K) : Type,
|
|
322
|
+
comptime(V) : Type,
|
|
323
|
+
h : RBNode(K, V),
|
|
324
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
325
|
+
) -> RBNode(K, V)
|
|
326
|
+
)({
|
|
288
327
|
(node : RBNode(K, V)) = _flip_colors(K, V, h);
|
|
289
|
-
left_left_red := match(
|
|
328
|
+
left_left_red := match(
|
|
329
|
+
node._left,
|
|
290
330
|
.Some(l) => _is_red(K, V, l._left),
|
|
291
331
|
.None => false
|
|
292
332
|
);
|
|
@@ -296,73 +336,85 @@ _move_red_right :: (fn(
|
|
|
296
336
|
});
|
|
297
337
|
node
|
|
298
338
|
});
|
|
299
|
-
|
|
300
339
|
/// Find the minimum node in a subtree.
|
|
301
|
-
_node_min :: (
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
340
|
+
_node_min :: (
|
|
341
|
+
fn(
|
|
342
|
+
comptime(K) : Type,
|
|
343
|
+
comptime(V) : Type,
|
|
344
|
+
h : RBNode(K, V),
|
|
345
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
346
|
+
) -> RBNode(K, V)
|
|
347
|
+
)(
|
|
348
|
+
match(
|
|
349
|
+
h._left,
|
|
308
350
|
.Some(l) => recur(K, V, l),
|
|
309
351
|
.None => h
|
|
310
352
|
)
|
|
311
353
|
);
|
|
312
|
-
|
|
313
354
|
/// Delete the minimum node from subtree.
|
|
314
|
-
_delete_min :: (
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
355
|
+
_delete_min :: (
|
|
356
|
+
fn(
|
|
357
|
+
comptime(K) : Type,
|
|
358
|
+
comptime(V) : Type,
|
|
359
|
+
h : RBNode(K, V),
|
|
360
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
361
|
+
) -> Option(RBNode(K, V))
|
|
362
|
+
)(
|
|
363
|
+
match(
|
|
364
|
+
h._left,
|
|
365
|
+
.None =>.None,
|
|
322
366
|
.Some(l) => {
|
|
323
367
|
(node : RBNode(K, V)) = h;
|
|
324
|
-
if(
|
|
368
|
+
if(!(_is_red(K, V,.Some(l))) && !(_is_red(K, V, l._left)), {
|
|
325
369
|
node = _move_red_left(K, V, node);
|
|
326
370
|
});
|
|
327
|
-
new_left := match(
|
|
371
|
+
new_left := match(
|
|
372
|
+
node._left,
|
|
328
373
|
.Some(nl) => recur(K, V, nl),
|
|
329
|
-
.None =>
|
|
374
|
+
.None => Option(RBNode(K, V)).None
|
|
330
375
|
);
|
|
331
|
-
.Some(
|
|
332
|
-
|
|
333
|
-
|
|
376
|
+
.Some(
|
|
377
|
+
_fixup(
|
|
378
|
+
K,
|
|
379
|
+
V,
|
|
380
|
+
_new_node(K, V, node._key, node._value, node._color, new_left, node._right)
|
|
381
|
+
)
|
|
382
|
+
)
|
|
334
383
|
}
|
|
335
384
|
)
|
|
336
385
|
);
|
|
337
|
-
|
|
338
386
|
/// Remove key from subtree. Returns new subtree (or None if empty).
|
|
339
|
-
_node_remove :: (
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
387
|
+
_node_remove :: (
|
|
388
|
+
fn(
|
|
389
|
+
comptime(K) : Type,
|
|
390
|
+
comptime(V) : Type,
|
|
391
|
+
h : RBNode(K, V),
|
|
392
|
+
key : K,
|
|
393
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
394
|
+
) -> Option(RBNode(K, V))
|
|
395
|
+
)({
|
|
346
396
|
(node : RBNode(K, V)) = h;
|
|
347
|
-
|
|
348
|
-
if((key < node._key), {
|
|
397
|
+
if(key < node._key, {
|
|
349
398
|
// Go left
|
|
350
|
-
has_left := match(
|
|
399
|
+
has_left := match(
|
|
400
|
+
node._left,
|
|
351
401
|
.Some(_) => true,
|
|
352
402
|
.None => false
|
|
353
403
|
);
|
|
354
404
|
if(has_left, {
|
|
355
405
|
left_red := _is_red(K, V, node._left);
|
|
356
|
-
left_left_red := match(
|
|
406
|
+
left_left_red := match(
|
|
407
|
+
node._left,
|
|
357
408
|
.Some(l) => _is_red(K, V, l._left),
|
|
358
409
|
.None => false
|
|
359
410
|
);
|
|
360
|
-
if(
|
|
411
|
+
if(!(left_red) && !(left_left_red), {
|
|
361
412
|
node = _move_red_left(K, V, node);
|
|
362
413
|
});
|
|
363
|
-
new_left := match(
|
|
414
|
+
new_left := match(
|
|
415
|
+
node._left,
|
|
364
416
|
.Some(nl) => recur(K, V, nl, key),
|
|
365
|
-
.None =>
|
|
417
|
+
.None => Option(RBNode(K, V)).None
|
|
366
418
|
);
|
|
367
419
|
node = _new_node(K, V, node._key, node._value, node._color, new_left, node._right);
|
|
368
420
|
});
|
|
@@ -372,67 +424,69 @@ _node_remove :: (fn(
|
|
|
372
424
|
if(_is_red(K, V, node._left), {
|
|
373
425
|
node = _rotate_right(K, V, node);
|
|
374
426
|
});
|
|
375
|
-
|
|
376
427
|
// If equal and no right child, delete this node
|
|
377
428
|
is_eq := (key == node._key);
|
|
378
|
-
has_right := match(
|
|
429
|
+
has_right := match(
|
|
430
|
+
node._right,
|
|
379
431
|
.Some(_) => true,
|
|
380
432
|
.None => false
|
|
381
433
|
);
|
|
382
|
-
if(
|
|
383
|
-
return
|
|
434
|
+
if(is_eq && !(has_right), {
|
|
435
|
+
return(.None);
|
|
384
436
|
});
|
|
385
|
-
|
|
386
437
|
// Ensure right child is not a 2-node
|
|
387
438
|
if(has_right, {
|
|
388
439
|
right_red := _is_red(K, V, node._right);
|
|
389
|
-
right_left_red := match(
|
|
440
|
+
right_left_red := match(
|
|
441
|
+
node._right,
|
|
390
442
|
.Some(r) => _is_red(K, V, r._left),
|
|
391
443
|
.None => false
|
|
392
444
|
);
|
|
393
|
-
if(
|
|
445
|
+
if(!(right_red) && !(right_left_red), {
|
|
394
446
|
node = _move_red_right(K, V, node);
|
|
395
447
|
});
|
|
396
448
|
});
|
|
397
|
-
|
|
398
449
|
is_eq2 := (key == node._key);
|
|
399
450
|
if(is_eq2, {
|
|
400
451
|
// Replace with successor (min of right subtree)
|
|
401
|
-
succ := match(
|
|
452
|
+
succ := match(
|
|
453
|
+
node._right,
|
|
402
454
|
.Some(r) => _node_min(K, V, r),
|
|
403
|
-
.None => node
|
|
455
|
+
.None => node // unreachable
|
|
404
456
|
);
|
|
405
|
-
new_right := match(
|
|
457
|
+
new_right := match(
|
|
458
|
+
node._right,
|
|
406
459
|
.Some(r) => _delete_min(K, V, r),
|
|
407
|
-
.None =>
|
|
460
|
+
.None => Option(RBNode(K, V)).None
|
|
408
461
|
);
|
|
409
462
|
node = _new_node(K, V, succ._key, succ._value, node._color, node._left, new_right);
|
|
410
463
|
}, {
|
|
411
464
|
// Go right
|
|
412
|
-
new_right := match(
|
|
465
|
+
new_right := match(
|
|
466
|
+
node._right,
|
|
413
467
|
.Some(r) => recur(K, V, r, key),
|
|
414
|
-
.None =>
|
|
468
|
+
.None => Option(RBNode(K, V)).None
|
|
415
469
|
);
|
|
416
470
|
node = _new_node(K, V, node._key, node._value, node._color, node._left, new_right);
|
|
417
471
|
});
|
|
418
|
-
|
|
419
472
|
.Some(_fixup(K, V, node))
|
|
420
473
|
})
|
|
421
474
|
});
|
|
422
|
-
|
|
423
475
|
// ---------------------------------------------------------------------------
|
|
424
476
|
// In-order traversal helpers
|
|
425
477
|
// ---------------------------------------------------------------------------
|
|
426
|
-
|
|
427
478
|
/// Collect keys in-order into a List.
|
|
428
|
-
_collect_keys :: (
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
479
|
+
_collect_keys :: (
|
|
480
|
+
fn(
|
|
481
|
+
comptime(K) : Type,
|
|
482
|
+
comptime(V) : Type,
|
|
483
|
+
node : Option(RBNode(K, V)),
|
|
484
|
+
acc : List(K),
|
|
485
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
486
|
+
) -> List(K)
|
|
487
|
+
)(
|
|
488
|
+
match(
|
|
489
|
+
node,
|
|
436
490
|
.None => acc,
|
|
437
491
|
.Some(h) => {
|
|
438
492
|
right_acc := recur(K, V, h._right, acc);
|
|
@@ -441,16 +495,18 @@ _collect_keys :: (fn(
|
|
|
441
495
|
}
|
|
442
496
|
)
|
|
443
497
|
);
|
|
444
|
-
|
|
445
498
|
/// Collect values in key-order into a List.
|
|
446
|
-
_collect_values :: (
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
)
|
|
453
|
-
|
|
499
|
+
_collect_values :: (
|
|
500
|
+
fn(
|
|
501
|
+
comptime(K) : Type,
|
|
502
|
+
comptime(V) : Type,
|
|
503
|
+
node : Option(RBNode(K, V)),
|
|
504
|
+
acc : List(V),
|
|
505
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send)
|
|
506
|
+
) -> List(V)
|
|
507
|
+
)(
|
|
508
|
+
match(
|
|
509
|
+
node,
|
|
454
510
|
.None => acc,
|
|
455
511
|
.Some(h) => {
|
|
456
512
|
right_acc := recur(K, V, h._right, acc);
|
|
@@ -459,85 +515,83 @@ _collect_values :: (fn(
|
|
|
459
515
|
}
|
|
460
516
|
)
|
|
461
517
|
);
|
|
462
|
-
|
|
463
518
|
// ---------------------------------------------------------------------------
|
|
464
519
|
// SortedMap impl
|
|
465
520
|
// ---------------------------------------------------------------------------
|
|
466
|
-
|
|
467
|
-
|
|
521
|
+
impl(
|
|
522
|
+
forall(K : Type, V : Type),
|
|
523
|
+
where(K <: (Eq(K), Ord(K), Send), V <: Send),
|
|
524
|
+
SortedMap(K, V),
|
|
468
525
|
/// Create an empty sorted map.
|
|
469
526
|
new : (fn() -> Self)(
|
|
470
|
-
Self(_root
|
|
527
|
+
Self(_root :.None, _len : usize(0))
|
|
471
528
|
),
|
|
472
|
-
|
|
473
529
|
/// Number of entries.
|
|
474
|
-
len : (fn(self: Self) -> usize)(self._len),
|
|
475
|
-
|
|
530
|
+
len : (fn(self : Self) -> usize)(self._len),
|
|
476
531
|
/// Check if the map is empty.
|
|
477
|
-
is_empty : (fn(self: Self) -> bool)(
|
|
478
|
-
|
|
532
|
+
is_empty : (fn(self : Self) -> bool)(self._len == usize(0)),
|
|
479
533
|
/// Look up a value by key.
|
|
480
|
-
get : (fn(self: Self, key: K) -> Option(V))(
|
|
534
|
+
get : (fn(self : Self, key : K) -> Option(V))(
|
|
481
535
|
_node_get(K, V, self._root, key)
|
|
482
536
|
),
|
|
483
|
-
|
|
484
537
|
/// Check if a key exists.
|
|
485
|
-
contains_key : (fn(self: Self, key: K) -> bool)(
|
|
538
|
+
contains_key : (fn(self : Self, key : K) -> bool)(
|
|
486
539
|
_node_contains(K, V, self._root, key)
|
|
487
540
|
),
|
|
488
|
-
|
|
489
541
|
/// Return a new map with the key-value pair inserted (or updated).
|
|
490
|
-
insert : (fn(self: Self, key: K, value: V) -> Self)({
|
|
542
|
+
insert : (fn(self : Self, key : K, value : V) -> Self)({
|
|
491
543
|
existed := _node_contains(K, V, self._root, key);
|
|
492
544
|
new_root := _node_insert(K, V, self._root, key, value);
|
|
493
545
|
// Root is always black
|
|
494
|
-
black_root := _new_node(K, V, new_root._key, new_root._value
|
|
546
|
+
black_root := _new_node(K, V, new_root._key, new_root._value,.Black, new_root._left, new_root._right);
|
|
495
547
|
new_len := cond(
|
|
496
548
|
existed => self._len,
|
|
497
549
|
true => (self._len + usize(1))
|
|
498
550
|
);
|
|
499
|
-
Self(_root
|
|
551
|
+
Self(_root :.Some(black_root), _len : new_len)
|
|
500
552
|
}),
|
|
501
|
-
|
|
502
553
|
/// Return a new map with the key removed.
|
|
503
|
-
remove : (fn(self: Self, key: K) -> Self)(
|
|
504
|
-
match(
|
|
554
|
+
remove : (fn(self : Self, key : K) -> Self)(
|
|
555
|
+
match(
|
|
556
|
+
self._root,
|
|
505
557
|
.None => self,
|
|
506
558
|
.Some(root) => {
|
|
507
|
-
existed := _node_contains(K, V
|
|
559
|
+
existed := _node_contains(K, V,.Some(root), key);
|
|
508
560
|
if(!(existed), {
|
|
509
|
-
return
|
|
561
|
+
return(self);
|
|
510
562
|
});
|
|
511
563
|
result := _node_remove(K, V, root, key);
|
|
512
|
-
(new_root : Option(RBNode(K, V))) = match(
|
|
513
|
-
|
|
514
|
-
.
|
|
564
|
+
(new_root : Option(RBNode(K, V))) = match(
|
|
565
|
+
result,
|
|
566
|
+
.Some(n) => Option(RBNode(K, V)).Some(_new_node(K, V, n._key, n._value,.Black, n._left, n._right)),
|
|
567
|
+
.None => Option(RBNode(K, V)).None
|
|
515
568
|
);
|
|
516
|
-
Self(_root: new_root, _len: (self._len - usize(1)))
|
|
569
|
+
Self(_root : new_root, _len : (self._len - usize(1)))
|
|
517
570
|
}
|
|
518
571
|
)
|
|
519
572
|
),
|
|
520
|
-
|
|
521
573
|
/// Get the minimum key in the map.
|
|
522
|
-
min_key : (fn(self: Self) -> Option(K))(
|
|
523
|
-
match(
|
|
524
|
-
.
|
|
574
|
+
min_key : (fn(self : Self) -> Option(K))(
|
|
575
|
+
match(
|
|
576
|
+
self._root,
|
|
577
|
+
.None =>.None,
|
|
525
578
|
.Some(root) => {
|
|
526
579
|
m := _node_min(K, V, root);
|
|
527
580
|
.Some(m._key)
|
|
528
581
|
}
|
|
529
582
|
)
|
|
530
583
|
),
|
|
531
|
-
|
|
532
584
|
/// Get the maximum key by going right.
|
|
533
|
-
max_key : (fn(self: Self) -> Option(K))(
|
|
534
|
-
match(
|
|
535
|
-
.
|
|
585
|
+
max_key : (fn(self : Self) -> Option(K))(
|
|
586
|
+
match(
|
|
587
|
+
self._root,
|
|
588
|
+
.None =>.None,
|
|
536
589
|
.Some(root) => {
|
|
537
590
|
(cur : RBNode(K, V)) = root;
|
|
538
591
|
(done : bool) = false;
|
|
539
|
-
while
|
|
540
|
-
match(
|
|
592
|
+
while(runtime(!(done)), {
|
|
593
|
+
match(
|
|
594
|
+
cur._right,
|
|
541
595
|
.Some(r) => {
|
|
542
596
|
cur = r;
|
|
543
597
|
},
|
|
@@ -545,51 +599,51 @@ impl(forall(K : Type, V : Type), where(K <: (Eq(K), Ord(K), Send), V <: Send), S
|
|
|
545
599
|
done = true;
|
|
546
600
|
}
|
|
547
601
|
);
|
|
548
|
-
};
|
|
602
|
+
});
|
|
549
603
|
.Some(cur._key)
|
|
550
604
|
}
|
|
551
605
|
)
|
|
552
606
|
),
|
|
553
|
-
|
|
554
607
|
/// Return in-order list of keys.
|
|
555
|
-
keys : (fn(self: Self) -> List(K))(
|
|
608
|
+
keys : (fn(self : Self) -> List(K))(
|
|
556
609
|
_collect_keys(K, V, self._root, List(K).new())
|
|
557
610
|
),
|
|
558
|
-
|
|
559
611
|
/// Return list of values in key order.
|
|
560
|
-
values : (fn(self: Self) -> List(V))(
|
|
612
|
+
values : (fn(self : Self) -> List(V))(
|
|
561
613
|
_collect_values(K, V, self._root, List(V).new())
|
|
562
614
|
),
|
|
563
|
-
|
|
564
615
|
/// Create a sorted map from a slice of key-value pairs.
|
|
565
|
-
from_entries : (fn(pairs: Slice(Pair(K, V))) -> Self)({
|
|
616
|
+
from_entries : (fn(pairs : Slice(Pair(K, V))) -> Self)({
|
|
566
617
|
(result : Self) = Self.new();
|
|
567
618
|
i := usize(0);
|
|
568
619
|
plen := pairs.len();
|
|
569
|
-
while
|
|
620
|
+
while(i < plen, i = (i + usize(1)), {
|
|
570
621
|
p := (pairs.ptr() &+ i).*;
|
|
571
622
|
result = result.insert(p.key, p.value);
|
|
572
|
-
};
|
|
623
|
+
});
|
|
573
624
|
result
|
|
574
625
|
})
|
|
575
626
|
);
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
(
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
)
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
627
|
+
impl(
|
|
628
|
+
forall(K : Type, V : Type),
|
|
629
|
+
where(K <: (Eq(K), Ord(K), Send), V <: (Eq(V), Send)),
|
|
630
|
+
SortedMap(K, V),
|
|
631
|
+
Eq(SortedMap(K, V))(
|
|
632
|
+
(==) : (fn(lhs : Self, rhs : Self) -> bool)({
|
|
633
|
+
if(lhs._len != rhs._len, {
|
|
634
|
+
return(false);
|
|
635
|
+
});
|
|
636
|
+
if((lhs._len == usize(0)) && (rhs._len == usize(0)), {
|
|
637
|
+
return(true);
|
|
638
|
+
});
|
|
639
|
+
lhs_keys := lhs.keys();
|
|
640
|
+
lhs_vals := lhs.values();
|
|
641
|
+
rhs_keys := rhs.keys();
|
|
642
|
+
rhs_vals := rhs.values();
|
|
643
|
+
(lhs_keys == rhs_keys) && (lhs_vals == rhs_vals)
|
|
644
|
+
})
|
|
645
|
+
)
|
|
646
|
+
);
|
|
647
|
+
export(SortedMap);
|
|
648
|
+
export(RBNode);
|
|
649
|
+
export(Color);
|