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/mem/arena.mt
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import std.mem.heap as heap
|
|
2
|
+
|
|
3
|
+
public type Mark = ptr_uint
|
|
4
|
+
|
|
5
|
+
public struct Arena:
|
|
6
|
+
memory: own[ubyte]?
|
|
7
|
+
capacity: ptr_uint
|
|
8
|
+
alignment: ptr_uint
|
|
9
|
+
offset: ptr_uint
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
public function create(capacity_bytes: ptr_uint) -> Arena:
|
|
13
|
+
return create_aligned(capacity_bytes, 1)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
public function create_aligned(capacity_bytes: ptr_uint, alignment: ptr_uint) -> Arena:
|
|
17
|
+
let normalized_alignment = heap.normalize_alignment(alignment)
|
|
18
|
+
if normalized_alignment == 0:
|
|
19
|
+
fatal(c"arena.create_aligned requires a power-of-two alignment")
|
|
20
|
+
|
|
21
|
+
let memory = heap.alloc_bytes_aligned(capacity_bytes, normalized_alignment) else:
|
|
22
|
+
if capacity_bytes != 0:
|
|
23
|
+
fatal(c"arena.create_aligned out of memory")
|
|
24
|
+
|
|
25
|
+
return Arena(
|
|
26
|
+
memory = null,
|
|
27
|
+
capacity = 0,
|
|
28
|
+
alignment = normalized_alignment,
|
|
29
|
+
offset = 0,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
return unsafe: Arena(
|
|
33
|
+
memory = own[ubyte]<-memory,
|
|
34
|
+
capacity = capacity_bytes,
|
|
35
|
+
alignment = normalized_alignment,
|
|
36
|
+
offset = 0
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
public function create_for[T](count: ptr_uint) -> Arena:
|
|
41
|
+
let element_size = ptr_uint<-size_of(T)
|
|
42
|
+
if heap.mul_overflows(count, element_size):
|
|
43
|
+
fatal(c"arena.create_for size overflow")
|
|
44
|
+
|
|
45
|
+
return create_aligned(count * element_size, align_of(T))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
extending Arena:
|
|
49
|
+
public function mark() -> Mark:
|
|
50
|
+
return this.offset
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
public editable function reset(mark: Mark) -> void:
|
|
54
|
+
if mark > this.offset:
|
|
55
|
+
fatal(c"arena.reset invalid mark")
|
|
56
|
+
|
|
57
|
+
this.offset = mark
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
public function remaining_bytes() -> ptr_uint:
|
|
61
|
+
return this.capacity - this.offset
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
public editable function alloc_bytes(size_bytes: ptr_uint) -> ptr[ubyte]?:
|
|
65
|
+
return this.alloc_bytes_aligned(size_bytes, 1)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
public editable function alloc_bytes_aligned(size_bytes: ptr_uint, alignment: ptr_uint) -> ptr[ubyte]?:
|
|
69
|
+
let backing = this.memory else:
|
|
70
|
+
return null
|
|
71
|
+
if alignment == 0:
|
|
72
|
+
return null
|
|
73
|
+
if (alignment & (alignment - 1)) != 0:
|
|
74
|
+
return null
|
|
75
|
+
if alignment > this.alignment:
|
|
76
|
+
return null
|
|
77
|
+
|
|
78
|
+
let mask = alignment - 1
|
|
79
|
+
if this.offset > heap.ptr_uint_max - mask:
|
|
80
|
+
return null
|
|
81
|
+
|
|
82
|
+
let aligned_offset = (this.offset + mask) & ~mask
|
|
83
|
+
if aligned_offset > this.capacity:
|
|
84
|
+
return null
|
|
85
|
+
if size_bytes > this.capacity - aligned_offset:
|
|
86
|
+
return null
|
|
87
|
+
|
|
88
|
+
let result = backing + aligned_offset
|
|
89
|
+
this.offset = aligned_offset + size_bytes
|
|
90
|
+
return result
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
public editable function alloc[T](count: ptr_uint) -> ptr[T]?:
|
|
94
|
+
let element_size = ptr_uint<-size_of(T)
|
|
95
|
+
if heap.mul_overflows(count, element_size):
|
|
96
|
+
return null
|
|
97
|
+
|
|
98
|
+
let memory = this.alloc_bytes_aligned(count * element_size, ptr_uint<-align_of(T)) else:
|
|
99
|
+
return null
|
|
100
|
+
|
|
101
|
+
return unsafe: ptr[T]<-memory
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
public editable function try_to_cstr(text: str) -> cstr?:
|
|
105
|
+
if text.len == heap.ptr_uint_max:
|
|
106
|
+
return null
|
|
107
|
+
|
|
108
|
+
let memory = this.alloc_bytes(text.len + 1) else:
|
|
109
|
+
return null
|
|
110
|
+
|
|
111
|
+
unsafe:
|
|
112
|
+
heap.copy_bytes(memory, ptr[ubyte]<-text.data, text.len)
|
|
113
|
+
let buffer = ptr[char]<-memory
|
|
114
|
+
read(buffer + text.len) = zero[char]
|
|
115
|
+
return cstr<-buffer
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
public editable function to_cstr(text: str) -> cstr:
|
|
119
|
+
if text.len == heap.ptr_uint_max:
|
|
120
|
+
fatal(c"arena.to_cstr size overflow")
|
|
121
|
+
|
|
122
|
+
let memory = this.alloc_bytes(text.len + 1) else:
|
|
123
|
+
fatal(c"arena.to_cstr out of memory")
|
|
124
|
+
|
|
125
|
+
unsafe:
|
|
126
|
+
heap.copy_bytes(memory, ptr[ubyte]<-text.data, text.len)
|
|
127
|
+
let buffer = ptr[char]<-memory
|
|
128
|
+
read(buffer + text.len) = zero[char]
|
|
129
|
+
return cstr<-buffer
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
public editable function release() -> void:
|
|
133
|
+
heap.release(this.memory)
|
|
134
|
+
this.memory = null
|
|
135
|
+
this.capacity = 0
|
|
136
|
+
this.alignment = 0
|
|
137
|
+
this.offset = 0
|
data/std/mem/endian.mt
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
public function swap_ushort(value: ushort) -> ushort:
|
|
2
|
+
return ushort<-(
|
|
3
|
+
((uint<-value & 0x00ff) << 8) |
|
|
4
|
+
((uint<-value & 0xff00) >> 8)
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
public function swap_uint(value: uint) -> uint:
|
|
9
|
+
return (
|
|
10
|
+
((value & 0x000000ff) << 24) |
|
|
11
|
+
((value & 0x0000ff00) << 8) |
|
|
12
|
+
((value & 0x00ff0000) >> 8) |
|
|
13
|
+
((value & 0xff000000) >> 24)
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
public function swap_ulong(value: ulong) -> ulong:
|
|
18
|
+
return (
|
|
19
|
+
((value & 0x00000000000000fful) << 56) |
|
|
20
|
+
((value & 0x000000000000ff00ul) << 40) |
|
|
21
|
+
((value & 0x0000000000ff0000ul) << 24) |
|
|
22
|
+
((value & 0x00000000ff000000ul) << 8) |
|
|
23
|
+
((value & 0x000000ff00000000ul) >> 8) |
|
|
24
|
+
((value & 0x0000ff0000000000ul) >> 24) |
|
|
25
|
+
((value & 0x00ff000000000000ul) >> 40) |
|
|
26
|
+
((value & 0xff00000000000000ul) >> 56)
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
public function hton_ushort(value: ushort) -> ushort:
|
|
31
|
+
return swap_ushort(value)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
public function hton_uint(value: uint) -> uint:
|
|
35
|
+
return swap_uint(value)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
public function hton_ulong(value: ulong) -> ulong:
|
|
39
|
+
return swap_ulong(value)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
public function ntoh_ushort(value: ushort) -> ushort:
|
|
43
|
+
return swap_ushort(value)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
public function ntoh_uint(value: uint) -> uint:
|
|
47
|
+
return swap_uint(value)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
public function ntoh_ulong(value: ulong) -> ulong:
|
|
51
|
+
return swap_ulong(value)
|
data/std/mem/heap.mt
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import std.c.libc as libc
|
|
2
|
+
import std.cstring as cstring
|
|
3
|
+
|
|
4
|
+
public const ptr_uint_max: ptr_uint = ~0
|
|
5
|
+
public const minimum_alignment: ptr_uint = size_of(ptr[void])
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
function valid_alignment(alignment: ptr_uint) -> bool:
|
|
9
|
+
if alignment == 0:
|
|
10
|
+
return false
|
|
11
|
+
|
|
12
|
+
return (alignment & (alignment - 1)) == 0
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
public function normalize_alignment(alignment: ptr_uint) -> ptr_uint:
|
|
16
|
+
if not valid_alignment(alignment):
|
|
17
|
+
return 0
|
|
18
|
+
|
|
19
|
+
let minimum = minimum_alignment
|
|
20
|
+
if alignment < minimum:
|
|
21
|
+
return minimum
|
|
22
|
+
|
|
23
|
+
return alignment
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
public function mul_overflows(left: ptr_uint, right: ptr_uint) -> bool:
|
|
27
|
+
if left != 0 and right > ptr_uint_max / left:
|
|
28
|
+
return true
|
|
29
|
+
|
|
30
|
+
return false
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
public function alloc_bytes(size_bytes: ptr_uint) -> ptr[void]?:
|
|
34
|
+
if size_bytes == 0:
|
|
35
|
+
return null
|
|
36
|
+
|
|
37
|
+
return libc.malloc(size_bytes)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
public function must_alloc_bytes(size_bytes: ptr_uint) -> ptr[void]:
|
|
41
|
+
if size_bytes == 0:
|
|
42
|
+
fatal(c"heap.must_alloc_bytes requires size > 0")
|
|
43
|
+
|
|
44
|
+
let memory = alloc_bytes(size_bytes) else:
|
|
45
|
+
fatal(c"heap.must_alloc_bytes out of memory")
|
|
46
|
+
|
|
47
|
+
return memory
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
public function alloc_bytes_aligned(size_bytes: ptr_uint, alignment: ptr_uint) -> ptr[void]?:
|
|
51
|
+
if size_bytes == 0:
|
|
52
|
+
return null
|
|
53
|
+
|
|
54
|
+
let normalized_alignment = normalize_alignment(alignment)
|
|
55
|
+
if normalized_alignment == 0:
|
|
56
|
+
return null
|
|
57
|
+
|
|
58
|
+
let mask = normalized_alignment - 1
|
|
59
|
+
if size_bytes > ptr_uint_max - mask:
|
|
60
|
+
return null
|
|
61
|
+
|
|
62
|
+
let rounded_size = (size_bytes + mask) & ~mask
|
|
63
|
+
return libc.aligned_alloc(normalized_alignment, rounded_size)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
public function must_alloc_bytes_aligned(size_bytes: ptr_uint, alignment: ptr_uint) -> ptr[void]:
|
|
67
|
+
if size_bytes == 0:
|
|
68
|
+
fatal(c"heap.must_alloc_bytes_aligned requires size > 0")
|
|
69
|
+
|
|
70
|
+
let normalized_alignment = normalize_alignment(alignment)
|
|
71
|
+
if normalized_alignment == 0:
|
|
72
|
+
fatal(c"heap.must_alloc_bytes_aligned requires a power-of-two alignment")
|
|
73
|
+
|
|
74
|
+
let memory = alloc_bytes_aligned(size_bytes, normalized_alignment) else:
|
|
75
|
+
fatal(c"heap.must_alloc_bytes_aligned out of memory")
|
|
76
|
+
|
|
77
|
+
return memory
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
public function alloc_zeroed_bytes(count: ptr_uint, element_size_bytes: ptr_uint) -> ptr[void]?:
|
|
81
|
+
if count == 0 or element_size_bytes == 0:
|
|
82
|
+
return null
|
|
83
|
+
|
|
84
|
+
if mul_overflows(count, element_size_bytes):
|
|
85
|
+
return null
|
|
86
|
+
|
|
87
|
+
return libc.calloc(count, element_size_bytes)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
public function must_alloc_zeroed_bytes(count: ptr_uint, element_size_bytes: ptr_uint) -> ptr[void]:
|
|
91
|
+
if count == 0 or element_size_bytes == 0:
|
|
92
|
+
fatal(c"heap.must_alloc_zeroed_bytes requires count > 0 and element size > 0")
|
|
93
|
+
|
|
94
|
+
let memory = alloc_zeroed_bytes(count, element_size_bytes) else:
|
|
95
|
+
fatal(c"heap.must_alloc_zeroed_bytes out of memory")
|
|
96
|
+
|
|
97
|
+
return memory
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
public function copy_bytes(destination: ptr[ubyte]?, source: ptr[ubyte]?, size_bytes: ptr_uint) -> void:
|
|
101
|
+
if size_bytes == 0:
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
if destination == null or source == null:
|
|
105
|
+
fatal(c"heap.copy_bytes requires non-null pointers for non-empty copies")
|
|
106
|
+
|
|
107
|
+
var index: ptr_uint = 0
|
|
108
|
+
while index < size_bytes:
|
|
109
|
+
unsafe:
|
|
110
|
+
read(destination + index) = read(source + index)
|
|
111
|
+
index += 1
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
public function move_bytes(destination: ptr[ubyte]?, source: ptr[ubyte]?, size_bytes: ptr_uint) -> void:
|
|
115
|
+
if size_bytes == 0:
|
|
116
|
+
return
|
|
117
|
+
|
|
118
|
+
if destination == null or source == null:
|
|
119
|
+
fatal(c"heap.move_bytes requires non-null pointers for non-empty copies")
|
|
120
|
+
|
|
121
|
+
unsafe:
|
|
122
|
+
cstring.move_bytes(ptr[void]<-destination, ptr[void]<-source, size_bytes)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
public function resize_bytes(memory: ptr[void]?, size_bytes: ptr_uint) -> ptr[void]?:
|
|
126
|
+
if size_bytes == 0:
|
|
127
|
+
release_bytes(memory)
|
|
128
|
+
return null
|
|
129
|
+
|
|
130
|
+
return libc.realloc(memory, size_bytes)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
public function must_resize_bytes(memory: ptr[void]?, size_bytes: ptr_uint) -> ptr[void]:
|
|
134
|
+
if size_bytes == 0:
|
|
135
|
+
fatal(c"heap.must_resize_bytes requires size > 0")
|
|
136
|
+
|
|
137
|
+
let resized = resize_bytes(memory, size_bytes) else:
|
|
138
|
+
fatal(c"heap.must_resize_bytes out of memory")
|
|
139
|
+
|
|
140
|
+
return resized
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
## Frees a raw memory allocation. The caller's binding is NOT nulled after
|
|
144
|
+
## this call — a second `release_bytes` on the same pointer is a double-free.
|
|
145
|
+
## This is inherent to by-value pointer parameters: the function cannot reach
|
|
146
|
+
## the caller's binding to null it. For idempotent safe-release syntax, see
|
|
147
|
+
## `release_and_null[T]` or use a scope-bound allocator such as `arena.Arena`.
|
|
148
|
+
public function release_bytes(memory: ptr[void]?) -> void:
|
|
149
|
+
libc.free(memory)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
public function alloc[T](count: ptr_uint) -> own[T]?:
|
|
153
|
+
let alignment = ptr_uint<-align_of(T)
|
|
154
|
+
if alignment > minimum_alignment:
|
|
155
|
+
return null
|
|
156
|
+
|
|
157
|
+
let element_size = ptr_uint<-size_of(T)
|
|
158
|
+
if mul_overflows(count, element_size):
|
|
159
|
+
return null
|
|
160
|
+
|
|
161
|
+
let memory = alloc_bytes(count * element_size) else:
|
|
162
|
+
return null
|
|
163
|
+
|
|
164
|
+
return unsafe: own[T]<-memory
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
public function must_alloc[T](count: ptr_uint) -> own[T]:
|
|
168
|
+
if count == 0:
|
|
169
|
+
fatal(c"heap.must_alloc requires count > 0")
|
|
170
|
+
|
|
171
|
+
if ptr_uint<-align_of(T) > minimum_alignment:
|
|
172
|
+
fatal(c"heap.must_alloc does not support over-aligned types")
|
|
173
|
+
|
|
174
|
+
let element_size = ptr_uint<-size_of(T)
|
|
175
|
+
if mul_overflows(count, element_size):
|
|
176
|
+
fatal(c"heap.must_alloc size overflow")
|
|
177
|
+
|
|
178
|
+
let memory = alloc[T](count) else:
|
|
179
|
+
fatal(c"heap.must_alloc out of memory")
|
|
180
|
+
|
|
181
|
+
return memory
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
public function alloc_aligned[T](count: ptr_uint) -> own[T]?:
|
|
185
|
+
let element_size = ptr_uint<-size_of(T)
|
|
186
|
+
if mul_overflows(count, element_size):
|
|
187
|
+
return null
|
|
188
|
+
|
|
189
|
+
let memory = alloc_bytes_aligned(count * element_size, align_of(T)) else:
|
|
190
|
+
return null
|
|
191
|
+
|
|
192
|
+
return unsafe: own[T]<-memory
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
public function must_alloc_aligned[T](count: ptr_uint) -> own[T]:
|
|
196
|
+
if count == 0:
|
|
197
|
+
fatal(c"heap.must_alloc_aligned requires count > 0")
|
|
198
|
+
|
|
199
|
+
let element_size = ptr_uint<-size_of(T)
|
|
200
|
+
if mul_overflows(count, element_size):
|
|
201
|
+
fatal(c"heap.must_alloc_aligned size overflow")
|
|
202
|
+
|
|
203
|
+
let memory = alloc_aligned[T](count) else:
|
|
204
|
+
fatal(c"heap.must_alloc_aligned out of memory")
|
|
205
|
+
|
|
206
|
+
return memory
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
public function alloc_zeroed[T](count: ptr_uint) -> own[T]?:
|
|
210
|
+
let alignment = ptr_uint<-align_of(T)
|
|
211
|
+
if alignment > minimum_alignment:
|
|
212
|
+
return null
|
|
213
|
+
|
|
214
|
+
let memory = alloc_zeroed_bytes(count, size_of(T)) else:
|
|
215
|
+
return null
|
|
216
|
+
|
|
217
|
+
return unsafe: own[T]<-memory
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
public function must_alloc_zeroed[T](count: ptr_uint) -> own[T]:
|
|
221
|
+
if count == 0:
|
|
222
|
+
fatal(c"heap.must_alloc_zeroed requires count > 0")
|
|
223
|
+
|
|
224
|
+
if ptr_uint<-align_of(T) > minimum_alignment:
|
|
225
|
+
fatal(c"heap.must_alloc_zeroed does not support over-aligned types")
|
|
226
|
+
|
|
227
|
+
let element_size = ptr_uint<-size_of(T)
|
|
228
|
+
if mul_overflows(count, element_size):
|
|
229
|
+
fatal(c"heap.must_alloc_zeroed size overflow")
|
|
230
|
+
|
|
231
|
+
let memory = alloc_zeroed[T](count) else:
|
|
232
|
+
fatal(c"heap.must_alloc_zeroed out of memory")
|
|
233
|
+
|
|
234
|
+
return memory
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
public function resize[T](memory: ptr[T]?, count: ptr_uint) -> own[T]?:
|
|
238
|
+
let alignment = ptr_uint<-align_of(T)
|
|
239
|
+
if alignment > minimum_alignment:
|
|
240
|
+
return null
|
|
241
|
+
|
|
242
|
+
let element_size = ptr_uint<-size_of(T)
|
|
243
|
+
if mul_overflows(count, element_size):
|
|
244
|
+
return null
|
|
245
|
+
|
|
246
|
+
if memory == null:
|
|
247
|
+
let resized = resize_bytes(null, count * element_size) else:
|
|
248
|
+
return null
|
|
249
|
+
|
|
250
|
+
return unsafe: own[T]<-resized
|
|
251
|
+
|
|
252
|
+
unsafe:
|
|
253
|
+
let resized = resize_bytes(ptr[void]<-memory, count * element_size) else:
|
|
254
|
+
return null
|
|
255
|
+
|
|
256
|
+
return own[T]<-resized
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
public function must_resize[T](memory: ptr[T]?, count: ptr_uint) -> own[T]:
|
|
260
|
+
if count == 0:
|
|
261
|
+
fatal(c"heap.must_resize requires count > 0")
|
|
262
|
+
|
|
263
|
+
if ptr_uint<-align_of(T) > minimum_alignment:
|
|
264
|
+
fatal(c"heap.must_resize does not support over-aligned types")
|
|
265
|
+
|
|
266
|
+
let element_size = ptr_uint<-size_of(T)
|
|
267
|
+
if mul_overflows(count, element_size):
|
|
268
|
+
fatal(c"heap.must_resize size overflow")
|
|
269
|
+
|
|
270
|
+
let resized = resize[T](memory, count) else:
|
|
271
|
+
fatal(c"heap.must_resize out of memory")
|
|
272
|
+
|
|
273
|
+
return resized
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
## Frees a typed heap allocation. The caller's binding is NOT nulled — a
|
|
277
|
+
## second `release` on the same pointer is a double-free. Prefer
|
|
278
|
+
## `release_and_null[T]` when you need the binding nulled after freeing,
|
|
279
|
+
## or use a scope-bound allocator such as `arena.Arena` for bulk free.
|
|
280
|
+
public function release[T](memory: ptr[T]?) -> void:
|
|
281
|
+
unsafe: release_bytes(ptr[void]<-memory)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
## Frees a typed heap allocation and nulls the caller's binding so a second
|
|
285
|
+
## release is a no-op. The binding is passed by `ref[ptr[T]?]` so the helper
|
|
286
|
+
## can write `null` back into the caller's variable.
|
|
287
|
+
##
|
|
288
|
+
## var mem = heap.must_alloc[MyStruct](1)
|
|
289
|
+
## heap.release_and_null(ref_of(mem)) # mem is now null
|
|
290
|
+
## heap.release_and_null(ref_of(mem)) # safe — no-op
|
|
291
|
+
public function release_and_null[T](memory: ref[ptr[T]?]) -> void:
|
|
292
|
+
unsafe: release_bytes(ptr[void]<-read(memory))
|
|
293
|
+
read(memory) = null
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
public function bytes_of[T](value: ref[T]) -> span[ubyte]:
|
|
297
|
+
unsafe:
|
|
298
|
+
return span[ubyte](data = ptr[ubyte]<-ptr_of(value), len = size_of(T))
|
data/std/mem/pool.mt
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import std.mem.heap as heap
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function slot_alignment(slot_size_bytes: ptr_uint, base_alignment: ptr_uint) -> ptr_uint:
|
|
5
|
+
if slot_size_bytes == 0:
|
|
6
|
+
return base_alignment
|
|
7
|
+
|
|
8
|
+
var alignment = base_alignment
|
|
9
|
+
while alignment > 1 and (slot_size_bytes & (alignment - 1)) != 0:
|
|
10
|
+
alignment = alignment / 2
|
|
11
|
+
|
|
12
|
+
return alignment
|
|
13
|
+
|
|
14
|
+
public struct Pool:
|
|
15
|
+
memory: ptr[ubyte]?
|
|
16
|
+
occupancy: ptr[bool]?
|
|
17
|
+
slot_size: ptr_uint
|
|
18
|
+
slot_alignment: ptr_uint
|
|
19
|
+
slot_count: ptr_uint
|
|
20
|
+
used_count: ptr_uint
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
public function create(slot_size_bytes: ptr_uint, slot_count: ptr_uint) -> Pool:
|
|
24
|
+
return create_aligned(slot_size_bytes, slot_count, 1)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
public function create_aligned(slot_size_bytes: ptr_uint, slot_count: ptr_uint, alignment: ptr_uint) -> Pool:
|
|
28
|
+
let normalized_alignment = heap.normalize_alignment(alignment)
|
|
29
|
+
if normalized_alignment == 0:
|
|
30
|
+
fatal(c"pool.create_aligned requires a power-of-two alignment")
|
|
31
|
+
|
|
32
|
+
if slot_count == 0:
|
|
33
|
+
return Pool(
|
|
34
|
+
memory = null,
|
|
35
|
+
occupancy = null,
|
|
36
|
+
slot_size = slot_size_bytes,
|
|
37
|
+
slot_alignment = slot_alignment(slot_size_bytes, normalized_alignment),
|
|
38
|
+
slot_count = 0,
|
|
39
|
+
used_count = 0
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if slot_size_bytes == 0:
|
|
43
|
+
fatal(c"pool.create_aligned requires slot size > 0 when slot count > 0")
|
|
44
|
+
|
|
45
|
+
if heap.mul_overflows(slot_size_bytes, slot_count):
|
|
46
|
+
fatal(c"pool.create size overflow")
|
|
47
|
+
|
|
48
|
+
let total_size = slot_size_bytes * slot_count
|
|
49
|
+
let memory = heap.alloc_bytes_aligned(total_size, normalized_alignment) else:
|
|
50
|
+
fatal(c"pool.create_aligned out of memory")
|
|
51
|
+
|
|
52
|
+
let occupancy = heap.alloc_zeroed[bool](slot_count) else:
|
|
53
|
+
heap.release_bytes(memory)
|
|
54
|
+
fatal(c"pool.create occupancy out of memory")
|
|
55
|
+
|
|
56
|
+
return unsafe: Pool(
|
|
57
|
+
memory = ptr[ubyte]<-memory,
|
|
58
|
+
occupancy = occupancy,
|
|
59
|
+
slot_size = slot_size_bytes,
|
|
60
|
+
slot_alignment = slot_alignment(slot_size_bytes, normalized_alignment),
|
|
61
|
+
slot_count = slot_count,
|
|
62
|
+
used_count = 0
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
public function slot_size_for[T]() -> ptr_uint:
|
|
67
|
+
let size = ptr_uint<-size_of(T)
|
|
68
|
+
let alignment = ptr_uint<-align_of(T)
|
|
69
|
+
let mask = alignment - 1
|
|
70
|
+
if size > heap.ptr_uint_max - mask:
|
|
71
|
+
fatal(c"pool.slot_size_for overflow")
|
|
72
|
+
|
|
73
|
+
return (size + mask) & ~mask
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
public function create_for[T](slot_count: ptr_uint) -> Pool:
|
|
77
|
+
return create_aligned(slot_size_for[T](), slot_count, align_of(T))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
extending Pool:
|
|
81
|
+
public function remaining_slots() -> ptr_uint:
|
|
82
|
+
return this.slot_count - this.used_count
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
public editable function alloc_bytes() -> ptr[ubyte]?:
|
|
86
|
+
let memory = this.memory else:
|
|
87
|
+
return null
|
|
88
|
+
let occupancy = this.occupancy else:
|
|
89
|
+
return null
|
|
90
|
+
|
|
91
|
+
var index: ptr_uint = 0
|
|
92
|
+
while index < this.slot_count:
|
|
93
|
+
unsafe:
|
|
94
|
+
let state_ptr = occupancy + index
|
|
95
|
+
if not (read(state_ptr)):
|
|
96
|
+
read(state_ptr) = true
|
|
97
|
+
this.used_count = this.used_count + 1
|
|
98
|
+
return memory + (index * this.slot_size)
|
|
99
|
+
index = index + 1
|
|
100
|
+
|
|
101
|
+
return null
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
public editable function alloc[T]() -> ptr[T]?:
|
|
105
|
+
let size = ptr_uint<-size_of(T)
|
|
106
|
+
let alignment = ptr_uint<-align_of(T)
|
|
107
|
+
let mask = alignment - 1
|
|
108
|
+
if size > heap.ptr_uint_max - mask:
|
|
109
|
+
return null
|
|
110
|
+
|
|
111
|
+
let slot_size = (size + mask) & ~mask
|
|
112
|
+
if this.slot_alignment < alignment:
|
|
113
|
+
return null
|
|
114
|
+
if this.slot_size < slot_size:
|
|
115
|
+
return null
|
|
116
|
+
|
|
117
|
+
let memory = this.alloc_bytes() else:
|
|
118
|
+
return null
|
|
119
|
+
|
|
120
|
+
return unsafe: ptr[T]<-memory
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
public editable function release_bytes(slot: ptr[ubyte]?) -> bool:
|
|
124
|
+
if slot == null:
|
|
125
|
+
return false
|
|
126
|
+
|
|
127
|
+
let memory = this.memory else:
|
|
128
|
+
return false
|
|
129
|
+
let occupancy = this.occupancy else:
|
|
130
|
+
return false
|
|
131
|
+
|
|
132
|
+
var index: ptr_uint = 0
|
|
133
|
+
while index < this.slot_count:
|
|
134
|
+
unsafe:
|
|
135
|
+
let candidate = memory + (index * this.slot_size)
|
|
136
|
+
if candidate == slot:
|
|
137
|
+
let state_ptr = occupancy + index
|
|
138
|
+
if not (read(state_ptr)):
|
|
139
|
+
return false
|
|
140
|
+
|
|
141
|
+
read(state_ptr) = false
|
|
142
|
+
this.used_count = this.used_count - 1
|
|
143
|
+
return true
|
|
144
|
+
index = index + 1
|
|
145
|
+
|
|
146
|
+
return false
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
public editable function release_slot[T](slot: ptr[T]?) -> bool:
|
|
150
|
+
if slot == null:
|
|
151
|
+
return false
|
|
152
|
+
|
|
153
|
+
return unsafe: this.release_bytes(ptr[ubyte]<-slot)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
public editable function release() -> void:
|
|
157
|
+
heap.release(this.memory)
|
|
158
|
+
heap.release(this.occupancy)
|
|
159
|
+
this.memory = null
|
|
160
|
+
this.occupancy = null
|
|
161
|
+
this.slot_size = 0
|
|
162
|
+
this.slot_alignment = 0
|
|
163
|
+
this.slot_count = 0
|
|
164
|
+
this.used_count = 0
|
data/std/mem/stack.mt
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import std.mem.arena as arena
|
|
2
|
+
|
|
3
|
+
public type Mark = arena.Mark
|
|
4
|
+
|
|
5
|
+
public struct Stack:
|
|
6
|
+
arena: arena.Arena
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
public function create(capacity_bytes: ptr_uint) -> Stack:
|
|
10
|
+
return create_aligned(capacity_bytes, 1)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
public function create_aligned(capacity_bytes: ptr_uint, alignment: ptr_uint) -> Stack:
|
|
14
|
+
return Stack(arena = arena.create_aligned(capacity_bytes, alignment))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
public function create_for[T](count: ptr_uint) -> Stack:
|
|
18
|
+
return Stack(arena = arena.create_for[T](count))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
extending Stack:
|
|
22
|
+
public function mark() -> Mark:
|
|
23
|
+
return this.arena.mark()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
public editable function reset(mark: Mark) -> void:
|
|
27
|
+
this.arena.reset(mark)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
public function remaining_bytes() -> ptr_uint:
|
|
31
|
+
return this.arena.remaining_bytes()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
public editable function alloc_bytes(size_bytes: ptr_uint) -> ptr[ubyte]?:
|
|
35
|
+
return this.arena.alloc_bytes(size_bytes)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
public editable function alloc_bytes_aligned(size_bytes: ptr_uint, alignment: ptr_uint) -> ptr[ubyte]?:
|
|
39
|
+
return this.arena.alloc_bytes_aligned(size_bytes, alignment)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
public editable function alloc[T](count: ptr_uint) -> ptr[T]?:
|
|
43
|
+
return this.arena.alloc[T](count)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
public editable function release() -> void:
|
|
47
|
+
this.arena.release()
|