Merge remote-tracking branch 'origin/master'

This commit is contained in:
Benoit Jacquier
2022-08-27 16:22:37 +02:00
109 changed files with 4860 additions and 3397 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ scanner_destroy :: proc(s: ^Scanner) {
}
// Returns the first non-EOF error that was encounted by the scanner
// Returns the first non-EOF error that was encountered by the scanner
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
switch s._err {
case .EOF, nil:
+1 -1
View File
@@ -331,7 +331,7 @@ fmin :: proc{libc_fmin, libc_fminf}
fma :: proc{libc_fma, libc_fmaf}
// But retain the 'f' suffix-variant functions as well so they can be used,
// a trick is used here where we use explicit procedrual overloading of one
// a trick is used here where we use explicit procedural overloading of one
// procedure. This is done because the foreign block is marked @(private) and
// aliasing functions does not remove privateness from the entity.
acosf :: proc{libc_acosf}
@@ -85,7 +85,6 @@ _shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool {
_shift_up :: proc(pq: ^$Q/Priority_Queue($T), j: int) {
j := j
queue := pq.queue[:]
n := builtin.len(queue)
for 0 <= j {
i := (j-1)/2
if i == j || !pq.less(queue[j], queue[i]) {
+1 -1
View File
@@ -81,7 +81,7 @@ The crypto package is not thread-safe at the moment. This may change in the futu
### Disclaimer
The algorithms were ported out of curiosity and due to interest in the field.
We have not had any of the code verified by a third party or tested/fuzzed by any automatic means.
Whereever we were able to find official test vectors, those were used to verify the implementation.
Wherever we were able to find official test vectors, those were used to verify the implementation.
We do not recommend using them in a production environment, without any additional testing and/or verification.
### ToDo
+1 -1
View File
@@ -30,6 +30,6 @@ equivalence.
For the most part, alterations to the base fiat-crypto generated code was
kept to a minimum, to aid auditability. This results in a somewhat
ideosyncratic style, and in some cases minor performance penalties.
idiosyncratic style, and in some cases minor performance penalties.
[1]: https://github.com/mit-plv/fiat-crypto
+1 -1
View File
@@ -233,7 +233,7 @@ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) {
}
update :: proc(ctx: ^Context, data: []byte) {
assert(ctx.is_initialized, "crypto/siphash: Context is not initalized")
assert(ctx.is_initialized, "crypto/siphash: Context is not initialized")
ctx.last_block = len(data) / 8 * 8
ctx.buf = data
i := 0
+1 -1
View File
@@ -107,7 +107,7 @@ Node :: struct {
/* Conventions */
/* ------------
Much of HxA's use is based on convention. HxA lets users store arbitrary data in its structure that can be parsed but whose semantic meaning does not need to be understood.
A few conventions are hard, and some are soft. Hard convention that a user HAS to follow in order to produce a valid file. Hard conventions simplify parsing becaus the parser can make some assumptions. Soft convenbtions are basicly recomendations of how to store common data.
A few conventions are hard, and some are soft. Hard convention that a user HAS to follow in order to produce a valid file. Hard conventions simplify parsing becaus the parser can make some assumptions. Soft convenbtions are basically recomendations of how to store common data.
If you use HxA for something not covered by the conventions but need a convention for your use case. Please let us know so that we can add it!
*/
+215 -40
View File
@@ -17,25 +17,54 @@ Marshal_Error :: union #shared_nil {
io.Error,
}
marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
// careful with MJSON maps & non quotes usage as keys without whitespace will lead to bad results
Marshal_Options :: struct {
// output based on spec
spec: Specification,
// use line breaks & tab|spaces
pretty: bool,
// spacing
use_spaces: bool,
spaces: int,
// state
indentation: int,
// option to output uint in JSON5 & MJSON
write_uint_as_hex: bool,
// mjson output options
mjson_keys_use_quotes: bool,
mjson_keys_use_equal_sign: bool,
// mjson state
mjson_skipped_first_braces_start: bool,
mjson_skipped_first_braces_end: bool,
}
marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
b := strings.builder_make(allocator)
defer if err != nil {
strings.builder_destroy(&b)
}
marshal_to_builder(&b, v) or_return
opt := opt
marshal_to_builder(&b, v, &opt) or_return
if len(b.buf) != 0 {
data = b.buf[:]
}
return data, nil
}
marshal_to_builder :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
return marshal_to_writer(strings.to_writer(b), v)
marshal_to_builder :: proc(b: ^strings.Builder, v: any, opt: ^Marshal_Options) -> Marshal_Error {
return marshal_to_writer(strings.to_writer(b), v, opt)
}
marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) {
if v == nil {
io.write_string(w, "null") or_return
return
@@ -56,6 +85,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
case i16: u = u128(i)
case i32: u = u128(i)
case i64: u = u128(i)
case i128: u = u128(i)
case int: u = u128(i)
case u8: u = u128(i)
case u16: u = u128(i)
@@ -82,7 +112,21 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
case u128be: u = u128(i)
}
s := strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
s: string
// allow uints to be printed as hex
if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) {
switch i in a {
case u8, u16, u32, u64, u128:
s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix })
case:
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
}
} else {
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
}
io.write_string(w, s) or_return
@@ -147,6 +191,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
case runtime.Type_Info_Multi_Pointer:
return .Unsupported_Type
case runtime.Type_Info_Soa_Pointer:
return .Unsupported_Type
case runtime.Type_Info_Procedure:
return .Unsupported_Type
@@ -166,52 +213,48 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
return .Unsupported_Type
case runtime.Type_Info_Array:
io.write_byte(w, '[') or_return
opt_write_start(w, opt, '[') or_return
for i in 0..<info.count {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(v.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
}
io.write_byte(w, ']') or_return
opt_write_end(w, opt, ']') or_return
case runtime.Type_Info_Enumerated_Array:
index := runtime.type_info_base(info.index).variant.(runtime.Type_Info_Enum)
io.write_byte(w, '[') or_return
opt_write_start(w, opt, '[') or_return
for i in 0..<info.count {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(v.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
}
io.write_byte(w, ']') or_return
opt_write_end(w, opt, ']') or_return
case runtime.Type_Info_Dynamic_Array:
io.write_byte(w, '[') or_return
opt_write_start(w, opt, '[') or_return
array := cast(^mem.Raw_Dynamic_Array)v.data
for i in 0..<array.len {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(array.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
}
io.write_byte(w, ']') or_return
opt_write_end(w, opt, ']') or_return
case runtime.Type_Info_Slice:
io.write_byte(w, '[') or_return
opt_write_start(w, opt, '[') or_return
slice := cast(^mem.Raw_Slice)v.data
for i in 0..<slice.len {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(slice.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
}
io.write_byte(w, ']') or_return
opt_write_end(w, opt, ']') or_return
case runtime.Type_Info_Map:
m := (^mem.Raw_Map)(v.data)
opt_write_start(w, opt, '{') or_return
io.write_byte(w, '{') or_return
if m != nil {
if info.generated_struct == nil {
return .Unsupported_Type
@@ -223,31 +266,50 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
entry_size := ed.elem_size
for i in 0..<entries.len {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(entries.data) + uintptr(i*entry_size)
key := rawptr(data + entry_type.offsets[2])
value := rawptr(data + entry_type.offsets[3])
marshal_to_writer(w, any{key, info.key.id}) or_return
io.write_string(w, ": ") or_return
marshal_to_writer(w, any{value, info.value.id}) or_return
// check for string type
{
v := any{key, info.key.id}
ti := runtime.type_info_base(type_info_of(v.id))
a := any{v.data, ti.id}
name: string
#partial switch info in ti.variant {
case runtime.Type_Info_String:
switch s in a {
case string: name = s
case cstring: name = string(s)
}
opt_write_key(w, opt, name) or_return
case: return .Unsupported_Type
}
}
marshal_to_writer(w, any{value, info.value.id}, opt) or_return
}
}
io.write_byte(w, '}') or_return
opt_write_end(w, opt, '}') or_return
case runtime.Type_Info_Struct:
io.write_byte(w, '{') or_return
opt_write_start(w, opt, '{') or_return
for name, i in info.names {
if i > 0 { io.write_string(w, ", ") or_return }
io.write_quoted_string(w, name) or_return
io.write_string(w, ": ") or_return
opt_write_iteration(w, opt, i) or_return
opt_write_key(w, opt, name) or_return
id := info.types[i].id
data := rawptr(uintptr(v.data) + info.offsets[i])
marshal_to_writer(w, any{data, id}) or_return
marshal_to_writer(w, any{data, id}, opt) or_return
}
io.write_byte(w, '}') or_return
opt_write_end(w, opt, '}') or_return
case runtime.Type_Info_Union:
tag_ptr := uintptr(v.data) + info.tag_offset
@@ -270,11 +332,11 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
io.write_string(w, "null") or_return
} else {
id := info.variants[tag-1].id
return marshal_to_writer(w, any{v.data, id})
return marshal_to_writer(w, any{v.data, id}, opt)
}
case runtime.Type_Info_Enum:
return marshal_to_writer(w, any{v.data, info.base.id})
return marshal_to_writer(w, any{v.data, info.base.id}, opt)
case runtime.Type_Info_Bit_Set:
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
@@ -330,3 +392,116 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
return
}
// write key as quoted string or with optional quotes in mjson
opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err: io.Error) {
switch opt.spec {
case .JSON, .JSON5:
io.write_quoted_string(w, name) or_return
io.write_string(w, ": ") or_return
case .MJSON:
if opt.mjson_keys_use_quotes {
io.write_quoted_string(w, name) or_return
} else {
io.write_string(w, name) or_return
}
if opt.mjson_keys_use_equal_sign {
io.write_string(w, " = ") or_return
} else {
io.write_string(w, ": ") or_return
}
}
return
}
// insert start byte and increase indentation on pretty
opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) {
// skip mjson starting braces
if opt.spec == .MJSON && !opt.mjson_skipped_first_braces_start {
opt.mjson_skipped_first_braces_start = true
return
}
io.write_byte(w, c) or_return
opt.indentation += 1
if opt.pretty {
io.write_byte(w, '\n') or_return
}
return
}
// insert comma seperation and write indentations
opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) {
switch opt.spec {
case .JSON, .JSON5:
if iteration > 0 {
io.write_string(w, ", ") or_return
if opt.pretty {
io.write_byte(w, '\n') or_return
}
}
opt_write_indentation(w, opt) or_return
case .MJSON:
if iteration > 0 {
// on pretty no commas necessary
if opt.pretty {
io.write_byte(w, '\n') or_return
} else {
// comma seperation necessary for non pretty output!
io.write_string(w, ", ") or_return
}
}
opt_write_indentation(w, opt) or_return
}
return
}
// decrease indent, write spacing and insert end byte
opt_write_end :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) {
if opt.spec == .MJSON && opt.mjson_skipped_first_braces_start && !opt.mjson_skipped_first_braces_end {
if opt.indentation == 0 {
opt.mjson_skipped_first_braces_end = true
return
}
}
opt.indentation -= 1
if opt.pretty {
io.write_byte(w, '\n') or_return
opt_write_indentation(w, opt) or_return
}
io.write_byte(w, c) or_return
return
}
// writes current indentation level based on options
opt_write_indentation :: proc(w: io.Writer, opt: ^Marshal_Options) -> (err: io.Error) {
if !opt.pretty {
return
}
if opt.use_spaces {
spaces := opt.spaces == 0 ? 4 : opt.spaces
for _ in 0..<opt.indentation * spaces {
io.write_byte(w, ' ') or_return
}
} else {
for _ in 0..<opt.indentation {
io.write_byte(w, '\t') or_return
}
}
return
}
+2 -2
View File
@@ -325,7 +325,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token}
if end_token == .Close_Brace {
assert(expect_token(p, .Open_Brace) == nil)
unmarshal_expect_token(p, .Open_Brace)
}
v := v
@@ -473,7 +473,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
}
if end_token == .Close_Brace {
assert(expect_token(p, .Close_Brace) == nil)
unmarshal_expect_token(p, .Close_Brace)
}
return
}
+30 -2
View File
@@ -1031,6 +1031,15 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
}
}
fmt_soa_pointer :: proc(fi: ^Info, p: runtime.Raw_Soa_Pointer, verb: rune) {
io.write_string(fi.writer, "#soa{data=0x", &fi.n)
_fmt_int(fi, u64(uintptr(p.data)), 16, false, 8*size_of(rawptr), __DIGITS_UPPER)
io.write_string(fi.writer, ", index=", &fi.n)
_fmt_int(fi, u64(p.index), 10, false, 8*size_of(rawptr), __DIGITS_UPPER)
io.write_string(fi.writer, "}", &fi.n)
}
enum_value_to_string :: proc(val: any) -> (string, bool) {
v := val
v.id = runtime.typeid_base(v.id)
@@ -1867,6 +1876,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
fmt_pointer(fi, ptr, verb)
}
case runtime.Type_Info_Soa_Pointer:
ptr := (^runtime.Raw_Soa_Pointer)(v.data)^
fmt_soa_pointer(fi, ptr, verb)
case runtime.Type_Info_Multi_Pointer:
ptr := (^rawptr)(v.data)^
if ptr == nil {
@@ -2046,18 +2059,33 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
entry_type := ed.elem.variant.(runtime.Type_Info_Struct)
entry_size := ed.elem_size
/*
NOTE: The layout of a `map` is as follows:
map[Key]Value
## Internal Layout
struct {
hashes: []int,
entries: [dynamic]struct{
hash: uintptr,
next: int,
key: Key,
value: Value,
},
}
*/
for i in 0..<entries.len {
if i > 0 { io.write_string(fi.writer, ", ", &fi.n) }
data := uintptr(entries.data) + uintptr(i*entry_size)
key := data + entry_type.offsets[2]
key := data + entry_type.offsets[2] // key: Key
fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, 'v')
io.write_string(fi.writer, "=", &fi.n)
value := data + entry_type.offsets[3]
value := data + entry_type.offsets[3] // value: Value
fmt_arg(fi, any{rawptr(value), info.value.id}, 'v')
}
}
+5 -5
View File
@@ -475,7 +475,7 @@ return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok
}
// Does the image have 1 or 2 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid?
// Is the pointer valid, are the dimensions valid?
is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image?
if img == nil {
@@ -495,7 +495,7 @@ is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
// This returns 0 if any of the inputs is zero.
bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth)
// If the dimenions are invalid or the buffer size doesn't match the image characteristics, bail.
// If the dimensions are invalid or the buffer size doesn't match the image characteristics, bail.
if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS {
return false
}
@@ -504,7 +504,7 @@ is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
}
// Does the image have 3 or 4 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid?
// Is the pointer valid, are the dimensions valid?
is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image?
if img == nil {
@@ -524,7 +524,7 @@ is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
// This returns 0 if any of the inputs is zero.
bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth)
// If the dimenions are invalid or the buffer size doesn't match the image characteristics, bail.
// If the dimensions are invalid or the buffer size doesn't match the image characteristics, bail.
if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS {
return false
}
@@ -533,7 +533,7 @@ is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
}
// Does the image have 1..4 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid?
// Is the pointer valid, are the dimensions valid?
is_valid_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image?
if img == nil {
+1 -1
View File
@@ -219,7 +219,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b
defer close(fd)
write_string(fd,
fmt.tprintf("P6\n%v %v\n%v\n", width, height, (1 << uint(depth) - 1)),
fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)),
)
if channels == 3 {
+3 -3
View File
@@ -1002,7 +1002,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
o16 = o16[out_image_channels:]
}
case:
unreachable("We should never seen # channels other than 1-4 inclusive.")
panic("We should never seen # channels other than 1-4 inclusive.")
}
img.pixels = t
@@ -1195,7 +1195,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
o = o[out_image_channels:]
}
case:
unreachable("We should never seen # channels other than 1-4 inclusive.")
panic("We should never seen # channels other than 1-4 inclusive.")
}
img.pixels = t
@@ -1206,7 +1206,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
This may change if we ever don't expand 1, 2 and 4 bit images. But, those raw
returns will likely bypass this processing pipeline.
*/
unreachable("We should never see bit depths other than 8, 16 and 'Paletted' here.")
panic("We should never see bit depths other than 8, 16 and 'Paletted' here.")
}
return img, nil
+3
View File
@@ -295,6 +295,9 @@ objc_register_selector :: proc($name: string) -> objc_SEL ---
objc_find_class :: proc($name: string) -> objc_Class ---
objc_register_class :: proc($name: string) -> objc_Class ---
valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, a3, a4: uintptr) -> uintptr ---
// Internal compiler use only
__entry_point :: proc() ---
+2 -2
View File
@@ -56,7 +56,7 @@ create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logg
return Logger{file_console_logger_proc, data, lowest, opt}
}
destroy_console_logger :: proc(log: ^Logger) {
destroy_console_logger :: proc(log: Logger) {
free(log.data)
}
@@ -95,7 +95,7 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string
fmt.sbprintf(&buf, "[%s] ", data.ident)
}
//TODO(Hoej): When we have better atomics and such, make this thread-safe
fmt.fprintf(h, "%s %s\n", strings.to_string(buf), text)
fmt.fprintf(h, "%s%s\n", strings.to_string(buf), text)
}
do_level_header :: proc(opts: Options, level: Level, str: ^strings.Builder) {
+5 -6
View File
@@ -6,7 +6,6 @@ import "core:fmt"
// NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle.
Level :: runtime.Logger_Level
/*
Logger_Level :: enum {
Debug = 0,
@@ -16,8 +15,8 @@ Logger_Level :: enum {
Fatal = 40,
}
*/
Level :: runtime.Logger_Level
Option :: runtime.Logger_Option
/*
Option :: enum {
Level,
@@ -30,11 +29,12 @@ Option :: enum {
Terminal_Color
}
*/
Option :: runtime.Logger_Option
Options :: runtime.Logger_Options
/*
Options :: bit_set[Option];
*/
Options :: runtime.Logger_Options
Full_Timestamp_Opts :: Options{
.Date,
@@ -52,12 +52,11 @@ Location_File_Opts :: Options{
}
Logger_Proc :: runtime.Logger_Proc
/*
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
*/
Logger_Proc :: runtime.Logger_Proc
Logger :: runtime.Logger
/*
Logger :: struct {
procedure: Logger_Proc,
@@ -66,6 +65,7 @@ Logger :: struct {
options: Logger_Options,
}
*/
Logger :: runtime.Logger
nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
// Do nothing
@@ -75,7 +75,6 @@ nil_logger :: proc() -> Logger {
return Logger{nil_logger_proc, nil, Level.Debug, nil}
}
// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
logf(level=.Debug, fmt_str=fmt_str, args=args, location=location)
}
+107
View File
@@ -0,0 +1,107 @@
package log
import "core:runtime"
Log_Allocator :: struct {
allocator: runtime.Allocator,
level: Level,
prefix: string,
locked: bool,
}
log_allocator_init :: proc(la: ^Log_Allocator, level: Level, allocator := context.allocator, prefix := "") {
la.allocator = allocator
la.level = level
la.prefix = prefix
la.locked = false
}
log_allocator :: proc(la: ^Log_Allocator) -> runtime.Allocator {
return runtime.Allocator{
procedure = log_allocator_proc,
data = la,
}
}
log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
la := (^Log_Allocator)(allocator_data)
padding := " " if la.prefix != "" else ""
if !la.locked {
la.locked = true
defer la.locked = false
switch mode {
case .Alloc:
logf(
level=la.level,
fmt_str = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)",
args = {la.prefix, padding, size, alignment},
location = location,
)
case .Free:
if old_size != 0 {
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)",
args = {la.prefix, padding, old_memory, old_size},
location = location,
)
} else {
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)",
args = {la.prefix, padding, old_memory},
location = location,
)
}
case .Free_All:
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free_All)",
args = {la.prefix, padding},
location = location,
)
case .Resize:
logf(
level=la.level,
fmt_str = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)",
args = {la.prefix, padding, old_memory, old_size, size, alignment},
location = location,
)
case .Query_Features:
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR(mode=.Query_Features)",
args = {la.prefix, padding},
location = location,
)
case .Query_Info:
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR(mode=.Query_Info)",
args = {la.prefix, padding},
location = location,
)
}
}
data, err := la.allocator.procedure(la.allocator.data, mode, size, alignment, old_memory, old_size, location)
if !la.locked {
la.locked = true
defer la.locked = false
if err != nil {
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR ERROR=%v",
args = {la.prefix, padding, error},
location = location,
)
}
}
return data, err
}
+1 -1
View File
@@ -449,7 +449,7 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra
in the loop is non-zero, although very low.
-- NOTE(Jeroen): This is not yet true in Odin, but I have some ideas.
If the BPSW test and/or the addtional Frobenious test have been
If the BPSW test and/or the additional Frobenious test have been
performed instead of just the Miller-Rabin test with the bases 2 and 3,
a single extra test should suffice, so such a very unlikely event will not do much harm.
+3 -3
View File
@@ -94,7 +94,7 @@ quaternion_cross :: proc(q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) {
vector_cross :: proc{scalar_cross, vector_cross2, vector_cross3}
cross :: proc{scalar_cross, vector_cross2, vector_cross3, quaternion_cross}
vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) {
vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_FLOAT(E) {
return v / length(v)
}
quaternion_normalize :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
@@ -102,7 +102,7 @@ quaternion_normalize :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
}
normalize :: proc{vector_normalize, quaternion_normalize}
vector_normalize0 :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) {
vector_normalize0 :: proc(v: $T/[$N]$E) -> T where IS_FLOAT(E) {
m := length(v)
return 0 if m == 0 else v/m
}
@@ -113,7 +113,7 @@ quaternion_normalize0 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
normalize0 :: proc{vector_normalize0, quaternion_normalize0}
vector_length :: proc(v: $T/[$N]$E) -> E where IS_NUMERIC(E) {
vector_length :: proc(v: $T/[$N]$E) -> E where IS_FLOAT(E) {
return math.sqrt(dot(v, v))
}
+36 -10
View File
@@ -185,16 +185,23 @@ log :: proc{
log_f64, log_f64le, log_f64be,
}
log2_f16 :: logb_f16
log2_f16le :: logb_f16le
log2_f16be :: logb_f16be
log2_f32 :: logb_f32
log2_f32le :: logb_f32le
log2_f32be :: logb_f32be
log2_f64 :: logb_f64
log2_f64le :: logb_f64le
log2_f64be :: logb_f64be
log2 :: logb
log2_f16 :: proc "contextless" (x: f16) -> f16 { return log(f16(x), f16(2.0)) }
log2_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log_f16(f16(x), f16(2.0))) }
log2_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log_f16(f16(x), f16(2.0))) }
log2_f32 :: proc "contextless" (x: f32) -> f32 { return log(f32(x), f32(2.0)) }
log2_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log_f32(f32(x), f32(2.0))) }
log2_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log_f32(f32(x), f32(2.0))) }
log2_f64 :: proc "contextless" (x: f64) -> f64 { return log(f64(x), f64(2.0)) }
log2_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log_f64(f64(x), f64(2.0))) }
log2_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log_f64(f64(x), f64(2.0))) }
log2 :: proc{
log2_f16, log2_f16le, log2_f16be,
log2_f32, log2_f32le, log2_f32be,
log2_f64, log2_f64le, log2_f64be,
}
log10_f16 :: proc "contextless" (x: f16) -> f16 { return ln(x)/LN10 }
log10_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log10_f16(f16(x))) }
@@ -607,6 +614,25 @@ floor_mod :: proc "contextless" (x, y: $T) -> T
return r
}
divmod :: #force_inline proc "contextless" (x, y: $T) -> (div, mod: T)
where intrinsics.type_is_integer(T) {
div = x / y
mod = x % y
return
}
floor_divmod :: #force_inline proc "contextless" (x, y: $T) -> (div, mod: T)
where intrinsics.type_is_integer(T) {
div = x / y
mod = x % y
if (div > 0 && y < 0) || (mod < 0 && y > 0) {
div -= 1
mod += y
}
return
}
modf_f16 :: proc "contextless" (x: f16) -> (int: f16, frac: f16) {
shift :: F16_SHIFT
mask :: F16_MASK
+9 -85
View File
@@ -61,114 +61,38 @@ DEFAULT_PAGE_SIZE ::
4 * 1024
alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
if size == 0 {
return nil
}
if allocator.procedure == nil {
return nil
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, loc)
_ = err
data, _ := runtime.mem_alloc(size, alignment, allocator, loc)
return raw_data(data)
}
alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if size == 0 {
return nil, nil
}
if allocator.procedure == nil {
return nil, nil
}
return allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, loc)
return runtime.mem_alloc(size, alignment, allocator, loc)
}
free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil {
return nil
}
if allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, 0, loc)
return err
return runtime.mem_free(ptr, allocator, loc)
}
free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if bytes == nil {
return nil
}
if allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, raw_data(bytes), len(bytes), loc)
return err
return runtime.mem_free_bytes(bytes, allocator, loc)
}
free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if allocator.procedure != nil {
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free_All, 0, 0, nil, 0, loc)
return err
}
return nil
return runtime.mem_free_all(allocator, loc)
}
resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
if allocator.procedure == nil {
return nil
}
if new_size == 0 {
if ptr != nil {
allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
}
return nil
} else if ptr == nil {
_, err := allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
_ = err
return nil
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return nil
}
runtime.copy(data, byte_slice(ptr, old_size))
_, err = allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
return raw_data(data)
}
data, _ := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
return raw_data(data)
}
resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if allocator.procedure == nil {
return nil, nil
}
ptr := raw_data(old_data)
old_size := len(old_data)
if new_size == 0 {
if ptr != nil {
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
return nil, err
}
return nil, nil
} else if ptr == nil {
return allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return data, err
}
runtime.copy(data, old_data)
_, err = allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
}
return data, err
return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
}
query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
if allocator.procedure != nil {
allocator.procedure(allocator.data, Allocator_Mode.Query_Features, 0, 0, &set, 0, loc)
allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
return set
}
return nil
@@ -177,7 +101,7 @@ query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: A
query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
props.pointer = pointer
if allocator.procedure != nil {
allocator.procedure(allocator.data, Allocator_Mode.Query_Info, 0, 0, &props, 0, loc)
allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc)
}
return
}
+29 -6
View File
@@ -31,6 +31,14 @@ Arena_Temp_Memory :: struct {
}
arena_init :: proc(a: ^Arena, data: []byte) {
a.data = data
a.offset = 0
a.peak_used = 0
a.temp_count = 0
}
@(deprecated="prefer 'mem.arena_init'")
init_arena :: proc(a: ^Arena, data: []byte) {
a.data = data
a.offset = 0
@@ -293,6 +301,14 @@ Stack :: struct {
peak_used: int,
}
stack_init :: proc(s: ^Stack, data: []byte) {
s.data = data
s.prev_offset = 0
s.curr_offset = 0
s.peak_used = 0
}
@(deprecated="prefer 'mem.stack_init'")
init_stack :: proc(s: ^Stack, data: []byte) {
s.data = data
s.prev_offset = 0
@@ -445,27 +461,34 @@ Small_Stack_Allocation_Header :: struct {
// Small_Stack is a stack-like allocator which uses the smallest possible header but at the cost of non-strict memory freeing order
Small_Stack :: struct {
data: []byte,
offset: int,
data: []byte,
offset: int,
peak_used: int,
}
small_stack_init :: proc(s: ^Small_Stack, data: []byte) {
s.data = data
s.offset = 0
s.peak_used = 0
}
@(deprecated="prefer 'small_stack_init'")
init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
s.data = data
s.offset = 0
s.data = data
s.offset = 0
s.peak_used = 0
}
small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
return Allocator{
procedure = small_stack_allocator_proc,
data = stack,
data = stack,
}
}
small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, ocation := #caller_location) -> ([]byte, Allocator_Error) {
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, Allocator_Error) {
s := cast(^Small_Stack)allocator_data
if s.data == nil {
+1 -42
View File
@@ -54,48 +54,7 @@ compare :: proc "contextless" (a, b: []byte) -> int {
}
compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
switch {
case a == b:
return 0
case a == nil:
return -1
case b == nil:
return -1
case n == 0:
return 0
}
x := slice_ptr(a, n)
y := slice_ptr(b, n)
SU :: size_of(uintptr)
fast := n/SU + 1
offset := (fast-1)*SU
curr_block := 0
if n < SU {
fast = 0
}
la := slice_ptr((^uintptr)(a), fast)
lb := slice_ptr((^uintptr)(b), fast)
for /**/; curr_block < fast; curr_block += 1 {
if la[curr_block] ~ lb[curr_block] != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
if x[pos] ~ y[pos] != 0 {
return (int(x[pos]) - int(y[pos])) < 0 ? -1 : +1
}
}
}
}
for /**/; offset < n; offset += 1 {
if x[offset] ~ y[offset] != 0 {
return (int(x[offset]) - int(y[offset])) < 0 ? -1 : +1
}
}
return 0
return runtime.memory_compare(a, b, n)
}
check_zero :: proc(data: []byte) -> bool {
+1
View File
@@ -8,6 +8,7 @@ Raw_Cstring :: runtime.Raw_Cstring
Raw_Slice :: runtime.Raw_Slice
Raw_Dynamic_Array :: runtime.Raw_Dynamic_Array
Raw_Map :: runtime.Raw_Map
Raw_Soa_Pointer :: runtime.Raw_Soa_Pointer
Raw_Complex64 :: struct {real, imag: f32}
Raw_Complex128 :: struct {real, imag: f64}
+5
View File
@@ -1,5 +1,10 @@
package mem_virtual
arena_init :: proc{
static_arena_init,
growing_arena_init,
}
arena_temp_begin :: proc{
static_arena_temp_begin,
growing_arena_temp_begin,
+11 -4
View File
@@ -13,6 +13,13 @@ Growing_Arena :: struct {
DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough
growing_arena_init :: proc(arena: ^Static_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
arena.block = memory_block_alloc(0, reserved, {}) or_return
arena.total_used = 0
arena.total_reserved = arena.block.reserved
return
}
growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
align_forward_offset :: proc "contextless" (arena: ^Growing_Arena, alignment: int) -> uint #no_bounds_check {
alignment_offset := uint(0)
@@ -37,7 +44,7 @@ growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int
block_size := max(size, arena.minimum_block_size)
new_block := memory_block_alloc(block_size, block_size, {}) or_return
new_block := memory_block_alloc(size, block_size, {}) or_return
new_block.prev = arena.curr_block
arena.curr_block = new_block
arena.total_reserved += new_block.reserved
@@ -95,9 +102,9 @@ growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator {
}
growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
size, alignment: int,
old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
arena := (^Growing_Arena)(allocator_data)
switch mode {
+148
View File
@@ -0,0 +1,148 @@
//+build darwin
//+private
package mem_virtual
foreign import libc "System.framework"
import "core:c"
PROT_NONE :: 0x0 /* [MC2] no permissions */
PROT_READ :: 0x1 /* [MC2] pages can be read */
PROT_WRITE :: 0x2 /* [MC2] pages can be written */
PROT_EXEC :: 0x4 /* [MC2] pages can be executed */
// Sharing options
MAP_SHARED :: 0x1 /* [MF|SHM] share changes */
MAP_PRIVATE :: 0x2 /* [MF|SHM] changes are private */
// Other flags
MAP_FIXED :: 0x0010 /* [MF|SHM] interpret addr exactly */
MAP_RENAME :: 0x0020 /* Sun: rename private pages to file */
MAP_NORESERVE :: 0x0040 /* Sun: don't reserve needed swap area */
MAP_RESERVED0080 :: 0x0080 /* previously unimplemented MAP_INHERIT */
MAP_NOEXTEND :: 0x0100 /* for MAP_FILE, don't change file size */
MAP_HASSEMAPHORE :: 0x0200 /* region may contain semaphores */
MAP_NOCACHE :: 0x0400 /* don't cache pages for this mapping */
MAP_JIT :: 0x0800 /* Allocate a region that will be used for JIT purposes */
// Mapping type
MAP_FILE :: 0x0000 /* map from file (default) */
MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */
/*
* The MAP_RESILIENT_* flags can be used when the caller wants to map some
* possibly unreliable memory and be able to access it safely, possibly
* getting the wrong contents rather than raising any exception.
* For safety reasons, such mappings have to be read-only (PROT_READ access
* only).
*
* MAP_RESILIENT_CODESIGN:
* accessing this mapping will not generate code-signing violations,
* even if the contents are tainted.
* MAP_RESILIENT_MEDIA:
* accessing this mapping will not generate an exception if the contents
* are not available (unreachable removable or remote media, access beyond
* end-of-file, ...). Missing contents will be replaced with zeroes.
*/
MAP_RESILIENT_CODESIGN :: 0x2000 /* no code-signing failures */
MAP_RESILIENT_MEDIA :: 0x4000 /* no backing-store failures */
MAP_32BIT :: 0x8000 /* Return virtual addresses <4G only */
// Flags used to support translated processes.
MAP_TRANSLATED_ALLOW_EXECUTE :: 0x20000 /* allow execute in translated processes */
MAP_UNIX03 :: 0x40000 /* UNIX03 compliance */
// Process memory locking
MCL_CURRENT :: 0x0001 /* [ML] Lock only current memory */
MCL_FUTURE :: 0x0002 /* [ML] Lock all future memory as well */
MADV_NORMAL :: 0 /* [MC1] no further special treatment */
MADV_RANDOM :: 1 /* [MC1] expect random page refs */
MADV_SEQUENTIAL :: 2 /* [MC1] expect sequential page refs */
MADV_WILLNEED :: 3 /* [MC1] will need these pages */
MADV_DONTNEED :: 4 /* [MC1] dont need these pages */
MADV_FREE :: 5 /* pages unneeded, discard contents */
MADV_ZERO_WIRED_PAGES :: 6 /* zero the wired pages that have not been unwired before the entry is deleted */
MADV_FREE_REUSABLE :: 7 /* pages can be reused (by anyone) */
MADV_FREE_REUSE :: 8 /* caller wants to reuse those pages */
MADV_CAN_REUSE :: 9
MADV_PAGEOUT :: 10 /* page out now (internal only) */
// msync() flags
MS_ASYNC :: 0x0001 /* [MF|SIO] return immediately */
MS_INVALIDATE :: 0x0002 /* [MF|SIO] invalidate all cached data */
MS_SYNC :: 0x0010 /* [MF|SIO] msync synchronously */
MS_KILLPAGES :: 0x0004 /* invalidate pages, leave mapped */
MS_DEACTIVATE :: 0x0008 /* deactivate pages, leave mapped */
// Return bits from mincore
MINCORE_INCORE :: 0x1 /* Page is incore */
MINCORE_REFERENCED :: 0x2 /* Page has been referenced by us */
MINCORE_MODIFIED :: 0x4 /* Page has been modified by us */
MINCORE_REFERENCED_OTHER :: 0x8 /* Page has been referenced */
MINCORE_MODIFIED_OTHER :: 0x10 /* Page has been modified */
MINCORE_PAGED_OUT :: 0x20 /* Page has been paged out */
MINCORE_COPIED :: 0x40 /* Page has been copied */
MINCORE_ANONYMOUS :: 0x80 /* Page belongs to an anonymous object */
// Allocation failure result
MAP_FAILED : rawptr = rawptr(~uintptr(0))
foreign libc {
@(link_name="mlockall") _mlockall :: proc(flags: c.int) -> c.int ---
@(link_name="munlockall") _munlockall :: proc() -> c.int ---
@(link_name="mlock") _mlock :: proc(addr: rawptr, len: c.size_t) -> c.int ---
@(link_name="mmap") _mmap :: proc(addr: rawptr, len: c.size_t, prot: c.int, flags: c.int, fd: c.int, offset: int) -> rawptr ---
@(link_name="mprotect") _mprotect :: proc(addr: rawptr, len: c.size_t, prot: c.int) -> c.int ---
@(link_name="msync") _msync :: proc(addr: rawptr, len: c.size_t) -> c.int ---
@(link_name="munlock") _munlock :: proc(addr: rawptr, len: c.size_t) -> c.int ---
@(link_name="munmap") _munmap :: proc(addr: rawptr, len: c.size_t) -> c.int ---
@(link_name="shm_open") _shm_open :: proc(name: cstring, oflag: c.int, #c_vararg args: ..any) -> c.int ---
@(link_name="shm_unlink") _shm_unlink :: proc(name: cstring) -> c.int ---
@(link_name="posix_madvise") _posix_madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
@(link_name="madvise") _madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
@(link_name="mincore") _mincore :: proc(addr: rawptr, len: c.size_t, vec: cstring) -> c.int ---
@(link_name="minherit") _minherit :: proc(addr: rawptr, len: c.size_t, inherit: c.int) -> c.int ---
}
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
result := _mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
if result == MAP_FAILED {
return nil, .Out_Of_Memory
}
return ([^]byte)(uintptr(result))[:size], nil
}
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
result := _mprotect(data, size, PROT_READ|PROT_WRITE)
if result != 0 {
return .Out_Of_Memory
}
return nil
}
_decommit :: proc "contextless" (data: rawptr, size: uint) {
_mprotect(data, size, PROT_NONE)
_madvise(data, size, MADV_FREE)
}
_release :: proc "contextless" (data: rawptr, size: uint) {
_munmap(data, size)
}
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
pflags: c.int
pflags = PROT_NONE
if .Read in flags { pflags |= PROT_READ }
if .Write in flags { pflags |= PROT_WRITE }
if .Execute in flags { pflags |= PROT_EXEC }
err := _mprotect(data, size, pflags)
return err != 0
}
_platform_memory_init :: proc() {
DEFAULT_PAGE_SIZE = 4096
// is power of two
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
}
+1 -1
View File
@@ -48,7 +48,7 @@ munmap :: proc "contextless" (addr: rawptr, length: uint) -> c.int {
}
mprotect :: proc "contextless" (addr: rawptr, length: uint, prot: c.int) -> c.int {
res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uint(prot))
res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uintptr(prot))
return c.int(res)
}
+37 -1
View File
@@ -552,13 +552,20 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
return
}
Field_Flags :: distinct bit_set[Field_Flag]
Field_Flag :: enum {
Invalid,
Unknown,
Ellipsis,
Using,
No_Alias,
C_Vararg,
Auto_Cast,
Any_Int,
Subtype,
By_Ptr,
Results,
Tags,
@@ -566,11 +573,38 @@ Field_Flag :: enum {
Typeid_Token,
}
Field_Flags :: distinct bit_set[Field_Flag]
field_flag_strings := [Field_Flag]string{
.Invalid = "",
.Unknown = "",
.Ellipsis = "..",
.Using = "using",
.No_Alias = "#no_alias",
.C_Vararg = "#c_vararg",
.Auto_Cast = "auto_cast",
.Any_Int = "#any_int",
.Subtype = "#subtype",
.By_Ptr = "#by_ptr",
.Results = "results",
.Tags = "field tag",
.Default_Parameters = "default parameters",
.Typeid_Token = "typeid",
}
field_hash_flag_strings := []struct{key: string, flag: Field_Flag}{
{"no_alias", .No_Alias},
{"c_vararg", .C_Vararg},
{"any_int", .Any_Int},
{"subtype", .Subtype},
{"by_ptr", .By_Ptr},
}
Field_Flags_Struct :: Field_Flags{
.Using,
.Tags,
.Subtype,
}
Field_Flags_Record_Poly_Params :: Field_Flags{
.Typeid_Token,
@@ -583,6 +617,7 @@ Field_Flags_Signature :: Field_Flags{
.C_Vararg,
.Auto_Cast,
.Any_Int,
.By_Ptr,
.Default_Parameters,
}
@@ -665,6 +700,7 @@ Proc_Type :: struct {
Pointer_Type :: struct {
using node: Expr,
tag: ^Expr,
pointer: tokenizer.Pos,
elem: ^Expr,
}
+1
View File
@@ -286,6 +286,7 @@ clone_node :: proc(node: ^Node) -> ^Node {
r.results = auto_cast clone(r.results)
case ^Pointer_Type:
r.elem = clone(r.elem)
r.tag = clone(r.tag)
case ^Multi_Pointer_Type:
r.elem = clone(r.elem)
case ^Array_Type:
+2
View File
@@ -186,6 +186,7 @@ Type_Kind :: enum u32le {
Relative_Slice = 21,
Multi_Pointer = 22,
Matrix = 23,
Soa_Pointer = 24,
}
Type_Elems_Cap :: 4
@@ -245,6 +246,7 @@ Type :: struct {
// .Relative_Slice - 2 types: 0=slice type, 1=base integer
// .Multi_Pointer - 1 type: 0=element
// .Matrix - 1 type: 0=element
// .Soa_Pointer - 1 type: 0=element
types: Array(Type_Index),
// Used by:
+40 -78
View File
@@ -245,12 +245,7 @@ peek_token :: proc(p: ^Parser, lookahead := 0) -> (tok: tokenizer.Token) {
return
}
skip_possible_newline :: proc(p: ^Parser) -> bool {
if .Optional_Semicolons not_in p.flags {
return false
}
prev := p.curr_tok
if tokenizer.is_newline(prev) {
if tokenizer.is_newline(p.curr_tok) {
advance_token(p)
return true
}
@@ -1611,20 +1606,6 @@ new_ast_field :: proc(names: []^ast.Expr, type: ^ast.Expr, default_value: ^ast.E
return field
}
Field_Prefix :: enum {
Invalid,
Unknown,
Using,
No_Alias,
C_Vararg,
Auto_Cast,
Any_Int,
}
Field_Prefixes :: distinct bit_set[Field_Prefix]
Expr_And_Flags :: struct {
expr: ^ast.Expr,
flags: ast.Field_Flags,
@@ -1666,7 +1647,7 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
return idents[:]
}
is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
is_token_field_prefix :: proc(p: ^Parser) -> ast.Field_Flag {
#partial switch p.curr_tok.kind {
case .EOF:
return .Invalid
@@ -1677,17 +1658,15 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
advance_token(p)
return .Auto_Cast
case .Hash:
tok: tokenizer.Token
advance_token(p)
defer advance_token(p)
#partial switch p.curr_tok.kind {
case .Ident:
switch p.curr_tok.text {
case "no_alias":
return .No_Alias
case "c_vararg":
return .C_Vararg
case "any_int":
return .Any_Int
tok = p.curr_tok
advance_token(p)
if tok.kind == .Ident {
for kf in ast.field_hash_flag_strings {
if kf.key == tok.text {
return kf.flag
}
}
}
return .Unknown
@@ -1695,8 +1674,8 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
return .Invalid
}
parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
counts: [len(Field_Prefix)]int
parse_field_prefixes :: proc(p: ^Parser) -> (flags: ast.Field_Flags) {
counts: [len(ast.Field_Flag)]int
for {
kind := is_token_field_prefix(p)
@@ -1712,31 +1691,17 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
counts[kind] += 1
}
flags: ast.Field_Flags
for kind in Field_Prefix {
for kind in ast.Field_Flag {
count := counts[kind]
switch kind {
case .Invalid, .Unknown: // Ignore
case .Using:
if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list") }
if count > 0 { flags += {.Using} }
case .No_Alias:
if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list") }
if count > 0 { flags += {.No_Alias} }
case .C_Vararg:
if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list") }
if count > 0 { flags += {.C_Vararg} }
case .Auto_Cast:
if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list") }
if count > 0 { flags += {.Auto_Cast} }
case .Any_Int:
if count > 1 { error(p, p.curr_tok.pos, "multiple '#any_int' in this field list") }
if count > 0 { flags += {.Any_Int} }
if kind == .Invalid || kind == .Unknown {
// Ignore
} else {
if count > 1 { error(p, p.curr_tok.pos, "multiple '%s' in this field list", ast.field_flag_strings[kind]) }
if count > 0 { flags += {kind} }
}
}
return flags
return
}
check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, set_flags: ast.Field_Flags) -> (flags: ast.Field_Flags) {
@@ -1748,19 +1713,13 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
for flag in ast.Field_Flag {
if flag not_in allowed_flags && flag in flags {
switch flag {
case .Using:
error(p, p.curr_tok.pos, "'using' is not allowed within this field list")
case .No_Alias:
error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list")
case .C_Vararg:
error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list")
case .Auto_Cast:
error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list")
case .Any_Int:
error(p, p.curr_tok.pos, "'#any_int' is not allowed within this field list")
#partial switch flag {
case .Unknown, .Invalid:
// ignore
case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
panic("Impossible prefixes")
case:
error(p, p.curr_tok.pos, "'%s' is not allowed within this field list", ast.field_flag_strings[flag])
}
flags -= {flag}
}
@@ -2271,7 +2230,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return parse_call_expr(p, bd)
case "soa", "simd":
case "soa":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
bd.tok = tok
bd.name = name.text
@@ -2280,6 +2239,20 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
#partial switch t in type.derived_expr {
case ^ast.Array_Type: t.tag = bd
case ^ast.Dynamic_Array_Type: t.tag = bd
case ^ast.Pointer_Type: t.tag = bd
case:
error(p, original_type.pos, "expected an array or pointer type after #%s", name.text)
}
return original_type
case "simd":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
bd.tok = tok
bd.name = name.text
original_type := parse_type(p)
type := ast.unparen_expr(original_type)
#partial switch t in type.derived_expr {
case ^ast.Array_Type: t.tag = bd
case:
error(p, original_type.pos, "expected an array type after #%s", name.text)
}
@@ -2631,7 +2604,6 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tok := expect_token(p, .Union)
poly_params: ^ast.Field_List
align: ^ast.Expr
is_maybe: bool
is_no_nil: bool
is_shared_nil: bool
@@ -2656,10 +2628,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
}
align = parse_expr(p, true)
case "maybe":
if is_maybe {
error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
}
is_maybe = true
error(p, tag.pos, "#%s functionality has now been merged with standard 'union' functionality", tag.text)
case "no_nil":
if is_no_nil {
error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
@@ -2676,19 +2645,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
}
p.expr_level = prev_level
if is_no_nil && is_maybe {
error(p, p.curr_tok.pos, "#maybe and #no_nil cannot be applied together")
}
if is_no_nil && is_shared_nil {
error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together")
}
if is_shared_nil && is_maybe {
error(p, p.curr_tok.pos, "#maybe and #shared_nil cannot be applied together")
}
union_kind := ast.Union_Type_Kind.Normal
switch {
case is_maybe: union_kind = .maybe
case is_no_nil: union_kind = .no_nil
case is_shared_nil: union_kind = .shared_nil
}
+10 -10
View File
@@ -6,19 +6,19 @@ import "core:runtime"
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Windows:
dir = get_env("LocalAppData")
dir = get_env("LocalAppData", allocator)
if dir != "" {
dir = strings.clone_safe(dir, allocator) or_return
}
case .Darwin:
dir = get_env("HOME")
dir = get_env("HOME", allocator)
if dir != "" {
dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME")
dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" {
dir = get_env("HOME")
dir = get_env("HOME", allocator)
if dir == "" {
return
}
@@ -34,19 +34,19 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Windows:
dir = get_env("AppData")
dir = get_env("AppData", allocator)
if dir != "" {
dir = strings.clone_safe(dir, allocator) or_return
}
case .Darwin:
dir = get_env("HOME")
dir = get_env("HOME", allocator)
if dir != "" {
dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME")
dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" {
dir = get_env("HOME")
dir = get_env("HOME", allocator)
if dir == "" {
return
}
@@ -59,13 +59,13 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
return
}
user_home_dir :: proc() -> (dir: string, err: Error) {
user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
env := "HOME"
#partial switch ODIN_OS {
case .Windows:
env = "USERPROFILE"
}
if v := get_env(env); v != "" {
if v := get_env(env, allocator); v != "" {
return v, nil
}
return "", .Invalid_Path
+1 -1
View File
@@ -311,7 +311,7 @@ _unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
low := uintptr(offset & 0xFFFFFFFF)
high := uintptr(offset >> 32)
result: i64
res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence)))
res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, uintptr(&result), uintptr(whence)))
return -1 if res < 0 else result
}
}
+1 -1
View File
@@ -271,7 +271,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := cont
}
d, derr := os.open(dir)
d, derr := os.open(dir, os.O_RDONLY)
if derr != 0 {
return
}
+39 -24
View File
@@ -1,7 +1,6 @@
package reflect
import "core:runtime"
import "core:mem"
import "core:intrinsics"
_ :: intrinsics
@@ -34,6 +33,7 @@ Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer
Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice
Type_Info_Matrix :: runtime.Type_Info_Matrix
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value
@@ -68,6 +68,7 @@ Type_Kind :: enum {
Relative_Pointer,
Relative_Slice,
Matrix,
Soa_Pointer,
}
@@ -102,6 +103,7 @@ type_kind :: proc(T: typeid) -> Type_Kind {
case Type_Info_Relative_Pointer: return .Relative_Pointer
case Type_Info_Relative_Slice: return .Relative_Slice
case Type_Info_Matrix: return .Matrix
case Type_Info_Soa_Pointer: return .Soa_Pointer
}
}
@@ -194,6 +196,7 @@ typeid_elem :: proc(id: typeid) -> typeid {
}
case Type_Info_Pointer: return v.elem.id
case Type_Info_Multi_Pointer: return v.elem.id
case Type_Info_Soa_Pointer: return v.elem.id
case Type_Info_Array: return v.elem.id
case Type_Info_Enumerated_Array: return v.elem.id
case Type_Info_Slice: return v.elem.id
@@ -220,7 +223,7 @@ align_of_typeid :: proc(T: typeid) -> int {
as_bytes :: proc(v: any) -> []byte {
if v != nil {
sz := size_of_typeid(v.id)
return mem.slice_ptr((^byte)(v.data), sz)
return ([^]byte)(v.data)[:sz]
}
return nil
}
@@ -262,19 +265,19 @@ length :: proc(val: any) -> int {
return a.count
case Type_Info_Slice:
return (^mem.Raw_Slice)(val.data).len
return (^runtime.Raw_Slice)(val.data).len
case Type_Info_Dynamic_Array:
return (^mem.Raw_Dynamic_Array)(val.data).len
return (^runtime.Raw_Dynamic_Array)(val.data).len
case Type_Info_Map:
return (^mem.Raw_Map)(val.data).entries.len
return (^runtime.Raw_Map)(val.data).entries.len
case Type_Info_String:
if a.is_cstring {
return len((^cstring)(val.data)^)
} else {
return (^mem.Raw_String)(val.data).len
return (^runtime.Raw_String)(val.data).len
}
}
return 0
@@ -297,10 +300,10 @@ capacity :: proc(val: any) -> int {
return a.count
case Type_Info_Dynamic_Array:
return (^mem.Raw_Dynamic_Array)(val.data).cap
return (^runtime.Raw_Dynamic_Array)(val.data).cap
case Type_Info_Map:
return (^mem.Raw_Map)(val.data).entries.cap
return (^runtime.Raw_Map)(val.data).entries.cap
}
return 0
}
@@ -340,14 +343,14 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
return any{data, a.elem.id}
case Type_Info_Slice:
raw := (^mem.Raw_Slice)(val.data)
raw := (^runtime.Raw_Slice)(val.data)
runtime.bounds_check_error_loc(loc, i, raw.len)
offset := uintptr(a.elem.size * i)
data := rawptr(uintptr(raw.data) + offset)
return any{data, a.elem.id}
case Type_Info_Dynamic_Array:
raw := (^mem.Raw_Dynamic_Array)(val.data)
raw := (^runtime.Raw_Dynamic_Array)(val.data)
runtime.bounds_check_error_loc(loc, i, raw.len)
offset := uintptr(a.elem.size * i)
data := rawptr(uintptr(raw.data) + offset)
@@ -356,7 +359,7 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
case Type_Info_String:
if a.is_cstring { return nil }
raw := (^mem.Raw_String)(val.data)
raw := (^runtime.Raw_String)(val.data)
runtime.bounds_check_error_loc(loc, i, raw.len)
offset := uintptr(size_of(u8) * i)
data := rawptr(uintptr(raw.data) + offset)
@@ -725,6 +728,17 @@ get_union_variant_raw_tag :: proc(a: any) -> i64 {
panic("expected a union to reflect.get_union_variant_raw_tag")
}
get_union_variant :: proc(a: any) -> any {
if a == nil {
return nil
}
id := union_variant_typeid(a)
if id == nil {
return nil
}
return any{a.data, id}
}
set_union_variant_raw_tag :: proc(a: any, tag: i64) {
if a == nil { return }
@@ -822,17 +836,17 @@ set_union_value :: proc(dst: any, value: any) -> bool {
ti := runtime.type_info_base(type_info_of(dst.id))
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
if value.id == nil {
mem.zero(dst.data, ti.size)
intrinsics.mem_zero(dst.data, ti.size)
return true
}
if ti.id == runtime.typeid_base(value.id) {
mem.copy(dst.data, value.data, ti.size)
intrinsics.mem_copy(dst.data, value.data, ti.size)
return true
}
if type_info_union_is_pure_maybe(info) {
if variant := info.variants[0]; variant.id == value.id {
mem.copy(dst.data, value.data, variant.size)
intrinsics.mem_copy(dst.data, value.data, variant.size)
return true
}
return false
@@ -844,7 +858,7 @@ set_union_value :: proc(dst: any, value: any) -> bool {
if !info.no_nil {
tag += 1
}
mem.copy(dst.data, value.data, variant.size)
intrinsics.mem_copy(dst.data, value.data, variant.size)
set_union_variant_raw_tag(dst, tag)
return true
}
@@ -1337,11 +1351,11 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
case Type_Info_Slice:
valid = true
value = (^mem.Raw_Slice)(a.data).data
value = (^runtime.Raw_Slice)(a.data).data
case Type_Info_Dynamic_Array:
valid = true
value = (^mem.Raw_Dynamic_Array)(a.data).data
value = (^runtime.Raw_Dynamic_Array)(a.data).data
}
return
@@ -1383,7 +1397,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
}
if .Simple_Compare in t.flags {
return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0
return runtime.memory_compare(a.data, b.data, t.size) == 0
}
t = runtime.type_info_core(t)
@@ -1419,8 +1433,9 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
Type_Info_Enum,
Type_Info_Simd_Vector,
Type_Info_Relative_Pointer,
Type_Info_Soa_Pointer,
Type_Info_Matrix:
return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0
return runtime.memory_compare(a.data, b.data, t.size) == 0
case Type_Info_String:
if v.is_cstring {
@@ -1474,8 +1489,8 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
if !including_indirect_array_recursion {
return false
}
array_a := (^mem.Raw_Slice)(a.data)
array_b := (^mem.Raw_Slice)(b.data)
array_a := (^runtime.Raw_Slice)(a.data)
array_b := (^runtime.Raw_Slice)(b.data)
if array_a.len != array_b.len {
return false
}
@@ -1494,8 +1509,8 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
if !including_indirect_array_recursion {
return false
}
array_a := (^mem.Raw_Dynamic_Array)(a.data)
array_b := (^mem.Raw_Dynamic_Array)(b.data)
array_a := (^runtime.Raw_Dynamic_Array)(a.data)
array_b := (^runtime.Raw_Dynamic_Array)(b.data)
if array_a.len != array_b.len {
return false
}
@@ -1503,7 +1518,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
return true
}
if .Simple_Compare in v.elem.flags {
return mem.compare_byte_ptrs((^byte)(array_a.data), (^byte)(array_b.data), array_a.len * v.elem.size) == 0
return runtime.memory_compare((^byte)(array_a.data), (^byte)(array_b.data), array_a.len * v.elem.size) == 0
}
for i in 0..<array_a.len {
+18
View File
@@ -68,6 +68,11 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
y := b.variant.(Type_Info_Multi_Pointer) or_return
return are_types_identical(x.elem, y.elem)
case Type_Info_Soa_Pointer:
y := b.variant.(Type_Info_Soa_Pointer) or_return
return are_types_identical(x.elem, y.elem)
case Type_Info_Procedure:
y := b.variant.(Type_Info_Procedure) or_return
switch {
@@ -256,6 +261,11 @@ is_multi_pointer :: proc(info: ^Type_Info) -> bool {
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
return ok
}
is_soa_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer)
return ok
}
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
#partial switch v in info.variant {
@@ -292,6 +302,11 @@ is_dynamic_map :: proc(info: ^Type_Info) -> bool {
_, ok := type_info_base(info).variant.(Type_Info_Map)
return ok
}
is_bit_set :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Bit_Set)
return ok
}
is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Slice)
@@ -437,6 +452,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
case Type_Info_Multi_Pointer:
io.write_string(w, "[^]", &n) or_return
write_type(w, info.elem, &n) or_return
case Type_Info_Soa_Pointer:
io.write_string(w, "#soa ^", &n) or_return
write_type(w, info.elem, &n) or_return
case Type_Info_Procedure:
io.write_string(w, "proc", &n) or_return
if info.params == nil {
+10
View File
@@ -176,6 +176,9 @@ Type_Info_Matrix :: struct {
column_count: int,
// Total element count = column_count * elem_stride
}
Type_Info_Soa_Pointer :: struct {
elem: ^Type_Info,
}
Type_Info_Flag :: enum u8 {
Comparable = 0,
@@ -217,6 +220,7 @@ Type_Info :: struct {
Type_Info_Relative_Pointer,
Type_Info_Relative_Slice,
Type_Info_Matrix,
Type_Info_Soa_Pointer,
},
}
@@ -403,6 +407,12 @@ Raw_Cstring :: struct {
data: [^]byte,
}
Raw_Soa_Pointer :: struct {
data: rawptr,
index: int,
}
/*
// Defined internally by the compiler
+61 -54
View File
@@ -143,7 +143,7 @@ free_all :: proc{mem_free_all}
@builtin
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(str), allocator, loc)
return mem_free_with_size(raw_data(str), len(str), allocator, loc)
}
@builtin
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
@@ -151,17 +151,24 @@ delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #cal
}
@builtin
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(array), array.allocator, loc)
return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
}
@builtin
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(array), allocator, loc)
return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
}
@builtin
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
Entry :: struct {
hash: uintptr,
next: int,
key: K,
value: V,
}
raw := transmute(Raw_Map)m
err := delete_slice(raw.hashes, raw.entries.allocator, loc)
err1 := mem_free(raw.entries.data, raw.entries.allocator, loc)
err1 := mem_free_with_size(raw.entries.data, raw.entries.cap*size_of(Entry), raw.entries.allocator, loc)
if err == nil {
err = err1
}
@@ -335,68 +342,80 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
@builtin
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int {
if array == nil {
return
return 0
}
if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1)
_ = reserve(array, cap, loc)
}
if cap(array)-len(array) > 0 {
a := (^Raw_Dynamic_Array)(array)
when size_of(E) != 0 {
data := ([^]E)(a.data)
assert(condition=data != nil, loc=loc)
data[a.len] = arg
when size_of(E) == 0 {
array.len += 1
return 1
} else {
if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1)
_ = reserve(array, cap, loc)
}
a.len += 1
if cap(array)-len(array) > 0 {
a := (^Raw_Dynamic_Array)(array)
when size_of(E) != 0 {
data := ([^]E)(a.data)
assert(condition=data != nil, loc=loc)
data[a.len] = arg
}
a.len += 1
return 1
}
return 0
}
}
@builtin
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) {
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int {
if array == nil {
return
return 0
}
arg_len := len(args)
if arg_len <= 0 {
return
return 0
}
if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len)
_ = reserve(array, cap, loc)
}
arg_len = min(cap(array)-len(array), arg_len)
if arg_len > 0 {
a := (^Raw_Dynamic_Array)(array)
when size_of(E) != 0 {
data := ([^]E)(a.data)
assert(condition=data != nil, loc=loc)
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
when size_of(E) == 0 {
array.len += arg_len
return arg_len
} else {
if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len)
_ = reserve(array, cap, loc)
}
a.len += arg_len
arg_len = min(cap(array)-len(array), arg_len)
if arg_len > 0 {
a := (^Raw_Dynamic_Array)(array)
when size_of(E) != 0 {
data := ([^]E)(a.data)
assert(condition=data != nil, loc=loc)
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
}
a.len += arg_len
}
return arg_len
}
}
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
@builtin
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) {
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> int {
args := transmute([]E)arg
append_elems(array=array, args=args, loc=loc)
return append_elems(array=array, args=args, loc=loc)
}
// The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
@builtin
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) {
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int) {
for arg in args {
append(array = array, args = transmute([]E)(arg), loc = loc)
n += append(array = array, args = transmute([]E)(arg), loc = loc)
}
return
}
// The append built-in procedure appends elements to the end of a dynamic array
@@ -404,11 +423,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
@builtin
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) {
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int {
if array == nil {
return
return 0
}
prev_len := len(array)
resize(array, len(array)+1)
return len(array)-prev_len
}
@@ -779,17 +800,3 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! {
}
p("not yet implemented", message, loc)
}
@builtin
@(disabled=ODIN_DISABLE_ASSERT)
unreachable :: proc(message := "", loc := #caller_location) -> ! {
p := context.assertion_failure_proc
if p == nil {
p = default_assertion_failure_proc
}
if message != "" {
p("internal error", message, loc)
} else {
p("internal error", "entered unreachable code", loc)
}
}
+7 -3
View File
@@ -29,11 +29,15 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
new_size := cap * elem_size
allocator := array.allocator
new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc)
new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
if err != nil {
return false
}
if new_data != nil || elem_size == 0 {
if elem_size == 0 {
array.data = raw_data(new_data)
array.cap = cap
return true
} else if new_data != nil {
array.data = raw_data(new_data)
array.cap = min(cap, len(new_data)/elem_size)
return true
@@ -59,7 +63,7 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c
new_size := new_cap * elem_size
allocator := array.allocator
new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc)
new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
if err != nil {
return
}
+8 -5
View File
@@ -194,12 +194,15 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l
new_size := new_count*size_of(T)
new_data, err := mem_resize(array.data, old_size, new_size, align_of(T), allocator, loc)
if new_data == nil || err != nil {
if err != nil {
return false
}
array.data = new_data
array.len = new_count
return true
if new_data != nil || size_of(E) == 0 {
array.data = raw_data(new_data)
array.len = new_count
return true
}
return false
}
__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) {
@@ -207,7 +210,7 @@ __dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_loc
m.hashes[i] = -1
}
for i in 0 ..< m.entries.len {
for i in 0..<m.entries.len {
entry_header := __dynamic_map_get_entry(header, i)
entry_hash := __get_map_hash_from_entry(header, entry_header)
entry_header.next = -1
+61 -37
View File
@@ -103,7 +103,7 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
if data == nil {
return nil
}
if len < 0 {
if len <= 0 {
return data
}
intrinsics.mem_zero(data, len)
@@ -111,22 +111,18 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
}
mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil {
return dst
if src != nil && dst != src && len > 0 {
// NOTE(bill): This _must_ be implemented like C's memmove
intrinsics.mem_copy(dst, src, len)
}
// NOTE(bill): This _must_ be implemented like C's memmove
intrinsics.mem_copy(dst, src, len)
return dst
}
mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil {
return dst
if src != nil && dst != src && len > 0 {
// NOTE(bill): This _must_ be implemented like C's memcpy
intrinsics.mem_copy_non_overlapping(dst, src, len)
}
// NOTE(bill): This _must_ be implemented like C's memcpy
intrinsics.mem_copy_non_overlapping(dst, src, len)
return dst
}
@@ -142,28 +138,38 @@ mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNM
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
}
mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
if size == 0 {
mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if size == 0 || allocator.procedure == nil {
return nil, nil
}
if allocator.procedure == nil {
return nil, nil
}
data, err := allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
return raw_data(data), err
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
}
mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil {
return .None
}
if allocator.procedure == nil {
return .None
if ptr == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc)
return err
}
mem_free_with_size :: #force_inline proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, byte_count, loc)
return err
}
mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if bytes == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, raw_data(bytes), len(bytes), loc)
return err
}
mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
if allocator.procedure != nil {
_, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc)
@@ -171,21 +177,34 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle
return
}
mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (new_ptr: rawptr, err: Allocator_Error) {
new_data: []byte
switch {
case allocator.procedure == nil:
return
case new_size == 0:
new_data, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc)
case ptr == nil:
new_data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
case:
new_data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if allocator.procedure == nil {
return nil, nil
}
new_ptr = raw_data(new_data)
return
if new_size == 0 {
if ptr != nil {
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
return nil, err
}
return nil, nil
} else if ptr == nil {
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
} else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 {
return ([^]byte)(ptr)[:old_size], nil
}
data, err := allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return data, err
}
copy(data, ([^]byte)(ptr)[:old_size])
_, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
}
return data, err
}
memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
switch {
case n == 0: return true
@@ -341,7 +360,12 @@ string_eq :: proc "contextless" (lhs, rhs: string) -> bool {
string_cmp :: proc "contextless" (a, b: string) -> int {
x := transmute(Raw_String)a
y := transmute(Raw_String)b
return memory_compare(x.data, y.data, min(x.len, y.len))
ret := memory_compare(x.data, y.data, min(x.len, y.len))
if ret == 0 && x.len != y.len {
return -1 if x.len < y.len else +1
}
return ret
}
string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) }
+3
View File
@@ -228,6 +228,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
case Type_Info_Multi_Pointer:
print_string("[^]")
print_type(info.elem)
case Type_Info_Soa_Pointer:
print_string("#soa ^")
print_type(info.elem)
case Type_Info_Procedure:
print_string("proc")
if info.params == nil {
+19 -9
View File
@@ -6,7 +6,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
@(private="file")
@(default_calling_convention="stdcall")
foreign lib {
RtlMoveMemory :: proc(dst, src: rawptr, length: int) ---
RtlMoveMemory :: proc(dst, s: rawptr, length: int) ---
RtlFillMemory :: proc(dst: rawptr, length: int, fill: i32) ---
}
@@ -40,24 +40,34 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
@(link_name="memmove", linkage="strong", require)
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
if dst != src {
d, s := ([^]byte)(dst), ([^]byte)(src)
d, s := ([^]byte)(dst), ([^]byte)(src)
if d == s || len == 0 {
return dst
}
if d > s && uintptr(d)-uintptr(s) < uintptr(len) {
for i := len-1; i >= 0; i -= 1 {
d[i] = s[i]
}
return dst
}
return dst
if s > d && uintptr(s)-uintptr(d) < uintptr(len) {
for i := 0; i < len; i += 1 {
d[i] = s[i]
}
return dst
}
return memcpy(dst, src, len)
}
@(link_name="memcpy", linkage="strong", require)
memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
if dst != src {
d, s := ([^]byte)(dst), ([^]byte)(src)
for i := len-1; i >= 0; i -= 1 {
d, s := ([^]byte)(dst), ([^]byte)(src)
if d != s {
for i := 0; i < len; i += 1 {
d[i] = s[i]
}
}
return dst
return d
}
} else {
+2 -2
View File
@@ -14,14 +14,14 @@ _ :: mem
Turn a pointer and a length into a slice.
*/
from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T {
return ([^]T)(ptr)[:count]
return ([^]T)(ptr)[:count]
}
/*
Turn a pointer and a length into a byte slice.
*/
bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte {
return ([^]byte)(ptr)[:byte_count]
return ([^]byte)(ptr)[:byte_count]
}
/*
+6 -1
View File
@@ -684,5 +684,10 @@ compare_f64s :: proc(a, b: f64) -> int {
compare_strings :: proc(a, b: string) -> int {
x := transmute(mem.Raw_String)a
y := transmute(mem.Raw_String)b
return mem.compare_byte_ptrs(x.data, y.data, min(x.len, y.len))
ret := mem.compare_byte_ptrs(x.data, y.data, min(x.len, y.len))
if ret == 0 && x.len != y.len {
return -1 if x.len < y.len else +1
}
return ret
}
+31 -18
View File
@@ -2,11 +2,13 @@ package strconv
import "core:unicode/utf8"
parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
parse_bool :: proc(s: string, n: ^int = nil) -> (result: bool = false, ok: bool) {
switch s {
case "1", "t", "T", "true", "TRUE", "True":
if n != nil { n^ = len(s) }
return true, true
case "0", "f", "F", "false", "FALSE", "False":
if n != nil { n^ = len(s) }
return false, true
}
return
@@ -32,10 +34,13 @@ _digit_value :: proc(r: rune) -> int {
// n, ok := strconv.parse_i64_of_base("-1234eeee", 10);
// assert(n == -1234 && ok);
// ```
parse_i64_of_base :: proc(str: string, base: int) -> (value: i64, ok: bool) {
parse_i64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i64, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -87,8 +92,9 @@ parse_i64_of_base :: proc(str: string, base: int) -> (value: i64, ok: bool) {
// n, ok = strconv.parse_i64_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_i64_maybe_prefixed :: proc(str: string) -> (value: i64, ok: bool) {
parse_i64_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: i64, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -155,9 +161,10 @@ parse_i64 :: proc{parse_i64_maybe_prefixed, parse_i64_of_base}
// n, ok = strconv.parse_u64_of_base("5678eeee", 16);
// assert(n == 0x5678eeee && ok);
// ```
parse_u64_of_base :: proc(str: string, base: int) -> (value: u64, ok: bool) {
parse_u64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u64, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -198,8 +205,9 @@ parse_u64_of_base :: proc(str: string, base: int) -> (value: u64, ok: bool) {
// n, ok = strconv.parse_u64_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_u64_maybe_prefixed :: proc(str: string) -> (value: u64, ok: bool) {
parse_u64_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u64, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -259,11 +267,11 @@ parse_u64 :: proc{parse_u64_maybe_prefixed, parse_u64_of_base}
// n, ok = strconv.parse_int("0xffff"); // with prefix and inferred base
// assert(n == 0xffff && ok);
// ```
parse_int :: proc(s: string, base := 0) -> (value: int, ok: bool) {
parse_int :: proc(s: string, base := 0, n: ^int = nil) -> (value: int, ok: bool) {
v: i64 = ---
switch base {
case 0: v, ok = parse_i64_maybe_prefixed(s)
case: v, ok = parse_i64_of_base(s, base)
case 0: v, ok = parse_i64_maybe_prefixed(s, n)
case: v, ok = parse_i64_of_base(s, base, n)
}
value = int(v)
return
@@ -289,11 +297,11 @@ parse_int :: proc(s: string, base := 0) -> (value: int, ok: bool) {
// n, ok = strconv.parse_uint("0xffff"); // with prefix and inferred base
// assert(n == 0xffff && ok);
// ```
parse_uint :: proc(s: string, base := 0) -> (value: uint, ok: bool) {
parse_uint :: proc(s: string, base := 0, n: ^int = nil) -> (value: uint, ok: bool) {
v: u64 = ---
switch base {
case 0: v, ok = parse_u64_maybe_prefixed(s)
case: v, ok = parse_u64_of_base(s, base)
case 0: v, ok = parse_u64_maybe_prefixed(s, n)
case: v, ok = parse_u64_of_base(s, base, n)
}
value = uint(v)
return
@@ -309,10 +317,11 @@ parse_uint :: proc(s: string, base := 0) -> (value: uint, ok: bool) {
// n, ok := strconv.parse_i128_of_base("-1234eeee", 10);
// assert(n == -1234 && ok);
// ```
parse_i128_of_base :: proc(str: string, base: int) -> (value: i128, ok: bool) {
parse_i128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i128, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -364,8 +373,9 @@ parse_i128_of_base :: proc(str: string, base: int) -> (value: i128, ok: bool) {
// n, ok = strconv.parse_i128_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_i128_maybe_prefixed :: proc(str: string) -> (value: i128, ok: bool) {
parse_i128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: i128, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -432,9 +442,10 @@ parse_i128 :: proc{parse_i128_maybe_prefixed, parse_i128_of_base}
// n, ok = strconv.parse_u128_of_base("5678eeee", 16);
// assert(n == 0x5678eeee && ok);
// ```
parse_u128_of_base :: proc(str: string, base: int) -> (value: u128, ok: bool) {
parse_u128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u128, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -475,8 +486,9 @@ parse_u128_of_base :: proc(str: string, base: int) -> (value: u128, ok: bool) {
// n, ok = strconv.parse_u128_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_u128_maybe_prefixed :: proc(str: string) -> (value: u128, ok: bool) {
parse_u128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u128, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -535,9 +547,9 @@ parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
// n, ok = strconv.parse_f32("12.34");
// assert(n == 12.34 && ok);
// ```
parse_f32 :: proc(s: string) -> (value: f32, ok: bool) {
parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
v: f64 = ---
v, ok = parse_f64(s)
v, ok = parse_f64(s, n)
return f32(v), ok
}
@@ -553,8 +565,9 @@ parse_f32 :: proc(s: string) -> (value: f32, ok: bool) {
// n, ok = strconv.parse_f32("12.34");
// assert(n == 12.34 && ok);
// ```
parse_f64 :: proc(str: string) -> (value: f64, ok: bool) {
parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
+11 -11
View File
@@ -31,31 +31,31 @@ intern_destroy :: proc(m: ^Intern) {
// returns the `text` string from the intern map - gets set if it didnt exist yet
// the returned string lives as long as the map entry lives
intern_get :: proc(m: ^Intern, text: string) -> string {
entry := _intern_get_entry(m, text)
#no_bounds_check return string(entry.str[:entry.len])
intern_get :: proc(m: ^Intern, text: string) -> (str: string, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) or_return
#no_bounds_check return string(entry.str[:entry.len]), nil
}
// returns the `text` cstring from the intern map - gets set if it didnt exist yet
// the returned cstring lives as long as the map entry lives
intern_get_cstring :: proc(m: ^Intern, text: string) -> cstring {
entry := _intern_get_entry(m, text)
return cstring(&entry.str[0])
intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) or_return
return cstring(&entry.str[0]), nil
}
// looks up wether the `text` string exists in the map, returns the entry
// sets & allocates the entry if it wasnt set yet
_intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_check {
_intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check {
if prev, ok := m.entries[text]; ok {
return prev
return prev, nil
}
if m.allocator.procedure == nil {
m.allocator = context.allocator
}
entry_size := int(offset_of(Intern_Entry, str)) + len(text) + 1
ptr, _ := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator)
new_entry := (^Intern_Entry)(ptr)
bytes := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator) or_return
new_entry = (^Intern_Entry)(raw_data(bytes))
new_entry.len = len(text)
copy(new_entry.str[:new_entry.len], text)
@@ -63,5 +63,5 @@ _intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_
key := string(new_entry.str[:new_entry.len])
m.entries[key] = new_entry
return new_entry
return new_entry, nil
}
+24 -2
View File
@@ -15,18 +15,40 @@ foreign import Ntdll "system:Ntdll.lib"
@(default_calling_convention="stdcall")
foreign Ntdll {
RtlWaitOnAddress :: proc(Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> i32 ---
RtlNtStatusToDosError :: proc(status: i32) -> u32 ---
SetLastError :: proc(err: u32) ---
}
/*
NOTE(bill, 2022-08-17)
WaitOnAddress is implemented on top of RtlWaitOnAddress
BUT requires taking the return value of it and if it is non-zero
converting that status to a DOS error and then SetLastError
If this is not done, then things don't work as expected when
and error occurs
GODDAMN MICROSOFT!
*/
CustomWaitOnAddress :: proc "stdcall" (Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> bool {
status := RtlWaitOnAddress(Address, CompareAddress, AddressSize, Timeout)
if status != 0 {
SetLastError(RtlNtStatusToDosError(status))
}
return status == 0
}
_futex_wait :: proc(f: ^Futex, expect: u32) -> bool {
expect := expect
return 0 == RtlWaitOnAddress(f, &expect, size_of(expect), nil)
return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
}
_futex_wait_with_timeout :: proc(f: ^Futex, expect: u32, duration: time.Duration) -> bool {
expect := expect
// NOTE(bill): for some bizarre reason, this has be a negative number
timeout := -i64(duration / 100)
return 0 == RtlWaitOnAddress(f, &expect, size_of(expect), &timeout)
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
}
_futex_signal :: proc(f: ^Futex) {
+3 -3
View File
@@ -1568,7 +1568,7 @@ sys_gettid :: proc "contextless" () -> int {
}
sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: int, flags: uint) -> int {
return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags))
return cast(int)intrinsics.syscall(SYS_getrandom, uintptr(buf), uintptr(buflen), uintptr(flags))
}
sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> int {
@@ -1622,7 +1622,7 @@ sys_lseek :: proc "contextless" (fd: int, offset: i64, whence: int) -> i64 {
low := uintptr(offset & 0xFFFFFFFF)
high := uintptr(offset >> 32)
result: i64
res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence)))
res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, uintptr(&result), uintptr(whence)))
return res if res < 0 else result
}
}
@@ -1748,7 +1748,7 @@ sys_unlink :: proc "contextless" (path: cstring) -> int {
}
sys_unlinkat :: proc "contextless" (dfd: int, path: cstring, flag: int = 0) -> int {
return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), flag))
return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flag)))
}
sys_rmdir :: proc "contextless" (path: cstring) -> int {
+63
View File
@@ -0,0 +1,63 @@
//+build amd64
package sys_valgrind
import "core:intrinsics"
Callgrind_Client_Request :: enum uintptr {
Dump_Stats = 'C'<<24 | 'T'<<16,
Zero_Stats,
Toggle_Collect,
Dump_Stats_At,
Start_Instrumentation,
Stop_Instrumentation,
}
@(require_results)
callgrind_client_request_expr :: proc "c" (default: uintptr, request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
}
callgrind_client_request_stmt :: proc "c" (request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) {
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
}
// Dump current state of cost centres, and zero them afterwards.
dump_stats :: proc "c" () {
callgrind_client_request_stmt(.Dump_Stats, 0, 0, 0, 0, 0)
}
// Zero cost centres
zero_stats :: proc "c" () {
callgrind_client_request_stmt(.Zero_Stats, 0, 0, 0, 0, 0)
}
// Toggles collection state.
// The collection state specifies whether the happening of events should be noted or
// if they are to be ignored. Events are noted by increment of counters in a cost centre.
toggle_collect :: proc "c" () {
callgrind_client_request_stmt(.Toggle_Collect, 0, 0, 0, 0, 0)
}
// Dump current state of cost centres, and zero them afterwards.
// The argument is appended to a string stating the reason which triggered
// the dump. This string is written as a description field into the
// profile data dump.
dump_stats_at :: proc "c" (pos_str: rawptr) {
callgrind_client_request_stmt(.Dump_Stats_At, uintptr(pos_str), 0, 0, 0, 0)
}
// Start full callgrind instrumentation if not already switched on.
// When cache simulation is done, it will flush the simulated cache;
// this will lead to an artificial cache warmup phase afterwards with
// cache misses which would not have happened in reality.
start_instrumentation :: proc "c" () {
callgrind_client_request_stmt(.Start_Instrumentation, 0, 0, 0, 0, 0)
}
// Stop full callgrind instrumentation if not already switched off.
// This flushes Valgrinds translation cache, and does no additional instrumentation
// afterwards, which effectivly will run at the same speed as the "none" tool (ie. at minimal slowdown).
// Use this to bypass Callgrind aggregation for uninteresting code parts.
// To start Callgrind in this mode to ignore the setup phase, use the option "--instr-atstart=no".
stop_instrumentation :: proc "c" () {
callgrind_client_request_stmt(.Stop_Instrumentation, 0, 0, 0, 0, 0)
}
+169
View File
@@ -0,0 +1,169 @@
//+build amd64
package sys_valgrind
import "core:intrinsics"
Mem_Check_Client_Request :: enum uintptr {
Make_Mem_No_Access = 'M'<<24 | 'C'<<16,
Make_Mem_Undefined,
Make_Mem_Defined,
Discard,
Check_Mem_Is_Addressable,
Check_Mem_Is_Defined,
Do_Leak_Check,
Count_Leaks,
Get_Vbits,
Set_Vbits,
Create_Block,
Make_Mem_Defined_If_Addressable,
Count_Leak_Blocks,
Enable_Addr_Error_Reporting_In_Range,
Disable_Addr_Error_Reporting_In_Range,
}
@(require_results)
mem_check_client_request_expr :: proc "c" (default: uintptr, request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
}
mem_check_client_request_stmt :: proc "c" (request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) {
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
}
// Mark memory at `raw_data(qzz)` as unaddressable for `len(qzz)` bytes.
// Returns true when run on Valgrind and false otherwise.
make_mem_no_access :: proc "c" (qzz: []byte) -> bool {
return 0 != mem_check_client_request_expr(0, .Make_Mem_No_Access, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Mark memory at `raw_data(qzz)` as addressable but undefined for `len(qzz)` bytes.
// Returns true when run on Valgrind and false otherwise.
make_mem_undefined :: proc "c" (qzz: []byte) -> bool {
return 0 != mem_check_client_request_expr(0, .Make_Mem_Undefined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Mark memory at `raw_data(qzz)` as addressable for `len(qzz)` bytes.
// Returns true when run on Valgrind and false otherwise.
make_mem_defined :: proc "c" (qzz: []byte) -> bool {
return 0 != mem_check_client_request_expr(0, .Make_Mem_Defined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Check that memory at `raw_data(qzz)` is addressable for `len(qzz)` bytes.
// If suitable addressibility is not established, Valgrind prints an error
// message and returns the address of the first offending byte.
// Otherwise it returns zero.
check_mem_is_addressable :: proc "c" (qzz: []byte) -> uintptr {
return mem_check_client_request_expr(0, .Check_Mem_Is_Addressable, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Check that memory at `raw_data(qzz)` is addressable and defined for `len(qzz)` bytes.
// If suitable addressibility and definedness are not established,
// Valgrind prints an error message and returns the address of the first
// offending byte. Otherwise it returns zero.
check_mem_is_defined :: proc "c" (qzz: []byte) -> uintptr {
return mem_check_client_request_expr(0, .Check_Mem_Is_Defined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Similar to `make_mem_defined(qzz)` except that addressability is not altered:
// bytes which are addressable are marked as defined, but those which
// are not addressable are left unchanged.
// Returns true when run on Valgrind and false otherwise.
make_mem_defined_if_addressable :: proc "c" (qzz: []byte) -> bool {
return 0 != mem_check_client_request_expr(0, .Make_Mem_Defined_If_Addressable, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Create a block-description handle.
// The description is an ascii string which is included in any messages
// pertaining to addresses within the specified memory range.
// Has no other effect on the properties of the memory range.
create_block :: proc "c" (qzz: []u8, desc: cstring) -> bool {
return 0 != mem_check_client_request_expr(0, .Create_Block, uintptr(raw_data(qzz)), uintptr(len(qzz)), uintptr(rawptr(desc)), 0, 0)
}
// Discard a block-description-handle. Returns true for an invalid handle, false for a valid handle.
discard :: proc "c" (blk_index: uintptr) -> bool {
return 0 != mem_check_client_request_expr(0, .Discard, 0, blk_index, 0, 0, 0)
}
// Do a full memory leak check (like `--leak-check=full`) mid-execution.
leak_check :: proc "c" () {
mem_check_client_request_stmt(.Do_Leak_Check, 0, 0, 0, 0, 0)
}
// Same as `leak_check()` but only showing the entries for which there was an increase
// in leaked bytes or leaked nr of blocks since the previous leak search.
added_leak_check :: proc "c" () {
mem_check_client_request_stmt(.Do_Leak_Check, 0, 1, 0, 0, 0)
}
// Same as `added_leak_check()` but showing entries with increased or decreased
// leaked bytes/blocks since previous leak search.
changed_leak_check :: proc "c" () {
mem_check_client_request_stmt(.Do_Leak_Check, 0, 2, 0, 0, 0)
}
// Do a summary memory leak check (like `--leak-check=summary`) mid-execution.
quick_leak_check :: proc "c" () {
mem_check_client_request_stmt(.Do_Leak_Check, 1, 0, 0, 0, 0)
}
Count_Result :: struct {
leaked: uint,
dubious: uint,
reachable: uint,
suppressed: uint,
}
count_leaks :: proc "c" () -> (res: Count_Result) {
mem_check_client_request_stmt(
.Count_Leaks,
uintptr(&res.leaked),
uintptr(&res.dubious),
uintptr(&res.reachable),
uintptr(&res.suppressed),
0,
)
return
}
count_leak_blocks :: proc "c" () -> (res: Count_Result) {
mem_check_client_request_stmt(
.Count_Leak_Blocks,
uintptr(&res.leaked),
uintptr(&res.dubious),
uintptr(&res.reachable),
uintptr(&res.suppressed),
0,
)
return
}
// Get the validity data for addresses zza and copy it
// into the provided zzvbits array. Return values:
// 0 - if not running on valgrind
// 1 - success
// 2 - [previously indicated unaligned arrays; these are now allowed]
// 3 - if any parts of zzsrc/zzvbits are not addressable.
// The metadata is not copied in cases 0, 2 or 3 so it should be
// impossible to segfault your system by using this call.
get_vbits :: proc(zza, zzvbits: []byte) -> u8 {
// assert requires a `context` thus these procedures cannot `proc "c"`
assert(len(zzvbits) >= len(zza)/8)
return u8(mem_check_client_request_expr(0, .Get_Vbits, uintptr(raw_data(zza)), uintptr(raw_data(zzvbits)), uintptr(len(zza)), 0, 0))
}
// Set the validity data for addresses zza, copying it
// from the provided zzvbits array. Return values:
// 0 - if not running on valgrind
// 1 - success
// 2 - [previously indicated unaligned arrays; these are now allowed]
// 3 - if any parts of zza/zzvbits are not addressable.
// The metadata is not copied in cases 0, 2 or 3 so it should be
// impossible to segfault your system by using this call.
set_vbits :: proc(zzvbits, zza: []byte) -> u8 {
// assert requires a `context` thus these procedures cannot `proc "c"`
assert(len(zzvbits) >= len(zza)/8)
return u8(mem_check_client_request_expr(0, .Set_Vbits, uintptr(raw_data(zza)), uintptr(raw_data(zzvbits)), uintptr(len(zza)), 0, 0))
}
// (Re-)enable reporting of addressing errors in the specified address range.
enable_addr_error_reporting_in_range :: proc "c" (qzz: []byte) -> uintptr {
return mem_check_client_request_expr(0, .Enable_Addr_Error_Reporting_In_Range, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Disable reporting of addressing errors in the specified address range.
disable_addr_error_reporting_in_range :: proc "c" (qzz: []byte) -> uintptr {
return mem_check_client_request_expr(0, .Disable_Addr_Error_Reporting_In_Range, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
+182
View File
@@ -0,0 +1,182 @@
//+build amd64
package sys_valgrind
import "core:intrinsics"
Client_Request :: enum uintptr {
Running_On_Valgrind = 4097,
Discard_Translations = 4098,
Client_Call0 = 4353,
Client_Call1 = 4354,
Client_Call2 = 4355,
Client_Call3 = 4356,
Count_Errors = 4609,
Gdb_Monitor_Command = 4610,
Malloc_Like_Block = 4865,
Resize_Inplace_Block = 4875,
Free_Like_Block = 4866,
Create_Mem_Pool = 4867,
Destroy_Mem_Pool = 4868,
Mem_Pool_Alloc = 4869,
Mem_Pool_Free = 4870,
Mem_Pool_Trim = 4871,
Move_Mem_Pool = 4872,
Mem_Pool_Change = 4873,
Mem_Pool_Exists = 4874,
Printf = 5121,
Printf_Backtrace = 5122,
Printf_Valist_By_Ref = 5123,
Printf_Backtrace_Valist_By_Ref = 5124,
Stack_Register = 5377,
Stack_Deregister = 5378,
Stack_Change = 5379,
Load_Pdb_Debug_Info = 5633,
Map_Ip_To_Src_Loc = 5889,
Change_Err_Disablement = 6145,
Vex_Init_For_Iri = 6401,
Inner_Threads = 6402,
}
@(require_results)
client_request_expr :: proc "c" (default: uintptr, request: Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
}
client_request_stmt :: proc "c" (request: Client_Request, a0, a1, a2, a3, a4: uintptr) {
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
}
// Returns the number of Valgrinds this code is running under
// 0 - running natively
// 1 - running under Valgrind
// 2 - running under Valgrind which is running under another Valgrind
running_on_valgrind :: proc "c" () -> uintptr {
return client_request_expr(0, .Running_On_Valgrind, 0, 0, 0, 0, 0)
}
// Discard translation of code in the slice qzz. Useful if you are debugging a JIT-er or some such,
// since it provides a way to make sure valgrind will retranslate the invalidated area.
discard_translations :: proc "c" (qzz: []byte) {
client_request_stmt(.Discard_Translations, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
non_simd_call0 :: proc "c" (p: proc "c" (uintptr) -> uintptr) -> uintptr {
return client_request_expr(0, .Client_Call0, uintptr(rawptr(p)), 0, 0, 0, 0)
}
non_simd_call1 :: proc "c" (p: proc "c" (uintptr, uintptr) -> uintptr, a0: uintptr) -> uintptr {
return client_request_expr(0, .Client_Call1, uintptr(rawptr(p)), a0, 0, 0, 0)
}
non_simd_call2 :: proc "c" (p: proc "c" (uintptr, uintptr, uintptr) -> uintptr, a0, a1: uintptr) -> uintptr {
return client_request_expr(0, .Client_Call2, uintptr(rawptr(p)), a0, a1, 0, 0)
}
non_simd_call3 :: proc "c" (p: proc "c" (uintptr, uintptr, uintptr, uintptr) -> uintptr, a0, a1, a2: uintptr) -> uintptr {
return client_request_expr(0, .Client_Call3, uintptr(rawptr(p)), a0, a1, a2, 0)
}
// Counts the number of errors that have been recorded by a tool.
count_errrors :: proc "c" () -> uint {
return uint(client_request_expr(0, .Count_Errors, 0, 0, 0, 0, 0))
}
monitor_command :: proc "c" (command: cstring) -> bool {
return 0 != client_request_expr(0, .Gdb_Monitor_Command, uintptr(rawptr(command)), 0, 0, 0, 0)
}
malloc_like_block :: proc "c" (mem: []byte, rz_b: uintptr, is_zeroed: bool) {
client_request_stmt(.Malloc_Like_Block, uintptr(raw_data(mem)), uintptr(len(mem)), rz_b, uintptr(is_zeroed), 0)
}
resize_inplace_block :: proc "c" (old_mem: []byte, new_size: uint, rz_b: uintptr) {
client_request_stmt(.Resize_Inplace_Block, uintptr(raw_data(old_mem)), uintptr(len(old_mem)), uintptr(new_size), rz_b, 0)
}
free_like_block :: proc "c" (addr: rawptr, rz_b: uintptr) {
client_request_stmt(.Free_Like_Block, uintptr(addr), rz_b, 0, 0, 0)
}
Mem_Pool_Flags :: distinct bit_set[Mem_Pool_Flag; uintptr]
Mem_Pool_Flag :: enum uintptr {
Auto_Free = 0,
Meta_Pool = 1,
}
// Create a memory pool.
create_mem_pool :: proc "c" (pool: rawptr, rz_b: uintptr, is_zeroed: bool, flags: Mem_Pool_Flags) {
client_request_stmt(.Create_Mem_Pool, uintptr(pool), rz_b, uintptr(is_zeroed), transmute(uintptr)flags, 0)
}
// Destroy a memory pool.
destroy_mem_pool :: proc "c" (pool: rawptr) {
client_request_stmt(.Destroy_Mem_Pool, uintptr(pool), 0, 0, 0, 0)
}
// Associate a section of memory with a memory pool.
mem_pool_alloc :: proc "c" (pool: rawptr, mem: []byte) {
client_request_stmt(.Mem_Pool_Alloc, uintptr(pool), uintptr(raw_data(mem)), uintptr(len(mem)), 0, 0)
}
// Disassociate a section of memory from a memory pool.
mem_pool_free :: proc "c" (pool: rawptr, addr: rawptr) {
client_request_stmt(.Mem_Pool_Free, uintptr(pool), uintptr(addr), 0, 0, 0)
}
// Disassociate parts of a section of memory outside a particular range.
mem_pool_trim :: proc "c" (pool: rawptr, mem: []byte) {
client_request_stmt(.Mem_Pool_Trim, uintptr(pool), uintptr(raw_data(mem)), uintptr(len(mem)), 0, 0)
}
// Resize and/or move a section of memory associated with a memory pool.
move_mem_pool :: proc "c" (pool_a, pool_b: rawptr) {
client_request_stmt(.Move_Mem_Pool, uintptr(pool_a), uintptr(pool_b), 0, 0, 0)
}
// Resize and/or move a section of memory associated with a memory pool.
mem_pool_change :: proc "c" (pool: rawptr, addr_a: rawptr, mem: []byte) {
client_request_stmt(.Mem_Pool_Change, uintptr(pool), uintptr(addr_a), uintptr(raw_data(mem)), uintptr(len(mem)), 0)
}
// Return true if a memory pool exists
mem_pool_exists :: proc "c" (pool: rawptr) -> bool {
return 0 != client_request_expr(0, .Mem_Pool_Exists, uintptr(pool), 0, 0, 0, 0)
}
// Mark a section of memory as being a stack. Returns a stack id.
stack_register :: proc "c" (stack: []byte) -> (stack_id: uintptr) {
ptr := uintptr(raw_data(stack))
return client_request_expr(0, .Stack_Register, ptr, ptr+uintptr(len(stack)), 0, 0, 0)
}
// Unmark a section of memory associated with a stack id as being a stack.
stack_deregister :: proc "c" (id: uintptr) {
client_request_stmt(.Stack_Deregister, id, 0, 0, 0, 0)
}
// Change the start and end address of the stack id with the `new_stack` slice.
stack_change :: proc "c" (id: uint, new_stack: []byte) {
ptr := uintptr(raw_data(new_stack))
client_request_stmt(.Stack_Change, uintptr(id), ptr, ptr + uintptr(len(new_stack)), 0, 0)
}
// Disable error reporting for the current thread/
// It behaves in a stack-like way, meaning you can safely call this multiple times
// given that `enable_error_reporting()` is called the same number of times to
// re-enable the error reporting.
// The first call of this macro disables reporting.
// Subsequent calls have no effect except to increase the number of `enable_error_reporting()`
// calls needed to re-enable reporting.
// Child threads do not inherit this setting from their parents;
// they are always created with reporting enabled.
disable_error_reporting :: proc "c" () {
client_request_stmt(.Change_Err_Disablement, 1, 0, 0, 0, 0)
}
// Re-enable error reporting
enable_error_reporting :: proc "c" () {
client_request_stmt(.Change_Err_Disablement, ~uintptr(0), 0, 0, 0, 0)
}
inner_threads :: proc "c" (qzz: rawptr) {
client_request_stmt(.Inner_Threads, uintptr(qzz), 0, 0, 0, 0)
}
// Map a code address to a source file name and line number.
// `buf64` must point to a 64-byte buffer in the caller's address space.
// The result will be dumped in there and is guaranteed to be zero terminated.
// If no info is found, the first byte is set to zero.
map_ip_to_src_loc :: proc "c" (addr: rawptr, buf64: ^[64]byte) -> uintptr {
return client_request_expr(0, .Map_Ip_To_Src_Loc, uintptr(addr), uintptr(buf64), 0, 0, 0)
}
+171 -259
View File
@@ -1148,6 +1148,156 @@ foreign wasi {
*/
how: sdflags_t,
) -> errno_t ---
/**
* Return a description of the given preopened file descriptor.
*/
fd_prestat_dir_name :: proc(
fd: fd_t,
/**
* A buffer into which to write the preopened directory name.
*/
path: string,
) -> errno_t ---
/**
* Create a directory.
* Note: This is similar to `mkdirat` in POSIX.
*/
path_create_directory :: proc(
fd: fd_t,
/**
* The path at which to create the directory.
*/
path: string,
) -> errno_t ---
/**
* Adjust the timestamps of a file or directory.
* Note: This is similar to `utimensat` in POSIX.
*/
path_filestat_set_times :: proc(
fd: fd_t,
/**
* Flags determining the method of how the path is resolved.
*/
flags: lookupflags_t,
/**
* The path of the file or directory to operate on.
*/
path: string,
/**
* The desired values of the data access timestamp.
*/
atim: timestamp_t,
/**
* The desired values of the data modification timestamp.
*/
mtim: timestamp_t,
/**
* A bitmask indicating which timestamps to adjust.
*/
fst_flags: fstflags_t,
) -> errno_t ---
/**
* Remove a directory.
* Return `errno::notempty` if the directory is not empty.
* Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
*/
path_remove_directory :: proc(
fd: fd_t,
/**
* The path to a directory to remove.
*/
path: string,
) -> errno_t ---
/**
* Create a hard link.
* Note: This is similar to `linkat` in POSIX.
*/
path_link :: proc(
old_fd: fd_t,
/**
* Flags determining the method of how the path is resolved.
*/
old_flags: lookupflags_t,
/**
* The source path from which to link.
*/
old_path: string,
/**
* The working directory at which the resolution of the new path starts.
*/
new_fd: fd_t,
/**
* The destination path at which to create the hard link.
*/
new_path: string,
) -> errno_t ---
/**
* Rename a file or directory.
* Note: This is similar to `renameat` in POSIX.
*/
path_rename :: proc(
fd: fd_t,
/**
* The source path of the file or directory to rename.
*/
old_path: string,
/**
* The working directory at which the resolution of the new path starts.
*/
new_fd: fd_t,
/**
* The destination path to which to rename the file or directory.
*/
new_path: string,
) -> errno_t ---
/**
* Create a symbolic link.
* Note: This is similar to `symlinkat` in POSIX.
*/
path_symlink :: proc(
/**
* The contents of the symbolic link.
*/
old_path: string,
fd: fd_t,
/**
* The destination path at which to create the symbolic link.
*/
new_path: string,
) -> errno_t ---
/**
* Unlink a file.
* Return `errno::isdir` if the path refers to a directory.
* Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
*/
path_unlink_file :: proc(
fd: fd_t,
/**
* The path to a file to unlink.
*/
path: string,
) -> errno_t ---
/**
* Write high-quality random data into a buffer.
* This function blocks when the implementation is unable to immediately
* provide sufficient high-quality random data.
* This function may execute slowly, so when large mounts of random data are
* required, it's advisable to use this function to seed a pseudo-random
* number generator, rather than to provide the random data directly.
*/
random_get :: proc(
/**
* The buffer to fill with random data.
*/
buf: []u8,
) -> errno_t ---
}
/**
@@ -1250,7 +1400,7 @@ fd_pread :: proc "c" (
*/
offset: filesize_t,
) -> (n: size_t, err: errno_t) {
err = wasi_fd_pread(fd, raw_data(iovs), len(iovs), offset, &n)
err = wasi_fd_pread(fd, iovs, offset, &n)
return
}
/**
@@ -1281,7 +1431,7 @@ fd_pwrite :: proc "c" (
*/
offset: filesize_t,
) -> (n: size_t, err: errno_t) {
err = wasi_fd_pwrite(fd, raw_data(iovs), len(iovs), offset, &n)
err = wasi_fd_pwrite(fd, iovs, offset, &n)
return
}
/**
@@ -1297,7 +1447,7 @@ fd_read :: proc "c" (
*/
iovs: []iovec_t,
) -> (n: size_t, err: errno_t) {
err = wasi_fd_read(fd, raw_data(iovs), len(iovs), &n)
err = wasi_fd_read(fd, iovs, &n)
return
}
/**
@@ -1324,7 +1474,7 @@ fd_readdir :: proc "c" (
*/
cookie: dircookie_t,
) -> (n: size_t, err: errno_t) {
err = wasi_fd_readdir(fd, raw_data(buf), len(buf), cookie, &n)
err = wasi_fd_readdir(fd, buf, cookie, &n)
return
}
/**
@@ -1370,7 +1520,7 @@ fd_write :: proc "c" (
*/
iovs: []ciovec_t,
) -> (n: size_t, err: errno_t) {
err = wasi_fd_write(fd, raw_data(iovs), len(iovs), &n)
err = wasi_fd_write(fd, iovs, &n)
return
}
/**
@@ -1390,7 +1540,7 @@ path_filestat_get :: proc "c" (
*/
path: string,
) -> (offset: filestat_t, err: errno_t) {
err = wasi_path_filestat_get(fd, flags, raw_data(path), len(path), &offset)
err = wasi_path_filestat_get(fd, flags, path, &offset)
return
}
/**
@@ -1432,7 +1582,7 @@ path_open :: proc "c" (
fs_rights_inheriting: rights_t,
fdflags: fdflags_t,
) -> (file: fd_t, err: errno_t) {
err = wasi_path_open(fd, dirflags, raw_data(path), len(path), oflags, fs_rights_base, fs_rights_inheriting, fdflags, &file)
err = wasi_path_open(fd, dirflags, path, oflags, fs_rights_base, fs_rights_inheriting, fdflags, &file)
return
}
/**
@@ -1452,7 +1602,7 @@ path_readlink :: proc "c" (
*/
buf: []u8,
) -> (n: size_t, err: errno_t) {
err = wasi_path_readlink(fd, raw_data(path), len(path), raw_data(buf), len(buf), &n)
err = wasi_path_readlink(fd, path, buf, &n)
return
}
/**
@@ -1495,7 +1645,7 @@ sock_recv :: proc "c" (
*/
ri_flags: riflags_t,
) -> (n: size_t, flags: roflags_t, err: errno_t) {
err = wasi_sock_recv(fd, raw_data(ri_data), len(ri_data), ri_flags, &n, &flags)
err = wasi_sock_recv(fd, ri_data, ri_flags, &n, &flags)
return
}
/**
@@ -1516,172 +1666,11 @@ sock_send :: proc "c" (
*/
si_flags: siflags_t,
) -> (n: size_t, err: errno_t) {
err = wasi_sock_send(fd, raw_data(si_data), len(si_data), si_flags, &n)
err = wasi_sock_send(fd, si_data, si_flags, &n)
return
}
/**
* Return a description of the given preopened file descriptor.
*/
fd_prestat_dir_name :: proc(
fd: fd_t,
/**
* A buffer into which to write the preopened directory name.
*/
path: string,
) -> errno_t {
return wasm_fd_prestat_dir_name(fd, raw_data(path), len(path))
}
/**
* Create a directory.
* Note: This is similar to `mkdirat` in POSIX.
*/
path_create_directory :: proc(
fd: fd_t,
/**
* The path at which to create the directory.
*/
path: string,
) -> errno_t {
return wasm_path_create_directory(fd, raw_data(path), len(path))
}
/**
* Adjust the timestamps of a file or directory.
* Note: This is similar to `utimensat` in POSIX.
*/
path_filestat_set_times :: proc(
fd: fd_t,
/**
* Flags determining the method of how the path is resolved.
*/
flags: lookupflags_t,
/**
* The path of the file or directory to operate on.
*/
path: string,
/**
* The desired values of the data access timestamp.
*/
atim: timestamp_t,
/**
* The desired values of the data modification timestamp.
*/
mtim: timestamp_t,
/**
* A bitmask indicating which timestamps to adjust.
*/
fst_flags: fstflags_t,
) -> errno_t {
return wasm_path_filestat_set_times(fd, flags, raw_data(path), len(path), atim, mtim, fst_flags)
}
/**
* Remove a directory.
* Return `errno::notempty` if the directory is not empty.
* Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
*/
path_remove_directory :: proc(
fd: fd_t,
/**
* The path to a directory to remove.
*/
path: string,
) -> errno_t {
return wasm_path_remove_directory(fd, raw_data(path), len(path))
}
/**
* Create a hard link.
* Note: This is similar to `linkat` in POSIX.
*/
path_link :: proc(
old_fd: fd_t,
/**
* Flags determining the method of how the path is resolved.
*/
old_flags: lookupflags_t,
/**
* The source path from which to link.
*/
old_path: string,
/**
* The working directory at which the resolution of the new path starts.
*/
new_fd: fd_t,
/**
* The destination path at which to create the hard link.
*/
new_path: string,
) -> errno_t {
return wasm_path_link(old_fd, old_flags, raw_data(old_path), len(old_path), new_fd, raw_data(new_path), len(new_path))
}
/**
* Rename a file or directory.
* Note: This is similar to `renameat` in POSIX.
*/
path_rename :: proc(
fd: fd_t,
/**
* The source path of the file or directory to rename.
*/
old_path: string,
/**
* The working directory at which the resolution of the new path starts.
*/
new_fd: fd_t,
/**
* The destination path to which to rename the file or directory.
*/
new_path: string,
) -> errno_t {
return wasm_path_rename(fd, raw_data(old_path), len(old_path), new_fd, raw_data(new_path), len(new_path))
}
/**
* Create a symbolic link.
* Note: This is similar to `symlinkat` in POSIX.
*/
path_symlink :: proc(
/**
* The contents of the symbolic link.
*/
old_path: string,
fd: fd_t,
/**
* The destination path at which to create the symbolic link.
*/
new_path: string,
) -> errno_t {
return wasm_path_symlink(raw_data(old_path), len(old_path), fd, raw_data(new_path), len(new_path))
}
/**
* Unlink a file.
* Return `errno::isdir` if the path refers to a directory.
* Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
*/
path_unlink_file :: proc(
fd: fd_t,
/**
* The path to a file to unlink.
*/
path: string,
) -> errno_t {
return wasm_path_unlink_file(fd, raw_data(path), len(path))
}
/**
* Write high-quality random data into a buffer.
* This function blocks when the implementation is unable to immediately
* provide sufficient high-quality random data.
* This function may execute slowly, so when large mounts of random data are
* required, it's advisable to use this function to seed a pseudo-random
* number generator, rather than to provide the random data directly.
*/
random_get :: proc(
/**
* The buffer to fill with random data.
*/
buf: []u8,
) -> errno_t {
return wasm_random_get(raw_data(buf), len(buf))
}
@@ -1722,8 +1711,7 @@ foreign wasi {
@(link_name="fd_pread")
wasi_fd_pread :: proc(
fd: fd_t,
iovs: [^]iovec_t,
iovs_len: size_t,
iovs: []iovec_t,
offset: filesize_t,
retptr0: ^size_t,
) -> errno_t ---
@@ -1735,23 +1723,20 @@ foreign wasi {
@(link_name="fd_pwrite")
wasi_fd_pwrite :: proc(
fd: fd_t,
iovs: [^]ciovec_t,
iovs_len: size_t,
iovs: []ciovec_t,
offset: filesize_t,
retptr0: ^size_t,
) -> errno_t ---
@(link_name="fd_read")
wasi_fd_read :: proc(
fd: fd_t,
iovs: [^]iovec_t,
iovs_len: size_t,
iovs: []iovec_t,
retptr0: ^size_t,
) -> errno_t ---
@(link_name="fd_readdir")
wasi_fd_readdir :: proc(
fd: fd_t,
buf: [^]u8,
buf_len: size_t,
buf: []u8,
cookie: dircookie_t,
retptr0: ^size_t,
) -> errno_t ---
@@ -1770,8 +1755,7 @@ foreign wasi {
@(link_name="fd_write")
wasi_fd_write :: proc(
fd: fd_t,
iovs: [^]ciovec_t,
iovs_len: size_t,
iovs: []ciovec_t,
retptr0: ^size_t,
) -> errno_t ---
@(link_name="path_filestat_get")
@@ -1781,16 +1765,14 @@ foreign wasi {
/**
* The path of the file or directory to inspect.
*/
path: [^]u8,
path_len: size_t,
path: string,
retptr0: ^filestat_t,
) -> errno_t ---
@(link_name="path_open")
wasi_path_open :: proc(
fd: fd_t,
dirflags: lookupflags_t,
path: [^]u8,
path_len: size_t,
path: string,
oflags: oflags_t,
fs_rights_base: rights_t,
fs_rights_inheriting: rights_t,
@@ -1800,10 +1782,8 @@ foreign wasi {
@(link_name="path_readlink")
wasi_path_readlink :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
buf: [^]u8,
buf_len: size_t,
path: string,
buf: []u8,
retptr0: ^size_t,
) -> errno_t ---
@(link_name="poll_oneoff")
@@ -1816,8 +1796,7 @@ foreign wasi {
@(link_name="sock_recv")
wasi_sock_recv :: proc(
fd: fd_t,
ri_data: [^]iovec_t,
ri_data_len: size_t,
ri_data: []iovec_t,
ri_flags: riflags_t,
retptr0: ^size_t,
retptr1: ^roflags_t,
@@ -1825,75 +1804,8 @@ foreign wasi {
@(link_name="sock_send")
wasi_sock_send :: proc(
fd: fd_t,
si_data: [^]ciovec_t,
si_data_len: size_t,
si_data: []ciovec_t,
si_flags: siflags_t,
retptr0: ^size_t,
) -> errno_t ---
@(link_name="fd_prestat_dir_name")
wasm_fd_prestat_dir_name :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
) -> errno_t ---
@(link_name="path_create_directory")
wasm_path_create_directory :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
) -> errno_t ---
@(link_name="path_filestat_set_times")
wasm_path_filestat_set_times :: proc(
fd: fd_t,
flags: lookupflags_t,
path: [^]u8,
path_len: size_t,
atim: timestamp_t,
mtim: timestamp_t,
fst_flags: fstflags_t,
) -> errno_t ---
@(link_name="path_remove_directory")
wasm_path_remove_directory :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
) -> errno_t ---
@(link_name="path_link")
wasm_path_link :: proc(
old_fd: fd_t,
old_flags: lookupflags_t,
old_path: [^]u8,
old_path_len: size_t,
new_fd: fd_t,
new_path: [^]u8,
new_path_len: size_t,
) -> errno_t ---
@(link_name="path_rename")
wasm_path_rename :: proc(
fd: fd_t,
old_path: [^]u8,
old_path_len: size_t,
new_fd: fd_t,
new_path: [^]u8,
new_path_len: size_t,
) -> errno_t ---
@(link_name="path_symlink")
wasm_path_symlink :: proc(
old_path: [^]u8,
old_path_len: size_t,
fd: fd_t,
new_path: [^]u8,
new_path_len: size_t,
) -> errno_t ---
@(link_name="path_unlink_file")
wasm_path_unlink_file :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
) -> errno_t ---
@(link_name="random_get")
wasm_random_get :: proc(
buf: [^]u8,
buf_len: size_t,
) -> errno_t ---
}
+2 -2
View File
@@ -290,10 +290,10 @@ foreign kernel32 {
InitializeSRWLock :: proc(SRWLock: ^SRWLOCK) ---
AcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) ---
TryAcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) -> BOOL ---
TryAcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) -> BOOLEAN ---
ReleaseSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) ---
AcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) ---
TryAcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) -> BOOL ---
TryAcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) -> BOOLEAN ---
ReleaseSRWLockShared :: proc(SRWLock: ^SRWLOCK) ---
InitializeConditionVariable :: proc(ConditionVariable: ^CONDITION_VARIABLE) ---
+33 -2
View File
@@ -18,6 +18,7 @@ foreign user32 {
RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM ---
RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM ---
UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL ---
CreateWindowExW :: proc(
dwExStyle: DWORD,
@@ -41,6 +42,7 @@ foreign user32 {
GetTopWindow :: proc(hWnd: HWND) -> HWND ---
SetForegroundWindow :: proc(hWnd: HWND) -> BOOL ---
GetForegroundWindow :: proc() -> HWND ---
UpdateWindow :: proc(hWnd: HWND) -> BOOL ---
SetActiveWindow :: proc(hWnd: HWND) -> HWND ---
GetActiveWindow :: proc() -> HWND ---
@@ -94,6 +96,7 @@ foreign user32 {
GetSystemMetrics :: proc(nIndex: c_int) -> c_int ---
AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL ---
AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL ---
AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL ---
SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL ---
@@ -136,7 +139,19 @@ foreign user32 {
SetCursor :: proc(hCursor: HCURSOR) -> HCURSOR ---
EnumDisplaySettingsW :: proc(lpszDeviceName: LPCWSTR, iModeNum: DWORD, lpDevMode: ^DEVMODEW) -> BOOL ---
MonitorFromPoint :: proc(pt: POINT, dwFlags: Monitor_From_Flags) -> HMONITOR ---
MonitorFromRect :: proc(lprc: LPRECT, dwFlags: Monitor_From_Flags) -> HMONITOR ---
MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR ---
EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL ---
SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT ---
GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT ---
GetWindowDpiAwarenessContext :: proc(hwnd: HWND) -> DPI_AWARENESS_CONTEXT ---
GetDpiFromDpiAwarenessContext :: proc(value: DPI_AWARENESS_CONTEXT) -> UINT ---
GetDpiForWindow :: proc(hwnd: HWND) -> UINT ---
SetProcessDpiAwarenessContext :: proc(value: DPI_AWARENESS_CONTEXT) -> BOOL ---
BroadcastSystemMessageW :: proc(
flags: DWORD,
lpInfo: LPDWORD,
@@ -220,7 +235,7 @@ when ODIN_ARCH == .amd64 {
SetClassLongPtrW :: SetClassLongW
GetWindowLongPtrW :: GetWindowLongW
SetWindowLongPtrW :: GetWindowLongW
SetWindowLongPtrW :: SetWindowLongW
}
GET_SC_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_int {
@@ -246,3 +261,19 @@ GET_XBUTTON_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> WORD
MAKEINTRESOURCEW :: #force_inline proc "contextless" (#any_int i: int) -> LPWSTR {
return cast(LPWSTR)uintptr(WORD(i))
}
Monitor_From_Flags :: enum DWORD {
MONITOR_DEFAULTTONULL = 0x00000000, // Returns NULL
MONITOR_DEFAULTTOPRIMARY = 0x00000001, // Returns a handle to the primary display monitor
MONITOR_DEFAULTTONEAREST = 0x00000002, // Returns a handle to the display monitor that is nearest to the window
}
Monitor_Enum_Proc :: #type proc "stdcall" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL
USER_DEFAULT_SCREEN_DPI :: 96
DPI_AWARENESS_CONTEXT :: distinct HANDLE
DPI_AWARENESS_CONTEXT_UNAWARE :: DPI_AWARENESS_CONTEXT(~uintptr(0)) // -1
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(1)) // -2
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(2)) // -3
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 :: DPI_AWARENESS_CONTEXT(~uintptr(3)) // -4
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED :: DPI_AWARENESS_CONTEXT(~uintptr(4)) // -5
+1 -1
View File
@@ -62,7 +62,7 @@ GetExtensionsStringARBType :: #type proc "c" (HDC) -> cstring
// Procedures
wglCreateContextAttribsARB: CreateContextAttribsARBType
wglChoosePixelFormatARB: ChoosePixelFormatARBType
wglSwapIntervalExt: SwapIntervalEXTType
wglSwapIntervalEXT: SwapIntervalEXTType
wglGetExtensionsStringARB: GetExtensionsStringARBType
+147
View File
@@ -0,0 +1,147 @@
// +build windows
package sys_windows
// WGL_ARB_buffer_region
WGL_FRONT_COLOR_BUFFER_BIT_ARB :: 0x00000001
WGL_BACK_COLOR_BUFFER_BIT_ARB :: 0x00000002
WGL_DEPTH_BUFFER_BIT_ARB :: 0x00000004
WGL_STENCIL_BUFFER_BIT_ARB :: 0x00000008
wglCreateBufferRegionARBType :: #type proc "c" (hDC: HDC, iLayerPlane: c_int, uType: UINT) -> HANDLE
wglDeleteBufferRegionARBType :: #type proc "c" (hRegion: HANDLE)
wglSaveBufferRegionARBType :: #type proc "c" (hRegion: HANDLE, x: c_int, y: c_int, width: c_int, height: c_int) -> BOOL
wglRestoreBufferRegionARBType :: #type proc "c" (hRegion: HANDLE, x: c_int, y: c_int, width: c_int, height: c_int, xSrc: c_int, ySrc: c_int) -> BOOL
// wglCreateBufferRegionARB: wglCreateBufferRegionARBType
// wglDeleteBufferRegionARB: wglDeleteBufferRegionARBType
// wglSaveBufferRegionARB: wglSaveBufferRegionARBType
// wglRestoreBufferRegionARB: wglRestoreBufferRegionARBType
// WGL_ARB_context_flush_control
WGL_CONTEXT_RELEASE_BEHAVIOR_ARB :: 0x2097
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB :: 0
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :: 0x2098
// WGL_ARB_create_context
WGL_CONTEXT_DEBUG_BIT_ARB :: 0x0001
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092
WGL_CONTEXT_LAYER_PLANE_ARB :: 0x2093
WGL_CONTEXT_FLAGS_ARB :: 0x2094
ERROR_INVALID_VERSION_ARB :: 0x2095
// WGL_ARB_create_context_no_error
WGL_CONTEXT_OPENGL_NO_ERROR_ARB :: 0x31B3
// WGL_ARB_create_context_profile
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
ERROR_INVALID_PROFILE_ARB :: 0x2096
// WGL_ARB_create_context_robustness
WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB :: 0x00000004
WGL_LOSE_CONTEXT_ON_RESET_ARB :: 0x8252
WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB :: 0x8256
WGL_NO_RESET_NOTIFICATION_ARB :: 0x8261
// WGL_ARB_framebuffer_sRGB
WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB :: 0x20A9
// WGL_ARB_make_current_read
ERROR_INVALID_PIXEL_TYPE_ARB :: 0x2043
ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB :: 0x2054
wglMakeContextCurrentARBType :: #type proc "c" (hDrawDC: HDC, hReadDC:HDC, hglrc: HGLRC) -> BOOL
wglGetCurrentReadDCARBType :: #type proc "c" () -> HDC
// wglMakeContextCurrentARB: wglMakeContextCurrentARBType
// wglGetCurrentReadDCARB: wglGetCurrentReadDCARBType
// WGL_ARB_multisample
WGL_SAMPLE_BUFFERS_ARB :: 0x2041
WGL_SAMPLES_ARB :: 0x2042
// WGL_ARB_pbuffer
HPBUFFERARB :: distinct rawptr
WGL_DRAW_TO_PBUFFER_ARB :: 0x202D
WGL_MAX_PBUFFER_PIXELS_ARB :: 0x202E
WGL_MAX_PBUFFER_WIDTH_ARB :: 0x202F
WGL_MAX_PBUFFER_HEIGHT_ARB :: 0x2030
WGL_PBUFFER_LARGEST_ARB :: 0x2033
WGL_PBUFFER_WIDTH_ARB :: 0x2034
WGL_PBUFFER_HEIGHT_ARB :: 0x2035
WGL_PBUFFER_LOST_ARB :: 0x2036
wglCreatePbufferARBType :: #type proc "c" (hDC: HDC, iPixelFormat, iWidth, iHeight: c_int, piAttribList: [^]c_int) -> HPBUFFERARB
wglGetPbufferDCARBType :: #type proc "c" (hPbuffer: HPBUFFERARB) -> HDC
wglReleasePbufferDCARBType :: #type proc "c" (hPbuffer: HPBUFFERARB, hDC: HDC) -> c_int
wglDestroyPbufferARBType :: #type proc "c" (hPbuffer: HPBUFFERARB) -> BOOL
wglQueryPbufferARBType :: #type proc "c" (hPbuffer: HPBUFFERARB, iAttribute: c_int, piValue: ^c_int) -> BOOL
// wglCreatePbufferARB: wglCreatePbufferARBType
// wglGetPbufferDCARB: wglGetPbufferDCARBType
// wglReleasePbufferDCARB: wglReleasePbufferDCARBType
// wglDestroyPbufferARB: wglDestroyPbufferARBType
// wglQueryPbufferARB: wglQueryPbufferARBType
// WGL_ARB_pixel_format
WGL_NUMBER_PIXEL_FORMATS_ARB :: 0x2000
WGL_DRAW_TO_WINDOW_ARB :: 0x2001
WGL_DRAW_TO_BITMAP_ARB :: 0x2002
WGL_ACCELERATION_ARB :: 0x2003
WGL_NEED_PALETTE_ARB :: 0x2004
WGL_NEED_SYSTEM_PALETTE_ARB :: 0x2005
WGL_SWAP_LAYER_BUFFERS_ARB :: 0x2006
WGL_SWAP_METHOD_ARB :: 0x2007
WGL_NUMBER_OVERLAYS_ARB :: 0x2008
WGL_NUMBER_UNDERLAYS_ARB :: 0x2009
WGL_TRANSPARENT_ARB :: 0x200A
WGL_TRANSPARENT_RED_VALUE_ARB :: 0x2037
WGL_TRANSPARENT_GREEN_VALUE_ARB :: 0x2038
WGL_TRANSPARENT_BLUE_VALUE_ARB :: 0x2039
WGL_TRANSPARENT_ALPHA_VALUE_ARB :: 0x203A
WGL_TRANSPARENT_INDEX_VALUE_ARB :: 0x203B
WGL_SHARE_DEPTH_ARB :: 0x200C
WGL_SHARE_STENCIL_ARB :: 0x200D
WGL_SHARE_ACCUM_ARB :: 0x200E
WGL_SUPPORT_GDI_ARB :: 0x200F
WGL_SUPPORT_OPENGL_ARB :: 0x2010
WGL_DOUBLE_BUFFER_ARB :: 0x2011
WGL_STEREO_ARB :: 0x2012
WGL_PIXEL_TYPE_ARB :: 0x2013
WGL_COLOR_BITS_ARB :: 0x2014
WGL_RED_BITS_ARB :: 0x2015
WGL_RED_SHIFT_ARB :: 0x2016
WGL_GREEN_BITS_ARB :: 0x2017
WGL_GREEN_SHIFT_ARB :: 0x2018
WGL_BLUE_BITS_ARB :: 0x2019
WGL_BLUE_SHIFT_ARB :: 0x201A
WGL_ALPHA_BITS_ARB :: 0x201B
WGL_ALPHA_SHIFT_ARB :: 0x201C
WGL_ACCUM_BITS_ARB :: 0x201D
WGL_ACCUM_RED_BITS_ARB :: 0x201E
WGL_ACCUM_GREEN_BITS_ARB :: 0x201F
WGL_ACCUM_BLUE_BITS_ARB :: 0x2020
WGL_ACCUM_ALPHA_BITS_ARB :: 0x2021
WGL_DEPTH_BITS_ARB :: 0x2022
WGL_STENCIL_BITS_ARB :: 0x2023
WGL_AUX_BUFFERS_ARB :: 0x2024
WGL_NO_ACCELERATION_ARB :: 0x2025
WGL_GENERIC_ACCELERATION_ARB :: 0x2026
WGL_FULL_ACCELERATION_ARB :: 0x2027
WGL_SWAP_EXCHANGE_ARB :: 0x2028
WGL_SWAP_COPY_ARB :: 0x2029
WGL_SWAP_UNDEFINED_ARB :: 0x202A
WGL_TYPE_RGBA_ARB :: 0x202B
WGL_TYPE_COLORINDEX_ARB :: 0x202C
wglGetPixelFormatAttribivARBType :: #type proc "c" (hdc: HDC, iPixelFormat, iLayerPlane: c_int, nAttributes: UINT, piAttributes: [^]c_int, piValues: [^]c_int) -> BOOL
wglGetPixelFormatAttribfvARBType :: #type proc "c" (hdc: HDC, iPixelFormat, iLayerPlane: c_int, nAttributes: UINT, piAttributes: [^]c_int, pfValues: [^]f32) -> BOOL
// wglGetPixelFormatAttribivARB: wglGetPixelFormatAttribivARBType
// wglGetPixelFormatAttribfvARB: wglGetPixelFormatAttribfvARBType
// WGL_ARB_pixel_format_float
WGL_TYPE_RGBA_FLOAT_ARB :: 0x21A0
+39
View File
@@ -153,6 +153,7 @@ BM_CLICK :: 0x00f5
BM_GETIMAGE :: 0x00f6
BM_SETIMAGE :: 0x00f7
BM_SETDONTCLICK :: 0x00f8
WM_INPUT_DEVICE_CHANGE :: 0x00fe
WM_INPUT :: 0x00ff
WM_KEYDOWN :: 0x0100
WM_KEYFIRST :: 0x0100
@@ -165,6 +166,7 @@ WM_SYSCHAR :: 0x0106
WM_SYSDEADCHAR :: 0x0107
WM_UNICHAR :: 0x0109
WM_KEYLAST :: 0x0109
UNICODE_NOCHAR :: 0xFFFF
WM_WNT_CONVERTREQUESTEX :: 0x0109
WM_CONVERTREQUEST :: 0x010a
WM_CONVERTRESULT :: 0x010b
@@ -279,6 +281,27 @@ WM_ENTERSIZEMOVE :: 0x0231
WM_EXITSIZEMOVE :: 0x0232
WM_DROPFILES :: 0x0233
WM_MDIREFRESHMENU :: 0x0234
WM_POINTERDEVICECHANGE :: 0x0238
WM_POINTERDEVICEINRANGE :: 0x0239
WM_POINTERDEVICEOUTOFRANGE :: 0x023a
WM_TOUCH :: 0x0240
WM_NCPOINTERUPDATE :: 0x0241
WM_NCPOINTERDOWN :: 0x0242
WM_NCPOINTERUP :: 0x0243
WM_POINTERUPDATE :: 0x0245
WM_POINTERDOWN :: 0x0246
WM_POINTERUP :: 0x0247
WM_POINTERENTER :: 0x0249
WM_POINTERLEAVE :: 0x024a
WM_POINTERACTIVATE :: 0x024b
WM_POINTERCAPTURECHANGED :: 0x024c
WM_TOUCHHITTESTING :: 0x024d
WM_POINTERWHEEL :: 0x024e
WM_POINTERHWHEEL :: 0x024f
DM_POINTERHITTEST :: 0x0250
WM_POINTERROUTEDTO :: 0x0251
WM_POINTERROUTEDAWAY :: 0x0252
WM_POINTERROUTEDRELEASED :: 0x0253
WM_IME_REPORT :: 0x0280
WM_IME_SETCONTEXT :: 0x0281
WM_IME_NOTIFY :: 0x0282
@@ -295,6 +318,13 @@ WM_NCMOUSEHOVER :: 0x02a0
WM_MOUSEHOVER :: 0x02a1
WM_NCMOUSELEAVE :: 0x02a2
WM_MOUSELEAVE :: 0x02a3
WM_WTSSESSION_CHANGE :: 0x02b1
WM_TABLET_FIRST :: 0x02c0
WM_TABLET_LAST :: 0x02df
WM_DPICHANGED :: 0x02e0
WM_DPICHANGED_BEFOREPARENT :: 0x02e2
WM_DPICHANGED_AFTERPARENT :: 0x02e3
WM_GETDPISCALEDSIZE :: 0x02e4
WM_CUT :: 0x0300
WM_COPY :: 0x0301
WM_PASTE :: 0x0302
@@ -317,6 +347,15 @@ WM_HOTKEY :: 0x0312
WM_PRINT :: 0x0317
WM_PRINTCLIENT :: 0x0318
WM_APPCOMMAND :: 0x0319
WM_THEMECHANGED :: 0x031A
WM_CLIPBOARDUPDATE :: 0x031D
WM_DWMCOMPOSITIONCHANGED :: 0x031E
WM_DWMNCRENDERINGCHANGED :: 0x031F
WM_DWMCOLORIZATIONCOLORCHANGED:: 0x0320
WM_DWMWINDOWMAXIMIZEDCHANGE :: 0x0321
WM_DWMSENDICONICTHUMBNAIL :: 0x0323
WM_DWMSENDICONICLIVEPREVIEWBITMAP :: 0x0326
WM_GETTITLEBARINFOEX :: 0x033F
WM_HANDHELDFIRST :: 0x0358
WM_HANDHELDLAST :: 0x035f
WM_AFXFIRST :: 0x0360
+2 -2
View File
@@ -99,14 +99,14 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur
}
for k in keys {
interned_key := strings.intern_get(&translation.intern, string(k))
interned_key, _ := strings.intern_get(&translation.intern, string(k))
interned_vals := make([]string, len(keys))
last_val: string
i := 0
for v in vals {
interned_vals[i] = strings.intern_get(&translation.intern, string(v))
interned_vals[i], _ = strings.intern_get(&translation.intern, string(v))
last_val = interned_vals[i]
i += 1
}
+5 -5
View File
@@ -59,9 +59,9 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
return translation, .TS_File_Expected_Context_Name,
}
section_name := strings.intern_get(&translation.intern, "")
section_name, _ := strings.intern_get(&translation.intern, "")
if !options.merge_sections {
section_name = strings.intern_get(&translation.intern, ts.elements[section_name_id].value)
section_name, _ = strings.intern_get(&translation.intern, ts.elements[section_name_id].value)
}
if section_name not_in translation.k_v {
@@ -92,8 +92,8 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
return translation, .TS_File_Expected_Translation
}
source := strings.intern_get(&translation.intern, ts.elements[source_id].value)
xlat := strings.intern_get(&translation.intern, ts.elements[translation_id].value)
source, _ := strings.intern_get(&translation.intern, ts.elements[source_id].value)
xlat, _ := strings.intern_get(&translation.intern, ts.elements[translation_id].value)
if source in section {
return translation, .Duplicate_Key
@@ -124,7 +124,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
if !numerus_found {
break
}
numerus := strings.intern_get(&translation.intern, ts.elements[numerus_id].value)
numerus, _ := strings.intern_get(&translation.intern, ts.elements[numerus_id].value)
section[source][num_plurals] = numerus
num_plurals += 1