mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-06 11:41:37 -07:00
Compare commits
186 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a04d849e30 | |||
| 8c9505505a | |||
| eac74631ec | |||
| 85706d559d | |||
| 67ba05cb7c | |||
| 2f1aeaf757 | |||
| 14a17fb36f | |||
| 1a9ec776cb | |||
| da1edac56d | |||
| 44ec95a983 | |||
| 1502066303 | |||
| 35a826a0fd | |||
| ebb8ca7c26 | |||
| 763de44853 | |||
| 62cc752066 | |||
| 965b962b29 | |||
| 2f3c5336d9 | |||
| 3824937295 | |||
| fc8ddcef5c | |||
| 3165b7cf95 | |||
| 5eea23cf76 | |||
| 2aa783179e | |||
| 24e7356825 | |||
| 2fcba25e50 | |||
| 28bc274449 | |||
| 16786aac78 | |||
| 32b37f3429 | |||
| 5808793cae | |||
| 7e11f3cc4b | |||
| 714ab516c5 | |||
| 498f68c06b | |||
| 070b450768 | |||
| 74174eb4ae | |||
| b190404b21 | |||
| 081a5a52a6 | |||
| fb86c23dbd | |||
| cb6a4ebf60 | |||
| 1bf8328606 | |||
| 6a7f39453b | |||
| 515fd2a228 | |||
| dd3322ac1f | |||
| f16f1d932e | |||
| a3e7b2baa1 | |||
| fadf9b5309 | |||
| f6a087775e | |||
| d5f7e181a0 | |||
| 65f8722afc | |||
| c0479f1564 | |||
| fe0b5bf4e2 | |||
| f20105ddfe | |||
| 42ab882db4 | |||
| dcc9e61362 | |||
| 2554c72bb2 | |||
| 49872e40dc | |||
| 849fe01e70 | |||
| d269dbcd40 | |||
| 18e639f59b | |||
| 6ad262c2df | |||
| 10b97a1b39 | |||
| 56b4e0a3c3 | |||
| 27dbe84f79 | |||
| 0711d4e5fe | |||
| 1e46537959 | |||
| a5e1693774 | |||
| 63771bc6e8 | |||
| 8516e2e7e3 | |||
| b3c3e41706 | |||
| 59f3a009fa | |||
| 9bc5b84c4d | |||
| f9265c14bf | |||
| 9c1e1a63a2 | |||
| 4dc5839e3d | |||
| fdcb9deaff | |||
| fe6539fad9 | |||
| 0e06383620 | |||
| cfbc1a447b | |||
| 1b23dd2257 | |||
| b612edba5a | |||
| d39c05b183 | |||
| 3a3cb521ab | |||
| 5b97ff0b48 | |||
| 2b918ada4b | |||
| b5754b6ed9 | |||
| 07ee23f817 | |||
| ecdaac9921 | |||
| 5ff82fc113 | |||
| 28a816ef25 | |||
| 6bdb210ad8 | |||
| db08847f9a | |||
| 841c428273 | |||
| 6b830f42b6 | |||
| fb01dfe048 | |||
| c7a9c8274f | |||
| cafb6e5587 | |||
| e9ae6e20e8 | |||
| 2ca2dbcc92 | |||
| 0d4642825f | |||
| 8eda756714 | |||
| c85ac955f7 | |||
| 97922406fe | |||
| 76ccce2942 | |||
| 686dbb4421 | |||
| cd6898439e | |||
| 95620aaf2a | |||
| 1d293749c2 | |||
| 2d35a5c1af | |||
| d4ea02a877 | |||
| 2a325b3da0 | |||
| f0529535e0 | |||
| 3f59c45740 | |||
| 29ebe0c3c9 | |||
| 6c48670819 | |||
| 51dcbc80c3 | |||
| 9ecbadd457 | |||
| 79f32d7b71 | |||
| 7501cc2f17 | |||
| a390ef41f8 | |||
| bb9c2f7aad | |||
| 6aa80ee8e4 | |||
| 0741bc37cc | |||
| c6ed3fa4b5 | |||
| e277102947 | |||
| 6cf5371d7d | |||
| e15f714660 | |||
| 4f77151ebc | |||
| 9a46463078 | |||
| a0816bb581 | |||
| b33ca6651e | |||
| 315a08f33f | |||
| 50668fa7a6 | |||
| ee260986a9 | |||
| c9bc759624 | |||
| 80f175cdb0 | |||
| 8f03811842 | |||
| 3def94505e | |||
| e30f16b1f3 | |||
| 7df93ea504 | |||
| 6209b02bf9 | |||
| 75b7f2b9fe | |||
| f1521aa980 | |||
| fb0a3ab7c1 | |||
| 8eaafd5242 | |||
| 774951e8c0 | |||
| 5ec93677a0 | |||
| 7e4067c44c | |||
| f2f6c3c67d | |||
| 847b05013f | |||
| d308473075 | |||
| 4334dbe69a | |||
| 8f91e9307c | |||
| 32ec1162bf | |||
| 7cc265e14c | |||
| 6f3e450c50 | |||
| cb1080d56c | |||
| 80bd1eb615 | |||
| fb53402914 | |||
| 731853ce78 | |||
| f0260e9771 | |||
| af612bc7e9 | |||
| d76dd95c0b | |||
| 1cff72ad62 | |||
| 773cfac449 | |||
| b02f2953ac | |||
| 566a750899 | |||
| 1d1d684cbc | |||
| 7a14acaa01 | |||
| 057174497a | |||
| 8c9597b24b | |||
| 72862ce30d | |||
| d0f4cb1de4 | |||
| 17613185e7 | |||
| 00ff1fbca2 | |||
| f15bb0b424 | |||
| f818d0feb1 | |||
| 8ff6f95571 | |||
| 68e5f57e27 | |||
| 38e5e13b3f | |||
| defc1672c3 | |||
| 12f459b5fb | |||
| e6b8f7e77a | |||
| 236b08cb49 | |||
| e4f28de3de | |||
| 750ee4ecdb | |||
| 92e70b9a58 | |||
| 822da9d12d | |||
| 5d80e24224 |
@@ -17,13 +17,16 @@ jobs:
|
||||
run: ./odin report
|
||||
timeout-minutes: 1
|
||||
- name: Odin check
|
||||
run: ./odin check examples/demo/demo.odin -vet
|
||||
run: ./odin check examples/demo -vet
|
||||
timeout-minutes: 10
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo/demo.odin
|
||||
run: ./odin run examples/demo
|
||||
timeout-minutes: 10
|
||||
- name: Odin run -debug
|
||||
run: ./odin run examples/demo/demo.odin -debug
|
||||
run: ./odin run examples/demo -debug
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all
|
||||
run: ./odin check examples/all -strict-style
|
||||
timeout-minutes: 10
|
||||
- name: Core library tests
|
||||
run: |
|
||||
@@ -54,13 +57,16 @@ jobs:
|
||||
run: ./odin report
|
||||
timeout-minutes: 1
|
||||
- name: Odin check
|
||||
run: ./odin check examples/demo/demo.odin -vet
|
||||
run: ./odin check examples/demo -vet
|
||||
timeout-minutes: 10
|
||||
- name: Odin run
|
||||
run: ./odin run examples/demo/demo.odin
|
||||
run: ./odin run examples/demo
|
||||
timeout-minutes: 10
|
||||
- name: Odin run -debug
|
||||
run: ./odin run examples/demo/demo.odin -debug
|
||||
run: ./odin run examples/demo -debug
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all
|
||||
run: ./odin check examples/all -strict-style
|
||||
timeout-minutes: 10
|
||||
- name: Core library tests
|
||||
run: |
|
||||
@@ -91,19 +97,25 @@ jobs:
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/demo/demo.odin -vet
|
||||
odin check examples/demo -vet
|
||||
timeout-minutes: 10
|
||||
- name: Odin run
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo/demo.odin
|
||||
odin run examples/demo
|
||||
timeout-minutes: 10
|
||||
- name: Odin run -debug
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin run examples/demo/demo.odin -debug
|
||||
odin run examples/demo -debug
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all
|
||||
shell: cmd
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
odin check examples/all -strict-style
|
||||
timeout-minutes: 10
|
||||
- name: Core library tests
|
||||
shell: cmd
|
||||
|
||||
@@ -8,22 +8,34 @@ CC=clang
|
||||
OS=$(shell uname)
|
||||
|
||||
ifeq ($(OS), Darwin)
|
||||
|
||||
ARCH=$(shell uname -m)
|
||||
LLVM_CONFIG=llvm-config
|
||||
LLVM_CONFIG=
|
||||
|
||||
# LLVM Version Setting
|
||||
LLVM_VERSION_PATTERN="^11\."
|
||||
LLVM_VERSION="11"
|
||||
# allow for arm only llvm's with version 13
|
||||
ifeq ($(ARCH), arm64)
|
||||
LLVM_VERSION="13"
|
||||
LLVM_VERSION_PATTERN="^13"
|
||||
endif
|
||||
LLVM_VERSIONS = "13.%.%"
|
||||
else
|
||||
# allow for x86 / amd64 all llvm versions begining from 11
|
||||
LLVM_VERSIONS = "13.%.%" "12.0.1" "11.1.0"
|
||||
endif
|
||||
|
||||
ifneq ($(shell llvm-config --version | grep $(LLVM_VERSION_PATTERN)),)
|
||||
LLVM_VERSION_PATTERN_SEPERATOR = )|(
|
||||
LLVM_VERSION_PATTERNS_ESCAPED_DOT = $(subst .,\.,$(LLVM_VERSIONS))
|
||||
LLVM_VERSION_PATTERNS_REPLACE_PERCENT = $(subst %,.*,$(LLVM_VERSION_PATTERNS_ESCAPED_DOT))
|
||||
LLVM_VERSION_PATTERN_REMOVE_ELEMENTS = $(subst " ",$(LLVM_VERSION_PATTERN_SEPERATOR),$(LLVM_VERSION_PATTERNS_REPLACE_PERCENT))
|
||||
LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR = $(subst ",,$(LLVM_VERSION_PATTERN_REMOVE_ELEMENTS))
|
||||
LLVM_VERSION_PATTERN = "^(($(LLMV_VERSION_PATTERN_REMOVE_SINGLE_STR)))"
|
||||
|
||||
ifneq ($(shell llvm-config --version | grep -E $(LLVM_VERSION_PATTERN)),)
|
||||
LLVM_CONFIG=llvm-config
|
||||
else
|
||||
$(error "Requirement: llvm-config must be version $(LLVM_VERSION)")
|
||||
endif
|
||||
ifeq ($(ARCH), arm64)
|
||||
$(error "Requirement: llvm-config must be base version 13 for arm64")
|
||||
else
|
||||
$(error "Requirement: llvm-config must be base version greater than 11 for amd64/x86")
|
||||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS:=$(LDFLAGS) -liconv
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
|
||||
@@ -84,7 +84,7 @@ The official Odin Language specification.
|
||||
|
||||
### Articles
|
||||
|
||||
#### [The Odin Blog](https://odin-lang.org/blog)
|
||||
#### [The Odin Blog](https://odin-lang.org/news/)
|
||||
|
||||
The official blog of the Odin programming language, featuring announcements, news, and in-depth articles by the Odin team and guests.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
package builtin
|
||||
|
||||
nil :: nil;
|
||||
false :: 0!==0;
|
||||
false :: 0!=0;
|
||||
true :: 0==0;
|
||||
|
||||
ODIN_OS :: ODIN_OS;
|
||||
|
||||
+3
-1
@@ -3,6 +3,8 @@ package c
|
||||
import builtin "core:builtin"
|
||||
|
||||
char :: builtin.u8 // assuming -funsigned-char
|
||||
|
||||
schar :: builtin.i8
|
||||
short :: builtin.i16
|
||||
int :: builtin.i32
|
||||
long :: builtin.i32 when (ODIN_OS == "windows" || size_of(builtin.rawptr) == 4) else builtin.i64
|
||||
@@ -46,7 +48,7 @@ int_least64_t :: builtin.i64
|
||||
uint_least64_t :: builtin.u64
|
||||
|
||||
// Same on Windows, Linux, and FreeBSD
|
||||
when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
||||
int_fast8_t :: builtin.i8
|
||||
uint_fast8_t :: builtin.u8
|
||||
int_fast16_t :: builtin.i32
|
||||
|
||||
@@ -956,7 +956,7 @@ substitute_token :: proc(cpp: ^Preprocessor, tok: ^Token, args: ^Macro_Arg) -> ^
|
||||
continue
|
||||
}
|
||||
|
||||
if tok.lit == "__VA__OPT__" && tok.next.lit == "(" {
|
||||
if tok.lit == "__VA_OPT__" && tok.next.lit == "(" {
|
||||
opt_arg := read_macro_arg_one(cpp, &tok, tok.next.next, true)
|
||||
if has_varargs(args) {
|
||||
for t := opt_arg.tok; t.kind != .EOF; t = t.next {
|
||||
|
||||
@@ -149,7 +149,7 @@ foreign libc {
|
||||
putchar :: proc() -> int ---
|
||||
puts :: proc(s: cstring) -> int ---
|
||||
ungetc :: proc(c: int, stream: ^FILE) -> int ---
|
||||
fread :: proc(ptr: rawptr, size: size_t, stream: ^FILE) -> size_t ---
|
||||
fread :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||
fwrite :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
|
||||
|
||||
// 7.21.9 File positioning functions
|
||||
|
||||
@@ -3,6 +3,8 @@ package libc
|
||||
import "core:c"
|
||||
|
||||
char :: c.char // assuming -funsigned-char
|
||||
|
||||
schar :: c.schar
|
||||
short :: c.short
|
||||
int :: c.int
|
||||
long :: c.long
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation, optimization.
|
||||
*/
|
||||
|
||||
|
||||
// package compress is a collection of utilities to aid with other compression packages
|
||||
package compress
|
||||
|
||||
import "core:io"
|
||||
|
||||
@@ -111,9 +111,9 @@ ZFAST_MASK :: ((1 << ZFAST_BITS) - 1)
|
||||
*/
|
||||
Huffman_Table :: struct {
|
||||
fast: [1 << ZFAST_BITS]u16,
|
||||
firstcode: [16]u16,
|
||||
firstcode: [17]u16,
|
||||
maxcode: [17]int,
|
||||
firstsymbol: [16]u16,
|
||||
firstsymbol: [17]u16,
|
||||
size: [288]u8,
|
||||
value: [288]u16,
|
||||
}
|
||||
@@ -244,7 +244,7 @@ allocate_huffman_table :: proc(allocator := context.allocator) -> (z: ^Huffman_T
|
||||
@(optimization_mode="speed")
|
||||
build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||
sizes: [HUFFMAN_MAX_BITS+1]int
|
||||
next_code: [HUFFMAN_MAX_BITS]int
|
||||
next_code: [HUFFMAN_MAX_BITS+1]int
|
||||
|
||||
k := int(0)
|
||||
|
||||
@@ -256,14 +256,14 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
|
||||
}
|
||||
sizes[0] = 0
|
||||
|
||||
for i in 1..<(HUFFMAN_MAX_BITS+1) {
|
||||
for i in 1 ..< HUFFMAN_MAX_BITS {
|
||||
if sizes[i] > (1 << uint(i)) {
|
||||
return E_Deflate.Huffman_Bad_Sizes
|
||||
}
|
||||
}
|
||||
code := int(0)
|
||||
|
||||
for i in 1..<HUFFMAN_MAX_BITS {
|
||||
for i in 1 ..= HUFFMAN_MAX_BITS {
|
||||
next_code[i] = code
|
||||
z.firstcode[i] = u16(code)
|
||||
z.firstsymbol[i] = u16(k)
|
||||
@@ -538,19 +538,20 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
final = compress.read_bits_lsb(z, 1)
|
||||
type = compress.read_bits_lsb(z, 2)
|
||||
|
||||
// fmt.printf("Final: %v | Type: %v\n", final, type);
|
||||
// fmt.printf("Final: %v | Type: %v\n", final, type)
|
||||
|
||||
switch type {
|
||||
case 0:
|
||||
// fmt.printf("Method 0: STORED\n")
|
||||
// Uncompressed block
|
||||
|
||||
// Discard bits until next byte boundary
|
||||
compress.discard_to_next_byte_lsb(z)
|
||||
|
||||
uncompressed_len := i16(compress.read_bits_lsb(z, 16))
|
||||
length_check := i16(compress.read_bits_lsb(z, 16))
|
||||
uncompressed_len := u16(compress.read_bits_lsb(z, 16))
|
||||
length_check := u16(compress.read_bits_lsb(z, 16))
|
||||
|
||||
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
|
||||
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check)
|
||||
|
||||
|
||||
if ~uncompressed_len != length_check {
|
||||
@@ -567,10 +568,12 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
|
||||
write_byte(z, u8(lit))
|
||||
uncompressed_len -= 1
|
||||
}
|
||||
assert(uncompressed_len == 0)
|
||||
|
||||
case 3:
|
||||
return E_Deflate.BType_3
|
||||
case:
|
||||
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
|
||||
// fmt.printf("Err: %v | Final: %v | Type: %v\n", err, final, type)
|
||||
if type == 1 {
|
||||
// Use fixed code lengths.
|
||||
build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return
|
||||
|
||||
@@ -88,7 +88,7 @@ create :: proc(max_index: int, min_index := 0, allocator := context.allocator) -
|
||||
res = Bit_Array{
|
||||
bias = min_index,
|
||||
}
|
||||
return res, resize_if_needed(&res, size_in_bits)
|
||||
return res, resize_if_needed(&res, legs)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
package container_lru
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:mem"
|
||||
_ :: intrinsics
|
||||
_ :: mem
|
||||
|
||||
Node :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||
prev, next: ^Node(Key, Value),
|
||||
key: Key,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
// Cache is an LRU cache. It automatically removes entries as new entries are
|
||||
// added if the capacity is reached. Entries are removed based on how recently
|
||||
// they were used where the oldest entries are removed first.
|
||||
Cache :: struct($Key, $Value: typeid) where intrinsics.type_is_valid_map_key(Key) {
|
||||
head: ^Node(Key, Value),
|
||||
tail: ^Node(Key, Value),
|
||||
|
||||
entries: map[Key]^Node(Key, Value),
|
||||
|
||||
count: int,
|
||||
capacity: int,
|
||||
|
||||
node_allocator: mem.Allocator,
|
||||
|
||||
on_remove: proc(key: Key, value: Value, user_data: rawptr),
|
||||
on_remove_user_data: rawptr,
|
||||
call_on_remove_on_destroy: bool,
|
||||
}
|
||||
|
||||
// init initializes a Cache
|
||||
init :: proc(c: ^$C/Cache($Key, $Value), capacity: int, entries_allocator := context.allocator, node_allocator := context.allocator) {
|
||||
c.entries.allocator = entries_allocator
|
||||
c.node_allocator = node_allocator
|
||||
c.capacity = capacity
|
||||
}
|
||||
|
||||
// destroy deinitializes a Cache
|
||||
destroy :: proc(c: ^$C/Cache($Key, $Value)) {
|
||||
for _, node in c.entries {
|
||||
if c.call_on_remove_on_destroy && c.on_remove != nil {
|
||||
c.on_remove(node.key, node.value, c.on_remove_user_data)
|
||||
}
|
||||
free(node, c.node_allocator)
|
||||
}
|
||||
clear(&c.entries)
|
||||
delete(c.entries)
|
||||
c.head = nil
|
||||
c.tail = nil
|
||||
c.count = 0
|
||||
}
|
||||
|
||||
// set the given key value pair. This operation updates the recent usage of the item.
|
||||
set :: proc(c: ^$C/Cache($Key, $Value), key: Key, value: Value) -> mem.Allocator_Error {
|
||||
if e, ok := c.entries[key]; ok {
|
||||
e.value = value
|
||||
return nil
|
||||
}
|
||||
|
||||
e := new(Node(Key, Value), c.node_allocator) or_return
|
||||
e.key = key
|
||||
e.value = value
|
||||
|
||||
_push_front_node(c, e)
|
||||
if c.count > c.capacity {
|
||||
_remove_node(c, c.tail)
|
||||
}
|
||||
|
||||
c.entries[key] = e
|
||||
return nil
|
||||
}
|
||||
|
||||
// get a value from the cache from a given key. This operation updates the usage of the item.
|
||||
get :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
|
||||
e: ^Node(Key, Value)
|
||||
e, ok = c.entries[key]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
_pop_node(c, e)
|
||||
_push_front_node(c, e)
|
||||
return e.value, true
|
||||
}
|
||||
|
||||
// get_ptr gets the pointer to a value the cache from a given key. This operation updates the usage of the item.
|
||||
get_ptr :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: ^Value, ok: bool) #optional_ok {
|
||||
e: ^Node(Key, Value)
|
||||
e, ok = c.entries[key]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
_pop_node(c, e)
|
||||
_push_front_node(c, e)
|
||||
return &e.value, true
|
||||
}
|
||||
|
||||
// peek gets the value from the cache from a given key without updating the recent usage.
|
||||
peek :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> (value: Value, ok: bool) #optional_ok {
|
||||
e: ^Node(Key, Value)
|
||||
e, ok = c.entries[key]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
return e.value, true
|
||||
}
|
||||
|
||||
// exists checks for the existence of a value from a given key without updating the recent usage.
|
||||
exists :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
|
||||
return key in c.entries
|
||||
}
|
||||
|
||||
// remove removes an item from the cache.
|
||||
remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool {
|
||||
e, ok := c.entries[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_remove_node(c, e)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
_remove_node :: proc(c: ^$C/Cache($Key, $Value), node: ^Node(Key, Value)) {
|
||||
if c.head == node {
|
||||
c.head = node.next
|
||||
}
|
||||
if c.tail == node {
|
||||
c.tail = node.prev
|
||||
}
|
||||
if node.prev != nil {
|
||||
node.prev.next = node.next
|
||||
}
|
||||
if node.next != nil {
|
||||
node.next.prev = node.prev
|
||||
}
|
||||
node.prev = nil
|
||||
node.next = nil
|
||||
|
||||
c.count -= 1
|
||||
|
||||
delete_key(&c.entries, node.key)
|
||||
|
||||
if c.on_remove != nil {
|
||||
c.on_remove(node.key, node.value, c.on_remove_user_data)
|
||||
}
|
||||
|
||||
free(node, c.node_allocator)
|
||||
|
||||
}
|
||||
|
||||
@(private)
|
||||
_push_front_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
|
||||
if c.head != nil {
|
||||
e.next = c.head
|
||||
e.next.prev = e
|
||||
}
|
||||
c.head = e
|
||||
if c.tail == nil {
|
||||
c.tail = e
|
||||
}
|
||||
e.prev = nil
|
||||
|
||||
c.count += 1
|
||||
}
|
||||
|
||||
@(private)
|
||||
_pop_node :: proc(c: ^$C/Cache($Key, $Value), e: ^Node(Key, Value)) {
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
if e.prev != nil {
|
||||
e.prev.next = e.next
|
||||
}
|
||||
|
||||
if e.next != nil {
|
||||
e.next.prev = e.prev
|
||||
}
|
||||
e.prev = nil
|
||||
e.next = nil
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package container_queue
|
||||
|
||||
import "core:builtin"
|
||||
import "core:runtime"
|
||||
_ :: runtime
|
||||
|
||||
// Dynamically resizable double-ended queue/ring-buffer
|
||||
Queue :: struct($T: typeid) {
|
||||
@@ -86,7 +87,8 @@ push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
|
||||
if space(q^) == 0 {
|
||||
_grow(q) or_return
|
||||
}
|
||||
q.data[q.len] = elem
|
||||
idx := (q.offset+uint(q.len))%builtin.len(q.data)
|
||||
q.data[idx] = elem
|
||||
q.len += 1
|
||||
return true
|
||||
}
|
||||
@@ -126,6 +128,7 @@ pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
||||
pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
|
||||
assert(condition=q.len > 0, loc=loc)
|
||||
elem = q.data[q.offset]
|
||||
q.offset = (q.offset+1)%builtin.len(q.data)
|
||||
q.len -= 1
|
||||
return
|
||||
}
|
||||
@@ -133,6 +136,7 @@ pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) {
|
||||
pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) {
|
||||
if q.len > 0 {
|
||||
elem = q.data[q.offset]
|
||||
q.offset = (q.offset+1)%builtin.len(q.data)
|
||||
q.len -= 1
|
||||
ok = true
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ fe_from_bytes :: #force_inline proc (out1: ^Tight_Field_Element, arg1: []byte, a
|
||||
|
||||
assert(len(arg1) == 16)
|
||||
|
||||
when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
||||
// While it may be unwise to do deserialization here on our
|
||||
// own when fiat-crypto provides equivalent functionality,
|
||||
// doing it this way provides a little under 3x performance
|
||||
|
||||
@@ -52,7 +52,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) {
|
||||
t: u64 = ---
|
||||
bc: [5]u64 = ---
|
||||
|
||||
when ODIN_ENDIAN != "little" {
|
||||
when ODIN_ENDIAN != .Little {
|
||||
v: uintptr = ---
|
||||
for i = 0; i < 25; i += 1 {
|
||||
v := uintptr(&st[i])
|
||||
@@ -98,7 +98,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) {
|
||||
st[0] ~= keccakf_rndc[r]
|
||||
}
|
||||
|
||||
when ODIN_ENDIAN != "little" {
|
||||
when ODIN_ENDIAN != .Little {
|
||||
for i = 0; i < 25; i += 1 {
|
||||
v = uintptr(&st[i])
|
||||
t = st[i]
|
||||
|
||||
@@ -44,7 +44,7 @@ hash_bytes_224 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
@@ -123,7 +123,7 @@ hash_bytes_256 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
@@ -202,7 +202,7 @@ hash_bytes_384 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
@@ -281,7 +281,7 @@ hash_bytes_512 :: proc "contextless" (data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
|
||||
@@ -46,7 +46,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -47,7 +47,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -346,7 +346,7 @@ _do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
|
||||
// Until dedicated assembly can be written leverage the fact that
|
||||
// the callers of this routine ensure that src/dst are valid.
|
||||
|
||||
when ODIN_ARCH == "386" || ODIN_ARCH == "amd64" {
|
||||
when ODIN_ARCH == "i386" || ODIN_ARCH == "amd64" {
|
||||
// util.PUT_U32_LE/util.U32_LE are not required on little-endian
|
||||
// systems that also happen to not be strict about aligned
|
||||
// memory access.
|
||||
|
||||
@@ -41,7 +41,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -44,7 +44,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
@@ -123,7 +123,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
@@ -202,7 +202,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
@@ -281,7 +281,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
|
||||
@@ -50,7 +50,7 @@ hash_bytes_128_3 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128_3 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128_3(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_128_3(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128_3 will hash the given input and write the
|
||||
@@ -135,7 +135,7 @@ hash_bytes_128_4 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128_4 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128_4(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_128_4(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128_4 will hash the given input and write the
|
||||
@@ -220,7 +220,7 @@ hash_bytes_128_5 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128_5 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128_5(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_128_5(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128_5 will hash the given input and write the
|
||||
@@ -305,7 +305,7 @@ hash_bytes_160_3 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160_3 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160_3(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_160_3(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160_3 will hash the given input and write the
|
||||
@@ -390,7 +390,7 @@ hash_bytes_160_4 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160_4 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160_4(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_160_4(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160_4 will hash the given input and write the
|
||||
@@ -475,7 +475,7 @@ hash_bytes_160_5 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160_5 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160_5(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_160_5(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160_5 will hash the given input and write the
|
||||
@@ -560,7 +560,7 @@ hash_bytes_192_3 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_192_3 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_192_3(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_192_3(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_192_3 will hash the given input and write the
|
||||
@@ -645,7 +645,7 @@ hash_bytes_192_4 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_192_4 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_192_4(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_192_4(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_192_4 will hash the given input and write the
|
||||
@@ -730,7 +730,7 @@ hash_bytes_192_5 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_192_5 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_192_5(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_192_5(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_192_5 will hash the given input and write the
|
||||
@@ -815,7 +815,7 @@ hash_bytes_224_3 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224_3 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224_3(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224_3(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224_3 will hash the given input and write the
|
||||
@@ -900,7 +900,7 @@ hash_bytes_224_4 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224_4 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224_4(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224_4(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224_4 will hash the given input and write the
|
||||
@@ -985,7 +985,7 @@ hash_bytes_224_5 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224_5 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224_5(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224_5(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224_5 will hash the given input and write the
|
||||
@@ -1070,7 +1070,7 @@ hash_bytes_256_3 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256_3 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256_3(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256_3(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256_3 will hash the given input and write the
|
||||
@@ -1155,7 +1155,7 @@ hash_bytes_256_4 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256_4 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256_4(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256_4(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256_4 will hash the given input and write the
|
||||
@@ -1240,7 +1240,7 @@ hash_bytes_256_5 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256_5 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256_5(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256_5(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256_5 will hash the given input and write the
|
||||
@@ -1332,7 +1332,7 @@ update :: proc(ctx: ^Haval_Context, data: []byte) {
|
||||
}
|
||||
ctx.count[1] += str_len >> 29
|
||||
|
||||
when ODIN_ENDIAN == "little" {
|
||||
when ODIN_ENDIAN == .Little {
|
||||
if rmd_len + str_len >= 128 {
|
||||
copy(util.slice_to_bytes(ctx.block[:])[rmd_len:], data[:fill_len])
|
||||
block(ctx, ctx.rounds)
|
||||
|
||||
@@ -44,7 +44,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
@@ -123,7 +123,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
@@ -202,7 +202,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
@@ -281,7 +281,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
|
||||
@@ -49,7 +49,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
@@ -131,7 +131,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
@@ -213,7 +213,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
@@ -295,7 +295,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
|
||||
@@ -40,7 +40,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -44,7 +44,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -43,7 +43,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||
@@ -121,7 +121,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||
@@ -197,7 +197,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
@@ -273,7 +273,7 @@ hash_bytes_320 :: proc(data: []byte) -> [DIGEST_SIZE_320]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_320 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_320(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_320(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_320 will hash the given input and write the
|
||||
|
||||
@@ -43,7 +43,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -48,7 +48,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
@@ -127,7 +127,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
@@ -206,7 +206,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
@@ -285,7 +285,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
|
||||
@@ -47,7 +47,7 @@ hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_224 will hash the given input and write the
|
||||
@@ -126,7 +126,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
@@ -205,7 +205,7 @@ hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_384 will hash the given input and write the
|
||||
@@ -284,7 +284,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
|
||||
@@ -46,7 +46,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||
@@ -128,7 +128,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
|
||||
@@ -42,7 +42,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -44,7 +44,7 @@ hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_256 will hash the given input and write the
|
||||
@@ -122,7 +122,7 @@ hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_512 will hash the given input and write the
|
||||
|
||||
@@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||
@@ -124,7 +124,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||
@@ -203,7 +203,7 @@ hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_192(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_192(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_192 will hash the given input and write the
|
||||
|
||||
@@ -45,7 +45,7 @@ hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_128 will hash the given input and write the
|
||||
@@ -124,7 +124,7 @@ hash_bytes_160 :: proc(data: []byte) -> [DIGEST_SIZE_160]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_160 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_160(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_160 will hash the given input and write the
|
||||
@@ -203,7 +203,7 @@ hash_bytes_192 :: proc(data: []byte) -> [DIGEST_SIZE_192]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer_192 :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer_192(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer_192(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer_192 will hash the given input and write the
|
||||
|
||||
@@ -42,7 +42,7 @@ hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
|
||||
// computed hash to the second parameter.
|
||||
// It requires that the destination buffer is at least as big as the digest size
|
||||
hash_string_to_buffer :: proc(data: string, hash: []byte) {
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash);
|
||||
hash_bytes_to_buffer(transmute([]byte)(data), hash)
|
||||
}
|
||||
|
||||
// hash_bytes_to_buffer will hash the given input and write the
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
// Construction history, or BSP trees would make the format too large to serve its purpose.
|
||||
// The facilities of the formats to store meta data should make the format flexible enough
|
||||
// for most uses. Adding HxA support should be something anyone can do in a days work.
|
||||
|
||||
//
|
||||
// Structure:
|
||||
// ----------
|
||||
// HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has
|
||||
@@ -45,17 +45,17 @@
|
||||
// of a number of named layers. All layers in the stack have the same number of elements. Each layer
|
||||
// describes one property of the primitive. Each layer can have multiple channels and each layer can
|
||||
// store data of a different type.
|
||||
|
||||
//
|
||||
// HaX stores 3 kinds of nodes
|
||||
// - Pixel data.
|
||||
// - Polygon geometry data.
|
||||
// - Meta data only.
|
||||
|
||||
//
|
||||
// Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness,
|
||||
// Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the
|
||||
// layers to store things like color. The length of the layer stack is determined by the type and
|
||||
// dimensions stored in the
|
||||
|
||||
//
|
||||
// Geometry data is stored in 3 separate layer stacks for: vertex data, corner data and face data. The
|
||||
// vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first
|
||||
// layer in a vertex stack has to be a 3 channel layer named "position" describing the base position
|
||||
@@ -63,7 +63,7 @@
|
||||
// for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel
|
||||
// integer layer named "index" describing the vertices used to form polygons. The last value in each
|
||||
// polygon has a negative - 1 index to indicate the end of the polygon.
|
||||
|
||||
//
|
||||
// Example:
|
||||
// A quad and a tri with the vertex index:
|
||||
// [0, 1, 2, 3] [1, 4, 2]
|
||||
@@ -72,7 +72,7 @@
|
||||
// The face stack stores values per face. the length of the face stack has to match the number of
|
||||
// negative values in the index layer in the corner stack. The face stack can be used to store things
|
||||
// like material index.
|
||||
|
||||
//
|
||||
// Storage
|
||||
// -------
|
||||
// All data is stored in little endian byte order with no padding. The layout mirrors the structs
|
||||
|
||||
@@ -285,8 +285,8 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
|
||||
case runtime.Type_Info_Integer:
|
||||
switch info.endianness {
|
||||
case .Platform: return false
|
||||
case .Little: return ODIN_ENDIAN != "little"
|
||||
case .Big: return ODIN_ENDIAN != "big"
|
||||
case .Little: return ODIN_ENDIAN != .Little
|
||||
case .Big: return ODIN_ENDIAN != .Big
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
+1
-1
@@ -64,6 +64,7 @@ If not present, the width is whatever is necessary to represent the value.
|
||||
Precision is specified after the (optional) width followed by a period followed by a decimal number.
|
||||
If no period is present, a default precision is used.
|
||||
A period with no following number specifies a precision of 0.
|
||||
|
||||
Examples:
|
||||
%f default width, default precision
|
||||
%8f width 8, default precision
|
||||
@@ -84,7 +85,6 @@ Other flags:
|
||||
add leading 0z for dozenal (%#z)
|
||||
add leading 0x or 0X for hexadecimal (%#x or %#X)
|
||||
remove leading 0x for %p (%#p)
|
||||
|
||||
' ' (space) leave a space for elided sign in numbers (% d)
|
||||
0 pad with leading zeros rather than spaces
|
||||
|
||||
|
||||
+29
-8
@@ -11,6 +11,7 @@ import "core:time"
|
||||
import "core:unicode/utf8"
|
||||
import "core:intrinsics"
|
||||
|
||||
// Internal data structure that stores the required information for formatted printing
|
||||
Info :: struct {
|
||||
minus: bool,
|
||||
plus: bool,
|
||||
@@ -46,9 +47,13 @@ Register_User_Formatter_Error :: enum {
|
||||
// it is prefixed with `_` rather than marked with a private attribute so that users can access it if necessary
|
||||
_user_formatters: ^map[typeid]User_Formatter
|
||||
|
||||
// set_user_formatters assigns m to a global value allowing the user have custom print formatting for specific
|
||||
// types
|
||||
set_user_formatters :: proc(m: ^map[typeid]User_Formatter) {
|
||||
_user_formatters = m
|
||||
}
|
||||
// register_user_formatter assigns a formatter to a specific typeid. set_user_formatters must be called
|
||||
// before any use of this procedure.
|
||||
register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Register_User_Formatter_Error {
|
||||
if _user_formatters == nil {
|
||||
return .No_User_Formatter
|
||||
@@ -61,7 +66,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist
|
||||
}
|
||||
|
||||
|
||||
// aprint* procedures return a string that was allocated with the current context
|
||||
// aprint procedure return a string that was allocated with the current context
|
||||
// They must be freed accordingly
|
||||
aprint :: proc(args: ..any, sep := " ") -> string {
|
||||
str: strings.Builder
|
||||
@@ -69,12 +74,16 @@ aprint :: proc(args: ..any, sep := " ") -> string {
|
||||
sbprint(buf=&str, args=args, sep=sep)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
// aprintln procedure return a string that was allocated with the current context
|
||||
// They must be freed accordingly
|
||||
aprintln :: proc(args: ..any, sep := " ") -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str)
|
||||
sbprintln(buf=&str, args=args, sep=sep)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
// aprintf procedure return a string that was allocated with the current context
|
||||
// They must be freed accordingly
|
||||
aprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str)
|
||||
@@ -83,19 +92,21 @@ aprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
}
|
||||
|
||||
|
||||
// tprint* procedures return a string that was allocated with the current context's temporary allocator
|
||||
// tprint procedure return a string that was allocated with the current context's temporary allocator
|
||||
tprint :: proc(args: ..any, sep := " ") -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str, context.temp_allocator)
|
||||
sbprint(buf=&str, args=args, sep=sep)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
// tprintln procedure return a string that was allocated with the current context's temporary allocator
|
||||
tprintln :: proc(args: ..any, sep := " ") -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str, context.temp_allocator)
|
||||
sbprintln(buf=&str, args=args, sep=sep)
|
||||
return strings.to_string(str)
|
||||
}
|
||||
// tprintf procedure return a string that was allocated with the current context's temporary allocator
|
||||
tprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
str: strings.Builder
|
||||
strings.init_builder(&str, context.temp_allocator)
|
||||
@@ -104,21 +115,24 @@ tprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
}
|
||||
|
||||
|
||||
// bprint* procedures return a string using a buffer from an array
|
||||
// bprint procedures return a string using a buffer from an array
|
||||
bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string {
|
||||
sb := strings.builder_from_slice(buf[0:len(buf)])
|
||||
return sbprint(buf=&sb, args=args, sep=sep)
|
||||
}
|
||||
// bprintln procedures return a string using a buffer from an array
|
||||
bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string {
|
||||
sb := strings.builder_from_slice(buf[0:len(buf)])
|
||||
return sbprintln(buf=&sb, args=args, sep=sep)
|
||||
}
|
||||
// bprintf procedures return a string using a buffer from an array
|
||||
bprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string {
|
||||
sb := strings.builder_from_slice(buf[0:len(buf)])
|
||||
return sbprintf(&sb, fmt, ..args)
|
||||
}
|
||||
|
||||
|
||||
// formatted assert
|
||||
assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_location) -> bool {
|
||||
if !condition {
|
||||
p := context.assertion_failure_proc
|
||||
@@ -131,6 +145,7 @@ assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_locati
|
||||
return condition
|
||||
}
|
||||
|
||||
// formatted panic
|
||||
panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
|
||||
p := context.assertion_failure_proc
|
||||
if p == nil {
|
||||
@@ -142,24 +157,26 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// sbprint formats using the default print settings and writes to buf
|
||||
sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
|
||||
wprint(w=strings.to_writer(buf), args=args, sep=sep)
|
||||
return strings.to_string(buf^)
|
||||
}
|
||||
|
||||
// sbprintln formats using the default print settings and writes to buf
|
||||
sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string {
|
||||
wprintln(w=strings.to_writer(buf), args=args, sep=sep)
|
||||
return strings.to_string(buf^)
|
||||
}
|
||||
|
||||
// sbprintf formats according to the specififed format string and writes to buf
|
||||
sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string {
|
||||
wprintf(w=strings.to_writer(buf), fmt=fmt, args=args)
|
||||
return strings.to_string(buf^)
|
||||
}
|
||||
|
||||
|
||||
// wprint formats using the default print settings and writes to w
|
||||
wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
fi: Info
|
||||
fi.writer = w
|
||||
@@ -194,6 +211,7 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
return int(size1 - size0)
|
||||
}
|
||||
|
||||
// wprintln formats using the default print settings and writes to w
|
||||
wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
fi: Info
|
||||
fi.writer = w
|
||||
@@ -214,6 +232,7 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ") -> int {
|
||||
return int(size1 - size0)
|
||||
}
|
||||
|
||||
// wprintf formats according to the specififed format string and writes to w
|
||||
wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
|
||||
fi: Info
|
||||
arg_index: int = 0
|
||||
@@ -493,11 +512,13 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any) -> int {
|
||||
return int(size1 - size0)
|
||||
}
|
||||
|
||||
// wprint_type is a utility procedure to write a ^runtime.Type_Info value to w
|
||||
wprint_type :: proc(w: io.Writer, info: ^runtime.Type_Info) -> (int, io.Error) {
|
||||
n, err := reflect.write_type(w, info)
|
||||
io.flush(auto_cast w)
|
||||
return n, err
|
||||
}
|
||||
// wprint_typeid is a utility procedure to write a typeid value to w
|
||||
wprint_typeid :: proc(w: io.Writer, id: typeid) -> (int, io.Error) {
|
||||
n, err := reflect.write_type(w, type_info_of(id))
|
||||
io.flush(auto_cast w)
|
||||
@@ -829,7 +850,7 @@ _pad :: proc(fi: ^Info, s: string) {
|
||||
|
||||
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||
switch verb {
|
||||
case 'f', 'F', 'v':
|
||||
case 'f', 'F', 'g', 'G', 'v':
|
||||
prec: int = 3
|
||||
if fi.prec_set {
|
||||
prec = fi.prec
|
||||
@@ -1092,8 +1113,8 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "") {
|
||||
case runtime.Type_Info_Integer:
|
||||
switch info.endianness {
|
||||
case .Platform: return false
|
||||
case .Little: return ODIN_ENDIAN != "little"
|
||||
case .Big: return ODIN_ENDIAN != "big"
|
||||
case .Little: return ODIN_ENDIAN != .Little
|
||||
case .Big: return ODIN_ENDIAN != .Big
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -34,11 +34,16 @@ stderr := io.Writer{
|
||||
},
|
||||
}
|
||||
|
||||
// print* procedures return the number of bytes written
|
||||
// print formats using the default print settings and writes to stdout
|
||||
print :: proc(args: ..any, sep := " ") -> int { return wprint(w=stdout, args=args, sep=sep) }
|
||||
// println formats using the default print settings and writes to stdout
|
||||
println :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stdout, args=args, sep=sep) }
|
||||
// printf formats according to the specififed format string and writes to stdout
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return wprintf(stdout, fmt, ..args) }
|
||||
|
||||
// eprint formats using the default print settings and writes to stderr
|
||||
eprint :: proc(args: ..any, sep := " ") -> int { return wprint(w=stderr, args=args, sep=sep) }
|
||||
// eprintln formats using the default print settings and writes to stderr
|
||||
eprintln :: proc(args: ..any, sep := " ") -> int { return wprintln(w=stderr, args=args, sep=sep) }
|
||||
// eprintf formats according to the specififed format string and writes to stderr
|
||||
eprintf :: proc(fmt: string, args: ..any) -> int { return wprintf(stderr, fmt, ..args) }
|
||||
|
||||
@@ -5,15 +5,18 @@ import "core:runtime"
|
||||
import "core:os"
|
||||
import "core:io"
|
||||
|
||||
// fprint formats using the default print settings and writes to fd
|
||||
fprint :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
|
||||
w := io.to_writer(os.stream_from_handle(fd))
|
||||
return wprint(w=w, args=args, sep=sep)
|
||||
}
|
||||
|
||||
// fprintln formats using the default print settings and writes to fd
|
||||
fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int {
|
||||
w := io.to_writer(os.stream_from_handle(fd))
|
||||
return wprintln(w=w, args=args, sep=sep)
|
||||
}
|
||||
// fprintf formats according to the specififed format string and writes to fd
|
||||
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
||||
w := io.to_writer(os.stream_from_handle(fd))
|
||||
return wprintf(w, fmt, ..args)
|
||||
@@ -27,11 +30,16 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) {
|
||||
return wprint_typeid(w, id)
|
||||
}
|
||||
|
||||
// print* procedures return the number of bytes written
|
||||
// print formats using the default print settings and writes to os.stdout
|
||||
print :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stdout, args=args, sep=sep) }
|
||||
// println formats using the default print settings and writes to os.stdout
|
||||
println :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stdout, args=args, sep=sep) }
|
||||
// printf formats according to the specififed format string and writes to os.stdout
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) }
|
||||
|
||||
// eprint formats using the default print settings and writes to os.stderr
|
||||
eprint :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stderr, args=args, sep=sep) }
|
||||
// eprintln formats using the default print settings and writes to os.stderr
|
||||
eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stderr, args=args, sep=sep) }
|
||||
// eprintf formats according to the specififed format string and writes to os.stderr
|
||||
eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) }
|
||||
|
||||
@@ -96,7 +96,7 @@ XXH3_128_canonical_from_hash :: proc(hash: XXH128_hash_t) -> (canonical: XXH128_
|
||||
#assert(size_of(XXH128_canonical) == size_of(XXH128_hash_t))
|
||||
|
||||
t := hash
|
||||
when ODIN_ENDIAN == "little" {
|
||||
when ODIN_ENDIAN == .Little {
|
||||
t.high = byte_swap(t.high)
|
||||
t.low = byte_swap(t.low)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
Jeroen van Rijn: Initial implementation, optimization.
|
||||
Ginger Bill: Cosmetic changes.
|
||||
*/
|
||||
|
||||
// package image implements a general 2D image library to be used with other image related packages
|
||||
package image
|
||||
|
||||
import "core:bytes"
|
||||
|
||||
@@ -189,7 +189,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b
|
||||
img := image
|
||||
|
||||
// PBM 16-bit images are big endian
|
||||
when ODIN_ENDIAN == "little" {
|
||||
when ODIN_ENDIAN == .Little {
|
||||
if img.depth == 16 {
|
||||
// The pixel components are in Big Endian. Let's byteswap back.
|
||||
input := mem.slice_data_cast([]u16, img.pixels.buf[:])
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
Ginger Bill: Cosmetic changes.
|
||||
*/
|
||||
|
||||
|
||||
// package png implements a PNG image reader
|
||||
//
|
||||
// The PNG specification is at https://www.w3.org/TR/PNG/.
|
||||
package png
|
||||
|
||||
import "core:compress"
|
||||
@@ -1611,7 +1616,7 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH
|
||||
}
|
||||
}
|
||||
}
|
||||
when ODIN_ENDIAN == "little" {
|
||||
when ODIN_ENDIAN == .Little {
|
||||
if img.depth == 16 {
|
||||
// The pixel components are in Big Endian. Let's byteswap.
|
||||
input := mem.slice_data_cast([]u16be, img.pixels.buf[:])
|
||||
|
||||
@@ -197,3 +197,8 @@ type_field_index_of :: proc($T: typeid, $name: string) -> uintptr ---
|
||||
|
||||
type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) ---
|
||||
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
|
||||
|
||||
|
||||
// Internal compiler use only
|
||||
|
||||
__entry_point :: proc() ---
|
||||
+39
-2
@@ -1,9 +1,13 @@
|
||||
// package io provides basic interfaces for generic data stream primitives.
|
||||
// The purpose of this package is wrap existing data structures and their
|
||||
// operations into an abstracted stream interface.
|
||||
package io
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
// Seek whence values
|
||||
Seek_From :: enum {
|
||||
Start = 0, // seek relative to the origin of the file
|
||||
Current = 1, // seek relative to the current offset
|
||||
@@ -139,6 +143,10 @@ destroy :: proc(s: Stream) -> Error {
|
||||
return .Empty
|
||||
}
|
||||
|
||||
// read reads up to len(p) bytes into s. It returns the number of bytes read and any error if occurred.
|
||||
//
|
||||
// When read encounters an .EOF or error after successfully reading n > 0 bytes, it returns the number of
|
||||
// bytes read along with the error.
|
||||
read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) {
|
||||
if s.stream_vtable != nil && s.impl_read != nil {
|
||||
n, err = s->impl_read(p)
|
||||
@@ -150,6 +158,7 @@ read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) {
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
// write writes up to len(p) bytes into s. It returns the number of bytes written and any error if occurred.
|
||||
write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
if s.stream_vtable != nil && s.impl_write != nil {
|
||||
n, err = s->impl_write(p)
|
||||
@@ -161,6 +170,13 @@ write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Erro
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
// seek sets the offset of the next read or write to offset.
|
||||
//
|
||||
// .Start means seek relative to the origin of the file.
|
||||
// .Current means seek relative to the current offset.
|
||||
// .End means seek relative to the end.
|
||||
//
|
||||
// seek returns the new offset to the start of the file/stream, and any error if occurred.
|
||||
seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
|
||||
if s.stream_vtable != nil && s.impl_seek != nil {
|
||||
return s->impl_seek(offset, whence)
|
||||
@@ -168,6 +184,8 @@ seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error)
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
// The behaviour of close after the first call is stream implementation defined.
|
||||
// Different streams may document their own behaviour.
|
||||
close :: proc(s: Closer) -> Error {
|
||||
if s.stream_vtable != nil && s.impl_close != nil {
|
||||
return s->impl_close()
|
||||
@@ -184,6 +202,7 @@ flush :: proc(s: Flusher) -> Error {
|
||||
return .None
|
||||
}
|
||||
|
||||
// size returns the size of the stream. If the stream does not support querying its size, 0 will be returned.
|
||||
size :: proc(s: Stream) -> i64 {
|
||||
if s.stream_vtable == nil {
|
||||
return 0
|
||||
@@ -214,7 +233,12 @@ size :: proc(s: Stream) -> i64 {
|
||||
|
||||
|
||||
|
||||
|
||||
// read_at reads len(p) bytes into p starting with the provided offset in the underlying Reader_At stream r.
|
||||
// It returns the number of bytes read and any error if occurred.
|
||||
//
|
||||
// When read_at returns n < len(p), it returns a non-nil Error explaining why.
|
||||
//
|
||||
// If n == len(p), err may be either nil or .EOF
|
||||
read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n: int, err: Error) {
|
||||
defer if n_read != nil {
|
||||
n_read^ += n
|
||||
@@ -245,6 +269,11 @@ read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n:
|
||||
|
||||
}
|
||||
|
||||
// write_at writes len(p) bytes into p starting with the provided offset in the underlying Writer_At stream w.
|
||||
// It returns the number of bytes written and any error if occurred.
|
||||
//
|
||||
// If write_at is writing to a Writer_At which has a seek offset, then write_at should not affect the underlying
|
||||
// seek offset.
|
||||
write_at :: proc(w: Writer_At, p: []byte, offset: i64, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
defer if n_written != nil {
|
||||
n_written^ += n
|
||||
@@ -294,6 +323,7 @@ read_from :: proc(w: Reader_From, r: Reader) -> (n: i64, err: Error) {
|
||||
}
|
||||
|
||||
|
||||
// read_byte reads and returns the next byte from r.
|
||||
read_byte :: proc(r: Byte_Reader, n_read: ^int = nil) -> (b: byte, err: Error) {
|
||||
defer if err == nil && n_read != nil {
|
||||
n_read^ += 1
|
||||
@@ -347,6 +377,7 @@ _write_byte :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> (err: Err
|
||||
return err
|
||||
}
|
||||
|
||||
// read_rune reads a single UTF-8 encoded Unicode codepoint and returns the rune and its size in bytes.
|
||||
read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) {
|
||||
defer if err == nil && n_read != nil {
|
||||
n_read^ += size
|
||||
@@ -405,10 +436,12 @@ unread_rune :: proc(s: Rune_Scanner) -> Error {
|
||||
}
|
||||
|
||||
|
||||
// write_string writes the contents of the string s to w.
|
||||
write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
return write(s, transmute([]byte)str, n_written)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
n_written^ += size
|
||||
@@ -430,12 +463,16 @@ write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err
|
||||
}
|
||||
|
||||
|
||||
|
||||
// read_full expected exactly len(buf) bytes from r into buf.
|
||||
read_full :: proc(r: Reader, buf: []byte) -> (n: int, err: Error) {
|
||||
return read_at_least(r, buf, len(buf))
|
||||
}
|
||||
|
||||
|
||||
// read_at_least reads from r into buf until it has read at least min bytes. It returns the number
|
||||
// of bytes copied and an error if fewer bytes were read. `.EOF` is only returned if no bytes were read.
|
||||
// `.Unexpected_EOF` is returned when an `.EOF ` is returned by the passed Reader after reading
|
||||
// fewer than min bytes. If len(buf) is less than min, `.Short_Buffer` is returned.
|
||||
read_at_least :: proc(r: Reader, buf: []byte, min: int) -> (n: int, err: Error) {
|
||||
if len(buf) < min {
|
||||
return 0, .Short_Buffer
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
An arbitrary precision mathematics implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
This file collects public proc maps and their aliases.
|
||||
*/
|
||||
|
||||
|
||||
package math_big
|
||||
/*
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
An arbitrary precision mathematics implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
*/
|
||||
|
||||
|
||||
package math_big
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
A BigInt implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
*/
|
||||
package math_big
|
||||
@@ -1,11 +1,9 @@
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
An arbitrary precision mathematics implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
*/
|
||||
|
||||
|
||||
package math_big
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
//+ignore
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
A BigInt implementation in Odin.
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
|
||||
========================== Low-level routines ==========================
|
||||
|
||||
IMPORTANT: `internal_*` procedures make certain assumptions about their input.
|
||||
@@ -29,6 +24,9 @@
|
||||
|
||||
TODO: Handle +/- Infinity and NaN.
|
||||
*/
|
||||
|
||||
|
||||
//+ignore
|
||||
package math_big
|
||||
|
||||
import "core:mem"
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
This file contains logical operations like `and`, `or` and `xor`.
|
||||
*/
|
||||
|
||||
|
||||
package math_big
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
This file contains prime finding operations.
|
||||
*/
|
||||
|
||||
|
||||
package math_big
|
||||
|
||||
import rnd "core:math/rand"
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
These aren't exported for the same reasons.
|
||||
*/
|
||||
|
||||
|
||||
package math_big
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
This file contains basic arithmetic operations like `add`, `sub`, `mul`, `div`, ...
|
||||
*/
|
||||
|
||||
|
||||
package math_big
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
- Use Barrett reduction for non-powers-of-two.
|
||||
- Also look at extracting and splatting several digits at once.
|
||||
*/
|
||||
|
||||
|
||||
package math_big
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
//+ignore
|
||||
/*
|
||||
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
@@ -7,6 +6,8 @@
|
||||
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
|
||||
The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks.
|
||||
*/
|
||||
|
||||
//+ignore
|
||||
package math_big
|
||||
|
||||
import "core:time"
|
||||
|
||||
+16
-16
@@ -69,29 +69,29 @@ rotate_left :: proc(x: uint, k: int) -> uint {
|
||||
}
|
||||
|
||||
from_be_u8 :: proc(i: u8) -> u8 { return i }
|
||||
from_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } }
|
||||
from_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } }
|
||||
from_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } }
|
||||
from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } }
|
||||
from_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
|
||||
from_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
|
||||
from_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
|
||||
from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
|
||||
|
||||
from_le_u8 :: proc(i: u8) -> u8 { return i }
|
||||
from_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } }
|
||||
from_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } }
|
||||
from_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } }
|
||||
from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } }
|
||||
from_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
|
||||
from_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
|
||||
from_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
|
||||
from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
|
||||
|
||||
to_be_u8 :: proc(i: u8) -> u8 { return i }
|
||||
to_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } }
|
||||
to_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } }
|
||||
to_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } }
|
||||
to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i } else { return byte_swap(i) } }
|
||||
to_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
|
||||
to_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
|
||||
to_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
|
||||
to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Big { return i } else { return byte_swap(i) } }
|
||||
|
||||
|
||||
to_le_u8 :: proc(i: u8) -> u8 { return i }
|
||||
to_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } }
|
||||
to_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } }
|
||||
to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } }
|
||||
to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i } else { return byte_swap(i) } }
|
||||
to_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
|
||||
to_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
|
||||
to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
|
||||
to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == .Little { return i } else { return byte_swap(i) } }
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package linalg
|
||||
|
||||
import "core:math"
|
||||
import "core:builtin"
|
||||
import "core:intrinsics"
|
||||
|
||||
// Generic
|
||||
@@ -60,14 +61,7 @@ quaternion256_dot :: proc(a, b: $T/quaternion256) -> (c: f64) {
|
||||
dot :: proc{scalar_dot, vector_dot, quaternion64_dot, quaternion128_dot, quaternion256_dot}
|
||||
|
||||
inner_product :: dot
|
||||
outer_product :: proc(a: $A/[$M]$E, b: $B/[$N]E) -> (out: [M][N]E) where IS_NUMERIC(E) #no_bounds_check {
|
||||
for i in 0..<M {
|
||||
for j in 0..<N {
|
||||
out[i][j] = a[i]*b[j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
outer_product :: builtin.outer_product
|
||||
|
||||
quaternion_inverse :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
|
||||
return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0)
|
||||
@@ -163,65 +157,28 @@ identity :: proc($T: typeid/[$N][N]$E) -> (m: T) #no_bounds_check {
|
||||
return m
|
||||
}
|
||||
|
||||
trace :: proc(m: $T/[$N][N]$E) -> (tr: E) {
|
||||
for i in 0..<N {
|
||||
tr += m[i][i]
|
||||
}
|
||||
return
|
||||
}
|
||||
trace :: builtin.matrix_trace
|
||||
transpose :: builtin.transpose
|
||||
|
||||
transpose :: proc(a: $T/[$N][$M]$E) -> (m: (T when N == M else [M][N]E)) #no_bounds_check {
|
||||
for j in 0..<M {
|
||||
for i in 0..<N {
|
||||
m[j][i] = a[i][j]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
matrix_mul :: proc(a, b: $M/[$N][N]$E) -> (c: M)
|
||||
matrix_mul :: proc(a, b: $M/matrix[$N, N]$E) -> (c: M)
|
||||
where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
|
||||
for i in 0..<N {
|
||||
for k in 0..<N {
|
||||
for j in 0..<N {
|
||||
c[k][i] += a[j][i] * b[k][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return a * b
|
||||
}
|
||||
|
||||
matrix_comp_mul :: proc(a, b: $M/[$J][$I]$E) -> (c: M)
|
||||
matrix_comp_mul :: proc(a, b: $M/matrix[$I, $J]$E) -> (c: M)
|
||||
where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
|
||||
for j in 0..<J {
|
||||
for i in 0..<I {
|
||||
c[j][i] = a[j][i] * b[j][i]
|
||||
}
|
||||
}
|
||||
return
|
||||
return hadamard_product(a, b)
|
||||
}
|
||||
|
||||
matrix_mul_differ :: proc(a: $A/[$J][$I]$E, b: $B/[$K][J]E) -> (c: [K][I]E)
|
||||
matrix_mul_differ :: proc(a: $A/matrix[$I, $J]$E, b: $B/matrix[J, $K]E) -> (c: matrix[I, K]E)
|
||||
where !IS_ARRAY(E), IS_NUMERIC(E), I != K #no_bounds_check {
|
||||
for k in 0..<K {
|
||||
for j in 0..<J {
|
||||
for i in 0..<I {
|
||||
c[k][i] += a[j][i] * b[k][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return a * b
|
||||
}
|
||||
|
||||
|
||||
matrix_mul_vector :: proc(a: $A/[$I][$J]$E, b: $B/[I]E) -> (c: B)
|
||||
matrix_mul_vector :: proc(a: $A/matrix[$I, $J]$E, b: $B/[J]E) -> (c: B)
|
||||
where !IS_ARRAY(E), IS_NUMERIC(E) #no_bounds_check {
|
||||
for i in 0..<I {
|
||||
for j in 0..<J {
|
||||
c[j] += a[i][j] * b[i]
|
||||
}
|
||||
}
|
||||
return
|
||||
return a * b
|
||||
}
|
||||
|
||||
quaternion_mul_quaternion :: proc(q1, q2: $Q) -> Q where IS_QUATERNION(Q) {
|
||||
@@ -270,8 +227,8 @@ mul :: proc{
|
||||
vector_to_ptr :: proc(v: ^$V/[$N]$E) -> ^E where IS_NUMERIC(E), N > 0 #no_bounds_check {
|
||||
return &v[0]
|
||||
}
|
||||
matrix_to_ptr :: proc(m: ^$A/[$I][$J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check {
|
||||
return &m[0][0]
|
||||
matrix_to_ptr :: proc(m: ^$A/matrix[$I, $J]$E) -> ^E where IS_NUMERIC(E), I > 0, J > 0 #no_bounds_check {
|
||||
return &m[0, 0]
|
||||
}
|
||||
|
||||
to_ptr :: proc{vector_to_ptr, matrix_to_ptr}
|
||||
@@ -330,10 +287,10 @@ array_cast :: proc(v: $A/[$N]$T, $Elem_Type: typeid) -> (w: [N]Elem_Type) #no_bo
|
||||
return
|
||||
}
|
||||
|
||||
matrix_cast :: proc(v: $A/[$M][$N]$T, $Elem_Type: typeid) -> (w: [M][N]Elem_Type) #no_bounds_check {
|
||||
for i in 0..<M {
|
||||
for j in 0..<N {
|
||||
w[i][j] = Elem_Type(v[i][j])
|
||||
matrix_cast :: proc(v: $A/matrix[$M, $N]$T, $Elem_Type: typeid) -> (w: matrix[M, N]Elem_Type) #no_bounds_check {
|
||||
for j in 0..<N {
|
||||
for i in 0..<M {
|
||||
w[i, j] = Elem_Type(v[i, j])
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -357,6 +314,6 @@ to_uint :: #force_inline proc(v: $A/[$N]$T) -> [N]uint { return array_cast(v, ui
|
||||
to_complex32 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex32 { return array_cast(v, complex32) }
|
||||
to_complex64 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex64 { return array_cast(v, complex64) }
|
||||
to_complex128 :: #force_inline proc(v: $A/[$N]$T) -> [N]complex128 { return array_cast(v, complex128) }
|
||||
to_quaternion64 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion64 { return array_cast(v, quaternion64) }
|
||||
to_quaternion64 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion64 { return array_cast(v, quaternion64) }
|
||||
to_quaternion128 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion128 { return array_cast(v, quaternion128) }
|
||||
to_quaternion256 :: #force_inline proc(v: $A/[$N]$T) -> [N]quaternion256 { return array_cast(v, quaternion256) }
|
||||
|
||||
@@ -473,6 +473,25 @@ floor_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {floor(x.x), floor(x.y), fl
|
||||
floor_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {floor(x.x), floor(x.y), floor(x.z), floor(x.w)} }
|
||||
|
||||
|
||||
|
||||
round :: proc{
|
||||
round_f32,
|
||||
round_f64,
|
||||
round_vec2,
|
||||
round_vec3,
|
||||
round_vec4,
|
||||
round_dvec2,
|
||||
round_dvec3,
|
||||
round_dvec4,
|
||||
}
|
||||
round_vec2 :: proc "c" (x: vec2) -> vec2 { return {round(x.x), round(x.y)} }
|
||||
round_vec3 :: proc "c" (x: vec3) -> vec3 { return {round(x.x), round(x.y), round(x.z)} }
|
||||
round_vec4 :: proc "c" (x: vec4) -> vec4 { return {round(x.x), round(x.y), round(x.z), round(x.w)} }
|
||||
round_dvec2 :: proc "c" (x: dvec2) -> dvec2 { return {round(x.x), round(x.y)} }
|
||||
round_dvec3 :: proc "c" (x: dvec3) -> dvec3 { return {round(x.x), round(x.y), round(x.z)} }
|
||||
round_dvec4 :: proc "c" (x: dvec4) -> dvec4 { return {round(x.x), round(x.y), round(x.z), round(x.w)} }
|
||||
|
||||
|
||||
ceil :: proc{
|
||||
ceil_f32,
|
||||
ceil_f64,
|
||||
@@ -693,23 +712,22 @@ saturate :: proc{
|
||||
saturate_uvec3,
|
||||
saturate_uvec4,
|
||||
}
|
||||
saturate_i32 :: proc "c" (x, y, z: i32) -> i32 { return builtin.clamp(x, 0, 1) }
|
||||
saturate_u32 :: proc "c" (x, y, z: u32) -> u32 { return builtin.clamp(x, 0, 1) }
|
||||
saturate_f32 :: proc "c" (x, y, z: f32) -> f32 { return builtin.clamp(x, 0, 1) }
|
||||
saturate_f64 :: proc "c" (x, y, z: f64) -> f64 { return builtin.clamp(x, 0, 1) }
|
||||
saturate_vec2 :: proc "c" (x, y, z: vec2) -> vec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} }
|
||||
saturate_vec3 :: proc "c" (x, y, z: vec3) -> vec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} }
|
||||
saturate_vec4 :: proc "c" (x, y, z: vec4) -> vec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} }
|
||||
saturate_dvec2 :: proc "c" (x, y, z: dvec2) -> dvec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} }
|
||||
saturate_dvec3 :: proc "c" (x, y, z: dvec3) -> dvec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} }
|
||||
saturate_dvec4 :: proc "c" (x, y, z: dvec4) -> dvec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} }
|
||||
saturate_ivec2 :: proc "c" (x, y, z: ivec2) -> ivec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} }
|
||||
saturate_ivec3 :: proc "c" (x, y, z: ivec3) -> ivec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} }
|
||||
saturate_ivec4 :: proc "c" (x, y, z: ivec4) -> ivec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} }
|
||||
saturate_uvec2 :: proc "c" (x, y, z: uvec2) -> uvec2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} }
|
||||
saturate_uvec3 :: proc "c" (x, y, z: uvec3) -> uvec3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} }
|
||||
saturate_uvec4 :: proc "c" (x, y, z: uvec4) -> uvec4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} }
|
||||
|
||||
saturate_i32 :: proc "c" (v: i32) -> i32 { return builtin.clamp(v, 0, 1) }
|
||||
saturate_u32 :: proc "c" (v: u32) -> u32 { return builtin.clamp(v, 0, 1) }
|
||||
saturate_f32 :: proc "c" (v: f32) -> f32 { return builtin.clamp(v, 0, 1) }
|
||||
saturate_f64 :: proc "c" (v: f64) -> f64 { return builtin.clamp(v, 0, 1) }
|
||||
saturate_vec2 :: proc "c" (v: vec2) -> vec2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} }
|
||||
saturate_vec3 :: proc "c" (v: vec3) -> vec3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} }
|
||||
saturate_vec4 :: proc "c" (v: vec4) -> vec4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} }
|
||||
saturate_dvec2 :: proc "c" (v: dvec2) -> dvec2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} }
|
||||
saturate_dvec3 :: proc "c" (v: dvec3) -> dvec3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} }
|
||||
saturate_dvec4 :: proc "c" (v: dvec4) -> dvec4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} }
|
||||
saturate_ivec2 :: proc "c" (v: ivec2) -> ivec2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} }
|
||||
saturate_ivec3 :: proc "c" (v: ivec3) -> ivec3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} }
|
||||
saturate_ivec4 :: proc "c" (v: ivec4) -> ivec4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} }
|
||||
saturate_uvec2 :: proc "c" (v: uvec2) -> uvec2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} }
|
||||
saturate_uvec3 :: proc "c" (v: uvec3) -> uvec3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} }
|
||||
saturate_uvec4 :: proc "c" (v: uvec4) -> uvec4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} }
|
||||
|
||||
mix :: proc{
|
||||
mix_f32,
|
||||
@@ -1597,7 +1615,7 @@ quatNlerp :: proc "c" (a, b: quat, t: f32) -> (c: quat) {
|
||||
c.y = a.y + (b.y-a.y)*t
|
||||
c.z = a.z + (b.z-a.z)*t
|
||||
c.w = a.w + (b.w-a.w)*t
|
||||
return c/builtin.abs(c)
|
||||
return c/quat(builtin.abs(c))
|
||||
}
|
||||
|
||||
quatSlerp :: proc "c" (x, y: quat, t: f32) -> (q: quat) {
|
||||
@@ -1699,7 +1717,7 @@ dquatNlerp :: proc "c" (a, b: dquat, t: f64) -> (c: dquat) {
|
||||
c.y = a.y + (b.y-a.y)*t
|
||||
c.z = a.z + (b.z-a.z)*t
|
||||
c.w = a.w + (b.w-a.w)*t
|
||||
return c/builtin.abs(c)
|
||||
return c/dquat(builtin.abs(c))
|
||||
}
|
||||
|
||||
dquatSlerp :: proc "c" (x, y: dquat, t: f64) -> (q: dquat) {
|
||||
|
||||
@@ -23,6 +23,7 @@ log_f32 :: proc "c" (x: f32) -> f32 { return math.ln(x) }
|
||||
exp2_f32 :: proc "c" (x: f32) -> f32 { return math.pow(f32(2), x) }
|
||||
sign_f32 :: proc "c" (x: f32) -> f32 { return math.sign(x) }
|
||||
floor_f32 :: proc "c" (x: f32) -> f32 { return math.floor(x) }
|
||||
round_f32 :: proc "c" (x: f32) -> f32 { return math.round(x) }
|
||||
ceil_f32 :: proc "c" (x: f32) -> f32 { return math.ceil(x) }
|
||||
mod_f32 :: proc "c" (x, y: f32) -> f32 { return math.mod(x, y) }
|
||||
fract_f32 :: proc "c" (x: f32) -> f32 {
|
||||
@@ -53,6 +54,7 @@ log_f64 :: proc "c" (x: f64) -> f64 { return math.ln(x) }
|
||||
exp2_f64 :: proc "c" (x: f64) -> f64 { return math.pow(f64(2), x) }
|
||||
sign_f64 :: proc "c" (x: f64) -> f64 { return math.sign(x) }
|
||||
floor_f64 :: proc "c" (x: f64) -> f64 { return math.floor(x) }
|
||||
round_f64 :: proc "c" (x: f64) -> f64 { return math.round(x) }
|
||||
ceil_f64 :: proc "c" (x: f64) -> f64 { return math.ceil(x) }
|
||||
mod_f64 :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) }
|
||||
fract_f64 :: proc "c" (x: f64) -> f64 {
|
||||
|
||||
@@ -551,6 +551,23 @@ floor_double2 :: proc "c" (x: double2) -> double2 { return {floor(x.x), floor(x.
|
||||
floor_double3 :: proc "c" (x: double3) -> double3 { return {floor(x.x), floor(x.y), floor(x.z)} }
|
||||
floor_double4 :: proc "c" (x: double4) -> double4 { return {floor(x.x), floor(x.y), floor(x.z), floor(x.w)} }
|
||||
|
||||
round :: proc{
|
||||
round_float,
|
||||
round_double,
|
||||
round_float2,
|
||||
round_float3,
|
||||
round_float4,
|
||||
round_double2,
|
||||
round_double3,
|
||||
round_double4,
|
||||
}
|
||||
round_float2 :: proc "c" (x: float2) -> float2 { return {round(x.x), round(x.y)} }
|
||||
round_float3 :: proc "c" (x: float3) -> float3 { return {round(x.x), round(x.y), round(x.z)} }
|
||||
round_float4 :: proc "c" (x: float4) -> float4 { return {round(x.x), round(x.y), round(x.z), round(x.w)} }
|
||||
round_double2 :: proc "c" (x: double2) -> double2 { return {round(x.x), round(x.y)} }
|
||||
round_double3 :: proc "c" (x: double3) -> double3 { return {round(x.x), round(x.y), round(x.z)} }
|
||||
round_double4 :: proc "c" (x: double4) -> double4 { return {round(x.x), round(x.y), round(x.z), round(x.w)} }
|
||||
|
||||
|
||||
ceil :: proc{
|
||||
ceil_float,
|
||||
@@ -570,6 +587,69 @@ ceil_double3 :: proc "c" (x: double3) -> double3 { return {ceil(x.x), ceil(x.y),
|
||||
ceil_double4 :: proc "c" (x: double4) -> double4 { return {ceil(x.x), ceil(x.y), ceil(x.z), ceil(x.w)} }
|
||||
|
||||
|
||||
isfinite_float :: proc "c" (x: float) -> bool { return !isinf_float(x) }
|
||||
isfinite_float2 :: proc "c" (x: float2) -> bool2 { return {isfinite_float(x.x), isfinite_float(x.y)} }
|
||||
isfinite_float3 :: proc "c" (x: float3) -> bool3 { return {isfinite_float(x.x), isfinite_float(x.y), isfinite_float(x.z)} }
|
||||
isfinite_float4 :: proc "c" (x: float4) -> bool4 { return {isfinite_float(x.x), isfinite_float(x.y), isfinite_float(x.z), isfinite_float(x.w)} }
|
||||
isfinite_double :: proc "c" (x: double) -> bool { return !isinf_double(x) }
|
||||
isfinite_double2 :: proc "c" (x: double2) -> bool2 { return {isfinite_double(x.x), isfinite_double(x.y)} }
|
||||
isfinite_double3 :: proc "c" (x: double3) -> bool3 { return {isfinite_double(x.x), isfinite_double(x.y), isfinite_double(x.z)} }
|
||||
isfinite_double4 :: proc "c" (x: double4) -> bool4 { return {isfinite_double(x.x), isfinite_double(x.y), isfinite_double(x.z), isfinite_double(x.w)} }
|
||||
|
||||
// isfinite is the opposite of isinf and returns true if the number is neither positive-infinite or negative-infinite
|
||||
isfinite :: proc{
|
||||
isfinite_float,
|
||||
isfinite_float2,
|
||||
isfinite_float3,
|
||||
isfinite_float4,
|
||||
isfinite_double,
|
||||
isfinite_double2,
|
||||
isfinite_double3,
|
||||
isfinite_double4,
|
||||
}
|
||||
|
||||
|
||||
isinf_float :: proc "c" (x: float) -> bool { return x * 0.5 == x }
|
||||
isinf_float2 :: proc "c" (x: float2) -> bool2 { return {isinf_float(x.x), isinf_float(x.y)} }
|
||||
isinf_float3 :: proc "c" (x: float3) -> bool3 { return {isinf_float(x.x), isinf_float(x.y), isinf_float(x.z)} }
|
||||
isinf_float4 :: proc "c" (x: float4) -> bool4 { return {isinf_float(x.x), isinf_float(x.y), isinf_float(x.z), isinf_float(x.w)} }
|
||||
isinf_double :: proc "c" (x: double) -> bool { return x * 0.5 == x }
|
||||
isinf_double2 :: proc "c" (x: double2) -> bool2 { return {isinf_double(x.x), isinf_double(x.y)} }
|
||||
isinf_double3 :: proc "c" (x: double3) -> bool3 { return {isinf_double(x.x), isinf_double(x.y), isinf_double(x.z)} }
|
||||
isinf_double4 :: proc "c" (x: double4) -> bool4 { return {isinf_double(x.x), isinf_double(x.y), isinf_double(x.z), isinf_double(x.w)} }
|
||||
|
||||
// isinf is the opposite of isfinite and returns true if the number is either positive-infinite or negative-infinite
|
||||
isinf :: proc{
|
||||
isinf_float,
|
||||
isinf_float2,
|
||||
isinf_float3,
|
||||
isinf_float4,
|
||||
isinf_double,
|
||||
isinf_double2,
|
||||
isinf_double3,
|
||||
isinf_double4,
|
||||
}
|
||||
|
||||
|
||||
isnan_float2 :: proc "c" (x: float2) -> bool2 { return {isnan_float(x.x), isnan_float(x.y)} }
|
||||
isnan_float3 :: proc "c" (x: float3) -> bool3 { return {isnan_float(x.x), isnan_float(x.y), isnan_float(x.z)} }
|
||||
isnan_float4 :: proc "c" (x: float4) -> bool4 { return {isnan_float(x.x), isnan_float(x.y), isnan_float(x.z), isnan_float(x.w)} }
|
||||
isnan_double2 :: proc "c" (x: double2) -> bool2 { return {isnan_double(x.x), isnan_double(x.y)} }
|
||||
isnan_double3 :: proc "c" (x: double3) -> bool3 { return {isnan_double(x.x), isnan_double(x.y), isnan_double(x.z)} }
|
||||
isnan_double4 :: proc "c" (x: double4) -> bool4 { return {isnan_double(x.x), isnan_double(x.y), isnan_double(x.z), isnan_double(x.w)} }
|
||||
|
||||
// isnan returns true if the input value is the special case of Not-A-Number
|
||||
isnan :: proc{
|
||||
isnan_float,
|
||||
isnan_float2,
|
||||
isnan_float3,
|
||||
isnan_float4,
|
||||
isnan_double,
|
||||
isnan_double2,
|
||||
isnan_double3,
|
||||
isnan_double4,
|
||||
}
|
||||
|
||||
fmod :: proc{
|
||||
fmod_float,
|
||||
fmod_double,
|
||||
@@ -772,22 +852,22 @@ saturate :: proc{
|
||||
saturate_uint3,
|
||||
saturate_uint4,
|
||||
}
|
||||
saturate_int :: proc "c" (x, y, z: int) -> int { return builtin.clamp(x, 0, 1) }
|
||||
saturate_uint :: proc "c" (x, y, z: uint) -> uint { return builtin.clamp(x, 0, 1) }
|
||||
saturate_float :: proc "c" (x, y, z: float) -> float { return builtin.clamp(x, 0, 1) }
|
||||
saturate_double :: proc "c" (x, y, z: double) -> double { return builtin.clamp(x, 0, 1) }
|
||||
saturate_float2 :: proc "c" (x, y, z: float2) -> float2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} }
|
||||
saturate_float3 :: proc "c" (x, y, z: float3) -> float3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} }
|
||||
saturate_float4 :: proc "c" (x, y, z: float4) -> float4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} }
|
||||
saturate_double2 :: proc "c" (x, y, z: double2) -> double2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} }
|
||||
saturate_double3 :: proc "c" (x, y, z: double3) -> double3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} }
|
||||
saturate_double4 :: proc "c" (x, y, z: double4) -> double4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} }
|
||||
saturate_int2 :: proc "c" (x, y, z: int2) -> int2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} }
|
||||
saturate_int3 :: proc "c" (x, y, z: int3) -> int3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} }
|
||||
saturate_int4 :: proc "c" (x, y, z: int4) -> int4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} }
|
||||
saturate_uint2 :: proc "c" (x, y, z: uint2) -> uint2 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1)} }
|
||||
saturate_uint3 :: proc "c" (x, y, z: uint3) -> uint3 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1)} }
|
||||
saturate_uint4 :: proc "c" (x, y, z: uint4) -> uint4 { return {builtin.clamp(x.x, 0, 1), builtin.clamp(x.y, 0, 1), builtin.clamp(x.z, 0, 1), builtin.clamp(x.w, 0, 1)} }
|
||||
saturate_int :: proc "c" (v: int) -> int { return builtin.clamp(v, 0, 1) }
|
||||
saturate_uint :: proc "c" (v: uint) -> uint { return builtin.clamp(v, 0, 1) }
|
||||
saturate_float :: proc "c" (v: float) -> float { return builtin.clamp(v, 0, 1) }
|
||||
saturate_double :: proc "c" (v: double) -> double { return builtin.clamp(v, 0, 1) }
|
||||
saturate_float2 :: proc "c" (v: float2) -> float2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} }
|
||||
saturate_float3 :: proc "c" (v: float3) -> float3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} }
|
||||
saturate_float4 :: proc "c" (v: float4) -> float4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} }
|
||||
saturate_double2 :: proc "c" (v: double2) -> double2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} }
|
||||
saturate_double3 :: proc "c" (v: double3) -> double3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} }
|
||||
saturate_double4 :: proc "c" (v: double4) -> double4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} }
|
||||
saturate_int2 :: proc "c" (v: int2) -> int2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} }
|
||||
saturate_int3 :: proc "c" (v: int3) -> int3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} }
|
||||
saturate_int4 :: proc "c" (v: int4) -> int4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} }
|
||||
saturate_uint2 :: proc "c" (v: uint2) -> uint2 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1)} }
|
||||
saturate_uint3 :: proc "c" (v: uint3) -> uint3 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1)} }
|
||||
saturate_uint4 :: proc "c" (v: uint4) -> uint4 { return {builtin.clamp(v.x, 0, 1), builtin.clamp(v.y, 0, 1), builtin.clamp(v.z, 0, 1), builtin.clamp(v.w, 0, 1)} }
|
||||
|
||||
|
||||
lerp :: proc{
|
||||
|
||||
@@ -26,7 +26,9 @@ log10_float :: proc "c" (x: float) -> float { return math.log(x, 10) }
|
||||
exp2_float :: proc "c" (x: float) -> float { return math.pow(float(2), x) }
|
||||
sign_float :: proc "c" (x: float) -> float { return math.sign(x) }
|
||||
floor_float :: proc "c" (x: float) -> float { return math.floor(x) }
|
||||
round_float :: proc "c" (x: float) -> float { return math.round(x) }
|
||||
ceil_float :: proc "c" (x: float) -> float { return math.ceil(x) }
|
||||
isnan_float :: proc "c" (x: float) -> bool { return math.classify(x) == .NaN}
|
||||
fmod_float :: proc "c" (x, y: float) -> float { return math.mod(x, y) }
|
||||
frac_float :: proc "c" (x: float) -> float {
|
||||
if x >= 0 {
|
||||
@@ -35,6 +37,7 @@ frac_float :: proc "c" (x: float) -> float {
|
||||
return math.trunc(-x) + x
|
||||
}
|
||||
|
||||
|
||||
cos_double :: proc "c" (x: double) -> double { return math.cos(x) }
|
||||
sin_double :: proc "c" (x: double) -> double { return math.sin(x) }
|
||||
tan_double :: proc "c" (x: double) -> double { return math.tan(x) }
|
||||
@@ -59,7 +62,9 @@ log10_double :: proc "c" (x: double) -> double { return math.log(x, 10)
|
||||
exp2_double :: proc "c" (x: double) -> double { return math.pow(double(2), x) }
|
||||
sign_double :: proc "c" (x: double) -> double { return math.sign(x) }
|
||||
floor_double :: proc "c" (x: double) -> double { return math.floor(x) }
|
||||
round_double :: proc "c" (x: double) -> double { return math.round(x) }
|
||||
ceil_double :: proc "c" (x: double) -> double { return math.ceil(x) }
|
||||
isnan_double :: proc "c" (x: double) -> bool { return math.classify(x) == .NaN}
|
||||
fmod_double :: proc "c" (x, y: double) -> double { return math.mod(x, y) }
|
||||
frac_double :: proc "c" (x: double) -> double {
|
||||
if x >= 0 {
|
||||
|
||||
+520
-543
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,10 @@
|
||||
package linalg
|
||||
|
||||
/*
|
||||
These procedures are to allow for swizzling with non-compile (runtime) known components
|
||||
*/
|
||||
|
||||
|
||||
Scalar_Components :: enum u8 {
|
||||
x = 0,
|
||||
r = 0,
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
package rand
|
||||
|
||||
import "core:math"
|
||||
|
||||
// exp_float64 returns a exponential distribution in the range (0, max(f64)],
|
||||
// with an exponential distribution who rate parameter is 1 (lambda) and whose mean
|
||||
// is 1 (1/lambda).
|
||||
//
|
||||
// To produce a distribution with a differetn rate parameter, divide the result by
|
||||
// the desired rate parameter
|
||||
//
|
||||
// "The Ziggurat Method for Generating Random Variables"
|
||||
// Authors: George Marsaglia, Wai Wan Tsang
|
||||
// Submitted: 2000-04-15. Published: 2000-10-02.
|
||||
// https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf]
|
||||
// https://www.jstatsoft.org/article/view/v005i08 [web page]
|
||||
//
|
||||
exp_float64 :: proc(r: ^Rand = nil) -> f64 {
|
||||
re :: 7.69711747013104972
|
||||
|
||||
@(static)
|
||||
ke := [256]u32{
|
||||
0xe290a139, 0x0, 0x9beadebc, 0xc377ac71, 0xd4ddb990,
|
||||
0xde893fb8, 0xe4a8e87c, 0xe8dff16a, 0xebf2deab, 0xee49a6e8,
|
||||
0xf0204efd, 0xf19bdb8e, 0xf2d458bb, 0xf3da104b, 0xf4b86d78,
|
||||
0xf577ad8a, 0xf61de83d, 0xf6afb784, 0xf730a573, 0xf7a37651,
|
||||
0xf80a5bb6, 0xf867189d, 0xf8bb1b4f, 0xf9079062, 0xf94d70ca,
|
||||
0xf98d8c7d, 0xf9c8928a, 0xf9ff175b, 0xfa319996, 0xfa6085f8,
|
||||
0xfa8c3a62, 0xfab5084e, 0xfadb36c8, 0xfaff0410, 0xfb20a6ea,
|
||||
0xfb404fb4, 0xfb5e2951, 0xfb7a59e9, 0xfb95038c, 0xfbae44ba,
|
||||
0xfbc638d8, 0xfbdcf892, 0xfbf29a30, 0xfc0731df, 0xfc1ad1ed,
|
||||
0xfc2d8b02, 0xfc3f6c4d, 0xfc5083ac, 0xfc60ddd1, 0xfc708662,
|
||||
0xfc7f8810, 0xfc8decb4, 0xfc9bbd62, 0xfca9027c, 0xfcb5c3c3,
|
||||
0xfcc20864, 0xfccdd70a, 0xfcd935e3, 0xfce42ab0, 0xfceebace,
|
||||
0xfcf8eb3b, 0xfd02c0a0, 0xfd0c3f59, 0xfd156b7b, 0xfd1e48d6,
|
||||
0xfd26daff, 0xfd2f2552, 0xfd372af7, 0xfd3eeee5, 0xfd4673e7,
|
||||
0xfd4dbc9e, 0xfd54cb85, 0xfd5ba2f2, 0xfd62451b, 0xfd68b415,
|
||||
0xfd6ef1da, 0xfd750047, 0xfd7ae120, 0xfd809612, 0xfd8620b4,
|
||||
0xfd8b8285, 0xfd90bcf5, 0xfd95d15e, 0xfd9ac10b, 0xfd9f8d36,
|
||||
0xfda43708, 0xfda8bf9e, 0xfdad2806, 0xfdb17141, 0xfdb59c46,
|
||||
0xfdb9a9fd, 0xfdbd9b46, 0xfdc170f6, 0xfdc52bd8, 0xfdc8ccac,
|
||||
0xfdcc542d, 0xfdcfc30b, 0xfdd319ef, 0xfdd6597a, 0xfdd98245,
|
||||
0xfddc94e5, 0xfddf91e6, 0xfde279ce, 0xfde54d1f, 0xfde80c52,
|
||||
0xfdeab7de, 0xfded5034, 0xfdefd5be, 0xfdf248e3, 0xfdf4aa06,
|
||||
0xfdf6f984, 0xfdf937b6, 0xfdfb64f4, 0xfdfd818d, 0xfdff8dd0,
|
||||
0xfe018a08, 0xfe03767a, 0xfe05536c, 0xfe07211c, 0xfe08dfc9,
|
||||
0xfe0a8fab, 0xfe0c30fb, 0xfe0dc3ec, 0xfe0f48b1, 0xfe10bf76,
|
||||
0xfe122869, 0xfe1383b4, 0xfe14d17c, 0xfe1611e7, 0xfe174516,
|
||||
0xfe186b2a, 0xfe19843e, 0xfe1a9070, 0xfe1b8fd6, 0xfe1c8289,
|
||||
0xfe1d689b, 0xfe1e4220, 0xfe1f0f26, 0xfe1fcfbc, 0xfe2083ed,
|
||||
0xfe212bc3, 0xfe21c745, 0xfe225678, 0xfe22d95f, 0xfe234ffb,
|
||||
0xfe23ba4a, 0xfe241849, 0xfe2469f2, 0xfe24af3c, 0xfe24e81e,
|
||||
0xfe25148b, 0xfe253474, 0xfe2547c7, 0xfe254e70, 0xfe25485a,
|
||||
0xfe25356a, 0xfe251586, 0xfe24e88f, 0xfe24ae64, 0xfe2466e1,
|
||||
0xfe2411df, 0xfe23af34, 0xfe233eb4, 0xfe22c02c, 0xfe22336b,
|
||||
0xfe219838, 0xfe20ee58, 0xfe20358c, 0xfe1f6d92, 0xfe1e9621,
|
||||
0xfe1daef0, 0xfe1cb7ac, 0xfe1bb002, 0xfe1a9798, 0xfe196e0d,
|
||||
0xfe1832fd, 0xfe16e5fe, 0xfe15869d, 0xfe141464, 0xfe128ed3,
|
||||
0xfe10f565, 0xfe0f478c, 0xfe0d84b1, 0xfe0bac36, 0xfe09bd73,
|
||||
0xfe07b7b5, 0xfe059a40, 0xfe03644c, 0xfe011504, 0xfdfeab88,
|
||||
0xfdfc26e9, 0xfdf98629, 0xfdf6c83b, 0xfdf3ec01, 0xfdf0f04a,
|
||||
0xfdedd3d1, 0xfdea953d, 0xfde7331e, 0xfde3abe9, 0xfddffdfb,
|
||||
0xfddc2791, 0xfdd826cd, 0xfdd3f9a8, 0xfdcf9dfc, 0xfdcb1176,
|
||||
0xfdc65198, 0xfdc15bb3, 0xfdbc2ce2, 0xfdb6c206, 0xfdb117be,
|
||||
0xfdab2a63, 0xfda4f5fd, 0xfd9e7640, 0xfd97a67a, 0xfd908192,
|
||||
0xfd8901f2, 0xfd812182, 0xfd78d98e, 0xfd7022bb, 0xfd66f4ed,
|
||||
0xfd5d4732, 0xfd530f9c, 0xfd48432b, 0xfd3cd59a, 0xfd30b936,
|
||||
0xfd23dea4, 0xfd16349e, 0xfd07a7a3, 0xfcf8219b, 0xfce7895b,
|
||||
0xfcd5c220, 0xfcc2aadb, 0xfcae1d5e, 0xfc97ed4e, 0xfc7fe6d4,
|
||||
0xfc65ccf3, 0xfc495762, 0xfc2a2fc8, 0xfc07ee19, 0xfbe213c1,
|
||||
0xfbb8051a, 0xfb890078, 0xfb5411a5, 0xfb180005, 0xfad33482,
|
||||
0xfa839276, 0xfa263b32, 0xf9b72d1c, 0xf930a1a2, 0xf889f023,
|
||||
0xf7b577d2, 0xf69c650c, 0xf51530f0, 0xf2cb0e3c, 0xeeefb15d,
|
||||
0xe6da6ecf,
|
||||
}
|
||||
@(static)
|
||||
we := [256]f32{
|
||||
2.0249555e-09, 1.486674e-11, 2.4409617e-11, 3.1968806e-11,
|
||||
3.844677e-11, 4.4228204e-11, 4.9516443e-11, 5.443359e-11,
|
||||
5.905944e-11, 6.344942e-11, 6.7643814e-11, 7.1672945e-11,
|
||||
7.556032e-11, 7.932458e-11, 8.298079e-11, 8.654132e-11,
|
||||
9.0016515e-11, 9.3415074e-11, 9.674443e-11, 1.0001099e-10,
|
||||
1.03220314e-10, 1.06377254e-10, 1.09486115e-10, 1.1255068e-10,
|
||||
1.1557435e-10, 1.1856015e-10, 1.2151083e-10, 1.2442886e-10,
|
||||
1.2731648e-10, 1.3017575e-10, 1.3300853e-10, 1.3581657e-10,
|
||||
1.3860142e-10, 1.4136457e-10, 1.4410738e-10, 1.4683108e-10,
|
||||
1.4953687e-10, 1.5222583e-10, 1.54899e-10, 1.5755733e-10,
|
||||
1.6020171e-10, 1.6283301e-10, 1.6545203e-10, 1.6805951e-10,
|
||||
1.7065617e-10, 1.732427e-10, 1.7581973e-10, 1.7838787e-10,
|
||||
1.8094774e-10, 1.8349985e-10, 1.8604476e-10, 1.8858298e-10,
|
||||
1.9111498e-10, 1.9364126e-10, 1.9616223e-10, 1.9867835e-10,
|
||||
2.0119004e-10, 2.0369768e-10, 2.0620168e-10, 2.087024e-10,
|
||||
2.1120022e-10, 2.136955e-10, 2.1618855e-10, 2.1867974e-10,
|
||||
2.2116936e-10, 2.2365775e-10, 2.261452e-10, 2.2863202e-10,
|
||||
2.311185e-10, 2.3360494e-10, 2.360916e-10, 2.3857874e-10,
|
||||
2.4106667e-10, 2.4355562e-10, 2.4604588e-10, 2.485377e-10,
|
||||
2.5103128e-10, 2.5352695e-10, 2.560249e-10, 2.585254e-10,
|
||||
2.6102867e-10, 2.6353494e-10, 2.6604446e-10, 2.6855745e-10,
|
||||
2.7107416e-10, 2.7359479e-10, 2.761196e-10, 2.7864877e-10,
|
||||
2.8118255e-10, 2.8372119e-10, 2.8626485e-10, 2.888138e-10,
|
||||
2.9136826e-10, 2.939284e-10, 2.9649452e-10, 2.9906677e-10,
|
||||
3.016454e-10, 3.0423064e-10, 3.0682268e-10, 3.0942177e-10,
|
||||
3.1202813e-10, 3.1464195e-10, 3.1726352e-10, 3.19893e-10,
|
||||
3.2253064e-10, 3.251767e-10, 3.2783135e-10, 3.3049485e-10,
|
||||
3.3316744e-10, 3.3584938e-10, 3.3854083e-10, 3.4124212e-10,
|
||||
3.4395342e-10, 3.46675e-10, 3.4940711e-10, 3.5215003e-10,
|
||||
3.5490397e-10, 3.5766917e-10, 3.6044595e-10, 3.6323455e-10,
|
||||
3.660352e-10, 3.6884823e-10, 3.7167386e-10, 3.745124e-10,
|
||||
3.773641e-10, 3.802293e-10, 3.8310827e-10, 3.860013e-10,
|
||||
3.8890866e-10, 3.918307e-10, 3.9476775e-10, 3.9772008e-10,
|
||||
4.0068804e-10, 4.0367196e-10, 4.0667217e-10, 4.09689e-10,
|
||||
4.1272286e-10, 4.1577405e-10, 4.1884296e-10, 4.2192994e-10,
|
||||
4.250354e-10, 4.281597e-10, 4.313033e-10, 4.3446652e-10,
|
||||
4.3764986e-10, 4.408537e-10, 4.4407847e-10, 4.4732465e-10,
|
||||
4.5059267e-10, 4.5388301e-10, 4.571962e-10, 4.6053267e-10,
|
||||
4.6389292e-10, 4.6727755e-10, 4.70687e-10, 4.741219e-10,
|
||||
4.7758275e-10, 4.810702e-10, 4.845848e-10, 4.8812715e-10,
|
||||
4.9169796e-10, 4.9529775e-10, 4.989273e-10, 5.0258725e-10,
|
||||
5.0627835e-10, 5.100013e-10, 5.1375687e-10, 5.1754584e-10,
|
||||
5.21369e-10, 5.2522725e-10, 5.2912136e-10, 5.330522e-10,
|
||||
5.370208e-10, 5.4102806e-10, 5.45075e-10, 5.491625e-10,
|
||||
5.532918e-10, 5.5746385e-10, 5.616799e-10, 5.6594107e-10,
|
||||
5.7024857e-10, 5.746037e-10, 5.7900773e-10, 5.834621e-10,
|
||||
5.8796823e-10, 5.925276e-10, 5.971417e-10, 6.018122e-10,
|
||||
6.065408e-10, 6.113292e-10, 6.1617933e-10, 6.2109295e-10,
|
||||
6.260722e-10, 6.3111916e-10, 6.3623595e-10, 6.4142497e-10,
|
||||
6.4668854e-10, 6.5202926e-10, 6.5744976e-10, 6.6295286e-10,
|
||||
6.6854156e-10, 6.742188e-10, 6.79988e-10, 6.858526e-10,
|
||||
6.9181616e-10, 6.978826e-10, 7.04056e-10, 7.103407e-10,
|
||||
7.167412e-10, 7.2326256e-10, 7.2990985e-10, 7.366886e-10,
|
||||
7.4360473e-10, 7.5066453e-10, 7.5787476e-10, 7.6524265e-10,
|
||||
7.7277595e-10, 7.80483e-10, 7.883728e-10, 7.9645507e-10,
|
||||
8.047402e-10, 8.1323964e-10, 8.219657e-10, 8.309319e-10,
|
||||
8.401528e-10, 8.496445e-10, 8.594247e-10, 8.6951274e-10,
|
||||
8.799301e-10, 8.9070046e-10, 9.018503e-10, 9.134092e-10,
|
||||
9.254101e-10, 9.378904e-10, 9.508923e-10, 9.644638e-10,
|
||||
9.786603e-10, 9.935448e-10, 1.0091913e-09, 1.025686e-09,
|
||||
1.0431306e-09, 1.0616465e-09, 1.08138e-09, 1.1025096e-09,
|
||||
1.1252564e-09, 1.1498986e-09, 1.1767932e-09, 1.206409e-09,
|
||||
1.2393786e-09, 1.276585e-09, 1.3193139e-09, 1.3695435e-09,
|
||||
1.4305498e-09, 1.508365e-09, 1.6160854e-09, 1.7921248e-09,
|
||||
}
|
||||
@(static)
|
||||
fe := [256]f32{
|
||||
1, 0.9381437, 0.90046996, 0.87170434, 0.8477855, 0.8269933,
|
||||
0.8084217, 0.7915276, 0.77595687, 0.7614634, 0.7478686,
|
||||
0.7350381, 0.72286767, 0.71127474, 0.70019263, 0.6895665,
|
||||
0.67935055, 0.6695063, 0.66000086, 0.65080583, 0.6418967,
|
||||
0.63325197, 0.6248527, 0.6166822, 0.60872537, 0.60096896,
|
||||
0.5934009, 0.58601034, 0.5787874, 0.57172304, 0.5648092,
|
||||
0.5580383, 0.5514034, 0.5448982, 0.5385169, 0.53225386,
|
||||
0.5261042, 0.52006316, 0.5141264, 0.50828975, 0.5025495,
|
||||
0.496902, 0.49134386, 0.485872, 0.48048335, 0.4751752,
|
||||
0.46994483, 0.46478975, 0.45970762, 0.45469615, 0.44975325,
|
||||
0.44487688, 0.44006512, 0.43531612, 0.43062815, 0.42599955,
|
||||
0.42142874, 0.4169142, 0.41245446, 0.40804818, 0.403694,
|
||||
0.3993907, 0.39513698, 0.39093173, 0.38677382, 0.38266218,
|
||||
0.37859577, 0.37457356, 0.37059465, 0.3666581, 0.362763,
|
||||
0.35890847, 0.35509375, 0.351318, 0.3475805, 0.34388044,
|
||||
0.34021714, 0.3365899, 0.33299807, 0.32944095, 0.32591796,
|
||||
0.3224285, 0.3189719, 0.31554767, 0.31215525, 0.30879408,
|
||||
0.3054636, 0.3021634, 0.29889292, 0.2956517, 0.29243928,
|
||||
0.28925523, 0.28609908, 0.28297043, 0.27986884, 0.27679393,
|
||||
0.2737453, 0.2707226, 0.2677254, 0.26475343, 0.26180625,
|
||||
0.25888354, 0.25598502, 0.2531103, 0.25025907, 0.24743107,
|
||||
0.24462597, 0.24184346, 0.23908329, 0.23634516, 0.23362878,
|
||||
0.23093392, 0.2282603, 0.22560766, 0.22297576, 0.22036438,
|
||||
0.21777324, 0.21520215, 0.21265087, 0.21011916, 0.20760682,
|
||||
0.20511365, 0.20263945, 0.20018397, 0.19774707, 0.19532852,
|
||||
0.19292815, 0.19054577, 0.1881812, 0.18583426, 0.18350479,
|
||||
0.1811926, 0.17889754, 0.17661946, 0.17435817, 0.17211354,
|
||||
0.1698854, 0.16767362, 0.16547804, 0.16329853, 0.16113494,
|
||||
0.15898713, 0.15685499, 0.15473837, 0.15263714, 0.15055119,
|
||||
0.14848037, 0.14642459, 0.14438373, 0.14235765, 0.14034624,
|
||||
0.13834943, 0.13636707, 0.13439907, 0.13244532, 0.13050574,
|
||||
0.1285802, 0.12666863, 0.12477092, 0.12288698, 0.12101672,
|
||||
0.119160056, 0.1173169, 0.115487166, 0.11367077, 0.11186763,
|
||||
0.11007768, 0.10830083, 0.10653701, 0.10478614, 0.10304816,
|
||||
0.101323, 0.09961058, 0.09791085, 0.09622374, 0.09454919,
|
||||
0.09288713, 0.091237515, 0.08960028, 0.087975375, 0.08636274,
|
||||
0.08476233, 0.083174095, 0.081597984, 0.08003395, 0.07848195,
|
||||
0.076941945, 0.07541389, 0.07389775, 0.072393484, 0.07090106,
|
||||
0.069420435, 0.06795159, 0.066494495, 0.06504912, 0.063615434,
|
||||
0.062193416, 0.060783047, 0.059384305, 0.057997175,
|
||||
0.05662164, 0.05525769, 0.053905312, 0.052564494, 0.051235236,
|
||||
0.049917534, 0.048611384, 0.047316793, 0.046033762, 0.0447623,
|
||||
0.043502413, 0.042254124, 0.041017443, 0.039792392,
|
||||
0.038578995, 0.037377283, 0.036187284, 0.035009038,
|
||||
0.033842582, 0.032687962, 0.031545233, 0.030414443, 0.02929566,
|
||||
0.02818895, 0.027094385, 0.026012046, 0.024942026, 0.023884421,
|
||||
0.022839336, 0.021806888, 0.020787204, 0.019780423, 0.0187867,
|
||||
0.0178062, 0.016839107, 0.015885621, 0.014945968, 0.014020392,
|
||||
0.013109165, 0.012212592, 0.011331013, 0.01046481, 0.009614414,
|
||||
0.008780315, 0.007963077, 0.0071633533, 0.006381906,
|
||||
0.0056196423, 0.0048776558, 0.004157295, 0.0034602648,
|
||||
0.0027887989, 0.0021459677, 0.0015362998, 0.0009672693,
|
||||
0.00045413437,
|
||||
}
|
||||
|
||||
for {
|
||||
j := uint32(r)
|
||||
i := j & 0xFF
|
||||
x := f64(j) * f64(we[i])
|
||||
if j < ke[i] {
|
||||
return x
|
||||
}
|
||||
if i == 0 {
|
||||
return re - math.ln(float64(r))
|
||||
}
|
||||
if fe[i]+f32(float64(r))*(fe[i-1]-fe[i]) < f32(math.exp(-x)) {
|
||||
return x
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,12 @@ package rand
|
||||
|
||||
import "core:math"
|
||||
|
||||
|
||||
// norm_float64 returns a normally distributed f64 in the range -max(f64) through +max(f64) inclusive,
|
||||
// with a standard normal distribution with a mean of 0 and standard deviation of 1.
|
||||
//
|
||||
// sample = norm_float64() * std_dev + mean
|
||||
//
|
||||
//
|
||||
// Normal distribution
|
||||
//
|
||||
@@ -11,12 +17,6 @@ import "core:math"
|
||||
// https://www.jstatsoft.org/index.php/jss/article/view/v005i08/ziggurat.pdf [pdf]
|
||||
// https://www.jstatsoft.org/article/view/v005i08 [web page]
|
||||
//
|
||||
|
||||
// norm_float64 returns a normally distributed f64 in the range -max(f64) through +max(f64) inclusive,
|
||||
// with a standard normal distribution with a mean of 0 and standard deviation of 1.
|
||||
//
|
||||
// sample = norm_float64() * std_dev + mean
|
||||
//
|
||||
norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
||||
rn :: 3.442619855899
|
||||
|
||||
@@ -49,7 +49,6 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
||||
0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a,
|
||||
0x7ba90bdc, 0x7a722176, 0x77d664e5,
|
||||
}
|
||||
|
||||
@(static)
|
||||
wn := [128]f32{
|
||||
1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10,
|
||||
@@ -85,7 +84,6 @@ norm_float64 :: proc(r: ^Rand = nil) -> f64 {
|
||||
1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09,
|
||||
1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09,
|
||||
}
|
||||
|
||||
@(static)
|
||||
fn := [128]f32{
|
||||
1.00000000, 0.9635997, 0.9362827, 0.9130436, 0.89228165,
|
||||
|
||||
@@ -70,7 +70,7 @@ int31_max :: proc(n: i32, r: ^Rand = nil) -> i32 {
|
||||
if n&(n-1) == 0 {
|
||||
return int31(r) & (n-1)
|
||||
}
|
||||
max := i32((1<<31) - 1 - (1<<31)&u32(n))
|
||||
max := i32((1<<31) - 1 - (1<<31)%u32(n))
|
||||
v := int31(r)
|
||||
for v > max {
|
||||
v = int31(r)
|
||||
@@ -85,7 +85,7 @@ int63_max :: proc(n: i64, r: ^Rand = nil) -> i64 {
|
||||
if n&(n-1) == 0 {
|
||||
return int63(r) & (n-1)
|
||||
}
|
||||
max := i64((1<<63) - 1 - (1<<63)&u64(n))
|
||||
max := i64((1<<63) - 1 - (1<<63)%u64(n))
|
||||
v := int63(r)
|
||||
for v > max {
|
||||
v = int63(r)
|
||||
@@ -100,7 +100,7 @@ int127_max :: proc(n: i128, r: ^Rand = nil) -> i128 {
|
||||
if n&(n-1) == 0 {
|
||||
return int127(r) & (n-1)
|
||||
}
|
||||
max := i128((1<<63) - 1 - (1<<63)&u128(n))
|
||||
max := i128((1<<127) - 1 - (1<<127)%u128(n))
|
||||
v := int127(r)
|
||||
for v > max {
|
||||
v = int127(r)
|
||||
@@ -142,8 +142,8 @@ read :: proc(p: []byte, r: ^Rand = nil) -> (n: int) {
|
||||
}
|
||||
|
||||
// perm returns a slice of n ints in a pseudo-random permutation of integers in the range [0, n)
|
||||
perm :: proc(n: int, r: ^Rand = nil) -> []int {
|
||||
m := make([]int, n)
|
||||
perm :: proc(n: int, r: ^Rand = nil, allocator := context.allocator) -> []int {
|
||||
m := make([]int, n, allocator)
|
||||
for i := 0; i < n; i += 1 {
|
||||
j := int_max(i+1, r)
|
||||
m[i] = m[j]
|
||||
|
||||
@@ -11,7 +11,7 @@ String :: distinct Array(byte)
|
||||
|
||||
Version_Type_Major :: 0
|
||||
Version_Type_Minor :: 2
|
||||
Version_Type_Patch :: 1
|
||||
Version_Type_Patch :: 4
|
||||
|
||||
Version_Type :: struct {
|
||||
major, minor, patch: u8,
|
||||
@@ -77,9 +77,15 @@ Pkg :: struct {
|
||||
flags: Pkg_Flags,
|
||||
docs: String,
|
||||
files: Array(File_Index),
|
||||
entities: Array(Entity_Index),
|
||||
entries: Array(Scope_Entry),
|
||||
}
|
||||
|
||||
Scope_Entry :: struct {
|
||||
name: String,
|
||||
entity: Entity_Index,
|
||||
}
|
||||
|
||||
|
||||
Entity_Kind :: enum u32le {
|
||||
Invalid = 0,
|
||||
Constant = 1,
|
||||
@@ -89,6 +95,7 @@ Entity_Kind :: enum u32le {
|
||||
Proc_Group = 5,
|
||||
Import_Name = 6,
|
||||
Library_Name = 7,
|
||||
Builtin = 8,
|
||||
}
|
||||
|
||||
Entity_Flag :: enum u32le {
|
||||
@@ -105,8 +112,13 @@ Entity_Flag :: enum u32le {
|
||||
|
||||
Type_Alias = 20,
|
||||
|
||||
Builtin_Pkg_Builtin = 30,
|
||||
Builtin_Pkg_Intrinsics = 31,
|
||||
|
||||
Var_Thread_Local = 40,
|
||||
Var_Static = 41,
|
||||
|
||||
Private = 50,
|
||||
}
|
||||
|
||||
Entity_Flags :: distinct bit_set[Entity_Flag; u64le]
|
||||
@@ -122,6 +134,10 @@ Entity :: struct {
|
||||
_: u32le, // reserved for init
|
||||
comment: String,
|
||||
docs: String,
|
||||
// May be used by (Struct fields and procedure fields):
|
||||
// .Variable
|
||||
// .Constant
|
||||
field_group_index: i32le,
|
||||
|
||||
// May used by:
|
||||
// .Variable
|
||||
@@ -242,6 +258,8 @@ Type :: struct {
|
||||
polymorphic_params: Type_Index,
|
||||
// Used By: .Struct, .Union
|
||||
where_clauses: Array(String),
|
||||
// Used By: .Struct
|
||||
tags: Array(String),
|
||||
}
|
||||
|
||||
Type_Flags_Basic :: distinct bit_set[Type_Flag_Basic; u32le]
|
||||
|
||||
+24
-1
@@ -296,6 +296,8 @@ foreign libc {
|
||||
@(link_name="readdir_r$INODE64") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
||||
@(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, buf: ^byte) -> c.int ---
|
||||
|
||||
@(link_name="fchmod") _unix_fchmod :: proc(fildes: Handle, mode: u16) -> c.int ---
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
@@ -305,6 +307,8 @@ foreign libc {
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
|
||||
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
}
|
||||
|
||||
@@ -319,16 +323,35 @@ get_last_error :: proc() -> int {
|
||||
return __error()^
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||
get_last_error_string :: proc() -> string {
|
||||
return cast(string)_darwin_string_error(cast(c.int)get_last_error())
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
|
||||
cstr := strings.clone_to_cstring(path)
|
||||
handle := _unix_open(cstr, i32(flags), u16(mode))
|
||||
delete(cstr)
|
||||
if handle == -1 {
|
||||
return INVALID_HANDLE, 1
|
||||
}
|
||||
|
||||
when ODIN_OS == "darwin" && ODIN_ARCH == "arm64" {
|
||||
if mode != 0 {
|
||||
err := fchmod(handle, cast(u16)mode)
|
||||
if err != 0 {
|
||||
_unix_close(handle)
|
||||
return INVALID_HANDLE, 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handle, 0
|
||||
}
|
||||
|
||||
fchmod :: proc(fildes: Handle, mode: u16) -> Errno {
|
||||
return cast(Errno)_unix_fchmod(fildes, mode)
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) {
|
||||
_unix_close(fd)
|
||||
}
|
||||
|
||||
+233
-48
@@ -266,33 +266,142 @@ X_OK :: 1 // Test for execute permission
|
||||
W_OK :: 2 // Test for write permission
|
||||
R_OK :: 4 // Test for read permission
|
||||
|
||||
AT_FDCWD :: -100
|
||||
AT_REMOVEDIR :: uintptr(0x200)
|
||||
AT_SYMLINK_NOFOLLOW :: uintptr(0x100)
|
||||
|
||||
_unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode)))
|
||||
} else { // NOTE: arm64 does not have open
|
||||
res := int(intrinsics.syscall(unix.SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode))))
|
||||
}
|
||||
return -1 if res < 0 else Handle(res)
|
||||
}
|
||||
|
||||
_unix_close :: proc(fd: Handle) -> int {
|
||||
return int(intrinsics.syscall(unix.SYS_close, uintptr(fd)))
|
||||
}
|
||||
|
||||
_unix_read :: proc(fd: Handle, buf: rawptr, size: uint) -> int {
|
||||
return int(intrinsics.syscall(unix.SYS_read, uintptr(fd), uintptr(buf), uintptr(size)))
|
||||
}
|
||||
|
||||
_unix_write :: proc(fd: Handle, buf: rawptr, size: uint) -> int {
|
||||
return int(intrinsics.syscall(unix.SYS_write, uintptr(fd), uintptr(buf), uintptr(size)))
|
||||
}
|
||||
|
||||
_unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
|
||||
when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" {
|
||||
return i64(intrinsics.syscall(unix.SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence)))
|
||||
} else {
|
||||
low := uintptr(offset & 0xFFFFFFFF)
|
||||
high := uintptr(offset >> 32)
|
||||
result: i64
|
||||
res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence)))
|
||||
return -1 if res < 0 else result
|
||||
}
|
||||
}
|
||||
|
||||
_unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||
when ODIN_ARCH == "amd64" {
|
||||
return int(intrinsics.syscall(unix.SYS_stat, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else when ODIN_ARCH != "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else { // NOTE: arm64 does not have stat
|
||||
return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0))
|
||||
}
|
||||
}
|
||||
|
||||
_unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int {
|
||||
when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_fstat, uintptr(fd), uintptr(stat)))
|
||||
} else {
|
||||
return int(intrinsics.syscall(unix.SYS_fstat64, uintptr(fd), uintptr(stat)))
|
||||
}
|
||||
}
|
||||
|
||||
_unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||
when ODIN_ARCH == "amd64" {
|
||||
return int(intrinsics.syscall(unix.SYS_lstat, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else when ODIN_ARCH != "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else { // NOTE: arm64 does not have any lstat
|
||||
return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW))
|
||||
}
|
||||
}
|
||||
|
||||
_unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||
} else { // NOTE: arm64 does not have readlink
|
||||
return int(intrinsics.syscall(unix.SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||
}
|
||||
}
|
||||
|
||||
_unix_access :: proc(path: cstring, mask: int) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask)))
|
||||
} else { // NOTE: arm64 does not have access
|
||||
return int(intrinsics.syscall(unix.SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask)))
|
||||
}
|
||||
}
|
||||
|
||||
_unix_getcwd :: proc(buf: rawptr, size: uint) -> int {
|
||||
return int(intrinsics.syscall(unix.SYS_getcwd, uintptr(buf), uintptr(size)))
|
||||
}
|
||||
|
||||
_unix_chdir :: proc(path: cstring) -> int {
|
||||
return int(intrinsics.syscall(unix.SYS_chdir, uintptr(rawptr(path))))
|
||||
}
|
||||
|
||||
_unix_rename :: proc(old, new: cstring) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||
} else { // NOTE: arm64 does not have rename
|
||||
return int(intrinsics.syscall(unix.SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||
}
|
||||
}
|
||||
|
||||
_unix_unlink :: proc(path: cstring) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path))))
|
||||
} else { // NOTE: arm64 does not have unlink
|
||||
return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0)))
|
||||
}
|
||||
}
|
||||
|
||||
_unix_rmdir :: proc(path: cstring) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path))))
|
||||
} else { // NOTE: arm64 does not have rmdir
|
||||
return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR))
|
||||
}
|
||||
}
|
||||
|
||||
_unix_mkdir :: proc(path: cstring, mode: u32) -> int {
|
||||
when ODIN_ARCH != "arm64" {
|
||||
return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode)))
|
||||
} else { // NOTE: arm64 does not have mkdir
|
||||
return int(intrinsics.syscall(unix.SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode)))
|
||||
}
|
||||
}
|
||||
|
||||
foreign libc {
|
||||
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---
|
||||
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
|
||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
|
||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---
|
||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---
|
||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||
@(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
|
||||
@(link_name="lstat") _unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
|
||||
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---
|
||||
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||
@(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
||||
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
@@ -308,51 +417,57 @@ is_path_separator :: proc(r: rune) -> bool {
|
||||
return r == '/'
|
||||
}
|
||||
|
||||
// determine errno from syscall return value
|
||||
@private
|
||||
_get_errno :: proc(res: int) -> Errno {
|
||||
if res < 0 && res > -4096 {
|
||||
return Errno(-res)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// get errno from libc
|
||||
get_last_error :: proc() -> int {
|
||||
return __errno_location()^
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
|
||||
cstr := strings.clone_to_cstring(path)
|
||||
handle := _unix_open(cstr, c.int(flags), c.int(mode))
|
||||
delete(cstr)
|
||||
if handle == -1 {
|
||||
return INVALID_HANDLE, Errno(get_last_error())
|
||||
handle := _unix_open(cstr, flags, mode)
|
||||
defer delete(cstr)
|
||||
if handle < 0 {
|
||||
return INVALID_HANDLE, _get_errno(int(handle))
|
||||
}
|
||||
return handle, ERROR_NONE
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) -> Errno {
|
||||
result := _unix_close(fd)
|
||||
if result == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
return _get_errno(_unix_close(fd))
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
|
||||
if bytes_read == -1 {
|
||||
return -1, Errno(get_last_error())
|
||||
if bytes_read < 0 {
|
||||
return -1, _get_errno(bytes_read)
|
||||
}
|
||||
return int(bytes_read), ERROR_NONE
|
||||
return bytes_read, ERROR_NONE
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if len(data) == 0 {
|
||||
return 0, ERROR_NONE
|
||||
}
|
||||
bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
|
||||
if bytes_written == -1 {
|
||||
return -1, Errno(get_last_error())
|
||||
bytes_written := _unix_write(fd, &data[0], uint(len(data)))
|
||||
if bytes_written < 0 {
|
||||
return -1, _get_errno(bytes_written)
|
||||
}
|
||||
return int(bytes_written), ERROR_NONE
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
res := _unix_seek(fd, offset, c.int(whence))
|
||||
if res == -1 {
|
||||
return -1, Errno(get_last_error())
|
||||
res := _unix_seek(fd, offset, whence)
|
||||
if res < 0 {
|
||||
return -1, _get_errno(int(res))
|
||||
}
|
||||
return res, ERROR_NONE
|
||||
}
|
||||
@@ -365,6 +480,75 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
return max(s.size, 0), ERROR_NONE
|
||||
}
|
||||
|
||||
rename :: proc(old_path, new_path: string) -> Errno {
|
||||
old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
|
||||
new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||
return _get_errno(_unix_rename(old_path_cstr, new_path_cstr))
|
||||
}
|
||||
|
||||
remove :: proc(path: string) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
return _get_errno(_unix_unlink(path_cstr))
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
return _get_errno(_unix_mkdir(path_cstr, mode))
|
||||
}
|
||||
|
||||
remove_directory :: proc(path: string) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
return _get_errno(_unix_rmdir(path_cstr))
|
||||
}
|
||||
|
||||
is_file_handle :: proc(fd: Handle) -> bool {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
s: OS_Stat
|
||||
err: Errno
|
||||
if follow_links {
|
||||
s, err = _stat(path)
|
||||
} else {
|
||||
s, err = _lstat(path)
|
||||
}
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
|
||||
is_dir_handle :: proc(fd: Handle) -> bool {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
s: OS_Stat
|
||||
err: Errno
|
||||
if follow_links {
|
||||
s, err = _stat(path)
|
||||
} else {
|
||||
s, err = _lstat(path)
|
||||
}
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
is_file :: proc {is_file_path, is_file_handle}
|
||||
is_dir :: proc {is_dir_path, is_dir_handle}
|
||||
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
|
||||
@@ -401,8 +585,8 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
|
||||
s: OS_Stat
|
||||
result := _unix_stat(cstr, &s)
|
||||
if result == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
if result < 0 {
|
||||
return s, _get_errno(result)
|
||||
}
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
@@ -414,8 +598,8 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
|
||||
s: OS_Stat
|
||||
result := _unix_lstat(cstr, &s)
|
||||
if result == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
if result < 0 {
|
||||
return s, _get_errno(result)
|
||||
}
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
@@ -424,8 +608,8 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||
s: OS_Stat
|
||||
result := _unix_fstat(fd, &s)
|
||||
if result == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
if result < 0 {
|
||||
return s, _get_errno(result)
|
||||
}
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
@@ -482,9 +666,9 @@ _readlink :: proc(path: string) -> (string, Errno) {
|
||||
buf := make([]byte, bufsz)
|
||||
for {
|
||||
rc := _unix_readlink(path_cstr, &(buf[0]), bufsz)
|
||||
if rc == -1 {
|
||||
if rc < 0 {
|
||||
delete(buf)
|
||||
return "", Errno(get_last_error())
|
||||
return "", _get_errno(rc)
|
||||
} else if rc == int(bufsz) {
|
||||
// NOTE(laleksic, 2021-01-21): Any cleaner way to resize the slice?
|
||||
bufsz *= 2
|
||||
@@ -530,9 +714,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
||||
cstr := strings.clone_to_cstring(path)
|
||||
defer delete(cstr)
|
||||
result := _unix_access(cstr, c.int(mask))
|
||||
if result == -1 {
|
||||
return false, Errno(get_last_error())
|
||||
result := _unix_access(cstr, mask)
|
||||
if result < 0 {
|
||||
return false, _get_errno(result)
|
||||
}
|
||||
return true, ERROR_NONE
|
||||
}
|
||||
@@ -567,11 +751,12 @@ get_current_directory :: proc() -> string {
|
||||
page_size := get_page_size()
|
||||
buf := make([dynamic]u8, page_size)
|
||||
for {
|
||||
#no_bounds_check cwd := _unix_getcwd(cstring(&buf[0]), c.size_t(len(buf)))
|
||||
if cwd != nil {
|
||||
return string(cwd)
|
||||
#no_bounds_check res := _unix_getcwd(&buf[0], uint(len(buf)))
|
||||
|
||||
if res >= 0 {
|
||||
return strings.string_from_nul_terminated_ptr(&buf[0], len(buf))
|
||||
}
|
||||
if Errno(get_last_error()) != ERANGE {
|
||||
if _get_errno(res) != ERANGE {
|
||||
return ""
|
||||
}
|
||||
resize(&buf, len(buf)+page_size)
|
||||
@@ -582,8 +767,8 @@ get_current_directory :: proc() -> string {
|
||||
set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_chdir(cstr)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
if res < 0 {
|
||||
return _get_errno(res)
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package path
|
||||
|
||||
#panic(
|
||||
`core:path/slashpath - for paths separated by forward slashes, e.g. paths in URLs, this does not deal with OS-specific paths
|
||||
core:path/filepath - uses either forward slashes or backslashes depending on the operating system, deals with Windows/NT paths with volume letters or backslashes (on the related platforms)`)
|
||||
@@ -1,4 +1,4 @@
|
||||
package path
|
||||
package slashpath
|
||||
|
||||
import "core:strings"
|
||||
import "core:unicode/utf8"
|
||||
@@ -1,9 +1,9 @@
|
||||
// The path package is only to be used for paths separated by forward slashes,
|
||||
// The slashpath package is only to be used for paths separated by forward slashes,
|
||||
// e.g. paths in URLs
|
||||
//
|
||||
// This package does not deal with Windows/NT paths with volume letters or backslashes
|
||||
// To manipulate operating system specific paths, use the path/filepath package
|
||||
package path
|
||||
package slashpath
|
||||
|
||||
import "core:strings"
|
||||
|
||||
@@ -386,6 +386,29 @@ Raw_Cstring :: struct {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Build_Mode_Type :: enum int {
|
||||
Executable,
|
||||
Dynamic,
|
||||
Object,
|
||||
Assembly,
|
||||
LLVM_IR,
|
||||
}
|
||||
*/
|
||||
Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE)
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Endian_Type :: enum int {
|
||||
Unknown,
|
||||
Little,
|
||||
Big,
|
||||
}
|
||||
*/
|
||||
Odin_Endian_Type :: type_of(ODIN_ENDIAN)
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
// Init Startup Procedures //
|
||||
/////////////////////////////
|
||||
|
||||
@@ -614,6 +614,10 @@ raw_data :: proc{raw_array_data, raw_slice_data, raw_dynamic_array_data, raw_str
|
||||
@(disabled=ODIN_DISABLE_ASSERT)
|
||||
assert :: proc(condition: bool, message := "", loc := #caller_location) {
|
||||
if !condition {
|
||||
// NOTE(bill): This is wrapped in a procedure call
|
||||
// to improve performance to make the CPU not
|
||||
// execute speculatively, making it about an order of
|
||||
// magnitude faster
|
||||
proc(message: string, loc: Source_Code_Location) {
|
||||
p := context.assertion_failure_proc
|
||||
if p == nil {
|
||||
|
||||
@@ -146,14 +146,14 @@ matrix2x2_inverse_transpose :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y:
|
||||
d := x[0, 0]*x[1, 1] - x[0, 1]*x[1, 0]
|
||||
when intrinsics.type_is_integer(T) {
|
||||
y[0, 0] = +x[1, 1] / d
|
||||
y[1, 0] = -x[1, 0] / d
|
||||
y[0, 1] = -x[0, 1] / d
|
||||
y[1, 0] = -x[0, 1] / d
|
||||
y[0, 1] = -x[1, 0] / d
|
||||
y[1, 1] = +x[0, 0] / d
|
||||
} else {
|
||||
id := 1 / d
|
||||
y[0, 0] = +x[1, 1] * id
|
||||
y[1, 0] = -x[1, 0] * id
|
||||
y[0, 1] = -x[0, 1] * id
|
||||
y[1, 0] = -x[0, 1] * id
|
||||
y[0, 1] = -x[1, 0] * id
|
||||
y[1, 1] = +x[0, 0] * id
|
||||
}
|
||||
return
|
||||
@@ -214,16 +214,16 @@ matrix1x1_inverse :: proc "contextless" (x: $M/matrix[1, 1]$T) -> (y: M) {
|
||||
matrix2x2_inverse :: proc "contextless" (x: $M/matrix[2, 2]$T) -> (y: M) {
|
||||
d := x[0, 0]*x[1, 1] - x[0, 1]*x[1, 0]
|
||||
when intrinsics.type_is_integer(T) {
|
||||
y[0, 0] = x[1, 1] / d
|
||||
y[0, 1] = x[1, 0] / d
|
||||
y[1, 0] = x[0, 1] / d
|
||||
y[1, 1] = x[0, 0] / d
|
||||
y[0, 0] = +x[1, 1] / d
|
||||
y[0, 1] = -x[0, 1] / d
|
||||
y[1, 0] = -x[1, 0] / d
|
||||
y[1, 1] = +x[0, 0] / d
|
||||
} else {
|
||||
id := 1 / d
|
||||
y[0, 0] = x[1, 1] * id
|
||||
y[0, 1] = x[1, 0] * id
|
||||
y[1, 0] = x[0, 1] * id
|
||||
y[1, 1] = x[0, 0] * id
|
||||
y[0, 0] = +x[1, 1] * id
|
||||
y[0, 1] = -x[0, 1] * id
|
||||
y[1, 0] = -x[1, 0] * id
|
||||
y[1, 1] = +x[0, 0] * id
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
//+private
|
||||
//+build linux, darwin, freebsd
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
when ODIN_BUILD_MODE == .Dynamic {
|
||||
@(link_name="_odin_entry_point", linkage="strong", require/*, link_section=".init"*/)
|
||||
_odin_entry_point :: proc "c" () {
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
}
|
||||
@(link_name="_odin_exit_point", linkage="strong", require/*, link_section=".fini"*/)
|
||||
_odin_exit_point :: proc "c" () {
|
||||
context = default_context()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
}
|
||||
@(link_name="main", linkage="strong", require)
|
||||
main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
|
||||
return 0
|
||||
}
|
||||
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||
@(link_name="main", linkage="strong", require)
|
||||
main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
|
||||
args__ = argv[:argc]
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//+private
|
||||
//+build wasm32, wasm64
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||
@(link_name="_start", linkage="strong", require, export)
|
||||
_start :: proc "c" () {
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
}
|
||||
@(link_name="_end", linkage="strong", require, export)
|
||||
_end :: proc "c" () {
|
||||
context = default_context()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//+private
|
||||
//+build windows
|
||||
package runtime
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
when ODIN_BUILD_MODE == .Dynamic {
|
||||
@(link_name="DllMain", linkage="strong", require)
|
||||
DllMain :: proc "stdcall" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 {
|
||||
context = default_context()
|
||||
switch fdwReason {
|
||||
case 1: // DLL_PROCESS_ATTACH
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
case 0: // DLL_PROCESS_DETACH
|
||||
#force_no_inline _cleanup_runtime()
|
||||
case 2: // DLL_THREAD_ATTACH
|
||||
break
|
||||
case 3: // DLL_THREAD_DETACH
|
||||
break
|
||||
}
|
||||
return true
|
||||
}
|
||||
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||
when ODIN_ARCH == "i386" || ODIN_NO_CRT {
|
||||
@(link_name="mainCRTStartup", linkage="strong", require)
|
||||
mainCRTStartup :: proc "stdcall" () -> i32 {
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
return 0
|
||||
}
|
||||
} else {
|
||||
@(link_name="main", linkage="strong", require)
|
||||
main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
|
||||
args__ = argv[:argc]
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ IS_WASM :: ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64"
|
||||
@(private)
|
||||
RUNTIME_LINKAGE :: "strong" when (
|
||||
(ODIN_USE_SEPARATE_MODULES ||
|
||||
ODIN_BUILD_MODE == "dynamic" ||
|
||||
ODIN_BUILD_MODE == .Dynamic ||
|
||||
!ODIN_NO_CRT) &&
|
||||
!IS_WASM) else "internal"
|
||||
RUNTIME_REQUIRE :: true
|
||||
|
||||
+15
-5
@@ -143,11 +143,21 @@ print_int :: proc "contextless" (x: int) { print_i64(i64(x)) }
|
||||
|
||||
print_caller_location :: proc "contextless" (using loc: Source_Code_Location) {
|
||||
print_string(file_path)
|
||||
print_byte('(')
|
||||
print_u64(u64(line))
|
||||
print_byte(':')
|
||||
print_u64(u64(column))
|
||||
print_byte(')')
|
||||
when ODIN_ERROR_POS_STYLE == .Default {
|
||||
print_byte('(')
|
||||
print_u64(u64(line))
|
||||
print_byte(':')
|
||||
print_u64(u64(column))
|
||||
print_byte(')')
|
||||
} else when ODIN_ERROR_POS_STYLE == .Unix {
|
||||
print_byte(':')
|
||||
print_u64(u64(line))
|
||||
print_byte(':')
|
||||
print_u64(u64(column))
|
||||
print_byte(':')
|
||||
} else {
|
||||
#panic("unhandled ODIN_ERROR_POS_STYLE")
|
||||
}
|
||||
}
|
||||
print_typeid :: proc "contextless" (id: typeid) {
|
||||
if id == nil {
|
||||
|
||||
@@ -22,4 +22,4 @@ windows_trap_type_assertion :: proc "contextless" () -> ! {
|
||||
when ODIN_NO_CRT {
|
||||
@(require)
|
||||
foreign import crt_lib "procs_windows_amd64.asm"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
|
||||
q, r: [2]u64
|
||||
sr: u32 = 0
|
||||
|
||||
low :: 1 when ODIN_ENDIAN == "big" else 0
|
||||
low :: 1 when ODIN_ENDIAN == .Big else 0
|
||||
high :: 1 - low
|
||||
U64_BITS :: 8*size_of(u64)
|
||||
U128_BITS :: 8*size_of(u128)
|
||||
|
||||
@@ -304,6 +304,23 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -
|
||||
return r[:]
|
||||
}
|
||||
|
||||
scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U)->V, allocator := context.allocator) -> []V {
|
||||
if len(s) == 0 { return {} }
|
||||
|
||||
res := make([]V, len(s), allocator)
|
||||
p := as_ptr(s)
|
||||
q := as_ptr(res)
|
||||
r := initializer
|
||||
|
||||
for l := len(s); l > 0; l -= 1 {
|
||||
r = f(r, p[0])
|
||||
q[0] = r
|
||||
p = p[1:]
|
||||
q = q[1:]
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
|
||||
|
||||
+31
-488
@@ -1,10 +1,5 @@
|
||||
package slice
|
||||
|
||||
import "core:intrinsics"
|
||||
_ :: intrinsics
|
||||
|
||||
ORD :: intrinsics.type_is_ordered
|
||||
|
||||
Ordering :: enum {
|
||||
Less = -1,
|
||||
Equal = 0,
|
||||
@@ -38,7 +33,7 @@ cmp_proc :: proc($E: typeid) -> (proc(E, E) -> Ordering) where ORD(E) {
|
||||
sort :: proc(data: $T/[]$E) where ORD(E) {
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
_quick_sort(data, 0, n, _max_depth(n))
|
||||
_quick_sort_general(data, 0, n, _max_depth(n), struct{}{}, .Ordered)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +43,7 @@ sort :: proc(data: $T/[]$E) where ORD(E) {
|
||||
sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
_quick_sort_less(data, 0, n, _max_depth(n), less)
|
||||
_quick_sort_general(data, 0, n, _max_depth(n), less, .Less)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +51,33 @@ sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
|
||||
sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
_quick_sort_cmp(data, 0, n, _max_depth(n), cmp)
|
||||
_quick_sort_general(data, 0, n, _max_depth(n), cmp, .Cmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stable_sort sorts a slice
|
||||
stable_sort :: proc(data: $T/[]$E) where ORD(E) {
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
_stable_sort_general(data, struct{}{}, .Ordered)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stable_sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j"
|
||||
stable_sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
_stable_sort_general(data, less, .Less)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stable_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
|
||||
when size_of(E) != 0 {
|
||||
if n := len(data); n > 1 {
|
||||
_stable_sort_general(data, cmp, .Cmp)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,6 +100,7 @@ is_sorted_by :: proc(array: $T/[]$E, less: proc(i, j: E) -> bool) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
is_sorted_by_cmp :: is_sorted_cmp
|
||||
is_sorted_cmp :: proc(array: $T/[]$E, cmp: proc(i, j: E) -> Ordering) -> bool {
|
||||
for i := len(array)-1; i > 0; i -= 1 {
|
||||
if cmp(array[i], array[i-1]) == .Equal {
|
||||
@@ -140,489 +162,10 @@ is_sorted_by_key :: proc(array: $T/[]$E, key: proc(E) -> $K) -> bool where ORD(K
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_max_depth :: proc(n: int) -> int { // 2*ceil(log2(n+1))
|
||||
depth: int
|
||||
_max_depth :: proc(n: int) -> (depth: int) { // 2*ceil(log2(n+1))
|
||||
for i := n; i > 0; i >>= 1 {
|
||||
depth += 1
|
||||
}
|
||||
return depth * 2
|
||||
}
|
||||
|
||||
@(private)
|
||||
_quick_sort :: proc(data: $T/[]$E, a, b, max_depth: int) where ORD(E) #no_bounds_check {
|
||||
median3 :: proc(data: T, m1, m0, m2: int) #no_bounds_check {
|
||||
if data[m1] < data[m0] {
|
||||
swap(data, m1, m0)
|
||||
}
|
||||
if data[m2] < data[m1] {
|
||||
swap(data, m2, m1)
|
||||
if data[m1] < data[m0] {
|
||||
swap(data, m1, m0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_pivot :: proc(data: T, lo, hi: int) -> (midlo, midhi: int) #no_bounds_check {
|
||||
m := int(uint(lo+hi)>>1)
|
||||
if hi-lo > 40 {
|
||||
s := (hi-lo)/8
|
||||
median3(data, lo, lo+s, lo+s*2)
|
||||
median3(data, m, m-s, m+s)
|
||||
median3(data, hi-1, hi-1-s, hi-1-s*2)
|
||||
}
|
||||
median3(data, lo, m, hi-1)
|
||||
|
||||
|
||||
pivot := lo
|
||||
a, c := lo+1, hi-1
|
||||
|
||||
for ; a < c && data[a] < data[pivot]; a += 1 {
|
||||
}
|
||||
b := a
|
||||
|
||||
for {
|
||||
for ; b < c && !(data[pivot] < data[b]); b += 1 { // data[b] <= pivot
|
||||
}
|
||||
for ; b < c && data[pivot] < data[c-1]; c -=1 { // data[c-1] > pivot
|
||||
}
|
||||
if b >= c {
|
||||
break
|
||||
}
|
||||
|
||||
swap(data, b, c-1)
|
||||
b += 1
|
||||
c -= 1
|
||||
}
|
||||
|
||||
protect := hi-c < 5
|
||||
if !protect && hi-c < (hi-lo)/4 {
|
||||
dups := 0
|
||||
if !(data[pivot] < data[hi-1]) {
|
||||
swap(data, c, hi-1)
|
||||
c += 1
|
||||
dups += 1
|
||||
}
|
||||
if !(data[b-1] < data[pivot]) {
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
|
||||
if !(data[m] < data[pivot]) {
|
||||
swap(data, m, b-1)
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
protect = dups > 1
|
||||
}
|
||||
if protect {
|
||||
for {
|
||||
for ; a < b && !(data[b-1] < data[pivot]); b -= 1 {
|
||||
}
|
||||
for ; a < b && data[a] < data[pivot]; a += 1 {
|
||||
}
|
||||
if a >= b {
|
||||
break
|
||||
}
|
||||
swap(data, a, b-1)
|
||||
a += 1
|
||||
b -= 1
|
||||
}
|
||||
}
|
||||
swap(data, pivot, b-1)
|
||||
return b-1, c
|
||||
}
|
||||
|
||||
|
||||
a, b, max_depth := a, b, max_depth
|
||||
|
||||
if b-a > 12 { // only use shell sort for lengths <= 12
|
||||
if max_depth == 0 {
|
||||
_heap_sort(data, a, b)
|
||||
return
|
||||
}
|
||||
max_depth -= 1
|
||||
mlo, mhi := do_pivot(data, a, b)
|
||||
if mlo-a < b-mhi {
|
||||
_quick_sort(data, a, mlo, max_depth)
|
||||
a = mhi
|
||||
} else {
|
||||
_quick_sort(data, mhi, b, max_depth)
|
||||
b = mlo
|
||||
}
|
||||
}
|
||||
if b-a > 1 {
|
||||
// Shell short with gap 6
|
||||
for i in a+6..<b {
|
||||
if data[i] < data[i-6] {
|
||||
swap(data, i, i-6)
|
||||
}
|
||||
}
|
||||
_insertion_sort(data, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_insertion_sort :: proc(data: $T/[]$E, a, b: int) where ORD(E) #no_bounds_check {
|
||||
for i in a+1..<b {
|
||||
for j := i; j > a && data[j] < data[j-1]; j -= 1 {
|
||||
swap(data, j, j-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_heap_sort :: proc(data: $T/[]$E, a, b: int) where ORD(E) #no_bounds_check {
|
||||
sift_down :: proc(data: T, lo, hi, first: int) #no_bounds_check {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && data[first+child] < data[first+child+1] {
|
||||
child += 1
|
||||
}
|
||||
if !(data[first+root] < data[first+child]) {
|
||||
return
|
||||
}
|
||||
swap(data, first+root, first+child)
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
first, lo, hi := a, 0, b-a
|
||||
|
||||
for i := (hi-1)/2; i >= 0; i -= 1 {
|
||||
sift_down(data, i, hi, first)
|
||||
}
|
||||
|
||||
for i := hi-1; i >= 0; i -= 1 {
|
||||
swap(data, first, first+i)
|
||||
sift_down(data, lo, i, first)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_quick_sort_less :: proc(data: $T/[]$E, a, b, max_depth: int, less: proc(i, j: E) -> bool) #no_bounds_check {
|
||||
median3 :: proc(data: T, m1, m0, m2: int, less: proc(i, j: E) -> bool) #no_bounds_check {
|
||||
if less(data[m1], data[m0]) {
|
||||
swap(data, m1, m0)
|
||||
}
|
||||
if less(data[m2], data[m1]) {
|
||||
swap(data, m2, m1)
|
||||
if less(data[m1], data[m0]) {
|
||||
swap(data, m1, m0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_pivot :: proc(data: T, lo, hi: int, less: proc(i, j: E) -> bool) -> (midlo, midhi: int) #no_bounds_check {
|
||||
m := int(uint(lo+hi)>>1)
|
||||
if hi-lo > 40 {
|
||||
s := (hi-lo)/8
|
||||
median3(data, lo, lo+s, lo+s*2, less)
|
||||
median3(data, m, m-s, m+s, less)
|
||||
median3(data, hi-1, hi-1-s, hi-1-s*2, less)
|
||||
}
|
||||
median3(data, lo, m, hi-1, less)
|
||||
|
||||
pivot := lo
|
||||
a, c := lo+1, hi-1
|
||||
|
||||
for ; a < c && less(data[a], data[pivot]); a += 1 {
|
||||
}
|
||||
b := a
|
||||
|
||||
for {
|
||||
for ; b < c && !less(data[pivot], data[b]); b += 1 { // data[b] <= pivot
|
||||
}
|
||||
for ; b < c && less(data[pivot], data[c-1]); c -=1 { // data[c-1] > pivot
|
||||
}
|
||||
if b >= c {
|
||||
break
|
||||
}
|
||||
|
||||
swap(data, b, c-1)
|
||||
b += 1
|
||||
c -= 1
|
||||
}
|
||||
|
||||
protect := hi-c < 5
|
||||
if !protect && hi-c < (hi-lo)/4 {
|
||||
dups := 0
|
||||
if !less(data[pivot], data[hi-1]) {
|
||||
swap(data, c, hi-1)
|
||||
c += 1
|
||||
dups += 1
|
||||
}
|
||||
if !less(data[b-1], data[pivot]) {
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
|
||||
if !less(data[m], data[pivot]) {
|
||||
swap(data, m, b-1)
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
protect = dups > 1
|
||||
}
|
||||
if protect {
|
||||
for {
|
||||
for ; a < b && !less(data[b-1], data[pivot]); b -= 1 {
|
||||
}
|
||||
for ; a < b && less(data[a], data[pivot]); a += 1 {
|
||||
}
|
||||
if a >= b {
|
||||
break
|
||||
}
|
||||
swap(data, a, b-1)
|
||||
a += 1
|
||||
b -= 1
|
||||
}
|
||||
}
|
||||
swap(data, pivot, b-1)
|
||||
return b-1, c
|
||||
}
|
||||
|
||||
|
||||
a, b, max_depth := a, b, max_depth
|
||||
|
||||
if b-a > 12 { // only use shell sort for lengths <= 12
|
||||
if max_depth == 0 {
|
||||
_heap_sort_less(data, a, b, less)
|
||||
return
|
||||
}
|
||||
max_depth -= 1
|
||||
mlo, mhi := do_pivot(data, a, b, less)
|
||||
if mlo-a < b-mhi {
|
||||
_quick_sort_less(data, a, mlo, max_depth, less)
|
||||
a = mhi
|
||||
} else {
|
||||
_quick_sort_less(data, mhi, b, max_depth, less)
|
||||
b = mlo
|
||||
}
|
||||
}
|
||||
if b-a > 1 {
|
||||
// Shell short with gap 6
|
||||
for i in a+6..<b {
|
||||
if less(data[i], data[i-6]) {
|
||||
swap(data, i, i-6)
|
||||
}
|
||||
}
|
||||
_insertion_sort_less(data, a, b, less)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_insertion_sort_less :: proc(data: $T/[]$E, a, b: int, less: proc(i, j: E) -> bool) #no_bounds_check {
|
||||
for i in a+1..<b {
|
||||
for j := i; j > a && less(data[j], data[j-1]); j -= 1 {
|
||||
swap(data, j, j-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_heap_sort_less :: proc(data: $T/[]$E, a, b: int, less: proc(i, j: E) -> bool) #no_bounds_check {
|
||||
sift_down :: proc(data: T, lo, hi, first: int, less: proc(i, j: E) -> bool) #no_bounds_check {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && less(data[first+child], data[first+child+1]) {
|
||||
child += 1
|
||||
}
|
||||
if !less(data[first+root], data[first+child]) {
|
||||
return
|
||||
}
|
||||
swap(data, first+root, first+child)
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
first, lo, hi := a, 0, b-a
|
||||
|
||||
for i := (hi-1)/2; i >= 0; i -= 1 {
|
||||
sift_down(data, i, hi, first, less)
|
||||
}
|
||||
|
||||
for i := hi-1; i >= 0; i -= 1 {
|
||||
swap(data, first, first+i)
|
||||
sift_down(data, lo, i, first, less)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_quick_sort_cmp :: proc(data: $T/[]$E, a, b, max_depth: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check {
|
||||
median3 :: proc(data: T, m1, m0, m2: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check {
|
||||
if cmp(data[m1], data[m0]) == .Less {
|
||||
swap(data, m1, m0)
|
||||
}
|
||||
if cmp(data[m2], data[m1]) == .Less {
|
||||
swap(data, m2, m1)
|
||||
if cmp(data[m1], data[m0]) == .Less {
|
||||
swap(data, m1, m0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_pivot :: proc(data: T, lo, hi: int, cmp: proc(i, j: E) -> Ordering) -> (midlo, midhi: int) #no_bounds_check {
|
||||
m := int(uint(lo+hi)>>1)
|
||||
if hi-lo > 40 {
|
||||
s := (hi-lo)/8
|
||||
median3(data, lo, lo+s, lo+s*2, cmp)
|
||||
median3(data, m, m-s, m+s, cmp)
|
||||
median3(data, hi-1, hi-1-s, hi-1-s*2, cmp)
|
||||
}
|
||||
median3(data, lo, m, hi-1, cmp)
|
||||
|
||||
pivot := lo
|
||||
a, c := lo+1, hi-1
|
||||
|
||||
for ; a < c && cmp(data[a], data[pivot]) == .Less; a += 1 {
|
||||
}
|
||||
b := a
|
||||
|
||||
for {
|
||||
for ; b < c && cmp(data[pivot], data[b]) >= .Equal; b += 1 { // data[b] <= pivot
|
||||
}
|
||||
for ; b < c && cmp(data[pivot], data[c-1]) == .Less; c -=1 { // data[c-1] > pivot
|
||||
}
|
||||
if b >= c {
|
||||
break
|
||||
}
|
||||
|
||||
swap(data, b, c-1)
|
||||
b += 1
|
||||
c -= 1
|
||||
}
|
||||
|
||||
protect := hi-c < 5
|
||||
if !protect && hi-c < (hi-lo)/4 {
|
||||
dups := 0
|
||||
if cmp(data[pivot], data[hi-1]) != .Less {
|
||||
swap(data, c, hi-1)
|
||||
c += 1
|
||||
dups += 1
|
||||
}
|
||||
if cmp(data[b-1], data[pivot]) != .Less {
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
|
||||
if cmp(data[m], data[pivot]) != .Less {
|
||||
swap(data, m, b-1)
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
protect = dups > 1
|
||||
}
|
||||
if protect {
|
||||
for {
|
||||
for ; a < b && cmp(data[b-1], data[pivot]) >= .Equal; b -= 1 {
|
||||
}
|
||||
for ; a < b && cmp(data[a], data[pivot]) == .Less; a += 1 {
|
||||
}
|
||||
if a >= b {
|
||||
break
|
||||
}
|
||||
swap(data, a, b-1)
|
||||
a += 1
|
||||
b -= 1
|
||||
}
|
||||
}
|
||||
swap(data, pivot, b-1)
|
||||
return b-1, c
|
||||
}
|
||||
|
||||
|
||||
a, b, max_depth := a, b, max_depth
|
||||
|
||||
if b-a > 12 { // only use shell sort for lengths <= 12
|
||||
if max_depth == 0 {
|
||||
_heap_sort_cmp(data, a, b, cmp)
|
||||
return
|
||||
}
|
||||
max_depth -= 1
|
||||
mlo, mhi := do_pivot(data, a, b, cmp)
|
||||
if mlo-a < b-mhi {
|
||||
_quick_sort_cmp(data, a, mlo, max_depth, cmp)
|
||||
a = mhi
|
||||
} else {
|
||||
_quick_sort_cmp(data, mhi, b, max_depth, cmp)
|
||||
b = mlo
|
||||
}
|
||||
}
|
||||
if b-a > 1 {
|
||||
// Shell short with gap 6
|
||||
for i in a+6..<b {
|
||||
if cmp(data[i], data[i-6]) == .Less {
|
||||
swap(data, i, i-6)
|
||||
}
|
||||
}
|
||||
_insertion_sort_cmp(data, a, b, cmp)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_insertion_sort_cmp :: proc(data: $T/[]$E, a, b: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check {
|
||||
for i in a+1..<b {
|
||||
for j := i; j > a && cmp(data[j], data[j-1]) == .Less; j -= 1 {
|
||||
swap(data, j, j-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_heap_sort_cmp :: proc(data: $T/[]$E, a, b: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check {
|
||||
sift_down :: proc(data: T, lo, hi, first: int, cmp: proc(i, j: E) -> Ordering) #no_bounds_check {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && cmp(data[first+child], data[first+child+1]) == .Less {
|
||||
child += 1
|
||||
}
|
||||
if cmp(data[first+root], data[first+child]) >= .Equal {
|
||||
return
|
||||
}
|
||||
swap(data, first+root, first+child)
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
first, lo, hi := a, 0, b-a
|
||||
|
||||
for i := (hi-1)/2; i >= 0; i -= 1 {
|
||||
sift_down(data, i, hi, first, cmp)
|
||||
}
|
||||
|
||||
for i := hi-1; i >= 0; i -= 1 {
|
||||
swap(data, first, first+i)
|
||||
sift_down(data, lo, i, first, cmp)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
//+private
|
||||
package slice
|
||||
|
||||
import "core:intrinsics"
|
||||
_ :: intrinsics
|
||||
|
||||
ORD :: intrinsics.type_is_ordered
|
||||
|
||||
Sort_Kind :: enum {
|
||||
Ordered,
|
||||
Less,
|
||||
Cmp,
|
||||
}
|
||||
|
||||
_quick_sort_general :: proc(data: $T/[]$E, a, b, max_depth: int, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
|
||||
less :: #force_inline proc(a, b: E, call: P) -> bool {
|
||||
when KIND == .Ordered {
|
||||
return a < b
|
||||
} else when KIND == .Less {
|
||||
return call(a, b)
|
||||
} else when KIND == .Cmp {
|
||||
return call(a, b) == .Less
|
||||
} else {
|
||||
#panic("unhandled Sort_Kind")
|
||||
}
|
||||
}
|
||||
|
||||
insertion_sort :: proc(data: $T/[]$E, a, b: int, call: P) #no_bounds_check {
|
||||
for i in a+1..<b {
|
||||
for j := i; j > a && less(data[j], data[j-1], call); j -= 1 {
|
||||
swap(data, j, j-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
heap_sort :: proc(data: $T/[]$E, a, b: int, call: P) #no_bounds_check {
|
||||
sift_down :: proc(data: T, lo, hi, first: int, call: P) #no_bounds_check {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && less(data[first+child], data[first+child+1], call) {
|
||||
child += 1
|
||||
}
|
||||
if !less(data[first+root], data[first+child], call) {
|
||||
return
|
||||
}
|
||||
swap(data, first+root, first+child)
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
first, lo, hi := a, 0, b-a
|
||||
|
||||
for i := (hi-1)/2; i >= 0; i -= 1 {
|
||||
sift_down(data, i, hi, first, call)
|
||||
}
|
||||
|
||||
for i := hi-1; i >= 0; i -= 1 {
|
||||
swap(data, first, first+i)
|
||||
sift_down(data, lo, i, first, call)
|
||||
}
|
||||
}
|
||||
|
||||
median3 :: proc(data: T, m1, m0, m2: int, call: P) #no_bounds_check {
|
||||
if less(data[m1], data[m0], call) {
|
||||
swap(data, m1, m0)
|
||||
}
|
||||
if less(data[m2], data[m1], call) {
|
||||
swap(data, m2, m1)
|
||||
if less(data[m1], data[m0], call) {
|
||||
swap(data, m1, m0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_pivot :: proc(data: T, lo, hi: int, call: P) -> (midlo, midhi: int) #no_bounds_check {
|
||||
m := int(uint(lo+hi)>>1)
|
||||
if hi-lo > 40 {
|
||||
s := (hi-lo)/8
|
||||
median3(data, lo, lo+s, lo+s*2, call)
|
||||
median3(data, m, m-s, m+s, call)
|
||||
median3(data, hi-1, hi-1-s, hi-1-s*2, call)
|
||||
}
|
||||
median3(data, lo, m, hi-1, call)
|
||||
|
||||
pivot := lo
|
||||
a, c := lo+1, hi-1
|
||||
|
||||
|
||||
for ; a < c && less(data[a], data[pivot], call); a += 1 {
|
||||
}
|
||||
b := a
|
||||
|
||||
for {
|
||||
for ; b < c && !less(data[pivot], data[b], call); b += 1 { // data[b] <= pivot
|
||||
}
|
||||
for ; b < c && less(data[pivot], data[c-1], call); c -=1 { // data[c-1] > pivot
|
||||
}
|
||||
if b >= c {
|
||||
break
|
||||
}
|
||||
|
||||
swap(data, b, c-1)
|
||||
b += 1
|
||||
c -= 1
|
||||
}
|
||||
|
||||
protect := hi-c < 5
|
||||
if !protect && hi-c < (hi-lo)/4 {
|
||||
dups := 0
|
||||
if !less(data[pivot], data[hi-1], call) {
|
||||
swap(data, c, hi-1)
|
||||
c += 1
|
||||
dups += 1
|
||||
}
|
||||
if !less(data[b-1], data[pivot], call) {
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
|
||||
if !less(data[m], data[pivot], call) {
|
||||
swap(data, m, b-1)
|
||||
b -= 1
|
||||
dups += 1
|
||||
}
|
||||
protect = dups > 1
|
||||
}
|
||||
if protect {
|
||||
for {
|
||||
for ; a < b && !less(data[b-1], data[pivot], call); b -= 1 {
|
||||
}
|
||||
for ; a < b && less(data[a], data[pivot], call); a += 1 {
|
||||
}
|
||||
if a >= b {
|
||||
break
|
||||
}
|
||||
swap(data, a, b-1)
|
||||
a += 1
|
||||
b -= 1
|
||||
}
|
||||
}
|
||||
swap(data, pivot, b-1)
|
||||
return b-1, c
|
||||
}
|
||||
|
||||
|
||||
a, b, max_depth := a, b, max_depth
|
||||
|
||||
if b-a > 12 { // only use shell sort for lengths <= 12
|
||||
if max_depth == 0 {
|
||||
heap_sort(data, a, b, call)
|
||||
return
|
||||
}
|
||||
max_depth -= 1
|
||||
mlo, mhi := do_pivot(data, a, b, call)
|
||||
if mlo-a < b-mhi {
|
||||
_quick_sort_general(data, a, mlo, max_depth, call, KIND)
|
||||
a = mhi
|
||||
} else {
|
||||
_quick_sort_general(data, mhi, b, max_depth, call, KIND)
|
||||
b = mlo
|
||||
}
|
||||
}
|
||||
if b-a > 1 {
|
||||
// Shell short with gap 6
|
||||
for i in a+6..<b {
|
||||
if less(data[i], data[i-6], call) {
|
||||
swap(data, i, i-6)
|
||||
}
|
||||
}
|
||||
insertion_sort(data, a, b, call)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// merge sort
|
||||
_stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
|
||||
less :: #force_inline proc(a, b: E, call: P) -> bool {
|
||||
when KIND == .Ordered {
|
||||
return a < b
|
||||
} else when KIND == .Less {
|
||||
return call(a, b)
|
||||
} else when KIND == .Cmp {
|
||||
return call(a, b) == .Less
|
||||
} else {
|
||||
#panic("unhandled Sort_Kind")
|
||||
}
|
||||
}
|
||||
|
||||
n := len(data)
|
||||
for i in 1..<n {
|
||||
for j := i; j > 0 && less(data[j], data[j-1], call); j -= 1 {
|
||||
swap(data, j, j-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,9 @@ import "core:intrinsics"
|
||||
import "core:runtime"
|
||||
import "core:slice"
|
||||
|
||||
_ :: runtime
|
||||
_ :: slice
|
||||
|
||||
map_entries_by_key :: proc(m: ^$M/map[$K]$V, loc := #caller_location) where intrinsics.type_is_ordered(K) {
|
||||
Entry :: struct {
|
||||
hash: uintptr,
|
||||
|
||||
@@ -353,6 +353,76 @@ split_after_n_iterator :: proc(s: ^string, sep: string, n: int) -> (string, bool
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
_trim_cr :: proc(s: string) -> string {
|
||||
n := len(s)
|
||||
if n > 0 {
|
||||
if s[n-1] == '\r' {
|
||||
return s[:n-1]
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
split_lines :: proc(s: string, allocator := context.allocator) -> []string {
|
||||
sep :: "\n"
|
||||
lines := _split(s, sep, 0, -1, allocator)
|
||||
for line in &lines {
|
||||
line = _trim_cr(line)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
split_lines_n :: proc(s: string, n: int, allocator := context.allocator) -> []string {
|
||||
sep :: "\n"
|
||||
lines := _split(s, sep, 0, n, allocator)
|
||||
for line in &lines {
|
||||
line = _trim_cr(line)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
split_lines_after :: proc(s: string, allocator := context.allocator) -> []string {
|
||||
sep :: "\n"
|
||||
lines := _split(s, sep, len(sep), -1, allocator)
|
||||
for line in &lines {
|
||||
line = _trim_cr(line)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) -> []string {
|
||||
sep :: "\n"
|
||||
lines := _split(s, sep, len(sep), n, allocator)
|
||||
for line in &lines {
|
||||
line = _trim_cr(line)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
split_lines_iterator :: proc(s: ^string) -> (line: string, ok: bool) {
|
||||
sep :: "\n"
|
||||
line = _split_iterator(s, sep, 0, -1) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
split_lines_n_iterator :: proc(s: ^string, n: int) -> (line: string, ok: bool) {
|
||||
sep :: "\n"
|
||||
line = _split_iterator(s, sep, 0, n) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
split_lines_after_iterator :: proc(s: ^string) -> (line: string, ok: bool) {
|
||||
sep :: "\n"
|
||||
line = _split_iterator(s, sep, len(sep), -1) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
split_lines_after_n_iterator :: proc(s: ^string, n: int) -> (line: string, ok: bool) {
|
||||
sep :: "\n"
|
||||
line = _split_iterator(s, sep, len(sep), n) or_return
|
||||
return _trim_cr(line), true
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+36
-37
@@ -1,44 +1,43 @@
|
||||
package sync
|
||||
|
||||
|
||||
// A barrier enabling multiple threads to synchronize the beginning of some computation
|
||||
/*
|
||||
* Example:
|
||||
*
|
||||
* package example
|
||||
*
|
||||
* import "core:fmt"
|
||||
* import "core:sync"
|
||||
* import "core:thread"
|
||||
*
|
||||
* barrier := &sync.Barrier{};
|
||||
*
|
||||
* main :: proc() {
|
||||
* fmt.println("Start");
|
||||
*
|
||||
* THREAD_COUNT :: 4;
|
||||
* threads: [THREAD_COUNT]^thread.Thread;
|
||||
*
|
||||
* sync.barrier_init(barrier, THREAD_COUNT);
|
||||
* defer sync.barrier_destroy(barrier);
|
||||
*
|
||||
*
|
||||
* for _, i in threads {
|
||||
* threads[i] = thread.create_and_start(proc(t: ^thread.Thread) {
|
||||
* // Same messages will be printed together but without any interleaving
|
||||
* fmt.println("Getting ready!");
|
||||
* sync.barrier_wait(barrier);
|
||||
* fmt.println("Off their marks they go!");
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* for t in threads {
|
||||
* thread.destroy(t); // join and free thread
|
||||
* }
|
||||
* fmt.println("Finished");
|
||||
* }
|
||||
*
|
||||
*/
|
||||
A barrier enabling multiple threads to synchronize the beginning of some computation
|
||||
Example:
|
||||
|
||||
package example
|
||||
|
||||
import "core:fmt"
|
||||
import "core:sync"
|
||||
import "core:thread"
|
||||
|
||||
barrier := &sync.Barrier{};
|
||||
|
||||
main :: proc() {
|
||||
fmt.println("Start");
|
||||
|
||||
THREAD_COUNT :: 4;
|
||||
threads: [THREAD_COUNT]^thread.Thread;
|
||||
|
||||
sync.barrier_init(barrier, THREAD_COUNT);
|
||||
defer sync.barrier_destroy(barrier);
|
||||
|
||||
|
||||
for _, i in threads {
|
||||
threads[i] = thread.create_and_start(proc(t: ^thread.Thread) {
|
||||
// Same messages will be printed together but without any interleaving
|
||||
fmt.println("Getting ready!");
|
||||
sync.barrier_wait(barrier);
|
||||
fmt.println("Off their marks they go!");
|
||||
});
|
||||
}
|
||||
|
||||
for t in threads {
|
||||
thread.destroy(t); // join and free thread
|
||||
}
|
||||
fmt.println("Finished");
|
||||
}
|
||||
*/
|
||||
Barrier :: struct {
|
||||
mutex: Blocking_Mutex,
|
||||
cond: Condition,
|
||||
|
||||
@@ -67,44 +67,41 @@ wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -
|
||||
|
||||
|
||||
|
||||
// A barrier enabling multiple threads to synchronize the beginning of some computation
|
||||
/*
|
||||
* Example:
|
||||
*
|
||||
* package example
|
||||
*
|
||||
* import "core:fmt"
|
||||
* import "core:sync"
|
||||
* import "core:thread"
|
||||
*
|
||||
* barrier := &sync.Barrier{}
|
||||
*
|
||||
* main :: proc() {
|
||||
* fmt.println("Start")
|
||||
*
|
||||
* THREAD_COUNT :: 4
|
||||
* threads: [THREAD_COUNT]^thread.Thread
|
||||
*
|
||||
* sync.barrier_init(barrier, THREAD_COUNT)
|
||||
* defer sync.barrier_destroy(barrier)
|
||||
*
|
||||
*
|
||||
* for _, i in threads {
|
||||
* threads[i] = thread.create_and_start(proc(t: ^thread.Thread) {
|
||||
* // Same messages will be printed together but without any interleaving
|
||||
* fmt.println("Getting ready!")
|
||||
* sync.barrier_wait(barrier)
|
||||
* fmt.println("Off their marks they go!")
|
||||
* })
|
||||
* }
|
||||
*
|
||||
* for t in threads {
|
||||
* thread.destroy(t) // join and free thread
|
||||
* }
|
||||
* fmt.println("Finished")
|
||||
* }
|
||||
*
|
||||
*/
|
||||
A barrier enabling multiple threads to synchronize the beginning of some computation
|
||||
|
||||
Example:
|
||||
package example
|
||||
|
||||
import "core:fmt"
|
||||
import "core:sync"
|
||||
import "core:thread"
|
||||
|
||||
barrier := &sync.Barrier{}
|
||||
|
||||
main :: proc() {
|
||||
fmt.println("Start")
|
||||
|
||||
THREAD_COUNT :: 4
|
||||
threads: [THREAD_COUNT]^thread.Thread
|
||||
|
||||
sync.barrier_init(barrier, THREAD_COUNT)
|
||||
|
||||
for _, i in threads {
|
||||
threads[i] = thread.create_and_start(proc(t: ^thread.Thread) {
|
||||
// Same messages will be printed together but without any interleaving
|
||||
fmt.println("Getting ready!")
|
||||
sync.barrier_wait(barrier)
|
||||
fmt.println("Off their marks they go!")
|
||||
})
|
||||
}
|
||||
|
||||
for t in threads {
|
||||
thread.destroy(t) // join and free thread
|
||||
}
|
||||
fmt.println("Finished")
|
||||
}
|
||||
*/
|
||||
Barrier :: struct {
|
||||
mutex: Mutex,
|
||||
cond: Cond,
|
||||
|
||||
@@ -29,12 +29,12 @@ mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
return _mutex_try_lock(m)
|
||||
}
|
||||
|
||||
// Example:
|
||||
//
|
||||
// if mutex_guard(&m) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Example:
|
||||
if mutex_guard(&m) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(deferred_in=mutex_unlock)
|
||||
mutex_guard :: proc(m: ^Mutex) -> bool {
|
||||
mutex_lock(m)
|
||||
@@ -80,25 +80,24 @@ rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
||||
rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
return _rw_mutex_try_shared_lock(rw)
|
||||
}
|
||||
|
||||
// Example:
|
||||
//
|
||||
// if rw_mutex_guard(&m) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Example:
|
||||
if rw_mutex_guard(&m) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(deferred_in=rw_mutex_unlock)
|
||||
rw_mutex_guard :: proc(m: ^RW_Mutex) -> bool {
|
||||
rw_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
// Example:
|
||||
//
|
||||
// if rw_mutex_shared_guard(&m) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Example:
|
||||
if rw_mutex_shared_guard(&m) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(deferred_in=rw_mutex_shared_unlock)
|
||||
rw_mutex_shared_guard :: proc(m: ^RW_Mutex) -> bool {
|
||||
rw_mutex_shared_lock(m)
|
||||
@@ -127,13 +126,12 @@ recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||
return _recursive_mutex_try_lock(m)
|
||||
}
|
||||
|
||||
|
||||
// Example:
|
||||
//
|
||||
// if recursive_mutex_guard(&m) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Example:
|
||||
if recursive_mutex_guard(&m) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(deferred_in=recursive_mutex_unlock)
|
||||
recursive_mutex_guard :: proc(m: ^Recursive_Mutex) -> bool {
|
||||
recursive_mutex_lock(m)
|
||||
|
||||
@@ -82,13 +82,12 @@ atomic_mutex_try_lock :: proc(m: ^Atomic_Mutex) -> bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
|
||||
// Example:
|
||||
//
|
||||
// if atomic_mutex_guard(&m) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Example:
|
||||
if atomic_mutex_guard(&m) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(deferred_in=atomic_mutex_unlock)
|
||||
atomic_mutex_guard :: proc(m: ^Atomic_Mutex) -> bool {
|
||||
atomic_mutex_lock(m)
|
||||
@@ -193,25 +192,24 @@ atomic_rw_mutex_try_shared_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// Example:
|
||||
//
|
||||
// if atomic_rw_mutex_guard(&m) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Example:
|
||||
if atomic_rw_mutex_guard(&m) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(deferred_in=atomic_rw_mutex_unlock)
|
||||
atomic_rw_mutex_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
|
||||
// Example:
|
||||
//
|
||||
// if atomic_rw_mutex_shared_guard(&m) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Example:
|
||||
if atomic_rw_mutex_shared_guard(&m) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(deferred_in=atomic_rw_mutex_shared_unlock)
|
||||
atomic_rw_mutex_shared_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_shared_lock(m)
|
||||
@@ -270,13 +268,12 @@ atomic_recursive_mutex_try_lock :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
// Example:
|
||||
//
|
||||
// if atomic_recursive_mutex_guard(&m) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
/*
|
||||
Example:
|
||||
if atomic_recursive_mutex_guard(&m) {
|
||||
...
|
||||
}
|
||||
*/
|
||||
@(deferred_in=atomic_recursive_mutex_unlock)
|
||||
atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
atomic_recursive_mutex_lock(m)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user