Merge tag 'dev-2025-09'

This commit is contained in:
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
steps:
- uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1
with:
branch: edge
- name: (Linux) Download LLVM
- name: (Linux) Download LLVM and Build Odin
run: |
apk add --no-cache \
musl-dev llvm20-dev clang20 git mold lz4 \
libxml2-static llvm20-static zlib-static zstd-static \
make
shell: alpine.sh --root {0}
- name: build odin
# NOTE: this build does slow compile times because of musl
run: ci/build_linux_static.sh
shell: alpine.sh {0}
docker run --rm -v "$PWD:/src" -w /src 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
@@ -74,6 +69,7 @@ jobs:
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
@@ -85,6 +81,46 @@ jobs:
with:
name: linux_artifacts
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:
name: MacOS Build
if: github.repository == 'odin-lang/Odin'
@@ -111,6 +147,7 @@ jobs:
cp -r core $FILE
cp -r vendor $FILE
cp -r examples $FILE
./ci/remove_windows_binaries.sh $FILE
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
tar -czvf dist.tar.gz $FILE
@@ -149,6 +186,7 @@ jobs:
cp -r core $FILE
cp -r vendor $FILE
cp -r examples $FILE
./ci/remove_windows_binaries.sh $FILE
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
tar -czvf dist.tar.gz $FILE
@@ -163,7 +201,7 @@ jobs:
path: dist.tar.gz
upload_b2:
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:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
@@ -192,6 +230,12 @@ jobs:
name: 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
uses: actions/download-artifact@v4.1.7
with:
@@ -219,6 +263,7 @@ jobs:
file linux_artifacts/dist.tar.gz
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-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-arm64 macos_arm_artifacts/dist.tar.gz
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_typeid :: 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_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) ---
// 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_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_register_class :: proc($name: string) -> objc_Class ---
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 ---
+17 -1
View File
@@ -61,6 +61,11 @@ Type_Info_Struct_Soa_Kind :: enum u8 {
Dynamic = 3,
}
Type_Info_String_Encoding_Kind :: enum u8 {
UTF_8 = 0,
UTF_16 = 1,
}
// Variant Types
Type_Info_Named :: struct {
name: string,
@@ -73,7 +78,7 @@ Type_Info_Rune :: struct {}
Type_Info_Float :: struct {endianness: Platform_Endianness}
Type_Info_Complex :: 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_Any :: struct {}
Type_Info_Type_Id :: struct {}
@@ -397,6 +402,11 @@ Raw_String :: struct {
len: int,
}
Raw_String16 :: struct {
data: [^]u16,
len: int,
}
Raw_Slice :: struct {
data: rawptr,
len: int,
@@ -450,6 +460,12 @@ Raw_Cstring :: struct {
}
#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 {
data: rawptr,
index: int,
+32 -1
View File
@@ -5,6 +5,11 @@ import "base:intrinsics"
@builtin
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.
@@ -86,11 +91,26 @@ copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int
}
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`.
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
// of len(src) and len(dst).
@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.
//
// Note: Prefer `delete` over the specific `delete_*` procedures where possible.
@@ -297,6 +326,8 @@ delete :: proc{
delete_map,
delete_soa_slice,
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 {
return nil
}
reserve_soa(array, length, loc) or_return
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
return nil
}
@@ -252,17 +275,77 @@ _reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, zero_memory: boo
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(
array.allocator.data, .Alloc if zero_memory else .Alloc_Non_Zeroed, new_size, max_align,
nil, old_size, loc,
) or_return
new_data := raw_data(new_bytes)
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 _|
for i in 0..<field_count {
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
}
array.allocator.procedure(
array.allocator.data, .Free, 0, max_align,
old_data, old_size, loc,
) or_return
if old_data != nil {
array.allocator.procedure(
array.allocator.data, .Free, 0, max_align,
old_data, old_size, loc,
) or_return
}
return nil
}
+3 -1
View File
@@ -23,7 +23,8 @@ nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, .None
}
nil_allocator :: proc() -> Allocator {
@(require_results)
nil_allocator :: proc "contextless" () -> Allocator {
return Allocator{
procedure = nil_allocator_proc,
data = nil,
@@ -72,6 +73,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, nil
}
@(require_results)
panic_allocator :: proc() -> Allocator {
return Allocator{
procedure = panic_allocator_proc,
@@ -52,10 +52,13 @@ memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint
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 {
allocator := block_to_free.allocator
// sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity)
context = default_context()
context.allocator = allocator
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_destroy :: proc(arena: ^Arena, loc := #caller_location) {
arena_destroy :: proc "contextless" (arena: ^Arena, loc := #caller_location) {
for arena.curr_block != nil {
free_block := arena.curr_block
arena.curr_block = free_block.prev
@@ -186,6 +189,7 @@ arena_destroy :: proc(arena: ^Arena, loc := #caller_location) {
arena.total_capacity = 0
}
@(require_results)
arena_allocator :: proc(arena: ^Arena) -> Allocator {
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_destroy :: proc(s: ^Default_Temp_Allocator) {}
default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {}
default_temp_allocator_proc :: nil_allocator_proc
@@ -28,7 +28,7 @@ when NO_DEFAULT_TEMP_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 {
arena_destroy(&s.arena)
s^ = {}
@@ -61,7 +61,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR {
}
@(fini, private)
_destroy_temp_allocator_fini :: proc() {
_destroy_temp_allocator_fini :: proc "contextless" () {
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 {
return Allocator{
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"
@(require_results)
heap_allocator :: proc() -> Allocator {
return Allocator{
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
for /**/; i < m; i += 8 {
m = (n-i) / size_of(uintptr) * size_of(uintptr)
for /**/; i < m; i += size_of(uintptr) {
if intrinsics.unaligned_load(cast(^uintptr)&a[i]) != intrinsics.unaligned_load(cast(^uintptr)&b[i]) {
return false
}
@@ -389,8 +389,8 @@ memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_
}
}
m = (n-i) / 8 * 8
for /**/; i < m; i += 8 {
m = (n-i) / size_of(uintptr) * size_of(uintptr)
for /**/; i < m; i += size_of(uintptr) {
if intrinsics.unaligned_load(cast(^uintptr)&bytes[i]) != 0 {
return 1
}
@@ -493,12 +493,40 @@ string_cmp :: proc "contextless" (a, b: string) -> int {
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_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_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 }
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 {
p0 := uintptr((^byte)(s))
p := p0
@@ -508,6 +536,16 @@ cstring_len :: proc "contextless" (s: cstring) -> int {
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 {
if s == nil {
return ""
@@ -517,6 +555,15 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
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 {
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_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_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
}
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 {
p, q := abs(real(x)), abs(imag(x))
if p < q {
+7
View File
@@ -293,7 +293,14 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
print_string("quaternion")
print_u64(u64(8*ti.size))
case Type_Info_String:
if info.is_cstring {
print_byte('c')
}
print_string("string")
switch info.encoding {
case .UTF_8: /**/
case .UTF_16: print_string("16")
}
case Type_Info_Boolean:
switch ti.id {
case bool: print_string("bool")
+11 -1
View File
@@ -1,9 +1,12 @@
#+private
package runtime
@(priority_index=-1e6)
@(priority_index=-1e5)
foreign import ObjC "system:objc"
@(priority_index=-1e6)
foreign import libSystem "system:System"
import "base:intrinsics"
objc_id :: ^intrinsics.objc_object
@@ -34,3 +37,10 @@ foreign ObjC {
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, private="file")
init_default_context :: proc() {
init_default_context_for_js = context
init_default_context :: proc "contextless" () {
__init_context(&init_default_context_for_js)
}
@(export)
+1 -1
View File
@@ -97,7 +97,7 @@ default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode,
for &v in p {
if pos == 0 {
val = read_u64(r)
pos = 7
pos = 8
}
v = byte(val)
val >>= 8
+9 -2
View File
@@ -1,10 +1,14 @@
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")
thread_local_cleaners: [8]Thread_Local_Cleaner
// Add a procedure that will be run at the end of a thread for the purpose of
// deallocating state marked as `thread_local`.
//
@@ -29,6 +33,9 @@ run_thread_local_cleaners :: proc "odin" () {
if p == nil {
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
@(require_results)
default_wasm_allocator :: proc() -> Allocator {
return wasm_allocator(&global_default_wasm_allocator_data)
}
@(require_results)
wasm_allocator :: proc(a: ^WASM_Allocator) -> Allocator {
return {
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,
p_sign_posn: c.char,
n_sign_posn: c.char,
_W_decimal_point: [^]u16 `fmt:"s,0"`,
_W_thousands_sep: [^]u16 `fmt:"s,0"`,
_W_int_curr_symbol: [^]u16 `fmt:"s,0"`,
_W_currency_symbol: [^]u16 `fmt:"s,0"`,
_W_mon_decimal_point: [^]u16 `fmt:"s,0"`,
_W_mon_thousands_sep: [^]u16 `fmt:"s,0"`,
_W_positive_sign: [^]u16 `fmt:"s,0"`,
_W_negative_sign: [^]u16 `fmt:"s,0"`,
_W_decimal_point: cstring16,
_W_thousands_sep: cstring16,
_W_int_curr_symbol: cstring16,
_W_currency_symbol: cstring16,
_W_mon_decimal_point: cstring16,
_W_mon_thousands_sep: cstring16,
_W_positive_sign: cstring16,
_W_negative_sign: cstring16,
}
} else {
lconv :: struct {
+12 -12
View File
@@ -22,7 +22,7 @@ DEFAULT_CAPACITY :: 16
/*
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)
q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{
data = nil,
@@ -30,7 +30,7 @@ init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := contex
cap = 0,
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.
*/
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^) {
return _grow(q, uint(capacity))
return _grow(q, uint(capacity), loc)
}
return nil
}
@@ -269,9 +269,9 @@ Example:
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 {
_grow(q) or_return
_grow(q, loc = loc) or_return
}
idx := (q.offset+uint(q.len))%builtin.len(q.data)
q.data[idx] = elem
@@ -303,9 +303,9 @@ Example:
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 {
_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.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
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))
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))
@@ -465,10 +465,10 @@ clear :: proc(q: ^$Q/Queue($T)) {
// 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)
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 {
diff := n - q.offset
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.MaxNameLen = 255
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 {
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) {
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
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)
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
// 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_type[type] = impl
}
// Register a custom tag implementation to be used when marshalling that tag number or marshalling
// 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_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)
@(private, init, disabled=!INITIALIZE_DEFAULT_TAGS)
tags_initialize_defaults :: proc() {
tags_initialize_defaults :: proc "contextless" () {
tags_register_defaults()
}
// 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.
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_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)
@@ -298,7 +300,7 @@ tag_base64_unmarshal :: proc(_: ^Tag_Implementation, d: Decoder, _: Tag_Number,
#partial switch t in ti.variant {
case reflect.Type_Info_String:
assert(t.encoding == .UTF_8)
if t.is_cstring {
length := base64.decoded_len(bytes)
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) {
#partial switch t in ti.variant {
case reflect.Type_Info_String:
assert(t.encoding == .UTF_8)
bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return
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 {
case runtime.Type_Info_String:
switch x in v {
case string:
return x == ""
case cstring:
return x == nil || x == ""
case string: return x == ""
case cstring: return x == nil || x == ""
case string16: return x == ""
case cstring16: return x == nil || x == ""
}
case runtime.Type_Info_Any:
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
#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_cstr: cstring
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:
assert(specific_type_info.encoding == .UTF_8)
if specific_type_info.is_cstring {
cstr_ptr := (^cstring)(ptr)
if cstr_ptr != nil {
+1 -1
View File
@@ -38,6 +38,6 @@ Note that only one can be active at a time.
Inputs:
- 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
}
+2 -2
View File
@@ -29,6 +29,8 @@ Integer:
%x base 16, with lower-case letters for a-f
%X base 16, with upper-case letters for A-F
%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:
%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
%h hexadecimal (lower-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
%s the uninterpreted bytes of the string or slice
%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_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.
//
// 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 {
case byte: fmt_string(fi, string(([^]byte)(data)[:n]), verb); return
case u16: print_utf16(fi, ([^]u16)(data)[:n]); return
case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return
case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return
case u32: print_utf32(fi, ([^]u32)(data)[:n]); return
case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return
case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return
case rune: print_utf32(fi, ([^]rune)(data)[:n]); return
case byte: fmt_string(fi, string (([^]byte)(data)[:n]), verb); return
case u16: fmt_string16(fi, string16(([^]u16) (data)[:n]), verb); return
case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return
case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return
case u32: print_utf32(fi, ([^]u32)(data)[:n]); return
case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return
case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return
case rune: print_utf32(fi, ([^]rune)(data)[:n]); return
}
}
if verb == 'p' {
@@ -3210,6 +3283,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
case string: fmt_string(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 i16le: fmt_int(fi, u64(a), true, 16, verb)
+1 -1
View File
@@ -741,6 +741,6 @@ destroy :: proc(img: ^Image) {
}
@(init, private)
_register :: proc() {
_register :: proc "contextless" () {
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_destroyers: [Which_File_Type]Destroy_Proc
register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
assert(loader != nil)
assert(destroyer != nil)
assert(_internal_loaders[kind] == nil)
register :: proc "contextless" (kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) {
assert_contextless(loader != nil)
assert_contextless(destroyer != nil)
assert_contextless(_internal_loaders[kind] == nil)
_internal_loaders[kind] = loader
assert(_internal_destroyers[kind] == nil)
assert_contextless(_internal_destroyers[kind] == nil)
_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)
_register :: proc() {
_register :: proc "contextless" () {
loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) {
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)
_register :: proc() {
_register :: proc "contextless" () {
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)
_register :: proc() {
_register :: proc "contextless" () {
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
@(init, private)
_register :: proc() {
_register :: proc "contextless" () {
image.register(.TGA, load_from_bytes, destroy)
}
+24
View File
@@ -5,6 +5,7 @@ package io
import "base:intrinsics"
import "core:unicode/utf8"
import "core:unicode/utf16"
// Seek whence values
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)
}
// 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 :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) {
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
}
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
write_quoted_rune :: proc(w: Writer, r: rune) -> (n: 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
@(init, private)
init_standard_stream_status :: proc() {
init_standard_stream_status :: proc "contextless" () {
// NOTE(Feoramund): While it is technically possible for these streams to
// 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
// uncommonly-used feature.
if terminal.color_enabled {
context = runtime.default_context()
// This is done this way because it's possible that only one of these
// streams could be redirected to a file.
if !terminal.is_terminal(os.stdout) {
+10 -8
View File
@@ -7,6 +7,7 @@
package math_big
import "base:intrinsics"
import "base:runtime"
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{}
@(init, private)
_init_constants :: proc() {
_init_constants :: proc "contextless" () {
initialize_constants()
}
initialize_constants :: proc() -> (res: int) {
internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable}
internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
initialize_constants :: proc "contextless" () -> (res: int) {
context = runtime.default_context()
internal_int_set_from_integer( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
internal_int_set_from_integer( INT_ONE, 1); INT_ONE.flags = {.Immutable}
internal_int_set_from_integer(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
/*
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.
*/
internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
internal_set( 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_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
internal_int_set_from_integer( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf}
internal_int_set_from_integer(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
return _DEFAULT_MUL_KARATSUBA_CUTOFF
}
+5 -5
View File
@@ -27,10 +27,10 @@
package math_big
import "core:mem"
import "base:intrinsics"
import rnd "core:math/rand"
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.
@@ -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_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 }
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 {
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.
@@ -84,7 +77,7 @@ Possible Output:
*/
@(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.
@@ -107,7 +100,11 @@ Possible Output:
*/
@(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.
@@ -131,13 +128,13 @@ Possible Output:
*/
@(require_results)
uint128 :: proc(gen := context.random_generator) -> (val: u128) {
a := u128(_random_u64(gen))
b := u128(_random_u64(gen))
a := u128(uint64(gen))
b := u128(uint64(gen))
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.
Returns:
@@ -160,7 +157,7 @@ Possible Output:
@(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.
Returns:
@@ -183,7 +180,7 @@ Possible Output:
@(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.
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.
Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value.
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.
Inputs:
- p: The byte slice to fill
@@ -508,22 +505,12 @@ Possible Output:
*/
@(require_results)
read :: proc(p: []byte, gen := context.random_generator) -> (n: int) {
pos := i8(0)
val := i64(0)
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
if !runtime.random_generator_read_bytes(gen, p) {return 0}
return len(p)
}
/*
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*
@@ -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:
- 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:
- 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
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)
// sanitizer.address_unpoison(data)
return data, nil
@@ -2436,6 +2436,7 @@ compat_allocator_init :: proc(rra: ^Compat_Allocator, allocator := context.alloc
rra.parent = allocator
}
@(require_results)
compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator {
return Allocator{
data = rra,
+1 -1
View File
@@ -9,7 +9,7 @@ _ :: runtime
DEFAULT_PAGE_SIZE := uint(4096)
@(init, private)
platform_memory_init :: proc() {
platform_memory_init :: proc "contextless" () {
_platform_memory_init()
}
+2 -2
View File
@@ -43,10 +43,10 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
return errno == .NONE
}
_platform_memory_init :: proc() {
_platform_memory_init :: proc "contextless" () {
DEFAULT_PAGE_SIZE = 4096
// 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
}
_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) {
+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
}
_platform_memory_init :: proc() {
_platform_memory_init :: proc "contextless" () {
// NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`.
size := posix.sysconf(._PAGESIZE)
DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE))
// 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) {
+3 -3
View File
@@ -72,7 +72,7 @@ foreign Kernel32 {
flProtect: u32,
dwMaximumSizeHigh: u32,
dwMaximumSizeLow: u32,
lpName: [^]u16,
lpName: cstring16,
) -> rawptr ---
MapViewOfFile :: proc(
@@ -146,13 +146,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags)
@(no_sanitize_address)
_platform_memory_init :: proc() {
_platform_memory_init :: proc "contextless" () {
sys_info: SYSTEM_INFO
GetSystemInfo(&sys_info)
DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize))
// 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)
ensure_winsock_initialized :: proc() {
ensure_winsock_initialized :: proc "contextless" () {
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 {
offset := t.offset - 1
for t.ch != '\n' {
for t.ch != '\n' && t.ch != utf8.RUNE_EOF {
if t.ch == '/' {
next := peek_byte(t, 0)
if next == '/' || next == '*' {
break
}
}
}
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)
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 {
err = get_last_error()
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
@(fini, private)
temp_allocator_fini :: proc() {
temp_allocator_fini :: proc "contextless" () {
for &arena in global_default_temp_allocator_arenas {
runtime.arena_destroy(&arena)
}
@@ -69,6 +69,6 @@ _temp_allocator_end :: proc(tmp: runtime.Arena_Temp) {
}
@(init, private)
init_thread_local_cleaner :: proc() {
init_thread_local_cleaner :: proc "contextless" () {
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 })
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)
defer win32.CloseHandle(handle)
@@ -107,15 +107,7 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
return
}
wpath: []u16
{
i := 0
for impl.wname[i] != 0 {
i += 1
}
wpath = impl.wname[:i]
}
wpath := string16(impl.wname)
temp_allocator := TEMP_ALLOCATOR_GUARD({})
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)+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 {
read_directory_iterator_set_error(it, impl.name, _get_platform_error())
return
+1 -1
View File
@@ -31,7 +31,7 @@ _lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value:
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
return
}
+2 -2
View File
@@ -45,8 +45,8 @@ _stderr := File{
}
@init
_standard_stream_init :: proc() {
new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
_standard_stream_init :: proc "contextless" () {
new_std :: proc "contextless" (impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File {
impl.file.impl = impl
impl.fd = linux.Fd(fd)
impl.allocator = runtime.nil_allocator()
+2 -2
View File
@@ -25,8 +25,8 @@ File_Impl :: struct {
}
@(init)
init_std_files :: proc() {
new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
init_std_files :: proc "contextless" () {
new_std :: proc "contextless" (impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File {
impl.file.impl = impl
impl.fd = fd
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, err = read(f, buffer[:])
total += n
append_elems(&out_buffer, ..buffer[:n])
append_elems(&out_buffer, ..buffer[:n]) or_return
if err != nil {
if err == .EOF || err == .Broken_Pipe {
err = nil
+2 -2
View File
@@ -30,8 +30,8 @@ Preopen :: struct {
preopens: []Preopen
@(init)
init_std_files :: proc() {
new_std :: proc(impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File {
init_std_files :: proc "contextless" () {
new_std :: proc "contextless" (impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File {
impl.file.impl = impl
impl.allocator = runtime.nil_allocator()
impl.fd = fd
+58 -22
View File
@@ -43,8 +43,8 @@ File_Impl :: struct {
}
@(init)
init_std_files :: proc() {
new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File {
init_std_files :: proc "contextless" () {
new_std :: proc "contextless" (impl: ^File_Impl, code: u32, name: string) -> ^File {
impl.file.impl = impl
impl.allocator = runtime.nil_allocator()
@@ -77,7 +77,7 @@ init_std_files :: proc() {
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))
}
@@ -234,7 +234,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) {
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 {
return INVALID_HANDLE
}
@@ -247,7 +247,7 @@ _destroy :: proc(f: ^File_Impl) -> Error {
}
a := f.allocator
err0 := free(f.wname, a)
err0 := free(rawptr(f.wname), a)
err1 := delete(f.name, a)
err2 := delete(f.r_buf, a)
err3 := delete(f.w_buf, a)
@@ -619,7 +619,7 @@ _symlink :: proc(old_name, new_name: string) -> Error {
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 |= win32.FILE_FLAG_OPEN_REPARSE_POINT
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)
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 })
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 {
return "", _get_platform_error()
}
@@ -713,7 +713,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er
switch rdb.ReparseTag {
case win32.IO_REPARSE_TAG_SYMLINK:
rb := (^win32.SYMBOLIC_LINK_REPARSE_BUFFER)(&rdb.rest)
pb := win32.wstring(&rb.PathBuffer)
pb := ([^]u16)(&rb.PathBuffer)
pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0
p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength]
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:
rb := (^win32.MOUNT_POINT_REPARSE_BUFFER)(&rdb.rest)
pb := win32.wstring(&rb.PathBuffer)
pb := ([^]u16)(&rb.PathBuffer)
pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0
p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength]
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)
win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: [^]u16, err: runtime.Allocator_Error) {
ws = raw_data(win32_utf8_to_utf16(s, allocator) or_return)
win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: cstring16, err: runtime.Allocator_Error) {
ws = cstring16(raw_data(win32_utf8_to_utf16(s, allocator) or_return))
return
}
@@ -909,24 +909,26 @@ win32_utf8_to_utf16 :: proc(s: string, allocator: runtime.Allocator) -> (ws: []u
}
@(private="package", require_results)
win32_wstring_to_utf8 :: proc(s: [^]u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
if s == nil || s[0] == 0 {
win32_wstring_to_utf8 :: proc(s: cstring16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) {
if s == nil || s == "" {
return "", nil
}
n := 0
for s[n] != 0 {
n += 1
}
return win32_utf16_to_utf8(s[:n], allocator)
return win32_utf16_to_utf8(string16(s), allocator)
}
@(private="package")
win32_utf16_to_utf8 :: proc{
win32_utf16_string16_to_utf8,
win32_utf16_u16_to_utf8,
}
@(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 {
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 {
return
}
@@ -938,7 +940,41 @@ win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: str
// will not be null terminated.
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 {
delete(text, allocator)
return
+5 -5
View File
@@ -91,11 +91,11 @@ _remove_all :: proc(path: string) -> Error {
nil,
win32.FO_DELETE,
dir,
&empty[0],
cstring16(&empty[0]),
win32.FOF_NOCONFIRMATION | win32.FOF_NOERRORUI | win32.FOF_SILENT,
false,
nil,
&empty[0],
cstring16(&empty[0]),
}
res := win32.SHFileOperationW(&file_op)
if res != 0 {
@@ -160,7 +160,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
can_use_long_paths: bool
@(init)
init_long_path_support :: proc() {
init_long_path_support :: proc "contextless" () {
can_use_long_paths = false
key: win32.HKEY
@@ -303,13 +303,13 @@ _get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absol
}
temp_allocator := TEMP_ALLOCATOR_GUARD({ 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 {
return "", Platform_Error(win32.GetLastError())
}
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 {
return "", Platform_Error(win32.GetLastError())
}
+8 -1
View File
@@ -16,7 +16,8 @@ Arguments to the current process.
args := get_args()
@(private="file")
get_args :: proc() -> []string {
get_args :: proc "contextless" () -> []string {
context = runtime.default_context()
result := make([]string, len(runtime.args__), heap_allocator())
for rt_arg, i in runtime.args__ {
result[i] = string(rt_arg)
@@ -24,6 +25,12 @@ get_args :: proc() -> []string {
return result
}
@(fini, private="file")
delete_args :: proc "contextless" () {
context = runtime.default_context()
delete(args, heap_allocator())
}
/*
Exit the current process.
*/
+1 -1
View File
@@ -13,7 +13,7 @@ import "core:time"
foreign import lib "system:System"
foreign lib {
sysctl :: proc(
sysctl :: proc "c" (
name: [^]i32, namelen: u32,
oldp: rawptr, oldlenp: ^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}
}
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}
}
}
@@ -286,7 +286,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields
info.fields += {.Command_Line}
}
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}
}
}
@@ -610,7 +610,7 @@ _process_exe_by_pid :: proc(pid: int, allocator: runtime.Allocator) -> (exe_path
err =_get_platform_error()
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) {
@@ -650,7 +650,7 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc
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
argv_w := win32.CommandLineToArgvW(cmd_line_w, &argc)
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
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
if n == 0 {
return "", _get_platform_error()
}
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 {
return "", _get_platform_error()
}
@@ -140,8 +140,8 @@ _cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (strin
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
buf := make([]u16, max(n, 260)+1, temp_allocator)
n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
return _cleanpath_from_buf(buf[:n], allocator)
n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0)
return _cleanpath_from_buf(string16(buf[:n]), allocator)
}
_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({})
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
}
_cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
buf := buf
_cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
buf := transmute([]u16)buf
buf = _cleanpath_strip_prefix(buf)
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 })
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] == '\\' {
} else if n > 0 && b[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
}
dir, _ = win32.wstring_to_utf8(path_w, -1, allocator)
return
return win32_wstring_to_utf8(cstring16(path_w), allocator)
}
+4 -2
View File
@@ -1226,7 +1226,8 @@ _processor_core_count :: proc() -> int {
}
@(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__))
for _, i in res {
res[i] = string(runtime.args__[i])
@@ -1235,7 +1236,8 @@ _alloc_command_line_arguments :: proc() -> []string {
}
@(private, fini)
_delete_command_line_arguments :: proc() {
_delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args)
}
+4 -2
View File
@@ -965,7 +965,8 @@ _processor_core_count :: proc() -> int {
@(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__))
for _, i in res {
res[i] = string(runtime.args__[i])
@@ -974,6 +975,7 @@ _alloc_command_line_arguments :: proc() -> []string {
}
@(private, fini)
_delete_command_line_arguments :: proc() {
_delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args)
}
+4 -2
View File
@@ -317,7 +317,8 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
args := _alloc_command_line_arguments()
@(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__))
for arg, i in runtime.args__ {
res[i] = string(arg)
@@ -326,7 +327,8 @@ _alloc_command_line_arguments :: proc() -> []string {
}
@(private, fini)
_delete_command_line_arguments :: proc() {
_delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args)
}
+4 -2
View File
@@ -1098,7 +1098,8 @@ _processor_core_count :: proc() -> int {
}
@(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__))
for _, i in res {
res[i] = string(runtime.args__[i])
@@ -1107,7 +1108,8 @@ _alloc_command_line_arguments :: proc() -> []string {
}
@(private, fini)
_delete_command_line_arguments :: proc() {
_delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args)
}
+4 -2
View File
@@ -1015,7 +1015,8 @@ _processor_core_count :: proc() -> int {
}
@(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__))
for _, i in res {
res[i] = string(runtime.args__[i])
@@ -1024,6 +1025,7 @@ _alloc_command_line_arguments :: proc() -> []string {
}
@(private, fini)
_delete_command_line_arguments :: proc() {
_delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args)
}
+4 -2
View File
@@ -915,7 +915,8 @@ _processor_core_count :: proc() -> int {
}
@(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__))
for _, i in res {
res[i] = string(runtime.args__[i])
@@ -924,6 +925,7 @@ _alloc_command_line_arguments :: proc() -> []string {
}
@(private, fini)
_delete_command_line_arguments :: proc() {
_delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args)
}
+11 -8
View File
@@ -28,16 +28,18 @@ stderr: Handle = 2
args := _alloc_command_line_arguments()
@(private, require_results)
_alloc_command_line_arguments :: proc() -> (args: []string) {
args = make([]string, len(runtime.args__))
for &arg, i in args {
_alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
cmd_args := make([]string, len(runtime.args__))
for &arg, i in cmd_args {
arg = string(runtime.args__[i])
}
return
return cmd_args
}
@(private, fini)
_delete_command_line_arguments :: proc() {
_delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
delete(args)
}
@@ -57,9 +59,8 @@ Preopen :: struct {
preopens: []Preopen
@(init, private)
init_preopens :: proc() {
strip_prefixes :: proc(path: string) -> string {
init_preopens :: proc "contextless" () {
strip_prefixes :: proc "contextless"(path: string) -> string {
path := path
loop: for len(path) > 0 {
switch {
@@ -76,6 +77,8 @@ init_preopens :: proc() {
return path
}
context = runtime.default_context()
dyn_preopens: [dynamic]Preopen
loop: for fd := wasi.fd_t(3); ; fd += 1 {
desc, err := wasi.fd_prestat_get(fd)
+4 -2
View File
@@ -194,7 +194,8 @@ current_thread_id :: proc "contextless" () -> int {
@(private, require_results)
_alloc_command_line_arguments :: proc() -> []string {
_alloc_command_line_arguments :: proc "contextless" () -> []string {
context = runtime.default_context()
arg_count: i32
arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count)
arg_list := make([]string, int(arg_count))
@@ -216,7 +217,8 @@ _alloc_command_line_arguments :: proc() -> []string {
}
@(private, fini)
_delete_command_line_arguments :: proc() {
_delete_command_line_arguments :: proc "contextless" () {
context = runtime.default_context()
for s in args {
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)
defer delete(buf)
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 {
return "", get_last_error()
}
@@ -154,7 +154,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> (
return nil, get_last_error()
}
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
}
@(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)
n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil)
if n == 0 {
return "", os.get_last_error()
}
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 {
delete(buf)
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
case Type_Info_String:
if info.is_cstring {
io.write_string(w, "cstring", &n) or_return
} else {
io.write_string(w, "string", &n) or_return
io.write_byte(w, 'c', &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:
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")
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")
Layer_contentsScale :: proc "c" (self: ^Layer) -> Float {
return msgSend(Float, self, "contentsScale")
@@ -654,8 +663,12 @@ Window_frame :: proc "c" (self: ^Window) -> Rect {
return msgSend(Rect, self, "frame")
}
@(objc_type=Window, objc_name="setFrame")
Window_setFrame :: proc "c" (self: ^Window, frame: Rect) {
msgSend(nil, self, "setFrame:", frame)
Window_setFrame :: proc "c" (self: ^Window, frame: Rect, display: BOOL) {
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")
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) {
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")
Window_setStyleMask :: proc "c" (self: ^Window, style_mask: WindowStyleMask) {
msgSend(nil, self, "setStyleMask:", style_mask)
+2 -2
View File
@@ -52,7 +52,7 @@ CPU :: struct {
cpu: CPU
@(init, private)
init_cpu_features :: proc "c" () {
init_cpu_features :: proc "contextless" () {
is_set :: #force_inline proc "c" (bit: u32, value: u32) -> bool {
return (value>>bit) & 0x1 != 0
}
@@ -156,7 +156,7 @@ init_cpu_features :: proc "c" () {
_cpu_name_buf: [72]u8
@(init, private)
init_cpu_name :: proc "c" () {
init_cpu_name :: proc "contextless" () {
number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0)
if number_of_extended_ids < 0x8000_0004 {
return
+3 -1
View File
@@ -2,11 +2,13 @@
#+build linux
package sysinfo
import "base:runtime"
import "core:sys/linux"
import "core:strings"
@(init, private)
init_cpu_features :: proc() {
init_cpu_features :: proc "contextless" () {
context = runtime.default_context()
fd, err := linux.open("/proc/cpuinfo", {})
if err != .NONE { return }
defer linux.close(fd)
+4 -1
View File
@@ -2,12 +2,15 @@
#+build linux
package sysinfo
import "base:runtime"
import "core:sys/linux"
import "core:strings"
import "core:strconv"
@(init, private)
init_cpu_core_count :: proc() {
init_cpu_core_count :: proc "contextless" () {
context = runtime.default_context()
fd, err := linux.open("/proc/cpuinfo", {})
if err != .NONE { return }
defer linux.close(fd)
+5 -5
View File
@@ -7,7 +7,7 @@ import "base:intrinsics"
import "core:sys/linux"
@(init, private)
init_cpu_features :: proc() {
init_cpu_features :: proc "contextless" () {
_features: CPU_Features
defer cpu.features = _features
@@ -81,11 +81,11 @@ init_cpu_features :: proc() {
}
err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {})
if err != nil {
assert(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
assert_contextless(err == .ENOSYS, "unexpected error from riscv_hwprobe()")
return
}
assert(pairs[0].key == .IMA_EXT_0)
assert_contextless(pairs[0].key == .IMA_EXT_0)
exts := pairs[0].value.ima_ext_0
exts -= { .FD, .C, .V }
_features += transmute(CPU_Features)exts
@@ -97,7 +97,7 @@ init_cpu_features :: proc() {
_features += { .Misaligned_Supported }
}
} else {
assert(pairs[1].key == .CPUPERF_0)
assert_contextless(pairs[1].key == .CPUPERF_0)
if .FAST in pairs[1].value.cpu_perf_0 {
_features += { .Misaligned_Supported, .Misaligned_Fast }
} else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 {
@@ -108,6 +108,6 @@ init_cpu_features :: proc() {
}
@(init, private)
init_cpu_name :: proc() {
init_cpu_name :: proc "contextless" () {
cpu.name = "RISCV64"
}
+4 -1
View File
@@ -2,9 +2,12 @@ package sysinfo
import sys "core:sys/windows"
import "base:intrinsics"
import "base:runtime"
@(init, private)
init_cpu_core_count :: proc() {
init_cpu_core_count :: proc "contextless" () {
context = runtime.default_context()
infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION
defer delete(infos)
+4 -2
View File
@@ -10,7 +10,9 @@ import "base:runtime"
version_string_buf: [1024]u8
@(init, private)
init_os_version :: proc () {
init_os_version :: proc "contextless" () {
context = runtime.default_context()
when ODIN_OS == .NetBSD {
os_version.platform = .NetBSD
} else {
@@ -66,7 +68,7 @@ init_os_version :: proc () {
}
@(init, private)
init_ram :: proc() {
init_ram :: proc "contextless" () {
// Retrieve RAM info using `sysctl`
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64}
mem_size: u64
+4 -1
View File
@@ -1,5 +1,7 @@
package sysinfo
import "base:runtime"
import "core:strconv"
import "core:strings"
import "core:sys/unix"
@@ -9,7 +11,8 @@ import NS "core:sys/darwin/Foundation"
version_string_buf: [1024]u8
@(init, private)
init_platform :: proc() {
init_platform :: proc "contextless" () {
context = runtime.default_context()
ws :: strings.write_string
wi :: strings.write_int
+4 -2
View File
@@ -9,7 +9,9 @@ import "base:runtime"
version_string_buf: [1024]u8
@(init, private)
init_os_version :: proc () {
init_os_version :: proc "contextless" () {
context = runtime.default_context()
os_version.platform = .FreeBSD
kernel_version_buf: [1024]u8
@@ -68,7 +70,7 @@ init_os_version :: proc () {
}
@(init, private)
init_ram :: proc() {
init_ram :: proc "contextless" () {
// Retrieve RAM info using `sysctl`
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM}
mem_size: u64
+6 -3
View File
@@ -1,6 +1,7 @@
package sysinfo
import "base:intrinsics"
import "base:runtime"
import "core:strconv"
import "core:strings"
@@ -10,7 +11,9 @@ import "core:sys/linux"
version_string_buf: [1024]u8
@(init, private)
init_os_version :: proc () {
init_os_version :: proc "contextless" () {
context = runtime.default_context()
os_version.platform = .Linux
b := strings.builder_from_bytes(version_string_buf[:])
@@ -91,11 +94,11 @@ init_os_version :: proc () {
}
@(init, private)
init_ram :: proc() {
init_ram :: proc "contextless" () {
// Retrieve RAM info using `sysinfo`
sys_info: linux.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{
total_ram = int(sys_info.totalram) * 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
@(init, private)
init_os_version :: proc () {
init_os_version :: proc "contextless" () {
context = runtime.default_context()
/*
NOTE(Jeroen):
`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.build[0] = int(osvi.dwBuildNumber)
b := strings.builder_from_bytes(version_string_buf[:])
strings.write_string(&b, "Windows ")
@@ -259,7 +262,7 @@ init_os_version :: proc () {
}
@(init, private)
init_ram :: proc() {
init_ram :: proc "contextless" () {
state: sys.MEMORYSTATUSEX
state.dwLength = size_of(state)
@@ -276,10 +279,11 @@ init_ram :: proc() {
}
@(init, private)
init_gpu_info :: proc() {
init_gpu_info :: proc "contextless" () {
GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\"
context = runtime.default_context()
gpu_list: [dynamic]GPU
gpu_index: int
@@ -324,8 +328,8 @@ read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
cstring16(&key_name_wide[0]),
cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_SZ,
nil,
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))
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
cstring16(&key_name_wide[0]),
cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_DWORD,
nil,
&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))
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
cstring16(&key_name_wide[0]),
cstring16(&val_name_wide[0]),
sys.RRF_RT_REG_QWORD,
nil,
&res,
+1 -1
View File
@@ -1838,7 +1838,7 @@ Clock_Id :: enum {
Bits for POSIX interval timer flags.
*/
ITimer_Flags_Bits :: enum {
ABSTIME = 1,
ABSTIME = 0,
}
/*
+1
View File
@@ -1,3 +1,4 @@
#+build linux, darwin, openbsd, freebsd, netbsd, haiku
package posix
when ODIN_OS == .Darwin {
+1 -1
View File
@@ -60,7 +60,7 @@ wctomb :: libc.wctomb
mbstowcs :: libc.mbstowcs
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))
}
+1 -1
View File
@@ -3,7 +3,7 @@ package unix
import "base:intrinsics"
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
mib := mib
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 ---
}
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
mib := mib
result_size := c.size_t(size_of(T))
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 ---
}
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) {
mib := mib
result_size := c.size_t(size_of(T))
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)
}
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 {
from_use_capture_false: bool
from_use_capture_true: bool
if e.id == "" {
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_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 {
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)
+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")
}
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 {
panic("vendor:wasm/js not supported on non JS targets")
}
+73
View File
@@ -392,6 +392,9 @@ class WebGLInterface {
BindTexture: (target, texture) => {
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) => {
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); },
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) => {
let array = this.mem.loadF32Array(addr, 2*2);
this.ctx.uniformMatrix2fv(this.uniforms[location], false, array);
@@ -1701,6 +1738,28 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
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) => {
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
let name = wasmMemoryInterface.loadString(name_ptr, name_len);
@@ -1733,6 +1792,20 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) {
element.removeEventListener(name, listener, !!use_capture);
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: () => {
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))
}
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 {
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 {
return SendMessageW(hwnd, BCM_GETNOTELENGTH, 0, 0)
@@ -604,10 +604,10 @@ EDITBALLOONTIP :: struct {
PEDITBALLOONTIP :: ^EDITBALLOONTIP
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 {
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 {
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))
}
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 {
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