Merge tag 'dev-2025-09'

This commit is contained in:
ed
2025-09-14 10:09:53 -04:00
172 changed files with 5296 additions and 851 deletions
+59 -14
View File
@@ -47,20 +47,15 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1 - name: (Linux) Download LLVM and Build Odin
with:
branch: edge
- name: (Linux) Download LLVM
run: | run: |
apk add --no-cache \ docker run --rm -v "$PWD:/src" -w /src alpine sh -c '
musl-dev llvm20-dev clang20 git mold lz4 \ apk add --no-cache \
libxml2-static llvm20-static zlib-static zstd-static \ musl-dev llvm20-dev clang20 git mold lz4 \
make libxml2-static llvm20-static zlib-static zstd-static \
shell: alpine.sh --root {0} make &&
- name: build odin ./ci/build_linux_static.sh
# NOTE: this build does slow compile times because of musl '
run: ci/build_linux_static.sh
shell: alpine.sh {0}
- name: Odin run - name: Odin run
run: ./odin run examples/demo run: ./odin run examples/demo
- name: Copy artifacts - name: Copy artifacts
@@ -74,6 +69,7 @@ jobs:
cp -r core $FILE cp -r core $FILE
cp -r vendor $FILE cp -r vendor $FILE
cp -r examples $FILE cp -r examples $FILE
./ci/remove_windows_binaries.sh $FILE
# Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38 # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
tar -czvf dist.tar.gz $FILE tar -czvf dist.tar.gz $FILE
- name: Odin run - name: Odin run
@@ -85,6 +81,46 @@ jobs:
with: with:
name: linux_artifacts name: linux_artifacts
path: dist.tar.gz path: dist.tar.gz
build_linux_arm:
name: Linux ARM Build
if: github.repository == 'odin-lang/Odin'
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- name: (Linux ARM) Download LLVM and Build Odin
run: |
docker run --rm -v "$PWD:/src" -w /src arm64v8/alpine sh -c '
apk add --no-cache \
musl-dev llvm20-dev clang20 git mold lz4 \
libxml2-static llvm20-static zlib-static zstd-static \
make &&
./ci/build_linux_static.sh
'
- name: Odin run
run: ./odin run examples/demo
- name: Copy artifacts
run: |
FILE="odin-linux-arm64-nightly+$(date -I)"
mkdir $FILE
cp odin $FILE
cp LICENSE $FILE
cp -r shared $FILE
cp -r base $FILE
cp -r core $FILE
cp -r vendor $FILE
cp -r examples $FILE
./ci/remove_windows_binaries.sh $FILE
# Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
tar -czvf dist.tar.gz $FILE
- name: Odin run
run: |
FILE="odin-linux-arm64-nightly+$(date -I)"
$FILE/odin run examples/demo
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: linux_arm_artifacts
path: dist.tar.gz
build_macos: build_macos:
name: MacOS Build name: MacOS Build
if: github.repository == 'odin-lang/Odin' if: github.repository == 'odin-lang/Odin'
@@ -111,6 +147,7 @@ jobs:
cp -r core $FILE cp -r core $FILE
cp -r vendor $FILE cp -r vendor $FILE
cp -r examples $FILE cp -r examples $FILE
./ci/remove_windows_binaries.sh $FILE
dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs
# Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38 # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
tar -czvf dist.tar.gz $FILE tar -czvf dist.tar.gz $FILE
@@ -149,6 +186,7 @@ jobs:
cp -r core $FILE cp -r core $FILE
cp -r vendor $FILE cp -r vendor $FILE
cp -r examples $FILE cp -r examples $FILE
./ci/remove_windows_binaries.sh $FILE
dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs
# Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38 # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
tar -czvf dist.tar.gz $FILE tar -czvf dist.tar.gz $FILE
@@ -163,7 +201,7 @@ jobs:
path: dist.tar.gz path: dist.tar.gz
upload_b2: upload_b2:
runs-on: [ubuntu-latest] runs-on: [ubuntu-latest]
needs: [build_windows, build_macos, build_macos_arm, build_linux] needs: [build_windows, build_macos, build_macos_arm, build_linux, build_linux_arm]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5 - uses: actions/setup-python@v5
@@ -192,6 +230,12 @@ jobs:
name: linux_artifacts name: linux_artifacts
path: linux_artifacts path: linux_artifacts
- name: Download Ubuntu ARM artifacts
uses: actions/download-artifact@v4.1.7
with:
name: linux_arm_artifacts
path: linux_arm_artifacts
- name: Download macOS artifacts - name: Download macOS artifacts
uses: actions/download-artifact@v4.1.7 uses: actions/download-artifact@v4.1.7
with: with:
@@ -219,6 +263,7 @@ jobs:
file linux_artifacts/dist.tar.gz file linux_artifacts/dist.tar.gz
python3 ci/nightly.py artifact windows-amd64 windows_artifacts/ python3 ci/nightly.py artifact windows-amd64 windows_artifacts/
python3 ci/nightly.py artifact linux-amd64 linux_artifacts/dist.tar.gz python3 ci/nightly.py artifact linux-amd64 linux_artifacts/dist.tar.gz
python3 ci/nightly.py artifact linux-arm64 linux_arm_artifacts/dist.tar.gz
python3 ci/nightly.py artifact macos-amd64 macos_artifacts/dist.tar.gz python3 ci/nightly.py artifact macos-amd64 macos_artifacts/dist.tar.gz
python3 ci/nightly.py artifact macos-arm64 macos_arm_artifacts/dist.tar.gz python3 ci/nightly.py artifact macos-arm64 macos_arm_artifacts/dist.tar.gz
python3 ci/nightly.py prune python3 ci/nightly.py prune
+5
View File
@@ -141,6 +141,7 @@ type_is_quaternion :: proc($T: typeid) -> bool ---
type_is_string :: proc($T: typeid) -> bool --- type_is_string :: proc($T: typeid) -> bool ---
type_is_typeid :: proc($T: typeid) -> bool --- type_is_typeid :: proc($T: typeid) -> bool ---
type_is_any :: proc($T: typeid) -> bool --- type_is_any :: proc($T: typeid) -> bool ---
type_is_string16 :: proc($T: typeid) -> bool ---
type_is_endian_platform :: proc($T: typeid) -> bool --- type_is_endian_platform :: proc($T: typeid) -> bool ---
type_is_endian_little :: proc($T: typeid) -> bool --- type_is_endian_little :: proc($T: typeid) -> bool ---
@@ -232,6 +233,9 @@ type_integer_to_signed :: proc($T: typeid) -> type where type_is_integer(T), t
type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) --- type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) ---
// Returns the canonicalized name of the type, of which is used to produce the pseudo-unique 'typeid'
type_canonical_name :: proc($T: typeid) -> string ---
constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
constant_log2 :: proc($v: $T) -> T where type_is_integer(T) --- constant_log2 :: proc($v: $T) -> T where type_is_integer(T) ---
@@ -380,6 +384,7 @@ objc_register_selector :: proc($name: string) -> objc_SEL ---
objc_find_class :: proc($name: string) -> objc_Class --- objc_find_class :: proc($name: string) -> objc_Class ---
objc_register_class :: proc($name: string) -> objc_Class --- objc_register_class :: proc($name: string) -> objc_Class ---
objc_ivar_get :: proc(self: ^$T) -> ^$U --- objc_ivar_get :: proc(self: ^$T) -> ^$U ---
objc_block :: proc(invoke: $T, ..any) -> ^Objc_Block(T) where type_is_proc(T) ---
valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, a3, a4: uintptr) -> uintptr --- valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, a3, a4: uintptr) -> uintptr ---
+17 -1
View File
@@ -61,6 +61,11 @@ Type_Info_Struct_Soa_Kind :: enum u8 {
Dynamic = 3, Dynamic = 3,
} }
Type_Info_String_Encoding_Kind :: enum u8 {
UTF_8 = 0,
UTF_16 = 1,
}
// Variant Types // Variant Types
Type_Info_Named :: struct { Type_Info_Named :: struct {
name: string, name: string,
@@ -73,7 +78,7 @@ Type_Info_Rune :: struct {}
Type_Info_Float :: struct {endianness: Platform_Endianness} Type_Info_Float :: struct {endianness: Platform_Endianness}
Type_Info_Complex :: struct {} Type_Info_Complex :: struct {}
Type_Info_Quaternion :: struct {} Type_Info_Quaternion :: struct {}
Type_Info_String :: struct {is_cstring: bool} Type_Info_String :: struct {is_cstring: bool, encoding: Type_Info_String_Encoding_Kind}
Type_Info_Boolean :: struct {} Type_Info_Boolean :: struct {}
Type_Info_Any :: struct {} Type_Info_Any :: struct {}
Type_Info_Type_Id :: struct {} Type_Info_Type_Id :: struct {}
@@ -397,6 +402,11 @@ Raw_String :: struct {
len: int, len: int,
} }
Raw_String16 :: struct {
data: [^]u16,
len: int,
}
Raw_Slice :: struct { Raw_Slice :: struct {
data: rawptr, data: rawptr,
len: int, len: int,
@@ -450,6 +460,12 @@ Raw_Cstring :: struct {
} }
#assert(size_of(Raw_Cstring) == size_of(cstring)) #assert(size_of(Raw_Cstring) == size_of(cstring))
Raw_Cstring16 :: struct {
data: [^]u16,
}
#assert(size_of(Raw_Cstring16) == size_of(cstring16))
Raw_Soa_Pointer :: struct { Raw_Soa_Pointer :: struct {
data: rawptr, data: rawptr,
index: int, index: int,
+32 -1
View File
@@ -5,6 +5,11 @@ import "base:intrinsics"
@builtin @builtin
Maybe :: union($T: typeid) {T} Maybe :: union($T: typeid) {T}
/*
Represents an Objective-C block with a given procedure signature T
*/
@builtin
Objc_Block :: struct($T: typeid) where intrinsics.type_is_proc(T) { using _: intrinsics.objc_object }
/* /*
Recovers the containing/parent struct from a pointer to one of its fields. Recovers the containing/parent struct from a pointer to one of its fields.
@@ -86,11 +91,26 @@ copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int
} }
return n return n
} }
// `copy_from_string16` is a built-in procedure that copies elements from a source string `src` to a destination slice `dst`.
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
// of len(src) and len(dst).
//
// Prefer the procedure group `copy`.
@builtin
copy_from_string16 :: proc "contextless" (dst: $T/[]$E/u16, src: $S/string16) -> int {
n := min(len(dst), len(src))
if n > 0 {
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(u16))
}
return n
}
// `copy` is a built-in procedure that copies elements from a source slice/string `src` to a destination slice `dst`. // `copy` is a built-in procedure that copies elements from a source slice/string `src` to a destination slice `dst`.
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum // The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
// of len(src) and len(dst). // of len(src) and len(dst).
@builtin @builtin
copy :: proc{copy_slice, copy_from_string} copy :: proc{copy_slice, copy_from_string, copy_from_string16}
@@ -285,6 +305,15 @@ delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error
} }
@builtin
delete_string16 :: proc(str: string16, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free_with_size(raw_data(str), len(str)*size_of(u16), allocator, loc)
}
@builtin
delete_cstring16 :: proc(str: cstring16, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free((^u16)(str), allocator, loc)
}
// `delete` will try to free the underlying data of the passed built-in data structure (string, cstring, dynamic array, slice, or map), with the given `allocator` if the allocator supports this operation. // `delete` will try to free the underlying data of the passed built-in data structure (string, cstring, dynamic array, slice, or map), with the given `allocator` if the allocator supports this operation.
// //
// Note: Prefer `delete` over the specific `delete_*` procedures where possible. // Note: Prefer `delete` over the specific `delete_*` procedures where possible.
@@ -297,6 +326,8 @@ delete :: proc{
delete_map, delete_map,
delete_soa_slice, delete_soa_slice,
delete_soa_dynamic_array, delete_soa_dynamic_array,
delete_string16,
delete_cstring16,
} }
+91 -6
View File
@@ -180,8 +180,31 @@ resize_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int length: int, loc := #cal
if array == nil { if array == nil {
return nil return nil
} }
reserve_soa(array, length, loc) or_return
footer := raw_soa_footer(array) footer := raw_soa_footer(array)
if length > footer.cap {
reserve_soa(array, length, loc) or_return
} else if size_of(E) > 0 && length > footer.len {
ti := type_info_base(type_info_of(typeid_of(T)))
si := &ti.variant.(Type_Info_Struct)
field_count := len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)
data := (^rawptr)(array)^
soa_offset := 0
for i in 0..<field_count {
type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
soa_offset = align_forward_int(soa_offset, align_of(E))
mem_zero(rawptr(uintptr(data) + uintptr(soa_offset) + uintptr(type.size * footer.len)), type.size * (length - footer.len))
soa_offset += type.size * footer.cap
}
}
footer.len = length footer.len = length
return nil return nil
} }
@@ -252,17 +275,77 @@ _reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, zero_memory: boo
old_data := (^rawptr)(array)^ old_data := (^rawptr)(array)^
resize: if old_data != nil {
new_bytes, resize_err := array.allocator.procedure(
array.allocator.data, .Resize_Non_Zeroed, new_size, max_align,
old_data, old_size, loc,
)
new_data := raw_data(new_bytes)
#partial switch resize_err {
case .Mode_Not_Implemented: break resize
case .None: // continue resizing
case: return resize_err
}
footer.cap = capacity
old_offset := 0
new_offset := 0
// Correct data memory
// from: |x x y y z z _ _ _|
// to: |x x _ y y _ z z _|
// move old data to the end of the new allocation to avoid overlap
old_data = rawptr(uintptr(new_data) + uintptr(new_size - old_size))
mem_copy(old_data, new_data, old_size)
// now: |_ _ _ x x y y z z|
for i in 0..<field_count {
type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
old_offset = align_forward_int(old_offset, max_align)
new_offset = align_forward_int(new_offset, max_align)
new_data_elem := rawptr(uintptr(new_data) + uintptr(new_offset))
old_data_elem := rawptr(uintptr(old_data) + uintptr(old_offset))
old_size_elem := type.size * old_cap
new_size_elem := type.size * capacity
mem_copy(new_data_elem, old_data_elem, old_size_elem)
(^rawptr)(uintptr(array) + i*size_of(rawptr))^ = new_data_elem
if zero_memory {
mem_zero(rawptr(uintptr(new_data_elem) + uintptr(old_size_elem)), new_size_elem - old_size_elem)
}
old_offset += old_size_elem
new_offset += new_size_elem
}
return nil
}
new_bytes := array.allocator.procedure( new_bytes := array.allocator.procedure(
array.allocator.data, .Alloc if zero_memory else .Alloc_Non_Zeroed, new_size, max_align, array.allocator.data, .Alloc if zero_memory else .Alloc_Non_Zeroed, new_size, max_align,
nil, old_size, loc, nil, old_size, loc,
) or_return ) or_return
new_data := raw_data(new_bytes) new_data := raw_data(new_bytes)
footer.cap = capacity footer.cap = capacity
old_offset := 0 old_offset := 0
new_offset := 0 new_offset := 0
// Correct data memory
// from: |x x y y z z| ... |_ _ _ _ _ _ _ _ _|
// to: |x x _ y y _ z z _|
for i in 0..<field_count { for i in 0..<field_count {
type := si.types[i].variant.(Type_Info_Multi_Pointer).elem type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
@@ -280,10 +363,12 @@ _reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, zero_memory: boo
new_offset += type.size * capacity new_offset += type.size * capacity
} }
array.allocator.procedure( if old_data != nil {
array.allocator.data, .Free, 0, max_align, array.allocator.procedure(
old_data, old_size, loc, array.allocator.data, .Free, 0, max_align,
) or_return old_data, old_size, loc,
) or_return
}
return nil return nil
} }
+3 -1
View File
@@ -23,7 +23,8 @@ nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, .None return nil, .None
} }
nil_allocator :: proc() -> Allocator { @(require_results)
nil_allocator :: proc "contextless" () -> Allocator {
return Allocator{ return Allocator{
procedure = nil_allocator_proc, procedure = nil_allocator_proc,
data = nil, data = nil,
@@ -72,6 +73,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, nil return nil, nil
} }
@(require_results)
panic_allocator :: proc() -> Allocator { panic_allocator :: proc() -> Allocator {
return Allocator{ return Allocator{
procedure = panic_allocator_proc, procedure = panic_allocator_proc,
@@ -52,10 +52,13 @@ memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint
return return
} }
memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) { memory_block_dealloc :: proc "contextless" (block_to_free: ^Memory_Block, loc := #caller_location) {
if block_to_free != nil { if block_to_free != nil {
allocator := block_to_free.allocator allocator := block_to_free.allocator
// sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity) // sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity)
context = default_context()
context.allocator = allocator
mem_free(block_to_free, allocator, loc) mem_free(block_to_free, allocator, loc)
} }
} }
@@ -174,7 +177,7 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) {
arena.total_used = 0 arena.total_used = 0
} }
arena_destroy :: proc(arena: ^Arena, loc := #caller_location) { arena_destroy :: proc "contextless" (arena: ^Arena, loc := #caller_location) {
for arena.curr_block != nil { for arena.curr_block != nil {
free_block := arena.curr_block free_block := arena.curr_block
arena.curr_block = free_block.prev arena.curr_block = free_block.prev
@@ -186,6 +189,7 @@ arena_destroy :: proc(arena: ^Arena, loc := #caller_location) {
arena.total_capacity = 0 arena.total_capacity = 0
} }
@(require_results)
arena_allocator :: proc(arena: ^Arena) -> Allocator { arena_allocator :: proc(arena: ^Arena) -> Allocator {
return Allocator{arena_allocator_proc, arena} return Allocator{arena_allocator_proc, arena}
} }
@@ -8,7 +8,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {} default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {}
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {} default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {}
default_temp_allocator_proc :: nil_allocator_proc default_temp_allocator_proc :: nil_allocator_proc
@@ -28,7 +28,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
_ = arena_init(&s.arena, uint(size), backing_allocator) _ = arena_init(&s.arena, uint(size), backing_allocator)
} }
default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) { default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {
if s != nil { if s != nil {
arena_destroy(&s.arena) arena_destroy(&s.arena)
s^ = {} s^ = {}
@@ -61,7 +61,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
} }
@(fini, private) @(fini, private)
_destroy_temp_allocator_fini :: proc() { _destroy_temp_allocator_fini :: proc "contextless" () {
default_temp_allocator_destroy(&global_default_temp_allocator_data) default_temp_allocator_destroy(&global_default_temp_allocator_data)
} }
} }
@@ -75,7 +75,7 @@ DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD :: #force_inline proc(ignore := false, loc :=
} }
} }
@(require_results)
default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator { default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator {
return Allocator{ return Allocator{
procedure = default_temp_allocator_proc, procedure = default_temp_allocator_proc,
+244
View File
@@ -0,0 +1,244 @@
/*
Declarations which are required by the compiler
## Descriptions of files
There are a lot of files in this package and below is described roughly what
kind of functionality is placed in different files:
| File pattern | Description
|----------------------|------------------------------------------------------|
| `core.odin` | Contains the declarations that compiler will require to be present. Contains context-related declarations, `Type_Info` declarations and some other types used to implement the runtime and other packages. |
| `core_builtin*.odin` | Contain `@(builtin)` declarations that can be used without importing the package. Most of them aren't required by the compiler |
| `default_*.odin` | Contain default implementations for context allocators |
| `entry_*.odin` | Contain OS-specific entry points |
| `os_specific_*.odin` | Contain OS-specific utility procedures |
| `*internal*.odin` | Contain implementations for internal procedures that can be called by the compiler |
## Implementing custom runtime
For embedded and kernel development it might be required to re-implement parts
of the `base:runtime` package. This can include changing the default printing
procedures that handle console output when the program panics, custom
entry-points, tailored for a specific platform or execution environment, or
simply switching up implementations of some procedures.
In case this is required, the following is suggested:
1. Define `$ODIN_ROOT` environment variable to point to a directory within your
project that contains the following directories: `base/`, `core/` and `vendor/`.
2. Inside the `$ODIN_ROOT/base` subdirectory, implement the *necessary
declarations*.
What constitutes the necessary definitions is described below.
### Context-related
The compiler will require these declarations as they concern the `context`
variable.
* `Maybe`
* `Source_Code_Location`
* `Context`
* `Allocator`
* `Random_Generator`
* `Logger`
* `__init_context`
### Runtime initialization/cleanup
These are not strictly required for compilation, but if global variables or
`@(init)`/`@(fini)` blocks are used, these procedures need to be called inside
the entry point.
* `_startup_runtime`
* `_cleanup_runtime`
### Type assertion check
These procedures are called every time `.(Type)` expressions are used in order
to check the union tag or the underlying type of `any` before returning the
value of the underlying type. These are not required if `-no-type-assert` is
specified.
* `type_assertion_check`
* `type_assertion_check2` (takes in typeid)
### Bounds checking procedures
These procedures are called every time index or slicing expression are used in
order to perform bounds-checking before the actual operation. These are not
required if the `-no-bounds-check` option is specified.
* `bounds_check_error`
* `matrix_bounds_check_error`
* `slice_expr_error_hi`
* `slice_expr_error_lo_hi`
* `multi_pointer_slice_expr_error`
### cstring calls
If `cstring` or `cstring16` types are used, these procedures are required.
* `cstring_to_string`
* `cstring_len`
* `cstring16_to_string16`
* `cstring16_len`
### Comparison
These procedures are required for comparison operators between strings and other
compound types to function properly. If strings, structs nor unions are compared,
only `string_eq` procedure is required.
* `memory_equal`
* `memory_compare`
* `memory_compare_zero`
* `cstring_eq`
* `cstring16_eq`
* `cstring_ne`
* `cstring16_ne`
* `cstring_lt`
* `cstring16_lt`
* `cstring_gt`
* `cstring16_gt`
* `cstring_le`
* `cstring16_le`
* `cstring_ge`
* `cstring16_ge`
* `string_eq`
* `string16_eq`
* `string_ne`
* `string16_ne`
* `string_lt`
* `string16_lt`
* `string_gt`
* `string16_gt`
* `string_le`
* `string16_le`
* `string_ge`
* `string16_ge`
* `complex32_eq`
* `complex32_ne`
* `complex64_eq`
* `complex64_ne`
* `complex128_eq`
* `complex128_ne`
* `quaternion64_eq`
* `quaternion64_ne`
* `quaternion128_eq`
* `quaternion128_ne`
* `quaternion256_eq`
* `quaternion256_ne`
### for-in `string` type
These procedures are required to iterate strings using `for ... in` loop. If this
kind of loop isn't used, these procedures aren't required.
* `string_decode_rune`
* `string_decode_last_rune` (for `#reverse for`)
### Required when RTTI is enabled (the vast majority of targets)
These declarations are required unless the `-no-rtti` compiler option is
specified. Note that in order to be useful, some other procedures need to be
implemented. Those procedures aren't mentioned here as the compiler won't
complain if they're missing.
* `Type_Info`
* `type_table`
* `__type_info_of`
### Hashing
Required if maps are used
* `default_hasher`
* `default_hasher_cstring`
* `default_hasher_string`
### Pseudo-CRT required procedured due to LLVM but useful in general
* `memset`
* `memcpy`
* `memove`
### Procedures required by the LLVM backend if u128/i128 is used
* `umodti3`
* `udivti3`
* `modti3`
* `divti3`
* `fixdfti`
* `fixunsdfti`
* `fixunsdfdi`
* `floattidf`
* `floattidf_unsigned`
* `truncsfhf2`
* `truncdfhf2`
* `gnu_h2f_ieee`
* `gnu_f2h_ieee`
* `extendhfsf2`
### Procedures required by the LLVM backend if f16 is used (WASM only)
* `__ashlti3`
* `__multi3`
### When -no-crt is defined (windows only)
* `_tls_index`
* `_fltused`
### Arithmetic
* `quo_complex32`
* `quo_complex64`
* `quo_complex128`
* `mul_quaternion64`
* `mul_quaternion128`
* `mul_quaternion256`
* `quo_quaternion64`
* `quo_quaternion128`
* `quo_quaternion256`
* `abs_complex32`
* `abs_complex64`
* `abs_complex128`
* `abs_quaternion64`
* `abs_quaternion128`
* `abs_quaternion256`
## Map specific calls
* `map_seed_from_map_data`
* `__dynamic_map_check_grow` (for static map calls)
* `map_insert_hash_dynamic` (for static map calls)
* `__dynamic_map_get` (for dynamic map calls)
* `__dynamic_map_set` (for dynamic map calls)
## Dynamic literals (`[dynamic]T` and `map[K]V`) (can be disabled with `-no-dynamic-literals`)
* `__dynamic_array_reserve`
* `__dynamic_array_append`
* `__dynamic_map_reserve`
### Objective-C specific
* `objc_lookUpClass`
* `sel_registerName`
* `objc_allocateClassPair`
### Other required declarations
This is required without conditions.
* `Load_Directory_File`
*/
package runtime
-180
View File
@@ -1,180 +0,0 @@
package runtime
/*
package runtime has numerous entities (declarations) which are required by the compiler to function.
## Basic types and calls (and anything they rely on)
Source_Code_Location
Context
Allocator
Logger
__init_context
_cleanup_runtime
## cstring calls
cstring_to_string
cstring_len
## Required when RTTI is enabled (the vast majority of targets)
Type_Info
type_table
__type_info_of
## Hashing
default_hasher
default_hasher_cstring
default_hasher_string
## Pseudo-CRT required procedured due to LLVM but useful in general
memset
memcpy
memove
## Procedures required by the LLVM backend if u128/i128 is used
umodti3
udivti3
modti3
divti3
fixdfti
fixunsdfti
fixunsdfdi
floattidf
floattidf_unsigned
truncsfhf2
truncdfhf2
gnu_h2f_ieee
gnu_f2h_ieee
extendhfsf2
## Procedures required by the LLVM backend if f16 is used
__ashlti3 // wasm specific
__multi3 // wasm specific
## Required an entry point is defined (i.e. 'main')
args__
## When -no-crt is defined (and not a wasm target) (mostly due to LLVM)
_tls_index
_fltused
## Bounds checking procedures (when not disabled with -no-bounds-check)
bounds_check_error
matrix_bounds_check_error
slice_expr_error_hi
slice_expr_error_lo_hi
multi_pointer_slice_expr_error
## Type assertion check
type_assertion_check
type_assertion_check2 // takes in typeid
## Arithmetic
quo_complex32
quo_complex64
quo_complex128
mul_quaternion64
mul_quaternion128
mul_quaternion256
quo_quaternion64
quo_quaternion128
quo_quaternion256
abs_complex32
abs_complex64
abs_complex128
abs_quaternion64
abs_quaternion128
abs_quaternion256
## Comparison
memory_equal
memory_compare
memory_compare_zero
cstring_eq
cstring_ne
cstring_lt
cstring_gt
cstring_le
cstring_gt
string_eq
string_ne
string_lt
string_gt
string_le
string_gt
complex32_eq
complex32_ne
complex64_eq
complex64_ne
complex128_eq
complex128_ne
quaternion64_eq
quaternion64_ne
quaternion128_eq
quaternion128_ne
quaternion256_eq
quaternion256_ne
## Map specific calls
map_seed_from_map_data
__dynamic_map_check_grow // static map calls
map_insert_hash_dynamic // static map calls
__dynamic_map_get // dynamic map calls
__dynamic_map_set // dynamic map calls
## Dynamic literals ([dynamic]T and map[K]V) (can be disabled with -no-dynamic-literals)
__dynamic_array_reserve
__dynamic_array_append
__dynamic_map_reserve
## Objective-C specific
objc_lookUpClass
sel_registerName
objc_allocateClassPair
## for-in `string` type
string_decode_rune
string_decode_last_rune // #reverse for
*/
+1
View File
@@ -2,6 +2,7 @@ package runtime
import "base:intrinsics" import "base:intrinsics"
@(require_results)
heap_allocator :: proc() -> Allocator { heap_allocator :: proc() -> Allocator {
return Allocator{ return Allocator{
procedure = heap_allocator_proc, procedure = heap_allocator_proc,
+153 -4
View File
@@ -268,8 +268,8 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
} }
} }
m = (n-i) / 8 * 8 m = (n-i) / size_of(uintptr) * size_of(uintptr)
for /**/; i < m; i += 8 { for /**/; i < m; i += size_of(uintptr) {
if intrinsics.unaligned_load(cast(^uintptr)&a[i]) != intrinsics.unaligned_load(cast(^uintptr)&b[i]) { if intrinsics.unaligned_load(cast(^uintptr)&a[i]) != intrinsics.unaligned_load(cast(^uintptr)&b[i]) {
return false return false
} }
@@ -389,8 +389,8 @@ memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_
} }
} }
m = (n-i) / 8 * 8 m = (n-i) / size_of(uintptr) * size_of(uintptr)
for /**/; i < m; i += 8 { for /**/; i < m; i += size_of(uintptr) {
if intrinsics.unaligned_load(cast(^uintptr)&bytes[i]) != 0 { if intrinsics.unaligned_load(cast(^uintptr)&bytes[i]) != 0 {
return 1 return 1
} }
@@ -493,12 +493,40 @@ string_cmp :: proc "contextless" (a, b: string) -> int {
return ret return ret
} }
string16_eq :: proc "contextless" (lhs, rhs: string16) -> bool {
x := transmute(Raw_String16)lhs
y := transmute(Raw_String16)rhs
if x.len != y.len {
return false
}
return #force_inline memory_equal(x.data, y.data, x.len*size_of(u16))
}
string16_cmp :: proc "contextless" (a, b: string16) -> int {
x := transmute(Raw_String16)a
y := transmute(Raw_String16)b
ret := memory_compare(x.data, y.data, min(x.len, y.len)*size_of(u16))
if ret == 0 && x.len != y.len {
return -1 if x.len < y.len else +1
}
return ret
}
string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) } string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) }
string_lt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) < 0 } string_lt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) < 0 }
string_gt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) > 0 } string_gt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) > 0 }
string_le :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) <= 0 } string_le :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) <= 0 }
string_ge :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0 } string_ge :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0 }
string16_ne :: #force_inline proc "contextless" (a, b: string16) -> bool { return !string16_eq(a, b) }
string16_lt :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) < 0 }
string16_gt :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) > 0 }
string16_le :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) <= 0 }
string16_ge :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) >= 0 }
cstring_len :: proc "contextless" (s: cstring) -> int { cstring_len :: proc "contextless" (s: cstring) -> int {
p0 := uintptr((^byte)(s)) p0 := uintptr((^byte)(s))
p := p0 p := p0
@@ -508,6 +536,16 @@ cstring_len :: proc "contextless" (s: cstring) -> int {
return int(p - p0) return int(p - p0)
} }
cstring16_len :: proc "contextless" (s: cstring16) -> int {
p := ([^]u16)(s)
n := 0
for p != nil && p[0] != 0 {
p = p[1:]
n += 1
}
return n
}
cstring_to_string :: proc "contextless" (s: cstring) -> string { cstring_to_string :: proc "contextless" (s: cstring) -> string {
if s == nil { if s == nil {
return "" return ""
@@ -517,6 +555,15 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
return transmute(string)Raw_String{ptr, n} return transmute(string)Raw_String{ptr, n}
} }
cstring16_to_string16 :: proc "contextless" (s: cstring16) -> string16 {
if s == nil {
return ""
}
ptr := (^u16)(s)
n := cstring16_len(s)
return transmute(string16)Raw_String16{ptr, n}
}
cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool { cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool {
x := ([^]byte)(lhs) x := ([^]byte)(lhs)
@@ -559,6 +606,46 @@ cstring_gt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return
cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 } cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 }
cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 } cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 }
cstring16_eq :: proc "contextless" (lhs, rhs: cstring16) -> bool {
x := ([^]u16)(lhs)
y := ([^]u16)(rhs)
if x == y {
return true
}
if (x == nil) ~ (y == nil) {
return false
}
xn := cstring16_len(lhs)
yn := cstring16_len(rhs)
if xn != yn {
return false
}
return #force_inline memory_equal(x, y, xn*size_of(u16))
}
cstring16_cmp :: proc "contextless" (lhs, rhs: cstring16) -> int {
x := ([^]u16)(lhs)
y := ([^]u16)(rhs)
if x == y {
return 0
}
if (x == nil) ~ (y == nil) {
return -1 if x == nil else +1
}
xn := cstring16_len(lhs)
yn := cstring16_len(rhs)
ret := memory_compare(x, y, min(xn, yn)*size_of(u16))
if ret == 0 && xn != yn {
return -1 if xn < yn else +1
}
return ret
}
cstring16_ne :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return !cstring16_eq(a, b) }
cstring16_lt :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) < 0 }
cstring16_gt :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) > 0 }
cstring16_le :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) <= 0 }
cstring16_ge :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) >= 0 }
complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) } complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) }
complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) } complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) }
@@ -694,6 +781,68 @@ string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) {
return r, size return r, size
} }
string16_decode_rune :: #force_inline proc "contextless" (s: string16) -> (rune, int) {
REPLACEMENT_CHAR :: '\ufffd'
_surr1 :: 0xd800
_surr2 :: 0xdc00
_surr3 :: 0xe000
_surr_self :: 0x10000
r := rune(REPLACEMENT_CHAR)
if len(s) < 1 {
return r, 0
}
w := 1
switch c := s[0]; {
case c < _surr1, _surr3 <= c:
r = rune(c)
case _surr1 <= c && c < _surr2 && 1 < len(s) &&
_surr2 <= s[1] && s[1] < _surr3:
r1, r2 := rune(c), rune(s[1])
if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 {
r = (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self
}
w += 1
}
return r, w
}
string16_decode_last_rune :: proc "contextless" (s: string16) -> (rune, int) {
REPLACEMENT_CHAR :: '\ufffd'
_surr1 :: 0xd800
_surr2 :: 0xdc00
_surr3 :: 0xe000
_surr_self :: 0x10000
r := rune(REPLACEMENT_CHAR)
if len(s) < 1 {
return r, 0
}
n := len(s)-1
c := s[n]
w := 1
if _surr2 <= c && c < _surr3 {
if n >= 1 {
r1 := rune(s[n-1])
r2 := rune(c)
if _surr1 <= r1 && r1 < _surr2 {
r = (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self
}
w = 2
}
} else if c < _surr1 || _surr3 <= c {
r = rune(c)
}
return r, w
}
abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 { abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 {
p, q := abs(real(x)), abs(imag(x)) p, q := abs(real(x)), abs(imag(x))
if p < q { if p < q {
+7
View File
@@ -293,7 +293,14 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
print_string("quaternion") print_string("quaternion")
print_u64(u64(8*ti.size)) print_u64(u64(8*ti.size))
case Type_Info_String: case Type_Info_String:
if info.is_cstring {
print_byte('c')
}
print_string("string") print_string("string")
switch info.encoding {
case .UTF_8: /**/
case .UTF_16: print_string("16")
}
case Type_Info_Boolean: case Type_Info_Boolean:
switch ti.id { switch ti.id {
case bool: print_string("bool") case bool: print_string("bool")
+11 -1
View File
@@ -1,9 +1,12 @@
#+private #+private
package runtime package runtime
@(priority_index=-1e6) @(priority_index=-1e5)
foreign import ObjC "system:objc" foreign import ObjC "system:objc"
@(priority_index=-1e6)
foreign import libSystem "system:System"
import "base:intrinsics" import "base:intrinsics"
objc_id :: ^intrinsics.objc_object objc_id :: ^intrinsics.objc_object
@@ -34,3 +37,10 @@ foreign ObjC {
object_getClass :: proc "c" (obj: objc_id) -> objc_Class --- object_getClass :: proc "c" (obj: objc_id) -> objc_Class ---
} }
foreign libSystem {
_NSConcreteGlobalBlock: intrinsics.objc_class
_NSConcreteStackBlock: intrinsics.objc_class
_Block_object_assign :: proc "c" (rawptr, rawptr, i32) ---
_Block_object_dispose :: proc "c" (rawptr, i32) ---
}
+2 -2
View File
@@ -3,8 +3,8 @@ package runtime
init_default_context_for_js: Context init_default_context_for_js: Context
@(init, private="file") @(init, private="file")
init_default_context :: proc() { init_default_context :: proc "contextless" () {
init_default_context_for_js = context __init_context(&init_default_context_for_js)
} }
@(export) @(export)
+1 -1
View File
@@ -97,7 +97,7 @@ default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode,
for &v in p { for &v in p {
if pos == 0 { if pos == 0 {
val = read_u64(r) val = read_u64(r)
pos = 7 pos = 8
} }
v = byte(val) v = byte(val)
val >>= 8 val >>= 8
+9 -2
View File
@@ -1,10 +1,14 @@
package runtime package runtime
Thread_Local_Cleaner :: #type proc "odin" () Thread_Local_Cleaner_Odin :: #type proc "odin" ()
Thread_Local_Cleaner_Contextless :: #type proc "contextless" ()
Thread_Local_Cleaner :: union #shared_nil {Thread_Local_Cleaner_Odin, Thread_Local_Cleaner_Contextless}
@(private="file") @(private="file")
thread_local_cleaners: [8]Thread_Local_Cleaner thread_local_cleaners: [8]Thread_Local_Cleaner
// Add a procedure that will be run at the end of a thread for the purpose of // Add a procedure that will be run at the end of a thread for the purpose of
// deallocating state marked as `thread_local`. // deallocating state marked as `thread_local`.
// //
@@ -29,6 +33,9 @@ run_thread_local_cleaners :: proc "odin" () {
if p == nil { if p == nil {
break break
} }
p() switch v in p {
case Thread_Local_Cleaner_Odin: v()
case Thread_Local_Cleaner_Contextless: v()
}
} }
} }
+2
View File
@@ -89,10 +89,12 @@ wasm_allocator_init :: proc(a: ^WASM_Allocator, alignment: uint = 8) {
global_default_wasm_allocator_data: WASM_Allocator global_default_wasm_allocator_data: WASM_Allocator
@(require_results)
default_wasm_allocator :: proc() -> Allocator { default_wasm_allocator :: proc() -> Allocator {
return wasm_allocator(&global_default_wasm_allocator_data) return wasm_allocator(&global_default_wasm_allocator_data)
} }
@(require_results)
wasm_allocator :: proc(a: ^WASM_Allocator) -> Allocator { wasm_allocator :: proc(a: ^WASM_Allocator) -> Allocator {
return { return {
data = a, data = a,
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env sh
find "$1" -type f \(\
-iname "*.exe" \
-o -iname "*.dll" \
-o -iname "*.lib" \
-o -iname "*.pdb" \
\) -delete
+8 -8
View File
@@ -72,14 +72,14 @@ when ODIN_OS == .Windows {
n_sep_by_space: c.char, n_sep_by_space: c.char,
p_sign_posn: c.char, p_sign_posn: c.char,
n_sign_posn: c.char, n_sign_posn: c.char,
_W_decimal_point: [^]u16 `fmt:"s,0"`, _W_decimal_point: cstring16,
_W_thousands_sep: [^]u16 `fmt:"s,0"`, _W_thousands_sep: cstring16,
_W_int_curr_symbol: [^]u16 `fmt:"s,0"`, _W_int_curr_symbol: cstring16,
_W_currency_symbol: [^]u16 `fmt:"s,0"`, _W_currency_symbol: cstring16,
_W_mon_decimal_point: [^]u16 `fmt:"s,0"`, _W_mon_decimal_point: cstring16,
_W_mon_thousands_sep: [^]u16 `fmt:"s,0"`, _W_mon_thousands_sep: cstring16,
_W_positive_sign: [^]u16 `fmt:"s,0"`, _W_positive_sign: cstring16,
_W_negative_sign: [^]u16 `fmt:"s,0"`, _W_negative_sign: cstring16,
} }
} else { } else {
lconv :: struct { lconv :: struct {
+12 -12
View File
@@ -22,7 +22,7 @@ DEFAULT_CAPACITY :: 16
/* /*
Initialize a `Queue` with a starting `capacity` and an `allocator`. Initialize a `Queue` with a starting `capacity` and an `allocator`.
*/ */
init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> runtime.Allocator_Error { init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator, loc := #caller_location) -> runtime.Allocator_Error {
clear(q) clear(q)
q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{ q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
data = nil, data = nil,
@@ -30,7 +30,7 @@ init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := contex
cap = 0, cap = 0,
allocator = allocator, allocator = allocator,
} }
return reserve(q, capacity) return reserve(q, capacity, loc)
} }
/* /*
@@ -114,9 +114,9 @@ Reserve enough space in the queue for at least the specified capacity.
This may return an error if allocation failed. This may return an error if allocation failed.
*/ */
reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error { reserve :: proc(q: ^$Q/Queue($T), capacity: int, loc := #caller_location) -> runtime.Allocator_Error {
if capacity > space(q^) { if capacity > space(q^) {
return _grow(q, uint(capacity)) return _grow(q, uint(capacity), loc)
} }
return nil return nil
} }
@@ -269,9 +269,9 @@ Example:
assert(queue.pop_front(&q) == 3) assert(queue.pop_front(&q) == 3)
} }
*/ */
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) { push_back :: proc(q: ^$Q/Queue($T), elem: T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) {
if space(q^) == 0 { if space(q^) == 0 {
_grow(q) or_return _grow(q, loc = loc) or_return
} }
idx := (q.offset+uint(q.len))%builtin.len(q.data) idx := (q.offset+uint(q.len))%builtin.len(q.data)
q.data[idx] = elem q.data[idx] = elem
@@ -303,9 +303,9 @@ Example:
assert(queue.pop_back(&q) == 1) assert(queue.pop_back(&q) == 1)
} }
*/ */
push_front :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) { push_front :: proc(q: ^$Q/Queue($T), elem: T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) {
if space(q^) == 0 { if space(q^) == 0 {
_grow(q) or_return _grow(q, loc = loc) or_return
} }
q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data) q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data)
q.len += 1 q.len += 1
@@ -396,10 +396,10 @@ Push many elements at once to the back of the queue.
If there is not enough space left and allocation fails to get more, this will If there is not enough space left and allocation fails to get more, this will
return false with an `Allocator_Error`. return false with an `Allocator_Error`.
*/ */
push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime.Allocator_Error) { push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) {
n := uint(builtin.len(elems)) n := uint(builtin.len(elems))
if space(q^) < int(n) { if space(q^) < int(n) {
_grow(q, q.len + n) or_return _grow(q, q.len + n, loc) or_return
} }
sz := uint(builtin.len(q.data)) sz := uint(builtin.len(q.data))
@@ -465,10 +465,10 @@ clear :: proc(q: ^$Q/Queue($T)) {
// Internal growing procedure // Internal growing procedure
_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> runtime.Allocator_Error { _grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0, loc := #caller_location) -> runtime.Allocator_Error {
new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2) new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2)
n := uint(builtin.len(q.data)) n := uint(builtin.len(q.data))
builtin.resize(&q.data, int(new_capacity)) or_return builtin.resize(&q.data, int(new_capacity), loc) or_return
if q.offset + q.len > n { if q.offset + q.len > n {
diff := n - q.offset diff := n - q.offset
copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff]) copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff])
+1 -1
View File
@@ -54,7 +54,7 @@ _resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> (
symbol.SizeOfStruct = size_of(symbol^) symbol.SizeOfStruct = size_of(symbol^)
symbol.MaxNameLen = 255 symbol.MaxNameLen = 255
if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) { if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) {
fl.procedure, _ = win32.wstring_to_utf8(&symbol.Name[0], -1, allocator) fl.procedure, _ = win32.wstring_to_utf8(cstring16(&symbol.Name[0]), -1, allocator)
} else { } else {
fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator) fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator)
} }
+1 -1
View File
@@ -13,7 +13,7 @@ _LIBRARY_FILE_EXTENSION :: "dll"
_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) { _load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) {
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL // NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
wide_path := win32.utf8_to_wstring(path, allocator) wide_path := win32.utf8_to_wstring(path, allocator)
defer free(wide_path, allocator) defer free(rawptr(wide_path), allocator)
handle := cast(Library)win32.LoadLibraryW(wide_path) handle := cast(Library)win32.LoadLibraryW(wide_path)
return handle, handle != nil return handle, handle != nil
} }
+7 -5
View File
@@ -82,14 +82,16 @@ _tag_implementations_id: map[string]Tag_Implementation
_tag_implementations_type: map[typeid]Tag_Implementation _tag_implementations_type: map[typeid]Tag_Implementation
// Register a custom tag implementation to be used when marshalling that type and unmarshalling that tag number. // Register a custom tag implementation to be used when marshalling that type and unmarshalling that tag number.
tag_register_type :: proc(impl: Tag_Implementation, nr: Tag_Number, type: typeid) { tag_register_type :: proc "contextless" (impl: Tag_Implementation, nr: Tag_Number, type: typeid) {
context = runtime.default_context()
_tag_implementations_nr[nr] = impl _tag_implementations_nr[nr] = impl
_tag_implementations_type[type] = impl _tag_implementations_type[type] = impl
} }
// Register a custom tag implementation to be used when marshalling that tag number or marshalling // Register a custom tag implementation to be used when marshalling that tag number or marshalling
// a field with the struct tag `cbor_tag:"nr"`. // a field with the struct tag `cbor_tag:"nr"`.
tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string) { tag_register_number :: proc "contextless" (impl: Tag_Implementation, nr: Tag_Number, id: string) {
context = runtime.default_context()
_tag_implementations_nr[nr] = impl _tag_implementations_nr[nr] = impl
_tag_implementations_id[id] = impl _tag_implementations_id[id] = impl
} }
@@ -98,13 +100,13 @@ tag_register_number :: proc(impl: Tag_Implementation, nr: Tag_Number, id: string
INITIALIZE_DEFAULT_TAGS :: #config(CBOR_INITIALIZE_DEFAULT_TAGS, !ODIN_DEFAULT_TO_PANIC_ALLOCATOR && !ODIN_DEFAULT_TO_NIL_ALLOCATOR) INITIALIZE_DEFAULT_TAGS :: #config(CBOR_INITIALIZE_DEFAULT_TAGS, !ODIN_DEFAULT_TO_PANIC_ALLOCATOR && !ODIN_DEFAULT_TO_NIL_ALLOCATOR)
@(private, init, disabled=!INITIALIZE_DEFAULT_TAGS) @(private, init, disabled=!INITIALIZE_DEFAULT_TAGS)
tags_initialize_defaults :: proc() { tags_initialize_defaults :: proc "contextless" () {
tags_register_defaults() tags_register_defaults()
} }
// Registers tags that have implementations provided by this package. // Registers tags that have implementations provided by this package.
// This is done by default and can be controlled with the `CBOR_INITIALIZE_DEFAULT_TAGS` define. // This is done by default and can be controlled with the `CBOR_INITIALIZE_DEFAULT_TAGS` define.
tags_register_defaults :: proc() { tags_register_defaults :: proc "contextless" () {
tag_register_number({nil, tag_time_unmarshal, tag_time_marshal}, TAG_EPOCH_TIME_NR, TAG_EPOCH_TIME_ID) tag_register_number({nil, tag_time_unmarshal, tag_time_marshal}, TAG_EPOCH_TIME_NR, TAG_EPOCH_TIME_ID)
tag_register_number({nil, tag_base64_unmarshal, tag_base64_marshal}, TAG_BASE64_NR, TAG_BASE64_ID) tag_register_number({nil, tag_base64_unmarshal, tag_base64_marshal}, TAG_BASE64_NR, TAG_BASE64_ID)
tag_register_number({nil, tag_cbor_unmarshal, tag_cbor_marshal}, TAG_CBOR_NR, TAG_CBOR_ID) tag_register_number({nil, tag_cbor_unmarshal, tag_cbor_marshal}, TAG_CBOR_NR, TAG_CBOR_ID)
@@ -298,7 +300,7 @@ tag_base64_unmarshal :: proc(_: ^Tag_Implementation, d: Decoder, _: Tag_Number,
#partial switch t in ti.variant { #partial switch t in ti.variant {
case reflect.Type_Info_String: case reflect.Type_Info_String:
assert(t.encoding == .UTF_8)
if t.is_cstring { if t.is_cstring {
length := base64.decoded_len(bytes) length := base64.decoded_len(bytes)
builder := strings.builder_make(0, length+1) builder := strings.builder_make(0, length+1)
+2
View File
@@ -335,6 +335,8 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.a
_unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) { _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) {
#partial switch t in ti.variant { #partial switch t in ti.variant {
case reflect.Type_Info_String: case reflect.Type_Info_String:
assert(t.encoding == .UTF_8)
bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return
if t.is_cstring { if t.is_cstring {
+4 -4
View File
@@ -353,10 +353,10 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
#partial switch info in ti.variant { #partial switch info in ti.variant {
case runtime.Type_Info_String: case runtime.Type_Info_String:
switch x in v { switch x in v {
case string: case string: return x == ""
return x == "" case cstring: return x == nil || x == ""
case cstring: case string16: return x == ""
return x == nil || x == "" case cstring16: return x == nil || x == ""
} }
case runtime.Type_Info_Any: case runtime.Type_Info_Any:
return v.(any) == nil return v.(any) == nil
+3 -1
View File
@@ -572,7 +572,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
key_ptr: rawptr key_ptr: rawptr
#partial switch tk in t.key.variant { #partial switch tk in t.key.variant {
case runtime.Type_Info_String: case runtime.Type_Info_String:
assert(tk.encoding == .UTF_8)
key_ptr = rawptr(&key) key_ptr = rawptr(&key)
key_cstr: cstring key_cstr: cstring
if reflect.is_cstring(t.key) { if reflect.is_cstring(t.key) {
+2
View File
@@ -127,6 +127,8 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info:
} }
case runtime.Type_Info_String: case runtime.Type_Info_String:
assert(specific_type_info.encoding == .UTF_8)
if specific_type_info.is_cstring { if specific_type_info.is_cstring {
cstr_ptr := (^cstring)(ptr) cstr_ptr := (^cstring)(ptr)
if cstr_ptr != nil { if cstr_ptr != nil {
+1 -1
View File
@@ -38,6 +38,6 @@ Note that only one can be active at a time.
Inputs: Inputs:
- setter: The type setter. Pass `nil` to disable any previously set setter. - setter: The type setter. Pass `nil` to disable any previously set setter.
*/ */
register_type_setter :: proc(setter: Custom_Type_Setter) { register_type_setter :: proc "contextless" (setter: Custom_Type_Setter) {
global_custom_type_setter = setter global_custom_type_setter = setter
} }
+2 -2
View File
@@ -29,6 +29,8 @@ Integer:
%x base 16, with lower-case letters for a-f %x base 16, with lower-case letters for a-f
%X base 16, with upper-case letters for A-F %X base 16, with upper-case letters for A-F
%U Unicode format: U+1234; same as "U+%04X" %U Unicode format: U+1234; same as "U+%04X"
%m number of bytes in the best unit of measurement, e.g. 123.45mib
%M number of bytes in the best unit of measurement, e.g. 123.45MiB
Floating-point, complex numbers, and quaternions: Floating-point, complex numbers, and quaternions:
%e scientific notation, e.g. -1.23456e+78 %e scientific notation, e.g. -1.23456e+78
%E scientific notation, e.g. -1.23456E+78 %E scientific notation, e.g. -1.23456E+78
@@ -38,8 +40,6 @@ Floating-point, complex numbers, and quaternions:
%G synonym for %g %G synonym for %g
%h hexadecimal (lower-case) representation with 0h prefix (0h01234abcd) %h hexadecimal (lower-case) representation with 0h prefix (0h01234abcd)
%H hexadecimal (upper-case) representation with 0H prefix (0h01234ABCD) %H hexadecimal (upper-case) representation with 0H prefix (0h01234ABCD)
%m number of bytes in the best unit of measurement, e.g. 123.45mib
%M number of bytes in the best unit of measurement, e.g. 123.45MiB
String and slice of bytes String and slice of bytes
%s the uninterpreted bytes of the string or slice %s the uninterpreted bytes of the string or slice
%q a double-quoted string safely escaped with Odin syntax %q a double-quoted string safely escaped with Odin syntax
+84 -8
View File
@@ -1551,6 +1551,79 @@ fmt_string :: proc(fi: ^Info, s: string, verb: rune) {
fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) { fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) {
fmt_string(fi, string(s), verb) fmt_string(fi, string(s), verb)
} }
// Formats a string UTF-16 with a specific format.
//
// Inputs:
// - fi: Pointer to the Info struct containing format settings.
// - s: The string to format.
// - verb: The format specifier character (e.g. 's', 'v', 'q', 'x', 'X').
//
fmt_string16 :: proc(fi: ^Info, s: string16, verb: rune) {
s, verb := s, verb
if ol, ok := fi.optional_len.?; ok {
s = s[:clamp(ol, 0, len(s))]
}
if !fi.in_bad && fi.record_level > 0 && verb == 'v' {
verb = 'q'
}
switch verb {
case 's', 'v':
if fi.width_set {
if fi.width > len(s) {
if fi.minus {
io.write_string16(fi.writer, s, &fi.n)
}
for _ in 0..<fi.width - len(s) {
io.write_byte(fi.writer, ' ', &fi.n)
}
if !fi.minus {
io.write_string16(fi.writer, s, &fi.n)
}
} else {
io.write_string16(fi.writer, s, &fi.n)
}
} else {
io.write_string16(fi.writer, s, &fi.n)
}
case 'q', 'w': // quoted string
io.write_quoted_string16(fi.writer, s, '"', &fi.n)
case 'x', 'X':
space := fi.space
fi.space = false
defer fi.space = space
for i in 0..<len(s) {
if i > 0 && space {
io.write_byte(fi.writer, ' ', &fi.n)
}
char_set := __DIGITS_UPPER
if verb == 'x' {
char_set = __DIGITS_LOWER
}
_fmt_int(fi, u64(s[i]), 16, false, bit_size=16, digits=char_set)
}
case:
fmt_bad_verb(fi, verb)
}
}
// Formats a C-style UTF-16 string with a specific format.
//
// Inputs:
// - fi: Pointer to the Info struct containing format settings.
// - s: The C-style string to format.
// - verb: The format specifier character (Ref fmt_string).
//
fmt_cstring16 :: proc(fi: ^Info, s: cstring16, verb: rune) {
fmt_string16(fi, string16(s), verb)
}
// Formats a raw pointer with a specific format. // Formats a raw pointer with a specific format.
// //
// Inputs: // Inputs:
@@ -2273,14 +2346,14 @@ fmt_array :: proc(fi: ^Info, data: rawptr, n: int, elem_size: int, elem: ^reflec
} }
switch reflect.type_info_base(elem).id { switch reflect.type_info_base(elem).id {
case byte: fmt_string(fi, string(([^]byte)(data)[:n]), verb); return case byte: fmt_string(fi, string (([^]byte)(data)[:n]), verb); return
case u16: print_utf16(fi, ([^]u16)(data)[:n]); return case u16: fmt_string16(fi, string16(([^]u16) (data)[:n]), verb); return
case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return
case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return
case u32: print_utf32(fi, ([^]u32)(data)[:n]); return case u32: print_utf32(fi, ([^]u32)(data)[:n]); return
case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return
case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return
case rune: print_utf32(fi, ([^]rune)(data)[:n]); return case rune: print_utf32(fi, ([^]rune)(data)[:n]); return
} }
} }
if verb == 'p' { if verb == 'p' {
@@ -3210,6 +3283,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case string: fmt_string(fi, a, verb) case string: fmt_string(fi, a, verb)
case cstring: fmt_cstring(fi, a, verb) case cstring: fmt_cstring(fi, a, verb)
case string16: fmt_string16(fi, a, verb)
case cstring16: fmt_cstring16(fi, a, verb)
case typeid: reflect.write_typeid(fi.writer, a, &fi.n) case typeid: reflect.write_typeid(fi.writer, a, &fi.n)
case i16le: fmt_int(fi, u64(a), true, 16, verb) case i16le: fmt_int(fi, u64(a), true, 16, verb)
+1 -1
View File
@@ -741,6 +741,6 @@ destroy :: proc(img: ^Image) {
} }
@(init, private) @(init, private)
_register :: proc() { _register :: proc "contextless" () {
image.register(.BMP, load_from_bytes, destroy) image.register(.BMP, load_from_bytes, destroy)
} }
+5 -5
View File
@@ -10,13 +10,13 @@ Destroy_Proc :: #type proc(img: ^Image)
_internal_loaders: [Which_File_Type]Loader_Proc _internal_loaders: [Which_File_Type]Loader_Proc
_internal_destroyers: [Which_File_Type]Destroy_Proc _internal_destroyers: [Which_File_Type]Destroy_Proc
register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) { register :: proc "contextless" (kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
assert(loader != nil) assert_contextless(loader != nil)
assert(destroyer != nil) assert_contextless(destroyer != nil)
assert(_internal_loaders[kind] == nil) assert_contextless(_internal_loaders[kind] == nil)
_internal_loaders[kind] = loader _internal_loaders[kind] = loader
assert(_internal_destroyers[kind] == nil) assert_contextless(_internal_destroyers[kind] == nil)
_internal_destroyers[kind] = destroyer _internal_destroyers[kind] = destroyer
} }
+1 -1
View File
@@ -720,7 +720,7 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for
} }
@(init, private) @(init, private)
_register :: proc() { _register :: proc "contextless" () {
loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) { loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) {
return load_from_bytes(data, allocator) return load_from_bytes(data, allocator)
} }
+1 -1
View File
@@ -1611,6 +1611,6 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
} }
@(init, private) @(init, private)
_register :: proc() { _register :: proc "contextless" () {
image.register(.PNG, load_from_bytes, destroy) image.register(.PNG, load_from_bytes, destroy)
} }
+1 -1
View File
@@ -371,6 +371,6 @@ qoi_hash :: #force_inline proc(pixel: RGBA_Pixel) -> (index: u8) {
} }
@(init, private) @(init, private)
_register :: proc() { _register :: proc "contextless" () {
image.register(.QOI, load_from_bytes, destroy) image.register(.QOI, load_from_bytes, destroy)
} }
+1 -1
View File
@@ -406,6 +406,6 @@ IMAGE_DESCRIPTOR_RIGHT_MASK :: 1<<4
IMAGE_DESCRIPTOR_TOP_MASK :: 1<<5 IMAGE_DESCRIPTOR_TOP_MASK :: 1<<5
@(init, private) @(init, private)
_register :: proc() { _register :: proc "contextless" () {
image.register(.TGA, load_from_bytes, destroy) image.register(.TGA, load_from_bytes, destroy)
} }
+24
View File
@@ -5,6 +5,7 @@ package io
import "base:intrinsics" import "base:intrinsics"
import "core:unicode/utf8" import "core:unicode/utf8"
import "core:unicode/utf16"
// Seek whence values // Seek whence values
Seek_From :: enum { Seek_From :: enum {
@@ -314,6 +315,29 @@ write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int,
return write(s, transmute([]byte)str, n_written) return write(s, transmute([]byte)str, n_written)
} }
// write_string16 writes the contents of the string16 s to w reencoded as utf-8
write_string16 :: proc(s: Writer, str: string16, n_written: ^int = nil) -> (n: int, err: Error) {
for i := 0; i < len(str); i += 1 {
r := rune(utf16.REPLACEMENT_CHAR)
switch c := str[i]; {
case c < utf16._surr1, utf16._surr3 <= c:
r = rune(c)
case utf16._surr1 <= c && c < utf16._surr2 && i+1 < len(str) &&
utf16._surr2 <= str[i+1] && str[i+1] < utf16._surr3:
r = utf16.decode_surrogate_pair(rune(c), rune(str[i+1]))
i += 1
}
w: int
w, err = write_rune(s, r, n_written)
n += w
if err != nil {
return
}
}
return
}
// write_rune writes a UTF-8 encoded rune to w. // write_rune writes a UTF-8 encoded rune to w.
write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) { write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) {
defer if err == nil && n_written != nil { defer if err == nil && n_written != nil {
+27
View File
@@ -264,6 +264,33 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written
return return
} }
write_quoted_string16 :: proc(w: Writer, str: string16, quote: byte = '"', n_written: ^int = nil, for_json := false) -> (n: int, err: Error) {
defer if n_written != nil {
n_written^ += n
}
write_byte(w, quote, &n) or_return
for width, s := 0, str; len(s) > 0; s = s[width:] {
r := rune(s[0])
width = 1
if r >= utf8.RUNE_SELF {
r, width = utf16.decode_rune_in_string(s)
}
if width == 1 && r == utf8.RUNE_ERROR {
write_byte(w, '\\', &n) or_return
write_byte(w, 'x', &n) or_return
write_byte(w, DIGITS_LOWER[s[0]>>4], &n) or_return
write_byte(w, DIGITS_LOWER[s[0]&0xf], &n) or_return
continue
}
n_wrapper(write_escaped_rune(w, r, quote, false, nil, for_json), &n) or_return
}
write_byte(w, quote, &n) or_return
return
}
// writer append a quoted rune into the byte buffer, return the written size // writer append a quoted rune into the byte buffer, return the written size
write_quoted_rune :: proc(w: Writer, r: rune) -> (n: int) { write_quoted_rune :: proc(w: Writer, r: rune) -> (n: int) {
_write_byte :: #force_inline proc(w: Writer, c: byte) -> int { _write_byte :: #force_inline proc(w: Writer, c: byte) -> int {
+3 -1
View File
@@ -43,12 +43,14 @@ File_Console_Logger_Data :: struct {
@(private) global_subtract_stderr_options: Options @(private) global_subtract_stderr_options: Options
@(init, private) @(init, private)
init_standard_stream_status :: proc() { init_standard_stream_status :: proc "contextless" () {
// NOTE(Feoramund): While it is technically possible for these streams to // NOTE(Feoramund): While it is technically possible for these streams to
// be redirected during the runtime of the program, the cost of checking on // be redirected during the runtime of the program, the cost of checking on
// every single log message is not worth it to support such an // every single log message is not worth it to support such an
// uncommonly-used feature. // uncommonly-used feature.
if terminal.color_enabled { if terminal.color_enabled {
context = runtime.default_context()
// This is done this way because it's possible that only one of these // This is done this way because it's possible that only one of these
// streams could be redirected to a file. // streams could be redirected to a file.
if !terminal.is_terminal(os.stdout) { if !terminal.is_terminal(os.stdout) {
+10 -8
View File
@@ -7,6 +7,7 @@
package math_big package math_big
import "base:intrinsics" import "base:intrinsics"
import "base:runtime"
import rnd "core:math/rand" import rnd "core:math/rand"
/* /*
@@ -778,22 +779,23 @@ 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{} INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
@(init, private) @(init, private)
_init_constants :: proc() { _init_constants :: proc "contextless" () {
initialize_constants() initialize_constants()
} }
initialize_constants :: proc() -> (res: int) { initialize_constants :: proc "contextless" () -> (res: int) {
internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable} context = runtime.default_context()
internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable} internal_int_set_from_integer( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.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}
/* /*
We set these special values to -1 or 1 so they don't get mistake for zero accidentally. We set these special values to -1 or 1 so they don't get mistake for zero accidentally.
This allows for shortcut tests of is_zero as .used == 0. This allows for shortcut tests of is_zero as .used == 0.
*/ */
internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN} internal_int_set_from_integer( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
internal_set( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf} internal_int_set_from_integer( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf}
internal_set(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf} internal_int_set_from_integer(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
return _DEFAULT_MUL_KARATSUBA_CUTOFF return _DEFAULT_MUL_KARATSUBA_CUTOFF
} }
+5 -5
View File
@@ -27,10 +27,10 @@
package math_big package math_big
import "core:mem"
import "base:intrinsics"
import rnd "core:math/rand"
import "base:builtin" import "base:builtin"
import "base:intrinsics"
import "core:mem"
import rnd "core:math/rand"
/* /*
Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7. Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7.
@@ -2885,12 +2885,12 @@ internal_clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context
} }
internal_clear_if_uninitialized :: proc {internal_clear_if_uninitialized_single, internal_clear_if_uninitialized_multi, } internal_clear_if_uninitialized :: proc {internal_clear_if_uninitialized_single, internal_clear_if_uninitialized_multi, }
internal_error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) { internal_error_if_immutable_single :: proc "contextless" (arg: ^Int) -> (err: Error) {
if arg != nil && .Immutable in arg.flags { return .Assignment_To_Immutable } if arg != nil && .Immutable in arg.flags { return .Assignment_To_Immutable }
return nil return nil
} }
internal_error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) { internal_error_if_immutable_multi :: proc "contextless" (args: ..^Int) -> (err: Error) {
for i in args { for i in args {
if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable } if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable }
} }
+18 -31
View File
@@ -56,13 +56,6 @@ query_info :: proc(gen := context.random_generator) -> Generator_Query_Info {
} }
@(private)
_random_u64 :: proc(gen := context.random_generator) -> (res: u64) {
ok := runtime.random_generator_read_ptr(gen, &res, size_of(res))
assert(ok, "uninitialized gen/context.random_generator")
return
}
/* /*
Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
@@ -84,7 +77,7 @@ Possible Output:
*/ */
@(require_results) @(require_results)
uint32 :: proc(gen := context.random_generator) -> (val: u32) { return u32(_random_u64(gen)) } uint32 :: proc(gen := context.random_generator) -> (val: u32) {return u32(uint64(gen))}
/* /*
Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
@@ -107,7 +100,11 @@ Possible Output:
*/ */
@(require_results) @(require_results)
uint64 :: proc(gen := context.random_generator) -> (val: u64) { return _random_u64(gen) } uint64 :: proc(gen := context.random_generator) -> (val: u64) {
ok := runtime.random_generator_read_ptr(gen, &val, size_of(val))
assert(ok, "uninitialized gen/context.random_generator")
return
}
/* /*
Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
@@ -131,13 +128,13 @@ Possible Output:
*/ */
@(require_results) @(require_results)
uint128 :: proc(gen := context.random_generator) -> (val: u128) { uint128 :: proc(gen := context.random_generator) -> (val: u128) {
a := u128(_random_u64(gen)) a := u128(uint64(gen))
b := u128(_random_u64(gen)) b := u128(uint64(gen))
return (a<<64) | b return (a<<64) | b
} }
/* /*
Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive. The sign bit will always be set to 0, thus all generated numbers will be positive.
Returns: Returns:
@@ -160,7 +157,7 @@ Possible Output:
@(require_results) int31 :: proc(gen := context.random_generator) -> (val: i32) { return i32(uint32(gen) << 1 >> 1) } @(require_results) int31 :: proc(gen := context.random_generator) -> (val: i32) { return i32(uint32(gen) << 1 >> 1) }
/* /*
Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive. The sign bit will always be set to 0, thus all generated numbers will be positive.
Returns: Returns:
@@ -183,7 +180,7 @@ Possible Output:
@(require_results) int63 :: proc(gen := context.random_generator) -> (val: i64) { return i64(uint64(gen) << 1 >> 1) } @(require_results) int63 :: proc(gen := context.random_generator) -> (val: i64) { return i64(uint64(gen) << 1 >> 1) }
/* /*
Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used.
The sign bit will always be set to 0, thus all generated numbers will be positive. The sign bit will always be set to 0, thus all generated numbers will be positive.
Returns: Returns:
@@ -480,8 +477,8 @@ Possible Output:
} }
/* /*
Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used. Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value. Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value.
Inputs: Inputs:
- p: The byte slice to fill - p: The byte slice to fill
@@ -508,22 +505,12 @@ Possible Output:
*/ */
@(require_results) @(require_results)
read :: proc(p: []byte, gen := context.random_generator) -> (n: int) { read :: proc(p: []byte, gen := context.random_generator) -> (n: int) {
pos := i8(0) if !runtime.random_generator_read_bytes(gen, p) {return 0}
val := i64(0) return len(p)
for n = 0; n < len(p); n += 1 {
if pos == 0 {
val = int63(gen)
pos = 7
}
p[n] = byte(val)
val >>= 8
pos -= 1
}
return
} }
/* /*
Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used. Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used.
*Allocates Using Provided Allocator* *Allocates Using Provided Allocator*
@@ -566,7 +553,7 @@ perm :: proc(n: int, allocator := context.allocator, gen := context.random_gener
} }
/* /*
Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used. Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- array: The slice to randomize - array: The slice to randomize
@@ -607,7 +594,7 @@ shuffle :: proc(array: $T/[]$E, gen := context.random_generator) {
} }
/* /*
Returns a random element from the provided slice. If no generator is provided the global random number generator will be used. Returns a random element from the provided slice. If no generator is provided the global random number generator will be used.
Inputs: Inputs:
- array: The slice to choose an element from - array: The slice to choose an element from
+2 -1
View File
@@ -2331,7 +2331,7 @@ buddy_allocator_alloc_bytes_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint)
} }
found.is_free = false found.is_free = false
data := ([^]byte)(found)[b.alignment:][:size] data := ([^]byte)(found)[b.alignment:][:size]
assert(cast(uintptr)raw_data(data)+cast(uintptr)size < cast(uintptr)buddy_block_next(found), "Buddy_Allocator has made an allocation which overlaps a block header.") assert(cast(uintptr)raw_data(data)+cast(uintptr)(size-1) < cast(uintptr)buddy_block_next(found), "Buddy_Allocator has made an allocation which overlaps a block header.")
// ensure_poisoned(data) // ensure_poisoned(data)
// sanitizer.address_unpoison(data) // sanitizer.address_unpoison(data)
return data, nil return data, nil
@@ -2436,6 +2436,7 @@ compat_allocator_init :: proc(rra: ^Compat_Allocator, allocator := context.alloc
rra.parent = allocator rra.parent = allocator
} }
@(require_results)
compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator { compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator {
return Allocator{ return Allocator{
data = rra, data = rra,
+1 -1
View File
@@ -9,7 +9,7 @@ _ :: runtime
DEFAULT_PAGE_SIZE := uint(4096) DEFAULT_PAGE_SIZE := uint(4096)
@(init, private) @(init, private)
platform_memory_init :: proc() { platform_memory_init :: proc "contextless" () {
_platform_memory_init() _platform_memory_init()
} }
+2 -2
View File
@@ -43,10 +43,10 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
return errno == .NONE return errno == .NONE
} }
_platform_memory_init :: proc() { _platform_memory_init :: proc "contextless" () {
DEFAULT_PAGE_SIZE = 4096 DEFAULT_PAGE_SIZE = 4096
// is power of two // is power of two
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
} }
+1 -1
View File
@@ -25,7 +25,7 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
return false return false
} }
_platform_memory_init :: proc() { _platform_memory_init :: proc "contextless" () {
} }
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
+2 -2
View File
@@ -28,13 +28,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK
} }
_platform_memory_init :: proc() { _platform_memory_init :: proc "contextless" () {
// NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`. // NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`.
size := posix.sysconf(._PAGESIZE) size := posix.sysconf(._PAGESIZE)
DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE)) DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE))
// is power of two // is power of two
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
} }
_map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) {
+3 -3
View File
@@ -72,7 +72,7 @@ foreign Kernel32 {
flProtect: u32, flProtect: u32,
dwMaximumSizeHigh: u32, dwMaximumSizeHigh: u32,
dwMaximumSizeLow: u32, dwMaximumSizeLow: u32,
lpName: [^]u16, lpName: cstring16,
) -> rawptr --- ) -> rawptr ---
MapViewOfFile :: proc( MapViewOfFile :: proc(
@@ -146,13 +146,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
@(no_sanitize_address) @(no_sanitize_address)
_platform_memory_init :: proc() { _platform_memory_init :: proc "contextless" () {
sys_info: SYSTEM_INFO sys_info: SYSTEM_INFO
GetSystemInfo(&sys_info) GetSystemInfo(&sys_info)
DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize)) DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize))
// is power of two // is power of two
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
} }
+1 -1
View File
@@ -79,7 +79,7 @@ Shutdown_Manner :: enum c.int {
} }
@(init, private) @(init, private)
ensure_winsock_initialized :: proc() { ensure_winsock_initialized :: proc "contextless" () {
win.ensure_winsock_initialized() win.ensure_winsock_initialized()
} }
+2 -2
View File
@@ -209,14 +209,14 @@ scan_comment :: proc(t: ^Tokenizer) -> string {
scan_file_tag :: proc(t: ^Tokenizer) -> string { scan_file_tag :: proc(t: ^Tokenizer) -> string {
offset := t.offset - 1 offset := t.offset - 1
for t.ch != '\n' { for t.ch != '\n' && t.ch != utf8.RUNE_EOF {
if t.ch == '/' { if t.ch == '/' {
next := peek_byte(t, 0) next := peek_byte(t, 0)
if next == '/' || next == '*' { if next == '/' || next == '*' {
break break
} }
} }
advance_rune(t) advance_rune(t)
} }
+1 -1
View File
@@ -87,7 +87,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
defer delete(path) defer delete(path)
find_data := &win32.WIN32_FIND_DATAW{} find_data := &win32.WIN32_FIND_DATAW{}
find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data) find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data)
if find_handle == win32.INVALID_HANDLE_VALUE { if find_handle == win32.INVALID_HANDLE_VALUE {
err = get_last_error() err = get_last_error()
return dfi[:], err return dfi[:], err
+2 -2
View File
@@ -16,7 +16,7 @@ MAX_TEMP_ARENA_COLLISIONS :: MAX_TEMP_ARENA_COUNT - 1
global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena
@(fini, private) @(fini, private)
temp_allocator_fini :: proc() { temp_allocator_fini :: proc "contextless" () {
for &arena in global_default_temp_allocator_arenas { for &arena in global_default_temp_allocator_arenas {
runtime.arena_destroy(&arena) runtime.arena_destroy(&arena)
} }
@@ -69,6 +69,6 @@ _temp_allocator_end :: proc(tmp: runtime.Arena_Temp) {
} }
@(init, private) @(init, private)
init_thread_local_cleaner :: proc() { init_thread_local_cleaner :: proc "contextless" () {
runtime.add_thread_local_cleaner(temp_allocator_fini) runtime.add_thread_local_cleaner(temp_allocator_fini)
} }
+3 -11
View File
@@ -16,7 +16,7 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al
} }
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
path := concatenate({base_path, `\`, win32_wstring_to_utf8(raw_data(d.cFileName[:]), temp_allocator) or_else ""}, allocator) or_return path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0) handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0)
defer win32.CloseHandle(handle) defer win32.CloseHandle(handle)
@@ -107,15 +107,7 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
return return
} }
wpath: []u16 wpath := string16(impl.wname)
{
i := 0
for impl.wname[i] != 0 {
i += 1
}
wpath = impl.wname[:i]
}
temp_allocator := TEMP_ALLOCATOR_GUARD({}) temp_allocator := TEMP_ALLOCATOR_GUARD({})
wpath_search := make([]u16, len(wpath)+3, temp_allocator) wpath_search := make([]u16, len(wpath)+3, temp_allocator)
@@ -124,7 +116,7 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
wpath_search[len(wpath)+1] = '*' wpath_search[len(wpath)+1] = '*'
wpath_search[len(wpath)+2] = 0 wpath_search[len(wpath)+2] = 0
it.impl.find_handle = win32.FindFirstFileW(raw_data(wpath_search), &it.impl.find_data) it.impl.find_handle = win32.FindFirstFileW(cstring16(raw_data(wpath_search)), &it.impl.find_data)
if it.impl.find_handle == win32.INVALID_HANDLE_VALUE { if it.impl.find_handle == win32.INVALID_HANDLE_VALUE {
read_directory_iterator_set_error(it, impl.name, _get_platform_error()) read_directory_iterator_set_error(it, impl.name, _get_platform_error())
return return
+1 -1
View File
@@ -31,7 +31,7 @@ _lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value:
return "", false return "", false
} }
value = win32_utf16_to_utf8(b[:n], allocator) or_else "" value = win32_utf16_to_utf8(string16(b[:n]), allocator) or_else ""
found = true found = true
return return
} }
+2 -2
View File
@@ -45,8 +45,8 @@ _stderr := File{
} }
@init @init
_standard_stream_init :: proc() { _standard_stream_init :: proc "contextless" () {
new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File { new_std :: proc "contextless" (impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
impl.file.impl = impl impl.file.impl = impl
impl.fd = linux.Fd(fd) impl.fd = linux.Fd(fd)
impl.allocator = runtime.nil_allocator() impl.allocator = runtime.nil_allocator()
+2 -2
View File
@@ -25,8 +25,8 @@ File_Impl :: struct {
} }
@(init) @(init)
init_std_files :: proc() { init_std_files :: proc "contextless" () {
new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File { new_std :: proc "contextless" (impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
impl.file.impl = impl impl.file.impl = impl
impl.fd = fd impl.fd = fd
impl.allocator = runtime.nil_allocator() impl.allocator = runtime.nil_allocator()
+1 -1
View File
@@ -151,7 +151,7 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
n: int n: int
n, err = read(f, buffer[:]) n, err = read(f, buffer[:])
total += n total += n
append_elems(&out_buffer, ..buffer[:n]) append_elems(&out_buffer, ..buffer[:n]) or_return
if err != nil { if err != nil {
if err == .EOF || err == .Broken_Pipe { if err == .EOF || err == .Broken_Pipe {
err = nil err = nil
+2 -2
View File
@@ -30,8 +30,8 @@ Preopen :: struct {
preopens: []Preopen preopens: []Preopen
@(init) @(init)
init_std_files :: proc() { init_std_files :: proc "contextless" () {
new_std :: proc(impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File { new_std :: proc "contextless" (impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File {
impl.file.impl = impl impl.file.impl = impl
impl.allocator = runtime.nil_allocator() impl.allocator = runtime.nil_allocator()
impl.fd = fd impl.fd = fd
+58 -22
View File
@@ -43,8 +43,8 @@ File_Impl :: struct {
} }
@(init) @(init)
init_std_files :: proc() { init_std_files :: proc "contextless" () {
new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File { new_std :: proc "contextless" (impl: ^File_Impl, code: u32, name: string) -> ^File {
impl.file.impl = impl impl.file.impl = impl
impl.allocator = runtime.nil_allocator() impl.allocator = runtime.nil_allocator()
@@ -77,7 +77,7 @@ init_std_files :: proc() {
stderr = new_std(&files[2], win32.STD_ERROR_HANDLE, "<stderr>") stderr = new_std(&files[2], win32.STD_ERROR_HANDLE, "<stderr>")
} }
_handle :: proc(f: ^File) -> win32.HANDLE { _handle :: proc "contextless" (f: ^File) -> win32.HANDLE {
return win32.HANDLE(_fd(f)) return win32.HANDLE(_fd(f))
} }
@@ -234,7 +234,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) {
return _new_file(uintptr(clonefd), name(f), file_allocator()) return _new_file(uintptr(clonefd), name(f), file_allocator())
} }
_fd :: proc(f: ^File) -> uintptr { _fd :: proc "contextless" (f: ^File) -> uintptr {
if f == nil || f.impl == nil { if f == nil || f.impl == nil {
return INVALID_HANDLE return INVALID_HANDLE
} }
@@ -247,7 +247,7 @@ _destroy :: proc(f: ^File_Impl) -> Error {
} }
a := f.allocator a := f.allocator
err0 := free(f.wname, a) err0 := free(rawptr(f.wname), a)
err1 := delete(f.name, a) err1 := delete(f.name, a)
err2 := delete(f.r_buf, a) err2 := delete(f.r_buf, a)
err3 := delete(f.w_buf, a) err3 := delete(f.w_buf, a)
@@ -619,7 +619,7 @@ _symlink :: proc(old_name, new_name: string) -> Error {
return .Unsupported return .Unsupported
} }
_open_sym_link :: proc(p: [^]u16) -> (handle: win32.HANDLE, err: Error) { _open_sym_link :: proc(p: cstring16) -> (handle: win32.HANDLE, err: Error) {
attrs := u32(win32.FILE_FLAG_BACKUP_SEMANTICS) attrs := u32(win32.FILE_FLAG_BACKUP_SEMANTICS)
attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT
handle = win32.CreateFileW(p, 0, 0, nil, win32.OPEN_EXISTING, attrs, nil) handle = win32.CreateFileW(p, 0, 0, nil, win32.OPEN_EXISTING, attrs, nil)
@@ -661,7 +661,7 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
} }
handle := _open_sym_link(raw_data(p)) or_return handle := _open_sym_link(cstring16(raw_data(p))) or_return
defer win32.CloseHandle(handle) defer win32.CloseHandle(handle)
n := win32.GetFinalPathNameByHandleW(handle, nil, 0, win32.VOLUME_NAME_DOS) n := win32.GetFinalPathNameByHandleW(handle, nil, 0, win32.VOLUME_NAME_DOS)
@@ -672,7 +672,7 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
buf := make([]u16, n+1, temp_allocator) buf := make([]u16, n+1, temp_allocator)
n = win32.GetFinalPathNameByHandleW(handle, raw_data(buf), u32(len(buf)), win32.VOLUME_NAME_DOS) n = win32.GetFinalPathNameByHandleW(handle, cstring16(raw_data(buf)), u32(len(buf)), win32.VOLUME_NAME_DOS)
if n == 0 { if n == 0 {
return "", _get_platform_error() return "", _get_platform_error()
} }
@@ -713,7 +713,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
switch rdb.ReparseTag { switch rdb.ReparseTag {
case win32.IO_REPARSE_TAG_SYMLINK: case win32.IO_REPARSE_TAG_SYMLINK:
rb := (^win32.SYMBOLIC_LINK_REPARSE_BUFFER)(&rdb.rest) rb := (^win32.SYMBOLIC_LINK_REPARSE_BUFFER)(&rdb.rest)
pb := win32.wstring(&rb.PathBuffer) pb := ([^]u16)(&rb.PathBuffer)
pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0 pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0
p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength] p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength]
if rb.Flags & win32.SYMLINK_FLAG_RELATIVE != 0 { if rb.Flags & win32.SYMLINK_FLAG_RELATIVE != 0 {
@@ -723,7 +723,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
case win32.IO_REPARSE_TAG_MOUNT_POINT: case win32.IO_REPARSE_TAG_MOUNT_POINT:
rb := (^win32.MOUNT_POINT_REPARSE_BUFFER)(&rdb.rest) rb := (^win32.MOUNT_POINT_REPARSE_BUFFER)(&rdb.rest)
pb := win32.wstring(&rb.PathBuffer) pb := ([^]u16)(&rb.PathBuffer)
pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0 pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0
p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength] p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength]
return _normalize_link_path(p, allocator) return _normalize_link_path(p, allocator)
@@ -874,8 +874,8 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
@(private="package", require_results) @(private="package", require_results)
win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: [^]u16, err: runtime.Allocator_Error) { win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: cstring16, err: runtime.Allocator_Error) {
ws = raw_data(win32_utf8_to_utf16(s, allocator) or_return) ws = cstring16(raw_data(win32_utf8_to_utf16(s, allocator) or_return))
return return
} }
@@ -909,24 +909,26 @@ win32_utf8_to_utf16 :: proc(s: string, allocator: runtime.Allocator) -> (ws: []u
} }
@(private="package", require_results) @(private="package", require_results)
win32_wstring_to_utf8 :: proc(s: [^]u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) { win32_wstring_to_utf8 :: proc(s: cstring16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
if s == nil || s[0] == 0 { if s == nil || s == "" {
return "", nil return "", nil
} }
n := 0 return win32_utf16_to_utf8(string16(s), allocator)
for s[n] != 0 { }
n += 1
} @(private="package")
return win32_utf16_to_utf8(s[:n], allocator) win32_utf16_to_utf8 :: proc{
win32_utf16_string16_to_utf8,
win32_utf16_u16_to_utf8,
} }
@(private="package", require_results) @(private="package", require_results)
win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) { win32_utf16_string16_to_utf8 :: proc(s: string16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
if len(s) == 0 { if len(s) == 0 {
return return
} }
n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), nil, 0, nil, nil) n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), nil, 0, nil, nil)
if n == 0 { if n == 0 {
return return
} }
@@ -938,7 +940,41 @@ win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: str
// will not be null terminated. // will not be null terminated.
text := make([]byte, n, allocator) or_return text := make([]byte, n, allocator) or_return
n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), raw_data(text), n, nil, nil) n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), raw_data(text), n, nil, nil)
if n1 == 0 {
delete(text, allocator)
return
}
for i in 0..<n {
if text[i] == 0 {
n = i
break
}
}
res = string(text[:n])
return
}
@(private="package", require_results)
win32_utf16_u16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
if len(s) == 0 {
return
}
n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), nil, 0, nil, nil)
if n == 0 {
return
}
// If N < 0 the call to WideCharToMultiByte assume the wide string is null terminated
// and will scan it to find the first null terminated character. The resulting string will
// also be null terminated.
// If N > 0 it assumes the wide string is not null terminated and the resulting string
// will not be null terminated.
text := make([]byte, n, allocator) or_return
n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), raw_data(text), n, nil, nil)
if n1 == 0 { if n1 == 0 {
delete(text, allocator) delete(text, allocator)
return return
+5 -5
View File
@@ -91,11 +91,11 @@ _remove_all :: proc(path: string) -> Error {
nil, nil,
win32.FO_DELETE, win32.FO_DELETE,
dir, dir,
&empty[0], cstring16(&empty[0]),
win32.FOF_NOCONFIRMATION | win32.FOF_NOERRORUI | win32.FOF_SILENT, win32.FOF_NOCONFIRMATION | win32.FOF_NOERRORUI | win32.FOF_SILENT,
false, false,
nil, nil,
&empty[0], cstring16(&empty[0]),
} }
res := win32.SHFileOperationW(&file_op) res := win32.SHFileOperationW(&file_op)
if res != 0 { if res != 0 {
@@ -160,7 +160,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
can_use_long_paths: bool can_use_long_paths: bool
@(init) @(init)
init_long_path_support :: proc() { init_long_path_support :: proc "contextless" () {
can_use_long_paths = false can_use_long_paths = false
key: win32.HKEY key: win32.HKEY
@@ -303,13 +303,13 @@ _get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absol
} }
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator) rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator)
n := win32.GetFullPathNameW(raw_data(rel_utf16), 0, nil, nil) n := win32.GetFullPathNameW(cstring16(raw_data(rel_utf16)), 0, nil, nil)
if n == 0 { if n == 0 {
return "", Platform_Error(win32.GetLastError()) return "", Platform_Error(win32.GetLastError())
} }
buf := make([]u16, n, temp_allocator) or_return buf := make([]u16, n, temp_allocator) or_return
n = win32.GetFullPathNameW(raw_data(rel_utf16), u32(n), raw_data(buf), nil) n = win32.GetFullPathNameW(cstring16(raw_data(rel_utf16)), u32(n), cstring16(raw_data(buf)), nil)
if n == 0 { if n == 0 {
return "", Platform_Error(win32.GetLastError()) return "", Platform_Error(win32.GetLastError())
} }
+8 -1
View File
@@ -16,7 +16,8 @@ Arguments to the current process.
args := get_args() args := get_args()
@(private="file") @(private="file")
get_args :: proc() -> []string { get_args :: proc "contextless" () -> []string {
context = runtime.default_context()
result := make([]string, len(runtime.args__), heap_allocator()) result := make([]string, len(runtime.args__), heap_allocator())
for rt_arg, i in runtime.args__ { for rt_arg, i in runtime.args__ {
result[i] = string(rt_arg) result[i] = string(rt_arg)
@@ -24,6 +25,12 @@ get_args :: proc() -> []string {
return result return result
} }
@(fini, private="file")
delete_args :: proc "contextless" () {
context = runtime.default_context()
delete(args, heap_allocator())
}
/* /*
Exit the current process. Exit the current process.
*/ */
+1 -1
View File
@@ -13,7 +13,7 @@ import "core:time"
foreign import lib "system:System" foreign import lib "system:System"
foreign lib { foreign lib {
sysctl :: proc( sysctl :: proc "c" (
name: [^]i32, namelen: u32, name: [^]i32, namelen: u32,
oldp: rawptr, oldlenp: ^uint, oldp: rawptr, oldlenp: ^uint,
newp: rawptr, newlen: uint, newp: rawptr, newlen: uint,
+4 -4
View File
@@ -175,7 +175,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator
info.fields += {.Command_Line} info.fields += {.Command_Line}
} }
if .Command_Args in selection { if .Command_Args in selection {
info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return info.command_args = _parse_command_line(cstring16(raw_data(cmdline_w)), allocator) or_return
info.fields += {.Command_Args} info.fields += {.Command_Args}
} }
} }
@@ -286,7 +286,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
info.fields += {.Command_Line} info.fields += {.Command_Line}
} }
if .Command_Args in selection { if .Command_Args in selection {
info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return info.command_args = _parse_command_line(cstring16(raw_data(cmdline_w)), allocator) or_return
info.fields += {.Command_Args} info.fields += {.Command_Args}
} }
} }
@@ -610,7 +610,7 @@ _process_exe_by_pid :: proc(pid: int, allocator: runtime.Allocator) -> (exe_path
err =_get_platform_error() err =_get_platform_error()
return return
} }
return win32_wstring_to_utf8(raw_data(entry.szExePath[:]), allocator) return win32_wstring_to_utf8(cstring16(raw_data(entry.szExePath[:])), allocator)
} }
_get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Allocator) -> (full_username: string, err: Error) { _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Allocator) -> (full_username: string, err: Error) {
@@ -650,7 +650,7 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc
return strings.concatenate({domain, "\\", username}, allocator) return strings.concatenate({domain, "\\", username}, allocator)
} }
_parse_command_line :: proc(cmd_line_w: [^]u16, allocator: runtime.Allocator) -> (argv: []string, err: Error) { _parse_command_line :: proc(cmd_line_w: cstring16, allocator: runtime.Allocator) -> (argv: []string, err: Error) {
argc: i32 argc: i32
argv_w := win32.CommandLineToArgvW(cmd_line_w, &argc) argv_w := win32.CommandLineToArgvW(cmd_line_w, &argc)
if argv_w == nil { if argv_w == nil {
+7 -7
View File
@@ -49,12 +49,12 @@ full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path
p := win32_utf8_to_utf16(name, temp_allocator) or_return p := win32_utf8_to_utf16(name, temp_allocator) or_return
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil) n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
if n == 0 { if n == 0 {
return "", _get_platform_error() return "", _get_platform_error()
} }
buf := make([]u16, n+1, temp_allocator) buf := make([]u16, n+1, temp_allocator)
n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
if n == 0 { if n == 0 {
return "", _get_platform_error() return "", _get_platform_error()
} }
@@ -140,8 +140,8 @@ _cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (strin
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
buf := make([]u16, max(n, 260)+1, temp_allocator) buf := make([]u16, max(n, 260)+1, temp_allocator)
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0) n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
return _cleanpath_from_buf(buf[:n], allocator) return _cleanpath_from_buf(string16(buf[:n]), allocator)
} }
_cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) { _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
@@ -158,12 +158,12 @@ _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({}) temp_allocator := TEMP_ALLOCATOR_GUARD({})
buf := make([]u16, max(n, 260)+1, temp_allocator) buf := make([]u16, max(n, 260)+1, temp_allocator)
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0) n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
return _cleanpath_strip_prefix(buf[:n]), nil return _cleanpath_strip_prefix(buf[:n]), nil
} }
_cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { _cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
buf := buf buf := transmute([]u16)buf
buf = _cleanpath_strip_prefix(buf) buf = _cleanpath_strip_prefix(buf)
return win32_utf16_to_utf8(buf, allocator) return win32_utf16_to_utf8(buf, allocator)
} }
+2 -2
View File
@@ -12,12 +12,12 @@ _temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Er
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
b := make([]u16, max(win32.MAX_PATH, n), temp_allocator) b := make([]u16, max(win32.MAX_PATH, n), temp_allocator)
n = win32.GetTempPathW(u32(len(b)), raw_data(b)) n = win32.GetTempPathW(u32(len(b)), cstring16(raw_data(b)))
if n == 3 && b[1] == ':' && b[2] == '\\' { if n == 3 && b[1] == ':' && b[2] == '\\' {
} else if n > 0 && b[n-1] == '\\' { } else if n > 0 && b[n-1] == '\\' {
n -= 1 n -= 1
} }
return win32_utf16_to_utf8(b[:n], allocator) return win32_utf16_to_utf8(string16(b[:n]), allocator)
} }
+1 -2
View File
@@ -74,6 +74,5 @@ _get_known_folder_path :: proc(rfid: win32.REFKNOWNFOLDERID, allocator: runtime.
return "", .Invalid_Path return "", .Invalid_Path
} }
dir, _ = win32.wstring_to_utf8(path_w, -1, allocator) return win32_wstring_to_utf8(cstring16(path_w), allocator)
return
} }
+4 -2
View File
@@ -1226,7 +1226,8 @@ _processor_core_count :: proc() -> int {
} }
@(private, require_results) @(private, require_results)
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
res := make([]string, len(runtime.args__)) res := make([]string, len(runtime.args__))
for _, i in res { for _, i in res {
res[i] = string(runtime.args__[i]) res[i] = string(runtime.args__[i])
@@ -1235,7 +1236,8 @@ _alloc_command_line_arguments :: proc() -> []string {
} }
@(private, fini) @(private, fini)
_delete_command_line_arguments :: proc() { _delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args) delete(args)
} }
+4 -2
View File
@@ -965,7 +965,8 @@ _processor_core_count :: proc() -> int {
@(private, require_results) @(private, require_results)
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
res := make([]string, len(runtime.args__)) res := make([]string, len(runtime.args__))
for _, i in res { for _, i in res {
res[i] = string(runtime.args__[i]) res[i] = string(runtime.args__[i])
@@ -974,6 +975,7 @@ _alloc_command_line_arguments :: proc() -> []string {
} }
@(private, fini) @(private, fini)
_delete_command_line_arguments :: proc() { _delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args) delete(args)
} }
+4 -2
View File
@@ -317,7 +317,8 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
args := _alloc_command_line_arguments() args := _alloc_command_line_arguments()
@(private, require_results) @(private, require_results)
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
res := make([]string, len(runtime.args__)) res := make([]string, len(runtime.args__))
for arg, i in runtime.args__ { for arg, i in runtime.args__ {
res[i] = string(arg) res[i] = string(arg)
@@ -326,7 +327,8 @@ _alloc_command_line_arguments :: proc() -> []string {
} }
@(private, fini) @(private, fini)
_delete_command_line_arguments :: proc() { _delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args) delete(args)
} }
+4 -2
View File
@@ -1098,7 +1098,8 @@ _processor_core_count :: proc() -> int {
} }
@(private, require_results) @(private, require_results)
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
res := make([]string, len(runtime.args__)) res := make([]string, len(runtime.args__))
for _, i in res { for _, i in res {
res[i] = string(runtime.args__[i]) res[i] = string(runtime.args__[i])
@@ -1107,7 +1108,8 @@ _alloc_command_line_arguments :: proc() -> []string {
} }
@(private, fini) @(private, fini)
_delete_command_line_arguments :: proc() { _delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args) delete(args)
} }
+4 -2
View File
@@ -1015,7 +1015,8 @@ _processor_core_count :: proc() -> int {
} }
@(private, require_results) @(private, require_results)
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
res := make([]string, len(runtime.args__)) res := make([]string, len(runtime.args__))
for _, i in res { for _, i in res {
res[i] = string(runtime.args__[i]) res[i] = string(runtime.args__[i])
@@ -1024,6 +1025,7 @@ _alloc_command_line_arguments :: proc() -> []string {
} }
@(private, fini) @(private, fini)
_delete_command_line_arguments :: proc() { _delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args) delete(args)
} }
+4 -2
View File
@@ -915,7 +915,8 @@ _processor_core_count :: proc() -> int {
} }
@(private, require_results) @(private, require_results)
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
res := make([]string, len(runtime.args__)) res := make([]string, len(runtime.args__))
for _, i in res { for _, i in res {
res[i] = string(runtime.args__[i]) res[i] = string(runtime.args__[i])
@@ -924,6 +925,7 @@ _alloc_command_line_arguments :: proc() -> []string {
} }
@(private, fini) @(private, fini)
_delete_command_line_arguments :: proc() { _delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args) delete(args)
} }
+11 -8
View File
@@ -28,16 +28,18 @@ stderr: Handle = 2
args := _alloc_command_line_arguments() args := _alloc_command_line_arguments()
@(private, require_results) @(private, require_results)
_alloc_command_line_arguments :: proc() -> (args: []string) { _alloc_command_line_arguments :: proc "contextless" () -> []string {
args = make([]string, len(runtime.args__)) context = runtime.default_context()
for &arg, i in args { cmd_args := make([]string, len(runtime.args__))
for &arg, i in cmd_args {
arg = string(runtime.args__[i]) arg = string(runtime.args__[i])
} }
return return cmd_args
} }
@(private, fini) @(private, fini)
_delete_command_line_arguments :: proc() { _delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args) delete(args)
} }
@@ -57,9 +59,8 @@ Preopen :: struct {
preopens: []Preopen preopens: []Preopen
@(init, private) @(init, private)
init_preopens :: proc() { init_preopens :: proc "contextless" () {
strip_prefixes :: proc "contextless"(path: string) -> string {
strip_prefixes :: proc(path: string) -> string {
path := path path := path
loop: for len(path) > 0 { loop: for len(path) > 0 {
switch { switch {
@@ -76,6 +77,8 @@ init_preopens :: proc() {
return path return path
} }
context = runtime.default_context()
dyn_preopens: [dynamic]Preopen dyn_preopens: [dynamic]Preopen
loop: for fd := wasi.fd_t(3); ; fd += 1 { loop: for fd := wasi.fd_t(3); ; fd += 1 {
desc, err := wasi.fd_prestat_get(fd) desc, err := wasi.fd_prestat_get(fd)
+4 -2
View File
@@ -194,7 +194,8 @@ current_thread_id :: proc "contextless" () -> int {
@(private, require_results) @(private, require_results)
_alloc_command_line_arguments :: proc() -> []string { _alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
arg_count: i32 arg_count: i32
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count) arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count)
arg_list := make([]string, int(arg_count)) arg_list := make([]string, int(arg_count))
@@ -216,7 +217,8 @@ _alloc_command_line_arguments :: proc() -> []string {
} }
@(private, fini) @(private, fini)
_delete_command_line_arguments :: proc() { _delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
for s in args { for s in args {
delete(s) delete(s)
} }
+2 -2
View File
@@ -17,7 +17,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
buf := make([dynamic]u16, 100) buf := make([dynamic]u16, 100)
defer delete(buf) defer delete(buf)
for { for {
n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
if n == 0 { if n == 0 {
return "", get_last_error() return "", get_last_error()
} }
@@ -154,7 +154,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> (
return nil, get_last_error() return nil, get_last_error()
} }
buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) buf := make([]u16, max(n, win32.DWORD(260))+1, allocator)
buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0)
return buf[:buf_len], nil return buf[:buf_len], nil
} }
@(private, require_results) @(private, require_results)
+2 -2
View File
@@ -61,13 +61,13 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) {
} }
p := win32.utf8_to_utf16(name, ta) p := win32.utf8_to_utf16(name, ta)
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil) n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
if n == 0 { if n == 0 {
return "", os.get_last_error() return "", os.get_last_error()
} }
buf := make([]u16, n, ta) buf := make([]u16, n, ta)
n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil)
if n == 0 { if n == 0 {
delete(buf) delete(buf)
return "", os.get_last_error() return "", os.get_last_error()
+6 -3
View File
@@ -511,9 +511,12 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
io.write_i64(w, i64(8*ti.size), 10, &n) or_return io.write_i64(w, i64(8*ti.size), 10, &n) or_return
case Type_Info_String: case Type_Info_String:
if info.is_cstring { if info.is_cstring {
io.write_string(w, "cstring", &n) or_return io.write_byte(w, 'c', &n) or_return
} else { }
io.write_string(w, "string", &n) or_return io.write_string(w, "string", &n) or_return
switch info.encoding {
case .UTF_8: /**/
case .UTF_16: io.write_string(w, "16", &n) or_return
} }
case Type_Info_Boolean: case Type_Info_Boolean:
switch ti.id { switch ti.id {
@@ -0,0 +1,50 @@
package objc_Foundation
import "base:intrinsics"
@(objc_class="NSBitmapImageRep")
BitmapImageRep :: struct { using _: Object }
@(objc_type=BitmapImageRep, objc_name="alloc", objc_is_class_method=true)
BitmapImageRep_alloc :: proc "c" () -> ^BitmapImageRep {
return msgSend(^BitmapImageRep, BitmapImageRep, "alloc")
}
@(objc_type=BitmapImageRep, objc_name="initWithBitmapDataPlanes")
BitmapImageRep_initWithBitmapDataPlanes :: proc "c" (
self: ^BitmapImageRep,
bitmapDataPlanes: ^^u8,
pixelsWide: Integer,
pixelsHigh: Integer,
bitsPerSample: Integer,
samplesPerPixel: Integer,
hasAlpha: bool,
isPlanar: bool,
colorSpaceName: ^String,
bytesPerRow: Integer,
bitsPerPixel: Integer) -> ^BitmapImageRep {
return msgSend(^BitmapImageRep,
self,
"initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bytesPerRow:bitsPerPixel:",
bitmapDataPlanes,
pixelsWide,
pixelsHigh,
bitsPerSample,
samplesPerPixel,
hasAlpha,
isPlanar,
colorSpaceName,
bytesPerRow,
bitsPerPixel)
}
@(objc_type=BitmapImageRep, objc_name="bitmapData")
BitmapImageRep_bitmapData :: proc "c" (self: ^BitmapImageRep) -> rawptr {
return msgSend(rawptr, self, "bitmapData")
}
@(objc_type=BitmapImageRep, objc_name="CGImage")
BitmapImageRep_CGImage :: proc "c" (self: ^BitmapImageRep) -> rawptr {
return msgSend(rawptr, self, "CGImage")
}
+19 -2
View File
@@ -568,6 +568,15 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla
@(objc_class="CALayer") @(objc_class="CALayer")
Layer :: struct { using _: Object } Layer :: struct { using _: Object }
@(objc_type=Layer, objc_name="contents")
Layer_contents :: proc "c" (self: ^Layer) -> rawptr {
return msgSend(rawptr, self, "contents")
}
@(objc_type=Layer, objc_name="setContents")
Layer_setContents :: proc "c" (self: ^Layer, contents: rawptr) {
msgSend(nil, self, "setContents:", contents)
}
@(objc_type=Layer, objc_name="contentsScale") @(objc_type=Layer, objc_name="contentsScale")
Layer_contentsScale :: proc "c" (self: ^Layer) -> Float { Layer_contentsScale :: proc "c" (self: ^Layer) -> Float {
return msgSend(Float, self, "contentsScale") return msgSend(Float, self, "contentsScale")
@@ -654,8 +663,12 @@ Window_frame :: proc "c" (self: ^Window) -> Rect {
return msgSend(Rect, self, "frame") return msgSend(Rect, self, "frame")
} }
@(objc_type=Window, objc_name="setFrame") @(objc_type=Window, objc_name="setFrame")
Window_setFrame :: proc "c" (self: ^Window, frame: Rect) { Window_setFrame :: proc "c" (self: ^Window, frame: Rect, display: BOOL) {
msgSend(nil, self, "setFrame:", frame) msgSend(nil, self, "setFrame:display:", frame, display)
}
@(objc_type=Window, objc_name="setFrameOrigin")
Window_setFrameOrigin :: proc "c" (self: ^Window, origin: Point) {
msgSend(nil, self, "setFrameOrigin:", origin)
} }
@(objc_type=Window, objc_name="opaque") @(objc_type=Window, objc_name="opaque")
Window_opaque :: proc "c" (self: ^Window) -> BOOL { Window_opaque :: proc "c" (self: ^Window) -> BOOL {
@@ -693,6 +706,10 @@ Window_setMovable :: proc "c" (self: ^Window, ok: BOOL) {
Window_setMovableByWindowBackground :: proc "c" (self: ^Window, ok: BOOL) { Window_setMovableByWindowBackground :: proc "c" (self: ^Window, ok: BOOL) {
msgSend(nil, self, "setMovableByWindowBackground:", ok) msgSend(nil, self, "setMovableByWindowBackground:", ok)
} }
@(objc_type=Window, objc_name="setAcceptsMouseMovedEvents")
Window_setAcceptsMouseMovedEvents :: proc "c" (self: ^Window, ok: BOOL) {
msgSend(nil, self, "setAcceptsMouseMovedEvents:", ok)
}
@(objc_type=Window, objc_name="setStyleMask") @(objc_type=Window, objc_name="setStyleMask")
Window_setStyleMask :: proc "c" (self: ^Window, style_mask: WindowStyleMask) { Window_setStyleMask :: proc "c" (self: ^Window, style_mask: WindowStyleMask) {
msgSend(nil, self, "setStyleMask:", style_mask) msgSend(nil, self, "setStyleMask:", style_mask)
+2 -2
View File
@@ -52,7 +52,7 @@ CPU :: struct {
cpu: CPU cpu: CPU
@(init, private) @(init, private)
init_cpu_features :: proc "c" () { init_cpu_features :: proc "contextless" () {
is_set :: #force_inline proc "c" (bit: u32, value: u32) -> bool { is_set :: #force_inline proc "c" (bit: u32, value: u32) -> bool {
return (value>>bit) & 0x1 != 0 return (value>>bit) & 0x1 != 0
} }
@@ -156,7 +156,7 @@ init_cpu_features :: proc "c" () {
_cpu_name_buf: [72]u8 _cpu_name_buf: [72]u8
@(init, private) @(init, private)
init_cpu_name :: proc "c" () { init_cpu_name :: proc "contextless" () {
number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0) number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0)
if number_of_extended_ids < 0x8000_0004 { if number_of_extended_ids < 0x8000_0004 {
return return
+3 -1
View File
@@ -2,11 +2,13 @@
#+build linux #+build linux
package sysinfo package sysinfo
import "base:runtime"
import "core:sys/linux" import "core:sys/linux"
import "core:strings" import "core:strings"
@(init, private) @(init, private)
init_cpu_features :: proc() { init_cpu_features :: proc "contextless" () {
context = runtime.default_context()
fd, err := linux.open("/proc/cpuinfo", {}) fd, err := linux.open("/proc/cpuinfo", {})
if err != .NONE { return } if err != .NONE { return }
defer linux.close(fd) defer linux.close(fd)
+4 -1
View File
@@ -2,12 +2,15 @@
#+build linux #+build linux
package sysinfo package sysinfo
import "base:runtime"
import "core:sys/linux" import "core:sys/linux"
import "core:strings" import "core:strings"
import "core:strconv" import "core:strconv"
@(init, private) @(init, private)
init_cpu_core_count :: proc() { init_cpu_core_count :: proc "contextless" () {
context = runtime.default_context()
fd, err := linux.open("/proc/cpuinfo", {}) fd, err := linux.open("/proc/cpuinfo", {})
if err != .NONE { return } if err != .NONE { return }
defer linux.close(fd) defer linux.close(fd)
+5 -5
View File
@@ -7,7 +7,7 @@ import "base:intrinsics"
import "core:sys/linux" import "core:sys/linux"
@(init, private) @(init, private)
init_cpu_features :: proc() { init_cpu_features :: proc "contextless" () {
_features: CPU_Features _features: CPU_Features
defer cpu.features = _features defer cpu.features = _features
@@ -81,11 +81,11 @@ init_cpu_features :: proc() {
} }
err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {}) err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {})
if err != nil { if err != nil {
assert(err == .ENOSYS, "unexpected error from riscv_hwprobe()") assert_contextless(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
return return
} }
assert(pairs[0].key == .IMA_EXT_0) assert_contextless(pairs[0].key == .IMA_EXT_0)
exts := pairs[0].value.ima_ext_0 exts := pairs[0].value.ima_ext_0
exts -= { .FD, .C, .V } exts -= { .FD, .C, .V }
_features += transmute(CPU_Features)exts _features += transmute(CPU_Features)exts
@@ -97,7 +97,7 @@ init_cpu_features :: proc() {
_features += { .Misaligned_Supported } _features += { .Misaligned_Supported }
} }
} else { } else {
assert(pairs[1].key == .CPUPERF_0) assert_contextless(pairs[1].key == .CPUPERF_0)
if .FAST in pairs[1].value.cpu_perf_0 { if .FAST in pairs[1].value.cpu_perf_0 {
_features += { .Misaligned_Supported, .Misaligned_Fast } _features += { .Misaligned_Supported, .Misaligned_Fast }
} else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 { } else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 {
@@ -108,6 +108,6 @@ init_cpu_features :: proc() {
} }
@(init, private) @(init, private)
init_cpu_name :: proc() { init_cpu_name :: proc "contextless" () {
cpu.name = "RISCV64" cpu.name = "RISCV64"
} }
+4 -1
View File
@@ -2,9 +2,12 @@ package sysinfo
import sys "core:sys/windows" import sys "core:sys/windows"
import "base:intrinsics" import "base:intrinsics"
import "base:runtime"
@(init, private) @(init, private)
init_cpu_core_count :: proc() { init_cpu_core_count :: proc "contextless" () {
context = runtime.default_context()
infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION
defer delete(infos) defer delete(infos)
+4 -2
View File
@@ -10,7 +10,9 @@ import "base:runtime"
version_string_buf: [1024]u8 version_string_buf: [1024]u8
@(init, private) @(init, private)
init_os_version :: proc () { init_os_version :: proc "contextless" () {
context = runtime.default_context()
when ODIN_OS == .NetBSD { when ODIN_OS == .NetBSD {
os_version.platform = .NetBSD os_version.platform = .NetBSD
} else { } else {
@@ -66,7 +68,7 @@ init_os_version :: proc () {
} }
@(init, private) @(init, private)
init_ram :: proc() { init_ram :: proc "contextless" () {
// Retrieve RAM info using `sysctl` // Retrieve RAM info using `sysctl`
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64} mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64}
mem_size: u64 mem_size: u64
+4 -1
View File
@@ -1,5 +1,7 @@
package sysinfo package sysinfo
import "base:runtime"
import "core:strconv" import "core:strconv"
import "core:strings" import "core:strings"
import "core:sys/unix" import "core:sys/unix"
@@ -9,7 +11,8 @@ import NS "core:sys/darwin/Foundation"
version_string_buf: [1024]u8 version_string_buf: [1024]u8
@(init, private) @(init, private)
init_platform :: proc() { init_platform :: proc "contextless" () {
context = runtime.default_context()
ws :: strings.write_string ws :: strings.write_string
wi :: strings.write_int wi :: strings.write_int
+4 -2
View File
@@ -9,7 +9,9 @@ import "base:runtime"
version_string_buf: [1024]u8 version_string_buf: [1024]u8
@(init, private) @(init, private)
init_os_version :: proc () { init_os_version :: proc "contextless" () {
context = runtime.default_context()
os_version.platform = .FreeBSD os_version.platform = .FreeBSD
kernel_version_buf: [1024]u8 kernel_version_buf: [1024]u8
@@ -68,7 +70,7 @@ init_os_version :: proc () {
} }
@(init, private) @(init, private)
init_ram :: proc() { init_ram :: proc "contextless" () {
// Retrieve RAM info using `sysctl` // Retrieve RAM info using `sysctl`
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM} mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM}
mem_size: u64 mem_size: u64
+6 -3
View File
@@ -1,6 +1,7 @@
package sysinfo package sysinfo
import "base:intrinsics" import "base:intrinsics"
import "base:runtime"
import "core:strconv" import "core:strconv"
import "core:strings" import "core:strings"
@@ -10,7 +11,9 @@ import "core:sys/linux"
version_string_buf: [1024]u8 version_string_buf: [1024]u8
@(init, private) @(init, private)
init_os_version :: proc () { init_os_version :: proc "contextless" () {
context = runtime.default_context()
os_version.platform = .Linux os_version.platform = .Linux
b := strings.builder_from_bytes(version_string_buf[:]) b := strings.builder_from_bytes(version_string_buf[:])
@@ -91,11 +94,11 @@ init_os_version :: proc () {
} }
@(init, private) @(init, private)
init_ram :: proc() { init_ram :: proc "contextless" () {
// Retrieve RAM info using `sysinfo` // Retrieve RAM info using `sysinfo`
sys_info: linux.Sys_Info sys_info: linux.Sys_Info
errno := linux.sysinfo(&sys_info) errno := linux.sysinfo(&sys_info)
assert(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!") assert_contextless(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!")
ram = RAM{ ram = RAM{
total_ram = int(sys_info.totalram) * int(sys_info.mem_unit), total_ram = int(sys_info.totalram) * int(sys_info.mem_unit),
free_ram = int(sys_info.freeram) * int(sys_info.mem_unit), free_ram = int(sys_info.freeram) * int(sys_info.mem_unit),
+14 -10
View File
@@ -12,7 +12,9 @@ import "base:runtime"
version_string_buf: [1024]u8 version_string_buf: [1024]u8
@(init, private) @(init, private)
init_os_version :: proc () { init_os_version :: proc "contextless" () {
context = runtime.default_context()
/* /*
NOTE(Jeroen): NOTE(Jeroen):
`GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10. `GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10.
@@ -43,6 +45,7 @@ init_os_version :: proc () {
os_version.minor = int(osvi.dwMinorVersion) os_version.minor = int(osvi.dwMinorVersion)
os_version.build[0] = int(osvi.dwBuildNumber) os_version.build[0] = int(osvi.dwBuildNumber)
b := strings.builder_from_bytes(version_string_buf[:]) b := strings.builder_from_bytes(version_string_buf[:])
strings.write_string(&b, "Windows ") strings.write_string(&b, "Windows ")
@@ -259,7 +262,7 @@ init_os_version :: proc () {
} }
@(init, private) @(init, private)
init_ram :: proc() { init_ram :: proc "contextless" () {
state: sys.MEMORYSTATUSEX state: sys.MEMORYSTATUSEX
state.dwLength = size_of(state) state.dwLength = size_of(state)
@@ -276,10 +279,11 @@ init_ram :: proc() {
} }
@(init, private) @(init, private)
init_gpu_info :: proc() { init_gpu_info :: proc "contextless" () {
GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\" GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\"
context = runtime.default_context()
gpu_list: [dynamic]GPU gpu_list: [dynamic]GPU
gpu_index: int gpu_index: int
@@ -324,8 +328,8 @@ read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok
status := sys.RegGetValueW( status := sys.RegGetValueW(
hkey, hkey,
&key_name_wide[0], cstring16(&key_name_wide[0]),
&val_name_wide[0], cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_SZ, sys.RRF_RT_REG_SZ,
nil, nil,
raw_data(result_wide[:]), raw_data(result_wide[:]),
@@ -359,8 +363,8 @@ read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool
result_size := sys.DWORD(size_of(i32)) result_size := sys.DWORD(size_of(i32))
status := sys.RegGetValueW( status := sys.RegGetValueW(
hkey, hkey,
&key_name_wide[0], cstring16(&key_name_wide[0]),
&val_name_wide[0], cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_DWORD, sys.RRF_RT_REG_DWORD,
nil, nil,
&res, &res,
@@ -386,8 +390,8 @@ read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool
result_size := sys.DWORD(size_of(i64)) result_size := sys.DWORD(size_of(i64))
status := sys.RegGetValueW( status := sys.RegGetValueW(
hkey, hkey,
&key_name_wide[0], cstring16(&key_name_wide[0]),
&val_name_wide[0], cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_QWORD, sys.RRF_RT_REG_QWORD,
nil, nil,
&res, &res,
+1 -1
View File
@@ -1838,7 +1838,7 @@ Clock_Id :: enum {
Bits for POSIX interval timer flags. Bits for POSIX interval timer flags.
*/ */
ITimer_Flags_Bits :: enum { ITimer_Flags_Bits :: enum {
ABSTIME = 1, ABSTIME = 0,
} }
/* /*
+1
View File
@@ -1,3 +1,4 @@
#+build linux, darwin, openbsd, freebsd, netbsd, haiku
package posix package posix
when ODIN_OS == .Darwin { when ODIN_OS == .Darwin {
+1 -1
View File
@@ -60,7 +60,7 @@ wctomb :: libc.wctomb
mbstowcs :: libc.mbstowcs mbstowcs :: libc.mbstowcs
wcstombs :: libc.wcstombs wcstombs :: libc.wcstombs
free :: #force_inline proc(ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring { free :: #force_inline proc "c" (ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring {
libc.free(rawptr(ptr)) libc.free(rawptr(ptr))
} }
+1 -1
View File
@@ -3,7 +3,7 @@ package unix
import "base:intrinsics" import "base:intrinsics"
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
mib := mib mib := mib
result_size := u64(size_of(T)) result_size := u64(size_of(T))
+1 -1
View File
@@ -8,7 +8,7 @@ foreign libc {
@(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 --- @(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 ---
} }
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
mib := mib mib := mib
result_size := c.size_t(size_of(T)) result_size := c.size_t(size_of(T))
res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0) res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0)
+1 -1
View File
@@ -9,7 +9,7 @@ foreign libc {
@(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 --- @(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 ---
} }
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
mib := mib mib := mib
result_size := c.size_t(size_of(T)) result_size := c.size_t(size_of(T))
res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0) res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0)
+20
View File
@@ -373,12 +373,32 @@ remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callba
return _remove_window_event_listener(event_kind_string[kind], user_data, callback, use_capture) return _remove_window_event_listener(event_kind_string[kind], user_data, callback, use_capture)
} }
add_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
@(default_calling_convention="contextless")
foreign dom_lib {
@(link_name="add_document_event_listener")
_add_document_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
}
return _add_document_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture)
}
remove_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
@(default_calling_convention="contextless")
foreign dom_lib {
@(link_name="remove_document_event_listener")
_remove_document_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool ---
}
return _remove_document_event_listener(event_kind_string[kind], user_data, callback, use_capture)
}
remove_event_listener_from_event :: proc(e: Event) -> bool { remove_event_listener_from_event :: proc(e: Event) -> bool {
from_use_capture_false: bool from_use_capture_false: bool
from_use_capture_true: bool from_use_capture_true: bool
if e.id == "" { if e.id == "" {
from_use_capture_false = remove_window_event_listener(e.kind, e.user_data, e.callback, false) from_use_capture_false = remove_window_event_listener(e.kind, e.user_data, e.callback, false)
from_use_capture_true = remove_window_event_listener(e.kind, e.user_data, e.callback, true) from_use_capture_true = remove_window_event_listener(e.kind, e.user_data, e.callback, true)
from_use_capture_false |= remove_document_event_listener(e.kind, e.user_data, e.callback, false)
from_use_capture_true |= remove_document_event_listener(e.kind, e.user_data, e.callback, true)
} else { } else {
from_use_capture_false = remove_event_listener(e.id, e.kind, e.user_data, e.callback, false) from_use_capture_false = remove_event_listener(e.id, e.kind, e.user_data, e.callback, false)
from_use_capture_true = remove_event_listener(e.id, e.kind, e.user_data, e.callback, true) from_use_capture_true = remove_event_listener(e.id, e.kind, e.user_data, e.callback, true)
+8
View File
@@ -275,6 +275,14 @@ remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callba
panic("vendor:wasm/js not supported on non JS targets") panic("vendor:wasm/js not supported on non JS targets")
} }
add_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
panic("vendor:wasm/js not supported on non JS targets")
}
remove_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool {
panic("vendor:wasm/js not supported on non JS targets")
}
remove_event_listener_from_event :: proc(e: Event) -> bool { remove_event_listener_from_event :: proc(e: Event) -> bool {
panic("vendor:wasm/js not supported on non JS targets") panic("vendor:wasm/js not supported on non JS targets")
} }
+73
View File
@@ -392,6 +392,9 @@ class WebGLInterface {
BindTexture: (target, texture) => { BindTexture: (target, texture) => {
this.ctx.bindTexture(target, texture ? this.textures[texture] : null) this.ctx.bindTexture(target, texture ? this.textures[texture] : null)
}, },
BindRenderbuffer: (target, renderbuffer) => {
this.ctx.bindRenderbuffer(target, renderbuffer ? this.renderbuffers[renderbuffer] : null)
},
BlendColor: (red, green, blue, alpha) => { BlendColor: (red, green, blue, alpha) => {
this.ctx.blendColor(red, green, blue, alpha); this.ctx.blendColor(red, green, blue, alpha);
}, },
@@ -809,6 +812,40 @@ class WebGLInterface {
Uniform3i: (location, v0, v1, v2) => { this.ctx.uniform3i(this.uniforms[location], v0, v1, v2); }, Uniform3i: (location, v0, v1, v2) => { this.ctx.uniform3i(this.uniforms[location], v0, v1, v2); },
Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); }, Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); },
Uniform1fv: (location, count, addr) => {
let array = this.mem.loadF32Array(addr, 1*count);
this.ctx.uniform1fv(this.uniforms[location], array);
},
Uniform2fv: (location, count, addr) => {
let array = this.mem.loadF32Array(addr, 2*count);
this.ctx.uniform2fv(this.uniforms[location], array);
},
Uniform3fv: (location, count, addr) => {
let array = this.mem.loadF32Array(addr, 3*count);
this.ctx.uniform3fv(this.uniforms[location], array);
},
Uniform4fv: (location, count, addr) => {
let array = this.mem.loadF32Array(addr, 4*count);
this.ctx.uniform4fv(this.uniforms[location], array);
},
Uniform1iv: (location, count, addr) => {
let array = this.mem.loadI32Array(addr, 1*count);
this.ctx.uniform1iv(this.uniforms[location], array);
},
Uniform2iv: (location, count, addr) => {
let array = this.mem.loadI32Array(addr, 2*count);
this.ctx.uniform2iv(this.uniforms[location], array);
},
Uniform3iv: (location, count, addr) => {
let array = this.mem.loadI32Array(addr, 3*count);
this.ctx.uniform3iv(this.uniforms[location], array);
},
Uniform4iv: (location, count, addr) => {
let array = this.mem.loadI32Array(addr, 4*count);
this.ctx.uniform4iv(this.uniforms[location], array);
},
UniformMatrix2fv: (location, addr) => { UniformMatrix2fv: (location, addr) => {
let array = this.mem.loadF32Array(addr, 2*2); let array = this.mem.loadF32Array(addr, 2*2);
this.ctx.uniformMatrix2fv(this.uniforms[location], false, array); this.ctx.uniformMatrix2fv(this.uniforms[location], false, array);
@@ -1701,6 +1738,28 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
return true; return true;
}, },
add_document_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => {
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
let element = document;
let key = listener_key('document', name, data, callback, !!use_capture);
if (wasmMemoryInterface.listenerMap.has(key)) {
return false;
}
let listener = (e) => {
let event_data = {};
event_data.id_ptr = 0;
event_data.id_len = 0;
event_data.event = e;
event_data.name_code = name_code;
onEventReceived(event_data, data, callback);
};
wasmMemoryInterface.listenerMap.set(key, listener);
element.addEventListener(name, listener, !!use_capture);
return true;
},
remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback, use_capture) => { remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback, use_capture) => {
let id = wasmMemoryInterface.loadString(id_ptr, id_len); let id = wasmMemoryInterface.loadString(id_ptr, id_len);
let name = wasmMemoryInterface.loadString(name_ptr, name_len); let name = wasmMemoryInterface.loadString(name_ptr, name_len);
@@ -1733,6 +1792,20 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
element.removeEventListener(name, listener, !!use_capture); element.removeEventListener(name, listener, !!use_capture);
return true; return true;
}, },
remove_document_event_listener: (name_ptr, name_len, data, callback, use_capture) => {
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
let element = document;
let key = listener_key('document', name, data, callback, !!use_capture);
let listener = wasmMemoryInterface.listenerMap.get(key);
if (listener === undefined) {
return false;
}
wasmMemoryInterface.listenerMap.delete(key);
element.removeEventListener(name, listener, !!use_capture);
return true;
},
event_stop_propagation: () => { event_stop_propagation: () => {
if (event_temp.data && event_temp.data.event) { if (event_temp.data && event_temp.data.event) {
+5 -5
View File
@@ -573,10 +573,10 @@ Button_GetTextMargin :: #force_inline proc "system" (hwnd: HWND, pmargin: ^RECT)
return cast(BOOL)SendMessageW(hwnd, BCM_GETTEXTMARGIN, 0, cast(LPARAM)uintptr(pmargin)) return cast(BOOL)SendMessageW(hwnd, BCM_GETTEXTMARGIN, 0, cast(LPARAM)uintptr(pmargin))
} }
Button_SetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR) -> BOOL { Button_SetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR) -> BOOL {
return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(psz)) return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(rawptr(psz)))
} }
Button_GetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR, pcc: ^c_int) -> BOOL { Button_GetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR, pcc: ^c_int) -> BOOL {
return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(psz)) return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(rawptr(psz)))
} }
Button_GetNoteLength :: #force_inline proc "system" (hwnd: HWND) -> LRESULT { Button_GetNoteLength :: #force_inline proc "system" (hwnd: HWND) -> LRESULT {
return SendMessageW(hwnd, BCM_GETNOTELENGTH, 0, 0) return SendMessageW(hwnd, BCM_GETNOTELENGTH, 0, 0)
@@ -604,10 +604,10 @@ EDITBALLOONTIP :: struct {
PEDITBALLOONTIP :: ^EDITBALLOONTIP PEDITBALLOONTIP :: ^EDITBALLOONTIP
Edit_SetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR) -> BOOL { Edit_SetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR) -> BOOL {
return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(lpcwText)) return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(rawptr(lpcwText)))
} }
Edit_SetCueBannerTextFocused :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR, fDrawFocused: BOOL) -> BOOL { Edit_SetCueBannerTextFocused :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR, fDrawFocused: BOOL) -> BOOL {
return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(lpcwText)) return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(rawptr(lpcwText)))
} }
Edit_GetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpwText: LPWSTR, cchText: LONG) -> BOOL { Edit_GetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpwText: LPWSTR, cchText: LONG) -> BOOL {
return cast(BOOL)SendMessageW(hwnd, EM_GETCUEBANNER, uintptr(lpwText), cast(LPARAM)cchText) return cast(BOOL)SendMessageW(hwnd, EM_GETCUEBANNER, uintptr(lpwText), cast(LPARAM)cchText)
@@ -1197,7 +1197,7 @@ ListView_GetItemPosition :: #force_inline proc "system" (hwnd: HWND, i: c_int, p
return cast(BOOL)SendMessageW(hwnd, LVM_GETITEMPOSITION, cast(WPARAM)i, cast(LPARAM)uintptr(ppt)) return cast(BOOL)SendMessageW(hwnd, LVM_GETITEMPOSITION, cast(WPARAM)i, cast(LPARAM)uintptr(ppt))
} }
ListView_GetStringWidth :: #force_inline proc "system" (hwndLV: HWND, psz: LPCWSTR) -> c_int { ListView_GetStringWidth :: #force_inline proc "system" (hwndLV: HWND, psz: LPCWSTR) -> c_int {
return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(psz)) return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(rawptr(psz)))
} }
ListView_HitTest :: #force_inline proc "system" (hwndLV: HWND, pinfo: ^LV_HITTESTINFO) -> c_int { ListView_HitTest :: #force_inline proc "system" (hwndLV: HWND, pinfo: ^LV_HITTESTINFO) -> c_int {
return cast(c_int)SendMessageW(hwndLV, LVM_HITTEST, 0, cast(LPARAM)uintptr(pinfo)) return cast(c_int)SendMessageW(hwndLV, LVM_HITTEST, 0, cast(LPARAM)uintptr(pinfo))

Some files were not shown because too many files have changed in this diff Show More