Compare commits

...

3 Commits

Author SHA1 Message Date
hl-valdemar 1d719c6a42 allow freeing immutable allocations 2026-07-22 01:10:33 +02:00
hl-valdemar 77696e19c9 rename none to null 2026-07-22 00:49:05 +02:00
hl-valdemar 979a8e5f07 update stdlib memory and reflection helpers 2026-07-22 00:47:48 +02:00
9 changed files with 41 additions and 62 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ import "@std/io"
print func($format []u8, $Args type, args Args) void {
writer io.Writer :: io.Writer{
context = none,
context = null,
handle = io.Handle{ file_desc = c_int(io.Stream.stderr) },
write = write,
}
+2 -2
View File
@@ -12,7 +12,7 @@ EnumMap func($E, $V type) type {
init func(
$E, $V type,
values meta.EnumFieldStruct(E, ?V, some!(none)),
values meta.EnumFieldStruct(E, ?V, some!(null)),
) EnumMap(E, V) {
map EnumMap(E, V) = undefined
@@ -37,7 +37,7 @@ get func($E, $V type, map @EnumMap(E, V), key E) ?V {
.enum |info|: expand for info.fields |field, i| {
if key == field!(E, field.name) {
if (map.present[i]) return map.values[i]
return none
return null
}
}
else: compile_error!("EnumMap key must be an enum")
+1 -1
View File
@@ -21,5 +21,5 @@ handles_sparse_enum_get test {
eof :: get(&names, TestEnum.eof)
try testing.expect_type(?[]u8, eof)
try testing.expect_equal(none, eof)
try testing.expect_equal(null, eof)
}
+2 -2
View File
@@ -56,14 +56,14 @@ get func(
map @HashMap(K, V, hash_key, keys_eql),
key K,
) ?V {
if (map.count == 0) return none
if (map.count == 0) return null
hash :: normalize(hash_key(key))
idx usize = hash & (map.entries.len - 1)
while true {
entry :: map.entries[idx]
if (entry.hash == 0) return none
if (entry.hash == 0) return null
if (entry.hash == hash and keys_eql(entry.key, key)) {
return entry.value
+1 -1
View File
@@ -138,7 +138,7 @@ hide system_vtable IoVTable :: IoVTable {
hide system func() Io {
return Io {
context = none,
context = null,
vtable = &system_vtable,
}
}
+27 -49
View File
@@ -28,29 +28,20 @@ raw_free func(allocator Allocator, memory ?*mut u8, size usize, alignment usize)
}
eql func($T type, left, right []T) bool {
if left.len != right.len {
return false
}
i usize = 0
while i < left.len : i += 1 {
if left[i] != right[i] {
return false
}
if (left.len != right.len) return false
for (0..left.len) |i| if (left[i] != right[i]) {
return false
}
return true
}
# allocate memory for a slice of type `T` with `count` elements.
alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
if count == 0 {
return empty_slice(T, 0)
}
if (count == 0) return empty_slice(T, 0)
element_size usize :: sizeof!(T)
if element_size == 0 {
return empty_slice(T, count)
}
if (element_size == 0) return empty_slice(T, count)
if count > divtrunc!(maxval!(usize), element_size) {
return .out_of_memory
}
@@ -84,7 +75,7 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
return .out_of_memory
}
old_memory ?*mut u8 = none
old_memory ?*mut u8 = null
old_size usize = 0
if memory.len != 0 {
old_memory = ptrcast!(u8, memory.ptr)
@@ -107,10 +98,14 @@ realloc func($T type, allocator Allocator, memory []mut T, new_count usize) []mu
# free memory allocated for a slice of type `T`.
# note: memory must be freed with the same allocator that was used to allocate it.
free func($T type, allocator Allocator, memory []mut T) void {
if memory.len != 0 and sizeof!(T) != 0 {
raw_free(allocator, ptrcast!(u8, memory.ptr), memory.len * sizeof!(T), alignof!(T))
}
free func($T type, allocator Allocator, memory []T) void {
if (memory.len == 0 or sizeof!(T) == 0) return
raw_free(allocator, ptrcast!(
u8,
constcast!(memory).ptr),
memory.len * sizeof!(T),
alignof!(T),
)
}
# get an empty slice of type `T` with `count` elements.
@@ -129,48 +124,36 @@ hide empty_storage [1]mut u64 = [0]
hide malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
hide power_of_two func(value usize) bool {
if value == 0 {
return false
}
if (value == 0) return false
current usize = value
while current > 1 {
half usize = divtrunc!(current, 2)
if half * 2 != current {
return false
}
if (half * 2 != current) return false
current = half
}
return true
}
hide c_alloc func(_ ?@mut anyopaque, size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
if (power_of_two(alignment) == false) return null
if alignment <= malloc_alignment {
return ptrcast!(u8, c.malloc(c_ulong(size)))
}
memory [1]mut ?*mut anyopaque = [none]
memory [1]mut ?*mut anyopaque = [null]
status c_int = c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
if status != 0 {
return none
}
if (status != 0) return null
return ptrcast!(u8, memory[0])
}
hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
if power_of_two(alignment) == false {
return none
}
if (power_of_two(alignment) == false) return null
if new_size == 0 {
c.free(memory)
return none
return null
}
if memory |old_memory| {
@@ -178,22 +161,17 @@ hide c_realloc func(_ ?@mut anyopaque, memory ?*mut u8, old_size usize, new_size
return ptrcast!(u8, c.realloc(old_memory, c_ulong(new_size)))
}
new_memory ?*mut u8 = c_alloc(none, new_size, alignment)
new_memory ?*mut u8 = c_alloc(null, new_size, alignment)
if new_memory |new_bytes| {
copy_size usize = old_size
if new_size < copy_size {
copy_size = new_size
}
i usize = 0
while i < copy_size : i += 1 {
new_bytes[i] = old_memory[i]
}
if (new_size < copy_size) copy_size = new_size
memcopy!(new_bytes[..copy_size], old_memory[..copy_size])
c.free(old_memory)
}
return new_memory
}
return c_alloc(none, new_size, alignment)
return c_alloc(null, new_size, alignment)
}
hide c_free func(_ ?@mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
@@ -207,6 +185,6 @@ hide c_vtable AllocatorVTable :: AllocatorVTable {
}
c_allocator Allocator :: Allocator {
context = none,
context = null,
vtable = &c_vtable,
}
+4 -3
View File
@@ -23,6 +23,7 @@ EnumInfo :: struct {
TypeInfo :: union(enum) {
invalid void
void void
noreturn void
anyopaque void
bool void
integer void
@@ -43,9 +44,9 @@ TypeInfo :: union(enum) {
EnumFieldStruct func($E, $Field type, $default ?Field) type {
match typeinfo!(E) {
.enum |info|: {
names [field!(typeinfo!(E), "enum").fields.len]mut []u8 = undefined
field_types [field!(typeinfo!(E), "enum").fields.len]mut type = undefined
defaults [field!(typeinfo!(E), "enum").fields.len]mut ?Field = undefined
names [info.fields.len]mut []u8 = undefined
field_types [info.fields.len]mut type = undefined
defaults [info.fields.len]mut ?Field = undefined
expand for info.fields |field, index| {
names[index] = field.name
field_types[index] = Field
+1 -1
View File
@@ -6,7 +6,7 @@ TestTokenKind :: enum(u8) {
eof = 21
}
TestNames :: alias EnumFieldStruct(TestTokenKind, ?[]u8, some!(none))
TestNames :: alias EnumFieldStruct(TestTokenKind, ?[]u8, some!(null))
enum_field_struct_defaults test {
names TestNames = {
+2 -2
View File
@@ -26,11 +26,11 @@ expect_equal func($T type, expected, actual T, location SourceLocation) void ! E
try expect_equal(expected_value, actual_value, location)
return
}
debug.print("{s}:{d}:{d}: expected an optional value, found none\n", {location.file, location.line, location.column})
debug.print("{s}:{d}:{d}: expected an optional value, found null\n", {location.file, location.line, location.column})
return .expectation_failed
}
if actual |_| {
debug.print("{s}:{d}:{d}: expected none, found an optional value\n", {location.file, location.line, location.column})
debug.print("{s}:{d}:{d}: expected null, found an optional value\n", {location.file, location.line, location.column})
return .expectation_failed
}
}