This commit is contained in:
gingerBill
2025-06-09 17:19:58 +01:00
56 changed files with 1075 additions and 504 deletions
+1
View File
@@ -169,6 +169,7 @@ type_is_union :: proc($T: typeid) -> bool ---
type_is_enum :: proc($T: typeid) -> bool --- type_is_enum :: proc($T: typeid) -> bool ---
type_is_proc :: proc($T: typeid) -> bool --- type_is_proc :: proc($T: typeid) -> bool ---
type_is_bit_set :: proc($T: typeid) -> bool --- type_is_bit_set :: proc($T: typeid) -> bool ---
type_is_bit_field :: proc($T: typeid) -> bool ---
type_is_simd_vector :: proc($T: typeid) -> bool --- type_is_simd_vector :: proc($T: typeid) -> bool ---
type_is_matrix :: proc($T: typeid) -> bool --- type_is_matrix :: proc($T: typeid) -> bool ---
+9
View File
@@ -648,6 +648,9 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: i
@builtin @builtin
inject_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { inject_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
when !ODIN_NO_BOUNDS_CHECK {
ensure(index >= 0, "Index must be positive.", loc)
}
if array == nil { if array == nil {
return return
} }
@@ -666,6 +669,9 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcas
@builtin @builtin
inject_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { inject_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
when !ODIN_NO_BOUNDS_CHECK {
ensure(index >= 0, "Index must be positive.", loc)
}
if array == nil { if array == nil {
return return
} }
@@ -689,6 +695,9 @@ inject_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadca
@builtin @builtin
inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
when !ODIN_NO_BOUNDS_CHECK {
ensure(index >= 0, "Index must be positive.", loc)
}
if array == nil { if array == nil {
return return
} }
+74
View File
@@ -0,0 +1,74 @@
#+no-instrumentation
package sanitizer
@(private="file")
MSAN_ENABLED :: .Memory in ODIN_SANITIZER_FLAGS
@(private="file")
@(default_calling_convention="system")
foreign {
__msan_unpoison :: proc(addr: rawptr, size: uint) ---
}
/*
Marks a slice as fully initialized.
Code instrumented with `-sanitize:memory` will be permitted to access any
address within the slice as if it had already been initialized.
When msan is not enabled this procedure does nothing.
*/
memory_unpoison_slice :: proc "contextless" (region: $T/[]$E) {
when MSAN_ENABLED {
__msan_unpoison(raw_data(region), size_of(E) * len(region))
}
}
/*
Marks a pointer as fully initialized.
Code instrumented with `-sanitize:memory` will be permitted to access memory
within the region the pointer points to as if it had already been initialized.
When msan is not enabled this procedure does nothing.
*/
memory_unpoison_ptr :: proc "contextless" (ptr: ^$T) {
when MSAN_ENABLED {
__msan_unpoison(ptr, size_of(T))
}
}
/*
Marks the region covering `[ptr, ptr+len)` as fully initialized.
Code instrumented with `-sanitize:memory` will be permitted to access memory
within this range as if it had already been initialized.
When msan is not enabled this procedure does nothing.
*/
memory_unpoison_rawptr :: proc "contextless" (ptr: rawptr, len: int) {
when MSAN_ENABLED {
__msan_unpoison(ptr, uint(len))
}
}
/*
Marks the region covering `[ptr, ptr+len)` as fully initialized.
Code instrumented with `-sanitize:memory` will be permitted to access memory
within this range as if it had already been initialized.
When msan is not enabled this procedure does nothing.
*/
memory_unpoison_rawptr_uint :: proc "contextless" (ptr: rawptr, len: uint) {
when MSAN_ENABLED {
__msan_unpoison(ptr, len)
}
}
memory_unpoison :: proc {
memory_unpoison_slice,
memory_unpoison_ptr,
memory_unpoison_rawptr,
memory_unpoison_rawptr_uint,
}
+3 -3
View File
@@ -385,17 +385,17 @@ to_diagnostic_format_writer :: proc(w: io.Writer, val: Value, padding := 0) -> i
// which we want for the diagnostic format. // which we want for the diagnostic format.
case f16: case f16:
buf: [64]byte buf: [64]byte
str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16)) str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16))
if str[0] == '+' && str != "+Inf" { str = str[1:] } if str[0] == '+' && str != "+Inf" { str = str[1:] }
io.write_string(w, str) or_return io.write_string(w, str) or_return
case f32: case f32:
buf: [128]byte buf: [128]byte
str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32)) str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32))
if str[0] == '+' && str != "+Inf" { str = str[1:] } if str[0] == '+' && str != "+Inf" { str = str[1:] }
io.write_string(w, str) or_return io.write_string(w, str) or_return
case f64: case f64:
buf: [256]byte buf: [256]byte
str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64)) str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64))
if str[0] == '+' && str != "+Inf" { str = str[1:] } if str[0] == '+' && str != "+Inf" { str = str[1:] }
io.write_string(w, str) or_return io.write_string(w, str) or_return
+36
View File
@@ -612,6 +612,42 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er
case: case:
panic("unknown bit_size size") panic("unknown bit_size size")
} }
case runtime.Type_Info_Matrix:
count := info.column_count * info.elem_stride
err_conv(_encode_u64(e, u64(count), .Array)) or_return
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
for i in 0..<count {
data := uintptr(v.data) + uintptr(i*info.elem_size)
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
}
return
}
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
for i in 0..<count {
data := uintptr(v.data) + uintptr(i*info.elem_size)
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
}
return
case runtime.Type_Info_Simd_Vector:
err_conv(_encode_u64(e, u64(info.count), .Array)) or_return
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
for i in 0..<info.count {
data := uintptr(v.data) + uintptr(i*info.elem_size)
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
}
return
}
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
for i in 0..<info.count {
data := uintptr(v.data) + uintptr(i*info.elem_size)
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
}
return
} }
return _unsupported(v.id, nil) return _unsupported(v.id, nil)
+25
View File
@@ -591,6 +591,31 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
if out_of_space { return _unsupported(v, hdr) } if out_of_space { return _unsupported(v, hdr) }
return return
case reflect.Type_Info_Matrix:
count := t.column_count * t.elem_stride
length, _ := err_conv(_decode_len_container(d, add)) or_return
if length > count {
return _unsupported(v, hdr)
}
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator }
out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return
if out_of_space { return _unsupported(v, hdr) }
return
case reflect.Type_Info_Simd_Vector:
length, _ := err_conv(_decode_len_container(d, add)) or_return
if length > t.count {
return _unsupported(v, hdr)
}
da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator }
out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return
if out_of_space { return _unsupported(v, hdr) }
return
case: return _unsupported(v, hdr) case: return _unsupported(v, hdr)
} }
} }
+4 -4
View File
@@ -108,13 +108,13 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) { if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) {
switch i in a { switch i in a {
case u8, u16, u32, u64, u128: case u8, u16, u32, u64, u128:
s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) s = strconv.write_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix })
case: case:
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) s = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
} }
} else { } else {
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) s = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
} }
io.write_string(w, s) or_return io.write_string(w, s) or_return
@@ -286,7 +286,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
case runtime.Type_Info_Integer: case runtime.Type_Info_Integer:
buf: [40]byte buf: [40]byte
u := cast_any_int_to_u128(ka) u := cast_any_int_to_u128(ka)
name = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil) name = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil)
opt_write_key(w, opt, name) or_return opt_write_key(w, opt, name) or_return
case: return .Unsupported_Type case: return .Unsupported_Type
+2 -1
View File
@@ -175,7 +175,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha
data = bytes.clone(data) data = bytes.clone(data)
} }
t := &Tokenizer{} t := new(Tokenizer)
init(t, string(data), path, error_handler) init(t, string(data), path, error_handler)
doc = new(Document) doc = new(Document)
@@ -403,6 +403,7 @@ destroy :: proc(doc: ^Document) {
} }
delete(doc.strings_to_free) delete(doc.strings_to_free)
free(doc.tokenizer)
free(doc) free(doc)
} }
+4 -4
View File
@@ -1122,7 +1122,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
flags: strconv.Int_Flags flags: strconv.Int_Flags
if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} } if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} }
if fi.plus { flags += {.Plus} } if fi.plus { flags += {.Plus} }
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags) s := strconv.write_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
prev_zero := fi.zero prev_zero := fi.zero
defer fi.zero = prev_zero defer fi.zero = prev_zero
fi.zero = false fi.zero = false
@@ -1207,7 +1207,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
flags: strconv.Int_Flags flags: strconv.Int_Flags
if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} } if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} }
if fi.plus { flags += {.Plus} } if fi.plus { flags += {.Plus} }
s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags) s := strconv.write_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags)
if fi.hash && fi.zero && fi.indent == 0 { if fi.hash && fi.zero && fi.indent == 0 {
c: byte = 0 c: byte = 0
@@ -1272,7 +1272,7 @@ _fmt_memory :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, units: st
} }
buf: [256]byte buf: [256]byte
str := strconv.append_float(buf[:], amt, 'f', prec, 64) str := strconv.write_float(buf[:], amt, 'f', prec, 64)
// Add the unit at the end. // Add the unit at the end.
copy(buf[len(str):], units[off:off+unit_len]) copy(buf[len(str):], units[off:off+unit_len])
@@ -1424,7 +1424,7 @@ _fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: b
buf: [386]byte buf: [386]byte
// Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>". // Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>".
str := strconv.append_float(buf[:], v, float_fmt, prec, bit_size) str := strconv.write_float(buf[:], v, float_fmt, prec, bit_size)
if !fi.plus { if !fi.plus {
// Strip sign from "+<value>" but not "+Inf". // Strip sign from "+<value>" but not "+Inf".
+8 -8
View File
@@ -22,12 +22,12 @@ write_ptr_at :: proc(w: Writer_At, p: rawptr, byte_size: int, offset: i64, n_wri
write_u64 :: proc(w: Writer, i: u64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { write_u64 :: proc(w: Writer, i: u64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [32]byte buf: [32]byte
s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil) s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil)
return write_string(w, s, n_written) return write_string(w, s, n_written)
} }
write_i64 :: proc(w: Writer, i: i64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { write_i64 :: proc(w: Writer, i: i64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [32]byte buf: [32]byte
s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil)
return write_string(w, s, n_written) return write_string(w, s, n_written)
} }
@@ -40,18 +40,18 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> (
write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [39]byte buf: [39]byte
s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil) s := strconv.write_bits_128(buf[:], i, base, false, 128, strconv.digits, nil)
return write_string(w, s, n_written) return write_string(w, s, n_written)
} }
write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [40]byte buf: [40]byte
s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil) s := strconv.write_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil)
return write_string(w, s, n_written) return write_string(w, s, n_written)
} }
write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: Error) { write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [386]byte buf: [386]byte
str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) str := strconv.write_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val))
s := buf[:len(str)+1] s := buf[:len(str)+1]
if s[1] == '+' || s[1] == '-' { if s[1] == '+' || s[1] == '-' {
s = s[1:] s = s[1:]
@@ -67,7 +67,7 @@ write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: E
write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: Error) { write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [386]byte buf: [386]byte
str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) str := strconv.write_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val))
s := buf[:len(str)+1] s := buf[:len(str)+1]
if s[1] == '+' || s[1] == '-' { if s[1] == '+' || s[1] == '-' {
s = s[1:] s = s[1:]
@@ -83,7 +83,7 @@ write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: E
write_f64 :: proc(w: Writer, val: f64, n_written: ^int = nil) -> (n: int, err: Error) { write_f64 :: proc(w: Writer, val: f64, n_written: ^int = nil) -> (n: int, err: Error) {
buf: [386]byte buf: [386]byte
str := strconv.append_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val)) str := strconv.write_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val))
s := buf[:len(str)+1] s := buf[:len(str)+1]
if s[1] == '+' || s[1] == '-' { if s[1] == '+' || s[1] == '-' {
s = s[1:] s = s[1:]
@@ -130,7 +130,7 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^
write_string(w, `\x`, &n) or_return write_string(w, `\x`, &n) or_return
buf: [2]byte buf: [2]byte
s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil) s := strconv.write_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil)
switch len(s) { switch len(s) {
case 0: case 0:
write_string(w, "00", &n) or_return write_string(w, "00", &n) or_return
+1 -1
View File
@@ -1370,8 +1370,8 @@ _private_int_div_recursive :: proc(quotient, remainder, a, b: ^Int, allocator :=
/* /*
Slower bit-bang division... also smaller. Slower bit-bang division... also smaller.
Prefer `_int_div_school` for speed.
*/ */
@(deprecated="Use `_int_div_school`, it's 3.5x faster.")
_private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) { _private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) {
ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{} ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{}
+10 -5
View File
@@ -103,7 +103,7 @@ round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing {
} }
@(require_results) @(require_results)
append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { write :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
Integer_Width :: 8*size_of(Backing) - Fraction_Width Integer_Width :: 8*size_of(Backing) - Fraction_Width
x := x x := x
@@ -124,16 +124,16 @@ append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
when size_of(Backing) < 16 { when size_of(Backing) < 16 {
T :: u64 T :: u64
append_uint :: strconv.append_uint write_uint :: strconv.write_uint
} else { } else {
T :: u128 T :: u128
append_uint :: strconv.append_u128 write_uint :: strconv.write_u128
} }
integer := T(x.i) >> Fraction_Width integer := T(x.i) >> Fraction_Width
fraction := T(x.i) & (1<<Fraction_Width - 1) fraction := T(x.i) & (1<<Fraction_Width - 1)
s := append_uint(buf[i:], integer, 10) s := write_uint(buf[i:], integer, 10)
i += len(s) i += len(s)
if fraction != 0 { if fraction != 0 {
buf[i] = '.' buf[i] = '.'
@@ -155,7 +155,7 @@ append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
@(require_results) @(require_results)
to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string { to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string {
buf: [48]byte buf: [48]byte
s := append(buf[:], x) s := write(buf[:], x)
str := make([]byte, len(s), allocator) str := make([]byte, len(s), allocator)
copy(str, s) copy(str, s)
return string(str) return string(str)
@@ -294,3 +294,8 @@ _power_of_two_table := [129]string{
"85070591730234615865843651857942052864", "85070591730234615865843651857942052864",
"170141183460469231731687303715884105728", "170141183460469231731687303715884105728",
} }
@(deprecated="Use write instead")
append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string {
return write(dst, x)
}
+1 -1
View File
@@ -125,7 +125,7 @@ percent_encode :: proc(s: string, allocator := context.allocator) -> string {
bytes, n := utf8.encode_rune(ch) bytes, n := utf8.encode_rune(ch)
for byte in bytes[:n] { for byte in bytes[:n] {
buf: [2]u8 = --- buf: [2]u8 = ---
t := strconv.append_int(buf[:], i64(byte), 16) t := strconv.write_int(buf[:], i64(byte), 16)
strings.write_rune(&b, '%') strings.write_rune(&b, '%')
strings.write_string(&b, t) strings.write_string(&b, t)
} }
+1 -1
View File
@@ -57,7 +57,7 @@ write_encoded_rune :: proc(f: Handle, r: rune) -> (n: int, err: Error) {
if r < 32 { if r < 32 {
if wrap(write_string(f, "\\x"), &n, &err) { return } if wrap(write_string(f, "\\x"), &n, &err) { return }
b: [2]byte b: [2]byte
s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) s := strconv.write_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil)
switch len(s) { switch len(s) {
case 0: if wrap(write_string(f, "00"), &n, &err) { return } case 0: if wrap(write_string(f, "00"), &n, &err) { return }
case 1: if wrap(write_rune(f, '0'), &n, &err) { return } case 1: if wrap(write_rune(f, '0'), &n, &err) { return }
+19 -14
View File
@@ -27,6 +27,9 @@ General_Error :: enum u32 {
Pattern_Has_Separator, Pattern_Has_Separator,
No_HOME_Variable,
Wordexp_Failed,
Unsupported, Unsupported,
} }
@@ -59,20 +62,22 @@ error_string :: proc(ferr: Error) -> string {
case General_Error: case General_Error:
switch e { switch e {
case .None: return "" case .None: return ""
case .Permission_Denied: return "permission denied" case .Permission_Denied: return "permission denied"
case .Exist: return "file already exists" case .Exist: return "file already exists"
case .Not_Exist: return "file does not exist" case .Not_Exist: return "file does not exist"
case .Closed: return "file already closed" case .Closed: return "file already closed"
case .Timeout: return "i/o timeout" case .Timeout: return "i/o timeout"
case .Broken_Pipe: return "Broken pipe" case .Broken_Pipe: return "Broken pipe"
case .No_Size: return "file has no definite size" case .No_Size: return "file has no definite size"
case .Invalid_File: return "invalid file" case .Invalid_File: return "invalid file"
case .Invalid_Dir: return "invalid directory" case .Invalid_Dir: return "invalid directory"
case .Invalid_Path: return "invalid path" case .Invalid_Path: return "invalid path"
case .Invalid_Callback: return "invalid callback" case .Invalid_Callback: return "invalid callback"
case .Invalid_Command: return "invalid command" case .Invalid_Command: return "invalid command"
case .Unsupported: return "unsupported" case .Unsupported: return "unsupported"
case .Pattern_Has_Separator: return "pattern has separator" case .Pattern_Has_Separator: return "pattern has separator"
case .No_HOME_Variable: return "no $HOME variable"
case .Wordexp_Failed: return "posix.wordexp was unable to expand"
} }
case io.Error: case io.Error:
switch e { switch e {
+1
View File
@@ -269,6 +269,7 @@ _write_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (nt: i64, err: Error
return return
} }
@(no_sanitize_memory)
_file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) { _file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) {
// TODO: Identify 0-sized "pseudo" files and return No_Size. This would // TODO: Identify 0-sized "pseudo" files and return No_Size. This would
// eliminate the need for the _read_entire_pseudo_file procs. // eliminate the need for the _read_entire_pseudo_file procs.
+1 -1
View File
@@ -59,7 +59,7 @@ write_encoded_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) {
if r < 32 { if r < 32 {
if wrap(write_string(f, "\\x"), &n, &err) { return } if wrap(write_string(f, "\\x"), &n, &err) { return }
b: [2]byte b: [2]byte
s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) s := strconv.write_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil)
switch len(s) { switch len(s) {
case 0: if wrap(write_string(f, "00"), &n, &err) { return } case 0: if wrap(write_string(f, "00"), &n, &err) { return }
case 1: if wrap(write_rune(f, '0'), &n, &err) { return } case 1: if wrap(write_rune(f, '0'), &n, &err) { return }
+141 -71
View File
@@ -2,78 +2,148 @@ package os2
import "base:runtime" import "base:runtime"
@(require_results) // ```
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { // Windows: C:\Users\Alice
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) // macOS: /Users/Alice
// Linux: /home/alice
#partial switch ODIN_OS { // ```
case .Windows:
dir = get_env("LocalAppData", temp_allocator)
if dir != "" {
dir = clone_string(dir, temp_allocator) or_return
}
case .Darwin:
dir = get_env("HOME", temp_allocator)
if dir != "" {
dir = concatenate({dir, "/Library/Caches"}, temp_allocator) or_return
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" {
dir = get_env("HOME", temp_allocator)
if dir == "" {
return
}
dir = concatenate({dir, "/.cache"}, temp_allocator) or_return
}
}
if dir == "" {
err = .Invalid_Path
}
return
}
@(require_results)
user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
#partial switch ODIN_OS {
case .Windows:
dir = get_env("AppData", temp_allocator)
if dir != "" {
dir = clone_string(dir, allocator) or_return
}
case .Darwin:
dir = get_env("HOME", temp_allocator)
if dir != "" {
dir = concatenate({dir, "/.config"}, allocator) or_return
}
case: // All other UNIX systems
dir = get_env("XDG_CONFIG_HOME", allocator)
if dir == "" {
dir = get_env("HOME", temp_allocator)
if dir == "" {
return
}
dir = concatenate({dir, "/.config"}, allocator) or_return
}
}
if dir == "" {
err = .Invalid_Path
}
return
}
@(require_results) @(require_results)
user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
env := "HOME" return _user_home_dir(allocator)
#partial switch ODIN_OS {
case .Windows:
env = "USERPROFILE"
}
if v := get_env(env, allocator); v != "" {
return v, nil
}
return "", .Invalid_Path
} }
// Files that applications can regenerate/refetch at a loss of speed, e.g. shader caches
//
// Sometimes deleted for system maintenance
//
// ```
// Windows: C:\Users\Alice\AppData\Local
// macOS: /Users/Alice/Library/Caches
// Linux: /home/alice/.cache
// ```
@(require_results)
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_cache_dir(allocator)
}
// User-hidden application data
//
// ```
// Windows: C:\Users\Alice\AppData\Local ("C:\Users\Alice\AppData\Roaming" if `roaming`)
// macOS: /Users/Alice/Library/Application Support
// Linux: /home/alice/.local/share
// ```
//
// NOTE: (Windows only) `roaming` is for syncing across multiple devices within a *domain network*
@(require_results)
user_data_dir :: proc(allocator: runtime.Allocator, roaming := false) -> (dir: string, err: Error) {
return _user_data_dir(allocator, roaming)
}
// Non-essential application data, e.g. history, ui layout state
//
// ```
// Windows: C:\Users\Alice\AppData\Local
// macOS: /Users/Alice/Library/Application Support
// Linux: /home/alice/.local/state
// ```
@(require_results)
user_state_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_state_dir(allocator)
}
// Application log files
//
// ```
// Windows: C:\Users\Alice\AppData\Local
// macOS: /Users/Alice/Library/Logs
// Linux: /home/alice/.local/state
// ```
@(require_results)
user_log_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_log_dir(allocator)
}
// Application settings/preferences
//
// ```
// Windows: C:\Users\Alice\AppData\Local ("C:\Users\Alice\AppData\Roaming" if `roaming`)
// macOS: /Users/Alice/Library/Application Support
// Linux: /home/alice/.config
// ```
//
// NOTE: (Windows only) `roaming` is for syncing across multiple devices within a *domain network*
@(require_results)
user_config_dir :: proc(allocator: runtime.Allocator, roaming := false) -> (dir: string, err: Error) {
return _user_config_dir(allocator, roaming)
}
// ```
// Windows: C:\Users\Alice\Music
// macOS: /Users/Alice/Music
// Linux: /home/alice/Music
// ```
@(require_results)
user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_music_dir(allocator)
}
// ```
// Windows: C:\Users\Alice\Desktop
// macOS: /Users/Alice/Desktop
// Linux: /home/alice/Desktop
// ```
@(require_results)
user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_desktop_dir(allocator)
}
// ```
// Windows: C:\Users\Alice\Documents
// macOS: /Users/Alice/Documents
// Linux: /home/alice/Documents
// ```
@(require_results)
user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_documents_dir(allocator)
}
// ```
// Windows: C:\Users\Alice\Downloads
// macOS: /Users/Alice/Downloads
// Linux: /home/alice/Downloads
// ```
@(require_results)
user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_downloads_dir(allocator)
}
// ```
// Windows: C:\Users\Alice\Pictures
// macOS: /Users/Alice/Pictures
// Linux: /home/alice/Pictures
// ```
@(require_results)
user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_pictures_dir(allocator)
}
// ```
// Windows: C:\Users\Alice\Public
// macOS: /Users/Alice/Public
// Linux: /home/alice/Public
// ```
@(require_results)
user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_public_dir(allocator)
}
// ```
// Windows: C:\Users\Alice\Videos
// macOS: /Users/Alice/Movies
// Linux: /home/alice/Videos
// ```
@(require_results)
user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
return _user_videos_dir(allocator)
}
+183
View File
@@ -0,0 +1,183 @@
#+build !windows
package os2
import "base:runtime"
import "core:encoding/ini"
import "core:strings"
import "core:sys/posix"
_user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Library/Caches", allocator)
case: // Unix
return _xdg_lookup("XDG_CACHE_HOME", "/.cache", allocator)
}
}
_user_config_dir :: proc(allocator: runtime.Allocator, _roaming: bool) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Library/Application Support", allocator)
case: // Unix
return _xdg_lookup("XDG_CONFIG_HOME", "/.config", allocator)
}
}
_user_state_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Library/Application Support", allocator)
case: // Unix
return _xdg_lookup("XDG_STATE_HOME", "/.local/state", allocator)
}
}
_user_log_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Library/Logs", allocator)
case: // Unix
return _xdg_lookup("XDG_STATE_HOME", "/.local/state", allocator)
}
}
_user_data_dir :: proc(allocator: runtime.Allocator, _roaming: bool) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Library/Application Support", allocator)
case: // Unix
return _xdg_lookup("XDG_DATA_HOME", "/.local/share", allocator)
}
}
_user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Music", allocator)
case: // Unix
return _xdg_lookup("XDG_MUSIC_DIR", "/Music", allocator)
}
}
_user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Desktop", allocator)
case: // Unix
return _xdg_lookup("XDG_DESKTOP_DIR", "/Desktop", allocator)
}
}
_user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Documents", allocator)
case: // Unix
return _xdg_lookup("XDG_DOCUMENTS_DIR", "/Documents", allocator)
}
}
_user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Downloads", allocator)
case: // Unix
return _xdg_lookup("XDG_DOWNLOAD_DIR", "/Downloads", allocator)
}
}
_user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Pictures", allocator)
case: // Unix
return _xdg_lookup("XDG_PICTURES_DIR", "/Pictures", allocator)
}
}
_user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Public", allocator)
case: // Unix
return _xdg_lookup("XDG_PUBLICSHARE_DIR", "/Public", allocator)
}
}
_user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Darwin:
return _xdg_lookup("", "/Movies", allocator)
case: // Unix
return _xdg_lookup("XDG_VIDEOS_DIR", "/Videos", allocator)
}
}
_user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
if v := get_env("HOME", allocator); v != "" {
return v, nil
}
err = .No_HOME_Variable
return
}
_xdg_lookup :: proc(xdg_key: string, fallback_suffix: string, allocator: runtime.Allocator) -> (dir: string, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
if xdg_key == "" { // Darwin doesn't have XDG paths.
dir = get_env("HOME", temp_allocator)
if dir == "" {
err = .No_HOME_Variable
return
}
return concatenate({dir, fallback_suffix}, allocator)
} else {
if strings.ends_with(xdg_key, "_DIR") {
dir = _xdg_user_dirs_lookup(xdg_key, allocator) or_return
} else {
dir = get_env(xdg_key, allocator)
}
if dir == "" {
dir = get_env("HOME", temp_allocator)
if dir == "" {
err = .No_HOME_Variable
return
}
dir = concatenate({dir, fallback_suffix}, allocator) or_return
}
return
}
}
// If `<config-dir>/user-dirs.dirs` doesn't exist, or `xdg_key` can't be found there: returns `""`
_xdg_user_dirs_lookup :: proc(xdg_key: string, allocator: runtime.Allocator) -> (dir: string, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
config_dir := user_config_dir(temp_allocator) or_return
user_dirs_path := concatenate({config_dir, "/user-dirs.dirs"}, temp_allocator) or_return
content := read_entire_file(user_dirs_path, temp_allocator) or_return
it := ini.Iterator{
section = "",
_src = string(content),
options = ini.Options{
comment = "#",
key_lower_case = false,
},
}
for k, v in ini.iterate(&it) {
if k == xdg_key {
we: posix.wordexp_t
defer posix.wordfree(&we)
if _err := posix.wordexp(strings.clone_to_cstring(v, temp_allocator), &we, nil); _err != nil || we.we_wordc != 1 {
return "", .Wordexp_Failed
}
return strings.clone_from_cstring(we.we_wordv[0], allocator)
}
}
return
}
+79
View File
@@ -0,0 +1,79 @@
package os2
import "base:runtime"
@(require) import win32 "core:sys/windows"
_local_appdata :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_LocalAppData
return _get_known_folder_path(&guid, allocator)
}
_local_appdata_or_roaming :: proc(allocator: runtime.Allocator, roaming: bool) -> (dir: string, err: Error) {
guid := win32.FOLDERID_LocalAppData
if roaming {
guid = win32.FOLDERID_RoamingAppData
}
return _get_known_folder_path(&guid, allocator)
}
_user_config_dir :: _local_appdata_or_roaming
_user_data_dir :: _local_appdata_or_roaming
_user_state_dir :: _local_appdata
_user_log_dir :: _local_appdata
_user_cache_dir :: _local_appdata
_user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_Profile
return _get_known_folder_path(&guid, allocator)
}
_user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_Music
return _get_known_folder_path(&guid, allocator)
}
_user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_Desktop
return _get_known_folder_path(&guid, allocator)
}
_user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_Documents
return _get_known_folder_path(&guid, allocator)
}
_user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_Downloads
return _get_known_folder_path(&guid, allocator)
}
_user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_Pictures
return _get_known_folder_path(&guid, allocator)
}
_user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_Public
return _get_known_folder_path(&guid, allocator)
}
_user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
guid := win32.FOLDERID_Videos
return _get_known_folder_path(&guid, allocator)
}
_get_known_folder_path :: proc(rfid: win32.REFKNOWNFOLDERID, allocator: runtime.Allocator) -> (dir: string, err: Error) {
// https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
// See also `known_folders.odin` in `core:sys/windows` for the GUIDs.
path_w: win32.LPWSTR
res := win32.SHGetKnownFolderPath(rfid, 0, nil, &path_w)
defer win32.CoTaskMemFree(path_w)
if res != 0 {
return "", .Invalid_Path
}
dir, _ = win32.wstring_to_utf8(path_w, -1, allocator)
return
}
+3 -3
View File
@@ -662,7 +662,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Error) {
return File_Time(modified), nil return File_Time(modified), nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) { _stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -674,7 +674,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) { _lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -688,7 +688,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
s: OS_Stat = --- s: OS_Stat = ---
result := _unix_fstat(fd, &s) result := _unix_fstat(fd, &s)
+3 -3
View File
@@ -325,7 +325,7 @@ _alloc_command_line_arguments :: proc() -> []string {
return res return res
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) { _stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -339,7 +339,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) { _lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -353,7 +353,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
// deliberately uninitialized // deliberately uninitialized
s: OS_Stat = --- s: OS_Stat = ---
+4 -4
View File
@@ -674,7 +674,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) {
return i64(res), nil return i64(res), nil
} }
@(require_results) @(require_results, no_sanitize_memory)
file_size :: proc(fd: Handle) -> (i64, Error) { file_size :: proc(fd: Handle) -> (i64, Error) {
// deliberately uninitialized; the syscall fills this buffer for us // deliberately uninitialized; the syscall fills this buffer for us
s: OS_Stat = --- s: OS_Stat = ---
@@ -794,7 +794,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) {
return File_Time(modified), nil return File_Time(modified), nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) { _stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -808,7 +808,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) { _lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -822,7 +822,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
// deliberately uninitialized; the syscall fills this buffer for us // deliberately uninitialized; the syscall fills this buffer for us
s: OS_Stat = --- s: OS_Stat = ---
+3 -3
View File
@@ -724,7 +724,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) {
return File_Time(modified), nil return File_Time(modified), nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) { _stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -736,7 +736,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) { _lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -750,7 +750,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
s: OS_Stat = --- s: OS_Stat = ---
result := _unix_fstat(fd, &s) result := _unix_fstat(fd, &s)
+3 -3
View File
@@ -639,7 +639,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) {
return File_Time(modified), nil return File_Time(modified), nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_stat :: proc(path: string) -> (OS_Stat, Error) { _stat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -653,7 +653,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_lstat :: proc(path: string) -> (OS_Stat, Error) { _lstat :: proc(path: string) -> (OS_Stat, Error) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator) cstr := strings.clone_to_cstring(path, context.temp_allocator)
@@ -667,7 +667,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) {
return s, nil return s, nil
} }
@(private, require_results) @(private, require_results, no_sanitize_memory)
_fstat :: proc(fd: Handle) -> (OS_Stat, Error) { _fstat :: proc(fd: Handle) -> (OS_Stat, Error) {
// deliberately uninitialized // deliberately uninitialized
s: OS_Stat = --- s: OS_Stat = ---
-46
View File
@@ -30,14 +30,6 @@ sort :: proc(it: Interface) {
_quick_sort(it, 0, n, max_depth(n)) _quick_sort(it, 0, n, max_depth(n))
} }
@(deprecated="use slice.sort")
slice :: proc(array: $T/[]$E) where ORD(E) {
_slice.sort(array)
// s := array;
// sort(slice_interface(&s));
}
slice_interface :: proc(s: ^$T/[]$E) -> Interface where ORD(E) { slice_interface :: proc(s: ^$T/[]$E) -> Interface where ORD(E) {
return Interface{ return Interface{
collection = rawptr(s), collection = rawptr(s),
@@ -80,31 +72,6 @@ reverse_sort :: proc(it: Interface) {
sort(reverse_interface(&it)) sort(reverse_interface(&it))
} }
@(deprecated="use slice.reverse")
reverse_slice :: proc(array: $T/[]$E) where ORD(E) {
_slice.reverse(array)
/*
s := array;
sort(Interface{
collection = rawptr(&s),
len = proc(it: Interface) -> int {
s := (^T)(it.collection);
return len(s^);
},
less = proc(it: Interface, i, j: int) -> bool {
s := (^T)(it.collection);
return s[j] < s[i]; // manual set up
},
swap = proc(it: Interface, i, j: int) {
s := (^T)(it.collection);
s[i], s[j] = s[j], s[i];
},
});
*/
}
is_sorted :: proc(it: Interface) -> bool { is_sorted :: proc(it: Interface) -> bool {
n := it->len() n := it->len()
for i := n-1; i > 0; i -= 1 { for i := n-1; i > 0; i -= 1 {
@@ -294,11 +261,6 @@ _insertion_sort :: proc(it: Interface, a, b: int) {
} }
} }
// @(deprecated="use sort.sort or slice.sort_by")
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil) assert(f != nil)
count := len(array) count := len(array)
@@ -327,7 +289,6 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
} }
} }
// @(deprecated="use sort.sort_slice or slice.sort")
bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
count := len(array) count := len(array)
@@ -355,7 +316,6 @@ bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
} }
} }
// @(deprecated="use sort.sort or slice.sort_by")
quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
assert(f != nil) assert(f != nil)
a := array a := array
@@ -384,7 +344,6 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
quick_sort_proc(a[i:n], f) quick_sort_proc(a[i:n], f)
} }
// @(deprecated="use sort.sort_slice or slice.sort")
quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
a := array a := array
n := len(a) n := len(a)
@@ -420,7 +379,6 @@ _log2 :: proc(x: int) -> int {
return res return res
} }
// @(deprecated="use sort.sort or slice.sort_by")
merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
merge :: proc(a: A, start, mid, end: int, f: proc(T, T) -> int) { merge :: proc(a: A, start, mid, end: int, f: proc(T, T) -> int) {
s, m := start, mid s, m := start, mid
@@ -462,7 +420,6 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
internal_sort(array, 0, len(array)-1, f) internal_sort(array, 0, len(array)-1, f)
} }
// @(deprecated="use sort.sort_slice or slice.sort")
merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
merge :: proc(a: A, start, mid, end: int) { merge :: proc(a: A, start, mid, end: int) {
s, m := start, mid s, m := start, mid
@@ -504,8 +461,6 @@ merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
internal_sort(array, 0, len(array)-1) internal_sort(array, 0, len(array)-1)
} }
// @(deprecated="use sort.sort or slice.sort_by")
heap_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { heap_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
sift_proc :: proc(a: A, pi: int, n: int, f: proc(T, T) -> int) #no_bounds_check { sift_proc :: proc(a: A, pi: int, n: int, f: proc(T, T) -> int) #no_bounds_check {
p := pi p := pi
@@ -540,7 +495,6 @@ heap_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
} }
} }
// @(deprecated="use sort.sort_slice or slice.sort")
heap_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { heap_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) {
sift :: proc(a: A, pi: int, n: int) #no_bounds_check { sift :: proc(a: A, pi: int, n: int) #no_bounds_check {
p := pi p := pi
+15 -15
View File
@@ -12,11 +12,11 @@ Decimal :: struct {
Sets a Decimal from a given string `s`. The string is expected to represent a float. Stores parsed number in the given Decimal structure. Sets a Decimal from a given string `s`. The string is expected to represent a float. Stores parsed number in the given Decimal structure.
If parsing fails, the Decimal will be left in an undefined state. If parsing fails, the Decimal will be left in an undefined state.
**Inputs** **Inputs**
- d: Pointer to a Decimal struct where the parsed result will be stored - d: Pointer to a Decimal struct where the parsed result will be stored
- s: The input string representing the floating-point number - s: The input string representing the floating-point number
**Returns** **Returns**
- ok: A boolean indicating whether the parsing was successful - ok: A boolean indicating whether the parsing was successful
*/ */
set :: proc(d: ^Decimal, s: string) -> (ok: bool) { set :: proc(d: ^Decimal, s: string) -> (ok: bool) {
@@ -104,11 +104,11 @@ set :: proc(d: ^Decimal, s: string) -> (ok: bool) {
/* /*
Converts a Decimal to a string representation, using the provided buffer as storage. Converts a Decimal to a string representation, using the provided buffer as storage.
**Inputs** **Inputs**
- buf: A byte slice buffer to hold the resulting string - buf: A byte slice buffer to hold the resulting string
- a: The struct to be converted to a string - a: The struct to be converted to a string
**Returns** **Returns**
- A string representation of the Decimal - A string representation of the Decimal
*/ */
decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string { decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
@@ -150,7 +150,7 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
/* /*
Trims trailing zeros in the given Decimal, updating the count and decimal_point values as needed. Trims trailing zeros in the given Decimal, updating the count and decimal_point values as needed.
**Inputs** **Inputs**
- a: Pointer to the Decimal struct to be trimmed - a: Pointer to the Decimal struct to be trimmed
*/ */
trim :: proc(a: ^Decimal) { trim :: proc(a: ^Decimal) {
@@ -166,7 +166,7 @@ Converts a given u64 integer `idx` to its Decimal representation in the provided
**Used for internal Decimal Operations.** **Used for internal Decimal Operations.**
**Inputs** **Inputs**
- a: Where the result will be stored - a: Where the result will be stored
- idx: The value to be assigned to the Decimal - idx: The value to be assigned to the Decimal
*/ */
@@ -190,11 +190,11 @@ assign :: proc(a: ^Decimal, idx: u64) {
trim(a) trim(a)
} }
/* /*
Shifts the Decimal value to the right by k positions. Shifts the Decimal value to the right by k positions.
**Used for internal Decimal Operations.** **Used for internal Decimal Operations.**
**Inputs** **Inputs**
- a: The Decimal struct to be shifted - a: The Decimal struct to be shifted
- k: The number of positions to shift right - k: The number of positions to shift right
*/ */
@@ -344,7 +344,7 @@ Shifts the decimal of the input value to the left by `k` places
WARNING: asserts `k < 61` WARNING: asserts `k < 61`
**Inputs** **Inputs**
- a: The Decimal to be modified - a: The Decimal to be modified
- k: The number of places to shift the decimal to the left - k: The number of places to shift the decimal to the left
*/ */
@@ -405,7 +405,7 @@ shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check {
/* /*
Shifts the decimal of the input value by the specified number of places Shifts the decimal of the input value by the specified number of places
**Inputs** **Inputs**
- a: The Decimal to be modified - a: The Decimal to be modified
- i: The number of places to shift the decimal (positive for left shift, negative for right shift) - i: The number of places to shift the decimal (positive for left shift, negative for right shift)
*/ */
@@ -435,7 +435,7 @@ shift :: proc(a: ^Decimal, i: int) {
/* /*
Determines if the Decimal can be rounded up at the given digit index Determines if the Decimal can be rounded up at the given digit index
**Inputs** **Inputs**
- a: The Decimal to check - a: The Decimal to check
- nd: The digit index to consider for rounding up - nd: The digit index to consider for rounding up
@@ -455,7 +455,7 @@ can_round_up :: proc(a: ^Decimal, nd: int) -> bool {
/* /*
Rounds the Decimal at the given digit index Rounds the Decimal at the given digit index
**Inputs** **Inputs**
- a: The Decimal to be modified - a: The Decimal to be modified
- nd: The digit index to round - nd: The digit index to round
*/ */
@@ -470,7 +470,7 @@ round :: proc(a: ^Decimal, nd: int) {
/* /*
Rounds the Decimal up at the given digit index Rounds the Decimal up at the given digit index
**Inputs** **Inputs**
- a: The Decimal to be modified - a: The Decimal to be modified
- nd: The digit index to round up - nd: The digit index to round up
*/ */
@@ -493,7 +493,7 @@ round_up :: proc(a: ^Decimal, nd: int) {
/* /*
Rounds down the decimal value to the specified number of decimal places Rounds down the decimal value to the specified number of decimal places
**Inputs** **Inputs**
- a: The Decimal value to be rounded down - a: The Decimal value to be rounded down
- nd: The number of decimal places to round down to - nd: The number of decimal places to round down to
@@ -522,7 +522,7 @@ round_down :: proc(a: ^Decimal, nd: int) {
/* /*
Extracts the rounded integer part of a decimal value Extracts the rounded integer part of a decimal value
**Inputs** **Inputs**
- a: A pointer to the Decimal value to extract the rounded integer part from - a: A pointer to the Decimal value to extract the rounded integer part from
WARNING: There are no guarantees about overflow. WARNING: There are no guarantees about overflow.
+38
View File
@@ -0,0 +1,38 @@
package strconv
// (2025-06-05) These procedures are to be removed at a later release.
@(deprecated="Use write_bits instead")
append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
return write_bits(buf, x, base, is_signed, bit_size, digits, flags)
}
@(deprecated="Use write_bits_128 instead")
append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
return write_bits_128(buf, x, base, is_signed, bit_size, digits, flags)
}
@(deprecated="Use write_bool instead")
append_bool :: proc(buf: []byte, b: bool) -> string {
return write_bool(buf, b)
}
@(deprecated="Use write_uint instead")
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
return write_uint(buf, u, base)
}
@(deprecated="Use write_int instead")
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
return write_int(buf, i, base)
}
@(deprecated="Use write_u128 instead")
append_u128 :: proc(buf: []byte, u: u128, base: int) -> string {
return write_u128(buf, u, base)
}
@(deprecated="Use write_float instead")
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
return write_float(buf, f, fmt, prec, bit_size)
}
+7 -7
View File
@@ -23,7 +23,7 @@ _f64_info := Float_Info{52, 11, -1023}
/* /*
Converts a floating-point number to a string with the specified format and precision. Converts a floating-point number to a string with the specified format and precision.
**Inputs** **Inputs**
buf: A byte slice to store the resulting string buf: A byte slice to store the resulting string
val: The floating-point value to be converted val: The floating-point value to be converted
@@ -40,7 +40,7 @@ Example:
bit_size := 64 bit_size := 64
result := strconv.generic_ftoa(buf[:], val, fmt, precision, bit_size) -> "3.14" result := strconv.generic_ftoa(buf[:], val, fmt, precision, bit_size) -> "3.14"
**Returns** **Returns**
- A byte slice containing the formatted string - A byte slice containing the formatted string
*/ */
generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte { generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte {
@@ -122,7 +122,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int)
/* /*
Converts a decimal floating-point number into a byte buffer with the given format Converts a decimal floating-point number into a byte buffer with the given format
**Inputs** **Inputs**
- buf: The byte buffer to store the formatted number - buf: The byte buffer to store the formatted number
- shortest: If true, generates the shortest representation of the number - shortest: If true, generates the shortest representation of the number
- neg: If true, the number is negative - neg: If true, the number is negative
@@ -130,7 +130,7 @@ Converts a decimal floating-point number into a byte buffer with the given forma
- precision: The number of digits after the decimal point - precision: The number of digits after the decimal point
- fmt: The format specifier (accepted values: 'f', 'F', 'e', 'E', 'g', 'G') - fmt: The format specifier (accepted values: 'f', 'F', 'e', 'E', 'g', 'G')
**Returns** **Returns**
- A byte slice containing the formatted decimal floating-point number - A byte slice containing the formatted decimal floating-point number
*/ */
format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, precision: int, fmt: byte) -> []byte { format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, precision: int, fmt: byte) -> []byte {
@@ -256,7 +256,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic
/* /*
Rounds the given decimal number to its shortest representation, considering the provided floating-point format Rounds the given decimal number to its shortest representation, considering the provided floating-point format
**Inputs** **Inputs**
- d: The decimal number to round - d: The decimal number to round
- mant: The mantissa of the floating-point number - mant: The mantissa of the floating-point number
- exp: The exponent of the floating-point number - exp: The exponent of the floating-point number
@@ -331,11 +331,11 @@ round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Inf
/* /*
Converts a decimal number to its floating-point representation with the given format and returns the resulting bits Converts a decimal number to its floating-point representation with the given format and returns the resulting bits
**Inputs** **Inputs**
- d: Pointer to the decimal number to convert - d: Pointer to the decimal number to convert
- info: Pointer to the Float_Info structure containing information about the floating-point format - info: Pointer to the Float_Info structure containing information about the floating-point format
**Returns** **Returns**
- b: The bits representing the floating-point number - b: The bits representing the floating-point number
- overflow: A boolean indicating whether an overflow occurred during conversion - overflow: A boolean indicating whether an overflow occurred during conversion
*/ */
+15 -15
View File
@@ -12,12 +12,12 @@ digits := "0123456789abcdefghijklmnopqrstuvwxyz"
/* /*
Determines whether the given unsigned 64-bit integer is a negative value by interpreting it as a signed integer with the specified bit size. Determines whether the given unsigned 64-bit integer is a negative value by interpreting it as a signed integer with the specified bit size.
**Inputs** **Inputs**
- x: The unsigned 64-bit integer to check for negativity - x: The unsigned 64-bit integer to check for negativity
- is_signed: A boolean indicating if the input should be treated as a signed integer - is_signed: A boolean indicating if the input should be treated as a signed integer
- bit_size: The bit size of the signed integer representation (8, 16, 32, or 64) - bit_size: The bit size of the signed integer representation (8, 16, 32, or 64)
**Returns** **Returns**
- u: The absolute value of the input integer - u: The absolute value of the input integer
- neg: A boolean indicating whether the input integer is negative - neg: A boolean indicating whether the input integer is negative
*/ */
@@ -48,9 +48,9 @@ is_integer_negative :: proc(x: u64, is_signed: bool, bit_size: int) -> (u: u64,
return return
} }
/* /*
Appends the string representation of an integer to a buffer with specified base, flags, and digit set. Writes the string representation of an integer to a buffer with specified base, flags, and digit set.
**Inputs** **Inputs**
- buf: The buffer to append the integer representation to - buf: The buffer to append the integer representation to
- x: The integer value to convert - x: The integer value to convert
- base: The base for the integer representation (2 <= base <= MAX_BASE) - base: The base for the integer representation (2 <= base <= MAX_BASE)
@@ -59,12 +59,12 @@ Appends the string representation of an integer to a buffer with specified base,
- digits: The digit set used for the integer representation - digits: The digit set used for the integer representation
- flags: The Int_Flags bit set to control integer formatting - flags: The Int_Flags bit set to control integer formatting
**Returns** **Returns**
- The string containing the integer representation appended to the buffer - The string containing the integer representation appended to the buffer
*/ */
append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { write_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
if base < 2 || base > MAX_BASE { if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits") panic("strconv: illegal base passed to write_bits")
} }
a: [129]byte a: [129]byte
@@ -106,12 +106,12 @@ append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: i
/* /*
Determines whether the given unsigned 128-bit integer is a negative value by interpreting it as a signed integer with the specified bit size. Determines whether the given unsigned 128-bit integer is a negative value by interpreting it as a signed integer with the specified bit size.
**Inputs** **Inputs**
- x: The unsigned 128-bit integer to check for negativity - x: The unsigned 128-bit integer to check for negativity
- is_signed: A boolean indicating if the input should be treated as a signed integer - is_signed: A boolean indicating if the input should be treated as a signed integer
- bit_size: The bit size of the signed integer representation (8, 16, 32, 64, or 128) - bit_size: The bit size of the signed integer representation (8, 16, 32, 64, or 128)
**Returns** **Returns**
- u: The absolute value of the input integer - u: The absolute value of the input integer
- neg: A boolean indicating whether the input integer is negative - neg: A boolean indicating whether the input integer is negative
*/ */
@@ -146,9 +146,9 @@ is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u:
return return
} }
/* /*
Appends the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set. Writes the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set.
**Inputs** **Inputs**
- buf: The buffer to append the integer representation to - buf: The buffer to append the integer representation to
- x: The 128-bit integer value to convert - x: The 128-bit integer value to convert
- base: The base for the integer representation (2 <= base <= MAX_BASE) - base: The base for the integer representation (2 <= base <= MAX_BASE)
@@ -157,12 +157,12 @@ Appends the string representation of a 128-bit integer to a buffer with specifie
- digits: The digit set used for the integer representation - digits: The digit set used for the integer representation
- flags: The Int_Flags bit set to control integer formatting - flags: The Int_Flags bit set to control integer formatting
**Returns** **Returns**
- The string containing the integer representation appended to the buffer - The string containing the integer representation written to the buffer
*/ */
append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { write_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
if base < 2 || base > MAX_BASE { if base < 2 || base > MAX_BASE {
panic("strconv: illegal base passed to append_bits") panic("strconv: illegal base passed to write_bits")
} }
a: [140]byte a: [140]byte
+138 -138
View File
@@ -5,8 +5,8 @@ import "decimal"
/* /*
Parses a boolean value from the input string Parses a boolean value from the input string
**Inputs** **Inputs**
- s: The input string - s: The input string
- true: "1", "t", "T", "true", "TRUE", "True" - true: "1", "t", "T", "true", "TRUE", "True"
- false: "0", "f", "F", "false", "FALSE", "False" - false: "0", "f", "F", "false", "FALSE", "False"
- n: An optional pointer to an int to store the length of the parsed substring (default: nil) - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
@@ -386,7 +386,7 @@ Parses an unsigned integer value from the input string, using the specified base
- If base is not 0, it will be used for parsing regardless of any prefix in the input string - If base is not 0, it will be used for parsing regardless of any prefix in the input string
Example: Example:
import "core:fmt" import "core:fmt"
import "core:strconv" import "core:strconv"
parse_uint_example :: proc() { parse_uint_example :: proc() {
@@ -399,14 +399,14 @@ Example:
n, ok = strconv.parse_uint("0xffff") // with prefix and inferred base n, ok = strconv.parse_uint("0xffff") // with prefix and inferred base
fmt.println(n,ok) fmt.println(n,ok)
} }
Output: Output:
1234 true 1234 true
65535 true 65535 true
65535 true 65535 true
**Returns** **Returns**
value: The parsed uint value value: The parsed uint value
ok: `false` if no appropriate value could be found; the value was negative; he input string contained more than just the number ok: `false` if no appropriate value could be found; the value was negative; he input string contained more than just the number
@@ -423,7 +423,7 @@ parse_uint :: proc(s: string, base := 0, n: ^int = nil) -> (value: uint, ok: boo
/* /*
Parses an integer value from a string in the given base, without any prefix Parses an integer value from a string in the given base, without any prefix
**Inputs** **Inputs**
- str: The input string containing the integer value - str: The input string containing the integer value
- base: The base (radix) to use for parsing the integer (1-16) - base: The base (radix) to use for parsing the integer (1-16)
- n: An optional pointer to an int to store the length of the parsed substring (default: nil) - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
@@ -436,12 +436,12 @@ Example:
n, ok := strconv.parse_i128_of_base("-1234eeee", 10) n, ok := strconv.parse_i128_of_base("-1234eeee", 10)
fmt.println(n,ok) fmt.println(n,ok)
} }
Output: Output:
-1234 false -1234 false
**Returns** **Returns**
- value: The parsed i128 value - value: The parsed i128 value
- ok: false if no numeric value of the appropriate base could be found, or if the input string contained more than just the number. - ok: false if no numeric value of the appropriate base could be found, or if the input string contained more than just the number.
*/ */
@@ -491,7 +491,7 @@ parse_i128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i12
/* /*
Parses an integer value from a string in base 10, unless there's a prefix Parses an integer value from a string in base 10, unless there's a prefix
**Inputs** **Inputs**
- str: The input string containing the integer value - str: The input string containing the integer value
- n: An optional pointer to an int to store the length of the parsed substring (default: nil) - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
@@ -506,13 +506,13 @@ Example:
n, ok = strconv.parse_i128_maybe_prefixed("0xeeee") n, ok = strconv.parse_i128_maybe_prefixed("0xeeee")
fmt.println(n, ok) fmt.println(n, ok)
} }
Output: Output:
1234 true 1234 true
61166 true 61166 true
**Returns** **Returns**
- value: The parsed i128 value - value: The parsed i128 value
- ok: `false` if a valid integer could not be found, or if the input string contained more than just the number. - ok: `false` if a valid integer could not be found, or if the input string contained more than just the number.
*/ */
@@ -574,7 +574,7 @@ parse_i128 :: proc{parse_i128_maybe_prefixed, parse_i128_of_base}
/* /*
Parses an unsigned integer value from a string in the given base, without any prefix Parses an unsigned integer value from a string in the given base, without any prefix
**Inputs** **Inputs**
- str: The input string containing the integer value - str: The input string containing the integer value
- base: The base (radix) to use for parsing the integer (1-16) - base: The base (radix) to use for parsing the integer (1-16)
- n: An optional pointer to an int to store the length of the parsed substring (default: nil) - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
@@ -590,13 +590,13 @@ Example:
n, ok = strconv.parse_u128_of_base("5678eeee", 16) n, ok = strconv.parse_u128_of_base("5678eeee", 16)
fmt.println(n, ok) fmt.println(n, ok)
} }
Output: Output:
1234 false 1234 false
1450766062 true 1450766062 true
**Returns** **Returns**
- value: The parsed u128 value - value: The parsed u128 value
- ok: `false` if no numeric value of the appropriate base could be found, or if the input string contained more than just the number. - ok: `false` if no numeric value of the appropriate base could be found, or if the input string contained more than just the number.
*/ */
@@ -634,7 +634,7 @@ parse_u128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u12
/* /*
Parses an unsigned integer value from a string in base 10, unless there's a prefix Parses an unsigned integer value from a string in base 10, unless there's a prefix
**Inputs** **Inputs**
- str: The input string containing the integer value - str: The input string containing the integer value
- n: An optional pointer to an int to store the length of the parsed substring (default: nil) - n: An optional pointer to an int to store the length of the parsed substring (default: nil)
@@ -649,13 +649,13 @@ Example:
n, ok = strconv.parse_u128_maybe_prefixed("5678eeee") n, ok = strconv.parse_u128_maybe_prefixed("5678eeee")
fmt.println(n, ok) fmt.println(n, ok)
} }
Output: Output:
1234 true 1234 true
5678 false 5678 false
**Returns** **Returns**
- value: The parsed u128 value - value: The parsed u128 value
- ok: false if a valid integer could not be found, if the value was negative, or if the input string contained more than just the number. - ok: false if a valid integer could not be found, if the value was negative, or if the input string contained more than just the number.
*/ */
@@ -706,10 +706,10 @@ parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
/* /*
Converts a byte to lowercase Converts a byte to lowercase
**Inputs** **Inputs**
- ch: A byte character to be converted to lowercase. - ch: A byte character to be converted to lowercase.
**Returns** **Returns**
- A lowercase byte character. - A lowercase byte character.
*/ */
@(private) @(private)
@@ -717,7 +717,7 @@ lower :: #force_inline proc "contextless" (ch: byte) -> byte { return ('a' - 'A'
/* /*
Parses a 32-bit floating point number from a string Parses a 32-bit floating point number from a string
**Inputs** **Inputs**
- s: The input string containing a 32-bit floating point number. - s: The input string containing a 32-bit floating point number.
- n: An optional pointer to an int to store the length of the parsed substring (default: nil). - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
@@ -732,13 +732,13 @@ Example:
n, ok = strconv.parse_f32("5678e2") n, ok = strconv.parse_f32("5678e2")
fmt.printfln("%.3f %v", n, ok) fmt.printfln("%.3f %v", n, ok)
} }
Output: Output:
0.000 false 0.000 false
567800.000 true 567800.000 true
**Returns** **Returns**
- value: The parsed 32-bit floating point number. - value: The parsed 32-bit floating point number.
- ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number. - ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number.
*/ */
@@ -750,7 +750,7 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
/* /*
Parses a 64-bit floating point number from a string Parses a 64-bit floating point number from a string
**Inputs** **Inputs**
- str: The input string containing a 64-bit floating point number. - str: The input string containing a 64-bit floating point number.
- n: An optional pointer to an int to store the length of the parsed substring (default: nil). - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
@@ -765,13 +765,13 @@ Example:
n, ok = strconv.parse_f64("5678e2") n, ok = strconv.parse_f64("5678e2")
fmt.printfln("%.3f %v", n, ok) fmt.printfln("%.3f %v", n, ok)
} }
Output: Output:
0.000 false 0.000 false
567800.000 true 567800.000 true
**Returns** **Returns**
- value: The parsed 64-bit floating point number. - value: The parsed 64-bit floating point number.
- ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number. - ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number.
*/ */
@@ -787,7 +787,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
/* /*
Parses a 32-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful Parses a 32-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful
**Inputs** **Inputs**
- str: The input string containing a 32-bit floating point number. - str: The input string containing a 32-bit floating point number.
Example: Example:
@@ -801,14 +801,14 @@ Example:
n, _, ok = strconv.parse_f32_prefix("5678e2") n, _, ok = strconv.parse_f32_prefix("5678e2")
fmt.printfln("%.3f %v", n, ok) fmt.printfln("%.3f %v", n, ok)
} }
Output: Output:
0.000 false 0.000 false
567800.000 true 567800.000 true
**Returns**
**Returns**
- value: The parsed 32-bit floating point number. - value: The parsed 32-bit floating point number.
- nr: The length of the parsed substring. - nr: The length of the parsed substring.
- ok: A boolean indicating whether the parsing was successful. - ok: A boolean indicating whether the parsing was successful.
@@ -822,7 +822,7 @@ parse_f32_prefix :: proc(str: string) -> (value: f32, nr: int, ok: bool) {
/* /*
Parses a 64-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful Parses a 64-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful
**Inputs** **Inputs**
- str: The input string containing a 64-bit floating point number. - str: The input string containing a 64-bit floating point number.
Example: Example:
@@ -846,7 +846,7 @@ Output:
1234.000 true 1234.000 true
13.370 true 13.370 true
**Returns** **Returns**
- value: The parsed 64-bit floating point number. - value: The parsed 64-bit floating point number.
- nr: The length of the parsed substring. - nr: The length of the parsed substring.
- ok: `false` if a base 10 float could not be found - ok: `false` if a base 10 float could not be found
@@ -1184,7 +1184,7 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) {
/* /*
Parses a 128-bit complex number from a string Parses a 128-bit complex number from a string
**Inputs** **Inputs**
- str: The input string containing a 128-bit complex number. - str: The input string containing a 128-bit complex number.
- n: An optional pointer to an int to store the length of the parsed substring (default: nil). - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
@@ -1200,13 +1200,13 @@ Example:
c, ok = strconv.parse_complex128("5+7i hellope", &n) c, ok = strconv.parse_complex128("5+7i hellope", &n)
fmt.printfln("%v %i %t", c, n, ok) fmt.printfln("%v %i %t", c, n, ok)
} }
Output: Output:
3+1i 4 true 3+1i 4 true
5+7i 4 false 5+7i 4 false
**Returns** **Returns**
- value: The parsed 128-bit complex number. - value: The parsed 128-bit complex number.
- ok: `false` if a complex number could not be found, or if the input string contained more than just the number. - ok: `false` if a complex number could not be found, or if the input string contained more than just the number.
*/ */
@@ -1232,12 +1232,12 @@ parse_complex128 :: proc(str: string, n: ^int = nil) -> (value: complex128, ok:
} }
value = complex(real_value, imag_value) value = complex(real_value, imag_value)
return return
} }
/* /*
Parses a 64-bit complex number from a string Parses a 64-bit complex number from a string
**Inputs** **Inputs**
- str: The input string containing a 64-bit complex number. - str: The input string containing a 64-bit complex number.
- n: An optional pointer to an int to store the length of the parsed substring (default: nil). - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
@@ -1253,13 +1253,13 @@ Example:
c, ok = strconv.parse_complex64("5+7i hellope", &n) c, ok = strconv.parse_complex64("5+7i hellope", &n)
fmt.printfln("%v %i %t", c, n, ok) fmt.printfln("%v %i %t", c, n, ok)
} }
Output: Output:
3+1i 4 true 3+1i 4 true
5+7i 4 false 5+7i 4 false
**Returns** **Returns**
- value: The parsed 64-bit complex number. - value: The parsed 64-bit complex number.
- ok: `false` if a complex number could not be found, or if the input string contained more than just the number. - ok: `false` if a complex number could not be found, or if the input string contained more than just the number.
*/ */
@@ -1271,7 +1271,7 @@ parse_complex64 :: proc(str: string, n: ^int = nil) -> (value: complex64, ok: bo
/* /*
Parses a 32-bit complex number from a string Parses a 32-bit complex number from a string
**Inputs** **Inputs**
- str: The input string containing a 32-bit complex number. - str: The input string containing a 32-bit complex number.
- n: An optional pointer to an int to store the length of the parsed substring (default: nil). - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
@@ -1287,13 +1287,13 @@ Example:
c, ok = strconv.parse_complex32("5+7i hellope", &n) c, ok = strconv.parse_complex32("5+7i hellope", &n)
fmt.printfln("%v %i %t", c, n, ok) fmt.printfln("%v %i %t", c, n, ok)
} }
Output: Output:
3+1i 4 true 3+1i 4 true
5+7i 4 false 5+7i 4 false
**Returns** **Returns**
- value: The parsed 32-bit complex number. - value: The parsed 32-bit complex number.
- ok: `false` if a complex number could not be found, or if the input string contained more than just the number. - ok: `false` if a complex number could not be found, or if the input string contained more than just the number.
*/ */
@@ -1305,7 +1305,7 @@ parse_complex32 :: proc(str: string, n: ^int = nil) -> (value: complex32, ok: bo
/* /*
Parses a 256-bit quaternion from a string Parses a 256-bit quaternion from a string
**Inputs** **Inputs**
- str: The input string containing a 256-bit quaternion. - str: The input string containing a 256-bit quaternion.
- n: An optional pointer to an int to store the length of the parsed substring (default: nil). - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
@@ -1321,13 +1321,13 @@ Example:
q, ok = strconv.parse_quaternion256("1+2i+3j+4k hellope", &n) q, ok = strconv.parse_quaternion256("1+2i+3j+4k hellope", &n)
fmt.printfln("%v %i %t", q, n, ok) fmt.printfln("%v %i %t", q, n, ok)
} }
Output: Output:
1+2i+3j+4k 10 true 1+2i+3j+4k 10 true
1+2i+3j+4k 10 false 1+2i+3j+4k 10 false
**Returns** **Returns**
- value: The parsed 256-bit quaternion. - value: The parsed 256-bit quaternion.
- ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion. - ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion.
*/ */
@@ -1385,7 +1385,7 @@ parse_quaternion256 :: proc(str: string, n: ^int = nil) -> (value: quaternion256
/* /*
Parses a 128-bit quaternion from a string Parses a 128-bit quaternion from a string
**Inputs** **Inputs**
- str: The input string containing a 128-bit quaternion. - str: The input string containing a 128-bit quaternion.
- n: An optional pointer to an int to store the length of the parsed substring (default: nil). - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
@@ -1401,13 +1401,13 @@ Example:
q, ok = strconv.parse_quaternion128("1+2i+3j+4k hellope", &n) q, ok = strconv.parse_quaternion128("1+2i+3j+4k hellope", &n)
fmt.printfln("%v %i %t", q, n, ok) fmt.printfln("%v %i %t", q, n, ok)
} }
Output: Output:
1+2i+3j+4k 10 true 1+2i+3j+4k 10 true
1+2i+3j+4k 10 false 1+2i+3j+4k 10 false
**Returns** **Returns**
- value: The parsed 128-bit quaternion. - value: The parsed 128-bit quaternion.
- ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion. - ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion.
*/ */
@@ -1419,7 +1419,7 @@ parse_quaternion128 :: proc(str: string, n: ^int = nil) -> (value: quaternion128
/* /*
Parses a 64-bit quaternion from a string Parses a 64-bit quaternion from a string
**Inputs** **Inputs**
- str: The input string containing a 64-bit quaternion. - str: The input string containing a 64-bit quaternion.
- n: An optional pointer to an int to store the length of the parsed substring (default: nil). - n: An optional pointer to an int to store the length of the parsed substring (default: nil).
@@ -1435,13 +1435,13 @@ Example:
q, ok = strconv.parse_quaternion64("1+2i+3j+4k hellope", &n) q, ok = strconv.parse_quaternion64("1+2i+3j+4k hellope", &n)
fmt.printfln("%v %i %t", q, n, ok) fmt.printfln("%v %i %t", q, n, ok)
} }
Output: Output:
1+2i+3j+4k 10 true 1+2i+3j+4k 10 true
1+2i+3j+4k 10 false 1+2i+3j+4k 10 false
**Returns** **Returns**
- value: The parsed 64-bit quaternion. - value: The parsed 64-bit quaternion.
- ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion. - ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion.
*/ */
@@ -1450,20 +1450,20 @@ parse_quaternion64 :: proc(str: string, n: ^int = nil) -> (value: quaternion64,
v, ok = parse_quaternion256(str, n) v, ok = parse_quaternion256(str, n)
return cast(quaternion64)v, ok return cast(quaternion64)v, ok
} }
/* /*
Appends a boolean value as a string to the given buffer Writes a boolean value as a string to the given buffer
**Inputs** **Inputs**
- buf: The buffer to append the boolean value to - buf: The buffer to write the boolean value to
- b: The boolean value to be appended - b: The boolean value to be written
Example: Example:
import "core:fmt" import "core:fmt"
import "core:strconv" import "core:strconv"
append_bool_example :: proc() { write_bool_example :: proc() {
buf: [6]byte buf: [6]byte
result := strconv.append_bool(buf[:], true) result := strconv.write_bool(buf[:], true)
fmt.println(result, buf) fmt.println(result, buf)
} }
@@ -1471,10 +1471,10 @@ Output:
true [116, 114, 117, 101, 0, 0] true [116, 114, 117, 101, 0, 0]
**Returns** **Returns**
- The resulting string after appending the boolean value - The resulting string after writing the boolean value
*/ */
append_bool :: proc(buf: []byte, b: bool) -> string { write_bool :: proc(buf: []byte, b: bool) -> string {
n := 0 n := 0
if b { if b {
n = copy(buf, "true") n = copy(buf, "true")
@@ -1483,21 +1483,21 @@ append_bool :: proc(buf: []byte, b: bool) -> string {
} }
return string(buf[:n]) return string(buf[:n])
} }
/* /*
Appends an unsigned integer value as a string to the given buffer with the specified base Writes an unsigned integer value as a string to the given buffer with the specified base
**Inputs** **Inputs**
- buf: The buffer to append the unsigned integer value to - buf: The buffer to write the unsigned integer value to
- u: The unsigned integer value to be appended - u: The unsigned integer value to be written
- base: The base to use for converting the integer value - base: The base to use for converting the integer value
Example: Example:
import "core:fmt" import "core:fmt"
import "core:strconv" import "core:strconv"
append_uint_example :: proc() { write_uint_example :: proc() {
buf: [4]byte buf: [4]byte
result := strconv.append_uint(buf[:], 42, 16) result := strconv.write_uint(buf[:], 42, 16)
fmt.println(result, buf) fmt.println(result, buf)
} }
@@ -1505,27 +1505,27 @@ Output:
2a [50, 97, 0, 0] 2a [50, 97, 0, 0]
**Returns** **Returns**
- The resulting string after appending the unsigned integer value - The resulting string after writing the unsigned integer value
*/ */
append_uint :: proc(buf: []byte, u: u64, base: int) -> string { write_uint :: proc(buf: []byte, u: u64, base: int) -> string {
return append_bits(buf, u, base, false, 8*size_of(uint), digits, nil) return write_bits(buf, u, base, false, 8*size_of(uint), digits, nil)
} }
/* /*
Appends a signed integer value as a string to the given buffer with the specified base Writes a signed integer value as a string to the given buffer with the specified base
**Inputs** **Inputs**
- buf: The buffer to append the signed integer value to - buf: The buffer to write the signed integer value to
- i: The signed integer value to be appended - i: The signed integer value to be written
- base: The base to use for converting the integer value - base: The base to use for converting the integer value
Example: Example:
import "core:fmt" import "core:fmt"
import "core:strconv" import "core:strconv"
append_int_example :: proc() { write_int_example :: proc() {
buf: [4]byte buf: [4]byte
result := strconv.append_int(buf[:], -42, 10) result := strconv.write_int(buf[:], -42, 10)
fmt.println(result, buf) fmt.println(result, buf)
} }
@@ -1533,23 +1533,23 @@ Output:
-42 [45, 52, 50, 0] -42 [45, 52, 50, 0]
**Returns** **Returns**
- The resulting string after appending the signed integer value - The resulting string after writing the signed integer value
*/ */
append_int :: proc(buf: []byte, i: i64, base: int) -> string { write_int :: proc(buf: []byte, i: i64, base: int) -> string {
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil) return write_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil)
} }
append_u128 :: proc(buf: []byte, u: u128, base: int) -> string { write_u128 :: proc(buf: []byte, u: u128, base: int) -> string {
return append_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil) return write_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil)
} }
/* /*
Converts an integer value to a string and stores it in the given buffer Converts an integer value to a string and stores it in the given buffer
**Inputs** **Inputs**
- buf: The buffer to store the resulting string - buf: The buffer to store the resulting string
- i: The integer value to be converted - i: The integer value to be converted
@@ -1567,16 +1567,16 @@ Output:
42 [52, 50, 0, 0] 42 [52, 50, 0, 0]
**Returns** **Returns**
- The resulting string after converting the integer value - The resulting string after converting the integer value
*/ */
itoa :: proc(buf: []byte, i: int) -> string { itoa :: proc(buf: []byte, i: int) -> string {
return append_int(buf, i64(i), 10) return write_int(buf, i64(i), 10)
} }
/* /*
Converts a string to an integer value Converts a string to an integer value
**Inputs** **Inputs**
- s: The string to be converted - s: The string to be converted
Example: Example:
@@ -1591,17 +1591,17 @@ Output:
42 42
**Returns** **Returns**
- The resulting integer value - The resulting integer value
*/ */
atoi :: proc(s: string) -> int { atoi :: proc(s: string) -> int {
v, _ := parse_int(s) v, _ := parse_int(s)
return v return v
} }
/* /*
Converts a string to a float64 value Converts a string to a float64 value
**Inputs** **Inputs**
- s: The string to be converted - s: The string to be converted
Example: Example:
@@ -1616,21 +1616,21 @@ Output:
3.140 3.140
**Returns** **Returns**
- The resulting float64 value after converting the string - The resulting float64 value after converting the string
*/ */
atof :: proc(s: string) -> f64 { atof :: proc(s: string) -> f64 {
v, _ := parse_f64(s) v, _ := parse_f64(s)
return v return v
} }
// Alias to `append_float` // Alias to `write_float`
ftoa :: append_float ftoa :: write_float
/* /*
Appends a float64 value as a string to the given buffer with the specified format and precision Writes a float64 value as a string to the given buffer with the specified format and precision
**Inputs** **Inputs**
- buf: The buffer to append the float64 value to - buf: The buffer to write the float64 value to
- f: The float64 value to be appended - f: The float64 value to be written
- fmt: The byte specifying the format to use for the conversion - fmt: The byte specifying the format to use for the conversion
- prec: The precision to use for the conversion - prec: The precision to use for the conversion
- bit_size: The size of the float in bits (32 or 64) - bit_size: The size of the float in bits (32 or 64)
@@ -1639,9 +1639,9 @@ Example:
import "core:fmt" import "core:fmt"
import "core:strconv" import "core:strconv"
append_float_example :: proc() { write_float_example :: proc() {
buf: [8]byte buf: [8]byte
result := strconv.append_float(buf[:], 3.14159, 'f', 2, 64) result := strconv.write_float(buf[:], 3.14159, 'f', 2, 64)
fmt.println(result, buf) fmt.println(result, buf)
} }
@@ -1649,20 +1649,20 @@ Output:
+3.14 [43, 51, 46, 49, 52, 0, 0, 0] +3.14 [43, 51, 46, 49, 52, 0, 0, 0]
**Returns** **Returns**
- The resulting string after appending the float - The resulting string after writing the float
*/ */
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { write_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size)) return string(generic_ftoa(buf, f, fmt, prec, bit_size))
} }
/* /*
Appends a quoted string representation of the input string to a given byte slice and returns the result as a string Writes a quoted string representation of the input string to a given byte slice and returns the result as a string
**Inputs** **Inputs**
- buf: The byte slice to which the quoted string will be appended - buf: The byte slice to which the quoted string will be written
- str: The input string to be quoted - str: The input string to be quoted
!! ISSUE !! NOT EXPECTED -- "\"hello\"" was expected !! ISSUE !! NOT EXPECTED -- "\"hello\"" was expected
Example: Example:
@@ -1678,8 +1678,8 @@ Output:
"'h''e''l''l''o'" [34, 39, 104, 39, 39, 101, 39, 39, 108, 39, 39, 108, 39, 39, 111, 39, 34, 0, 0, 0] "'h''e''l''l''o'" [34, 39, 104, 39, 39, 101, 39, 39, 108, 39, 39, 108, 39, 39, 111, 39, 34, 0, 0, 0]
**Returns** **Returns**
- The resulting string after appending the quoted string representation - The resulting string after writing the quoted string representation
*/ */
quote :: proc(buf: []byte, str: string) -> string { quote :: proc(buf: []byte, str: string) -> string {
write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) { write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) {
@@ -1719,10 +1719,10 @@ quote :: proc(buf: []byte, str: string) -> string {
return string(buf[:i]) return string(buf[:i])
} }
/* /*
Appends a quoted rune representation of the input rune to a given byte slice and returns the result as a string Writes a quoted rune representation of the input rune to a given byte slice and returns the result as a string
**Inputs** **Inputs**
- buf: The byte slice to which the quoted rune will be appended - buf: The byte slice to which the quoted rune will be written
- r: The input rune to be quoted - r: The input rune to be quoted
Example: Example:
@@ -1739,8 +1739,8 @@ Output:
'A' [39, 65, 39, 0] 'A' [39, 65, 39, 0]
**Returns** **Returns**
- The resulting string after appending the quoted rune representation - The resulting string after writing the quoted rune representation
*/ */
quote_rune :: proc(buf: []byte, r: rune) -> string { quote_rune :: proc(buf: []byte, r: rune) -> string {
write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) { write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) {
@@ -1783,7 +1783,7 @@ quote_rune :: proc(buf: []byte, r: rune) -> string {
if r < 32 { if r < 32 {
write_string(buf, &i, "\\x") write_string(buf, &i, "\\x")
b: [2]byte b: [2]byte
s := append_bits(b[:], u64(r), 16, true, 64, digits, nil) s := write_bits(b[:], u64(r), 16, true, 64, digits, nil)
switch len(s) { switch len(s) {
case 0: write_string(buf, &i, "00") case 0: write_string(buf, &i, "00")
case 1: write_rune(buf, &i, '0') case 1: write_rune(buf, &i, '0')
@@ -1800,11 +1800,11 @@ quote_rune :: proc(buf: []byte, r: rune) -> string {
/* /*
Unquotes a single character from the input string, considering the given quote character Unquotes a single character from the input string, considering the given quote character
**Inputs** **Inputs**
- str: The input string containing the character to unquote - str: The input string containing the character to unquote
- quote: The quote character to consider (e.g., '"') - quote: The quote character to consider (e.g., '"')
Example: Example:
import "core:fmt" import "core:fmt"
import "core:strconv" import "core:strconv"
@@ -1815,12 +1815,12 @@ Example:
fmt.printf("r: <%v>, multiple_bytes:%v, tail_string:<%s>, success:%v\n",r, multiple_bytes, tail_string, success) fmt.printf("r: <%v>, multiple_bytes:%v, tail_string:<%s>, success:%v\n",r, multiple_bytes, tail_string, success)
} }
Output: Output:
Source: 'The' raven Source: 'The' raven
r: <'>, multiple_bytes:false, tail_string:<The' raven>, success:true r: <'>, multiple_bytes:false, tail_string:<The' raven>, success:true
**Returns** **Returns**
- r: The unquoted rune - r: The unquoted rune
- multiple_bytes: A boolean indicating if the rune has multiple bytes - multiple_bytes: A boolean indicating if the rune has multiple bytes
- tail_string: The remaining portion of the input string after unquoting the character - tail_string: The remaining portion of the input string after unquoting the character
@@ -1923,13 +1923,13 @@ unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool
/* /*
Unquotes the input string considering any type of quote character and returns the unquoted string Unquotes the input string considering any type of quote character and returns the unquoted string
**Inputs** **Inputs**
- lit: The input string to unquote - lit: The input string to unquote
- allocator: (default: context.allocator) - allocator: (default: context.allocator)
WARNING: This procedure gives unexpected results if the quotes are not the first and last characters. WARNING: This procedure gives unexpected results if the quotes are not the first and last characters.
Example: Example:
import "core:fmt" import "core:fmt"
import "core:strconv" import "core:strconv"
@@ -1947,10 +1947,10 @@ Example:
src="The raven \'Huginn\' is black." src="The raven \'Huginn\' is black."
s, allocated, ok = strconv.unquote_string(src) // Will produce undesireable results s, allocated, ok = strconv.unquote_string(src) // Will produce undesireable results
fmt.println(src) fmt.println(src)
fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n", s, allocated, ok) fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n", s, allocated, ok)
} }
Output: Output:
"The raven Huginn is black." "The raven Huginn is black."
Unquoted: <The raven Huginn is black.>, alloc:false, ok:true Unquoted: <The raven Huginn is black.>, alloc:false, ok:true
@@ -1961,7 +1961,7 @@ Output:
The raven 'Huginn' is black. The raven 'Huginn' is black.
Unquoted: <he raven 'Huginn' is black>, alloc:false, ok:true Unquoted: <he raven 'Huginn' is black>, alloc:false, ok:true
**Returns** **Returns**
- res: The resulting unquoted string - res: The resulting unquoted string
- allocated: A boolean indicating if the resulting string was allocated using the provided allocator - allocated: A boolean indicating if the resulting string was allocated using the provided allocator
- success: A boolean indicating whether the unquoting was successful - success: A boolean indicating whether the unquoting was successful
@@ -2002,7 +2002,7 @@ unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: str
return s, false, true return s, false, true
} }
} }
context.allocator = allocator context.allocator = allocator
buf_len := 3*len(s) / 2 buf_len := 3*len(s) / 2
+6 -6
View File
@@ -675,7 +675,7 @@ Returns:
*/ */
write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) { write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) {
buf: [384]byte buf: [384]byte
s := strconv.append_float(buf[:], f, fmt, prec, bit_size) s := strconv.write_float(buf[:], f, fmt, prec, bit_size)
// If the result starts with a `+` then unless we always want signed results, // If the result starts with a `+` then unless we always want signed results,
// we skip it unless it's followed by an `I` (because of +Inf). // we skip it unless it's followed by an `I` (because of +Inf).
if !always_signed && (buf[0] == '+' && buf[1] != 'I') { if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
@@ -699,7 +699,7 @@ Returns:
*/ */
write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) { write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) {
buf: [384]byte buf: [384]byte
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
if !always_signed && (buf[0] == '+' && buf[1] != 'I') { if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
s = s[1:] s = s[1:]
} }
@@ -739,7 +739,7 @@ Output:
*/ */
write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: int) { write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: int) {
buf: [384]byte buf: [384]byte
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
if !always_signed && (buf[0] == '+' && buf[1] != 'I') { if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
s = s[1:] s = s[1:]
} }
@@ -761,7 +761,7 @@ Returns:
*/ */
write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) { write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) {
buf: [384]byte buf: [384]byte
s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f))
if !always_signed && (buf[0] == '+' && buf[1] != 'I') { if !always_signed && (buf[0] == '+' && buf[1] != 'I') {
s = s[1:] s = s[1:]
} }
@@ -782,7 +782,7 @@ Returns:
*/ */
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) { write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
buf: [32]byte buf: [32]byte
s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil) s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil)
return write_string(b, s) return write_string(b, s)
} }
/* /*
@@ -800,7 +800,7 @@ Returns:
*/ */
write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) { write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) {
buf: [32]byte buf: [32]byte
s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil)
return write_string(b, s) return write_string(b, s)
} }
/* /*
+82 -64
View File
@@ -28,24 +28,7 @@ clone :: proc(s: string, allocator := context.allocator, loc := #caller_location
copy(c, s) copy(c, s)
return string(c), nil return string(c), nil
} }
/*
Clones a string safely (returns early with an allocation error on failure)
*Allocates Using Provided Allocator*
Inputs:
- s: The string to be cloned
- allocator: (default: context.allocator)
- loc: The caller location for debugging purposes (default: #caller_location)
Returns:
- res: The cloned string
- err: An allocator error if one occured, `nil` otherwise
*/
@(deprecated="Prefer clone. It now returns an optional allocator error")
clone_safe :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) {
return clone(s, allocator, loc)
}
/* /*
Clones a string and appends a null-byte to make it a cstring Clones a string and appends a null-byte to make it a cstring
@@ -66,6 +49,7 @@ clone_to_cstring :: proc(s: string, allocator := context.allocator, loc := #call
c[len(s)] = 0 c[len(s)] = 0
return cstring(&c[0]), nil return cstring(&c[0]), nil
} }
/* /*
Transmutes a raw pointer into a string. Non-allocating. Transmutes a raw pointer into a string. Non-allocating.
@@ -81,6 +65,7 @@ Returns:
string_from_ptr :: proc(ptr: ^byte, len: int) -> (res: string) { string_from_ptr :: proc(ptr: ^byte, len: int) -> (res: string) {
return transmute(string)mem.Raw_String{ptr, len} return transmute(string)mem.Raw_String{ptr, len}
} }
/* /*
Transmutes a raw pointer (null-terminated) into a string. Non-allocating. Searches for a null-byte from `0..<len`, otherwise `len` will be the end size Transmutes a raw pointer (null-terminated) into a string. Non-allocating. Searches for a null-byte from `0..<len`, otherwise `len` will be the end size
@@ -99,20 +84,7 @@ string_from_null_terminated_ptr :: proc "contextless" (ptr: [^]byte, len: int) -
s = truncate_to_byte(s, 0) s = truncate_to_byte(s, 0)
return s return s
} }
/*
Gets the raw byte pointer for the start of a string `str`
Inputs:
- str: The input string
Returns:
- res: A pointer to the start of the string's bytes
*/
@(deprecated="Prefer the builtin raw_data.")
ptr_from_string :: proc(str: string) -> (res: ^byte) {
d := transmute(mem.Raw_String)str
return d.data
}
/* /*
Converts a string `str` to a cstring Converts a string `str` to a cstring
@@ -128,6 +100,7 @@ unsafe_string_to_cstring :: proc(str: string) -> (res: cstring) {
d := transmute(mem.Raw_String)str d := transmute(mem.Raw_String)str
return cstring(d.data) return cstring(d.data)
} }
/* /*
Truncates a string `str` at the first occurrence of char/byte `b` Truncates a string `str` at the first occurrence of char/byte `b`
@@ -147,6 +120,7 @@ truncate_to_byte :: proc "contextless" (str: string, b: byte) -> (res: string) {
} }
return str[:n] return str[:n]
} }
/* /*
Truncates a string `str` at the first occurrence of rune `r` as a slice of the original, entire string if not found Truncates a string `str` at the first occurrence of rune `r` as a slice of the original, entire string if not found
@@ -164,6 +138,7 @@ truncate_to_rune :: proc(str: string, r: rune) -> (res: string) {
} }
return str[:n] return str[:n]
} }
/* /*
Clones a byte array `s` and appends a null-byte Clones a byte array `s` and appends a null-byte
@@ -184,6 +159,7 @@ clone_from_bytes :: proc(s: []byte, allocator := context.allocator, loc := #call
c[len(s)] = 0 c[len(s)] = 0
return string(c[:len(s)]), nil return string(c[:len(s)]), nil
} }
/* /*
Clones a cstring `s` as a string Clones a cstring `s` as a string
@@ -201,6 +177,7 @@ Returns:
clone_from_cstring :: proc(s: cstring, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { clone_from_cstring :: proc(s: cstring, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
return clone(string(s), allocator, loc) return clone(string(s), allocator, loc)
} }
/* /*
Clones a string from a byte pointer `ptr` and a byte length `len` Clones a string from a byte pointer `ptr` and a byte length `len`
@@ -222,6 +199,7 @@ clone_from_ptr :: proc(ptr: ^byte, len: int, allocator := context.allocator, loc
s := string_from_ptr(ptr, len) s := string_from_ptr(ptr, len)
return clone(s, allocator, loc) return clone(s, allocator, loc)
} }
// Overloaded procedure to clone from a string, `[]byte`, `cstring` or a `^byte` + length // Overloaded procedure to clone from a string, `[]byte`, `cstring` or a `^byte` + length
clone_from :: proc{ clone_from :: proc{
clone, clone,
@@ -229,6 +207,7 @@ clone_from :: proc{
clone_from_cstring, clone_from_cstring,
clone_from_ptr, clone_from_ptr,
} }
/* /*
Clones a string from a null-terminated cstring `ptr` and a byte length `len` Clones a string from a null-terminated cstring `ptr` and a byte length `len`
@@ -251,6 +230,7 @@ clone_from_cstring_bounded :: proc(ptr: cstring, len: int, allocator := context.
s = truncate_to_byte(s, 0) s = truncate_to_byte(s, 0)
return clone(s, allocator, loc) return clone(s, allocator, loc)
} }
/* /*
Compares two strings, returning a value representing which one comes first lexicographically. Compares two strings, returning a value representing which one comes first lexicographically.
-1 for `lhs`; 1 for `rhs`, or 0 if they are equal. -1 for `lhs`; 1 for `rhs`, or 0 if they are equal.
@@ -265,6 +245,7 @@ Returns:
compare :: proc "contextless" (lhs, rhs: string) -> (result: int) { compare :: proc "contextless" (lhs, rhs: string) -> (result: int) {
return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs) return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs)
} }
/* /*
Checks if rune `r` in the string `s` Checks if rune `r` in the string `s`
@@ -283,6 +264,7 @@ contains_rune :: proc(s: string, r: rune) -> (result: bool) {
} }
return false return false
} }
/* /*
Returns true when the string `substr` is contained inside the string `s` Returns true when the string `substr` is contained inside the string `s`
@@ -314,6 +296,7 @@ Output:
contains :: proc(s, substr: string) -> (res: bool) { contains :: proc(s, substr: string) -> (res: bool) {
return index(s, substr) >= 0 return index(s, substr) >= 0
} }
/* /*
Returns `true` when the string `s` contains any of the characters inside the string `chars` Returns `true` when the string `s` contains any of the characters inside the string `chars`
@@ -386,6 +369,7 @@ Output:
rune_count :: proc(s: string) -> (res: int) { rune_count :: proc(s: string) -> (res: int) {
return utf8.rune_count_in_string(s) return utf8.rune_count_in_string(s)
} }
/* /*
Returns whether the strings `u` and `v` are the same alpha characters, ignoring different casings Returns whether the strings `u` and `v` are the same alpha characters, ignoring different casings
Works with UTF-8 string content Works with UTF-8 string content
@@ -508,6 +492,7 @@ prefix_length :: proc "contextless" (a, b: string) -> (n: int) {
} }
return return
} }
/* /*
Returns the common prefix between strings `a` and `b` Returns the common prefix between strings `a` and `b`
@@ -540,6 +525,7 @@ Output:
common_prefix :: proc(a, b: string) -> string { common_prefix :: proc(a, b: string) -> string {
return a[:prefix_length(a, b)] return a[:prefix_length(a, b)]
} }
/* /*
Determines if a string `s` starts with a given `prefix` Determines if a string `s` starts with a given `prefix`
@@ -661,24 +647,7 @@ join :: proc(a: []string, sep: string, allocator := context.allocator, loc := #c
} }
return string(b), nil return string(b), nil
} }
/*
Joins a slice of strings `a` with a `sep` string, returns an error on allocation failure
*Allocates Using Provided Allocator*
Inputs:
- a: A slice of strings to join
- sep: The separator string
- allocator: (default is context.allocator)
Returns:
- str: A combined string from the slice of strings `a` separated with the `sep` string
- err: An allocator error if one occured, `nil` otherwise
*/
@(deprecated="Prefer join. It now returns an optional allocator error")
join_safe :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
return join(a, sep, allocator)
}
/* /*
Returns a combined string from the slice of strings `a` without a separator Returns a combined string from the slice of strings `a` without a separator
@@ -723,22 +692,6 @@ concatenate :: proc(a: []string, allocator := context.allocator, loc := #caller_
} }
return string(b), nil return string(b), nil
} }
/*
Returns a combined string from the slice of strings `a` without a separator, or an error if allocation fails
*Allocates Using Provided Allocator*
Inputs:
- a: A slice of strings to concatenate
- allocator: (default is context.allocator)
Returns:
The concatenated string, and an error if allocation fails
*/
@(deprecated="Prefer concatenate. It now returns an optional allocator error")
concatenate_safe :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) {
return concatenate(a, allocator)
}
/* /*
Returns a substring of the input string `s` with the specified rune offset and length Returns a substring of the input string `s` with the specified rune offset and length
@@ -901,6 +854,7 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato
return res[:i+1], nil return res[:i+1], nil
} }
/* /*
Splits a string into parts based on a separator. Splits a string into parts based on a separator.
@@ -936,6 +890,7 @@ Output:
split :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { split :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error {
return _split(s, sep, 0, -1, allocator) return _split(s, sep, 0, -1, allocator)
} }
/* /*
Splits a string into parts based on a separator. If n < count of seperators, the remainder of the string is returned in the last entry. Splits a string into parts based on a separator. If n < count of seperators, the remainder of the string is returned in the last entry.
@@ -972,6 +927,7 @@ Output:
split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error {
return _split(s, sep, 0, n, allocator) return _split(s, sep, 0, n, allocator)
} }
/* /*
Splits a string into parts after the separator, retaining it in the substrings. Splits a string into parts after the separator, retaining it in the substrings.
@@ -1007,6 +963,7 @@ Output:
split_after :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { split_after :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error {
return _split(s, sep, len(sep), -1, allocator) return _split(s, sep, len(sep), -1, allocator)
} }
/* /*
Splits a string into a total of `n` parts after the separator. Splits a string into a total of `n` parts after the separator.
@@ -1043,6 +1000,7 @@ Output:
split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error {
return _split(s, sep, len(sep), n, allocator) return _split(s, sep, len(sep), n, allocator)
} }
/* /*
Searches for the first occurrence of `sep` in the given string and returns the substring Searches for the first occurrence of `sep` in the given string and returns the substring
up to (but not including) the separator, as well as a boolean indicating success. up to (but not including) the separator, as well as a boolean indicating success.
@@ -1083,6 +1041,7 @@ _split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string,
} }
return return
} }
/* /*
Splits the input string by the byte separator in an iterator fashion. Splits the input string by the byte separator in an iterator fashion.
@@ -1129,6 +1088,7 @@ split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) {
} }
return return
} }
/* /*
Splits the input string by the separator string in an iterator fashion. Splits the input string by the separator string in an iterator fashion.
@@ -1164,6 +1124,7 @@ Output:
split_iterator :: proc(s: ^string, sep: string) -> (res: string, ok: bool) { split_iterator :: proc(s: ^string, sep: string) -> (res: string, ok: bool) {
return _split_iterator(s, sep, 0) return _split_iterator(s, sep, 0)
} }
/* /*
Splits the input string after every separator string in an iterator fashion. Splits the input string after every separator string in an iterator fashion.
@@ -1199,6 +1160,7 @@ Output:
split_after_iterator :: proc(s: ^string, sep: string) -> (res: string, ok: bool) { split_after_iterator :: proc(s: ^string, sep: string) -> (res: string, ok: bool) {
return _split_iterator(s, sep, len(sep)) return _split_iterator(s, sep, len(sep))
} }
/* /*
Trims the carriage return character from the end of the input string. Trims the carriage return character from the end of the input string.
@@ -1220,6 +1182,7 @@ _trim_cr :: proc(s: string) -> (res: string) {
} }
return s return s
} }
/* /*
Splits the input string at every line break `\n`. Splits the input string at every line break `\n`.
@@ -1257,6 +1220,7 @@ split_lines :: proc(s: string, allocator := context.allocator) -> (res: []string
} }
return lines, nil return lines, nil
} }
/* /*
Splits the input string at every line break `\n` for `n` parts. Splits the input string at every line break `\n` for `n` parts.
@@ -1297,6 +1261,7 @@ split_lines_n :: proc(s: string, n: int, allocator := context.allocator) -> (res
} }
return lines, nil return lines, nil
} }
/* /*
Splits the input string at every line break `\n` leaving the `\n` in the resulting strings. Splits the input string at every line break `\n` leaving the `\n` in the resulting strings.
@@ -1336,6 +1301,7 @@ split_lines_after :: proc(s: string, allocator := context.allocator) -> (res: []
} }
return lines, nil return lines, nil
} }
/* /*
Splits the input string at every line break `\n` leaving the `\n` in the resulting strings. Splits the input string at every line break `\n` leaving the `\n` in the resulting strings.
Only runs for n parts. Only runs for n parts.
@@ -1377,6 +1343,7 @@ split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) -
} }
return lines, nil return lines, nil
} }
/* /*
Splits the input string at every line break `\n`. Splits the input string at every line break `\n`.
Returns the current split string every iteration until the string is consumed. Returns the current split string every iteration until the string is consumed.
@@ -1411,6 +1378,7 @@ split_lines_iterator :: proc(s: ^string) -> (line: string, ok: bool) {
line = _split_iterator(s, sep, 0) or_return line = _split_iterator(s, sep, 0) or_return
return _trim_cr(line), true return _trim_cr(line), true
} }
/* /*
Splits the input string at every line break `\n`. Splits the input string at every line break `\n`.
Returns the current split string with line breaks included every iteration until the string is consumed. Returns the current split string with line breaks included every iteration until the string is consumed.
@@ -1448,6 +1416,7 @@ split_lines_after_iterator :: proc(s: ^string) -> (line: string, ok: bool) {
line = _split_iterator(s, sep, len(sep)) or_return line = _split_iterator(s, sep, len(sep)) or_return
return _trim_cr(line), true return _trim_cr(line), true
} }
/* /*
Returns the byte offset of the first byte `c` in the string s it finds, -1 when not found. Returns the byte offset of the first byte `c` in the string s it finds, -1 when not found.
NOTE: Can't find UTF-8 based runes. NOTE: Can't find UTF-8 based runes.
@@ -1482,6 +1451,7 @@ Output:
index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) { index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
return #force_inline bytes.index_byte(transmute([]u8)s, c) return #force_inline bytes.index_byte(transmute([]u8)s, c)
} }
/* /*
Returns the byte offset of the last byte `c` in the string `s`, -1 when not found. Returns the byte offset of the last byte `c` in the string `s`, -1 when not found.
@@ -1517,6 +1487,7 @@ Output:
last_index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) { last_index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
return #force_inline bytes.last_index_byte(transmute([]u8)s, c) return #force_inline bytes.last_index_byte(transmute([]u8)s, c)
} }
/* /*
Returns the byte offset of the first rune `r` in the string `s` it finds, -1 when not found. Returns the byte offset of the first rune `r` in the string `s` it finds, -1 when not found.
Invalid runes return -1 Invalid runes return -1
@@ -1657,6 +1628,7 @@ index :: proc "contextless" (s, substr: string) -> (res: int) {
} }
return -1 return -1
} }
/* /*
Returns the last byte offset of the string `substr` in the string `s`, -1 when not found. Returns the last byte offset of the string `substr` in the string `s`, -1 when not found.
@@ -1734,6 +1706,7 @@ last_index :: proc(s, substr: string) -> (res: int) {
} }
return -1 return -1
} }
/* /*
Returns the index of any first char of `chars` found in `s`, -1 if not found. Returns the index of any first char of `chars` found in `s`, -1 if not found.
@@ -1797,6 +1770,7 @@ index_any :: proc(s, chars: string) -> (res: int) {
} }
return -1 return -1
} }
/* /*
Finds the last occurrence of any character in `chars` within `s`. Iterates in reverse. Finds the last occurrence of any character in `chars` within `s`. Iterates in reverse.
@@ -1878,6 +1852,7 @@ last_index_any :: proc(s, chars: string) -> (res: int) {
} }
return -1 return -1
} }
/* /*
Finds the first occurrence of any substring in `substrs` within `s` Finds the first occurrence of any substring in `substrs` within `s`
@@ -1919,6 +1894,7 @@ index_multi :: proc(s: string, substrs: []string) -> (idx: int, width: int) {
} }
return return
} }
/* /*
Counts the number of non-overlapping occurrences of `substr` in `s` Counts the number of non-overlapping occurrences of `substr` in `s`
@@ -1985,6 +1961,7 @@ count :: proc(s, substr: string) -> (res: int) {
} }
return n return n
} }
/* /*
Repeats the string `s` `count` times, concatenating the result Repeats the string `s` `count` times, concatenating the result
@@ -2030,6 +2007,7 @@ repeat :: proc(s: string, count: int, allocator := context.allocator, loc := #ca
} }
return string(b), nil return string(b), nil
} }
/* /*
Replaces all occurrences of `old` in `s` with `new` Replaces all occurrences of `old` in `s` with `new`
@@ -2063,9 +2041,11 @@ Output:
zzzz true zzzz true
*/ */
replace_all :: proc(s, old, new: string, allocator := context.allocator) -> (output: string, was_allocation: bool) { replace_all :: proc(s, old, new: string, allocator := context.allocator) -> (output: string, was_allocation: bool) {
return replace(s, old, new, -1, allocator) return replace(s, old, new, -1, allocator)
} }
/* /*
Replaces n instances of old in the string s with the new string Replaces n instances of old in the string s with the new string
@@ -2144,6 +2124,7 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator, loc
output = string(t[0:w]) output = string(t[0:w])
return return
} }
/* /*
Removes the key string `n` times from the `s` string Removes the key string `n` times from the `s` string
@@ -2182,6 +2163,7 @@ Output:
remove :: proc(s, key: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) { remove :: proc(s, key: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) {
return replace(s, key, "", n, allocator) return replace(s, key, "", n, allocator)
} }
/* /*
Removes all the `key` string instances from the `s` string Removes all the `key` string instances from the `s` string
@@ -2217,6 +2199,7 @@ Output:
remove_all :: proc(s, key: string, allocator := context.allocator) -> (output: string, was_allocation: bool) { remove_all :: proc(s, key: string, allocator := context.allocator) -> (output: string, was_allocation: bool) {
return remove(s, key, -1, allocator) return remove(s, key, -1, allocator)
} }
// Returns true if is an ASCII space character ('\t', '\n', '\v', '\f', '\r', ' ') // Returns true if is an ASCII space character ('\t', '\n', '\v', '\f', '\r', ' ')
@(private) _ascii_space := [256]bool{'\t' = true, '\n' = true, '\v' = true, '\f' = true, '\r' = true, ' ' = true} @(private) _ascii_space := [256]bool{'\t' = true, '\n' = true, '\v' = true, '\f' = true, '\r' = true, ' ' = true}
@@ -2320,6 +2303,7 @@ index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res: int
} }
return -1 return -1
} }
// Same as `index_proc`, but the procedure p takes a raw pointer for state // Same as `index_proc`, but the procedure p takes a raw pointer for state
index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> (res: int) { index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> (res: int) {
for r, i in s { for r, i in s {
@@ -2329,6 +2313,7 @@ index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: r
} }
return -1 return -1
} }
// Finds the index of the *last* rune in the string s for which the procedure p returns the same value as truth // Finds the index of the *last* rune in the string s for which the procedure p returns the same value as truth
last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res: int) { last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res: int) {
// TODO(bill): Probably use Rabin-Karp Search // TODO(bill): Probably use Rabin-Karp Search
@@ -2341,6 +2326,7 @@ last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res
} }
return -1 return -1
} }
// Same as `index_proc_with_state`, runs through the string in reverse // Same as `index_proc_with_state`, runs through the string in reverse
last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> (res: int) { last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> (res: int) {
// TODO(bill): Probably use Rabin-Karp Search // TODO(bill): Probably use Rabin-Karp Search
@@ -2353,6 +2339,7 @@ last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta
} }
return -1 return -1
} }
/* /*
Trims the input string `s` from the left until the procedure `p` returns false Trims the input string `s` from the left until the procedure `p` returns false
@@ -2387,6 +2374,7 @@ trim_left_proc :: proc(s: string, p: proc(rune) -> bool) -> (res: string) {
} }
return s[i:] return s[i:]
} }
/* /*
Trims the input string `s` from the left until the procedure `p` with state returns false Trims the input string `s` from the left until the procedure `p` with state returns false
@@ -2405,6 +2393,7 @@ trim_left_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, stat
} }
return s[i:] return s[i:]
} }
/* /*
Trims the input string `s` from the right until the procedure `p` returns `false` Trims the input string `s` from the right until the procedure `p` returns `false`
@@ -2442,6 +2431,7 @@ trim_right_proc :: proc(s: string, p: proc(rune) -> bool) -> (res: string) {
} }
return s[0:i] return s[0:i]
} }
/* /*
Trims the input string `s` from the right until the procedure `p` with state returns `false` Trims the input string `s` from the right until the procedure `p` with state returns `false`
@@ -2463,6 +2453,7 @@ trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta
} }
return s[0:i] return s[0:i]
} }
// Procedure for `trim_*_proc` variants, which has a string rawptr cast + rune comparison // Procedure for `trim_*_proc` variants, which has a string rawptr cast + rune comparison
is_in_cutset :: proc(state: rawptr, r: rune) -> (res: bool) { is_in_cutset :: proc(state: rawptr, r: rune) -> (res: bool) {
cutset := (^string)(state)^ cutset := (^string)(state)^
@@ -2473,6 +2464,7 @@ is_in_cutset :: proc(state: rawptr, r: rune) -> (res: bool) {
} }
return false return false
} }
/* /*
Trims the cutset string from the `s` string Trims the cutset string from the `s` string
@@ -2490,6 +2482,7 @@ trim_left :: proc(s: string, cutset: string) -> (res: string) {
state := cutset state := cutset
return trim_left_proc_with_state(s, is_in_cutset, &state) return trim_left_proc_with_state(s, is_in_cutset, &state)
} }
/* /*
Trims the cutset string from the `s` string from the right Trims the cutset string from the `s` string from the right
@@ -2507,6 +2500,7 @@ trim_right :: proc(s: string, cutset: string) -> (res: string) {
state := cutset state := cutset
return trim_right_proc_with_state(s, is_in_cutset, &state) return trim_right_proc_with_state(s, is_in_cutset, &state)
} }
/* /*
Trims the cutset string from the `s` string, both from left and right Trims the cutset string from the `s` string, both from left and right
@@ -2520,6 +2514,7 @@ Returns:
trim :: proc(s: string, cutset: string) -> (res: string) { trim :: proc(s: string, cutset: string) -> (res: string) {
return trim_right(trim_left(s, cutset), cutset) return trim_right(trim_left(s, cutset), cutset)
} }
/* /*
Trims until a valid non-space rune from the left, "\t\txyz\t\t" -> "xyz\t\t" Trims until a valid non-space rune from the left, "\t\txyz\t\t" -> "xyz\t\t"
@@ -2532,6 +2527,7 @@ Returns:
trim_left_space :: proc(s: string) -> (res: string) { trim_left_space :: proc(s: string) -> (res: string) {
return trim_left_proc(s, is_space) return trim_left_proc(s, is_space)
} }
/* /*
Trims from the right until a valid non-space rune, "\t\txyz\t\t" -> "\t\txyz" Trims from the right until a valid non-space rune, "\t\txyz\t\t" -> "\t\txyz"
@@ -2544,6 +2540,7 @@ Returns:
trim_right_space :: proc(s: string) -> (res: string) { trim_right_space :: proc(s: string) -> (res: string) {
return trim_right_proc(s, is_space) return trim_right_proc(s, is_space)
} }
/* /*
Trims from both sides until a valid non-space rune, "\t\txyz\t\t" -> "xyz" Trims from both sides until a valid non-space rune, "\t\txyz\t\t" -> "xyz"
@@ -2556,6 +2553,7 @@ Returns:
trim_space :: proc(s: string) -> (res: string) { trim_space :: proc(s: string) -> (res: string) {
return trim_right_space(trim_left_space(s)) return trim_right_space(trim_left_space(s))
} }
/* /*
Trims null runes from the left, "\x00\x00testing\x00\x00" -> "testing\x00\x00" Trims null runes from the left, "\x00\x00testing\x00\x00" -> "testing\x00\x00"
@@ -2568,6 +2566,7 @@ Returns:
trim_left_null :: proc(s: string) -> (res: string) { trim_left_null :: proc(s: string) -> (res: string) {
return trim_left_proc(s, is_null) return trim_left_proc(s, is_null)
} }
/* /*
Trims null runes from the right, "\x00\x00testing\x00\x00" -> "\x00\x00testing" Trims null runes from the right, "\x00\x00testing\x00\x00" -> "\x00\x00testing"
@@ -2580,6 +2579,7 @@ Returns:
trim_right_null :: proc(s: string) -> (res: string) { trim_right_null :: proc(s: string) -> (res: string) {
return trim_right_proc(s, is_null) return trim_right_proc(s, is_null)
} }
/* /*
Trims null runes from both sides, "\x00\x00testing\x00\x00" -> "testing" Trims null runes from both sides, "\x00\x00testing\x00\x00" -> "testing"
@@ -2591,6 +2591,7 @@ Returns:
trim_null :: proc(s: string) -> (res: string) { trim_null :: proc(s: string) -> (res: string) {
return trim_right_null(trim_left_null(s)) return trim_right_null(trim_left_null(s))
} }
/* /*
Trims a `prefix` string from the start of the `s` string and returns the trimmed string Trims a `prefix` string from the start of the `s` string and returns the trimmed string
@@ -2623,6 +2624,7 @@ trim_prefix :: proc(s, prefix: string) -> (res: string) {
} }
return s return s
} }
/* /*
Trims a `suffix` string from the end of the `s` string and returns the trimmed string Trims a `suffix` string from the end of the `s` string and returns the trimmed string
@@ -2655,6 +2657,7 @@ trim_suffix :: proc(s, suffix: string) -> (res: string) {
} }
return s return s
} }
/* /*
Splits the input string `s` by all possible `substrs` and returns an allocated array of strings Splits the input string `s` by all possible `substrs` and returns an allocated array of strings
@@ -2727,6 +2730,7 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator
assert(len(results) == n) assert(len(results) == n)
return results[:], nil return results[:], nil
} }
/* /*
Splits the input string `s` by all possible `substrs` in an iterator fashion. The full string is returned if no match. Splits the input string `s` by all possible `substrs` in an iterator fashion. The full string is returned if no match.
@@ -2786,6 +2790,7 @@ split_multi_iterate :: proc(it: ^string, substrs: []string) -> (res: string, ok:
ok = true ok = true
return return
} }
/* /*
Replaces invalid UTF-8 characters in the input string with a specified replacement string. Adjacent invalid bytes are only replaced once. Replaces invalid UTF-8 characters in the input string with a specified replacement string. Adjacent invalid bytes are only replaced once.
@@ -2846,6 +2851,7 @@ scrub :: proc(s: string, replacement: string, allocator := context.allocator) ->
return to_string(b), nil return to_string(b), nil
} }
/* /*
Reverses the input string `s` Reverses the input string `s`
@@ -2889,6 +2895,7 @@ reverse :: proc(s: string, allocator := context.allocator, loc := #caller_locati
} }
return string(buf), nil return string(buf), nil
} }
/* /*
Expands the input string by replacing tab characters with spaces to align to a specified tab size Expands the input string by replacing tab characters with spaces to align to a specified tab size
@@ -2920,6 +2927,7 @@ Output:
abc1 abc2 abc3 abc1 abc2 abc3
*/ */
expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error {
if tab_size <= 0 { if tab_size <= 0 {
panic("tab size must be positive") panic("tab size must be positive")
@@ -2961,6 +2969,7 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) ->
return to_string(b), nil return to_string(b), nil
} }
/* /*
Splits the input string `str` by the separator `sep` string and returns 3 parts. The values are slices of the original string. Splits the input string `str` by the separator `sep` string and returns 3 parts. The values are slices of the original string.
@@ -3011,8 +3020,10 @@ partition :: proc(str, sep: string) -> (head, match, tail: string) {
tail = str[i+len(sep):] tail = str[i+len(sep):]
return return
} }
// Alias for centre_justify // Alias for centre_justify
center_justify :: centre_justify // NOTE(bill): Because Americans exist center_justify :: centre_justify // NOTE(bill): Because Americans exist
/* /*
Centers the input string within a field of specified length by adding pad string on both sides, if its length is less than the target length. Centers the input string within a field of specified length by adding pad string on both sides, if its length is less than the target length.
@@ -3048,6 +3059,7 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
return to_string(b), nil return to_string(b), nil
} }
/* /*
Left-justifies the input string within a field of specified length by adding pad string on the right side, if its length is less than the target length. Left-justifies the input string within a field of specified length by adding pad string on the right side, if its length is less than the target length.
@@ -3082,6 +3094,7 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context
return to_string(b), nil return to_string(b), nil
} }
/* /*
Right-justifies the input string within a field of specified length by adding pad string on the left side, if its length is less than the target length. Right-justifies the input string within a field of specified length by adding pad string on the left side, if its length is less than the target length.
@@ -3116,6 +3129,7 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex
return to_string(b), nil return to_string(b), nil
} }
/* /*
Writes a given pad string a specified number of times to an `io.Writer` Writes a given pad string a specified number of times to an `io.Writer`
@@ -3142,6 +3156,7 @@ write_pad_string :: proc(w: io.Writer, pad: string, pad_len, remains: int) {
p = p[width:] p = p[width:]
} }
} }
/* /*
Splits a string into a slice of substrings at each instance of one or more consecutive white space characters, as defined by `unicode.is_space` Splits a string into a slice of substrings at each instance of one or more consecutive white space characters, as defined by `unicode.is_space`
@@ -3203,6 +3218,7 @@ fields :: proc(s: string, allocator := context.allocator, loc := #caller_locatio
} }
return a, nil return a, nil
} }
/* /*
Splits a string into a slice of substrings at each run of unicode code points `r` satisfying the predicate `f(r)` Splits a string into a slice of substrings at each run of unicode code points `r` satisfying the predicate `f(r)`
@@ -3245,6 +3261,7 @@ fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.alloc
return substrings[:], nil return substrings[:], nil
} }
/* /*
Retrieves the first non-space substring from a mutable string reference and advances the reference. `s` is advanced from any space after the substring, or be an empty string if the substring was the remaining characters Retrieves the first non-space substring from a mutable string reference and advances the reference. `s` is advanced from any space after the substring, or be an empty string if the substring was the remaining characters
@@ -3283,6 +3300,7 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) {
s^ = s[len(s):] s^ = s[len(s):]
return return
} }
/* /*
Computes the Levenshtein edit distance between two strings Computes the Levenshtein edit distance between two strings
@@ -3460,4 +3478,4 @@ substring_to :: proc(s: string, rune_end: int) -> (sub: string, ok: bool) {
} }
return internal_substring(s, -1, rune_end) return internal_substring(s, -1, rune_end)
} }
@@ -82,7 +82,6 @@ Application_setActivationPolicy :: proc "c" (self: ^Application, activationPolic
// NOTE: this is technically deprecated but still actively used (Sokol, glfw, SDL, etc.) // NOTE: this is technically deprecated but still actively used (Sokol, glfw, SDL, etc.)
// and has no clear alternative although `activate` is what Apple tells you to use, // and has no clear alternative although `activate` is what Apple tells you to use,
// that does not work the same way. // that does not work the same way.
// @(deprecated="Use NSApplication method activate instead.")
@(objc_type=Application, objc_name="activateIgnoringOtherApps") @(objc_type=Application, objc_name="activateIgnoringOtherApps")
Application_activateIgnoringOtherApps :: proc "c" (self: ^Application, ignoreOtherApps: BOOL) { Application_activateIgnoringOtherApps :: proc "c" (self: ^Application, ignoreOtherApps: BOOL) {
msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps) msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps)
+1 -1
View File
@@ -1413,7 +1413,7 @@ umask :: proc "contextless" (mask: Mode) -> Mode {
Available since Linux 1.0. Available since Linux 1.0.
*/ */
gettimeofday :: proc "contextless" (tv: ^Time_Val) -> (Errno) { gettimeofday :: proc "contextless" (tv: ^Time_Val) -> (Errno) {
ret := syscall(SYS_gettimeofday, tv) ret := syscall(SYS_gettimeofday, tv, rawptr(nil))
return Errno(-ret) return Errno(-ret)
} }
-8
View File
@@ -75,14 +75,6 @@ LANGIDFROMLCID :: #force_inline proc "contextless" (lcid: LCID) -> LANGID {
return LANGID(lcid) return LANGID(lcid)
} }
// this one gave me trouble as it do not mask the values.
// the _ in the name is also off comparing to the c code
// i can't find any usage in the odin repo
@(deprecated = "use MAKEWORD")
MAKE_WORD :: #force_inline proc "contextless" (x, y: WORD) -> WORD {
return x << 8 | y
}
utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 { utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
if len(s) < 1 { if len(s) < 1 {
return nil return nil
+3 -3
View File
@@ -243,9 +243,9 @@ foreign ws2_32 {
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ntohs) // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ntohs)
ntohs :: proc(netshort: c_ushort) -> c_ushort --- ntohs :: proc(netshort: c_ushort) -> c_ushort ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htonl) // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htonl)
@(deprecated="Use endian specific integers instead, https://odin-lang.org/docs/overview/#basic-types") // Prefer using endian-specific integers instead, https://odin-lang.org/docs/overview/#basic-types
htonl :: proc(hostlong: c_ulong) -> c_ulong --- htonl :: proc(hostlong: c_ulong) -> c_ulong ---
// [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htons) // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htons)
@(deprecated="Use endian specific integers instead, https://odin-lang.org/docs/overview/#basic-types") // Prefer using endian-specific integers instead, https://odin-lang.org/docs/overview/#basic-types
htons :: proc(hostshort: c_ushort) -> c_ushort --- htons :: proc(hostshort: c_ushort) -> c_ushort ---
} }
+1 -6
View File
@@ -577,12 +577,7 @@ parse_tzif :: proc(_buffer: []u8, region_name: string, allocator := context.allo
footer_str := string(buffer[:end_idx]) footer_str := string(buffer[:end_idx])
// UTC is a special case, we don't need to alloc // UTC is a special case, we don't need to alloc
if len(local_time_types) == 1 { if len(local_time_types) == 1 && local_time_types[0].utoff == 0 {
name := cstring(raw_data(timezone_string_table[local_time_types[0].idx:]))
if name != "UTC" {
return
}
return nil, true return nil, true
} }
+2
View File
@@ -41,6 +41,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool
is_type_enum, is_type_enum,
is_type_proc, is_type_proc,
is_type_bit_set, is_type_bit_set,
is_type_bit_field,
is_type_simd_vector, is_type_simd_vector,
is_type_matrix, is_type_matrix,
@@ -6081,6 +6082,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case BuiltinProc_type_is_enum: case BuiltinProc_type_is_enum:
case BuiltinProc_type_is_proc: case BuiltinProc_type_is_proc:
case BuiltinProc_type_is_bit_set: case BuiltinProc_type_is_bit_set:
case BuiltinProc_type_is_bit_field:
case BuiltinProc_type_is_simd_vector: case BuiltinProc_type_is_simd_vector:
case BuiltinProc_type_is_matrix: case BuiltinProc_type_is_matrix:
case BuiltinProc_type_is_specialized_polymorphic_record: case BuiltinProc_type_is_specialized_polymorphic_record:
+1
View File
@@ -1370,6 +1370,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
e->Procedure.has_instrumentation = has_instrumentation; e->Procedure.has_instrumentation = has_instrumentation;
e->Procedure.no_sanitize_address = ac.no_sanitize_address; e->Procedure.no_sanitize_address = ac.no_sanitize_address;
e->Procedure.no_sanitize_memory = ac.no_sanitize_memory;
e->deprecated_message = ac.deprecated_message; e->deprecated_message = ac.deprecated_message;
e->warning_message = ac.warning_message; e->warning_message = ac.warning_message;
+14
View File
@@ -1593,6 +1593,20 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
error_line("\tSuggestion: Was '#partial switch' wanted?\n"); error_line("\tSuggestion: Was '#partial switch' wanted?\n");
} }
} }
if (build_context.strict_style) {
Token stok = ss->token;
for_array(i, bs->stmts) {
Ast *stmt = bs->stmts[i];
if (stmt->kind != Ast_CaseClause) {
continue;
}
Token ctok = stmt->CaseClause.token;
if (ctok.pos.column > stok.pos.column) {
error(ctok, "With '-strict-style', 'case' statements must share the same column as the 'switch' token");
}
}
}
} }
gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) {
+9 -3
View File
@@ -2054,7 +2054,7 @@ gb_internal void add_type_info_type(CheckerContext *c, Type *t) {
} }
gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
if (t == nullptr) { if (t == nullptr || c == nullptr) {
return; return;
} }
@@ -3776,6 +3776,12 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
} }
ac->no_sanitize_address = true; ac->no_sanitize_address = true;
return true; return true;
} else if (name == "no_sanitize_memory") {
if (value != nullptr) {
error(value, "'%.*s' expects no parameter", LIT(name));
}
ac->no_sanitize_memory = true;
return true;
} }
return false; return false;
} }
@@ -6672,7 +6678,7 @@ gb_internal void check_sort_init_and_fini_procedures(Checker *c) {
gb_internal void add_type_info_for_type_definitions(Checker *c) { gb_internal void add_type_info_for_type_definitions(Checker *c) {
for_array(i, c->info.definitions) { for_array(i, c->info.definitions) {
Entity *e = c->info.definitions[i]; Entity *e = c->info.definitions[i];
if (e->kind == Entity_TypeName && e->type != nullptr) { if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) {
i64 align = type_align_of(e->type); i64 align = type_align_of(e->type);
if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) { if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
add_type_info_type(&c->builtin_ctx, e->type); add_type_info_type(&c->builtin_ctx, e->type);
@@ -6794,7 +6800,7 @@ gb_internal void check_parsed_files(Checker *c) {
// NOTE(bill): Check for illegal cyclic type declarations // NOTE(bill): Check for illegal cyclic type declarations
for_array(i, c->info.definitions) { for_array(i, c->info.definitions) {
Entity *e = c->info.definitions[i]; Entity *e = c->info.definitions[i];
if (e->kind == Entity_TypeName && e->type != nullptr) { if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) {
(void)type_align_of(e->type); (void)type_align_of(e->type);
} else if (e->kind == Entity_Procedure) { } else if (e->kind == Entity_Procedure) {
DeclInfo *decl = e->decl_info; DeclInfo *decl = e->decl_info;
+1
View File
@@ -140,6 +140,7 @@ struct AttributeContext {
bool instrumentation_enter : 1; bool instrumentation_enter : 1;
bool instrumentation_exit : 1; bool instrumentation_exit : 1;
bool no_sanitize_address : 1; bool no_sanitize_address : 1;
bool no_sanitize_memory : 1;
bool rodata : 1; bool rodata : 1;
bool ignore_duplicates : 1; bool ignore_duplicates : 1;
u32 optimization_mode; // ProcedureOptimizationMode u32 optimization_mode; // ProcedureOptimizationMode
+2
View File
@@ -240,6 +240,7 @@ BuiltinProc__type_begin,
BuiltinProc__type_simple_boolean_begin, BuiltinProc__type_simple_boolean_begin,
BuiltinProc_type_is_boolean, BuiltinProc_type_is_boolean,
BuiltinProc_type_is_bit_field,
BuiltinProc_type_is_integer, BuiltinProc_type_is_integer,
BuiltinProc_type_is_rune, BuiltinProc_type_is_rune,
BuiltinProc_type_is_float, BuiltinProc_type_is_float,
@@ -630,6 +631,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+1
View File
@@ -263,6 +263,7 @@ struct Entity {
bool uses_branch_location : 1; bool uses_branch_location : 1;
bool is_anonymous : 1; bool is_anonymous : 1;
bool no_sanitize_address : 1; bool no_sanitize_address : 1;
bool no_sanitize_memory : 1;
} Procedure; } Procedure;
struct { struct {
Array<Entity *> entities; Array<Entity *> entities;
+11
View File
@@ -1054,9 +1054,20 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
} }
} }
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
return res;
} else if (value.value_compound->tav.type == elem_type) {
// Compound is of array item type; expand its value to all items in array.
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
for (isize i = 0; i < type->Array.count; i++) {
values[i] = lb_const_value(m, elem_type, value, cc).value;
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
return res; return res;
} else { } else {
// Assume that compound value is an array literal
GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count);
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
+1 -1
View File
@@ -345,7 +345,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
if (build_context.sanitizer_flags & SanitizerFlag_Address && !entity->Procedure.no_sanitize_address) { if (build_context.sanitizer_flags & SanitizerFlag_Address && !entity->Procedure.no_sanitize_address) {
lb_add_attribute_to_proc(m, p->value, "sanitize_address"); lb_add_attribute_to_proc(m, p->value, "sanitize_address");
} }
if (build_context.sanitizer_flags & SanitizerFlag_Memory) { if (build_context.sanitizer_flags & SanitizerFlag_Memory && !entity->Procedure.no_sanitize_memory) {
lb_add_attribute_to_proc(m, p->value, "sanitize_memory"); lb_add_attribute_to_proc(m, p->value, "sanitize_memory");
} }
if (build_context.sanitizer_flags & SanitizerFlag_Thread) { if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
+52 -52
View File
@@ -1996,39 +1996,39 @@ gb_internal void show_timings(Checker *c, Timings *t) {
if (build_context.show_debug_messages && build_context.show_more_timings) { if (build_context.show_debug_messages && build_context.show_more_timings) {
{ {
gb_printf("\n"); gb_printf_err("\n");
gb_printf("Total Lines - %td\n", lines); gb_printf_err("Total Lines - %td\n", lines);
gb_printf("Total Tokens - %td\n", tokens); gb_printf_err("Total Tokens - %td\n", tokens);
gb_printf("Total Files - %td\n", files); gb_printf_err("Total Files - %td\n", files);
gb_printf("Total Packages - %td\n", packages); gb_printf_err("Total Packages - %td\n", packages);
gb_printf("Total File Size - %td\n", total_file_size); gb_printf_err("Total File Size - %td\n", total_file_size);
gb_printf("\n"); gb_printf_err("\n");
} }
{ {
f64 time = total_tokenizing_time; f64 time = total_tokenizing_time;
gb_printf("Tokenization Only\n"); gb_printf_err("Tokenization Only\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/time); gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time);
gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines); gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time); gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time);
gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens); gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time); gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time);
gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024)); gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size); gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
gb_printf("\n"); gb_printf_err("\n");
} }
{ {
f64 time = total_parsing_time; f64 time = total_parsing_time;
gb_printf("Parsing Only\n"); gb_printf_err("Parsing Only\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/time); gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time);
gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines); gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time); gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time);
gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens); gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time); gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time);
gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024)); gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size); gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
gb_printf("\n"); gb_printf_err("\n");
} }
{ {
TimeStamp ts = {}; TimeStamp ts = {};
@@ -2041,16 +2041,16 @@ gb_internal void show_timings(Checker *c, Timings *t) {
GB_ASSERT(ts.label == "parse files"); GB_ASSERT(ts.label == "parse files");
f64 parse_time = time_stamp_as_s(ts, t->freq); f64 parse_time = time_stamp_as_s(ts, t->freq);
gb_printf("Parse pass\n"); gb_printf_err("Parse pass\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time); gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time);
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines); gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time); gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens); gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time); gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024)); gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024));
gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size); gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
gb_printf("\n"); gb_printf_err("\n");
} }
{ {
TimeStamp ts = {}; TimeStamp ts = {};
@@ -2071,27 +2071,27 @@ gb_internal void show_timings(Checker *c, Timings *t) {
ts.finish = ts_end.finish; ts.finish = ts_end.finish;
f64 parse_time = time_stamp_as_s(ts, t->freq); f64 parse_time = time_stamp_as_s(ts, t->freq);
gb_printf("Checker pass\n"); gb_printf_err("Checker pass\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time); gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time);
gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines); gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time); gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens); gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time); gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
gb_printf("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024)); gb_printf_err("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024));
gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size); gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
gb_printf("\n"); gb_printf_err("\n");
} }
{ {
f64 total_time = t->total_time_seconds; f64 total_time = t->total_time_seconds;
gb_printf("Total pass\n"); gb_printf_err("Total pass\n");
gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time); gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/total_time);
gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines); gb_printf_err("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines);
gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time); gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/total_time);
gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens); gb_printf_err("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens);
gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/total_time); gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/total_time);
gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024)); gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024));
gb_printf("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size); gb_printf_err("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size);
gb_printf("\n"); gb_printf_err("\n");
} }
} }
} }
+2 -2
View File
@@ -5794,7 +5794,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const
for (FileInfo fi : list) { for (FileInfo fi : list) {
String name = fi.name; String name = fi.name;
String ext = path_extension(name); String ext = path_extension(name);
if (ext == FILE_EXT) { if (ext == FILE_EXT && !path_is_directory(name)) {
files_with_ext += 1; files_with_ext += 1;
} }
if (ext == FILE_EXT && !is_excluded_target_filename(name)) { if (ext == FILE_EXT && !is_excluded_target_filename(name)) {
@@ -5819,7 +5819,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const
for (FileInfo fi : list) { for (FileInfo fi : list) {
String name = fi.name; String name = fi.name;
String ext = path_extension(name); String ext = path_extension(name);
if (ext == FILE_EXT) { if (ext == FILE_EXT && !path_is_directory(name)) {
if (is_excluded_target_filename(name)) { if (is_excluded_target_filename(name)) {
continue; continue;
} }
+2 -2
View File
@@ -197,7 +197,7 @@ gb_internal void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Mill
f64 total_time = time_stamp(t->total, t->freq, unit); f64 total_time = time_stamp(t->total, t->freq, unit);
gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n", gb_printf_err("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
LIT(t->total.label), LIT(t->total.label),
cast(int)(max_len-t->total.label.len), SPACES, cast(int)(max_len-t->total.label.len), SPACES,
total_time, total_time,
@@ -207,7 +207,7 @@ gb_internal void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Mill
for_array(i, t->sections) { for_array(i, t->sections) {
TimeStamp ts = t->sections[i]; TimeStamp ts = t->sections[i];
f64 section_time = time_stamp(ts, t->freq, unit); f64 section_time = time_stamp(ts, t->freq, unit);
gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n", gb_printf_err("%.*s%.*s - % 9.3f %s - %6.2f%%\n",
LIT(ts.label), LIT(ts.label),
cast(int)(max_len-ts.label.len), SPACES, cast(int)(max_len-ts.label.len), SPACES,
section_time, section_time,
@@ -43,6 +43,8 @@ Foo :: struct {
biggest: big.Int, biggest: big.Int,
smallest: big.Int, smallest: big.Int,
ignore_this: ^Foo `cbor:"-"`, ignore_this: ^Foo `cbor:"-"`,
mat: matrix[4, 4]f32,
vec: #simd [4]f64,
} }
FooBar :: enum { FooBar :: enum {
@@ -95,6 +97,8 @@ test_marshalling :: proc(t: ^testing.T) {
onetwenty = i128(12345), onetwenty = i128(12345),
small_onetwenty = -i128(max(u64)), small_onetwenty = -i128(max(u64)),
ignore_this = &Foo{}, ignore_this = &Foo{},
mat = 1,
vec = 2,
} }
big.atoi(&f.biggest, "1234567891011121314151617181920") big.atoi(&f.biggest, "1234567891011121314151617181920")
@@ -120,11 +124,35 @@ test_marshalling :: proc(t: ^testing.T) {
defer delete(diagnosis) defer delete(diagnosis)
testing.expect_value(t, diagnosis, `{ testing.expect_value(t, diagnosis, `{
"no": null, "no": null,
"mat": [
1.0000,
0.0000,
0.0000,
0.0000,
0.0000,
1.0000,
0.0000,
0.0000,
0.0000,
0.0000,
1.0000,
0.0000,
0.0000,
0.0000,
0.0000,
1.0000
],
"neg": -69, "neg": -69,
"nos": undefined, "nos": undefined,
"now": 1(1701117968), "now": 1(1701117968),
"pos": 1212, "pos": 1212,
"str": "Hellope", "str": "Hellope",
"vec": [
2.0000,
2.0000,
2.0000,
2.0000
],
"yes": true, "yes": true,
"comp": [ "comp": [
32.0000, 32.0000,
+1 -1
View File
@@ -1238,7 +1238,7 @@ test_count_digits :: proc(t: ^testing.T) {
buf: [64]u8 buf: [64]u8
for n in 0..<i64(base*base*base) { for n in 0..<i64(base*base*base) {
count := math.count_digits_of_base(n, base) count := math.count_digits_of_base(n, base)
str := strconv.append_int(buf[:], n, base) str := strconv.write_int(buf[:], n, base)
if !testing.expectf(t, if !testing.expectf(t,
len(str) == count, len(str) == count,
"decimal %i in base-%i digit count is %i, does not match length %i of %q", "decimal %i in base-%i digit count is %i, does not match length %i of %q",
+1
View File
@@ -17,6 +17,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style
..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_4364.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_5043.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5043.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b
+1
View File
@@ -18,6 +18,7 @@ $ODIN test ../test_issue_2615.odin $COMMON
$ODIN test ../test_issue_2637.odin $COMMON $ODIN test ../test_issue_2637.odin $COMMON
$ODIN test ../test_issue_2666.odin $COMMON $ODIN test ../test_issue_2666.odin $COMMON
$ODIN test ../test_issue_4210.odin $COMMON $ODIN test ../test_issue_4210.odin $COMMON
$ODIN test ../test_issue_4364.odin $COMMON
$ODIN test ../test_issue_4584.odin $COMMON $ODIN test ../test_issue_4584.odin $COMMON
if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then
echo "SUCCESSFUL 1/1" echo "SUCCESSFUL 1/1"
+18
View File
@@ -0,0 +1,18 @@
// Tests issue #4364 https://github.com/odin-lang/Odin/issues/4364
package test_issues
import "core:testing"
@test
test_const_array_fill_assignment :: proc(t: ^testing.T) {
MAGIC :: 12345
Struct :: struct {x: int}
CONST_ARR : [4]Struct : Struct{MAGIC}
arr := CONST_ARR
testing.expect_value(t, len(arr), 4)
testing.expect_value(t, arr[0], Struct{MAGIC})
testing.expect_value(t, arr[1], Struct{MAGIC})
testing.expect_value(t, arr[2], Struct{MAGIC})
testing.expect_value(t, arr[3], Struct{MAGIC})
}
+3 -3
View File
@@ -194,7 +194,7 @@ ICompiler_VTable :: struct {
using iunknown_vtable: IUnknown_VTable, using iunknown_vtable: IUnknown_VTable,
Compile: proc "system" ( Compile: proc "system" (
this: ^ICompiler, this: ^ICompiler,
pSource: ^Buffer, pSource: ^IBlob,
pSourceName: wstring, pSourceName: wstring,
pEntryPoint: wstring, pEntryPoint: wstring,
pTargetProfile: wstring, pTargetProfile: wstring,
@@ -206,7 +206,7 @@ ICompiler_VTable :: struct {
ppResult: ^^IOperationResult) -> HRESULT, ppResult: ^^IOperationResult) -> HRESULT,
Preprocess: proc "system" ( Preprocess: proc "system" (
this: ^ICompiler, this: ^ICompiler,
pSource: ^Buffer, pSource: ^IBlob,
pSourceName: wstring, pSourceName: wstring,
pArguments: [^]wstring, pArguments: [^]wstring,
argCount: u32, argCount: u32,
@@ -227,7 +227,7 @@ ICompiler2_VTable :: struct {
using idxccompiler_vtable: ^ICompiler_VTable, using idxccompiler_vtable: ^ICompiler_VTable,
CompileWithDebug: proc "system" ( CompileWithDebug: proc "system" (
this: ^ICompiler2, this: ^ICompiler2,
pSource: ^Buffer, pSource: ^IBlob,
pSourceName: wstring, pSourceName: wstring,
pEntryPoint: wstring, pEntryPoint: wstring,
pTargetProfile: wstring, pTargetProfile: wstring,