mt-lang 0.2.0 → 0.2.1
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.
- checksums.yaml +4 -4
- data/docs/index.html +4 -3
- data/lib/milk_tea/base.rb +1 -1
- data/std/asset_pack.mt +267 -0
- data/std/async/libuv_runtime.mt +539 -0
- data/std/async/mailbox.mt +191 -0
- data/std/async/runtime.mt +87 -0
- data/std/async.mt +87 -0
- data/std/base64.mt +185 -0
- data/std/behavior_tree.mt +396 -0
- data/std/binary.mt +314 -0
- data/std/binary_heap.mt +157 -0
- data/std/bitset.mt +239 -0
- data/std/box2d.mt +535 -0
- data/std/bytes.mt +46 -0
- data/std/c/box2d.mt +1254 -0
- data/std/c/cgltf.mt +647 -0
- data/std/c/cjson.mt +106 -0
- data/std/c/crypto.mt +11 -0
- data/std/c/crypto_support.h +51 -0
- data/std/c/ctype.mt +19 -0
- data/std/c/ctype_bindgen.h +29 -0
- data/std/c/curl.mt +1223 -0
- data/std/c/enet.mt +473 -0
- data/std/c/errno.mt +41 -0
- data/std/c/errno_bindgen.h +53 -0
- data/std/c/flecs.mt +2945 -0
- data/std/c/fs.linux.mt +43 -0
- data/std/c/fs.windows.mt +43 -0
- data/std/c/fs_support.h +954 -0
- data/std/c/gl.mt +2065 -0
- data/std/c/gl_registry_helpers.h +10748 -0
- data/std/c/glfw.mt +499 -0
- data/std/c/libc.mt +167 -0
- data/std/c/libuv.mt +1491 -0
- data/std/c/math.mt +22 -0
- data/std/c/math_bindgen.h +31 -0
- data/std/c/miniaudio.mt +3420 -0
- data/std/c/pcre2.mt +735 -0
- data/std/c/process.mt +58 -0
- data/std/c/process_support.h +1147 -0
- data/std/c/raygui.mt +1602 -0
- data/std/c/raylib.mt +1245 -0
- data/std/c/raymath.mt +163 -0
- data/std/c/rlgl.mt +434 -0
- data/std/c/rpng.mt +60 -0
- data/std/c/rres.mt +187 -0
- data/std/c/sdl3.mt +4132 -0
- data/std/c/sqlite3.mt +951 -0
- data/std/c/stb_image.mt +52 -0
- data/std/c/stb_image_resize2.mt +128 -0
- data/std/c/stb_image_write.mt +19 -0
- data/std/c/stb_rect_pack.mt +38 -0
- data/std/c/stb_truetype.mt +175 -0
- data/std/c/stb_vorbis.mt +31 -0
- data/std/c/stdio.mt +90 -0
- data/std/c/steamworks.h +5769 -0
- data/std/c/steamworks.mt +4771 -0
- data/std/c/string.mt +16 -0
- data/std/c/string_bindgen.h +36 -0
- data/std/c/sync.mt +33 -0
- data/std/c/sync_support.h +219 -0
- data/std/c/terminal.mt +24 -0
- data/std/c/terminal_support.h +408 -0
- data/std/c/time.mt +26 -0
- data/std/c/tls.mt +24 -0
- data/std/c/tls_support.h +626 -0
- data/std/c/tracy.mt +53 -0
- data/std/c/zlib.mt +20 -0
- data/std/c/zlib_support.h +239 -0
- data/std/c/zstd.mt +231 -0
- data/std/cell.mt +60 -0
- data/std/cgltf.mt +115 -0
- data/std/cjson.mt +90 -0
- data/std/cli.mt +768 -0
- data/std/cookie.mt +198 -0
- data/std/counter.mt +160 -0
- data/std/crypto.mt +74 -0
- data/std/cstring.mt +13 -0
- data/std/ctype.mt +52 -0
- data/std/curl/runtime.mt +261 -0
- data/std/curl.mt +38 -0
- data/std/deque.mt +348 -0
- data/std/encoding.mt +93 -0
- data/std/enet.mt +133 -0
- data/std/env.mt +41 -0
- data/std/errno.mt +47 -0
- data/std/flecs.mt +978 -0
- data/std/fmt.mt +271 -0
- data/std/fs.linux.mt +696 -0
- data/std/fs.windows.mt +711 -0
- data/std/fsm.mt +267 -0
- data/std/gl.mt +2062 -0
- data/std/glfw.mt +471 -0
- data/std/goap.mt +342 -0
- data/std/graph.mt +521 -0
- data/std/gzip.mt +77 -0
- data/std/hash.mt +429 -0
- data/std/http/server.mt +810 -0
- data/std/http.mt +1227 -0
- data/std/intern.mt +53 -0
- data/std/jobs.mt +288 -0
- data/std/json.mt +627 -0
- data/std/libc.mt +34 -0
- data/std/libuv.mt +554 -0
- data/std/linear_algebra.mt +243 -0
- data/std/linked_map.mt +372 -0
- data/std/linked_map_view.mt +49 -0
- data/std/linked_set.mt +117 -0
- data/std/log.mt +69 -0
- data/std/map.mt +418 -0
- data/std/math.mt +24 -0
- data/std/mem/arena.mt +137 -0
- data/std/mem/endian.mt +51 -0
- data/std/mem/heap.mt +298 -0
- data/std/mem/pool.mt +164 -0
- data/std/mem/stack.mt +47 -0
- data/std/mem/tracking.mt +119 -0
- data/std/miniaudio.mt +1299 -0
- data/std/multiset.mt +191 -0
- data/std/net/channel.mt +727 -0
- data/std/net/clock.mt +237 -0
- data/std/net/discovery.mt +277 -0
- data/std/net/lobby.mt +813 -0
- data/std/net/manager.mt +539 -0
- data/std/net/mux.mt +839 -0
- data/std/net/nat.mt +122 -0
- data/std/net/packet.mt +219 -0
- data/std/net/punch.mt +162 -0
- data/std/net/rpc.mt +119 -0
- data/std/net/session.mt +1157 -0
- data/std/net/stun.mt +252 -0
- data/std/net/sync.mt +183 -0
- data/std/net/turn.mt +459 -0
- data/std/net.mt +2944 -0
- data/std/oauth2.mt +408 -0
- data/std/option.mt +51 -0
- data/std/ordered_map.mt +497 -0
- data/std/ordered_set.mt +348 -0
- data/std/path.mt +368 -0
- data/std/pcre2/runtime.mt +35 -0
- data/std/pcre2.mt +78 -0
- data/std/priority_queue.mt +55 -0
- data/std/process.mt +837 -0
- data/std/queue.mt +55 -0
- data/std/random.mt +146 -0
- data/std/raygui.mt +99 -0
- data/std/raylib/debug_console.mt +71 -0
- data/std/raylib/easing.mt +388 -0
- data/std/raylib/packed_assets.mt +255 -0
- data/std/raylib/runtime.mt +30 -0
- data/std/raylib/tracy_gpu.mt +37 -0
- data/std/raylib.mt +1510 -0
- data/std/raymath.mt +153 -0
- data/std/result.mt +89 -0
- data/std/rlgl.mt +268 -0
- data/std/rpng.mt +46 -0
- data/std/rres.mt +36 -0
- data/std/sdl3/runtime.mt +54 -0
- data/std/sdl3.mt +1731 -0
- data/std/serialize.mt +68 -0
- data/std/set.mt +124 -0
- data/std/spatial.mt +176 -0
- data/std/sqlite3.mt +151 -0
- data/std/stack.mt +55 -0
- data/std/stb_image.mt +47 -0
- data/std/stb_image_resize2.mt +41 -0
- data/std/stb_image_write.mt +17 -0
- data/std/stb_rect_pack.mt +15 -0
- data/std/stb_truetype.mt +77 -0
- data/std/stb_vorbis.mt +16 -0
- data/std/stdio.mt +88 -0
- data/std/steamworks.mt +1542 -0
- data/std/str.mt +293 -0
- data/std/string.mt +234 -0
- data/std/sync.mt +194 -0
- data/std/tar.mt +704 -0
- data/std/terminal.mt +1002 -0
- data/std/testing.mt +266 -0
- data/std/thread.mt +120 -0
- data/std/time.mt +105 -0
- data/std/tls.mt +616 -0
- data/std/toml.mt +1310 -0
- data/std/tracy.mt +42 -0
- data/std/uri.mt +118 -0
- data/std/url.mt +372 -0
- data/std/vec.mt +433 -0
- data/std/zstd.mt +94 -0
- metadata +187 -2
data/std/ordered_set.mt
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import std.mem.heap as heap
|
|
2
|
+
|
|
3
|
+
struct Node[T]:
|
|
4
|
+
value: T
|
|
5
|
+
left: ptr[Node[T]]?
|
|
6
|
+
right: ptr[Node[T]]?
|
|
7
|
+
parent: ptr[Node[T]]?
|
|
8
|
+
height: int
|
|
9
|
+
|
|
10
|
+
struct SearchResult[T]:
|
|
11
|
+
node: ptr[Node[T]]?
|
|
12
|
+
parent: ptr[Node[T]]?
|
|
13
|
+
compare: int
|
|
14
|
+
found: bool
|
|
15
|
+
|
|
16
|
+
public struct Iter[T]:
|
|
17
|
+
node: ptr[Node[T]]?
|
|
18
|
+
|
|
19
|
+
public struct OrderedSet[T]:
|
|
20
|
+
root: ptr[Node[T]]?
|
|
21
|
+
len: ptr_uint
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
extending OrderedSet[T]:
|
|
25
|
+
public static function create() -> OrderedSet[T]:
|
|
26
|
+
return OrderedSet[T](root = null, len = 0)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
static function height(node: ptr[Node[T]]?) -> int:
|
|
30
|
+
if node == null:
|
|
31
|
+
return 0
|
|
32
|
+
|
|
33
|
+
unsafe:
|
|
34
|
+
return read(ptr[Node[T]]<-node).height
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
static function update_height(node: ptr[Node[T]]) -> void:
|
|
38
|
+
let left_height = unsafe: OrderedSet[T].height(read(node).left)
|
|
39
|
+
let right_height = unsafe: OrderedSet[T].height(read(node).right)
|
|
40
|
+
var next_height = left_height
|
|
41
|
+
if right_height > next_height:
|
|
42
|
+
next_height = right_height
|
|
43
|
+
|
|
44
|
+
unsafe:
|
|
45
|
+
read(node).height = next_height + 1
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
static function balance_factor(node: ptr[Node[T]]?) -> int:
|
|
49
|
+
if node == null:
|
|
50
|
+
return 0
|
|
51
|
+
|
|
52
|
+
unsafe:
|
|
53
|
+
return OrderedSet[T].height(read(ptr[Node[T]]<-node).left) - OrderedSet[T].height(read(ptr[Node[T]]<-node).right)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
static function minimum(node: ptr[Node[T]]?) -> ptr[Node[T]]?:
|
|
57
|
+
var current = node
|
|
58
|
+
while current != null:
|
|
59
|
+
let left = unsafe: read(ptr[Node[T]]<-current).left else:
|
|
60
|
+
return current
|
|
61
|
+
|
|
62
|
+
current = left
|
|
63
|
+
|
|
64
|
+
return null
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
static function successor(node: ptr[Node[T]]?) -> ptr[Node[T]]?:
|
|
68
|
+
if node == null:
|
|
69
|
+
return null
|
|
70
|
+
|
|
71
|
+
let current = unsafe: ptr[Node[T]]<-node
|
|
72
|
+
let right = unsafe: read(current).right
|
|
73
|
+
if right != null:
|
|
74
|
+
return OrderedSet[T].minimum(right)
|
|
75
|
+
|
|
76
|
+
var child = node
|
|
77
|
+
var parent = unsafe: read(current).parent
|
|
78
|
+
while parent != null:
|
|
79
|
+
let parent_ptr = unsafe: ptr[Node[T]]<-parent
|
|
80
|
+
if unsafe: read(parent_ptr).left == child:
|
|
81
|
+
return parent
|
|
82
|
+
|
|
83
|
+
child = parent
|
|
84
|
+
parent = unsafe: read(parent_ptr).parent
|
|
85
|
+
|
|
86
|
+
return null
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
static function replace_child(
|
|
90
|
+
current: ref[OrderedSet[T]],
|
|
91
|
+
parent: ptr[Node[T]]?,
|
|
92
|
+
previous: ptr[Node[T]],
|
|
93
|
+
replacement: ptr[Node[T]]?
|
|
94
|
+
) -> void:
|
|
95
|
+
if parent == null:
|
|
96
|
+
current.root = replacement
|
|
97
|
+
else:
|
|
98
|
+
unsafe:
|
|
99
|
+
let parent_ptr = ptr[Node[T]]<-parent
|
|
100
|
+
if read(parent_ptr).left == previous:
|
|
101
|
+
read(parent_ptr).left = replacement
|
|
102
|
+
else if read(parent_ptr).right == previous:
|
|
103
|
+
read(parent_ptr).right = replacement
|
|
104
|
+
else:
|
|
105
|
+
fatal(c"ordered_set.OrderedSet.replace_child missing previous child")
|
|
106
|
+
|
|
107
|
+
if replacement != null:
|
|
108
|
+
unsafe:
|
|
109
|
+
read(ptr[Node[T]]<-replacement).parent = parent
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
static function rotate_left(current: ref[OrderedSet[T]], node: ptr[Node[T]]) -> ptr[Node[T]]:
|
|
113
|
+
let pivot = unsafe: read(node).right else:
|
|
114
|
+
fatal(c"ordered_set.OrderedSet.rotate_left missing pivot")
|
|
115
|
+
|
|
116
|
+
let pivot_ptr = unsafe: ptr[Node[T]]<-pivot
|
|
117
|
+
let parent = unsafe: read(node).parent
|
|
118
|
+
let pivot_left = unsafe: read(pivot_ptr).left
|
|
119
|
+
|
|
120
|
+
unsafe:
|
|
121
|
+
read(node).right = pivot_left
|
|
122
|
+
if pivot_left != null:
|
|
123
|
+
unsafe:
|
|
124
|
+
read(ptr[Node[T]]<-pivot_left).parent = node
|
|
125
|
+
|
|
126
|
+
OrderedSet[T].replace_child(current, parent, node, pivot)
|
|
127
|
+
|
|
128
|
+
unsafe:
|
|
129
|
+
read(pivot_ptr).left = node
|
|
130
|
+
read(node).parent = pivot
|
|
131
|
+
|
|
132
|
+
OrderedSet[T].update_height(node)
|
|
133
|
+
OrderedSet[T].update_height(pivot_ptr)
|
|
134
|
+
return pivot_ptr
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
static function rotate_right(current: ref[OrderedSet[T]], node: ptr[Node[T]]) -> ptr[Node[T]]:
|
|
138
|
+
let pivot = unsafe: read(node).left else:
|
|
139
|
+
fatal(c"ordered_set.OrderedSet.rotate_right missing pivot")
|
|
140
|
+
|
|
141
|
+
let pivot_ptr = unsafe: ptr[Node[T]]<-pivot
|
|
142
|
+
let parent = unsafe: read(node).parent
|
|
143
|
+
let pivot_right = unsafe: read(pivot_ptr).right
|
|
144
|
+
|
|
145
|
+
unsafe:
|
|
146
|
+
read(node).left = pivot_right
|
|
147
|
+
if pivot_right != null:
|
|
148
|
+
unsafe:
|
|
149
|
+
read(ptr[Node[T]]<-pivot_right).parent = node
|
|
150
|
+
|
|
151
|
+
OrderedSet[T].replace_child(current, parent, node, pivot)
|
|
152
|
+
|
|
153
|
+
unsafe:
|
|
154
|
+
read(pivot_ptr).right = node
|
|
155
|
+
read(node).parent = pivot
|
|
156
|
+
|
|
157
|
+
OrderedSet[T].update_height(node)
|
|
158
|
+
OrderedSet[T].update_height(pivot_ptr)
|
|
159
|
+
return pivot_ptr
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
static function rebalance(current: ref[OrderedSet[T]], node: ptr[Node[T]]?) -> void:
|
|
163
|
+
var cursor = node
|
|
164
|
+
while cursor != null:
|
|
165
|
+
let cursor_ptr = unsafe: ptr[Node[T]]<-cursor
|
|
166
|
+
OrderedSet[T].update_height(cursor_ptr)
|
|
167
|
+
|
|
168
|
+
let balance = OrderedSet[T].balance_factor(cursor)
|
|
169
|
+
if balance > 1:
|
|
170
|
+
let left = unsafe: read(cursor_ptr).left
|
|
171
|
+
if OrderedSet[T].balance_factor(left) < 0:
|
|
172
|
+
if left == null:
|
|
173
|
+
fatal(c"ordered_set.OrderedSet.rebalance missing left child")
|
|
174
|
+
OrderedSet[T].rotate_left(current, unsafe: ptr[Node[T]]<-left)
|
|
175
|
+
|
|
176
|
+
let rotated = OrderedSet[T].rotate_right(current, cursor_ptr)
|
|
177
|
+
cursor = unsafe: read(rotated).parent
|
|
178
|
+
else if balance < -1:
|
|
179
|
+
let right = unsafe: read(cursor_ptr).right
|
|
180
|
+
if OrderedSet[T].balance_factor(right) > 0:
|
|
181
|
+
if right == null:
|
|
182
|
+
fatal(c"ordered_set.OrderedSet.rebalance missing right child")
|
|
183
|
+
OrderedSet[T].rotate_right(current, unsafe: ptr[Node[T]]<-right)
|
|
184
|
+
|
|
185
|
+
let rotated = OrderedSet[T].rotate_left(current, cursor_ptr)
|
|
186
|
+
cursor = unsafe: read(rotated).parent
|
|
187
|
+
else:
|
|
188
|
+
cursor = unsafe: read(cursor_ptr).parent
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
static function locate(current: OrderedSet[T], value: T) -> SearchResult[T]:
|
|
192
|
+
var parent: ptr[Node[T]]? = null
|
|
193
|
+
var node = current.root
|
|
194
|
+
var compare = 0
|
|
195
|
+
while node != null:
|
|
196
|
+
let node_ptr = unsafe: ptr[Node[T]]<-node
|
|
197
|
+
let stored = unsafe: const_ptr_of(read(node_ptr).value)
|
|
198
|
+
compare = order[T](value, stored)
|
|
199
|
+
if compare < 0:
|
|
200
|
+
parent = node
|
|
201
|
+
unsafe:
|
|
202
|
+
node = read(node_ptr).left
|
|
203
|
+
else if compare > 0:
|
|
204
|
+
parent = node
|
|
205
|
+
unsafe:
|
|
206
|
+
node = read(node_ptr).right
|
|
207
|
+
else:
|
|
208
|
+
return SearchResult[T](node = node, parent = parent, compare = 0, found = true)
|
|
209
|
+
|
|
210
|
+
return SearchResult[T](node = null, parent = parent, compare = compare, found = false)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
static function release_subtree(node: ptr[Node[T]]?) -> void:
|
|
214
|
+
if node == null:
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
let node_ptr = unsafe: ptr[Node[T]]<-node
|
|
218
|
+
let left = unsafe: read(node_ptr).left
|
|
219
|
+
let right = unsafe: read(node_ptr).right
|
|
220
|
+
OrderedSet[T].release_subtree(left)
|
|
221
|
+
OrderedSet[T].release_subtree(right)
|
|
222
|
+
heap.release(node)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
static function detach_node(current: ref[OrderedSet[T]], node: ptr[Node[T]]) -> ptr[Node[T]]?:
|
|
226
|
+
let left = unsafe: read(node).left
|
|
227
|
+
let right = unsafe: read(node).right
|
|
228
|
+
if left != null and right != null:
|
|
229
|
+
let successor = OrderedSet[T].minimum(right) else:
|
|
230
|
+
fatal(c"ordered_set.OrderedSet.detach_node missing successor")
|
|
231
|
+
|
|
232
|
+
unsafe:
|
|
233
|
+
read(node).value = read(ptr[Node[T]]<-successor).value
|
|
234
|
+
|
|
235
|
+
return OrderedSet[T].detach_node(current, unsafe: ptr[Node[T]]<-successor)
|
|
236
|
+
|
|
237
|
+
var child = left
|
|
238
|
+
if child == null:
|
|
239
|
+
child = right
|
|
240
|
+
|
|
241
|
+
let parent = unsafe: read(node).parent
|
|
242
|
+
OrderedSet[T].replace_child(current, parent, node, child)
|
|
243
|
+
heap.release(node)
|
|
244
|
+
|
|
245
|
+
if parent != null:
|
|
246
|
+
return parent
|
|
247
|
+
|
|
248
|
+
return child
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
public function len() -> ptr_uint:
|
|
252
|
+
return this.len
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
public function is_empty() -> bool:
|
|
256
|
+
return this.len == 0
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
public function get(value: T) -> const_ptr[T]?:
|
|
260
|
+
let location = OrderedSet[T].locate(this, value)
|
|
261
|
+
if not location.found:
|
|
262
|
+
return null
|
|
263
|
+
|
|
264
|
+
let candidate = location.node else:
|
|
265
|
+
fatal(c"ordered_set.OrderedSet.get missing node")
|
|
266
|
+
|
|
267
|
+
unsafe:
|
|
268
|
+
return const_ptr_of(read(ptr[Node[T]]<-candidate).value)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
public function at(value: T) -> Option[T]:
|
|
272
|
+
let p = this.get(value) else:
|
|
273
|
+
return Option[T].none
|
|
274
|
+
|
|
275
|
+
unsafe:
|
|
276
|
+
return Option[T].some(value = read(ptr[T]<-p))
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
public function contains(value: T) -> bool:
|
|
280
|
+
return this.get(value) != null
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
public function iter() -> Iter[T]:
|
|
284
|
+
return Iter[T](node = OrderedSet[T].minimum(this.root))
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
public editable function clear() -> void:
|
|
288
|
+
OrderedSet[T].release_subtree(this.root)
|
|
289
|
+
this.root = null
|
|
290
|
+
this.len = 0
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
public editable function release() -> void:
|
|
294
|
+
this.clear()
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
public editable function insert(value: T) -> bool:
|
|
298
|
+
let location = OrderedSet[T].locate(this, value)
|
|
299
|
+
if location.found:
|
|
300
|
+
return false
|
|
301
|
+
|
|
302
|
+
let node = heap.must_alloc[Node[T]](1)
|
|
303
|
+
unsafe:
|
|
304
|
+
read(node) = Node[T](value = value, left = null, right = null, parent = location.parent, height = 1)
|
|
305
|
+
|
|
306
|
+
let parent = location.parent
|
|
307
|
+
if parent == null:
|
|
308
|
+
this.root = node
|
|
309
|
+
else:
|
|
310
|
+
unsafe:
|
|
311
|
+
let parent_ptr = ptr[Node[T]]<-parent
|
|
312
|
+
if location.compare < 0:
|
|
313
|
+
read(parent_ptr).left = node
|
|
314
|
+
else:
|
|
315
|
+
read(parent_ptr).right = node
|
|
316
|
+
|
|
317
|
+
this.len += 1
|
|
318
|
+
OrderedSet[T].rebalance(this, parent)
|
|
319
|
+
return true
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
public editable function remove(value: T) -> bool:
|
|
323
|
+
let location = OrderedSet[T].locate(this, value)
|
|
324
|
+
if not location.found:
|
|
325
|
+
return false
|
|
326
|
+
|
|
327
|
+
let node = location.node else:
|
|
328
|
+
fatal(c"ordered_set.OrderedSet.remove missing node")
|
|
329
|
+
|
|
330
|
+
let rebalance_from = OrderedSet[T].detach_node(this, unsafe: ptr[Node[T]]<-node)
|
|
331
|
+
this.len -= 1
|
|
332
|
+
OrderedSet[T].rebalance(this, rebalance_from)
|
|
333
|
+
return true
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
extending Iter[T]:
|
|
337
|
+
public function iter() -> Iter[T]:
|
|
338
|
+
return this
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
public editable function next() -> const_ptr[T]?:
|
|
342
|
+
let current = this.node else:
|
|
343
|
+
return null
|
|
344
|
+
|
|
345
|
+
this.node = OrderedSet[T].successor(current)
|
|
346
|
+
|
|
347
|
+
unsafe:
|
|
348
|
+
return const_ptr_of(read(ptr[Node[T]]<-current).value)
|
data/std/path.mt
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import std.str as text_ops
|
|
2
|
+
import std.string as string
|
|
3
|
+
import std.vec as vec
|
|
4
|
+
|
|
5
|
+
struct Segment:
|
|
6
|
+
start: ptr_uint
|
|
7
|
+
len: ptr_uint
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
public function is_absolute(path: str) -> bool:
|
|
11
|
+
return root_length(path) != 0
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
public function normalize_separators(path: str) -> string.String:
|
|
15
|
+
var result = string.String.with_capacity(path.len)
|
|
16
|
+
|
|
17
|
+
var index: ptr_uint = 0
|
|
18
|
+
while index < path.len:
|
|
19
|
+
let value = path.byte_at(index)
|
|
20
|
+
if value == 92:
|
|
21
|
+
result.push_byte(47)
|
|
22
|
+
else:
|
|
23
|
+
result.push_byte(value)
|
|
24
|
+
index += 1
|
|
25
|
+
|
|
26
|
+
return result
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
public function join(left: str, right: str) -> string.String:
|
|
30
|
+
if left.len == 0:
|
|
31
|
+
return string.String.from_str(right)
|
|
32
|
+
|
|
33
|
+
if right.len == 0:
|
|
34
|
+
return string.String.from_str(left)
|
|
35
|
+
|
|
36
|
+
if is_absolute(right):
|
|
37
|
+
return string.String.from_str(right)
|
|
38
|
+
|
|
39
|
+
var result = string.String.from_str(left)
|
|
40
|
+
let last = result.as_str().byte_at(result.len() - 1)
|
|
41
|
+
if not is_separator(last):
|
|
42
|
+
result.append("/")
|
|
43
|
+
|
|
44
|
+
var start: ptr_uint = 0
|
|
45
|
+
while start < right.len and is_separator(right.byte_at(start)):
|
|
46
|
+
start += 1
|
|
47
|
+
|
|
48
|
+
if start == right.len:
|
|
49
|
+
return result
|
|
50
|
+
|
|
51
|
+
result.append(right.slice(start, right.len - start))
|
|
52
|
+
return result
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
public function relative_path(path: str, base: str) -> Option[string.String]:
|
|
56
|
+
var normalized_path = normalize_separators(path)
|
|
57
|
+
defer normalized_path.release()
|
|
58
|
+
var normalized_base = normalize_separators(base)
|
|
59
|
+
defer normalized_base.release()
|
|
60
|
+
|
|
61
|
+
let path_text = normalized_path.as_str()
|
|
62
|
+
let base_text = normalized_base.as_str()
|
|
63
|
+
let path_root = root_length(path_text)
|
|
64
|
+
let base_root = root_length(base_text)
|
|
65
|
+
if not roots_compatible(path_text, path_root, base_text, base_root):
|
|
66
|
+
return Option[string.String].none
|
|
67
|
+
|
|
68
|
+
var path_segments = vec.Vec[Segment].create()
|
|
69
|
+
defer path_segments.release()
|
|
70
|
+
collect_normalized_segments(path_text, path_root, ref_of(path_segments))
|
|
71
|
+
|
|
72
|
+
var base_segments = vec.Vec[Segment].create()
|
|
73
|
+
defer base_segments.release()
|
|
74
|
+
collect_normalized_segments(base_text, base_root, ref_of(base_segments))
|
|
75
|
+
|
|
76
|
+
var common: ptr_uint = 0
|
|
77
|
+
let shared_len = min_ptr_uint(path_segments.len(), base_segments.len())
|
|
78
|
+
while common < shared_len:
|
|
79
|
+
let path_segment_ptr = path_segments.get(common) else:
|
|
80
|
+
fatal(c"path.relative_path missing path segment")
|
|
81
|
+
let base_segment_ptr = base_segments.get(common) else:
|
|
82
|
+
fatal(c"path.relative_path missing base segment")
|
|
83
|
+
|
|
84
|
+
unsafe:
|
|
85
|
+
if not segments_equal(path_text, read(path_segment_ptr), base_text, read(base_segment_ptr)):
|
|
86
|
+
break
|
|
87
|
+
|
|
88
|
+
common += 1
|
|
89
|
+
|
|
90
|
+
var result = string.String.with_capacity(path_text.len + base_text.len)
|
|
91
|
+
var index: ptr_uint = common
|
|
92
|
+
while index < base_segments.len():
|
|
93
|
+
append_relative_segment(ref_of(result), "..")
|
|
94
|
+
index += 1
|
|
95
|
+
|
|
96
|
+
index = common
|
|
97
|
+
while index < path_segments.len():
|
|
98
|
+
let path_segment_ptr = path_segments.get(index) else:
|
|
99
|
+
fatal(c"path.relative_path missing path segment for append")
|
|
100
|
+
|
|
101
|
+
unsafe:
|
|
102
|
+
append_relative_segment(ref_of(result), segment_text(path_text, read(path_segment_ptr)))
|
|
103
|
+
|
|
104
|
+
index += 1
|
|
105
|
+
|
|
106
|
+
if result.is_empty():
|
|
107
|
+
result.append(".")
|
|
108
|
+
|
|
109
|
+
return Option[string.String].some(value= result)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
public function is_within_root(path: str, root: str) -> bool:
|
|
113
|
+
var normalized_path = normalize_separators(path)
|
|
114
|
+
defer normalized_path.release()
|
|
115
|
+
var normalized_root = normalize_separators(root)
|
|
116
|
+
defer normalized_root.release()
|
|
117
|
+
|
|
118
|
+
let path_text = normalized_path.as_str()
|
|
119
|
+
let root_text = normalized_root.as_str()
|
|
120
|
+
let path_root = root_length(path_text)
|
|
121
|
+
let root_root = root_length(root_text)
|
|
122
|
+
if not roots_compatible(path_text, path_root, root_text, root_root):
|
|
123
|
+
return false
|
|
124
|
+
|
|
125
|
+
var path_segments = vec.Vec[Segment].create()
|
|
126
|
+
defer path_segments.release()
|
|
127
|
+
collect_normalized_segments(path_text, path_root, ref_of(path_segments))
|
|
128
|
+
|
|
129
|
+
var root_segments = vec.Vec[Segment].create()
|
|
130
|
+
defer root_segments.release()
|
|
131
|
+
collect_normalized_segments(root_text, root_root, ref_of(root_segments))
|
|
132
|
+
|
|
133
|
+
if path_segments.len() < root_segments.len():
|
|
134
|
+
return false
|
|
135
|
+
|
|
136
|
+
var index: ptr_uint = 0
|
|
137
|
+
while index < root_segments.len():
|
|
138
|
+
let path_segment_ptr = path_segments.get(index) else:
|
|
139
|
+
fatal(c"path.is_within_root missing path segment")
|
|
140
|
+
let root_segment_ptr = root_segments.get(index) else:
|
|
141
|
+
fatal(c"path.is_within_root missing root segment")
|
|
142
|
+
|
|
143
|
+
unsafe:
|
|
144
|
+
if not segments_equal(path_text, read(path_segment_ptr), root_text, read(root_segment_ptr)):
|
|
145
|
+
return false
|
|
146
|
+
|
|
147
|
+
index += 1
|
|
148
|
+
|
|
149
|
+
return true
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
public function basename(path: str) -> str:
|
|
153
|
+
if path.len == 0:
|
|
154
|
+
return "."
|
|
155
|
+
|
|
156
|
+
let root = root_length(path)
|
|
157
|
+
let stop = trim_trailing_separators(path, root)
|
|
158
|
+
if stop == root:
|
|
159
|
+
if root == 0:
|
|
160
|
+
return "."
|
|
161
|
+
|
|
162
|
+
return path.slice(0, root)
|
|
163
|
+
|
|
164
|
+
var index = stop
|
|
165
|
+
while index > root:
|
|
166
|
+
if is_separator(path.byte_at(index - 1)):
|
|
167
|
+
return path.slice(index, stop - index)
|
|
168
|
+
index -= 1
|
|
169
|
+
|
|
170
|
+
if root != 0:
|
|
171
|
+
return path.slice(root, stop - root)
|
|
172
|
+
|
|
173
|
+
return path.slice(0, stop)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
public function dirname(path: str) -> str:
|
|
177
|
+
if path.len == 0:
|
|
178
|
+
return "."
|
|
179
|
+
|
|
180
|
+
let root = root_length(path)
|
|
181
|
+
let stop = trim_trailing_separators(path, root)
|
|
182
|
+
if stop == root:
|
|
183
|
+
if root == 0:
|
|
184
|
+
return "."
|
|
185
|
+
|
|
186
|
+
return path.slice(0, root)
|
|
187
|
+
|
|
188
|
+
var index = stop
|
|
189
|
+
while index > root:
|
|
190
|
+
if is_separator(path.byte_at(index - 1)):
|
|
191
|
+
var dir_stop = index - 1
|
|
192
|
+
while dir_stop > root and is_separator(path.byte_at(dir_stop - 1)):
|
|
193
|
+
dir_stop -= 1
|
|
194
|
+
|
|
195
|
+
if dir_stop == 0:
|
|
196
|
+
return "."
|
|
197
|
+
|
|
198
|
+
return path.slice(0, dir_stop)
|
|
199
|
+
index -= 1
|
|
200
|
+
|
|
201
|
+
if root != 0:
|
|
202
|
+
return path.slice(0, root)
|
|
203
|
+
|
|
204
|
+
return "."
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
public function extension(path: str) -> Option[str]:
|
|
208
|
+
let name = basename(path)
|
|
209
|
+
match extension_dot(name):
|
|
210
|
+
Option.some as payload:
|
|
211
|
+
return Option[str].some(value= name.slice(payload.value, name.len - payload.value))
|
|
212
|
+
Option.none:
|
|
213
|
+
return Option[str].none
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
public function stem(path: str) -> str:
|
|
217
|
+
let name = basename(path)
|
|
218
|
+
return name.slice(0, extension_dot(name).unwrap_or(name.len))
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
function root_length(path: str) -> ptr_uint:
|
|
222
|
+
if path.len == 0:
|
|
223
|
+
return 0
|
|
224
|
+
|
|
225
|
+
if is_separator(path.byte_at(0)):
|
|
226
|
+
return 1
|
|
227
|
+
|
|
228
|
+
if path.len >= 3 and is_ascii_letter(path.byte_at(0)) and path.byte_at(1) == 58 and is_separator(path.byte_at(2)):
|
|
229
|
+
return 3
|
|
230
|
+
|
|
231
|
+
return 0
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
function roots_compatible(left: str, left_root: ptr_uint, right: str, right_root: ptr_uint) -> bool:
|
|
235
|
+
if left_root != right_root:
|
|
236
|
+
return false
|
|
237
|
+
|
|
238
|
+
if left_root == 0:
|
|
239
|
+
return true
|
|
240
|
+
|
|
241
|
+
if left_root == 1:
|
|
242
|
+
return true
|
|
243
|
+
|
|
244
|
+
if left_root == 3 and left.byte_at(1) == 58 and right.byte_at(1) == 58:
|
|
245
|
+
return ascii_fold(left.byte_at(0)) == ascii_fold(right.byte_at(0))
|
|
246
|
+
|
|
247
|
+
var index: ptr_uint = 0
|
|
248
|
+
while index < left_root:
|
|
249
|
+
if left.byte_at(index) != right.byte_at(index):
|
|
250
|
+
return false
|
|
251
|
+
|
|
252
|
+
index += 1
|
|
253
|
+
|
|
254
|
+
return true
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
function ascii_fold(value: ubyte) -> ubyte:
|
|
258
|
+
if value >= 65 and value <= 90:
|
|
259
|
+
return value + 32
|
|
260
|
+
|
|
261
|
+
return value
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
function collect_normalized_segments(path: str, root: ptr_uint, output: ref[vec.Vec[Segment]]) -> void:
|
|
265
|
+
var index = root
|
|
266
|
+
while index < path.len:
|
|
267
|
+
while index < path.len and is_separator(path.byte_at(index)):
|
|
268
|
+
index += 1
|
|
269
|
+
|
|
270
|
+
if index == path.len:
|
|
271
|
+
return
|
|
272
|
+
|
|
273
|
+
let segment_start = index
|
|
274
|
+
while index < path.len and not is_separator(path.byte_at(index)):
|
|
275
|
+
index += 1
|
|
276
|
+
|
|
277
|
+
let segment_len = index - segment_start
|
|
278
|
+
if segment_is_current_directory(path, segment_start, segment_len):
|
|
279
|
+
continue
|
|
280
|
+
|
|
281
|
+
if segment_is_parent_directory(path, segment_start, segment_len):
|
|
282
|
+
let last_segment_ptr = output.last()
|
|
283
|
+
if last_segment_ptr != null:
|
|
284
|
+
unsafe:
|
|
285
|
+
let last_segment = read(last_segment_ptr)
|
|
286
|
+
if not segment_is_parent_directory(path, last_segment.start, last_segment.len):
|
|
287
|
+
match output.pop():
|
|
288
|
+
Option.some:
|
|
289
|
+
pass
|
|
290
|
+
Option.none:
|
|
291
|
+
fatal(c"path.collect_normalized_segments failed to pop segment")
|
|
292
|
+
continue
|
|
293
|
+
|
|
294
|
+
if root == 0:
|
|
295
|
+
output.push(Segment(start = segment_start, len = segment_len))
|
|
296
|
+
|
|
297
|
+
continue
|
|
298
|
+
|
|
299
|
+
output.push(Segment(start = segment_start, len = segment_len))
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
function segment_is_current_directory(path: str, start: ptr_uint, len: ptr_uint) -> bool:
|
|
303
|
+
return len == 1 and path.byte_at(start) == 46
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
function segment_is_parent_directory(path: str, start: ptr_uint, len: ptr_uint) -> bool:
|
|
307
|
+
return len == 2 and path.byte_at(start) == 46 and path.byte_at(start + 1) == 46
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
function segments_equal(left: str, left_segment: Segment, right: str, right_segment: Segment) -> bool:
|
|
311
|
+
if left_segment.len != right_segment.len:
|
|
312
|
+
return false
|
|
313
|
+
|
|
314
|
+
var index: ptr_uint = 0
|
|
315
|
+
while index < left_segment.len:
|
|
316
|
+
if left.byte_at(left_segment.start + index) != right.byte_at(right_segment.start + index):
|
|
317
|
+
return false
|
|
318
|
+
|
|
319
|
+
index += 1
|
|
320
|
+
|
|
321
|
+
return true
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
function segment_text(path: str, segment: Segment) -> str:
|
|
325
|
+
return path.slice(segment.start, segment.len)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
function append_relative_segment(output: ref[string.String], segment: str) -> void:
|
|
329
|
+
if not output.is_empty():
|
|
330
|
+
output.append("/")
|
|
331
|
+
|
|
332
|
+
output.append(segment)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
function min_ptr_uint(left: ptr_uint, right: ptr_uint) -> ptr_uint:
|
|
336
|
+
if left < right:
|
|
337
|
+
return left
|
|
338
|
+
|
|
339
|
+
return right
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
function trim_trailing_separators(path: str, minimum: ptr_uint) -> ptr_uint:
|
|
343
|
+
var stop = path.len
|
|
344
|
+
while stop > minimum and is_separator(path.byte_at(stop - 1)):
|
|
345
|
+
stop -= 1
|
|
346
|
+
|
|
347
|
+
return stop
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
function extension_dot(name: str) -> Option[ptr_uint]:
|
|
351
|
+
var index = name.len
|
|
352
|
+
while index > 0:
|
|
353
|
+
index -= 1
|
|
354
|
+
if name.byte_at(index) == 46:
|
|
355
|
+
if index == 0:
|
|
356
|
+
return Option[ptr_uint].none
|
|
357
|
+
|
|
358
|
+
return Option[ptr_uint].some(value= index)
|
|
359
|
+
|
|
360
|
+
return Option[ptr_uint].none
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
function is_separator(value: ubyte) -> bool:
|
|
364
|
+
return value == 47 or value == 92
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
function is_ascii_letter(value: ubyte) -> bool:
|
|
368
|
+
return (value >= 65 and value <= 90) or (value >= 97 and value <= 122)
|