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