Merge remote-tracking branch 'offical/master'

This commit is contained in:
ed
2025-10-04 10:05:37 -04:00
82 changed files with 4715 additions and 1458 deletions
+1 -1
View File
@@ -275,7 +275,7 @@ foreign libc {
// 7.21.7 Character input/output functions
fgetc :: proc(stream: ^FILE) -> int ---
fgets :: proc(s: [^]char, n: int, stream: ^FILE) -> [^]char ---
fputc :: proc(s: cstring, stream: ^FILE) -> int ---
fputc :: proc(s: c.int, stream: ^FILE) -> int ---
getc :: proc(stream: ^FILE) -> int ---
getchar :: proc() -> int ---
putc :: proc(c: int, stream: ^FILE) -> int ---
+56 -10
View File
@@ -1,8 +1,8 @@
package container_small_array
import "base:builtin"
import "base:runtime"
_ :: runtime
@require import "base:intrinsics"
@require import "base:runtime"
/*
A fixed-size stack-allocated array operated on in a dynamic fashion.
@@ -169,7 +169,7 @@ Output:
x
*/
get_safe :: proc(a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check {
get_safe :: proc "contextless" (a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check {
if index < 0 || index >= a.len {
return {}, false
}
@@ -183,11 +183,11 @@ Get a pointer to the item at the specified position.
- `a`: A pointer to the small-array
- `index`: The position of the item to get
**Returns**
**Returns**
- the pointer to the element at the specified position
- true if element exists, false otherwise
*/
get_ptr_safe :: proc(a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check {
get_ptr_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check {
if index < 0 || index >= a.len {
return {}, false
}
@@ -231,7 +231,7 @@ Example:
fmt.println(small_array.slice(&a))
// resizing makes the change visible
small_array.resize(&a, 100)
small_array.non_zero_resize(&a, 100)
fmt.println(small_array.slice(&a))
}
@@ -250,6 +250,8 @@ set :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, item: T) {
/*
Tries to resize the small-array to the specified length.
The memory of added elements will be zeroed out.
The new length will be:
- `length` if `length` <= capacity
- capacity if length > capacity
@@ -259,7 +261,7 @@ The new length will be:
- `length`: The new desired length
Example:
import "core:container/small_array"
import "core:fmt"
@@ -269,7 +271,7 @@ Example:
small_array.push_back(&a, 1)
small_array.push_back(&a, 2)
fmt.println(small_array.slice(&a))
small_array.resize(&a, 1)
fmt.println(small_array.slice(&a))
@@ -278,12 +280,56 @@ Example:
}
Output:
[1, 2]
[1]
[1, 0, 0, 0, 0]
*/
resize :: proc "contextless" (a: ^$A/Small_Array($N, $T), length: int) {
prev_len := a.len
a.len = min(length, builtin.len(a.data))
if prev_len < a.len {
intrinsics.mem_zero(&a.data[prev_len], size_of(T)*(a.len-prev_len))
}
}
/*
Tries to resize the small-array to the specified length.
The new length will be:
- `length` if `length` <= capacity
- capacity if length > capacity
**Inputs**
- `a`: A pointer to the small-array
- `length`: The new desired length
Example:
import "core:container/small_array"
import "core:fmt"
non_zero_resize :: proc() {
a: small_array.Small_Array(5, int)
small_array.push_back(&a, 1)
small_array.push_back(&a, 2)
fmt.println(small_array.slice(&a))
small_array.non_zero_resize(&a, 1)
fmt.println(small_array.slice(&a))
small_array.non_zero_resize(&a, 100)
fmt.println(small_array.slice(&a))
}
Output:
[1, 2]
[1]
[1, 2, 0, 0, 0]
*/
resize :: proc "contextless" (a: ^$A/Small_Array, length: int) {
non_zero_resize :: proc "contextless" (a: ^$A/Small_Array, length: int) {
a.len = min(length, builtin.len(a.data))
}
+1
View File
@@ -1,3 +1,4 @@
#+test
package encoding_base32
import "core:testing"
+144 -2
View File
@@ -64,8 +64,16 @@ Image_Metadata :: union #shared_nil {
^QOI_Info,
^TGA_Info,
^BMP_Info,
^JPEG_Info,
}
Exif :: struct {
byte_order: enum {
little_endian,
big_endian,
},
data: []u8 `fmt:"-"`,
}
/*
@@ -112,8 +120,7 @@ Image_Option:
`.alpha_drop_if_present`
If the image has an alpha channel, drop it.
You may want to use `.alpha_
tiply` in this case.
You may want to use `.alpha_premultiply` in this case.
NOTE: For PNG, this also skips handling of the tRNS chunk, if present,
unless you select `alpha_premultiply`.
@@ -163,6 +170,7 @@ Error :: union #shared_nil {
PNG_Error,
QOI_Error,
BMP_Error,
JPEG_Error,
compress.Error,
compress.General_Error,
@@ -575,6 +583,140 @@ TGA_Info :: struct {
extension: Maybe(TGA_Extension),
}
/*
JPEG-specific
*/
JFIF_Magic := [?]byte{0x4A, 0x46, 0x49, 0x46} // "JFIF"
JFXX_Magic := [?]byte{0x4A, 0x46, 0x58, 0x58} // "JFXX"
Exif_Magic := [?]byte{0x45, 0x78, 0x69, 0x66} // "Exif"
JPEG_Error :: enum {
None = 0,
Duplicate_SOI_Marker,
Invalid_JFXX_Extension_Code,
Encountered_SOS_Before_SOF,
Invalid_Quantization_Table_Precision,
Invalid_Quantization_Table_Index,
Invalid_Huffman_Coefficient_Type,
Invalid_Huffman_Table_Index,
Unsupported_Frame_Type,
Invalid_Frame_Bit_Depth_Combo,
Invalid_Sampling_Factor,
Unsupported_12_Bit_Depth,
Multiple_SOS_Markers,
Encountered_RST_Marker_Outside_ECS,
Extra_Data_After_SOS, // Image seemed to have decoded okay, but there's more data after SOS
Invalid_Thumbnail_Size,
Huffman_Symbols_Exceeds_Max,
}
JFIF_Unit :: enum byte {
None = 0,
Dots_Per_Inch = 1,
Dots_Per_Centimeter = 2,
}
JFIF_APP0 :: struct {
version: u16be,
x_density: u16be,
y_density: u16be,
units: JFIF_Unit,
x_thumbnail: u8,
y_thumbnail: u8,
greyscale_thumbnail: bool,
thumbnail: []RGB_Pixel `fmt:"-"`,
}
JFXX_APP0 :: struct {
extension_code: JFXX_Extension_Code,
x_thumbnail: u8,
y_thumbnail: u8,
thumbnail: []byte `fmt:"-"`,
}
JFXX_Extension_Code :: enum u8 {
Thumbnail_JPEG = 0x10,
Thumbnail_1_Byte_Palette = 0x11,
Thumbnail_3_Byte_RGB = 0x13,
}
JPEG_Marker :: enum u8 {
SOF0 = 0xC0, // Baseline sequential DCT
SOF1 = 0xC1, // Extended sequential DCT
SOF2 = 0xC2, // Progressive DCT
SOF3 = 0xC3, // Lossless (sequential)
SOF5 = 0xC5, // Differential sequential DCT
SOF6 = 0xC6, // Differential progressive DCT
SOF7 = 0xC7, // Differential lossless (sequential)
SOF9 = 0xC9, // Extended sequential DCT, Arithmetic coding
SOF10 = 0xCA, // Progressive DCT, Arithmetic coding
SOF11 = 0xCB, // Lossless (sequential), Arithmetic coding
SOF13 = 0xCD, // Differential sequential DCT, Arithmetic coding
SOF14 = 0xCE, // Differential progressive DCT, Arithmetic coding
SOF15 = 0xCF, // Differential lossless (sequential), Arithmetic coding
DHT = 0xC4,
JPG = 0xC8,
DAC = 0xCC,
RST0 = 0xD0,
RST1 = 0xD1,
RST2 = 0xD2,
RST3 = 0xD3,
RST4 = 0xD4,
RST5 = 0xD5,
RST6 = 0xD6,
RST7 = 0xD7,
SOI = 0xD8,
EOI = 0xD9,
SOS = 0xDA,
DQT = 0xDB,
DNL = 0xDC,
DRI = 0xDD,
DHP = 0xDE,
EXP = 0xDF,
APP0 = 0xE0,
APP1 = 0xE1,
APP2 = 0xE2,
APP3 = 0xE3,
APP4 = 0xE4,
APP5 = 0xE5,
APP6 = 0xE6,
APP7 = 0xE7,
APP8 = 0xE8,
APP9 = 0xE9,
APP10 = 0xEA,
APP11 = 0xEB,
APP12 = 0xEC,
APP13 = 0xED,
APP14 = 0xEE,
APP15 = 0xEF,
JPG0 = 0xF0,
JPG1 = 0xF1,
JPG2 = 0xF2,
JPG3 = 0xF3,
JPG4 = 0xF4,
JPG5 = 0xF5,
JPG6 = 0xF6,
JPG7 = 0xF7,
JPG8 = 0xF8,
JPG9 = 0xF9,
JPG10 = 0xFA,
JPG11 = 0xFB,
JPG12 = 0xFC,
JPG13 = 0xFD,
COM = 0xFE,
TEM = 0x01,
}
JPEG_Info :: struct {
jfif_app0: Maybe(JFIF_APP0),
jfxx_app0: Maybe(JFXX_APP0),
comments: [dynamic]string,
exif: [dynamic]Exif,
frame_type: JPEG_Marker,
}
// Function to help with image buffer calculations
compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) {
size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height
+1 -1
View File
@@ -147,7 +147,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
return .JPEG
case s[:3] == "\xff\xd8\xff":
switch s[3] {
case 0xdb, 0xee, 0xe1, 0xe0:
case 0xdb, 0xee, 0xe1, 0xe0, 0xfe, 0xed:
return .JPEG
}
switch {
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
package jpeg
load :: proc{load_from_bytes, load_from_context}
+18
View File
@@ -0,0 +1,18 @@
package jpeg
import "core:os"
load :: proc{load_from_file, load_from_bytes, load_from_context}
load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
context.allocator = allocator
data, ok := os.read_entire_file(filename)
defer delete(data)
if ok {
return load_from_bytes(data, options)
} else {
return nil, .Unable_To_Read_File
}
}
+2 -2
View File
@@ -366,7 +366,7 @@ chrm :: proc(c: image.PNG_Chunk) -> (res: cHRM, ok: bool) {
return
}
exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
exif :: proc(c: image.PNG_Chunk) -> (res: image.Exif, ok: bool) {
ok = true
@@ -396,4 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
General helper functions
*/
compute_buffer_size :: image.compute_buffer_size
compute_buffer_size :: image.compute_buffer_size
+5 -9
View File
@@ -138,14 +138,6 @@ Text :: struct {
text: string,
}
Exif :: struct {
byte_order: enum {
little_endian,
big_endian,
},
data: []u8,
}
iCCP :: struct {
name: string,
profile: []u8,
@@ -250,10 +242,14 @@ read_header :: proc(ctx: ^$C) -> (image.PNG_IHDR, Error) {
header := (^image.PNG_IHDR)(raw_data(c.data))^
// Validate IHDR
using header
if width == 0 || height == 0 || u128(width) * u128(height) > image.MAX_DIMENSIONS {
if width == 0 || height == 0 {
return {}, .Invalid_Image_Dimensions
}
if u128(width) * u128(height) > image.MAX_DIMENSIONS {
return {}, .Image_Dimensions_Too_Large
}
if compression_method != 0 {
return {}, compress.General_Error.Unknown_Compression_Method
}
+17
View File
@@ -189,6 +189,23 @@ write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false,
write_encoded_rune(w, r, false, &n) or_return
return
}
if r < 32 && for_json {
switch r {
case '\b': write_string(w, `\b`, &n) or_return
case '\f': write_string(w, `\f`, &n) or_return
case '\n': write_string(w, `\n`, &n) or_return
case '\r': write_string(w, `\r`, &n) or_return
case '\t': write_string(w, `\t`, &n) or_return
case:
write_byte(w, '\\', &n) or_return
write_byte(w, 'u', &n) or_return
write_byte(w, '0', &n) or_return
write_byte(w, '0', &n) or_return
write_byte(w, DIGITS_LOWER[r>>4 & 0xf], &n) or_return
write_byte(w, DIGITS_LOWER[r & 0xf], &n) or_return
}
return
}
switch r {
case '\a': write_string(w, `\a`, &n) or_return
case '\b': write_string(w, `\b`, &n) or_return
+1 -12
View File
@@ -14,23 +14,12 @@ import "base:intrinsics"
This allows to benchmark and/or setting optimized values for a certain CPU without recompiling.
*/
/*
========================== TUNABLES ==========================
`initialize_constants` returns `#config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF)`
and we initialize this cutoff that way so that the procedure is used and called,
because it handles initializing the constants ONE, ZERO, MINUS_ONE, NAN and INF.
`initialize_constants` also replaces the other `_DEFAULT_*` cutoffs with custom compile-time values if so `#config`ured.
*/
/*
There is a bug with DLL globals. They don't get set.
To allow tests to run we add `-define:MATH_BIG_EXE=false` to hardcode the cutoffs for now.
*/
when #config(MATH_BIG_EXE, true) {
MUL_KARATSUBA_CUTOFF := initialize_constants()
MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF
+11 -8
View File
@@ -778,13 +778,14 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
*/
INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
@(init, private)
_init_constants :: proc "contextless" () {
initialize_constants()
}
@(private)
constant_allocator: runtime.Allocator
initialize_constants :: proc "contextless" () -> (res: int) {
@(init, private)
initialize_constants :: proc "contextless" () {
context = runtime.default_context()
constant_allocator = context.allocator
internal_int_set_from_integer( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
internal_int_set_from_integer( INT_ONE, 1); INT_ONE.flags = {.Immutable}
internal_int_set_from_integer(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
@@ -796,15 +797,17 @@ initialize_constants :: proc "contextless" () -> (res: int) {
internal_int_set_from_integer( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
internal_int_set_from_integer( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf}
internal_int_set_from_integer(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
return _DEFAULT_MUL_KARATSUBA_CUTOFF
}
/*
Destroy constants.
Optional for an EXE, as this would be called at the very end of a process.
*/
destroy_constants :: proc() {
@(fini, private)
destroy_constants :: proc "contextless" () {
context = runtime.default_context()
context.allocator = constant_allocator
internal_destroy(INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN)
}
+8 -8
View File
@@ -1819,18 +1819,18 @@ memory region.
*/
@(require_results)
dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
n := align_formula(size, a.alignment)
if n > a.block_size {
return nil, .Invalid_Argument
}
if n >= a.out_band_size {
assert(a.block_allocator.procedure != nil, "Backing block allocator must be initialized", loc=loc)
memory, err := alloc_bytes_non_zeroed(a.block_size, a.alignment, a.block_allocator, loc)
if size >= a.out_band_size {
assert(a.out_band_allocations.allocator.procedure != nil, "Backing array allocator must be initialized", loc=loc)
memory, err := alloc_bytes_non_zeroed(size, a.alignment, a.out_band_allocations.allocator, loc)
if memory != nil {
append(&a.out_band_allocations, raw_data(memory), loc = loc)
}
return memory, err
}
n := align_formula(size, a.alignment)
if n > a.block_size {
return nil, .Invalid_Argument
}
if a.bytes_left < n {
err := _dynamic_arena_cycle_new_block(a, loc)
if err != nil {
@@ -1867,7 +1867,7 @@ dynamic_arena_reset :: proc(a: ^Dynamic_Arena, loc := #caller_location) {
}
clear(&a.used_blocks)
for allocation in a.out_band_allocations {
free(allocation, a.block_allocator, loc=loc)
free(allocation, a.out_band_allocations.allocator, loc=loc)
}
clear(&a.out_band_allocations)
a.bytes_left = 0 // Make new allocations call `_dynamic_arena_cycle_new_block` again.
+16 -2
View File
@@ -108,6 +108,16 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
}
sync.mutex_guard(&arena.mutex)
return arena_alloc_unguarded(arena, size, alignment, loc)
}
// Allocates memory from the provided arena.
@(require_results, no_sanitize_address, private)
arena_alloc_unguarded :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
size := size
if size == 0 {
return nil, nil
}
switch arena.kind {
case .Growing:
@@ -345,7 +355,11 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
case size == 0:
err = .Mode_Not_Implemented
return
case uintptr(old_data) & uintptr(alignment-1) == 0:
}
sync.mutex_guard(&arena.mutex)
if uintptr(old_data) & uintptr(alignment-1) == 0 {
if size < old_size {
// shrink data in-place
data = old_data[:size]
@@ -369,7 +383,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
}
}
new_memory := arena_alloc(arena, size, alignment, location) or_return
new_memory := arena_alloc_unguarded(arena, size, alignment, location) or_return
if new_memory == nil {
return
}
+1 -1
View File
@@ -2485,7 +2485,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
allow_token(p, .Comma) or_break
}
close := expect_token(p, .Close_Brace)
close := expect_closing_brace_of_field_list(p)
if len(args) == 0 {
error(p, tok.pos, "expected at least 1 argument in procedure group")
+5 -7
View File
@@ -18,7 +18,7 @@ create_temp_file :: proc(dir, pattern: string) -> (f: ^File, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
dir := dir if dir != "" else temp_directory(temp_allocator) or_return
prefix, suffix := _prefix_and_suffix(pattern) or_return
prefix = temp_join_path(dir, prefix) or_return
prefix = temp_join_path(dir, prefix, temp_allocator) or_return
rand_buf: [10]byte
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator)
@@ -50,7 +50,7 @@ make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator)
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
dir := dir if dir != "" else temp_directory(temp_allocator) or_return
prefix, suffix := _prefix_and_suffix(pattern) or_return
prefix = temp_join_path(dir, prefix) or_return
prefix = temp_join_path(dir, prefix, temp_allocator) or_return
rand_buf: [10]byte
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator)
@@ -88,12 +88,10 @@ temp_directory :: proc(allocator: runtime.Allocator) -> (string, Error) {
@(private="file")
temp_join_path :: proc(dir, name: string) -> (string, runtime.Allocator_Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
temp_join_path :: proc(dir, name: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
if len(dir) > 0 && is_path_separator(dir[len(dir)-1]) {
return concatenate({dir, name}, temp_allocator,)
return concatenate({dir, name}, allocator)
}
return concatenate({dir, Path_Separator_String, name}, temp_allocator)
return concatenate({dir, Path_Separator_String, name}, allocator)
}
+13 -16
View File
@@ -32,7 +32,6 @@ is_UNC :: proc(path: string) -> bool {
return volume_name_len(path) > 2
}
is_abs :: proc(path: string) -> bool {
if is_reserved_name(path) {
return true
@@ -50,7 +49,6 @@ is_abs :: proc(path: string) -> bool {
return is_slash(path[0])
}
@(private)
temp_full_path :: proc(name: string) -> (path: string, err: os.Error) {
ta := context.temp_allocator
@@ -76,8 +74,6 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) {
return win32.utf16_to_utf8(buf[:n], ta)
}
abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
full_path, err := temp_full_path(path)
@@ -88,17 +84,16 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
return p, true
}
join :: proc(elems: []string, allocator := context.allocator) -> string {
join :: proc(elems: []string, allocator := context.allocator) -> (string, runtime.Allocator_Error) #optional_allocator_error {
for e, i in elems {
if e != "" {
return join_non_empty(elems[i:], allocator)
}
}
return ""
return "", nil
}
join_non_empty :: proc(elems: []string, allocator := context.allocator) -> string {
join_non_empty :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) {
context.allocator = allocator
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
@@ -110,23 +105,25 @@ join_non_empty :: proc(elems: []string, allocator := context.allocator) -> strin
break
}
}
s := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator)
s = strings.concatenate({elems[0], s}, context.temp_allocator)
s := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return
s = strings.concatenate({elems[0], s}, context.temp_allocator) or_return
return clean(s)
}
p := clean(strings.join(elems, SEPARATOR_STRING, context.temp_allocator))
p := strings.join(elems, SEPARATOR_STRING, context.temp_allocator) or_return
p = clean(p) or_return
if !is_UNC(p) {
return p
return p, nil
}
head := clean(elems[0], context.temp_allocator)
head := clean(elems[0], context.temp_allocator) or_return
if is_UNC(head) {
return p
return p, nil
}
delete(p) // It is not needed now
tail := clean(strings.join(elems[1:], SEPARATOR_STRING, context.temp_allocator), context.temp_allocator)
tail := strings.join(elems[1:], SEPARATOR_STRING, context.temp_allocator) or_return
tail = clean(tail, context.temp_allocator) or_return
if head[len(head)-1] == SEPARATOR {
return strings.concatenate({head, tail})
}
+7
View File
@@ -1655,6 +1655,13 @@ Output:
write_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
return string(generic_ftoa(buf, f, fmt, prec, bit_size))
}
// Accepts '0'..='9', otherwise returns ok = false
digit_to_int :: proc(r: rune) -> (value: int, ok: bool) {
if '0' <= r && r <= '9' {
return int(r - '0'), true
}
return -1, false
}
/*
Writes a quoted string representation of the input string to a given byte slice and returns the result as a string
+6 -6
View File
@@ -296,8 +296,8 @@ Inputs:
Returns:
- res: A cstring of the Builder's buffer
*/
unsafe_to_cstring :: proc(b: ^Builder) -> (res: cstring) {
append(&b.buf, 0)
unsafe_to_cstring :: proc(b: ^Builder, loc := #caller_location) -> (res: cstring) {
append(&b.buf, 0, loc)
pop(&b.buf)
return cstring(raw_data(b.buf))
}
@@ -311,8 +311,8 @@ Returns:
- res: A cstring of the Builder's buffer upon success
- err: An optional allocator error if one occured, `nil` otherwise
*/
to_cstring :: proc(b: ^Builder) -> (res: cstring, err: mem.Allocator_Error) #optional_allocator_error {
n := append(&b.buf, 0) or_return
to_cstring :: proc(b: ^Builder, loc := #caller_location) -> (res: cstring, err: mem.Allocator_Error) #optional_allocator_error {
n := append(&b.buf, 0, loc) or_return
if n != 1 {
return nil, .Out_Of_Memory
}
@@ -518,9 +518,9 @@ Output:
abc
*/
write_string :: proc(b: ^Builder, s: string) -> (n: int) {
write_string :: proc(b: ^Builder, s: string, loc := #caller_location) -> (n: int) {
n0 := len(b.buf)
append(&b.buf, s)
append(&b.buf, s, loc)
n1 := len(b.buf)
return n1-n0
}
+4 -2
View File
@@ -1,10 +1,12 @@
package CoreFoundation
import "core:c"
foreign import CoreFoundation "system:CoreFoundation.framework"
String :: distinct TypeRef // same as CFStringRef
StringEncoding :: distinct u32
StringEncoding :: distinct c.long
StringBuiltInEncodings :: enum StringEncoding {
MacRoman = 0,
@@ -171,7 +173,7 @@ foreign CoreFoundation {
// Fetches a range of the characters from a string into a byte buffer after converting the characters to a specified encoding.
StringGetBytes :: proc(thestring: String, range: Range, encoding: StringEncoding, lossByte: u8, isExternalRepresentation: b8, buffer: [^]byte, maxBufLen: Index, usedBufLen: ^Index) -> Index ---
StringIsEncodingAvailable :: proc(encoding: StringEncoding) -> bool ---
StringIsEncodingAvailable :: proc(encoding: StringEncoding) -> b8 ---
@(link_name = "__CFStringMakeConstantString")
StringMakeConstantString :: proc "c" (#const c: cstring) -> String ---
+15 -3
View File
@@ -50,10 +50,22 @@ NotificationCenter_defaultCenter :: proc "c" () -> ^NotificationCenter {
return msgSend(^NotificationCenter, NotificationCenter, "defaultCenter")
}
@(objc_type=NotificationCenter, objc_name="addObserver")
NotificationCenter_addObserverName :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Block) -> ^Object {
return msgSend(^Object, self, "addObserverName:object:queue:block:", name, pObj, pQueue, block)
@(objc_type=NotificationCenter, objc_name="addObserverForName")
NotificationCenter_addObserverForName :: proc{NotificationCenter_addObserverForName_old, NotificationCenter_addObserverForName_new}
NotificationCenter_addObserverForName_old :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Block) -> ^Object {
return msgSend(^Object, self, "addObserverForName:object:queue:usingBlock:", name, pObj, pQueue, block)
}
NotificationCenter_addObserverForName_new :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Objc_Block) -> ^Object {
return msgSend(^Object, self, "addObserverForName:object:queue:usingBlock:", name, pObj, pQueue, block)
}
@(objc_type=NotificationCenter, objc_name="addObserver")
NotificationCenter_addObserver :: proc "c" (self: ^NotificationCenter, observer: ^Object, selector: SEL, name: NotificationName, object: ^Object) {
msgSend(nil, self, "addObserver:selector:name:object:", observer, selector, name, object)
}
@(objc_type=NotificationCenter, objc_name="removeObserver")
NotificationCenter_removeObserver :: proc "c" (self: ^NotificationCenter, pObserver: ^Object) {
msgSend(nil, self, "removeObserver:", pObserver)
-1
View File
@@ -30,7 +30,6 @@ Example:
fmt.printfln("OS: %v", si.os_version.as_string)
fmt.printfln("OS: %#v", si.os_version)
fmt.printfln("CPU: %v", si.cpu.name)
fmt.printfln("CPU: %v", si.cpu.name)
fmt.printfln("CPU cores: %vc/%vt", si.cpu.physical_cores, si.cpu.logical_cores)
fmt.printfln("RAM: %#.1M", si.ram.total_ram)
-1
View File
@@ -50,7 +50,6 @@ foreign lib {
af: AF, // INET or INET6
src: cstring,
dst: rawptr, // either ^in_addr or ^in_addr6
size: socklen_t, // size_of(dst^)
) -> pton_result ---
}
+2 -2
View File
@@ -124,7 +124,7 @@ foreign lib {
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getscope.html ]]
*/
pthread_attr_setscope :: proc(attr: ^pthread_attr_t, contentionscope: ^Thread_Scope) -> Errno ---
pthread_attr_setscope :: proc(attr: ^pthread_attr_t, contentionscope: Thread_Scope) -> Errno ---
/*
Get the area of storage to be used for the created thread's stack.
@@ -400,7 +400,7 @@ when ODIN_OS == .Darwin {
PTHREAD_SCOPE_PROCESS :: 2
PTHREAD_SCOPE_SYSTEM :: 1
pthread_t :: distinct u64
pthread_t :: distinct rawptr
pthread_attr_t :: struct {
__sig: c.long,
+6 -1
View File
@@ -92,7 +92,12 @@ foreign lib {
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html ]]
*/
shm_open :: proc(name: cstring, oflag: O_Flags, mode: mode_t) -> FD ---
when ODIN_OS == .Darwin {
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/shm_open.2.html
shm_open :: proc(name: cstring, oflag: O_Flags, #c_vararg args: ..any) -> FD ---
} else {
shm_open :: proc(name: cstring, oflag: O_Flags, mode: mode_t) -> FD ---
}
/*
Removes a shared memory object.
+2
View File
@@ -413,6 +413,7 @@ foreign kernel32 {
lpBytesLeftThisMessage: ^u32,
) -> BOOL ---
CancelIo :: proc(handle: HANDLE) -> BOOL ---
CancelIoEx :: proc(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL ---
GetOverlappedResult :: proc(
hFile: HANDLE,
lpOverlapped: LPOVERLAPPED,
@@ -554,6 +555,7 @@ foreign kernel32 {
GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL ---
RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT ---
RtlNtStatusToDosError :: proc(status: NTSTATUS) -> ULONG ---
GetSystemPowerStatus :: proc(lpSystemPowerStatus: ^SYSTEM_POWER_STATUS) -> BOOL ---
}
+2
View File
@@ -222,9 +222,11 @@ ERROR_LOCK_FAILED : DWORD : 167
ERROR_ALREADY_EXISTS : DWORD : 183
ERROR_NO_DATA : DWORD : 232
ERROR_ENVVAR_NOT_FOUND : DWORD : 203
ERROR_MR_MID_NOT_FOUND : DWORD : 317
ERROR_OPERATION_ABORTED : DWORD : 995
ERROR_IO_PENDING : DWORD : 997
ERROR_NO_UNICODE_TRANSLATION : DWORD : 1113
ERROR_NOT_FOUND : DWORD : 1168
ERROR_TIMEOUT : DWORD : 1460
ERROR_DATATYPE_MISMATCH : DWORD : 1629
ERROR_UNSUPPORTED_TYPE : DWORD : 1630
+12 -4
View File
@@ -24,10 +24,18 @@ import "core:terminal/ansi"
@(private="file") stop_test_passed: libc.sig_atomic_t
@(private="file") stop_test_alert: libc.sig_atomic_t
@(private="file", thread_local)
local_test_index: libc.sig_atomic_t
@(private="file", thread_local)
local_test_index_set: bool
when ODIN_ARCH == .i386 && ODIN_OS == .Windows {
// Thread-local storage is problematic on Windows i386
@(private="file")
local_test_index: libc.sig_atomic_t
@(private="file")
local_test_index_set: bool
} else {
@(private="file", thread_local)
local_test_index: libc.sig_atomic_t
@(private="file", thread_local)
local_test_index_set: bool
}
// Windows does not appear to have a SIGTRAP, so this is defined here, instead
// of in the libc package, just so there's no confusion about it being
+1 -1
View File
@@ -24,7 +24,7 @@ _sleep :: proc "contextless" (d: Duration) {
_tick_now :: proc "contextless" () -> Tick {
foreign odin_env {
tick_now :: proc "contextless" () -> f32 ---
tick_now :: proc "contextless" () -> f64 ---
}
return Tick{i64(tick_now()*1e6)}
}