Merge branch 'master' into pretty-json-2

This commit is contained in:
gingerBill
2022-08-11 16:14:27 +01:00
committed by GitHub
134 changed files with 3800 additions and 3085 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:
+8
View File
@@ -161,6 +161,10 @@ buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
return copy(b.buf[m:], p), nil
}
buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
return buffer_write(b, ([^]byte)(ptr)[:size])
}
buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) {
b.last_read = .Invalid
m, ok := _buffer_try_grow(b, len(s))
@@ -229,6 +233,10 @@ buffer_read :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
return
}
buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
return buffer_read(b, ([^]byte)(ptr)[:size])
}
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
b.last_read = .Invalid
+1 -1
View File
@@ -519,7 +519,7 @@ join_adjacent_string_literals :: proc(cpp: ^Preprocessor, initial_tok: ^Token) {
quote_string :: proc(s: string) -> []byte {
b := strings.make_builder(0, len(s)+2)
b := strings.builder_make(0, len(s)+2)
io.write_quoted_string(strings.to_writer(&b), s, '"')
return b.buf[:]
}
+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}
+1 -1
View File
@@ -196,7 +196,7 @@ foreign libc {
getc :: proc(stream: ^FILE) -> int ---
getchar :: proc() -> int ---
putc :: proc(c: int, stream: ^FILE) -> int ---
putchar :: proc() -> int ---
putchar :: proc(c: int) -> int ---
puts :: proc(s: cstring) -> int ---
ungetc :: proc(c: int, stream: ^FILE) -> int ---
fread :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
+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
+4 -4
View File
@@ -25,8 +25,8 @@ import "core:strings"
MAX_RUNE_CODEPOINT :: int(unicode.MAX_RUNE)
write_rune :: strings.write_rune_builder
write_string :: strings.write_string_builder
write_rune :: strings.write_rune
write_string :: strings.write_string
Error :: enum u8 {
None = 0,
@@ -94,8 +94,8 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
l := len(input)
if l == 0 { return "", .None }
builder := strings.make_builder()
defer strings.destroy_builder(&builder)
builder := strings.builder_make()
defer strings.builder_destroy(&builder)
t := Tokenizer{src=input}
in_data := false
@@ -8,7 +8,7 @@ import "core:time"
doc_print :: proc(doc: ^xml.Document) {
buf: strings.Builder
defer strings.destroy_builder(&buf)
defer strings.builder_destroy(&buf)
w := strings.to_writer(&buf)
xml.print(w, doc)
+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!
*/
+4 -1
View File
@@ -44,7 +44,7 @@ Marshal_Options :: struct {
mjson_skipped_first_braces_end: bool,
}
marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
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)
@@ -192,6 +192,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
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
+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
}
+1 -1
View File
@@ -84,7 +84,7 @@ example :: proc() {
doc_hash :: proc(doc: ^xml.Document, print := false) -> (crc32: u32) {
buf: strings.Builder
defer strings.destroy_builder(&buf)
defer strings.builder_destroy(&buf)
w := strings.to_writer(&buf)
xml.print(w, doc)
+21 -8
View File
@@ -77,7 +77,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist
// They must be freed accordingly
aprint :: proc(args: ..any, sep := " ") -> string {
str: strings.Builder
strings.init_builder(&str)
strings.builder_init(&str)
sbprint(buf=&str, args=args, sep=sep)
return strings.to_string(str)
}
@@ -85,7 +85,7 @@ aprint :: proc(args: ..any, sep := " ") -> string {
// They must be freed accordingly
aprintln :: proc(args: ..any, sep := " ") -> string {
str: strings.Builder
strings.init_builder(&str)
strings.builder_init(&str)
sbprintln(buf=&str, args=args, sep=sep)
return strings.to_string(str)
}
@@ -93,7 +93,7 @@ aprintln :: proc(args: ..any, sep := " ") -> string {
// They must be freed accordingly
aprintf :: proc(fmt: string, args: ..any) -> string {
str: strings.Builder
strings.init_builder(&str)
strings.builder_init(&str)
sbprintf(&str, fmt, ..args)
return strings.to_string(str)
}
@@ -102,21 +102,21 @@ aprintf :: proc(fmt: string, args: ..any) -> string {
// tprint procedure return a string that was allocated with the current context's temporary allocator
tprint :: proc(args: ..any, sep := " ") -> string {
str: strings.Builder
strings.init_builder(&str, context.temp_allocator)
strings.builder_init(&str, context.temp_allocator)
sbprint(buf=&str, args=args, sep=sep)
return strings.to_string(str)
}
// tprintln procedure return a string that was allocated with the current context's temporary allocator
tprintln :: proc(args: ..any, sep := " ") -> string {
str: strings.Builder
strings.init_builder(&str, context.temp_allocator)
strings.builder_init(&str, context.temp_allocator)
sbprintln(buf=&str, args=args, sep=sep)
return strings.to_string(str)
}
// tprintf procedure return a string that was allocated with the current context's temporary allocator
tprintf :: proc(fmt: string, args: ..any) -> string {
str: strings.Builder
strings.init_builder(&str, context.temp_allocator)
strings.builder_init(&str, context.temp_allocator)
sbprintf(&str, fmt, ..args)
return strings.to_string(str)
}
@@ -776,7 +776,7 @@ fmt_rune :: proc(fi: ^Info, r: rune, verb: rune) {
case 'c', 'r', 'v':
io.write_rune(fi.writer, r, &fi.n)
case 'q':
fi.n += strings.write_quoted_rune(fi.writer, r)
fi.n += io.write_quoted_rune(fi.writer, r)
case:
fmt_int(fi, u64(r), false, 32, verb)
}
@@ -1014,7 +1014,7 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
u := u64(uintptr(p))
switch verb {
case 'p', 'v':
if !fi.hash || verb == 'v' {
if !fi.hash && verb == 'v' {
io.write_string(fi.writer, "0x", &fi.n)
}
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER)
@@ -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 {
+2 -2
View File
@@ -1,8 +1,8 @@
package hash
@(optimization_mode="speed")
crc64_ecma_182 :: proc(data: []byte, seed := u32(0)) -> u64 #no_bounds_check {
result := u64(seed)
crc64_ecma_182 :: proc(data: []byte, seed := u64(0)) -> (result: u64) #no_bounds_check {
result = seed
#no_bounds_check for b in data {
result = result<<8 ~ _crc64_table_ecma_182[((result>>56) ~ u64(b)) & 0xff]
}
+101 -95
View File
@@ -172,108 +172,114 @@ murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 {
return h1
}
// See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L96
@(optimization_mode="speed")
murmur64 :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
when size_of(int) == 8 {
m :: 0xc6a4a7935bd1e995
r :: 47
murmur64a :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
m :: 0xc6a4a7935bd1e995
r :: 47
h: u64 = seed ~ (u64(len(data)) * m)
data64 := mem.slice_ptr(cast(^u64)raw_data(data), len(data)/size_of(u64))
h: u64 = seed ~ (u64(len(data)) * m)
data64 := mem.slice_data_cast([]u64, data)
for _, i in data64 {
k := data64[i]
for _, i in data64 {
k := data64[i]
k *= m
k ~= k>>r
k *= m
k *= m
k ~= k>>r
k *= m
h ~= k
h *= m
}
switch len(data)&7 {
case 7: h ~= u64(data[6]) << 48; fallthrough
case 6: h ~= u64(data[5]) << 40; fallthrough
case 5: h ~= u64(data[4]) << 32; fallthrough
case 4: h ~= u64(data[3]) << 24; fallthrough
case 3: h ~= u64(data[2]) << 16; fallthrough
case 2: h ~= u64(data[1]) << 8; fallthrough
case 1:
h ~= u64(data[0])
h *= m
}
h ~= h>>r
h ~= k
h *= m
h ~= h>>r
return h
} else {
m :: 0x5bd1e995
r :: 24
h1 := u32(seed) ~ u32(len(data))
h2 := u32(seed) >> 32
data32 := mem.slice_ptr(cast(^u32)raw_data(data), len(data)/size_of(u32))
len := len(data)
i := 0
for len >= 8 {
k1, k2: u32
k1 = data32[i]; i += 1
k1 *= m
k1 ~= k1>>r
k1 *= m
h1 *= m
h1 ~= k1
len -= 4
k2 = data32[i]; i += 1
k2 *= m
k2 ~= k2>>r
k2 *= m
h2 *= m
h2 ~= k2
len -= 4
}
if len >= 4 {
k1: u32
k1 = data32[i]; i += 1
k1 *= m
k1 ~= k1>>r
k1 *= m
h1 *= m
h1 ~= k1
len -= 4
}
// TODO(bill): Fix this
#no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3]
switch len {
case 3:
h2 ~= u32(data8[2]) << 16
fallthrough
case 2:
h2 ~= u32(data8[1]) << 8
fallthrough
case 1:
h2 ~= u32(data8[0])
h2 *= m
}
h1 ~= h2>>18
h1 *= m
h2 ~= h1>>22
h2 *= m
h1 ~= h2>>17
h1 *= m
h2 ~= h1>>19
h2 *= m
return u64(h1)<<32 | u64(h2)
}
offset := len(data64) * size_of(u64)
switch len(data)&7 {
case 7: h ~= u64(data[offset + 6]) << 48; fallthrough
case 6: h ~= u64(data[offset + 5]) << 40; fallthrough
case 5: h ~= u64(data[offset + 4]) << 32; fallthrough
case 4: h ~= u64(data[offset + 3]) << 24; fallthrough
case 3: h ~= u64(data[offset + 2]) << 16; fallthrough
case 2: h ~= u64(data[offset + 1]) << 8; fallthrough
case 1:
h ~= u64(data[offset + 0])
h *= m
}
h ~= h>>r
h *= m
h ~= h>>r
return h
}
// See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L140
@(optimization_mode="speed")
murmur64b :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
m :: 0x5bd1e995
r :: 24
h1 := u32(seed) ~ u32(len(data))
h2 := u32(seed) >> 32
data32 := mem.slice_ptr(cast(^u32)raw_data(data), len(data)/size_of(u32))
len := len(data)
i := 0
for len >= 8 {
k1, k2: u32
k1 = data32[i]; i += 1
k1 *= m
k1 ~= k1>>r
k1 *= m
h1 *= m
h1 ~= k1
len -= 4
k2 = data32[i]; i += 1
k2 *= m
k2 ~= k2>>r
k2 *= m
h2 *= m
h2 ~= k2
len -= 4
}
if len >= 4 {
k1: u32
k1 = data32[i]; i += 1
k1 *= m
k1 ~= k1>>r
k1 *= m
h1 *= m
h1 ~= k1
len -= 4
}
// TODO(bill): Fix this
#no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3]
switch len {
case 3:
h2 ~= u32(data8[2]) << 16
fallthrough
case 2:
h2 ~= u32(data8[1]) << 8
fallthrough
case 1:
h2 ~= u32(data8[0])
h2 *= m
}
h1 ~= h2>>18
h1 *= m
h2 ~= h1>>22
h2 *= m
h1 ~= h2>>17
h1 *= m
h2 ~= h1>>19
h2 *= m
return u64(h1)<<32 | u64(h2)
}
@(optimization_mode="speed")
+5 -5
View File
@@ -469,7 +469,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 {
@@ -489,7 +489,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
}
@@ -498,7 +498,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 {
@@ -518,7 +518,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
}
@@ -527,7 +527,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 {
+2 -2
View File
@@ -130,7 +130,7 @@ save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context
// we will write to a string builder
data: strings.Builder
strings.init_builder(&data)
strings.builder_init(&data)
// all PNM headers start with the format
fmt.sbprintf(&data, "%s\n", header.format)
@@ -409,7 +409,7 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head
// string buffer for the tupltype
tupltype: strings.Builder
strings.init_builder(&tupltype, context.temp_allocator); defer strings.destroy_builder(&tupltype)
strings.builder_init(&tupltype, context.temp_allocator); defer strings.builder_destroy(&tupltype)
fmt.sbprint(&tupltype, "")
// PAM uses actual lines, so we can iterate easily
+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
+24
View File
@@ -247,6 +247,30 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written
return
}
// writer append a quoted rune into the byte buffer, return the written size
write_quoted_rune :: proc(w: Writer, r: rune) -> (n: int) {
_write_byte :: #force_inline proc(w: Writer, c: byte) -> int {
err := write_byte(w, c)
return 1 if err == nil else 0
}
quote := byte('\'')
n += _write_byte(w, quote)
buf, width := utf8.encode_rune(r)
if width == 1 && r == utf8.RUNE_ERROR {
n += _write_byte(w, '\\')
n += _write_byte(w, 'x')
n += _write_byte(w, DIGITS_LOWER[buf[0]>>4])
n += _write_byte(w, DIGITS_LOWER[buf[0]&0xf])
} else {
i, _ := write_escaped_rune(w, r, quote)
n += i
}
n += _write_byte(w, quote)
return
}
Tee_Reader :: struct {
+1 -1
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)
}
+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.
+23 -11
View File
@@ -325,9 +325,9 @@ ease :: proc "contextless" (type: Ease, p: $T) -> T
// in case type was invalid
return 0
}
Flux_Map :: struct($T: typeid) {
values: map[^T]Flux_Tween(T),
keys_to_be_deleted: [dynamic]^T,
}
Flux_Tween :: struct($T: typeid) {
@@ -353,15 +353,17 @@ Flux_Tween :: struct($T: typeid) {
}
// init flux map to a float type and a wanted cap
flux_init :: proc($T: typeid, cap := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
flux_init :: proc($T: typeid, value_capacity := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
return {
make(map[^T]Flux_Tween(T), cap),
values = make(map[^T]Flux_Tween(T), value_capacity),
keys_to_be_deleted = make([dynamic]^T, 0, value_capacity)
}
}
// delete map content
flux_destroy :: proc(flux: Flux_Map($T)) where intrinsics.type_is_float(T) {
delete(flux.values)
delete(flux.keys_to_be_deleted)
}
// clear map content, stops all animations
@@ -374,8 +376,8 @@ flux_clear :: proc(flux: ^Flux_Map($T)) where intrinsics.type_is_float(T) {
// return value can be used to set callbacks
flux_to :: proc(
flux: ^Flux_Map($T),
value: ^f32,
goal: f32,
value: ^T,
goal: T,
type: Ease = .Quadratic_Out,
duration: time.Duration = time.Second,
delay: f64 = 0,
@@ -413,6 +415,8 @@ flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where i
// calls callbacks in all stages, when they're filled
// deletes tween from the map after completion
flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) {
clear(&flux.keys_to_be_deleted)
for key, tween in &flux.values {
delay_remainder := f64(0)
@@ -451,7 +455,8 @@ flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float
}
if tween.progress >= 1 {
delete_key(&flux.values, key)
// append keys to array that will be deleted after the loop
append(&flux.keys_to_be_deleted, key)
if tween.on_complete != nil {
tween.on_complete(flux, tween.data)
@@ -459,17 +464,24 @@ flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float
}
}
}
// loop through keys that should be deleted from the map
if len(flux.keys_to_be_deleted) != 0 {
for key in flux.keys_to_be_deleted {
delete_key(&flux.values, key)
}
}
}
// stop a specific key inside the map
// returns true when it successfully removed the key
flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) {
if key in flux.values {
delete_key(&flux.values, key)
return true
}
if key in flux.values {
delete_key(&flux.values, key)
return true
}
return false
return false
}
// returns the amount of time left for the tween animation, if the key exists in the map
+3 -3
View File
@@ -476,21 +476,21 @@ quaternion_angle_axis :: proc{
angle_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 {
if abs(q.w) > math.SQRT_THREE*0.5 {
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2
return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
}
return math.acos(q.w) * 2
}
angle_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 {
if abs(q.w) > math.SQRT_THREE*0.5 {
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2
return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
}
return math.acos(q.w) * 2
}
angle_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 {
if abs(q.w) > math.SQRT_THREE*0.5 {
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2
return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
}
return math.acos(q.w) * 2
+18 -11
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))) }
@@ -1357,7 +1364,7 @@ atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
}
asin :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
return atan2(x, 1 + sqrt(1 - x*x))
return atan2(x, sqrt(1 - x*x))
}
acos :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
+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
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,
+8 -1
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
+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)
}
+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:
+39 -72
View File
@@ -1611,20 +1611,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 +1652,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 +1663,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 +1679,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 +1696,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 +1718,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 +2235,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 +2244,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 +2609,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 +2633,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 +2650,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
}
+1 -1
View File
@@ -151,7 +151,7 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string {
fix_lines(p)
builder := strings.make_builder(0, 5 * mem.Megabyte, p.allocator)
builder := strings.builder_make(0, 5 * mem.Megabyte, p.allocator)
last_line := 0
+3 -3
View File
@@ -71,7 +71,7 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int {
return 0
} else {
builder := strings.make_builder(context.temp_allocator)
builder := strings.builder_make(context.temp_allocator)
c_len := len(comment.text)
trim_space := true
@@ -90,12 +90,12 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int {
continue
case c == '\r' && comment.text[min(c_len - 1, i + 1)] == '\n':
append(&multilines, strings.to_string(builder))
builder = strings.make_builder(context.temp_allocator)
builder = strings.builder_make(context.temp_allocator)
trim_space = true
i += 1
case c == '\n':
append(&multilines, strings.to_string(builder))
builder = strings.make_builder(context.temp_allocator)
builder = strings.builder_make(context.temp_allocator)
trim_space = true
case c == '/' && comment.text[min(c_len - 1, i + 1)] == '*':
strings.write_string(&builder, "/*")
+5 -3
View File
@@ -1,6 +1,5 @@
package os
import "core:strings"
import "core:mem"
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
@@ -51,10 +50,13 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
continue
}
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
fullpath := make([]byte, len(dirpath)+1+len(filename))
copy(fullpath, dirpath)
copy(fullpath[len(dirpath):], "/")
copy(fullpath[len(dirpath)+1:], filename)
defer delete(fullpath, context.temp_allocator)
fi_, err = stat(fullpath, allocator)
fi_, err = stat(string(fullpath), allocator)
if err != ERROR_NONE {
for fi__ in dfi {
file_info_delete(fi__, allocator)
+16 -16
View File
@@ -11,24 +11,24 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
return
}
wkey := win32.utf8_to_wstring(key)
b := make([dynamic]u16, 100, context.temp_allocator)
for {
n := win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
if n == 0 {
err := win32.GetLastError()
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
return "", false
}
n := win32.GetEnvironmentVariableW(wkey, nil, 0)
if n == 0 {
err := win32.GetLastError()
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
return "", false
}
if n <= u32(len(b)) {
value, _ = win32.utf16_to_utf8(b[:n], allocator)
found = true
return
}
resize(&b, len(b)*2)
}
b := make([dynamic]u16, n, context.temp_allocator)
n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
if n == 0 {
err := win32.GetLastError()
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
return "", false
}
}
value, _ = win32.utf16_to_utf8(b[:n], allocator)
found = true
return
}
+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
+8 -8
View File
@@ -241,13 +241,13 @@ S_ISGID :: 0o2000 // Set group id on execution
S_ISVTX :: 0o1000 // Directory restrcted delete
S_ISLNK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFLNK
S_ISREG :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFREG
S_ISDIR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFDIR
S_ISCHR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFCHR
S_ISBLK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFBLK
S_ISFIFO :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFIFO
S_ISSOCK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFSOCK
S_ISLNK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFLNK }
S_ISREG :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFREG }
S_ISDIR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFDIR }
S_ISCHR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFCHR }
S_ISBLK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFBLK }
S_ISFIFO :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFIFO }
S_ISSOCK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFSOCK }
F_OK :: 0 // Test for file existance
X_OK :: 1 // Test for execute permission
@@ -257,7 +257,7 @@ R_OK :: 4 // Test for read permission
foreign libc {
@(link_name="__error") __errno_location :: proc() -> ^int ---
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+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
}
+1 -1
View File
@@ -146,7 +146,7 @@ clean :: proc(path: string, allocator := context.allocator) -> string {
}
// join joins numerous path elements into a single path
join :: proc(elems: ..string, allocator := context.allocator) -> string {
join :: proc(elems: []string, allocator := context.allocator) -> string {
context.allocator = allocator
for elem, i in elems {
if elem != "" {
+5
View File
@@ -34,6 +34,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 +69,7 @@ Type_Kind :: enum {
Relative_Pointer,
Relative_Slice,
Matrix,
Soa_Pointer,
}
@@ -102,6 +104,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 +197,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
@@ -1419,6 +1423,7 @@ 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
+15 -2
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 {
@@ -437,6 +447,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 {
@@ -573,11 +586,11 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
write_type(w, info.elem, &n) or_return
case is_rune(info.elem):
io.write_encoded_rune(w, rune(info.lower), true, &n) or_return
io.write_string(w, "..", &n) or_return
io.write_string(w, "..=", &n) or_return
io.write_encoded_rune(w, rune(info.upper), true, &n) or_return
case:
io.write_i64(w, info.lower, 10, &n) or_return
io.write_string(w, "..", &n) or_return
io.write_string(w, "..=", &n) or_return
io.write_i64(w, info.upper, 10, &n) or_return
}
if info.underlying != 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
+90 -47
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
}
@@ -339,19 +346,22 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
if array == nil {
return
}
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 {
a.len += 1
} else {
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
}
a.len += 1
}
}
}
@@ -366,20 +376,23 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
return
}
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 {
a.len += arg_len
} else {
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)
}
a.len += arg_len
}
}
}
@@ -413,7 +426,7 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) {
@builtin
insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if array == nil {
return
}
@@ -432,7 +445,7 @@ insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
}
@builtin
insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if array == nil {
return
}
@@ -456,7 +469,7 @@ insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
}
@builtin
insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if array == nil {
return
}
@@ -477,7 +490,51 @@ insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
return
}
@builtin insert_at :: proc{insert_at_elem, insert_at_elems, insert_at_elem_string}
@builtin inject_at :: proc{inject_at_elem, inject_at_elems, inject_at_elem_string}
@builtin
assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if index < len(array) {
array[index] = arg
ok = true
} else if resize(array, index+1, loc) {
array[index] = arg
ok = true
}
return
}
@builtin
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if index+len(args) < len(array) {
copy(array[index:], args)
ok = true
} else if resize(array, index+1+len(args), loc) {
copy(array[index:], args)
ok = true
}
return
}
@builtin
assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if len(args) == 0 {
ok = true
} else if index+len(args) < len(array) {
copy(array[index:], args)
ok = true
} else if resize(array, index+1+len(args), loc) {
copy(array[index:], args)
ok = true
}
return
}
@builtin assign_at :: proc{assign_at_elem, assign_at_elems, assign_at_elem_string}
@@ -735,17 +792,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 {
+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
}
+43 -105
View File
@@ -17,50 +17,53 @@ Builder :: struct {
}
// return a builder, default length 0 / cap 16 are done through make
make_builder_none :: proc(allocator := context.allocator) -> Builder {
builder_make_none :: proc(allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, allocator)}
}
// return a builder, with a set length `len` and cap 16 byte buffer
make_builder_len :: proc(len: int, allocator := context.allocator) -> Builder {
builder_make_len :: proc(len: int, allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, len, allocator)}
}
// return a builder, with a set length `len` byte buffer and a custom `cap`
make_builder_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, len, cap, allocator)}
}
// overload simple `make_builder_*` with or without len / cap parameters
make_builder :: proc{
make_builder_none,
make_builder_len,
make_builder_len_cap,
// overload simple `builder_make_*` with or without len / cap parameters
builder_make :: proc{
builder_make_none,
builder_make_len,
builder_make_len_cap,
}
// initialize a builder, default length 0 / cap 16 are done through make
// replaces the existing `buf`
init_builder_none :: proc(b: ^Builder, allocator := context.allocator) {
builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, allocator)
return b
}
// initialize a builder, with a set length `len` and cap 16 byte buffer
// replaces the existing `buf`
init_builder_len :: proc(b: ^Builder, len: int, allocator := context.allocator) {
builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, len, allocator)
return b
}
// initialize a builder, with a set length `len` byte buffer and a custom `cap`
// replaces the existing `buf`
init_builder_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) {
builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, len, cap, allocator)
return b
}
// overload simple `init_builder_*` with or without len / ap parameters
init_builder :: proc{
init_builder_none,
init_builder_len,
init_builder_len_cap,
// overload simple `builder_init_*` with or without len / ap parameters
builder_init :: proc{
builder_init_none,
builder_init_len,
builder_init_len_cap,
}
@(private)
@@ -103,18 +106,18 @@ to_writer :: proc(b: ^Builder) -> io.Writer {
}
// delete and clear the builder byte buffer content
destroy_builder :: proc(b: ^Builder) {
builder_destroy :: proc(b: ^Builder) {
delete(b.buf)
clear(&b.buf)
}
// reserve the builfer byte buffer to a specific cap, when it's higher than before
grow_builder :: proc(b: ^Builder, cap: int) {
builder_grow :: proc(b: ^Builder, cap: int) {
reserve(&b.buf, cap)
}
// clear the builder byte buffer content
reset_builder :: proc(b: ^Builder) {
builder_reset :: proc(b: ^Builder) {
clear(&b.buf)
}
@@ -165,7 +168,7 @@ builder_space :: proc(b: Builder) -> int {
/*
appends a byte to the builder, returns the append diff
builder := strings.make_builder()
builder := strings.builder_make()
strings.write_byte(&builder, 'a') // 1
strings.write_byte(&builder, 'b') // 1
strings.write_byte(&builder, 'c') // 1
@@ -181,7 +184,7 @@ write_byte :: proc(b: ^Builder, x: byte) -> (n: int) {
/*
appends a slice of bytes to the builder, returns the append diff
builder := strings.make_builder()
builder := strings.builder_make()
bytes := [?]byte { 'a', 'b', 'c' }
strings.write_bytes(&builder, bytes[:]) // 3
fmt.println(strings.to_string(builder)) // -> abc
@@ -196,77 +199,46 @@ write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
/*
appends a single rune into the builder, returns written rune size and an `io.Error`
builder := strings.make_builder()
strings.write_rune_builder(&builder, 'ä') // 2 None
strings.write_rune_builder(&builder, 'b') // 1 None
strings.write_rune_builder(&builder, 'c') // 1 None
builder := strings.builder_make()
strings.write_rune(&builder, 'ä') // 2 None
strings.write_rune(&builder, 'b') // 1 None
strings.write_rune(&builder, 'c') // 1 None
fmt.println(strings.to_string(builder)) // -> äbc
*/
write_rune_builder :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
write_rune :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
return io.write_rune(to_writer(b), r)
}
/*
appends a quoted rune into the builder, returns written size
builder := strings.make_builder()
builder := strings.builder_make()
strings.write_string(&builder, "abc") // 3
strings.write_quoted_rune_builder(&builder, 'ä') // 4
strings.write_quoted_rune(&builder, 'ä') // 4
strings.write_string(&builder, "abc") // 3
fmt.println(strings.to_string(builder)) // -> abc'ä'abc
*/
write_quoted_rune_builder :: proc(b: ^Builder, r: rune) -> (n: int) {
return write_quoted_rune(to_writer(b), r)
write_quoted_rune :: proc(b: ^Builder, r: rune) -> (n: int) {
return io.write_quoted_rune(to_writer(b), r)
}
@(private)
_write_byte :: proc(w: io.Writer, c: byte) -> int {
err := io.write_byte(w, c)
return 1 if err == nil else 0
}
// writer append a quoted rune into the byte buffer, return the written size
write_quoted_rune :: proc(w: io.Writer, r: rune) -> (n: int) {
quote := byte('\'')
n += _write_byte(w, quote)
buf, width := utf8.encode_rune(r)
if width == 1 && r == utf8.RUNE_ERROR {
n += _write_byte(w, '\\')
n += _write_byte(w, 'x')
n += _write_byte(w, DIGITS_LOWER[buf[0]>>4])
n += _write_byte(w, DIGITS_LOWER[buf[0]&0xf])
} else {
i, _ := io.write_escaped_rune(w, r, quote)
n += i
}
n += _write_byte(w, quote)
return
}
// overload for `write_string_*` variants
write_string :: proc{
write_string_builder,
write_string_writer,
}
/*
appends a string to the builder, return the written byte size
builder := strings.make_builder()
builder := strings.builder_make()
strings.write_string(&builder, "a") // 1
strings.write_string(&builder, "bc") // 2
strings.write_string(&builder, "xyz") // 3
fmt.println(strings.to_string(builder)) // -> abcxyz
*/
write_string_builder :: proc(b: ^Builder, s: string) -> (n: int) {
return write_string_writer(to_writer(b), s)
write_string :: proc(b: ^Builder, s: string) -> (n: int) {
n0 := len(b.buf)
append(&b.buf, s)
n1 := len(b.buf)
return n1-n0
}
// appends a string to the writer
write_string_writer :: proc(w: io.Writer, s: string) -> (n: int) {
n, _ = io.write(w, transmute([]byte)s)
return
}
// pops and returns the last byte in the builder
// returns 0 when the builder is empty
@@ -297,70 +269,36 @@ pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
@(private)
DIGITS_LOWER := "0123456789abcdefx"
// overload for `write_quoted_string_*` variants
write_quoted_string :: proc{
write_quoted_string_builder,
write_quoted_string_writer,
}
/*
append a quoted string into the builder, return the written byte size
builder := strings.make_builder()
builder := strings.builder_make()
strings.write_quoted_string(&builder, "a") // 3
strings.write_quoted_string(&builder, "bc", '\'') // 4
strings.write_quoted_string(&builder, "xyz") // 5
fmt.println(strings.to_string(builder)) // -> "a"'bc'xyz"
*/
write_quoted_string_builder :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) {
write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) {
n, _ = io.write_quoted_string(to_writer(b), str, quote)
return
}
@(deprecated="prefer io.write_quoted_string")
write_quoted_string_writer :: proc(w: io.Writer, str: string, quote: byte = '"') -> (n: int) {
n, _ = io.write_quoted_string(w, str, quote)
return
}
// overload for `write_encoded_rune_*`
write_encoded_rune :: proc{
write_encoded_rune_builder,
write_encoded_rune_writer,
}
// appends a rune to the builder, optional `write_quote` boolean tag, returns the written rune size
write_encoded_rune_builder :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) {
write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) {
n, _ = io.write_encoded_rune(to_writer(b), r, write_quote)
return
}
@(deprecated="prefer io.write_encoded_rune")
write_encoded_rune_writer :: proc(w: io.Writer, r: rune, write_quote := true) -> (n: int) {
n, _ = io.write_encoded_rune(w, r, write_quote)
return
}
// overload for `write_escaped_rune_*`
write_escaped_rune :: proc{
write_escaped_rune_builder,
write_escaped_rune_writer,
}
// appends a rune to the builder, fully written out in case of escaped runes e.g. '\a' will be written as such
// when `r` and `quote` match and `quote` is `\\` - they will be written as two slashes
// `html_safe` flag in case the runes '<', '>', '&' should be encoded as digits e.g. `\u0026`
write_escaped_rune_builder :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe)
return
}
@(deprecated="prefer io.write_escaped_rune")
write_escaped_rune_writer :: proc(w: io.Writer, r: rune, quote: byte, html_safe := false) -> (n: int) {
n, _ = io.write_escaped_rune(w, r, quote, html_safe)
return
}
// writes a u64 value `i` in `base` = 10 into the builder, returns the written amount of characters
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
buf: [32]byte
+10 -10
View File
@@ -10,7 +10,7 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
}
b: Builder
init_builder(&b, 0, 0, allocator)
builder_init(&b, 0, 0, allocator)
s := s
for c, i in s {
@@ -20,7 +20,7 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
_, w := utf8.decode_rune_in_string(s[i:])
if w == 1 {
grow_builder(&b, len(s) + len(replacement))
builder_grow(&b, len(s) + len(replacement))
write_string(&b, s[:i])
s = s[i:]
break
@@ -67,9 +67,9 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
*/
to_lower :: proc(s: string, allocator := context.allocator) -> string {
b: Builder
init_builder(&b, 0, len(s), allocator)
builder_init(&b, 0, len(s), allocator)
for r in s {
write_rune_builder(&b, unicode.to_lower(r))
write_rune(&b, unicode.to_lower(r))
}
return to_string(b)
}
@@ -83,9 +83,9 @@ to_lower :: proc(s: string, allocator := context.allocator) -> string {
*/
to_upper :: proc(s: string, allocator := context.allocator) -> string {
b: Builder
init_builder(&b, 0, len(s), allocator)
builder_init(&b, 0, len(s), allocator)
for r in s {
write_rune_builder(&b, unicode.to_upper(r))
write_rune(&b, unicode.to_upper(r))
}
return to_string(b)
}
@@ -147,7 +147,7 @@ to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
s := s
s = trim_space(s)
b: Builder
init_builder(&b, 0, len(s), allocator)
builder_init(&b, 0, len(s), allocator)
w := to_writer(&b)
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
@@ -172,7 +172,7 @@ to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
s := s
s = trim_space(s)
b: Builder
init_builder(&b, 0, len(s), allocator)
builder_init(&b, 0, len(s), allocator)
w := to_writer(&b)
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
@@ -203,7 +203,7 @@ to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allo
s := s
s = trim_space(s)
b: Builder
init_builder(&b, 0, len(s), allocator)
builder_init(&b, 0, len(s), allocator)
w := to_writer(&b)
adjust_case := unicode.to_upper if all_upper_case else unicode.to_lower
@@ -272,7 +272,7 @@ to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
s := s
s = trim_space(s)
b: Builder
init_builder(&b, 0, len(s), allocator)
builder_init(&b, 0, len(s), allocator)
w := to_writer(&b)
prev, curr: rune
+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
}
+8 -8
View File
@@ -1553,7 +1553,7 @@ split_multi_iterate :: proc(using sm: ^Split_Multi) -> (res: string, ok: bool) #
scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string {
str := s
b: Builder
init_builder(&b, 0, len(s), allocator)
builder_init(&b, 0, len(s), allocator)
has_error := false
cursor := 0
@@ -1622,7 +1622,7 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) ->
}
b: Builder
init_builder(&b, allocator)
builder_init(&b, allocator)
writer := to_writer(&b)
str := s
column: int
@@ -1690,8 +1690,8 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
pad_len := rune_count(pad)
b: Builder
init_builder(&b, allocator)
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad))
builder_init(&b, allocator)
builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
w := to_writer(&b)
@@ -1713,8 +1713,8 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context
pad_len := rune_count(pad)
b: Builder
init_builder(&b, allocator)
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad))
builder_init(&b, allocator)
builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
w := to_writer(&b)
@@ -1735,8 +1735,8 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex
pad_len := rune_count(pad)
b: Builder
init_builder(&b, allocator)
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad))
builder_init(&b, allocator)
builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
w := to_writer(&b)
+8 -12
View File
@@ -3,24 +3,22 @@
package sync
import "core:c"
import "core:os"
import "core:time"
UMTX_OP_WAIT :: 2
UMTX_OP_WAKE :: 3
ETIMEDOUT :: 60
foreign import libc "system:c"
foreign libc {
_umtx_op :: proc "c" (obj: rawptr, op: c.int, val: c.ulong, uaddr: rawptr, uaddr2: rawptr) -> c.int ---
__error :: proc "c" () -> ^c.int ---
}
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
timeout := os.Unix_File_Time{
seconds = 5,
nanoseconds = 0,
}
timeout := [2]i64{14400, 0} // 4 hours
for {
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
@@ -28,7 +26,7 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
return true
}
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
if __error()^ == ETIMEDOUT {
continue
}
@@ -42,16 +40,14 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
return false
}
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &os.Unix_File_Time{
seconds = (os.time_t)(duration/1e9),
nanoseconds = (c.long)(duration%1e9),
})
timeout := [2]i64{i64(duration/1e9), i64(duration%1e9)}
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
if res != -1 {
return true
}
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
if __error()^ == ETIMEDOUT {
return false
}
+8 -2
View File
@@ -2,8 +2,14 @@
//+private
package sync
import "core:os"
import "core:c"
foreign import dl "system:dl"
foreign dl {
pthread_getthreadid_np :: proc "c" () -> c.int ---
}
_current_thread_id :: proc "contextless" () -> int {
return os.current_thread_id()
return int(pthread_getthreadid_np())
}
+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 ---
}
+1
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,
+4
View File
@@ -22,6 +22,10 @@ GET_Y_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int {
return cast(c_int)cast(c_short)HIWORD(cast(DWORD)lp)
}
MAKE_WORD :: #force_inline proc "contextless" (x, y: WORD) -> WORD {
return x << 8 | y
}
utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
if len(s) < 1 {
return nil
+1 -1
View File
@@ -45,4 +45,4 @@ ERROR_NOT_SAME_OBJECT : DWORD : 1656
E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001
SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool do return result >= 0
SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool { return result >= 0 }
+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
@@ -45,7 +45,7 @@ generate_encoding_entity_table :: proc() {
printf("\"%v\" loaded and parsed.\n", filename)
generated_buf: strings.Builder
defer strings.destroy_builder(&generated_buf)
defer strings.builder_destroy(&generated_buf)
w := strings.to_writer(&generated_buf)
charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist")