diff options
| author | ftphikari <ftphikari@gmail.com> | 2023-07-25 15:32:18 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-07-25 15:32:18 +0300 |
| commit | 699aec331d44da58bceddfb788bf349995473ad9 (patch) | |
| tree | 3f5ce42c72c18fff1fc79f0229797be72f0e7638 /core | |
| parent | d2375a79f29d8377c813484bce3127ae9c205974 (diff) | |
| parent | 5ac7fe453f5fbf0995c24f0c1c12ed439ae3aee9 (diff) | |
Merge branch 'odin-lang:master' into master
Diffstat (limited to 'core')
99 files changed, 2882 insertions, 1354 deletions
diff --git a/core/bufio/read_writer.odin b/core/bufio/read_writer.odin index f9ae1ed45..3e6bd3aa0 100644 --- a/core/bufio/read_writer.odin +++ b/core/bufio/read_writer.odin @@ -14,51 +14,29 @@ read_writer_init :: proc(rw: ^Read_Writer, r: ^Reader, w: ^Writer) { } read_writer_to_stream :: proc(rw: ^Read_Writer) -> (s: io.Stream) { - s.stream_data = rw - s.stream_vtable = &_read_writer_vtable + s.procedure = _read_writer_procedure + s.data = rw return } @(private) -_read_writer_vtable := io.Stream_VTable{ - impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - b := (^Read_Writer)(s.stream_data).r - return reader_read(b, p) - }, - impl_unread_byte = proc(s: io.Stream) -> io.Error { - b := (^Read_Writer)(s.stream_data).r - return reader_unread_byte(b) - }, - impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) { - b := (^Read_Writer)(s.stream_data).r - return reader_read_rune(b) - }, - impl_unread_rune = proc(s: io.Stream) -> io.Error { - b := (^Read_Writer)(s.stream_data).r - return reader_unread_rune(b) - }, - impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) { - b := (^Read_Writer)(s.stream_data).r - return reader_write_to(b, w) - }, - impl_flush = proc(s: io.Stream) -> io.Error { - b := (^Read_Writer)(s.stream_data).w - return writer_flush(b) - }, - impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - b := (^Read_Writer)(s.stream_data).w - return writer_write(b, p) - }, - impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error { - b := (^Read_Writer)(s.stream_data).w - return writer_write_byte(b, c) - }, - impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) { - b := (^Read_Writer)(s.stream_data).w - return writer_write_rune(b, r) - }, - impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) { - b := (^Read_Writer)(s.stream_data).w - return writer_read_from(b, r) - }, -} +_read_writer_procedure := proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + rw := (^Read_Writer)(stream_data) + n_int: int + #partial switch mode { + case .Flush: + err = writer_flush(rw.w) + return + case .Read: + n_int, err = reader_read(rw.r, p) + n = i64(n_int) + return + case .Write: + n_int, err = writer_write(rw.w, p) + n = i64(n_int) + return + case .Query: + return io.query_utility({.Flush, .Read, .Write, .Query}) + } + return 0, .Empty +}
\ No newline at end of file diff --git a/core/bufio/reader.odin b/core/bufio/reader.odin index 6bfc4cd9d..dc4e02c02 100644 --- a/core/bufio/reader.odin +++ b/core/bufio/reader.odin @@ -311,18 +311,6 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) { } m: i64 - if nr, ok := io.to_writer_to(b.rd); ok { - m, err = io.write_to(nr, w) - n += m - return n, err - } - - if nw, ok := io.to_reader_from(w); ok { - m, err = io.read_from(nw, b.rd) - n += m - return n, err - } - if b.w-b.r < len(b.buf) { if err = _reader_read_new_chunk(b); err != nil { return @@ -352,48 +340,28 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) { // reader_to_stream converts a Reader into an io.Stream reader_to_stream :: proc(b: ^Reader) -> (s: io.Stream) { - s.stream_data = b - s.stream_vtable = &_reader_vtable + s.data = b + s.procedure = _reader_proc return } @(private) -_reader_vtable := io.Stream_VTable{ - impl_destroy = proc(s: io.Stream) -> io.Error { - b := (^Reader)(s.stream_data) +_reader_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + b := (^Reader)(stream_data) + #partial switch mode { + case .Read: + return io._i64_err(reader_read(b, p)) + case .Destroy: reader_destroy(b) - return nil - }, - impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - b := (^Reader)(s.stream_data) - return reader_read(b, p) - }, - impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) { - b := (^Reader)(s.stream_data) - return reader_read_byte(b) - }, - impl_unread_byte = proc(s: io.Stream) -> io.Error { - b := (^Reader)(s.stream_data) - return reader_unread_byte(b) - }, - impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) { - b := (^Reader)(s.stream_data) - return reader_read_rune(b) - }, - impl_unread_rune = proc(s: io.Stream) -> io.Error { - b := (^Reader)(s.stream_data) - return reader_unread_rune(b) - }, - impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) { - b := (^Reader)(s.stream_data) - return reader_write_to(b, w) - }, + return + case .Query: + return io.query_utility({.Read, .Destroy, .Query}) + } + return 0, .Empty } - - // // Utility procedures // diff --git a/core/bufio/writer.odin b/core/bufio/writer.odin index ed0d557c5..bfa8b804f 100644 --- a/core/bufio/writer.odin +++ b/core/bufio/writer.odin @@ -173,14 +173,6 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) { if b.err != nil { return 0, b.err } - if writer_buffered(b) == 0 { - if w, ok := io.to_reader_from(b.wr); !ok { - n, err = io.read_from(w, r) - b.err = err - return - } - } - for { if writer_available(b) == 0 { writer_flush(b) or_return @@ -222,46 +214,35 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) { // writer_to_stream converts a Writer into an io.Stream writer_to_stream :: proc(b: ^Writer) -> (s: io.Stream) { - s.stream_data = b - s.stream_vtable = &_writer_vtable + s.data = b + s.procedure = _writer_proc return } // writer_to_stream converts a Writer into an io.Stream writer_to_writer :: proc(b: ^Writer) -> (s: io.Writer) { - s.stream_data = b - s.stream_vtable = &_writer_vtable - return + return writer_to_stream(b) } - @(private) -_writer_vtable := io.Stream_VTable{ - impl_destroy = proc(s: io.Stream) -> io.Error { - b := (^Writer)(s.stream_data) +_writer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + b := (^Writer)(stream_data) + #partial switch mode { + case .Flush: + err = writer_flush(b) + return + case .Write: + n_int: int + n_int, err = writer_write(b, p) + n = i64(n_int) + return + case .Destroy: writer_destroy(b) - return nil - }, - impl_flush = proc(s: io.Stream) -> io.Error { - b := (^Writer)(s.stream_data) - return writer_flush(b) - }, - impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - b := (^Writer)(s.stream_data) - return writer_write(b, p) - }, - impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error { - b := (^Writer)(s.stream_data) - return writer_write_byte(b, c) - }, - impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) { - b := (^Writer)(s.stream_data) - return writer_write_rune(b, r) - }, - impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) { - b := (^Writer)(s.stream_data) - return writer_read_from(b, r) - }, + return + case .Query: + return io.query_utility({.Flush, .Write, .Destroy, .Query}) + } + return 0, .Empty } diff --git a/core/bytes/buffer.odin b/core/bytes/buffer.odin index b60a8e877..4375d8195 100644 --- a/core/bytes/buffer.odin +++ b/core/bytes/buffer.odin @@ -375,69 +375,31 @@ buffer_read_from :: proc(b: ^Buffer, r: io.Reader) -> (n: i64, err: io.Error) #n buffer_to_stream :: proc(b: ^Buffer) -> (s: io.Stream) { - s.stream_data = b - s.stream_vtable = &_buffer_vtable + s.data = b + s.procedure = _buffer_proc return } @(private) -_buffer_vtable := io.Stream_VTable{ - impl_size = proc(s: io.Stream) -> i64 { - b := (^Buffer)(s.stream_data) - return i64(buffer_capacity(b)) - }, - impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_read(b, p) - }, - impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_read_at(b, p, int(offset)) - }, - impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_read_byte(b) - }, - impl_read_rune = proc(s: io.Stream) -> (r: rune, size: int, err: io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_read_rune(b) - }, - impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_write(b, p) - }, - impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_write_at(b, p, int(offset)) - }, - impl_write_byte = proc(s: io.Stream, c: byte) -> io.Error { - b := (^Buffer)(s.stream_data) - return buffer_write_byte(b, c) - }, - impl_write_rune = proc(s: io.Stream, r: rune) -> (int, io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_write_rune(b, r) - }, - impl_unread_byte = proc(s: io.Stream) -> io.Error { - b := (^Buffer)(s.stream_data) - return buffer_unread_byte(b) - }, - impl_unread_rune = proc(s: io.Stream) -> io.Error { - b := (^Buffer)(s.stream_data) - return buffer_unread_rune(b) - }, - impl_destroy = proc(s: io.Stream) -> io.Error { - b := (^Buffer)(s.stream_data) +_buffer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + b := (^Buffer)(stream_data) + #partial switch mode { + case .Read: + return io._i64_err(buffer_read(b, p)) + case .Read_At: + return io._i64_err(buffer_read_at(b, p, int(offset))) + case .Write: + return io._i64_err(buffer_write(b, p)) + case .Write_At: + return io._i64_err(buffer_write_at(b, p, int(offset))) + case .Size: + n = i64(buffer_capacity(b)) + return + case .Destroy: buffer_destroy(b) - return nil - }, - impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_write_to(b, w) - }, - impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) { - b := (^Buffer)(s.stream_data) - return buffer_read_from(b, r) - }, + return + case .Query: + return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Size, .Destroy}) + } + return 0, .Empty } - diff --git a/core/bytes/reader.odin b/core/bytes/reader.odin index 7c37f3061..4b18345ba 100644 --- a/core/bytes/reader.odin +++ b/core/bytes/reader.odin @@ -16,8 +16,8 @@ reader_init :: proc(r: ^Reader, s: []byte) { } reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) { - s.stream_data = r - s.stream_vtable = &_reader_vtable + s.data = r + s.procedure = _reader_proc return } @@ -137,41 +137,22 @@ reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) { @(private) -_reader_vtable := io.Stream_VTable{ - impl_size = proc(s: io.Stream) -> i64 { - r := (^Reader)(s.stream_data) - return reader_size(r) - }, - impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - r := (^Reader)(s.stream_data) - return reader_read(r, p) - }, - impl_read_at = proc(s: io.Stream, p: []byte, off: i64) -> (n: int, err: io.Error) { - r := (^Reader)(s.stream_data) - return reader_read_at(r, p, off) - }, - impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) { - r := (^Reader)(s.stream_data) - return reader_read_byte(r) - }, - impl_unread_byte = proc(s: io.Stream) -> io.Error { - r := (^Reader)(s.stream_data) - return reader_unread_byte(r) - }, - impl_read_rune = proc(s: io.Stream) -> (ch: rune, size: int, err: io.Error) { - r := (^Reader)(s.stream_data) - return reader_read_rune(r) - }, - impl_unread_rune = proc(s: io.Stream) -> io.Error { - r := (^Reader)(s.stream_data) - return reader_unread_rune(r) - }, - impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) { - r := (^Reader)(s.stream_data) - return reader_seek(r, offset, whence) - }, - impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) { - r := (^Reader)(s.stream_data) - return reader_write_to(r, w) - }, +_reader_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + r := (^Reader)(stream_data) + #partial switch mode { + case .Read: + return io._i64_err(reader_read(r, p)) + case .Read_At: + return io._i64_err(reader_read_at(r, p, offset)) + case .Seek: + n, err = reader_seek(r, offset, whence) + return + case .Size: + n = reader_size(r) + return + case .Query: + return io.query_utility({.Read, .Read_At, .Seek, .Size, .Query}) + } + return 0, .Empty } + diff --git a/core/c/frontend/preprocessor/preprocess.odin b/core/c/frontend/preprocessor/preprocess.odin index 4cfad2c1c..b5eab0bb3 100644 --- a/core/c/frontend/preprocessor/preprocess.odin +++ b/core/c/frontend/preprocessor/preprocess.odin @@ -1118,7 +1118,7 @@ expand_macro :: proc(cpp: ^Preprocessor, rest: ^^Token, tok: ^Token) -> bool { search_include_next :: proc(cpp: ^Preprocessor, filename: string) -> (path: string, ok: bool) { for ; cpp.include_next_index < len(cpp.include_paths); cpp.include_next_index += 1 { - tpath := filepath.join(elems={cpp.include_paths[cpp.include_next_index], filename}, allocator=context.temp_allocator) + tpath := filepath.join({cpp.include_paths[cpp.include_next_index], filename}, allocator=context.temp_allocator) if os.exists(tpath) { return strings.clone(tpath), true } @@ -1136,7 +1136,7 @@ search_include_paths :: proc(cpp: ^Preprocessor, filename: string) -> (path: str } for include_path in cpp.include_paths { - tpath := filepath.join(elems={include_path, filename}, allocator=context.temp_allocator) + tpath := filepath.join({include_path, filename}, allocator=context.temp_allocator) if os.exists(tpath) { path, ok = strings.clone(tpath), true cpp.filepath_cache[filename] = path diff --git a/core/compress/common.odin b/core/compress/common.odin index 6bcc46bf2..bc56229c2 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -188,7 +188,8 @@ input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Erro } input_size_from_stream :: proc(z: ^Context_Stream_Input) -> (res: i64, err: Error) { - return io.size(z.input), nil + res, _ = io.size(z.input) + return } input_size :: proc{input_size_from_memory, input_size_from_stream} @@ -215,7 +216,7 @@ read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int // TODO: REMOVE ALL USE OF context.temp_allocator here // the is literally no need for it b := make([]u8, size, context.temp_allocator) - _, e := z.input->impl_read(b[:]) + _, e := io.read(z.input, b[:]) if e == .None { return b, .None } diff --git a/core/compress/gzip/gzip.odin b/core/compress/gzip/gzip.odin index 4de4d1b63..b0ca4491b 100644 --- a/core/compress/gzip/gzip.odin +++ b/core/compress/gzip/gzip.odin @@ -335,7 +335,7 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp // fmt.printf("GZIP: Expected Payload Size: %v\n", expected_output_size); - zlib_error := zlib.inflate_raw(z=z, expected_output_size=expected_output_size) + zlib_error := zlib.inflate_raw(z, expected_output_size=expected_output_size) if zlib_error != nil { return zlib_error } diff --git a/core/compress/zlib/zlib.odin b/core/compress/zlib/zlib.odin index 855eef7a8..21172e8e8 100644 --- a/core/compress/zlib/zlib.odin +++ b/core/compress/zlib/zlib.odin @@ -471,7 +471,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f } // Parse ZLIB stream without header. - inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return + inflate_raw(ctx, expected_output_size=expected_output_size) or_return if !raw { compress.discard_to_next_byte_lsb(ctx) @@ -665,7 +665,7 @@ inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, e ctx.input_data = input ctx.output = buf - return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size) + return inflate_from_context(&ctx, raw=raw, expected_output_size=expected_output_size) } inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) { @@ -674,7 +674,7 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals ctx.input_data = input ctx.output = buf - return inflate_raw(z=&ctx, expected_output_size=expected_output_size) + return inflate_raw(&ctx, expected_output_size=expected_output_size) } inflate :: proc{inflate_from_context, inflate_from_byte_array} diff --git a/core/container/topological_sort/topological_sort.odin b/core/container/topological_sort/topological_sort.odin index 4b69930d5..314e3e070 100644 --- a/core/container/topological_sort/topological_sort.odin +++ b/core/container/topological_sort/topological_sort.odin @@ -32,7 +32,7 @@ init :: proc(sorter: ^$S/Sorter($K)) { } destroy :: proc(sorter: ^$S/Sorter($K)) { - for _, v in &sorter.relations { + for _, v in sorter.relations { delete(v.dependents) } delete(sorter.relations) @@ -80,7 +80,7 @@ sort :: proc(sorter: ^$S/Sorter($K)) -> (sorted, cycled: [dynamic]K) { } } - for root in &sorted do for k, _ in relations[root].dependents { + for root in sorted do for k, _ in relations[root].dependents { relation := &relations[k] relation.dependencies -= 1 if relation.dependencies == 0 { diff --git a/core/crypto/blake/blake.odin b/core/crypto/blake/blake.odin index 5fc0a02b9..3685109e4 100644 --- a/core/crypto/blake/blake.odin +++ b/core/crypto/blake/blake.odin @@ -70,7 +70,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -149,7 +149,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -228,7 +228,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -307,7 +307,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index e75d74197..8f0770f82 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -77,7 +77,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _blake2.update(&ctx, buf[:read]) } diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index 831335081..6a2d4ab9b 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -77,7 +77,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _blake2.update(&ctx, buf[:read]) } diff --git a/core/crypto/gost/gost.odin b/core/crypto/gost/gost.odin index 1d0274fae..5aca8ce95 100644 --- a/core/crypto/gost/gost.odin +++ b/core/crypto/gost/gost.odin @@ -65,7 +65,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/groestl/groestl.odin b/core/crypto/groestl/groestl.odin index 8e5a2440d..61460808f 100644 --- a/core/crypto/groestl/groestl.odin +++ b/core/crypto/groestl/groestl.odin @@ -70,7 +70,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -149,7 +149,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -228,7 +228,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -307,7 +307,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/haval/haval.odin b/core/crypto/haval/haval.odin index 811ecf95d..b98facb33 100644 --- a/core/crypto/haval/haval.odin +++ b/core/crypto/haval/haval.odin @@ -79,7 +79,7 @@ hash_stream_128_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -164,7 +164,7 @@ hash_stream_128_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -249,7 +249,7 @@ hash_stream_128_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -334,7 +334,7 @@ hash_stream_160_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -419,7 +419,7 @@ hash_stream_160_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -504,7 +504,7 @@ hash_stream_160_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -589,7 +589,7 @@ hash_stream_192_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -674,7 +674,7 @@ hash_stream_192_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -759,7 +759,7 @@ hash_stream_192_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -844,7 +844,7 @@ hash_stream_224_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -929,7 +929,7 @@ hash_stream_224_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -1014,7 +1014,7 @@ hash_stream_224_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -1099,7 +1099,7 @@ hash_stream_256_3 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -1184,7 +1184,7 @@ hash_stream_256_4 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) @@ -1270,7 +1270,7 @@ hash_stream_256_5 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) ctx.str_len = u32(len(buf[:read])) if read > 0 { update(&ctx, buf[:read]) diff --git a/core/crypto/jh/jh.odin b/core/crypto/jh/jh.odin index 42c2d1d34..5dc6c4e6b 100644 --- a/core/crypto/jh/jh.odin +++ b/core/crypto/jh/jh.odin @@ -70,7 +70,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -149,7 +149,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -228,7 +228,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -307,7 +307,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/keccak/keccak.odin b/core/crypto/keccak/keccak.odin index aeb5aac52..4c74858d2 100644 --- a/core/crypto/keccak/keccak.odin +++ b/core/crypto/keccak/keccak.odin @@ -77,7 +77,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } @@ -159,7 +159,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } @@ -241,7 +241,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } @@ -323,7 +323,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } diff --git a/core/crypto/md2/md2.odin b/core/crypto/md2/md2.odin index 711e6e9f6..4942183e1 100644 --- a/core/crypto/md2/md2.odin +++ b/core/crypto/md2/md2.odin @@ -64,7 +64,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/md4/md4.odin b/core/crypto/md4/md4.odin index b2651225b..8efdbb5a5 100644 --- a/core/crypto/md4/md4.odin +++ b/core/crypto/md4/md4.odin @@ -68,7 +68,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/md5/md5.odin b/core/crypto/md5/md5.odin index 30a556102..858480b04 100644 --- a/core/crypto/md5/md5.odin +++ b/core/crypto/md5/md5.odin @@ -67,7 +67,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/ripemd/ripemd.odin b/core/crypto/ripemd/ripemd.odin index 702d29037..f9edb121b 100644 --- a/core/crypto/ripemd/ripemd.odin +++ b/core/crypto/ripemd/ripemd.odin @@ -69,7 +69,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -145,7 +145,7 @@ hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -221,7 +221,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -297,7 +297,7 @@ hash_stream_320 :: proc(s: io.Stream) -> ([DIGEST_SIZE_320]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/sha1/sha1.odin b/core/crypto/sha1/sha1.odin index b0dbd7dc8..599d1791e 100644 --- a/core/crypto/sha1/sha1.odin +++ b/core/crypto/sha1/sha1.odin @@ -67,7 +67,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 9792a4cb8..0f55c4be1 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -74,7 +74,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -153,7 +153,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -232,7 +232,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -311,7 +311,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index 1202f8b23..5d8ad2106 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -73,7 +73,7 @@ hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } @@ -152,7 +152,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } @@ -231,7 +231,7 @@ hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } @@ -310,7 +310,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index 525dcfbd3..020ba68f3 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -73,7 +73,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } @@ -155,7 +155,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _sha3.update(&ctx, buf[:read]) } diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index 74c9f22e2..9e684ff08 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -66,7 +66,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/streebog/streebog.odin b/core/crypto/streebog/streebog.odin index f85977cba..42da1e695 100644 --- a/core/crypto/streebog/streebog.odin +++ b/core/crypto/streebog/streebog.odin @@ -70,7 +70,7 @@ hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } @@ -146,7 +146,7 @@ hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/crypto/tiger/tiger.odin b/core/crypto/tiger/tiger.odin index cf6159fad..614926129 100644 --- a/core/crypto/tiger/tiger.odin +++ b/core/crypto/tiger/tiger.odin @@ -71,7 +71,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _tiger.update(&ctx, buf[:read]) } @@ -150,7 +150,7 @@ hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _tiger.update(&ctx, buf[:read]) } @@ -229,7 +229,7 @@ hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _tiger.update(&ctx, buf[:read]) } diff --git a/core/crypto/tiger2/tiger2.odin b/core/crypto/tiger2/tiger2.odin index e8f2c4edb..ead874d56 100644 --- a/core/crypto/tiger2/tiger2.odin +++ b/core/crypto/tiger2/tiger2.odin @@ -71,7 +71,7 @@ hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _tiger.update(&ctx, buf[:read]) } @@ -150,7 +150,7 @@ hash_stream_160 :: proc(s: io.Stream) -> ([DIGEST_SIZE_160]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _tiger.update(&ctx, buf[:read]) } @@ -229,7 +229,7 @@ hash_stream_192 :: proc(s: io.Stream) -> ([DIGEST_SIZE_192]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { _tiger.update(&ctx, buf[:read]) } diff --git a/core/crypto/whirlpool/whirlpool.odin b/core/crypto/whirlpool/whirlpool.odin index 0cfef7c6b..cf0bf6490 100644 --- a/core/crypto/whirlpool/whirlpool.odin +++ b/core/crypto/whirlpool/whirlpool.odin @@ -66,7 +66,7 @@ hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) { defer delete(buf) read := 1 for read > 0 { - read, _ = s->impl_read(buf) + read, _ = io.read(s, buf) if read > 0 { update(&ctx, buf[:read]) } diff --git a/core/debug/pe/section.odin b/core/debug/pe/section.odin index 809da8bb4..926306dbb 100644 --- a/core/debug/pe/section.odin +++ b/core/debug/pe/section.odin @@ -1,8 +1,5 @@ package debug_pe -import "core:runtime" -import "core:io" - Section_Header32 :: struct { name: [8]u8, virtual_size: u32le, diff --git a/core/dynlib/lib_js.odin b/core/dynlib/lib_js.odin index 37dab8758..ace1b0939 100644 --- a/core/dynlib/lib_js.odin +++ b/core/dynlib/lib_js.odin @@ -3,13 +3,13 @@ package dynlib _load_library :: proc(path: string, global_symbols := false) -> (Library, bool) { - return + return nil, false } _unload_library :: proc(library: Library) -> bool { - return + return false } _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) { - return + return nil, false } diff --git a/core/encoding/hxa/read.odin b/core/encoding/hxa/read.odin index abe295530..8a8636f19 100644 --- a/core/encoding/hxa/read.odin +++ b/core/encoding/hxa/read.odin @@ -83,7 +83,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato meta_data = make([]Meta, int(capacity)) count := 0 defer meta_data = meta_data[:count] - for m in &meta_data { + for &m in meta_data { m.name = read_name(r) or_return type := read_value(r, Meta_Value_Type) or_return @@ -116,7 +116,7 @@ read :: proc(data: []byte, filename := "<input>", print_error := false, allocato layer_count := 0 layers = make(Layer_Stack, stack_count) defer layers = layers[:layer_count] - for layer in &layers { + for &layer in layers { layer.name = read_name(r) or_return layer.components = read_value(r, u8) or_return type := read_value(r, Layer_Data_Type) or_return diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index e6c61d8fa..678f2dcfa 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -72,7 +72,7 @@ unmarshal_string :: proc(data: string, ptr: ^$T, spec := DEFAULT_SPECIFICATION, @(private) assign_bool :: proc(val: any, b: bool) -> bool { v := reflect.any_core(val) - switch dst in &v { + switch &dst in v { case bool: dst = bool(b) case b8: dst = b8 (b) case b16: dst = b16 (b) @@ -85,7 +85,7 @@ assign_bool :: proc(val: any, b: bool) -> bool { @(private) assign_int :: proc(val: any, i: $T) -> bool { v := reflect.any_core(val) - switch dst in &v { + switch &dst in v { case i8: dst = i8 (i) case i16: dst = i16 (i) case i16le: dst = i16le (i) @@ -122,7 +122,7 @@ assign_int :: proc(val: any, i: $T) -> bool { @(private) assign_float :: proc(val: any, f: $T) -> bool { v := reflect.any_core(val) - switch dst in &v { + switch &dst in v { case f16: dst = f16 (f) case f16le: dst = f16le(f) case f16be: dst = f16be(f) @@ -150,7 +150,7 @@ assign_float :: proc(val: any, f: $T) -> bool { @(private) unmarshal_string_token :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.Type_Info) -> bool { val := val - switch dst in &val { + switch &dst in val { case string: dst = str return true @@ -215,7 +215,7 @@ unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) { } } - switch dst in &v { + switch &dst in v { // Handle json.Value as an unknown type case Value: dst = parse_value(p) or_return diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 61f7b5d99..f1f94b1b3 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -123,7 +123,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist aprint :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str) - sbprint(buf=&str, args=args, sep=sep) + sbprint(&str, ..args, sep=sep) return strings.to_string(str) } // Creates a formatted string with a newline character at the end @@ -139,7 +139,7 @@ aprint :: proc(args: ..any, sep := " ") -> string { aprintln :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str) - sbprintln(buf=&str, args=args, sep=sep) + sbprintln(&str, ..args, sep=sep) return strings.to_string(str) } // Creates a formatted string using a format string and arguments @@ -171,7 +171,7 @@ aprintf :: proc(fmt: string, args: ..any) -> string { tprint :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) - sbprint(buf=&str, args=args, sep=sep) + sbprint(&str, ..args, sep=sep) return strings.to_string(str) } // Creates a formatted string with a newline character at the end @@ -187,7 +187,7 @@ tprint :: proc(args: ..any, sep := " ") -> string { tprintln :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) - sbprintln(buf=&str, args=args, sep=sep) + sbprintln(&str, ..args, sep=sep) return strings.to_string(str) } // Creates a formatted string using a format string and arguments @@ -217,7 +217,7 @@ tprintf :: proc(fmt: string, args: ..any) -> string { // bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string { sb := strings.builder_from_bytes(buf[0:len(buf)]) - return sbprint(buf=&sb, args=args, sep=sep) + return sbprint(&sb, ..args, sep=sep) } // Creates a formatted string using a supplied buffer as the backing array, appends newline. Writes into the buffer. // @@ -230,7 +230,7 @@ bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string { // bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string { sb := strings.builder_from_bytes(buf[0:len(buf)]) - return sbprintln(buf=&sb, args=args, sep=sep) + return sbprintln(&sb, ..args, sep=sep) } // Creates a formatted string using a supplied buffer as the backing array. Writes into the buffer. // @@ -327,7 +327,7 @@ ctprintf :: proc(format: string, args: ..any) -> cstring { // Returns: A formatted string // sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { - wprint(w=strings.to_writer(buf), args=args, sep=sep) + wprint(strings.to_writer(buf), ..args, sep=sep) return strings.to_string(buf^) } // Formats and writes to a strings.Builder buffer using the default print settings @@ -340,7 +340,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { // Returns: The resulting formatted string // sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { - wprintln(w=strings.to_writer(buf), args=args, sep=sep) + wprintln(strings.to_writer(buf), ..args, sep=sep) return strings.to_string(buf^) } // Formats and writes to a strings.Builder buffer according to the specified format string @@ -353,7 +353,7 @@ sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { // Returns: The resulting formatted string // sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any) -> string { - wprintf(w=strings.to_writer(buf), fmt=fmt, args=args) + wprintf(strings.to_writer(buf), fmt, ..args) return strings.to_string(buf^) } // Formats and writes to an io.Writer using the default print settings diff --git a/core/fmt/fmt_js.odin b/core/fmt/fmt_js.odin index 5e06041f5..881cde867 100644 --- a/core/fmt/fmt_js.odin +++ b/core/fmt/fmt_js.odin @@ -11,27 +11,24 @@ foreign odin_env { } @(private="file") -write_vtable := io.Stream_VTable{ - impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - fd := u32(uintptr(s.stream_data)) +write_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + if mode == .Write { + fd := u32(uintptr(stream_data)) write(fd, p) - return len(p), nil - }, + return i64(len(p)), nil + } + return 0, .Empty } @(private="file") stdout := io.Writer{ - stream = { - stream_vtable = &write_vtable, - stream_data = rawptr(uintptr(1)), - }, + procedure = write_stream_proc, + data = rawptr(uintptr(1)), } @(private="file") stderr := io.Writer{ - stream = { - stream_vtable = &write_vtable, - stream_data = rawptr(uintptr(2)), - }, + procedure = write_stream_proc, + data = rawptr(uintptr(2)), } // print formats using the default print settings and writes to stdout diff --git a/core/fmt/fmt_os.odin b/core/fmt/fmt_os.odin index 861b0c3b9..840fd1545 100644 --- a/core/fmt/fmt_os.odin +++ b/core/fmt/fmt_os.odin @@ -12,9 +12,9 @@ fprint :: proc(fd: os.Handle, args: ..any, sep := " ") -> int { b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:]) + bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) w := bufio.writer_to_writer(&b) - return wprint(w=w, args=args, sep=sep) + return wprint(w, ..args, sep=sep) } // fprintln formats using the default print settings and writes to fd @@ -23,10 +23,10 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ") -> int { b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:]) + bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) w := bufio.writer_to_writer(&b) - return wprintln(w=w, args=args, sep=sep) + return wprintln(w, ..args, sep=sep) } // fprintf formats according to the specified format string and writes to fd fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { @@ -34,7 +34,7 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int { b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:]) + bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) w := bufio.writer_to_writer(&b) return wprintf(w, fmt, ..args) @@ -44,7 +44,7 @@ fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) -> (n: int, err: io b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:]) + bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) w := bufio.writer_to_writer(&b) return wprint_type(w, info) @@ -54,22 +54,22 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid) -> (n: int, err: io.Error) { b: bufio.Writer defer bufio.writer_flush(&b) - bufio.writer_init_with_buf(&b, {os.stream_from_handle(fd)}, buf[:]) + bufio.writer_init_with_buf(&b, os.stream_from_handle(fd), buf[:]) w := bufio.writer_to_writer(&b) return wprint_typeid(w, id) } // print formats using the default print settings and writes to os.stdout -print :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stdout, args=args, sep=sep) } +print :: proc(args: ..any, sep := " ") -> int { return fprint(os.stdout, ..args, sep=sep) } // println formats using the default print settings and writes to os.stdout -println :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stdout, args=args, sep=sep) } +println :: proc(args: ..any, sep := " ") -> int { return fprintln(os.stdout, ..args, sep=sep) } // printf formats according to the specified format string and writes to os.stdout printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args) } // eprint formats using the default print settings and writes to os.stderr -eprint :: proc(args: ..any, sep := " ") -> int { return fprint(fd=os.stderr, args=args, sep=sep) } +eprint :: proc(args: ..any, sep := " ") -> int { return fprint(os.stderr, ..args, sep=sep) } // eprintln formats using the default print settings and writes to os.stderr -eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(fd=os.stderr, args=args, sep=sep) } +eprintln :: proc(args: ..any, sep := " ") -> int { return fprintln(os.stderr, ..args, sep=sep) } // eprintf formats according to the specified format string and writes to os.stderr eprintf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args) } diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index cb07b1e3a..74e482cb4 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -161,18 +161,18 @@ save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context // convert from native endianness if img.depth == 16 { pixels := mem.slice_data_cast([]u16be, data.buf[len(header_buf):]) - for p in &pixels { + for &p in pixels { p = u16be(transmute(u16) p) } } else if header.format in PFM { if header.little_endian { pixels := mem.slice_data_cast([]f32le, data.buf[len(header_buf):]) - for p in &pixels { + for &p in pixels { p = f32le(transmute(f32) p) } } else { pixels := mem.slice_data_cast([]f32be, data.buf[len(header_buf):]) - for p in &pixels { + for &p in pixels { p = f32be(transmute(f32) p) } } @@ -578,18 +578,18 @@ decode_image :: proc(img: ^Image, header: Header, data: []byte, allocator := con if header.format in PFM { pixels := mem.slice_data_cast([]f32, img.pixels.buf[:]) if header.little_endian { - for p in &pixels { + for &p in pixels { p = f32(transmute(f32le) p) } } else { - for p in &pixels { + for &p in pixels { p = f32(transmute(f32be) p) } } } else { if img.depth == 16 { pixels := mem.slice_data_cast([]u16, img.pixels.buf[:]) - for p in &pixels { + for &p in pixels { p = u16(transmute(u16be) p) } } diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index bfe56d62e..889b3cb6b 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -36,7 +36,7 @@ destroy :: proc(img: ^Image) { bytes.buffer_destroy(&img.pixels) if v, ok := img.metadata.(^image.PNG_Info); ok { - for chunk in &v.chunks { + for chunk in v.chunks { delete(chunk.data) } delete(v.chunks) @@ -99,7 +99,7 @@ text :: proc(c: image.PNG_Chunk) -> (res: Text, ok: bool) { case .tEXt: ok = true - fields := bytes.split(s=c.data, sep=[]u8{0}, allocator=context.temp_allocator) + fields := bytes.split(c.data, sep=[]u8{0}, allocator=context.temp_allocator) if len(fields) == 2 { res.keyword = strings.clone(string(fields[0])) res.text = strings.clone(string(fields[1])) @@ -110,7 +110,7 @@ text :: proc(c: image.PNG_Chunk) -> (res: Text, ok: bool) { case .zTXt: ok = true - fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator) + fields := bytes.split_n(c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator) if len(fields) != 3 || len(fields[1]) != 0 { // Compression method must be 0=Deflate, which thanks to the split above turns // into an empty slice @@ -199,7 +199,7 @@ text_destroy :: proc(text: Text) { iccp :: proc(c: image.PNG_Chunk) -> (res: iCCP, ok: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) - fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator) + fields := bytes.split_n(c.data, sep=[]u8{0}, n=3, allocator=context.temp_allocator) if len(fields[0]) < 1 || len(fields[0]) > 79 { // Invalid profile name @@ -263,7 +263,7 @@ splt :: proc(c: image.PNG_Chunk) -> (res: sPLT, ok: bool) { } runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator) - fields := bytes.split_n(s=c.data, sep=[]u8{0}, n=2, allocator=context.temp_allocator) + fields := bytes.split_n(c.data, sep=[]u8{0}, n=2, allocator=context.temp_allocator) if len(fields) != 2 { return } diff --git a/core/io/conv.odin b/core/io/conv.odin index 39a72d69d..e3286baca 100644 --- a/core/io/conv.odin +++ b/core/io/conv.odin @@ -1,124 +1,80 @@ package io to_reader :: proc(s: Stream) -> (r: Reader, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable == nil || s.impl_read == nil { - ok = false - } + r = s + ok = .Read in query(s) return } to_writer :: proc(s: Stream) -> (w: Writer, ok: bool = true) #optional_ok { - w.stream = s - if s.stream_vtable == nil || s.impl_write == nil { - ok = false - } + w = s + ok = .Write in query(s) return } to_closer :: proc(s: Stream) -> (c: Closer, ok: bool = true) #optional_ok { - c.stream = s - if s.stream_vtable == nil || s.impl_close == nil { - ok = false - } + c = s + ok = .Close in query(s) return } to_flusher :: proc(s: Stream) -> (f: Flusher, ok: bool = true) #optional_ok { - f.stream = s - if s.stream_vtable == nil || s.impl_flush == nil { - ok = false - } + f = s + ok = .Flush in query(s) return } to_seeker :: proc(s: Stream) -> (seeker: Seeker, ok: bool = true) #optional_ok { - seeker.stream = s - if s.stream_vtable == nil || s.impl_seek == nil { - ok = false - } + seeker = s + ok = .Seek in query(s) return } to_read_writer :: proc(s: Stream) -> (r: Read_Writer, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable == nil || s.impl_read == nil || s.impl_write == nil { - ok = false - } + r = s + ok = query(s) >= {.Read, .Write} return } to_read_closer :: proc(s: Stream) -> (r: Read_Closer, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable == nil || s.impl_read == nil || s.impl_close == nil { - ok = false - } + r = s + ok = query(s) >= {.Read, .Close} return } to_read_write_closer :: proc(s: Stream) -> (r: Read_Write_Closer, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable == nil || s.impl_read == nil || s.impl_write == nil || s.impl_close == nil { - ok = false - } + r = s + ok = query(s) >= {.Read, .Write, .Close} return } to_read_write_seeker :: proc(s: Stream) -> (r: Read_Write_Seeker, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable == nil || s.impl_read == nil || s.impl_write == nil || s.impl_seek == nil { - ok = false - } + r = s + ok = query(s) >= {.Read, .Write, .Seek} return } to_write_flusher :: proc(s: Stream) -> (w: Write_Flusher, ok: bool = true) #optional_ok { - w.stream = s - if s.stream_vtable == nil || s.impl_write == nil || s.impl_flush == nil { - ok = false - } + w = s + ok = query(s) >= {.Write, .Flush} return } to_write_flush_closer :: proc(s: Stream) -> (w: Write_Flush_Closer, ok: bool = true) #optional_ok { - w.stream = s - if s.stream_vtable == nil || s.impl_write == nil || s.impl_flush == nil || s.impl_close == nil { - ok = false - } + w = s + ok = query(s) >= {.Write, .Flush, .Close} return } to_reader_at :: proc(s: Stream) -> (r: Reader_At, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable == nil || s.impl_read_at == nil { - ok = false - } + r = s + ok = query(s) >= {.Read_At} return } to_writer_at :: proc(s: Stream) -> (w: Writer_At, ok: bool = true) #optional_ok { - w.stream = s - if s.stream_vtable == nil || s.impl_write_at == nil { - ok = false - } - return -} -to_reader_from :: proc(s: Stream) -> (r: Reader_From, ok: bool = true) #optional_ok { - r.stream = s - if s.stream_vtable == nil || s.impl_read_from == nil { - ok = false - } - return -} -to_writer_to :: proc(s: Stream) -> (w: Writer_To, ok: bool = true) #optional_ok { - w.stream = s - if s.stream_vtable == nil || s.impl_write_to == nil { - ok = false - } + w = s + ok = query(s) >= {.Write_At} return } to_write_closer :: proc(s: Stream) -> (w: Write_Closer, ok: bool = true) #optional_ok { - w.stream = s - if s.stream_vtable == nil || s.impl_write == nil || s.impl_close == nil { - ok = false - } + w = s + ok = query(s) >= {.Write, .Close} return } to_write_seeker :: proc(s: Stream) -> (w: Write_Seeker, ok: bool = true) #optional_ok { - w.stream = s - if s.stream_vtable == nil || s.impl_write == nil || s.impl_seek == nil { - ok = false - } + w = s + ok = query(s) >= {.Write, .Seek} return } diff --git a/core/io/io.odin b/core/io/io.odin index 7faa500b1..566e13c54 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -53,137 +53,106 @@ Error :: enum i32 { Empty = -1, } -Close_Proc :: proc(using s: Stream) -> Error -Flush_Proc :: proc(using s: Stream) -> Error -Seek_Proc :: proc(using s: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error) -Size_Proc :: proc(using s: Stream) -> i64 -Read_Proc :: proc(using s: Stream, p: []byte) -> (n: int, err: Error) -Read_At_Proc :: proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error) -Read_From_Proc :: proc(using s: Stream, r: Reader) -> (n: i64, err: Error) -Read_Byte_Proc :: proc(using s: Stream) -> (byte, Error) -Read_Rune_Proc :: proc(using s: Stream) -> (ch: rune, size: int, err: Error) -Unread_Byte_Proc :: proc(using s: Stream) -> Error -Unread_Rune_Proc :: proc(using s: Stream) -> Error -Write_Proc :: proc(using s: Stream, p: []byte) -> (n: int, err: Error) -Write_At_Proc :: proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error) -Write_To_Proc :: proc(using s: Stream, w: Writer) -> (n: i64, err: Error) -Write_Byte_Proc :: proc(using s: Stream, c: byte) -> Error -Write_Rune_Proc :: proc(using s: Stream, r: rune) -> (size: int, err: Error) -Destroy_Proc :: proc(using s: Stream) -> Error - - -Stream :: struct { - using stream_vtable: ^Stream_VTable, - stream_data: rawptr, +Stream_Mode :: enum { + Close, + Flush, + Read, + Read_At, + Write, + Write_At, + Seek, + Size, + Destroy, + Query, // query what modes are available } -Stream_VTable :: struct { - impl_close: Close_Proc, - impl_flush: Flush_Proc, - - impl_seek: Seek_Proc, - impl_size: Size_Proc, - impl_read: Read_Proc, - impl_read_at: Read_At_Proc, - impl_read_byte: Read_Byte_Proc, - impl_read_rune: Read_Rune_Proc, - impl_write_to: Write_To_Proc, +Stream_Mode_Set :: distinct bit_set[Stream_Mode; i64] - impl_write: Write_Proc, - impl_write_at: Write_At_Proc, - impl_write_byte: Write_Byte_Proc, - impl_write_rune: Write_Rune_Proc, - impl_read_from: Read_From_Proc, +Stream_Proc :: #type proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) - impl_unread_byte: Unread_Byte_Proc, - impl_unread_rune: Unread_Rune_Proc, - - impl_destroy: Destroy_Proc, +Stream :: struct { + procedure: Stream_Proc, + data: rawptr, } +Reader :: Stream +Writer :: Stream +Closer :: Stream +Flusher :: Stream +Seeker :: Stream -Reader :: struct {using stream: Stream} -Writer :: struct {using stream: Stream} -Closer :: struct {using stream: Stream} -Flusher :: struct {using stream: Stream} -Seeker :: struct {using stream: Stream} - -Read_Writer :: struct {using stream: Stream} -Read_Closer :: struct {using stream: Stream} -Read_Write_Closer :: struct {using stream: Stream} -Read_Write_Seeker :: struct {using stream: Stream} +Read_Writer :: Stream +Read_Closer :: Stream +Read_Write_Closer :: Stream +Read_Write_Seeker :: Stream -Write_Closer :: struct {using stream: Stream} -Write_Seeker :: struct {using stream: Stream} -Write_Flusher :: struct {using stream: Stream} -Write_Flush_Closer :: struct {using stream: Stream} +Write_Closer :: Stream +Write_Seeker :: Stream +Write_Flusher :: Stream +Write_Flush_Closer :: Stream -Reader_At :: struct {using stream: Stream} -Writer_At :: struct {using stream: Stream} -Reader_From :: struct {using stream: Stream} -Writer_To :: struct {using stream: Stream} +Reader_At :: Stream +Writer_At :: Stream -destroy :: proc(s: Stream) -> Error { - close_err := close({s}) - if s.stream_vtable != nil && s.impl_destroy != nil { - return s->impl_destroy() +destroy :: proc(s: Stream) -> (err: Error) { + _ = flush(s) + _ = close(s) + if s.procedure != nil { + _, err = s.procedure(s.data, .Destroy, nil, 0, nil) + } else { + err = .Empty } - if close_err != .None { - return close_err + return +} + +query :: proc(s: Stream) -> (set: Stream_Mode_Set) { + if s.procedure != nil { + n, _ := s.procedure(s.data, .Query, nil, 0, nil) + set = transmute(Stream_Mode_Set)n + if set != nil { + set += {.Query} + } } - return .Empty + return +} + +query_utility :: #force_inline proc "contextless" (set: Stream_Mode_Set) -> (n: i64, err: Error) { + return transmute(i64)set, nil } +_i64_err :: #force_inline proc "contextless" (n: int, err: Error) -> (i64, Error) { + return i64(n), err +} + + // read reads up to len(p) bytes into s. It returns the number of bytes read and any error if occurred. // // When read encounters an .EOF or error after successfully reading n > 0 bytes, it returns the number of // bytes read along with the error. read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) { - if s.stream_vtable != nil { - if s.impl_read != nil { - n, err = s->impl_read(p) - if n_read != nil { - n_read^ += n - } - return - } else if s.impl_read_byte != nil { - bytes_read := 0 - defer if n_read != nil { - n_read^ += bytes_read - } - for _, i in p { - p[i] = s->impl_read_byte() or_return - bytes_read += 1 - } - return - } + if s.procedure != nil { + n64: i64 + n64, err = s.procedure(s.data, .Read, p, 0, nil) + n = int(n64) + if n_read != nil { n_read^ += n } + } else { + err = .Empty } - return 0, .Empty + return } // write writes up to len(p) bytes into s. It returns the number of bytes written and any error if occurred. write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) { - if s.stream_vtable != nil { - if s.impl_write != nil { - n, err = s->impl_write(p) - if n_written != nil { - n_written^ += n - } - return - } else if s.impl_write_byte != nil { - bytes_written := 0 - defer if n_written != nil { - n_written^ += bytes_written - } - for c in p { - s->impl_write_byte(c) or_return - bytes_written += 1 - } - return - } + if s.procedure != nil { + n64: i64 + n64, err = s.procedure(s.data, .Write, p, 0, nil) + n = int(n64) + if n_written != nil { n_written^ += n } + } else { + err = .Empty } - return 0, .Empty + return } // seek sets the offset of the next read or write to offset. @@ -194,57 +163,45 @@ write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Erro // // seek returns the new offset to the start of the file/stream, and any error if occurred. seek :: proc(s: Seeker, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { - if s.stream_vtable != nil && s.impl_seek != nil { - return s->impl_seek(offset, whence) + if s.procedure != nil { + n, err = s.procedure(s.data, .Seek, nil, offset, whence) + } else { + err = .Empty } - return 0, .Empty + return } // The behaviour of close after the first call is stream implementation defined. // Different streams may document their own behaviour. -close :: proc(s: Closer) -> Error { - if s.stream_vtable != nil && s.impl_close != nil { - return s->impl_close() +close :: proc(s: Closer) -> (err: Error) { + if s.procedure != nil { + _, err = s.procedure(s.data, .Close, nil, 0, nil) } - // Instead of .Empty, .None is fine in this case - return .None + return } -flush :: proc(s: Flusher) -> Error { - if s.stream_vtable != nil && s.impl_flush != nil { - return s->impl_flush() +flush :: proc(s: Flusher) -> (err: Error) { + if s.procedure != nil { + _, err = s.procedure(s.data, .Flush, nil, 0, nil) } - // Instead of .Empty, .None is fine in this case - return .None + return } // size returns the size of the stream. If the stream does not support querying its size, 0 will be returned. -size :: proc(s: Stream) -> i64 { - if s.stream_vtable == nil { - return 0 - } - if s.impl_size != nil { - return s->impl_size() - } - if s.impl_seek == nil { - return 0 - } - - curr, end: i64 - err: Error - if curr, err = s->impl_seek(0, .Current); err != nil { - return 0 - } - - if end, err = s->impl_seek(0, .End); err != nil { - return 0 - } - - if _, err = s->impl_seek(curr, .Start); err != nil { - return 0 +size :: proc(s: Stream) -> (n: i64, err: Error) { + if s.procedure != nil { + n, err = s.procedure(s.data, .Size, nil, 0, nil) + if err == .Empty { + n = 0 + curr := seek(s, 0, .Current) or_return + end := seek(s, 0, .End) or_return + seek(s, curr, .Start) or_return + n = end + } + } else { + err = .Empty } - - return end + return } @@ -256,29 +213,24 @@ size :: proc(s: Stream) -> i64 { // // If n == len(p), err may be either nil or .EOF read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n: int, err: Error) { - defer if n_read != nil { - n_read^ += n - } - - if r.stream_vtable == nil { - return 0, .Empty - } - if r.impl_read_at != nil { - return r->impl_read_at(p, offset) - } - if r.impl_seek == nil || r.impl_read == nil { - return 0, .Empty - } - - curr_offset := r->impl_seek(offset, .Current) or_return - - n, err = r->impl_read(p) - _, err1 := r->impl_seek(curr_offset, .Start) - if err1 != nil && err == nil { - err = err1 + if r.procedure != nil { + n64: i64 + n64, err = r.procedure(r.data, .Read_At, p, offset, nil) + if err != .Empty { + n = int(n64) + } else { + curr := seek(r, offset, .Current) or_return + n, err = read(r, p) + _, err1 := seek(r, curr, .Start) + if err1 != nil && err == nil { + err = err1 + } + } + if n_read != nil { n_read^ += n } + } else { + err = .Empty } return - } // write_at writes len(p) bytes into p starting with the provided offset in the underlying Writer_At stream w. @@ -287,97 +239,39 @@ read_at :: proc(r: Reader_At, p: []byte, offset: i64, n_read: ^int = nil) -> (n: // If write_at is writing to a Writer_At which has a seek offset, then write_at should not affect the underlying // seek offset. write_at :: proc(w: Writer_At, p: []byte, offset: i64, n_written: ^int = nil) -> (n: int, err: Error) { - defer if n_written != nil { - n_written^ += n - } - - if w.stream_vtable == nil { - return 0, .Empty - } - if w.impl_write_at != nil { - return w->impl_write_at(p, offset) - } - if w.impl_seek == nil || w.impl_write == nil { - return 0, .Empty - } - - curr_offset: i64 - curr_offset, err = w->impl_seek(offset, .Current) - if err != nil { - return 0, err - } - - n, err = w->impl_write(p) - _, err1 := w->impl_seek(curr_offset, .Start) - if err1 != nil && err == nil { - err = err1 + if w.procedure != nil { + n64: i64 + n64, err = w.procedure(w.data, .Write_At, p, offset, nil) + if err != .Empty { + n = int(n64) + } else { + curr := seek(w, offset, .Current) or_return + n, err = write(w, p) + _, err1 := seek(w, curr, .Start) + if err1 != nil && err == nil { + err = err1 + } + } + if n_written != nil { n_written^ += n } + } else { + err = .Empty } return } -write_to :: proc(r: Writer_To, w: Writer) -> (n: i64, err: Error) { - if r.stream_vtable == nil || w.stream_vtable == nil { - return 0, .Empty - } - if r.impl_write_to != nil { - return r->impl_write_to(w) - } - return 0, .Empty -} -read_from :: proc(w: Reader_From, r: Reader) -> (n: i64, err: Error) { - if r.stream_vtable == nil || w.stream_vtable == nil { - return 0, .Empty - } - if r.impl_read_from != nil { - return w->impl_read_from(r) - } - return 0, .Empty -} - - // read_byte reads and returns the next byte from r. read_byte :: proc(r: Reader, n_read: ^int = nil) -> (b: byte, err: Error) { - defer if err == nil && n_read != nil { - n_read^ += 1 - } - - if r.stream_vtable == nil { - return 0, .Empty - } - if r.impl_read_byte != nil { - return r->impl_read_byte() - } - if r.impl_read == nil { - return 0, .Empty - } - buf: [1]byte - _, err = r->impl_read(buf[:]) - return buf[0], err + _, err = read(r, buf[:], n_read) + b = buf[0] + return } write_byte :: proc(w: Writer, c: byte, n_written: ^int = nil) -> Error { - return _write_byte(auto_cast w, c, n_written) -} - -@(private) -_write_byte :: proc(w: Writer, c: byte, n_written: ^int = nil) -> (err: Error) { - defer if err == nil && n_written != nil { - n_written^ += 1 - } - if w.stream_vtable == nil { - return .Empty - } - if w.impl_write_byte != nil { - return w->impl_write_byte(c) - } - if w.impl_write == nil { - return .Empty - } - - b := [1]byte{c} - _, err = w->impl_write(b[:]) - return err + buf: [1]byte + buf[0] = c + write(w, buf[:], n_written) or_return + return nil } // read_rune reads a single UTF-8 encoded Unicode codepoint and returns the rune and its size in bytes. @@ -385,19 +279,9 @@ read_rune :: proc(br: Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: defer if err == nil && n_read != nil { n_read^ += size } - if br.stream_vtable == nil { - return 0, 0, .Empty - } - if br.impl_read_rune != nil { - return br->impl_read_rune() - } - if br.impl_read == nil { - return 0, 0, .Empty - } b: [utf8.UTF_MAX]byte - _, err = br->impl_read(b[:1]) - + _, err = read(br, b[:1]) s0 := b[0] ch = rune(s0) @@ -415,7 +299,7 @@ read_rune :: proc(br: Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: return } sz := int(x&7) - size, err = br->impl_read(b[1:sz]) + size, err = read(br, b[1:sz]) if err != nil || size+1 < sz { ch = utf8.RUNE_ERROR return @@ -425,28 +309,6 @@ read_rune :: proc(br: Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: return } -unread_byte :: proc(s: Stream) -> Error { - if s.stream_vtable == nil { - return .Empty - } - if s.impl_unread_byte != nil { - return s->impl_unread_byte() - } - if s.impl_seek != nil { - _, err := s->impl_seek(-1, .Current) - return err - } - - return .Empty -} -unread_rune :: proc(s: Writer) -> Error { - if s.stream_vtable != nil && s.impl_unread_rune != nil { - return s->impl_unread_rune() - } - return .Empty -} - - // write_string writes the contents of the string s to w. write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, err: Error) { return write(s, transmute([]byte)str, n_written) @@ -457,14 +319,6 @@ write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err defer if err == nil && n_written != nil { n_written^ += size } - - if s.stream_vtable == nil { - return 0, .Empty - } - if s.impl_write_rune != nil { - return s->impl_write_rune(r) - } - if r < utf8.RUNE_SELF { err = write_byte(s, byte(r)) if err == nil { @@ -542,21 +396,15 @@ copy_n :: proc(dst: Writer, src: Reader, n: i64) -> (written: i64, err: Error) { @(private) _copy_buffer :: proc(dst: Writer, src: Reader, buf: []byte) -> (written: i64, err: Error) { - if dst.stream_vtable == nil || src.stream_vtable == nil { + if dst.procedure == nil || src.procedure == nil { return 0, .Empty } - if src.impl_write_to != nil { - return src->impl_write_to(dst) - } - if src.impl_read_from != nil { - return dst->impl_read_from(src) - } buf := buf if buf == nil { DEFAULT_SIZE :: 4 * 1024 size := DEFAULT_SIZE - if src.stream_vtable == _limited_reader_vtable { - l := (^Limited_Reader)(src.stream_data) + if src.procedure == _limited_reader_proc { + l := (^Limited_Reader)(src.data) if i64(size) > l.n { if l.n < 1 { size = 1 diff --git a/core/io/multi.odin b/core/io/multi.odin index 64c533e37..e85114a7a 100644 --- a/core/io/multi.odin +++ b/core/io/multi.odin @@ -5,33 +5,37 @@ Multi_Reader :: struct { } @(private) -_multi_reader_vtable := &Stream_VTable{ - impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) { - mr := (^Multi_Reader)(s.stream_data) - for len(mr.readers) > 0 { - r := mr.readers[0] - n, err = read(r, p) - if err == .EOF { - ordered_remove(&mr.readers, 0) - } - if n > 0 || err != .EOF { - if err == .EOF && len(mr.readers) > 0 { - // Don't return EOF yet, more readers remain - err = nil - } - return +_multi_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { + if mode == .Query { + return query_utility({.Read, .Query}) + } else if mode != .Read { + return 0, .Empty + } + mr := (^Multi_Reader)(stream_data) + for len(mr.readers) > 0 { + r := mr.readers[0] + n, err = _i64_err(read(r, p)) + if err == .EOF { + ordered_remove(&mr.readers, 0) + } + if n > 0 || err != .EOF { + if err == .EOF && len(mr.readers) > 0 { + // Don't return EOF yet, more readers remain + err = nil } + return } - return 0, .EOF - }, + } + return 0, .EOF } + multi_reader_init :: proc(mr: ^Multi_Reader, readers: ..Reader, allocator := context.allocator) -> (r: Reader) { all_readers := make([dynamic]Reader, 0, len(readers), allocator) for w in readers { - if w.stream_vtable == _multi_reader_vtable { - other := (^Multi_Reader)(w.stream_data) + if w.procedure == _multi_reader_proc { + other := (^Multi_Reader)(w.data) append(&all_readers, ..other.readers[:]) } else { append(&all_readers, w) @@ -40,8 +44,8 @@ multi_reader_init :: proc(mr: ^Multi_Reader, readers: ..Reader, allocator := con mr.readers = all_readers - r.stream_vtable = _multi_reader_vtable - r.stream_data = mr + r.procedure = _multi_reader_proc + r.data = mr return } @@ -55,38 +59,42 @@ Multi_Writer :: struct { } @(private) -_multi_writer_vtable := &Stream_VTable{ - impl_write = proc(s: Stream, p: []byte) -> (n: int, err: Error) { - mw := (^Multi_Writer)(s.stream_data) - for w in mw.writers { - n, err = write(w, p) - if err != nil { - return - } - if n != len(p) { - err = .Short_Write - return - } +_multi_writer_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { + if mode == .Query { + return query_utility({.Write, .Query}) + } else if mode != .Write { + return 0, .Empty + } + mw := (^Multi_Writer)(stream_data) + for w in mw.writers { + n, err = _i64_err(write(w, p)) + if err != nil { + return + } + if n != i64(len(p)) { + err = .Short_Write + return } + } - return len(p), nil - }, + return i64(len(p)), nil } + multi_writer_init :: proc(mw: ^Multi_Writer, writers: ..Writer, allocator := context.allocator) -> (out: Writer) { mw.writers = make([dynamic]Writer, 0, len(writers), allocator) for w in writers { - if w.stream_vtable == _multi_writer_vtable { - other := (^Multi_Writer)(w.stream_data) + if w.procedure == _multi_writer_proc { + other := (^Multi_Writer)(w.data) append(&mw.writers, ..other.writers[:]) } else { append(&mw.writers, w) } } - out.stream_vtable = _multi_writer_vtable - out.stream_data = mw + out.procedure = _multi_writer_proc + out.data = mw return } diff --git a/core/io/util.odin b/core/io/util.odin index cfd7d3608..c77d0be9d 100644 --- a/core/io/util.odin +++ b/core/io/util.odin @@ -292,17 +292,21 @@ Tee_Reader :: struct { } @(private) -_tee_reader_vtable := &Stream_VTable{ - impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) { - t := (^Tee_Reader)(s.stream_data) - n, err = read(t.r, p) +_tee_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { + t := (^Tee_Reader)(stream_data) + #partial switch mode { + case .Read: + n, err = _i64_err(read(t.r, p)) if n > 0 { if wn, werr := write(t.w, p[:n]); werr != nil { - return wn, werr + return i64(wn), werr } } return - }, + case .Query: + return query_utility({.Read, .Query}) + } + return 0, .Empty } // tee_reader_init returns a Reader that writes to 'w' what it reads from 'r' @@ -317,8 +321,8 @@ tee_reader_init :: proc(t: ^Tee_Reader, r: Reader, w: Writer, allocator := conte } tee_reader_to_reader :: proc(t: ^Tee_Reader) -> (r: Reader) { - r.stream_data = t - r.stream_vtable = _tee_reader_vtable + r.data = t + r.procedure = _tee_reader_proc return } @@ -332,9 +336,10 @@ Limited_Reader :: struct { } @(private) -_limited_reader_vtable := &Stream_VTable{ - impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) { - l := (^Limited_Reader)(s.stream_data) +_limited_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { + l := (^Limited_Reader)(stream_data) + #partial switch mode { + case .Read: if l.n <= 0 { return 0, .EOF } @@ -342,10 +347,13 @@ _limited_reader_vtable := &Stream_VTable{ if i64(len(p)) > l.n { p = p[0:l.n] } - n, err = read(l.r, p) + n, err = _i64_err(read(l.r, p)) l.n -= i64(n) return - }, + case .Query: + return query_utility({.Read, .Query}) + } + return 0, .Empty } limited_reader_init :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader { @@ -355,8 +363,8 @@ limited_reader_init :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader { } limited_reader_to_reader :: proc(l: ^Limited_Reader) -> (r: Reader) { - r.stream_vtable = _limited_reader_vtable - r.stream_data = l + r.procedure = _limited_reader_proc + r.data = l return } @@ -375,15 +383,16 @@ section_reader_init :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64) return } section_reader_to_stream :: proc(s: ^Section_Reader) -> (out: Stream) { - out.stream_data = s - out.stream_vtable = _section_reader_vtable + out.data = s + out.procedure = _section_reader_proc return } @(private) -_section_reader_vtable := &Stream_VTable{ - impl_read = proc(stream: Stream, p: []byte) -> (n: int, err: Error) { - s := (^Section_Reader)(stream.stream_data) +_section_reader_proc :: proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { + s := (^Section_Reader)(stream_data) + #partial switch mode { + case .Read: if s.off >= s.limit { return 0, .EOF } @@ -391,13 +400,11 @@ _section_reader_vtable := &Stream_VTable{ if max := s.limit - s.off; i64(len(p)) > max { p = p[0:max] } - n, err = read_at(s.r, p, s.off) + n, err = _i64_err(read_at(s.r, p, s.off)) s.off += i64(n) return - }, - impl_read_at = proc(stream: Stream, p: []byte, off: i64) -> (n: int, err: Error) { - s := (^Section_Reader)(stream.stream_data) - p, off := p, off + case .Read_At: + p, off := p, offset if off < 0 || off >= s.limit - s.base { return 0, .EOF @@ -405,17 +412,15 @@ _section_reader_vtable := &Stream_VTable{ off += s.base if max := s.limit - off; i64(len(p)) > max { p = p[0:max] - n, err = read_at(s.r, p, off) + n, err = _i64_err(read_at(s.r, p, off)) if err == nil { err = .EOF } return } - return read_at(s.r, p, off) - }, - impl_seek = proc(stream: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error) { - s := (^Section_Reader)(stream.stream_data) + return _i64_err(read_at(s.r, p, off)) + case .Seek: offset := offset switch whence { case: @@ -433,10 +438,12 @@ _section_reader_vtable := &Stream_VTable{ s.off = offset n = offset - s.base return - }, - impl_size = proc(stream: Stream) -> i64 { - s := (^Section_Reader)(stream.stream_data) - return s.limit - s.base - }, -} + case .Size: + n = s.limit - s.base + return + case .Query: + return query_utility({.Read, .Read_At, .Seek, .Size, .Query}) + } + return 0, nil +} diff --git a/core/log/log.odin b/core/log/log.odin index a699247b8..f3554791b 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -76,43 +76,43 @@ nil_logger :: proc() -> Logger { } debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) { - logf(level=.Debug, fmt_str=fmt_str, args=args, location=location) + logf(.Debug, fmt_str, ..args, location=location) } infof :: proc(fmt_str: string, args: ..any, location := #caller_location) { - logf(level=.Info, fmt_str=fmt_str, args=args, location=location) + logf(.Info, fmt_str, ..args, location=location) } warnf :: proc(fmt_str: string, args: ..any, location := #caller_location) { - logf(level=.Warning, fmt_str=fmt_str, args=args, location=location) + logf(.Warning, fmt_str, ..args, location=location) } errorf :: proc(fmt_str: string, args: ..any, location := #caller_location) { - logf(level=.Error, fmt_str=fmt_str, args=args, location=location) + logf(.Error, fmt_str, ..args, location=location) } fatalf :: proc(fmt_str: string, args: ..any, location := #caller_location) { - logf(level=.Fatal, fmt_str=fmt_str, args=args, location=location) + logf(.Fatal, fmt_str, ..args, location=location) } debug :: proc(args: ..any, sep := " ", location := #caller_location) { - log(level=.Debug, args=args, sep=sep, location=location) + log(.Debug, ..args, sep=sep, location=location) } info :: proc(args: ..any, sep := " ", location := #caller_location) { - log(level=.Info, args=args, sep=sep, location=location) + log(.Info, ..args, sep=sep, location=location) } warn :: proc(args: ..any, sep := " ", location := #caller_location) { - log(level=.Warning, args=args, sep=sep, location=location) + log(.Warning, ..args, sep=sep, location=location) } error :: proc(args: ..any, sep := " ", location := #caller_location) { - log(level=.Error, args=args, sep=sep, location=location) + log(.Error, ..args, sep=sep, location=location) } fatal :: proc(args: ..any, sep := " ", location := #caller_location) { - log(level=.Fatal, args=args, sep=sep, location=location) + log(.Fatal, ..args, sep=sep, location=location) } panic :: proc(args: ..any, location := #caller_location) -> ! { - log(level=.Fatal, args=args, location=location) + log(.Fatal, ..args, location=location) runtime.panic("log.panic", location) } panicf :: proc(fmt_str: string, args: ..any, location := #caller_location) -> ! { - logf(level=.Fatal, fmt_str=fmt_str, args=args, location=location) + logf(.Fatal, fmt_str, ..args, location=location) runtime.panic("log.panicf", location) } @@ -127,7 +127,7 @@ log :: proc(level: Level, args: ..any, sep := " ", location := #caller_location) if level < logger.lowest_level { return } - str := fmt.tprint(args=args, sep=sep) //NOTE(Hoej): While tprint isn't thread-safe, no logging is. + str := fmt.tprint(..args, sep=sep) //NOTE(Hoej): While tprint isn't thread-safe, no logging is. logger.procedure(logger.data, level, str, logger.options, location) } diff --git a/core/log/log_allocator.odin b/core/log/log_allocator.odin index f4d1841db..934f0d643 100644 --- a/core/log/log_allocator.odin +++ b/core/log/log_allocator.odin @@ -38,60 +38,60 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, 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}, + la.level, + "%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)", + la.prefix, padding, size, alignment, location = location, ) case .Alloc_Non_Zeroed: logf( - level=la.level, - fmt_str = "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%d, alignment=%d)", - args = {la.prefix, padding, size, alignment}, + la.level, + "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%d, alignment=%d)", + 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}, + la.level, + "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)", + 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}, + la.level, + "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)", + 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}, + la.level, + "%s%s<<< ALLOCATOR(mode=.Free_All)", + 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}, + la.level, + "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)", + 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}, + la.level, + "%s%ALLOCATOR(mode=.Query_Features)", + la.prefix, padding, location = location, ) case .Query_Info: logf( - level=la.level, - fmt_str = "%s%ALLOCATOR(mode=.Query_Info)", - args = {la.prefix, padding}, + la.level, + "%s%ALLOCATOR(mode=.Query_Info)", + la.prefix, padding, location = location, ) } @@ -103,9 +103,9 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, defer la.locked = false if err != nil { logf( - level=la.level, - fmt_str = "%s%ALLOCATOR ERROR=%v", - args = {la.prefix, padding, error}, + la.level, + "%s%ALLOCATOR ERROR=%v", + la.prefix, padding, error, location = location, ) } diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 6c4b5dd01..a4313a244 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -19,7 +19,7 @@ import rnd "core:math/rand" int_destroy :: proc(integers: ..^Int) { integers := integers - for a in &integers { + for a in integers { assert_if_nil(a) } #force_inline internal_int_destroy(..integers) @@ -408,7 +408,7 @@ clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocato args := args assert_if_nil(..args) - for i in &args { + for i in args { #force_inline internal_clear_if_uninitialized_single(i, allocator) or_return } return err @@ -435,7 +435,7 @@ int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err assert_if_nil(..integers) integers := integers - for a in &integers { + for a in integers { #force_inline internal_clear(a, true, allocator) or_return } return nil diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 13aa96bef..968a26f8f 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -1857,7 +1857,7 @@ internal_root_n :: proc { internal_int_root_n, } internal_int_destroy :: proc(integers: ..^Int) { integers := integers - for a in &integers { + for &a in integers { if internal_int_allocated_cap(a) > 0 { mem.zero_slice(a.digit[:]) free(&a.digit[0]) @@ -2909,7 +2909,7 @@ internal_int_init_multi :: proc(integers: ..^Int, allocator := context.allocator context.allocator = allocator integers := integers - for a in &integers { + for a in integers { internal_clear(a) or_return } return nil diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 2b758dc35..d15ce0e98 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -429,7 +429,7 @@ internal_int_write_to_ascii_file :: proc(a: ^Int, filename: string, radix := i8( len = l, } - ok := os.write_entire_file(name=filename, data=data, truncate=true) + ok := os.write_entire_file(filename, data, truncate=true) return nil if ok else .Cannot_Write_File } diff --git a/core/math/big/rat.odin b/core/math/big/rat.odin index c3efc30aa..35618affb 100644 --- a/core/math/big/rat.odin +++ b/core/math/big/rat.odin @@ -137,7 +137,7 @@ rat_copy :: proc(dst, src: ^Rat, minimize := false, allocator := context.allocat internal_rat_destroy :: proc(rationals: ..^Rat) { rationals := rationals - for z in &rationals { + for &z in rationals { internal_int_destroy(&z.a, &z.b) } } diff --git a/core/math/cmplx/cmplx.odin b/core/math/cmplx/cmplx.odin new file mode 100644 index 000000000..c029be30c --- /dev/null +++ b/core/math/cmplx/cmplx.odin @@ -0,0 +1,513 @@ +package math_cmplx + +import "core:builtin" +import "core:math" + +// The original C code, the long comment, and the constants +// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c. +// The go code is a simplified version of the original C. +// +// Cephes Math Library Release 2.8: June, 2000 +// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +// +// The readme file at http://netlib.sandia.gov/cephes/ says: +// Some software in this archive may be from the book _Methods and +// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster +// International, 1989) or from the Cephes Mathematical Library, a +// commercial product. In either event, it is copyrighted by the author. +// What you see here may be used freely but it comes with no support or +// guarantee. +// +// The two known misprints in the book are repaired here in the +// source listings for the gamma function and the incomplete beta +// integral. +// +// Stephen L. Moshier +// moshier@na-net.ornl.gov + +abs :: builtin.abs +conj :: builtin.conj +real :: builtin.real +imag :: builtin.imag +jmag :: builtin.jmag +kmag :: builtin.kmag + + +sin :: proc{ + sin_complex128, +} +cos :: proc{ + cos_complex128, +} +tan :: proc{ + tan_complex128, +} +cot :: proc{ + cot_complex128, +} + + +sinh :: proc{ + sinh_complex128, +} +cosh :: proc{ + cosh_complex128, +} +tanh :: proc{ + tanh_complex128, +} + + + +// sqrt returns the square root of x. +// The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x). +sqrt :: proc{ + sqrt_complex32, + sqrt_complex64, + sqrt_complex128, +} +ln :: proc{ + ln_complex32, + ln_complex64, + ln_complex128, +} +log10 :: proc{ + log10_complex32, + log10_complex64, + log10_complex128, +} + +exp :: proc{ + exp_complex32, + exp_complex64, + exp_complex128, +} + +pow :: proc{ + pow_complex32, + pow_complex64, + pow_complex128, +} + +phase :: proc{ + phase_complex32, + phase_complex64, + phase_complex128, +} + +polar :: proc{ + polar_complex32, + polar_complex64, + polar_complex128, +} + +is_inf :: proc{ + is_inf_complex32, + is_inf_complex64, + is_inf_complex128, +} + +is_nan :: proc{ + is_nan_complex32, + is_nan_complex64, + is_nan_complex128, +} + + + +// sqrt_complex32 returns the square root of x. +// The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x). +sqrt_complex32 :: proc "contextless" (x: complex32) -> complex32 { + return complex32(sqrt_complex128(complex128(x))) +} + +// sqrt_complex64 returns the square root of x. +// The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x). +sqrt_complex64 :: proc "contextless" (x: complex64) -> complex64 { + return complex64(sqrt_complex128(complex128(x))) +} + + +// sqrt_complex128 returns the square root of x. +// The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x). +sqrt_complex128 :: proc "contextless" (x: complex128) -> complex128 { + // The original C code, the long comment, and the constants + // below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c. + // The go code is a simplified version of the original C. + // + // Cephes Math Library Release 2.8: June, 2000 + // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier + // + // The readme file at http://netlib.sandia.gov/cephes/ says: + // Some software in this archive may be from the book _Methods and + // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster + // International, 1989) or from the Cephes Mathematical Library, a + // commercial product. In either event, it is copyrighted by the author. + // What you see here may be used freely but it comes with no support or + // guarantee. + // + // The two known misprints in the book are repaired here in the + // source listings for the gamma function and the incomplete beta + // integral. + // + // Stephen L. Moshier + // moshier@na-net.ornl.gov + + // Complex square root + // + // DESCRIPTION: + // + // If z = x + iy, r = |z|, then + // + // 1/2 + // Re w = [ (r + x)/2 ] , + // + // 1/2 + // Im w = [ (r - x)/2 ] . + // + // Cancellation error in r-x or r+x is avoided by using the + // identity 2 Re w Im w = y. + // + // Note that -w is also a square root of z. The root chosen + // is always in the right half plane and Im w has the same sign as y. + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 25000 3.2e-17 9.6e-18 + // IEEE -10,+10 1,000,000 2.9e-16 6.1e-17 + + if imag(x) == 0 { + // Ensure that imag(r) has the same sign as imag(x) for imag(x) == signed zero. + if real(x) == 0 { + return complex(0, imag(x)) + } + if real(x) < 0 { + return complex(0, math.copy_sign(math.sqrt(-real(x)), imag(x))) + } + return complex(math.sqrt(real(x)), imag(x)) + } else if math.is_inf(imag(x), 0) { + return complex(math.inf_f64(1.0), imag(x)) + } + if real(x) == 0 { + if imag(x) < 0 { + r := math.sqrt(-0.5 * imag(x)) + return complex(r, -r) + } + r := math.sqrt(0.5 * imag(x)) + return complex(r, r) + } + a := real(x) + b := imag(x) + scale: f64 + // Rescale to avoid internal overflow or underflow. + if abs(a) > 4 || abs(b) > 4 { + a *= 0.25 + b *= 0.25 + scale = 2 + } else { + a *= 1.8014398509481984e16 // 2**54 + b *= 1.8014398509481984e16 + scale = 7.450580596923828125e-9 // 2**-27 + } + r := math.hypot(a, b) + t: f64 + if a > 0 { + t = math.sqrt(0.5*r + 0.5*a) + r = scale * abs((0.5*b)/t) + t *= scale + } else { + r = math.sqrt(0.5*r - 0.5*a) + t = scale * abs((0.5*b)/r) + r *= scale + } + if b < 0 { + return complex(t, -r) + } + return complex(t, r) +} + +ln_complex32 :: proc "contextless" (x: complex32) -> complex32 { + return complex(math.ln(abs(x)), phase(x)) +} +ln_complex64 :: proc "contextless" (x: complex64) -> complex64 { + return complex(math.ln(abs(x)), phase(x)) +} +ln_complex128 :: proc "contextless" (x: complex128) -> complex128 { + return complex(math.ln(abs(x)), phase(x)) +} + + +exp_complex32 :: proc "contextless" (x: complex32) -> complex32 { + switch re, im := real(x), imag(x); { + case math.is_inf(re, 0): + switch { + case re > 0 && im == 0: + return x + case math.is_inf(im, 0) || math.is_nan(im): + if re < 0 { + return complex(0, math.copy_sign(0, im)) + } else { + return complex(math.inf_f64(1.0), math.nan_f64()) + } + } + case math.is_nan(re): + if im == 0 { + return complex(math.nan_f16(), im) + } + } + r := math.exp(real(x)) + s, c := math.sincos(imag(x)) + return complex(r*c, r*s) +} +exp_complex64 :: proc "contextless" (x: complex64) -> complex64 { + switch re, im := real(x), imag(x); { + case math.is_inf(re, 0): + switch { + case re > 0 && im == 0: + return x + case math.is_inf(im, 0) || math.is_nan(im): + if re < 0 { + return complex(0, math.copy_sign(0, im)) + } else { + return complex(math.inf_f64(1.0), math.nan_f64()) + } + } + case math.is_nan(re): + if im == 0 { + return complex(math.nan_f32(), im) + } + } + r := math.exp(real(x)) + s, c := math.sincos(imag(x)) + return complex(r*c, r*s) +} +exp_complex128 :: proc "contextless" (x: complex128) -> complex128 { + switch re, im := real(x), imag(x); { + case math.is_inf(re, 0): + switch { + case re > 0 && im == 0: + return x + case math.is_inf(im, 0) || math.is_nan(im): + if re < 0 { + return complex(0, math.copy_sign(0, im)) + } else { + return complex(math.inf_f64(1.0), math.nan_f64()) + } + } + case math.is_nan(re): + if im == 0 { + return complex(math.nan_f64(), im) + } + } + r := math.exp(real(x)) + s, c := math.sincos(imag(x)) + return complex(r*c, r*s) +} + + +pow_complex32 :: proc "contextless" (x, y: complex32) -> complex32 { + if x == 0 { // Guaranteed also true for x == -0. + if is_nan(y) { + return nan_complex32() + } + r, i := real(y), imag(y) + switch { + case r == 0: + return 1 + case r < 0: + if i == 0 { + return complex(math.inf_f16(1), 0) + } + return inf_complex32() + case r > 0: + return 0 + } + unreachable() + } + modulus := abs(x) + if modulus == 0 { + return complex(0, 0) + } + r := math.pow(modulus, real(y)) + arg := phase(x) + theta := real(y) * arg + if imag(y) != 0 { + r *= math.exp(-imag(y) * arg) + theta += imag(y) * math.ln(modulus) + } + s, c := math.sincos(theta) + return complex(r*c, r*s) +} +pow_complex64 :: proc "contextless" (x, y: complex64) -> complex64 { + if x == 0 { // Guaranteed also true for x == -0. + if is_nan(y) { + return nan_complex64() + } + r, i := real(y), imag(y) + switch { + case r == 0: + return 1 + case r < 0: + if i == 0 { + return complex(math.inf_f32(1), 0) + } + return inf_complex64() + case r > 0: + return 0 + } + unreachable() + } + modulus := abs(x) + if modulus == 0 { + return complex(0, 0) + } + r := math.pow(modulus, real(y)) + arg := phase(x) + theta := real(y) * arg + if imag(y) != 0 { + r *= math.exp(-imag(y) * arg) + theta += imag(y) * math.ln(modulus) + } + s, c := math.sincos(theta) + return complex(r*c, r*s) +} +pow_complex128 :: proc "contextless" (x, y: complex128) -> complex128 { + if x == 0 { // Guaranteed also true for x == -0. + if is_nan(y) { + return nan_complex128() + } + r, i := real(y), imag(y) + switch { + case r == 0: + return 1 + case r < 0: + if i == 0 { + return complex(math.inf_f64(1), 0) + } + return inf_complex128() + case r > 0: + return 0 + } + unreachable() + } + modulus := abs(x) + if modulus == 0 { + return complex(0, 0) + } + r := math.pow(modulus, real(y)) + arg := phase(x) + theta := real(y) * arg + if imag(y) != 0 { + r *= math.exp(-imag(y) * arg) + theta += imag(y) * math.ln(modulus) + } + s, c := math.sincos(theta) + return complex(r*c, r*s) +} + + + +log10_complex32 :: proc "contextless" (x: complex32) -> complex32 { + return math.LN10*ln(x) +} +log10_complex64 :: proc "contextless" (x: complex64) -> complex64 { + return math.LN10*ln(x) +} +log10_complex128 :: proc "contextless" (x: complex128) -> complex128 { + return math.LN10*ln(x) +} + + +phase_complex32 :: proc "contextless" (x: complex32) -> f16 { + return math.atan2(imag(x), real(x)) +} +phase_complex64 :: proc "contextless" (x: complex64) -> f32 { + return math.atan2(imag(x), real(x)) +} +phase_complex128 :: proc "contextless" (x: complex128) -> f64 { + return math.atan2(imag(x), real(x)) +} + + +rect_complex32 :: proc "contextless" (r, θ: f16) -> complex32 { + s, c := math.sincos(θ) + return complex(r*c, r*s) +} +rect_complex64 :: proc "contextless" (r, θ: f32) -> complex64 { + s, c := math.sincos(θ) + return complex(r*c, r*s) +} +rect_complex128 :: proc "contextless" (r, θ: f64) -> complex128 { + s, c := math.sincos(θ) + return complex(r*c, r*s) +} + +polar_complex32 :: proc "contextless" (x: complex32) -> (r, θ: f16) { + return abs(x), phase(x) +} +polar_complex64 :: proc "contextless" (x: complex64) -> (r, θ: f32) { + return abs(x), phase(x) +} +polar_complex128 :: proc "contextless" (x: complex128) -> (r, θ: f64) { + return abs(x), phase(x) +} + + + + +nan_complex32 :: proc "contextless" () -> complex32 { + return complex(math.nan_f16(), math.nan_f16()) +} +nan_complex64 :: proc "contextless" () -> complex64 { + return complex(math.nan_f32(), math.nan_f32()) +} +nan_complex128 :: proc "contextless" () -> complex128 { + return complex(math.nan_f64(), math.nan_f64()) +} + + +inf_complex32 :: proc "contextless" () -> complex32 { + inf := math.inf_f16(1) + return complex(inf, inf) +} +inf_complex64 :: proc "contextless" () -> complex64 { + inf := math.inf_f32(1) + return complex(inf, inf) +} +inf_complex128 :: proc "contextless" () -> complex128 { + inf := math.inf_f64(1) + return complex(inf, inf) +} + + +is_inf_complex32 :: proc "contextless" (x: complex32) -> bool { + return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) +} +is_inf_complex64 :: proc "contextless" (x: complex64) -> bool { + return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) +} +is_inf_complex128 :: proc "contextless" (x: complex128) -> bool { + return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) +} + + +is_nan_complex32 :: proc "contextless" (x: complex32) -> bool { + if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) { + return false + } + return math.is_nan(real(x)) || math.is_nan(imag(x)) +} +is_nan_complex64 :: proc "contextless" (x: complex64) -> bool { + if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) { + return false + } + return math.is_nan(real(x)) || math.is_nan(imag(x)) +} +is_nan_complex128 :: proc "contextless" (x: complex128) -> bool { + if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) { + return false + } + return math.is_nan(real(x)) || math.is_nan(imag(x)) +} diff --git a/core/math/cmplx/cmplx_invtrig.odin b/core/math/cmplx/cmplx_invtrig.odin new file mode 100644 index 000000000..a746a370f --- /dev/null +++ b/core/math/cmplx/cmplx_invtrig.odin @@ -0,0 +1,273 @@ +package math_cmplx + +import "core:builtin" +import "core:math" + +// The original C code, the long comment, and the constants +// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c. +// The go code is a simplified version of the original C. +// +// Cephes Math Library Release 2.8: June, 2000 +// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +// +// The readme file at http://netlib.sandia.gov/cephes/ says: +// Some software in this archive may be from the book _Methods and +// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster +// International, 1989) or from the Cephes Mathematical Library, a +// commercial product. In either event, it is copyrighted by the author. +// What you see here may be used freely but it comes with no support or +// guarantee. +// +// The two known misprints in the book are repaired here in the +// source listings for the gamma function and the incomplete beta +// integral. +// +// Stephen L. Moshier +// moshier@na-net.ornl.gov + +acos :: proc{ + acos_complex32, + acos_complex64, + acos_complex128, +} +acosh :: proc{ + acosh_complex32, + acosh_complex64, + acosh_complex128, +} + +asin :: proc{ + asin_complex32, + asin_complex64, + asin_complex128, +} +asinh :: proc{ + asinh_complex32, + asinh_complex64, + asinh_complex128, +} + +atan :: proc{ + atan_complex32, + atan_complex64, + atan_complex128, +} + +atanh :: proc{ + atanh_complex32, + atanh_complex64, + atanh_complex128, +} + + +acos_complex32 :: proc "contextless" (x: complex32) -> complex32 { + w := asin(x) + return complex(math.PI/2 - real(w), -imag(w)) +} +acos_complex64 :: proc "contextless" (x: complex64) -> complex64 { + w := asin(x) + return complex(math.PI/2 - real(w), -imag(w)) +} +acos_complex128 :: proc "contextless" (x: complex128) -> complex128 { + w := asin(x) + return complex(math.PI/2 - real(w), -imag(w)) +} + + +acosh_complex32 :: proc "contextless" (x: complex32) -> complex32 { + if x == 0 { + return complex(0, math.copy_sign(math.PI/2, imag(x))) + } + w := acos(x) + if imag(w) <= 0 { + return complex(-imag(w), real(w)) + } + return complex(imag(w), -real(w)) +} +acosh_complex64 :: proc "contextless" (x: complex64) -> complex64 { + if x == 0 { + return complex(0, math.copy_sign(math.PI/2, imag(x))) + } + w := acos(x) + if imag(w) <= 0 { + return complex(-imag(w), real(w)) + } + return complex(imag(w), -real(w)) +} +acosh_complex128 :: proc "contextless" (x: complex128) -> complex128 { + if x == 0 { + return complex(0, math.copy_sign(math.PI/2, imag(x))) + } + w := acos(x) + if imag(w) <= 0 { + return complex(-imag(w), real(w)) + } + return complex(imag(w), -real(w)) +} + +asin_complex32 :: proc "contextless" (x: complex32) -> complex32 { + return complex32(asin_complex128(complex128(x))) +} +asin_complex64 :: proc "contextless" (x: complex64) -> complex64 { + return complex64(asin_complex128(complex128(x))) +} +asin_complex128 :: proc "contextless" (x: complex128) -> complex128 { + switch re, im := real(x), imag(x); { + case im == 0 && abs(re) <= 1: + return complex(math.asin(re), im) + case re == 0 && abs(im) <= 1: + return complex(re, math.asinh(im)) + case math.is_nan(im): + switch { + case re == 0: + return complex(re, math.nan_f64()) + case math.is_inf(re, 0): + return complex(math.nan_f64(), re) + case: + return nan_complex128() + } + case math.is_inf(im, 0): + switch { + case math.is_nan(re): + return x + case math.is_inf(re, 0): + return complex(math.copy_sign(math.PI/4, re), im) + case: + return complex(math.copy_sign(0, re), im) + } + case math.is_inf(re, 0): + return complex(math.copy_sign(math.PI/2, re), math.copy_sign(re, im)) + } + ct := complex(-imag(x), real(x)) // i * x + xx := x * x + x1 := complex(1-real(xx), -imag(xx)) // 1 - x*x + x2 := sqrt(x1) // x2 = sqrt(1 - x*x) + w := ln(ct + x2) + return complex(imag(w), -real(w)) // -i * w +} + +asinh_complex32 :: proc "contextless" (x: complex32) -> complex32 { + return complex32(asinh_complex128(complex128(x))) +} +asinh_complex64 :: proc "contextless" (x: complex64) -> complex64 { + return complex64(asinh_complex128(complex128(x))) +} +asinh_complex128 :: proc "contextless" (x: complex128) -> complex128 { + switch re, im := real(x), imag(x); { + case im == 0 && abs(re) <= 1: + return complex(math.asinh(re), im) + case re == 0 && abs(im) <= 1: + return complex(re, math.asin(im)) + case math.is_inf(re, 0): + switch { + case math.is_inf(im, 0): + return complex(re, math.copy_sign(math.PI/4, im)) + case math.is_nan(im): + return x + case: + return complex(re, math.copy_sign(0.0, im)) + } + case math.is_nan(re): + switch { + case im == 0: + return x + case math.is_inf(im, 0): + return complex(im, re) + case: + return nan_complex128() + } + case math.is_inf(im, 0): + return complex(math.copy_sign(im, re), math.copy_sign(math.PI/2, im)) + } + xx := x * x + x1 := complex(1+real(xx), imag(xx)) // 1 + x*x + return ln(x + sqrt(x1)) // log(x + sqrt(1 + x*x)) +} + + +atan_complex32 :: proc "contextless" (x: complex32) -> complex32 { + return complex32(atan_complex128(complex128(x))) +} +atan_complex64 :: proc "contextless" (x: complex64) -> complex64 { + return complex64(atan_complex128(complex128(x))) +} +atan_complex128 :: proc "contextless" (x: complex128) -> complex128 { + // Complex circular arc tangent + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // 1 ( 2x ) + // Re w = - arctan(-----------) + k PI + // 2 ( 2 2) + // (1 - x - y ) + // + // ( 2 2) + // 1 (x + (y+1) ) + // Im w = - log(------------) + // 4 ( 2 2) + // (x + (y-1) ) + // + // Where k is an arbitrary integer. + // + // catan(z) = -i catanh(iz). + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 5900 1.3e-16 7.8e-18 + // IEEE -10,+10 30000 2.3e-15 8.5e-17 + // The check catan( ctan(z) ) = z, with |x| and |y| < PI/2, + // had peak relative error 1.5e-16, rms relative error + // 2.9e-17. See also clog(). + + switch re, im := real(x), imag(x); { + case im == 0: + return complex(math.atan(re), im) + case re == 0 && abs(im) <= 1: + return complex(re, math.atanh(im)) + case math.is_inf(im, 0) || math.is_inf(re, 0): + if math.is_nan(re) { + return complex(math.nan_f64(), math.copy_sign(0, im)) + } + return complex(math.copy_sign(math.PI/2, re), math.copy_sign(0, im)) + case math.is_nan(re) || math.is_nan(im): + return nan_complex128() + } + x2 := real(x) * real(x) + a := 1 - x2 - imag(x)*imag(x) + if a == 0 { + return nan_complex128() + } + t := 0.5 * math.atan2(2*real(x), a) + w := _reduce_pi_f64(t) + + t = imag(x) - 1 + b := x2 + t*t + if b == 0 { + return nan_complex128() + } + t = imag(x) + 1 + c := (x2 + t*t) / b + return complex(w, 0.25*math.ln(c)) +} + +atanh_complex32 :: proc "contextless" (x: complex32) -> complex32 { + z := complex(-imag(x), real(x)) // z = i * x + z = atan(z) + return complex(imag(z), -real(z)) // z = -i * z +} +atanh_complex64 :: proc "contextless" (x: complex64) -> complex64 { + z := complex(-imag(x), real(x)) // z = i * x + z = atan(z) + return complex(imag(z), -real(z)) // z = -i * z +} +atanh_complex128 :: proc "contextless" (x: complex128) -> complex128 { + z := complex(-imag(x), real(x)) // z = i * x + z = atan(z) + return complex(imag(z), -real(z)) // z = -i * z +}
\ No newline at end of file diff --git a/core/math/cmplx/cmplx_trig.odin b/core/math/cmplx/cmplx_trig.odin new file mode 100644 index 000000000..7ca404fab --- /dev/null +++ b/core/math/cmplx/cmplx_trig.odin @@ -0,0 +1,409 @@ +package math_cmplx + +import "core:math" +import "core:math/bits" + +// The original C code, the long comment, and the constants +// below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c. +// The go code is a simplified version of the original C. +// +// Cephes Math Library Release 2.8: June, 2000 +// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +// +// The readme file at http://netlib.sandia.gov/cephes/ says: +// Some software in this archive may be from the book _Methods and +// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster +// International, 1989) or from the Cephes Mathematical Library, a +// commercial product. In either event, it is copyrighted by the author. +// What you see here may be used freely but it comes with no support or +// guarantee. +// +// The two known misprints in the book are repaired here in the +// source listings for the gamma function and the incomplete beta +// integral. +// +// Stephen L. Moshier +// moshier@na-net.ornl.gov + +sin_complex128 :: proc "contextless" (x: complex128) -> complex128 { + // Complex circular sine + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // + // w = sin x cosh y + i cos x sinh y. + // + // csin(z) = -i csinh(iz). + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 8400 5.3e-17 1.3e-17 + // IEEE -10,+10 30000 3.8e-16 1.0e-16 + // Also tested by csin(casin(z)) = z. + + switch re, im := real(x), imag(x); { + case im == 0 && (math.is_inf(re, 0) || math.is_nan(re)): + return complex(math.nan_f64(), im) + case math.is_inf(im, 0): + switch { + case re == 0: + return x + case math.is_inf(re, 0) || math.is_nan(re): + return complex(math.nan_f64(), im) + } + case re == 0 && math.is_nan(im): + return x + } + s, c := math.sincos(real(x)) + sh, ch := _sinhcosh_f64(imag(x)) + return complex(s*ch, c*sh) +} + +cos_complex128 :: proc "contextless" (x: complex128) -> complex128 { + // Complex circular cosine + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // + // w = cos x cosh y - i sin x sinh y. + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 8400 4.5e-17 1.3e-17 + // IEEE -10,+10 30000 3.8e-16 1.0e-16 + + switch re, im := real(x), imag(x); { + case im == 0 && (math.is_inf(re, 0) || math.is_nan(re)): + return complex(math.nan_f64(), -im*math.copy_sign(0, re)) + case math.is_inf(im, 0): + switch { + case re == 0: + return complex(math.inf_f64(1), -re*math.copy_sign(0, im)) + case math.is_inf(re, 0) || math.is_nan(re): + return complex(math.inf_f64(1), math.nan_f64()) + } + case re == 0 && math.is_nan(im): + return complex(math.nan_f64(), 0) + } + s, c := math.sincos(real(x)) + sh, ch := _sinhcosh_f64(imag(x)) + return complex(c*ch, -s*sh) +} + +sinh_complex128 :: proc "contextless" (x: complex128) -> complex128 { + // Complex hyperbolic sine + // + // DESCRIPTION: + // + // csinh z = (cexp(z) - cexp(-z))/2 + // = sinh x * cos y + i cosh x * sin y . + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // IEEE -10,+10 30000 3.1e-16 8.2e-17 + + switch re, im := real(x), imag(x); { + case re == 0 && (math.is_inf(im, 0) || math.is_nan(im)): + return complex(re, math.nan_f64()) + case math.is_inf(re, 0): + switch { + case im == 0: + return complex(re, im) + case math.is_inf(im, 0) || math.is_nan(im): + return complex(re, math.nan_f64()) + } + case im == 0 && math.is_nan(re): + return complex(math.nan_f64(), im) + } + s, c := math.sincos(imag(x)) + sh, ch := _sinhcosh_f64(real(x)) + return complex(c*sh, s*ch) +} + +cosh_complex128 :: proc "contextless" (x: complex128) -> complex128 { + // Complex hyperbolic cosine + // + // DESCRIPTION: + // + // ccosh(z) = cosh x cos y + i sinh x sin y . + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // IEEE -10,+10 30000 2.9e-16 8.1e-17 + + switch re, im := real(x), imag(x); { + case re == 0 && (math.is_inf(im, 0) || math.is_nan(im)): + return complex(math.nan_f64(), re*math.copy_sign(0, im)) + case math.is_inf(re, 0): + switch { + case im == 0: + return complex(math.inf_f64(1), im*math.copy_sign(0, re)) + case math.is_inf(im, 0) || math.is_nan(im): + return complex(math.inf_f64(1), math.nan_f64()) + } + case im == 0 && math.is_nan(re): + return complex(math.nan_f64(), im) + } + s, c := math.sincos(imag(x)) + sh, ch := _sinhcosh_f64(real(x)) + return complex(c*ch, s*sh) +} + +tan_complex128 :: proc "contextless" (x: complex128) -> complex128 { + // Complex circular tangent + // + // DESCRIPTION: + // + // If + // z = x + iy, + // + // then + // + // sin 2x + i sinh 2y + // w = --------------------. + // cos 2x + cosh 2y + // + // On the real axis the denominator is zero at odd multiples + // of PI/2. The denominator is evaluated by its Taylor + // series near these points. + // + // ctan(z) = -i ctanh(iz). + // + // ACCURACY: + // + // Relative error: + // arithmetic domain # trials peak rms + // DEC -10,+10 5200 7.1e-17 1.6e-17 + // IEEE -10,+10 30000 7.2e-16 1.2e-16 + // Also tested by ctan * ccot = 1 and catan(ctan(z)) = z. + + switch re, im := real(x), imag(x); { + case math.is_inf(im, 0): + switch { + case math.is_inf(re, 0) || math.is_nan(re): + return complex(math.copy_sign(0, re), math.copy_sign(1, im)) + } + return complex(math.copy_sign(0, math.sin(2*re)), math.copy_sign(1, im)) + case re == 0 && math.is_nan(im): + return x + } + d := math.cos(2*real(x)) + math.cosh(2*imag(x)) + if abs(d) < 0.25 { + d = _tan_series_f64(x) + } + if d == 0 { + return inf_complex128() + } + return complex(math.sin(2*real(x))/d, math.sinh(2*imag(x))/d) +} + +tanh_complex128 :: proc "contextless" (x: complex128) -> complex128 { + switch re, im := real(x), imag(x); { + case math.is_inf(re, 0): + switch { + case math.is_inf(im, 0) || math.is_nan(im): + return complex(math.copy_sign(1, re), math.copy_sign(0, im)) + } + return complex(math.copy_sign(1, re), math.copy_sign(0, math.sin(2*im))) + case im == 0 && math.is_nan(re): + return x + } + d := math.cosh(2*real(x)) + math.cos(2*imag(x)) + if d == 0 { + return inf_complex128() + } + return complex(math.sinh(2*real(x))/d, math.sin(2*imag(x))/d) +} + +cot_complex128 :: proc "contextless" (x: complex128) -> complex128 { + d := math.cosh(2*imag(x)) - math.cos(2*real(x)) + if abs(d) < 0.25 { + d = _tan_series_f64(x) + } + if d == 0 { + return inf_complex128() + } + return complex(math.sin(2*real(x))/d, -math.sinh(2*imag(x))/d) +} + + +@(private="file") +_sinhcosh_f64 :: proc "contextless" (x: f64) -> (sh, ch: f64) { + if abs(x) <= 0.5 { + return math.sinh(x), math.cosh(x) + } + e := math.exp(x) + ei := 0.5 / e + e *= 0.5 + return e - ei, e + ei +} + + +// taylor series of cosh(2y) - cos(2x) +@(private) +_tan_series_f64 :: proc "contextless" (z: complex128) -> f64 { + MACH_EPSILON :: 1.0 / (1 << 53) + + x := abs(2 * real(z)) + y := abs(2 * imag(z)) + x = _reduce_pi_f64(x) + x, y = x * x, y * y + x2, y2 := 1.0, 1.0 + f, rn, d := 1.0, 0.0, 0.0 + + for { + rn += 1 + f *= rn + rn += 1 + f *= rn + x2 *= x + y2 *= y + t := y2 + x2 + t /= f + d += t + + rn += 1 + f *= rn + rn += 1 + f *= rn + x2 *= x + y2 *= y + t = y2 - x2 + t /= f + d += t + if !(abs(t/d) > MACH_EPSILON) { // don't use <=, because of floating point nonsense and NaN + break + } + } + return d +} + +// _reduce_pi_f64 reduces the input argument x to the range (-PI/2, PI/2]. +// x must be greater than or equal to 0. For small arguments it +// uses Cody-Waite reduction in 3 f64 parts based on: +// "Elementary Function Evaluation: Algorithms and Implementation" +// Jean-Michel Muller, 1997. +// For very large arguments it uses Payne-Hanek range reduction based on: +// "ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit" +@(private) +_reduce_pi_f64 :: proc "contextless" (x: f64) -> f64 #no_bounds_check { + x := x + + // REDUCE_THRESHOLD is the maximum value of x where the reduction using + // Cody-Waite reduction still gives accurate results. This threshold + // is set by t*PIn being representable as a f64 without error + // where t is given by t = floor(x * (1 / PI)) and PIn are the leading partial + // terms of PI. Since the leading terms, PI1 and PI2 below, have 30 and 32 + // trailing zero bits respectively, t should have less than 30 significant bits. + // t < 1<<30 -> floor(x*(1/PI)+0.5) < 1<<30 -> x < (1<<30-1) * PI - 0.5 + // So, conservatively we can take x < 1<<30. + REDUCE_THRESHOLD :: f64(1 << 30) + + if abs(x) < REDUCE_THRESHOLD { + // Use Cody-Waite reduction in three parts. + // PI1, PI2 and PI3 comprise an extended precision value of PI + // such that PI ~= PI1 + PI2 + PI3. The parts are chosen so + // that PI1 and PI2 have an approximately equal number of trailing + // zero bits. This ensures that t*PI1 and t*PI2 are exact for + // large integer values of t. The full precision PI3 ensures the + // approximation of PI is accurate to 102 bits to handle cancellation + // during subtraction. + PI1 :: 0h400921fb40000000 // 3.141592502593994 + PI2 :: 0h3e84442d00000000 // 1.5099578831723193e-07 + PI3 :: 0h3d08469898cc5170 // 1.0780605716316238e-14 + + t := x / math.PI + t += 0.5 + t = f64(i64(t)) // i64(t) = the multiple + return ((x - t*PI1) - t*PI2) - t*PI3 + } + // Must apply Payne-Hanek range reduction + MASK :: 0x7FF + SHIFT :: 64 - 11 - 1 + BIAS :: 1023 + FRAC_MASK :: 1<<SHIFT - 1 + + // Extract out the integer and exponent such that, + // x = ix * 2 ** exp. + ix := transmute(u64)(x) + exp := int(ix>>SHIFT&MASK) - BIAS - SHIFT + ix &= FRAC_MASK + ix |= 1 << SHIFT + + // bdpi is the binary digits of 1/PI as a u64 array, + // that is, 1/PI = SUM bdpi[i]*2^(-64*i). + // 19 64-bit digits give 1216 bits of precision + // to handle the largest possible f64 exponent. + @static bdpi := [?]u64{ + 0x0000000000000000, + 0x517cc1b727220a94, + 0xfe13abe8fa9a6ee0, + 0x6db14acc9e21c820, + 0xff28b1d5ef5de2b0, + 0xdb92371d2126e970, + 0x0324977504e8c90e, + 0x7f0ef58e5894d39f, + 0x74411afa975da242, + 0x74ce38135a2fbf20, + 0x9cc8eb1cc1a99cfa, + 0x4e422fc5defc941d, + 0x8ffc4bffef02cc07, + 0xf79788c5ad05368f, + 0xb69b3f6793e584db, + 0xa7a31fb34f2ff516, + 0xba93dd63f5f2f8bd, + 0x9e839cfbc5294975, + 0x35fdafd88fc6ae84, + 0x2b0198237e3db5d5, + } + + // Use the exponent to extract the 3 appropriate u64 digits from bdpi, + // B ~ (z0, z1, z2), such that the product leading digit has the exponent -64. + // Note, exp >= 50 since x >= REDUCE_THRESHOLD and exp < 971 for maximum f64. + digit, bitshift := uint(exp+64)/64, uint(exp+64)%64 + z0 := (bdpi[digit] << bitshift) | (bdpi[digit+1] >> (64 - bitshift)) + z1 := (bdpi[digit+1] << bitshift) | (bdpi[digit+2] >> (64 - bitshift)) + z2 := (bdpi[digit+2] << bitshift) | (bdpi[digit+3] >> (64 - bitshift)) + + // Multiply mantissa by the digits and extract the upper two digits (hi, lo). + z2hi, _ := bits.mul(z2, ix) + z1hi, z1lo := bits.mul(z1, ix) + z0lo := z0 * ix + lo, c := bits.add(z1lo, z2hi, 0) + hi, _ := bits.add(z0lo, z1hi, c) + + // Find the magnitude of the fraction. + lz := uint(bits.leading_zeros(hi)) + e := u64(BIAS - (lz + 1)) + + // Clear implicit mantissa bit and shift into place. + hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))) + hi >>= 64 - SHIFT + + // Include the exponent and convert to a float. + hi |= e << SHIFT + x = transmute(f64)(hi) + + // map to (-PI/2, PI/2] + if x > 0.5 { + x -= 1 + } + return math.PI * x +} + diff --git a/core/math/ease/ease.odin b/core/math/ease/ease.odin index d5cb85dd8..0e6569bca 100644 --- a/core/math/ease/ease.odin +++ b/core/math/ease/ease.odin @@ -450,7 +450,7 @@ flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where i 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 { + for key, &tween in flux.values { delay_remainder := f64(0) // Update delay if necessary. diff --git a/core/math/math.odin b/core/math/math.odin index 05177378f..6f7a36bab 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -2158,6 +2158,80 @@ signbit :: proc{ } +@(require_results) +hypot_f16 :: proc "contextless" (x, y: f16) -> (r: f16) { + p, q := abs(x), abs(y) + switch { + case is_inf(p, 1) || is_inf(q, 1): + return inf_f16(1) + case is_nan(p) || is_nan(q): + return nan_f16() + } + if p < q { + p, q = q, p + } + if p == 0 { + return 0 + } + q = q / p + return p * sqrt(1+q*q) +} +@(require_results) +hypot_f32 :: proc "contextless" (x, y: f32) -> (r: f32) { + p, q := abs(x), abs(y) + switch { + case is_inf(p, 1) || is_inf(q, 1): + return inf_f32(1) + case is_nan(p) || is_nan(q): + return nan_f32() + } + if p < q { + p, q = q, p + } + if p == 0 { + return 0 + } + q = q / p + return p * sqrt(1+q*q) +} +@(require_results) +hypot_f64 :: proc "contextless" (x, y: f64) -> (r: f64) { + p, q := abs(x), abs(y) + switch { + case is_inf(p, 1) || is_inf(q, 1): + return inf_f64(1) + case is_nan(p) || is_nan(q): + return nan_f64() + } + if p < q { + p, q = q, p + } + if p == 0 { + return 0 + } + q = q / p + return p * sqrt(1+q*q) +} +@(require_results) hypot_f16le :: proc "contextless" (x, y: f16le) -> (r: f16le) { return f16le(hypot_f16(f16(x), f16(y))) } +@(require_results) hypot_f16be :: proc "contextless" (x, y: f16be) -> (r: f16be) { return f16be(hypot_f16(f16(x), f16(y))) } +@(require_results) hypot_f32le :: proc "contextless" (x, y: f32le) -> (r: f32le) { return f32le(hypot_f32(f32(x), f32(y))) } +@(require_results) hypot_f32be :: proc "contextless" (x, y: f32be) -> (r: f32be) { return f32be(hypot_f32(f32(x), f32(y))) } +@(require_results) hypot_f64le :: proc "contextless" (x, y: f64le) -> (r: f64le) { return f64le(hypot_f64(f64(x), f64(y))) } +@(require_results) hypot_f64be :: proc "contextless" (x, y: f64be) -> (r: f64be) { return f64be(hypot_f64(f64(x), f64(y))) } + +// hypot returns Sqrt(p*p + q*q), taking care to avoid unnecessary overflow and underflow. +// +// Special cases: +// hypot(±Inf, q) = +Inf +// hypot(p, ±Inf) = +Inf +// hypot(NaN, q) = NaN +// hypot(p, NaN) = NaN +hypot :: proc{ + hypot_f16, hypot_f16le, hypot_f16be, + hypot_f32, hypot_f32le, hypot_f32be, + hypot_f64, hypot_f64le, hypot_f64be, +} + F16_DIG :: 3 F16_EPSILON :: 0.00097656 F16_GUARD :: 0 diff --git a/core/math/math_basic.odin b/core/math/math_basic.odin index 785c43b10..95e0a93ec 100644 --- a/core/math/math_basic.odin +++ b/core/math/math_basic.odin @@ -3,45 +3,111 @@ package math import "core:intrinsics" -@(default_calling_convention="none") +@(default_calling_convention="none", private="file") foreign _ { @(link_name="llvm.sin.f16", require_results) - sin_f16 :: proc(θ: f16) -> f16 --- + _sin_f16 :: proc(θ: f16) -> f16 --- @(link_name="llvm.sin.f32", require_results) - sin_f32 :: proc(θ: f32) -> f32 --- + _sin_f32 :: proc(θ: f32) -> f32 --- @(link_name="llvm.sin.f64", require_results) - sin_f64 :: proc(θ: f64) -> f64 --- + _sin_f64 :: proc(θ: f64) -> f64 --- @(link_name="llvm.cos.f16", require_results) - cos_f16 :: proc(θ: f16) -> f16 --- + _cos_f16 :: proc(θ: f16) -> f16 --- @(link_name="llvm.cos.f32", require_results) - cos_f32 :: proc(θ: f32) -> f32 --- + _cos_f32 :: proc(θ: f32) -> f32 --- @(link_name="llvm.cos.f64", require_results) - cos_f64 :: proc(θ: f64) -> f64 --- + _cos_f64 :: proc(θ: f64) -> f64 --- @(link_name="llvm.pow.f16", require_results) - pow_f16 :: proc(x, power: f16) -> f16 --- + _pow_f16 :: proc(x, power: f16) -> f16 --- @(link_name="llvm.pow.f32", require_results) - pow_f32 :: proc(x, power: f32) -> f32 --- + _pow_f32 :: proc(x, power: f32) -> f32 --- @(link_name="llvm.pow.f64", require_results) - pow_f64 :: proc(x, power: f64) -> f64 --- + _pow_f64 :: proc(x, power: f64) -> f64 --- @(link_name="llvm.fmuladd.f16", require_results) - fmuladd_f16 :: proc(a, b, c: f16) -> f16 --- + _fmuladd_f16 :: proc(a, b, c: f16) -> f16 --- @(link_name="llvm.fmuladd.f32", require_results) - fmuladd_f32 :: proc(a, b, c: f32) -> f32 --- + _fmuladd_f32 :: proc(a, b, c: f32) -> f32 --- @(link_name="llvm.fmuladd.f64", require_results) - fmuladd_f64 :: proc(a, b, c: f64) -> f64 --- + _fmuladd_f64 :: proc(a, b, c: f64) -> f64 --- @(link_name="llvm.exp.f16", require_results) - exp_f16 :: proc(x: f16) -> f16 --- + _exp_f16 :: proc(x: f16) -> f16 --- @(link_name="llvm.exp.f32", require_results) - exp_f32 :: proc(x: f32) -> f32 --- + _exp_f32 :: proc(x: f32) -> f32 --- @(link_name="llvm.exp.f64", require_results) - exp_f64 :: proc(x: f64) -> f64 --- + _exp_f64 :: proc(x: f64) -> f64 --- } @(require_results) +sin_f16 :: proc "contextless" (θ: f16) -> f16 { + return _sin_f16(θ) +} +@(require_results) +sin_f32 :: proc "contextless" (θ: f32) -> f32 { + return _sin_f32(θ) +} +@(require_results) +sin_f64 :: proc "contextless" (θ: f64) -> f64 { + return _sin_f64(θ) +} + +@(require_results) +cos_f16 :: proc "contextless" (θ: f16) -> f16 { + return _cos_f16(θ) +} +@(require_results) +cos_f32 :: proc "contextless" (θ: f32) -> f32 { + return _cos_f32(θ) +} +@(require_results) +cos_f64 :: proc "contextless" (θ: f64) -> f64 { + return _cos_f64(θ) +} + +@(require_results) +pow_f16 :: proc "contextless" (x, power: f16) -> f16 { + return _pow_f16(x, power) +} +@(require_results) +pow_f32 :: proc "contextless" (x, power: f32) -> f32 { + return _pow_f32(x, power) +} +@(require_results) +pow_f64 :: proc "contextless" (x, power: f64) -> f64 { + return _pow_f64(x, power) +} + +@(require_results) +fmuladd_f16 :: proc "contextless" (a, b, c: f16) -> f16 { + return _fmuladd_f16(a, b, c) +} +@(require_results) +fmuladd_f32 :: proc "contextless" (a, b, c: f32) -> f32 { + return _fmuladd_f32(a, b, c) +} +@(require_results) +fmuladd_f64 :: proc "contextless" (a, b, c: f64) -> f64 { + return _fmuladd_f64(a, b, c) +} + +@(require_results) +exp_f16 :: proc "contextless" (x: f16) -> f16 { + return _exp_f16(x) +} +@(require_results) +exp_f32 :: proc "contextless" (x: f32) -> f32 { + return _exp_f32(x) +} +@(require_results) +exp_f64 :: proc "contextless" (x: f64) -> f64 { + return _exp_f64(x) +} + + +@(require_results) sqrt_f16 :: proc "contextless" (x: f16) -> f16 { return intrinsics.sqrt(x) } diff --git a/core/math/math_sincos.odin b/core/math/math_sincos.odin new file mode 100644 index 000000000..578876ac5 --- /dev/null +++ b/core/math/math_sincos.odin @@ -0,0 +1,308 @@ +package math + +import "core:math/bits" + +// The original C code, the long comment, and the constants +// below were from http://netlib.sandia.gov/cephes/cmath/sin.c, +// available from http://www.netlib.org/cephes/cmath.tgz. +// The go code is a simplified version of the original C. +// +// sin.c +// +// Circular sine +// +// SYNOPSIS: +// +// double x, y, sin(); +// y = sin( x ); +// +// DESCRIPTION: +// +// Range reduction is into intervals of pi/4. The reduction error is nearly +// eliminated by contriving an extended precision modular arithmetic. +// +// Two polynomial approximating functions are employed. +// Between 0 and pi/4 the sine is approximated by +// x + x**3 P(x**2). +// Between pi/4 and pi/2 the cosine is represented as +// 1 - x**2 Q(x**2). +// +// ACCURACY: +// +// Relative error: +// arithmetic domain # trials peak rms +// DEC 0, 10 150000 3.0e-17 7.8e-18 +// IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17 +// +// Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss +// is not gradual, but jumps suddenly to about 1 part in 10e7. Results may +// be meaningless for x > 2**49 = 5.6e14. +// +// cos.c +// +// Circular cosine +// +// SYNOPSIS: +// +// double x, y, cos(); +// y = cos( x ); +// +// DESCRIPTION: +// +// Range reduction is into intervals of pi/4. The reduction error is nearly +// eliminated by contriving an extended precision modular arithmetic. +// +// Two polynomial approximating functions are employed. +// Between 0 and pi/4 the cosine is approximated by +// 1 - x**2 Q(x**2). +// Between pi/4 and pi/2 the sine is represented as +// x + x**3 P(x**2). +// +// ACCURACY: +// +// Relative error: +// arithmetic domain # trials peak rms +// IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17 +// DEC 0,+1.07e9 17000 3.0e-17 7.2e-18 +// +// Cephes Math Library Release 2.8: June, 2000 +// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier +// +// The readme file at http://netlib.sandia.gov/cephes/ says: +// Some software in this archive may be from the book _Methods and +// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster +// International, 1989) or from the Cephes Mathematical Library, a +// commercial product. In either event, it is copyrighted by the author. +// What you see here may be used freely but it comes with no support or +// guarantee. +// +// The two known misprints in the book are repaired here in the +// source listings for the gamma function and the incomplete beta +// integral. +// +// Stephen L. Moshier +// moshier@na-net.ornl.gov + +sincos :: proc{ + sincos_f16, sincos_f16le, sincos_f16be, + sincos_f32, sincos_f32le, sincos_f32be, + sincos_f64, sincos_f64le, sincos_f64be, +} + +sincos_f16 :: proc "contextless" (x: f16) -> (sin, cos: f16) #no_bounds_check { + s, c := sincos_f64(f64(x)) + return f16(s), f16(c) +} +sincos_f16le :: proc "contextless" (x: f16le) -> (sin, cos: f16le) #no_bounds_check { + s, c := sincos_f64(f64(x)) + return f16le(s), f16le(c) +} +sincos_f16be :: proc "contextless" (x: f16be) -> (sin, cos: f16be) #no_bounds_check { + s, c := sincos_f64(f64(x)) + return f16be(s), f16be(c) +} + +sincos_f32 :: proc "contextless" (x: f32) -> (sin, cos: f32) #no_bounds_check { + s, c := sincos_f64(f64(x)) + return f32(s), f32(c) +} +sincos_f32le :: proc "contextless" (x: f32le) -> (sin, cos: f32le) #no_bounds_check { + s, c := sincos_f64(f64(x)) + return f32le(s), f32le(c) +} +sincos_f32be :: proc "contextless" (x: f32be) -> (sin, cos: f32be) #no_bounds_check { + s, c := sincos_f64(f64(x)) + return f32be(s), f32be(c) +} + +sincos_f64le :: proc "contextless" (x: f64le) -> (sin, cos: f64le) #no_bounds_check { + s, c := sincos_f64(f64(x)) + return f64le(s), f64le(c) +} +sincos_f64be :: proc "contextless" (x: f64be) -> (sin, cos: f64be) #no_bounds_check { + s, c := sincos_f64(f64(x)) + return f64be(s), f64be(c) +} + +sincos_f64 :: proc "contextless" (x: f64) -> (sin, cos: f64) #no_bounds_check { + x := x + + PI4A :: 0h3fe921fb40000000 // 7.85398125648498535156e-1 PI/4 split into three parts + PI4B :: 0h3e64442d00000000 // 3.77489470793079817668e-8 + PI4C :: 0h3ce8469898cc5170 // 2.69515142907905952645e-15 + + // special cases + switch { + case x == 0: + return x, 1 // return ±0.0, 1.0 + case is_nan(x) || is_inf(x, 0): + return nan_f64(), nan_f64() + } + + // make argument positive + sin_sign, cos_sign := false, false + if x < 0 { + x = -x + sin_sign = true + } + + j: u64 + y, z: f64 + if x >= REDUCE_THRESHOLD { + j, z = _trig_reduce_f64(x) + } else { + j = u64(x * (4 / PI)) // integer part of x/(PI/4), as integer for tests on the phase angle + y = f64(j) // integer part of x/(PI/4), as float + + if j&1 == 1 { // map zeros to origin + j += 1 + y += 1 + } + j &= 7 // octant modulo TAU radians (360 degrees) + z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic + } + if j > 3 { // reflect in x axis + j -= 4 + sin_sign, cos_sign = !sin_sign, !cos_sign + } + if j > 1 { + cos_sign = !cos_sign + } + + zz := z * z + + cos = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5]) + sin = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5]) + + if j == 1 || j == 2 { + sin, cos = cos, sin + } + if cos_sign { + cos = -cos + } + if sin_sign { + sin = -sin + } + return +} + +// sin coefficients +@(private="file") +_sin := [?]f64{ + 0h3de5d8fd1fd19ccd, // 1.58962301576546568060e-10 + 0hbe5ae5e5a9291f5d, // -2.50507477628578072866e-8 + 0h3ec71de3567d48a1, // 2.75573136213857245213e-6 + 0hbf2a01a019bfdf03, // -1.98412698295895385996e-4 + 0h3f8111111110f7d0, // 8.33333333332211858878e-3 + 0hbfc5555555555548, // -1.66666666666666307295e-1 +} + +// cos coefficients +@(private="file") +_cos := [?]f64{ + 0hbda8fa49a0861a9b, // -1.13585365213876817300e-11, + 0h3e21ee9d7b4e3f05, // 2.08757008419747316778e-9, + 0hbe927e4f7eac4bc6, // -2.75573141792967388112e-7, + 0h3efa01a019c844f5, // 2.48015872888517045348e-5, + 0hbf56c16c16c14f91, // -1.38888888888730564116e-3, + 0h3fa555555555554b, // 4.16666666666665929218e-2, +} + +// REDUCE_THRESHOLD is the maximum value of x where the reduction using Pi/4 +// in 3 f64 parts still gives accurate results. This threshold +// is set by y*C being representable as a f64 without error +// where y is given by y = floor(x * (4 / Pi)) and C is the leading partial +// terms of 4/Pi. Since the leading terms (PI4A and PI4B in sin.go) have 30 +// and 32 trailing zero bits, y should have less than 30 significant bits. +// +// y < 1<<30 -> floor(x*4/Pi) < 1<<30 -> x < (1<<30 - 1) * Pi/4 +// +// So, conservatively we can take x < 1<<29. +// Above this threshold Payne-Hanek range reduction must be used. +@(private="file") +REDUCE_THRESHOLD :: 1 << 29 + +// _trig_reduce_f64 implements Payne-Hanek range reduction by Pi/4 +// for x > 0. It returns the integer part mod 8 (j) and +// the fractional part (z) of x / (Pi/4). +// The implementation is based on: +// "ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit" +// K. C. Ng et al, March 24, 1992 +// The simulated multi-precision calculation of x*B uses 64-bit integer arithmetic. +_trig_reduce_f64 :: proc "contextless" (x: f64) -> (j: u64, z: f64) #no_bounds_check { + // bd_pi4 is the binary digits of 4/pi as a u64 array, + // that is, 4/pi = Sum bd_pi4[i]*2^(-64*i) + // 19 64-bit digits and the leading one bit give 1217 bits + // of precision to handle the largest possible f64 exponent. + @static bd_pi4 := [?]u64{ + 0x0000000000000001, + 0x45f306dc9c882a53, + 0xf84eafa3ea69bb81, + 0xb6c52b3278872083, + 0xfca2c757bd778ac3, + 0x6e48dc74849ba5c0, + 0x0c925dd413a32439, + 0xfc3bd63962534e7d, + 0xd1046bea5d768909, + 0xd338e04d68befc82, + 0x7323ac7306a673e9, + 0x3908bf177bf25076, + 0x3ff12fffbc0b301f, + 0xde5e2316b414da3e, + 0xda6cfd9e4f96136e, + 0x9e8c7ecd3cbfd45a, + 0xea4f758fd7cbe2f6, + 0x7a0e73ef14a525d4, + 0xd7f6bf623f1aba10, + 0xac06608df8f6d757, + } + + PI4 :: PI / 4 + if x < PI4 { + return 0, x + } + + MASK :: 0x7FF + SHIFT :: 64 - 11 - 1 + BIAS :: 1023 + + // Extract out the integer and exponent such that, + // x = ix * 2 ** exp. + ix := transmute(u64)x + exp := int(ix>>SHIFT&MASK) - BIAS - SHIFT + ix &~= MASK << SHIFT + ix |= 1 << SHIFT + // Use the exponent to extract the 3 appropriate u64 digits from bd_pi4, + // B ~ (z0, z1, z2), such that the product leading digit has the exponent -61. + // Note, exp >= -53 since x >= PI4 and exp < 971 for maximum f64. + digit, bitshift := uint(exp+61)/64, uint(exp+61)%64 + z0 := (bd_pi4[digit] << bitshift) | (bd_pi4[digit+1] >> (64 - bitshift)) + z1 := (bd_pi4[digit+1] << bitshift) | (bd_pi4[digit+2] >> (64 - bitshift)) + z2 := (bd_pi4[digit+2] << bitshift) | (bd_pi4[digit+3] >> (64 - bitshift)) + // Multiply mantissa by the digits and extract the upper two digits (hi, lo). + z2hi, _ := bits.mul(z2, ix) + z1hi, z1lo := bits.mul(z1, ix) + z0lo := z0 * ix + lo, c := bits.add(z1lo, z2hi, 0) + hi, _ := bits.add(z0lo, z1hi, c) + // The top 3 bits are j. + j = hi >> 61 + // Extract the fraction and find its magnitude. + hi = hi<<3 | lo>>61 + lz := uint(bits.leading_zeros(hi)) + e := u64(BIAS - (lz + 1)) + // Clear implicit mantissa bit and shift into place. + hi = (hi << (lz + 1)) | (lo >> (64 - (lz + 1))) + hi >>= 64 - SHIFT + // Include the exponent and convert to a float. + hi |= e << SHIFT + z = transmute(f64)hi + // Map zeros to origin. + if j&1 == 1 { + j += 1 + j &= 7 + z -= 1 + } + // Multiply the fractional part by pi/4. + return j, z * PI4 +} diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 603c2a6c7..7767740c9 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -813,22 +813,22 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, switch mode { case .Alloc: if size > 0 { - panic("mem: panic allocator, .Alloc called") + panic("mem: panic allocator, .Alloc called", loc=loc) } case .Alloc_Non_Zeroed: if size > 0 { - panic("mem: panic allocator, .Alloc_Non_Zeroed called") + panic("mem: panic allocator, .Alloc_Non_Zeroed called", loc=loc) } case .Resize: if size > 0 { - panic("mem: panic allocator, .Resize called") + panic("mem: panic allocator, .Resize called", loc=loc) } case .Free: if old_memory != nil { - panic("mem: panic allocator, .Free called") + panic("mem: panic allocator, .Free called", loc=loc) } case .Free_All: - panic("mem: panic allocator, .Free_All called") + panic("mem: panic allocator, .Free_All called", loc=loc) case .Query_Features: set := (^Allocator_Mode_Set)(old_memory) @@ -838,7 +838,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return nil, nil case .Query_Info: - panic("mem: panic allocator, .Query_Info called") + panic("mem: panic allocator, .Query_Info called", loc=loc) } return nil, nil diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 027a6ce6e..cfd35ab05 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -120,7 +120,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l if arena.minimum_block_size == 0 { arena.minimum_block_size = DEFAULT_ARENA_STATIC_RESERVE_SIZE } - arena_init_static(arena=arena, reserved=arena.minimum_block_size, commit_size=DEFAULT_ARENA_STATIC_COMMIT_SIZE) or_return + arena_init_static(arena, reserved=arena.minimum_block_size, commit_size=DEFAULT_ARENA_STATIC_COMMIT_SIZE) or_return } fallthrough case .Buffer: @@ -242,7 +242,7 @@ arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, min return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size) } -// Ability to bootstrap allocate a struct with an arena within the struct itself using the growing variant strategy. +// Ability to bootstrap allocate a struct with an arena within the struct itself using the static variant strategy. @(require_results) arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { bootstrap: Arena @@ -258,7 +258,7 @@ arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintpt return } -// Ability to bootstrap allocate a struct with an arena within the struct itself using the growing variant strategy. +// Ability to bootstrap allocate a struct with an arena within the struct itself using the static variant strategy. @(require_results) arena_static_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { return arena_static_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved) @@ -271,7 +271,7 @@ arena_allocator :: proc(arena: ^Arena) -> mem.Allocator { return mem.Allocator{arena_allocator_proc, arena} } -// The allocator procedured by an `Allocator` produced by `arena_allocator` +// The allocator procedure used by an `Allocator` produced by `arena_allocator` arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, @@ -328,7 +328,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, -// An `Arena_Temp` is a way to produce temporary watermarks to reset a arena to a previous state. +// An `Arena_Temp` is a way to produce temporary watermarks to reset an arena to a previous state. // All uses of an `Arena_Temp` must be handled by ending them with `arena_temp_end` or ignoring them with `arena_temp_ignore`. Arena_Temp :: struct { arena: ^Arena, diff --git a/core/mem/virtual/virtual_bsd.odin b/core/mem/virtual/virtual_bsd.odin new file mode 100644 index 000000000..103e48074 --- /dev/null +++ b/core/mem/virtual/virtual_bsd.odin @@ -0,0 +1,24 @@ +//+build freebsd, openbsd +//+private +package mem_virtual + + + +_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { + return nil, nil +} + +_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { + return nil +} +_decommit :: proc "contextless" (data: rawptr, size: uint) { +} +_release :: proc "contextless" (data: rawptr, size: uint) { +} +_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { + return false +} + +_platform_memory_init :: proc() { + +} diff --git a/core/net/dns_unix.odin b/core/net/dns_unix.odin index bbecc7476..e9b7bd066 100644 --- a/core/net/dns_unix.odin +++ b/core/net/dns_unix.odin @@ -44,9 +44,6 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator : if !hosts_ok { return nil, .Invalid_Hosts_Config_Error } - if len(hosts) == 0 { - return - } host_overrides := make([dynamic]DNS_Record) for host in hosts { @@ -80,4 +77,4 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator : } return get_dns_records_from_nameservers(hostname, type, name_servers, host_overrides[:]) -}
\ No newline at end of file +} diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index f00be9915..081892afd 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -268,9 +268,9 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca t, ok := value.(time.Duration) if !ok do panic("set_option() value must be a time.Duration here", loc) - nanos := time.duration_nanoseconds(t) - timeval_value.nanoseconds = int(nanos % 1e9) - timeval_value.seconds = (nanos - i64(timeval_value.nanoseconds)) / 1e9 + micros := i64(time.duration_microseconds(t)) + timeval_value.microseconds = int(micros % 1e6) + timeval_value.seconds = (micros - i64(timeval_value.microseconds)) / 1e6 ptr = &timeval_value len = size_of(timeval_value) @@ -368,4 +368,4 @@ _sockaddr_to_endpoint :: proc(native_addr: ^os.SOCKADDR_STORAGE_LH) -> (ep: Endp panic("native_addr is neither IP4 or IP6 address") } return -}
\ No newline at end of file +} diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index 690e09ab7..b7141e8ba 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -283,9 +283,9 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca t, ok := value.(time.Duration) if !ok do panic("set_option() value must be a time.Duration here", loc) - nanos := time.duration_nanoseconds(t) - timeval_value.nanoseconds = int(nanos % 1e9) - timeval_value.seconds = (nanos - i64(timeval_value.nanoseconds)) / 1e9 + micros := i64(time.duration_microseconds(t)) + timeval_value.microseconds = int(micros % 1e6) + timeval_value.seconds = (micros - i64(timeval_value.microseconds)) / 1e6 ptr = &timeval_value len = size_of(timeval_value) @@ -404,4 +404,4 @@ _sockaddr_basic_to_endpoint :: proc(native_addr: ^os.SOCKADDR) -> (ep: Endpoint) panic("native_addr is neither IP4 or IP6 address") } return -}
\ No newline at end of file +} diff --git a/core/os/os2/errors_windows.odin b/core/os/os2/errors_windows.odin index 27c16e72e..6500e7ccc 100644 --- a/core/os/os2/errors_windows.odin +++ b/core/os/os2/errors_windows.odin @@ -37,14 +37,18 @@ _get_platform_error :: proc() -> Error { case win32.ERROR_NOT_SUPPORTED: return .Unsupported + case win32.ERROR_HANDLE_EOF: + return .EOF + + case win32.ERROR_INVALID_HANDLE: + return .Invalid_File + case win32.ERROR_BAD_ARGUMENTS, win32.ERROR_INVALID_PARAMETER, win32.ERROR_NOT_ENOUGH_MEMORY, - win32.ERROR_INVALID_HANDLE, win32.ERROR_NO_MORE_FILES, win32.ERROR_LOCK_VIOLATION, - win32.ERROR_HANDLE_EOF, win32.ERROR_BROKEN_PIPE, win32.ERROR_CALL_NOT_IMPLEMENTED, win32.ERROR_INSUFFICIENT_BUFFER, diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index eb6d9e366..da822374a 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -8,12 +8,6 @@ File :: struct { impl: _File, } -Seek_From :: enum { - Start = 0, // seek relative to the origin of the file - Current = 1, // seek relative to the current offset - End = 2, // seek relative to the end -} - File_Mode :: distinct u32 File_Mode_Dir :: File_Mode(1<<16) File_Mode_Named_Pipe :: File_Mode(1<<17) @@ -72,56 +66,70 @@ fd :: proc(f: ^File) -> uintptr { return _fd(f) } - -close :: proc(f: ^File) -> Error { - return _close(f) -} - name :: proc(f: ^File) -> string { return _name(f) } -seek :: proc(f: ^File, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) { - return _seek(f, offset, whence) +close :: proc(f: ^File) -> Error { + if f != nil { + return io.close(f.impl.stream) + } + return nil } -read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { - return _read(f, p) +seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) { + if f != nil { + return io.seek(f.impl.stream, offset, whence) + } + return 0, .Invalid_File } -read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { - return _read_at(f, p, offset) +read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { + if f != nil { + return io.read(f.impl.stream, p) + } + return 0, .Invalid_File } -read_from :: proc(f: ^File, r: io.Reader) -> (n: i64, err: Error) { - return _read_from(f, r) +read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { + if f != nil { + return io.read_at(f.impl.stream, p, offset) + } + return 0, .Invalid_File } write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { - return _write(f, p) + if f != nil { + return io.write(f.impl.stream, p) + } + return 0, .Invalid_File } write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { - return _write_at(f, p, offset) -} - -write_to :: proc(f: ^File, w: io.Writer) -> (n: i64, err: Error) { - return _write_to(f, w) + if f != nil { + return io.write_at(f.impl.stream, p, offset) + } + return 0, .Invalid_File } file_size :: proc(f: ^File) -> (n: i64, err: Error) { - return _file_size(f) + if f != nil { + return io.size(f.impl.stream) + } + return 0, .Invalid_File } +flush :: proc(f: ^File) -> Error { + if f != nil { + return io.flush(f.impl.stream) + } + return nil +} sync :: proc(f: ^File) -> Error { return _sync(f) } -flush :: proc(f: ^File) -> Error { - return _flush(f) -} - truncate :: proc(f: ^File, size: i64) -> Error { return _truncate(f, size) } diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 890bbfc43..ddd827bce 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -33,6 +33,8 @@ _File :: struct { name: string, fd: int, allocator: runtime.Allocator, + + stream: io.Stream, } _file_allocator :: proc() -> runtime.Allocator { @@ -73,6 +75,10 @@ _new_file :: proc(fd: uintptr, _: string) -> ^File { file.impl.fd = int(fd) file.impl.allocator = _file_allocator() file.impl.name = _get_full_path(file.impl.fd, file.impl.allocator) + file.impl.stream = { + data = file, + procedure = _file_stream_proc, + } return file } @@ -102,7 +108,7 @@ _name :: proc(f: ^File) -> string { return f.impl.name if f != nil else "" } -_seek :: proc(f: ^File, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) { +_seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) { res := unix.sys_lseek(f.impl.fd, offset, int(whence)) if res < 0 { return -1, _get_platform_error(int(res)) @@ -110,18 +116,18 @@ _seek :: proc(f: ^File, offset: i64, whence: Seek_From) -> (ret: i64, err: Error return res, nil } -_read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { +_read :: proc(f: ^File, p: []byte) -> (i64, Error) { if len(p) == 0 { return 0, nil } - n = unix.sys_read(f.impl.fd, &p[0], len(p)) + n := unix.sys_read(f.impl.fd, &p[0], len(p)) if n < 0 { return -1, _get_platform_error(n) } - return n, nil + return i64(n), nil } -_read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { +_read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: i64, err: Error) { if offset < 0 { return 0, .Invalid_Offset } @@ -132,30 +138,25 @@ _read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { if m < 0 { return -1, _get_platform_error(m) } - n += m + n += i64(m) b = b[m:] offset += i64(m) } return } -_read_from :: proc(f: ^File, r: io.Reader) -> (n: i64, err: Error) { - //TODO - return -} - -_write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { +_write :: proc(f: ^File, p: []byte) -> (i64, Error) { if len(p) == 0 { return 0, nil } - n = unix.sys_write(f.impl.fd, &p[0], uint(len(p))) + n := unix.sys_write(f.impl.fd, &p[0], uint(len(p))) if n < 0 { return -1, _get_platform_error(n) } - return int(n), nil + return i64(n), nil } -_write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { +_write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: i64, err: Error) { if offset < 0 { return 0, .Invalid_Offset } @@ -166,18 +167,13 @@ _write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { if m < 0 { return -1, _get_platform_error(m) } - n += m + n += i64(m) b = b[m:] offset += i64(m) } return } -_write_to :: proc(f: ^File, w: io.Writer) -> (n: i64, err: Error) { - //TODO - return -} - _file_size :: proc(f: ^File) -> (n: i64, err: Error) { s: _Stat = --- res := unix.sys_fstat(f.impl.fd, &s) @@ -366,3 +362,49 @@ _is_dir_fd :: proc(fd: int) -> bool { _temp_name_to_cstring :: proc(name: string) -> (cname: cstring) { return strings.clone_to_cstring(name, context.temp_allocator) } + + +@(private="package") +_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + f := (^File)(stream_data) + ferr: Error + i: int + switch mode { + case .Read: + n, ferr = _read(f, p) + err = error_to_io_error(ferr) + return + case .Read_At: + n, ferr = _read_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Write: + n, ferr = _write(f, p) + err = error_to_io_error(ferr) + return + case .Write_At: + n, ferr = _write_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Seek: + n, ferr = _seek(f, offset, whence) + err = error_to_io_error(ferr) + return + case .Size: + n, ferr = _file_size(f) + err = error_to_io_error(ferr) + return + case .Flush: + ferr = _flush(f) + err = error_to_io_error(ferr) + return + case .Close, .Destroy: + ferr = _close(f) + err = error_to_io_error(ferr) + return + case .Query: + return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Destroy, .Query}) + } + return 0, .Empty +} + diff --git a/core/os/os2/file_stream.odin b/core/os/os2/file_stream.odin index 7edbd68fa..da1e3344f 100644 --- a/core/os/os2/file_stream.odin +++ b/core/os/os2/file_stream.odin @@ -3,17 +3,15 @@ package os2 import "core:io" to_stream :: proc(f: ^File) -> (s: io.Stream) { - s.stream_data = f - s.stream_vtable = &_file_stream_vtable + if f != nil { + assert(f.impl.stream.procedure != nil) + s = f.impl.stream + } return } -to_writer :: proc(f: ^File) -> (s: io.Writer) { - return {to_stream(f)} -} -to_reader :: proc(f: ^File) -> (s: io.Reader) { - return {to_stream(f)} -} +to_writer :: to_stream +to_reader :: to_stream @(private) @@ -23,71 +21,3 @@ error_to_io_error :: proc(ferr: Error) -> io.Error { } return ferr.(io.Error) or_else .Unknown } - - -@(private) -_file_stream_vtable := io.Stream_VTable{ - impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - f := (^File)(s.stream_data) - ferr: Error - n, ferr = read(f, p) - err = error_to_io_error(ferr) - return - }, - impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) { - f := (^File)(s.stream_data) - ferr: Error - n, ferr = read_at(f, p, offset) - err = error_to_io_error(ferr) - return - }, - impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) { - f := (^File)(s.stream_data) - ferr: Error - n, ferr = write_to(f, w) - err = error_to_io_error(ferr) - return - }, - impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - f := (^File)(s.stream_data) - ferr: Error - n, ferr = write(f, p) - err = error_to_io_error(ferr) - return - }, - impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) { - f := (^File)(s.stream_data) - ferr: Error - n, ferr = write_at(f, p, offset) - err = error_to_io_error(ferr) - return - }, - impl_read_from = proc(s: io.Stream, r: io.Reader) -> (n: i64, err: io.Error) { - f := (^File)(s.stream_data) - ferr: Error - n, ferr = read_from(f, r) - err = error_to_io_error(ferr) - return - }, - impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) { - f := (^File)(s.stream_data) - n, ferr := seek(f, offset, Seek_From(whence)) - err := error_to_io_error(ferr) - return n, err - }, - impl_size = proc(s: io.Stream) -> i64 { - f := (^File)(s.stream_data) - sz, _ := file_size(f) - return sz - }, - impl_flush = proc(s: io.Stream) -> io.Error { - f := (^File)(s.stream_data) - ferr := flush(f) - return error_to_io_error(ferr) - }, - impl_close = proc(s: io.Stream) -> io.Error { - f := (^File)(s.stream_data) - ferr := close(f) - return error_to_io_error(ferr) - }, -} diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index e4ae4856a..600ecde21 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -38,6 +38,8 @@ _File :: struct { wname: win32.wstring, kind: _File_Kind, + stream: io.Stream, + allocator: runtime.Allocator, rw_mutex: sync.RW_Mutex, // read write calls @@ -144,6 +146,11 @@ _new_file :: proc(handle: uintptr, name: string) -> ^File { } f.impl.kind = kind + f.impl.stream = { + data = f, + procedure = _file_stream_proc, + } + return f } @@ -181,7 +188,7 @@ _name :: proc(f: ^File) -> string { return f.impl.name if f != nil else "" } -_seek :: proc(f: ^File, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) { +_seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) { handle := _handle(f) if handle == win32.INVALID_HANDLE { return 0, .Invalid_File @@ -208,7 +215,7 @@ _seek :: proc(f: ^File, offset: i64, whence: Seek_From) -> (ret: i64, err: Error return i64(hi)<<32 + i64(dw_ptr), nil } -_read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { +_read :: proc(f: ^File, p: []byte) -> (n: i64, err: Error) { read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) { if len(b) == 0 { return 0, nil @@ -274,7 +281,7 @@ _read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { n, err := read_console(handle, p[total_read:][:to_read]) total_read += n if err != nil { - return int(total_read), err + return i64(total_read), err } } else { ok = win32.ReadFile(handle, &p[total_read], to_read, &single_read_length, nil) @@ -287,11 +294,11 @@ _read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { } } - return int(total_read), nil + return i64(total_read), err } -_read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { - pread :: proc(f: ^File, data: []byte, offset: i64) -> (n: int, err: Error) { +_read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: i64, err: Error) { + pread :: proc(f: ^File, data: []byte, offset: i64) -> (n: i64, err: Error) { buf := data if len(buf) > MAX_RW { buf = buf[:MAX_RW] @@ -313,7 +320,7 @@ _read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { err = _get_platform_error() done = 0 } - n = int(done) + n = i64(done) return } @@ -329,12 +336,7 @@ _read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { return } -_read_from :: proc(f: ^File, r: io.Reader) -> (n: i64, err: Error) { - // TODO(bill) - return -} - -_write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { +_write :: proc(f: ^File, p: []byte) -> (n: i64, err: Error) { if len(p) == 0 { return } @@ -352,17 +354,17 @@ _write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) { e := win32.WriteFile(handle, &p[total_write], to_write, &single_write_length, nil) if single_write_length <= 0 || !e { - n = int(total_write) + n = i64(total_write) err = _get_platform_error() return } total_write += i64(single_write_length) } - return int(total_write), nil + return i64(total_write), nil } -_write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { - pwrite :: proc(f: ^File, data: []byte, offset: i64) -> (n: int, err: Error) { +_write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: i64, err: Error) { + pwrite :: proc(f: ^File, data: []byte, offset: i64) -> (n: i64, err: Error) { buf := data if len(buf) > MAX_RW { buf = buf[:MAX_RW] @@ -382,7 +384,7 @@ _write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { err = _get_platform_error() done = 0 } - n = int(done) + n = i64(done) return } @@ -397,11 +399,6 @@ _write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) { return } -_write_to :: proc(f: ^File, w: io.Writer) -> (n: i64, err: Error) { - // TODO(bill) - return -} - _file_size :: proc(f: ^File) -> (n: i64, err: Error) { length: win32.LARGE_INTEGER handle := _handle(f) @@ -727,3 +724,51 @@ _is_dir :: proc(path: string) -> bool { } return false } + + +@(private="package") +_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + f := (^File)(stream_data) + ferr: Error + i: int + switch mode { + case .Read: + n, ferr = _read(f, p) + err = error_to_io_error(ferr) + return + case .Read_At: + n, ferr = _read_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Write: + n, ferr = _write(f, p) + err = error_to_io_error(ferr) + return + case .Write_At: + n, ferr = _write_at(f, p, offset) + err = error_to_io_error(ferr) + return + case .Seek: + n, ferr = _seek(f, offset, whence) + err = error_to_io_error(ferr) + return + case .Size: + n, ferr = _file_size(f) + err = error_to_io_error(ferr) + return + case .Flush: + ferr = _flush(f) + err = error_to_io_error(ferr) + return + case .Close: + ferr = _close(f) + err = error_to_io_error(ferr) + return + case .Query: + return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Flush, .Close, .Query}) + case .Destroy: + return 0, .Empty + } + return 0, .Empty +} + diff --git a/core/os/os2/path_windows.odin b/core/os/os2/path_windows.odin index 2dc667822..a2306784e 100644 --- a/core/os/os2/path_windows.odin +++ b/core/os/os2/path_windows.odin @@ -23,7 +23,7 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { fix_root_directory :: proc(p: string) -> (s: string, allocated: bool, err: runtime.Allocator_Error) { if len(p) == len(`\\?\c:`) { if is_path_separator(p[0]) && is_path_separator(p[1]) && p[2] == '?' && is_path_separator(p[3]) && p[5] == ':' { - s = strings.concatenate_safe({p, `\`}, _file_allocator()) or_return + s = strings.concatenate({p, `\`}, _file_allocator()) or_return allocated = true return } diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index a2d68aeed..d8ba40fd0 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -314,15 +314,16 @@ Dirent :: struct { Dir :: distinct rawptr // DIR* +ADDRESS_FAMILY :: c.char SOCKADDR :: struct #packed { len: c.char, - family: c.char, + family: ADDRESS_FAMILY, sa_data: [14]c.char, } SOCKADDR_STORAGE_LH :: struct #packed { len: c.char, - family: c.char, + family: ADDRESS_FAMILY, __ss_pad1: [6]c.char, __ss_align: i64, __ss_pad2: [112]c.char, @@ -330,7 +331,7 @@ SOCKADDR_STORAGE_LH :: struct #packed { sockaddr_in :: struct #packed { sin_len: c.char, - sin_family: c.char, + sin_family: ADDRESS_FAMILY, sin_port: u16be, sin_addr: in_addr, sin_zero: [8]c.char, @@ -338,7 +339,7 @@ sockaddr_in :: struct #packed { sockaddr_in6 :: struct #packed { sin6_len: c.char, - sin6_family: c.char, + sin6_family: ADDRESS_FAMILY, sin6_port: u16be, sin6_flowinfo: c.uint, sin6_addr: in6_addr, @@ -355,7 +356,7 @@ in6_addr :: struct #packed { Timeval :: struct { seconds: i64, - nanoseconds: int, + microseconds: int, } Linger :: struct { @@ -440,7 +441,7 @@ foreign libc { @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int --- @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) --- - @(link_name="__fcntl") _unix__fcntl :: proc(fd: Handle, cmd: c.int, #c_vararg args: ..any) -> c.int --- + @(link_name="__fcntl") _unix__fcntl :: proc(fd: Handle, cmd: c.int, arg: uintptr) -> c.int --- @(link_name="rename") _unix_rename :: proc(old: cstring, new: cstring) -> c.int --- @(link_name="remove") _unix_remove :: proc(path: cstring) -> c.int --- @@ -794,14 +795,14 @@ _readlink :: proc(path: string) -> (string, Errno) { } absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) { - buf : [256]byte - res := _unix__fcntl(fd, F_GETPATH, &buf[0]) - if res != 0 { - return "", Errno(get_last_error()) + buf: [DARWIN_MAXPATHLEN]byte + _, err := fcntl(int(fd), F_GETPATH, int(uintptr(&buf[0]))) + if err != ERROR_NONE { + return "", err } path := strings.clone_from_cstring(cstring(&buf[0])) - return path, ERROR_NONE + return path, err } absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { @@ -1068,7 +1069,7 @@ shutdown :: proc(sd: Socket, how: int) -> (Errno) { } fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { - result := _unix__fcntl(Handle(fd), c.int(cmd), c.int(arg)) + result := _unix__fcntl(Handle(fd), c.int(cmd), uintptr(arg)) if result < 0 { return 0, Errno(get_last_error()) } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 3dc48087a..1a4c1fddb 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -241,7 +241,7 @@ socklen_t :: c.int Timeval :: struct { seconds: i64, - nanoseconds: int, + microseconds: int, } // "Argv" arguments converted to Odin strings @@ -432,6 +432,14 @@ AT_FDCWD :: ~uintptr(99) /* -100 */ AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) +pollfd :: struct { + fd: c.int, + events: c.short, + revents: c.short, +} + +sigset_t :: distinct u64 + foreign libc { @(link_name="__errno_location") __errno_location :: proc() -> ^int --- @@ -450,6 +458,7 @@ foreign libc { @(link_name="execvp") _unix_execvp :: proc(path: cstring, argv: [^]cstring) -> int --- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- @(link_name="putenv") _unix_putenv :: proc(cstring) -> c.int --- + @(link_name="setenv") _unix_setenv :: proc(key: cstring, value: cstring, overwrite: c.int) -> c.int --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- @@ -885,8 +894,10 @@ get_env :: proc(key: string, allocator := context.allocator) -> (value: string) set_env :: proc(key, value: string) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - s := strings.concatenate({key, "=", value, "\x00"}, context.temp_allocator) - res := _unix_putenv(strings.unsafe_string_to_cstring(s)) + key_cstring := strings.clone_to_cstring(key, context.temp_allocator) + value_cstring := strings.clone_to_cstring(value, context.temp_allocator) + // NOTE(GoNZooo): `setenv` instead of `putenv` because it copies both key and value more commonly + res := _unix_setenv(key_cstring, value_cstring, 1) if res < 0 { return Errno(get_last_error()) } @@ -1086,4 +1097,20 @@ fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) { return 0, _get_errno(result) } return result, ERROR_NONE -}
\ No newline at end of file +} + +poll :: proc(fds: []pollfd, timeout: int) -> (int, Errno) { + result := unix.sys_poll(raw_data(fds), uint(len(fds)), timeout) + if result < 0 { + return 0, _get_errno(result) + } + return result, ERROR_NONE +} + +ppoll :: proc(fds: []pollfd, timeout: ^unix.timespec, sigmask: ^sigset_t) -> (int, Errno) { + result := unix.sys_ppoll(raw_data(fds), uint(len(fds)), timeout, sigmask, size_of(sigset_t)) + if result < 0 { + return 0, _get_errno(result) + } + return result, ERROR_NONE +} diff --git a/core/os/stream.odin b/core/os/stream.odin index 9506ed3a3..2b4c83663 100644 --- a/core/os/stream.odin +++ b/core/os/stream.odin @@ -4,66 +4,60 @@ import "core:io" stream_from_handle :: proc(fd: Handle) -> io.Stream { s: io.Stream - s.stream_data = rawptr(uintptr(fd)) - s.stream_vtable = &_file_stream_vtable + s.data = rawptr(uintptr(fd)) + s.procedure = _file_stream_proc return s } @(private) -_file_stream_vtable := io.Stream_VTable{ - impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - fd := Handle(uintptr(s.stream_data)) - os_err: Errno - n, os_err = read(fd, p) - return - }, - impl_read_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) { - when ODIN_OS == .Windows || ODIN_OS == .WASI { - fd := Handle(uintptr(s.stream_data)) - os_err: Errno - n, os_err = read_at(fd, p, offset) - } - return - }, - impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - fd := Handle(uintptr(s.stream_data)) - os_err: Errno - n, os_err = write(fd, p) - return - }, - impl_write_at = proc(s: io.Stream, p: []byte, offset: i64) -> (n: int, err: io.Error) { - when ODIN_OS == .Windows || ODIN_OS == .WASI { - fd := Handle(uintptr(s.stream_data)) - os_err: Errno - n, os_err = write_at(fd, p, offset) - _ = os_err - } - return - }, - impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) { - fd := Handle(uintptr(s.stream_data)) - n, os_err := seek(fd, offset, int(whence)) - _ = os_err - return n, nil - }, - impl_size = proc(s: io.Stream) -> i64 { - fd := Handle(uintptr(s.stream_data)) - sz, _ := file_size(fd) - return sz - }, - impl_flush = proc(s: io.Stream) -> io.Error { +_file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + fd := Handle(uintptr(stream_data)) + n_int: int + os_err: Errno + switch mode { + case .Close: + close(fd) + case .Flush: when ODIN_OS == .Windows { - fd := Handle(uintptr(s.stream_data)) flush(fd) } else { // TOOD(bill): other operating systems } - return nil - }, - impl_close = proc(s: io.Stream) -> io.Error { - fd := Handle(uintptr(s.stream_data)) - close(fd) - return nil - }, + case .Read: + n_int, os_err = read(fd, p) + n = i64(n_int) + if os_err != 0 { + err = .Unknown + } + case .Read_At: + when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) { + n_int, os_err = read_at(fd, p, offset) + n = i64(n_int) + } + case .Write: + n_int, os_err = write(fd, p) + n = i64(n_int) + case .Write_At: + when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) { + n_int, os_err = write_at(fd, p, offset) + n = i64(n_int) + } + case .Seek: + n, os_err = seek(fd, offset, int(whence)) + case .Size: + n, os_err = file_size(fd) + case .Destroy: + err = .Empty + case .Query: + when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { + return io.query_utility({.Close, .Flush, .Read, .Write, .Seek, .Size, .Query}) + } else { + return io.query_utility({.Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query}) + } + } + if err == nil && os_err != 0 { + err = .Unknown + } + return } diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index f8343ead2..a88557e0e 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -132,7 +132,7 @@ type_info_core :: runtime.type_info_core type_info_base_without_enum :: type_info_core -when !ODIN_DISALLOW_RTTI { +when !ODIN_NO_RTTI { typeid_base :: runtime.typeid_base typeid_core :: runtime.typeid_core typeid_base_without_enum :: typeid_core @@ -781,7 +781,7 @@ set_union_variant_raw_tag :: proc(a: any, tag: i64) { tag_ptr := uintptr(a.data) + info.tag_offset tag_any := any{rawptr(tag_ptr), info.tag_type.id} - switch i in &tag_any { + switch &i in tag_any { case u8: i = u8(tag) case i8: i = i8(tag) case u16: i = u16(tag) @@ -1312,7 +1312,7 @@ relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) ptr_any := any{data, base_integer_id} ptr: rawptr - switch i in &ptr_any { + switch &i in ptr_any { case u8: ptr = _handle(&i) case u16: ptr = _handle(&i) case u32: ptr = _handle(&i) diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 058ca6161..83504c9ee 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -566,7 +566,7 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check return &type_table[n] } -when !ODIN_DISALLOW_RTTI { +when !ODIN_NO_RTTI { typeid_base :: proc "contextless" (id: typeid) -> typeid { ti := type_info_of(id) ti = type_info_base(ti) diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index c5cb8cc07..9f2899bcc 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -112,7 +112,7 @@ remove_range :: proc(array: ^$D/[dynamic]$T, lo, hi: int, loc := #caller_locatio // Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic. @builtin pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { - assert(len(array) > 0, "", loc) + assert(len(array) > 0, loc=loc) res = array[len(array)-1] (^Raw_Dynamic_Array)(array).len -= 1 return res @@ -136,7 +136,7 @@ pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check // Note: If the dynamic array as no elements (`len(array) == 0`), this procedure will panic. @builtin pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { - assert(len(array) > 0, "", loc) + assert(len(array) > 0, loc=loc) res = array[0] if len(array) > 1 { copy(array[0:], array[1:]) @@ -424,7 +424,7 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> a := (^Raw_Dynamic_Array)(array) when size_of(E) != 0 { data := ([^]E)(a.data) - assert(condition=data != nil, loc=loc) + assert(data != nil, loc=loc) data[a.len] = arg } a.len += 1 @@ -459,7 +459,7 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) a := (^Raw_Dynamic_Array)(array) when size_of(E) != 0 { data := ([^]E)(a.data) - assert(condition=data != nil, loc=loc) + assert(data != nil, loc=loc) intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len) } a.len += arg_len @@ -472,7 +472,7 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) @builtin append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { args := transmute([]E)arg - return append_elems(array=array, args=args, loc=loc) + return append_elems(array, ..args, loc=loc) } @@ -481,7 +481,7 @@ append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #ca append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { n_arg: int for arg in args { - n_arg, err = append(array = array, args = transmute([]E)(arg), loc = loc) + n_arg, err = append(array, ..transmute([]E)(arg), loc=loc) n += n_arg if err != nil { return diff --git a/core/runtime/default_allocators_js.odin b/core/runtime/default_allocators_js.odin index cc70b963a..715073f08 100644 --- a/core/runtime/default_allocators_js.odin +++ b/core/runtime/default_allocators_js.odin @@ -1,5 +1,5 @@ //+build js package runtime -default_allocator_proc :: nil_allocator_proc -default_allocator :: nil_allocator +default_allocator_proc :: panic_allocator_proc +default_allocator :: panic_allocator diff --git a/core/runtime/default_allocators_nil.odin b/core/runtime/default_allocators_nil.odin index f86990581..a340050eb 100644 --- a/core/runtime/default_allocators_nil.odin +++ b/core/runtime/default_allocators_nil.odin @@ -35,4 +35,52 @@ nil_allocator :: proc() -> Allocator { when ODIN_OS == .Freestanding { default_allocator_proc :: nil_allocator_proc default_allocator :: nil_allocator -}
\ No newline at end of file +} + + + +panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) { + switch mode { + case .Alloc: + if size > 0 { + panic("panic allocator, .Alloc called", loc=loc) + } + case .Alloc_Non_Zeroed: + if size > 0 { + panic("panic allocator, .Alloc_Non_Zeroed called", loc=loc) + } + case .Resize: + if size > 0 { + panic("panic allocator, .Resize called", loc=loc) + } + case .Free: + if old_memory != nil { + panic("panic allocator, .Free called", loc=loc) + } + case .Free_All: + panic("panic allocator, .Free_All called", loc=loc) + + case .Query_Features: + set := (^Allocator_Mode_Set)(old_memory) + if set != nil { + set^ = {.Query_Features} + } + return nil, nil + + case .Query_Info: + panic("panic allocator, .Query_Info called", loc=loc) + } + + return nil, nil +} + +panic_allocator :: proc() -> Allocator { + return Allocator{ + procedure = nil_allocator_proc, + data = nil, + } +} + + diff --git a/core/runtime/default_allocators_wasi.odin b/core/runtime/default_allocators_wasi.odin index 2e475e055..a7e6842a6 100644 --- a/core/runtime/default_allocators_wasi.odin +++ b/core/runtime/default_allocators_wasi.odin @@ -1,5 +1,5 @@ //+build wasi package runtime -default_allocator_proc :: nil_allocator_proc -default_allocator :: nil_allocator +default_allocator_proc :: panic_allocator_proc +default_allocator :: panic_allocator diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 05c03028f..d34c29d4b 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -414,68 +414,21 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^ tk := map_cell_index_dynamic(sk, info.ks, 1) tv := map_cell_index_dynamic(sv, info.vs, 1) - for { - hp := &hs[pos] - element_hash := hp^ + swap_loop: for { + element_hash := hs[pos] if map_hash_is_empty(element_hash) { - kp := map_cell_index_dynamic(ks, info.ks, pos) - vp := map_cell_index_dynamic(vs, info.vs, pos) - intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k) - intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v) - hp^ = h + k_dst := map_cell_index_dynamic(ks, info.ks, pos) + v_dst := map_cell_index_dynamic(vs, info.vs, pos) + intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) + intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) + hs[pos] = h - return result if result != 0 else vp + return result if result != 0 else v_dst } if map_hash_is_deleted(element_hash) { - next_pos := (pos + 1) & mask - - // backward shift - for !map_hash_is_empty(hs[next_pos]) { - probe_distance := map_probe_distance(m^, hs[next_pos], next_pos) - if probe_distance == 0 { - break - } - probe_distance -= 1 - - kp := map_cell_index_dynamic(ks, info.ks, pos) - vp := map_cell_index_dynamic(vs, info.vs, pos) - kn := map_cell_index_dynamic(ks, info.ks, next_pos) - vn := map_cell_index_dynamic(vs, info.vs, next_pos) - - if distance > probe_distance { - if result == 0 { - result = vp - } - // move stored into pos; store next - intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k) - intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v) - hs[pos] = h - - intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(kn), size_of_k) - intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(vn), size_of_v) - h = hs[next_pos] - } else { - // move next back 1 - intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(kn), size_of_k) - intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(vn), size_of_v) - hs[pos] = hs[next_pos] - distance = probe_distance - } - hs[next_pos] = 0 - pos = (pos + 1) & mask - next_pos = (next_pos + 1) & mask - distance += 1 - } - - kp := map_cell_index_dynamic(ks, info.ks, pos) - vp := map_cell_index_dynamic(vs, info.vs, pos) - intrinsics.mem_copy_non_overlapping(rawptr(kp), rawptr(k), size_of_k) - intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(v), size_of_v) - hs[pos] = h - - return result if result != 0 else vp + break swap_loop } if probe_distance := map_probe_distance(m^, element_hash, pos); distance > probe_distance { @@ -495,8 +448,8 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^ intrinsics.mem_copy_non_overlapping(rawptr(vp), rawptr(tv), size_of_v) th := h - h = hp^ - hp^ = th + h = hs[pos] + hs[pos] = th distance = probe_distance } @@ -504,6 +457,103 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^ pos = (pos + 1) & mask distance += 1 } + + // backward shift loop + hs[pos] = 0 + look_ahead: uintptr = 1 + for { + la_pos := (pos + look_ahead) & mask + element_hash := hs[la_pos] + + if map_hash_is_deleted(element_hash) { + look_ahead += 1 + hs[la_pos] = 0 + continue + } + + k_dst := map_cell_index_dynamic(ks, info.ks, pos) + v_dst := map_cell_index_dynamic(vs, info.vs, pos) + + if map_hash_is_empty(element_hash) { + intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) + intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) + hs[pos] = h + + return result if result != 0 else v_dst + } + + k_src := map_cell_index_dynamic(ks, info.ks, la_pos) + v_src := map_cell_index_dynamic(vs, info.vs, la_pos) + probe_distance := map_probe_distance(m^, element_hash, la_pos) + + if probe_distance < look_ahead { + // probed can be made ideal while placing saved (ending condition) + if result == 0 { + result = v_dst + } + intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) + intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) + hs[pos] = h + + // This will be an ideal move + pos = (la_pos - probe_distance) & mask + look_ahead -= probe_distance + + // shift until we hit ideal/empty + for probe_distance != 0 { + k_dst = map_cell_index_dynamic(ks, info.ks, pos) + v_dst = map_cell_index_dynamic(vs, info.vs, pos) + + intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k_src), size_of_k) + intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v_src), size_of_v) + hs[pos] = element_hash + hs[la_pos] = 0 + + pos = (pos + 1) & mask + la_pos = (la_pos + 1) & mask + look_ahead = (la_pos - pos) & mask + element_hash = hs[la_pos] + if map_hash_is_empty(element_hash) { + return + } + + probe_distance = map_probe_distance(m^, element_hash, la_pos) + if probe_distance == 0 { + return + } + // can be ideal? + if probe_distance < look_ahead { + pos = (la_pos - probe_distance) & mask + } + k_src = map_cell_index_dynamic(ks, info.ks, la_pos) + v_src = map_cell_index_dynamic(vs, info.vs, la_pos) + } + return + } else if distance < probe_distance - look_ahead { + // shift back probed + intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k_src), size_of_k) + intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v_src), size_of_v) + hs[pos] = element_hash + hs[la_pos] = 0 + } else { + // place saved, save probed + if result == 0 { + result = v_dst + } + intrinsics.mem_copy_non_overlapping(rawptr(k_dst), rawptr(k), size_of_k) + intrinsics.mem_copy_non_overlapping(rawptr(v_dst), rawptr(v), size_of_v) + hs[pos] = h + + intrinsics.mem_copy_non_overlapping(rawptr(k), rawptr(k_src), size_of_k) + intrinsics.mem_copy_non_overlapping(rawptr(v), rawptr(v_src), size_of_v) + h = hs[la_pos] + hs[la_pos] = 0 + distance = probe_distance - look_ahead + } + + pos = (pos + 1) & mask + distance += 1 + } } @(require_results) @@ -696,49 +746,19 @@ map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #n m.len -= 1 ok = true - { // coalesce tombstones - // HACK NOTE(bill): This is an ugly bodge but it is coalescing the tombstone slots - mask := (uintptr(1)<<map_log2_cap(m^)) - 1 - curr_index := uintptr(index) - - // TODO(bill): determine a good value for this empirically - // if we do not implement backward shift deletion - PROBE_COUNT :: 8 - for _ in 0..<PROBE_COUNT { - next_index := (curr_index + 1) & mask - if next_index == index { - // looped around - break - } - - // if the next element is empty or has zero probe distance, then any lookup - // will always fail on the next, so we can clear both of them - hash := hs[next_index] - if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 { - hs[curr_index] = 0 - return - } - - // now the next element will have a probe count of at least one, - // so it can use the delete slot instead - hs[curr_index] = hs[next_index] - - mem_copy_non_overlapping( - rawptr(map_cell_index_dynamic(ks, info.ks, curr_index)), - rawptr(map_cell_index_dynamic(ks, info.ks, next_index)), - int(info.ks.size_of_type), - ) - mem_copy_non_overlapping( - rawptr(map_cell_index_dynamic(vs, info.vs, curr_index)), - rawptr(map_cell_index_dynamic(vs, info.vs, next_index)), - int(info.vs.size_of_type), - ) - - curr_index = next_index - } + mask := (uintptr(1)<<map_log2_cap(m^)) - 1 + curr_index := uintptr(index) + next_index := (curr_index + 1) & mask + // if the next element is empty or has zero probe distance, then any lookup + // will always fail on the next, so we can clear both of them + hash := hs[next_index] + if map_hash_is_empty(hash) || map_probe_distance(m^, hash, next_index) == 0 { + hs[curr_index] = 0 + } else { hs[curr_index] |= TOMBSTONE_MASK } + return } diff --git a/core/runtime/error_checks.odin b/core/runtime/error_checks.odin index 8539c724d..c189642af 100644 --- a/core/runtime/error_checks.odin +++ b/core/runtime/error_checks.odin @@ -22,7 +22,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index return } @(cold) - handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) { + handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Index ") print_i64(i64(index)) @@ -83,7 +83,7 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32, return } @(cold) - handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) { + handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Invalid dynamic array indices ") print_i64(i64(low)) @@ -104,7 +104,7 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32 return } @(cold) - handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) { + handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Matrix indices [") print_i64(i64(row_index)) @@ -122,13 +122,13 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32 } -when ODIN_DISALLOW_RTTI { +when ODIN_NO_RTTI { type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32) { if ok { return } @(cold) - handle_error :: proc "contextless" (file: string, line, column: i32) { + handle_error :: proc "contextless" (file: string, line, column: i32) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Invalid type assertion\n") type_assertion_trap() @@ -141,7 +141,7 @@ when ODIN_DISALLOW_RTTI { return } @(cold) - handle_error :: proc "contextless" (file: string, line, column: i32) { + handle_error :: proc "contextless" (file: string, line, column: i32) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Invalid type assertion\n") type_assertion_trap() @@ -154,7 +154,7 @@ when ODIN_DISALLOW_RTTI { return } @(cold) - handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) { + handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) -> ! { print_caller_location(Source_Code_Location{file, line, column, ""}) print_string(" Invalid type assertion from ") print_typeid(from) @@ -199,7 +199,7 @@ when ODIN_DISALLOW_RTTI { } @(cold) - handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) { + handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) -> ! { actual := variant_type(from, from_data) @@ -225,7 +225,7 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio return } @(cold) - handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) { + handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) -> ! { print_caller_location(loc) print_string(" Invalid slice length for make: ") print_i64(i64(len)) @@ -240,7 +240,7 @@ make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := # return } @(cold) - handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) { + handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) -> ! { print_caller_location(loc) print_string(" Invalid dynamic array parameters for make: ") print_i64(i64(len)) @@ -257,7 +257,7 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca return } @(cold) - handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) { + handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) -> ! { print_caller_location(loc) print_string(" Invalid map capacity for make: ") print_i64(i64(cap)) diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 71ad9386a..ad8a40acf 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -566,16 +566,37 @@ max_f64 :: #force_inline proc "contextless" (a, b: f64) -> f64 { } abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 { - r, i := real(x), imag(x) - return f16(intrinsics.sqrt(f32(r*r + i*i))) + p, q := abs(real(x)), abs(imag(x)) + if p < q { + p, q = q, p + } + if p == 0 { + return 0 + } + q = q / p + return p * f16(intrinsics.sqrt(f32(1 + q*q))) } abs_complex64 :: #force_inline proc "contextless" (x: complex64) -> f32 { - r, i := real(x), imag(x) - return intrinsics.sqrt(r*r + i*i) + p, q := abs(real(x)), abs(imag(x)) + if p < q { + p, q = q, p + } + if p == 0 { + return 0 + } + q = q / p + return p * intrinsics.sqrt(1 + q*q) } abs_complex128 :: #force_inline proc "contextless" (x: complex128) -> f64 { - r, i := real(x), imag(x) - return intrinsics.sqrt(r*r + i*i) + p, q := abs(real(x)), abs(imag(x)) + if p < q { + p, q = q, p + } + if p == 0 { + return 0 + } + q = q / p + return p * intrinsics.sqrt(1 + q*q) } abs_quaternion64 :: #force_inline proc "contextless" (x: quaternion64) -> f16 { r, i, j, k := real(x), imag(x), jmag(x), kmag(x) diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 326a29667..732ed9c12 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -5,7 +5,7 @@ _INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz" @(private="file") _INTEGER_DIGITS_VAR := _INTEGER_DIGITS -when !ODIN_DISALLOW_RTTI { +when !ODIN_NO_RTTI { print_any_single :: proc "contextless" (arg: any) { x := arg if loc, ok := x.(Source_Code_Location); ok { @@ -234,7 +234,7 @@ print_caller_location :: proc "contextless" (using loc: Source_Code_Location) { } } print_typeid :: proc "contextless" (id: typeid) { - when ODIN_DISALLOW_RTTI { + when ODIN_NO_RTTI { if id == nil { print_string("nil") } else { diff --git a/core/slice/ptr.odin b/core/slice/ptr.odin index e2f1c3e7b..b17a27dc8 100644 --- a/core/slice/ptr.odin +++ b/core/slice/ptr.odin @@ -1,7 +1,7 @@ package slice import "core:builtin" -import "core:mem" +import "core:runtime" ptr_add :: proc(p: $P/^$T, x: int) -> ^T { return ([^]T)(p)[x:] @@ -27,9 +27,9 @@ ptr_swap_non_overlapping :: proc(x, y: rawptr, len: int) { a := rawptr(uintptr(x) + uintptr(i)) b := rawptr(uintptr(y) + uintptr(i)) - mem.copy(t, a, BLOCK_SIZE) - mem.copy(a, b, BLOCK_SIZE) - mem.copy(b, t, BLOCK_SIZE) + runtime.mem_copy(t, a, BLOCK_SIZE) + runtime.mem_copy(a, b, BLOCK_SIZE) + runtime.mem_copy(b, t, BLOCK_SIZE) } if i < len { @@ -38,9 +38,9 @@ ptr_swap_non_overlapping :: proc(x, y: rawptr, len: int) { a := rawptr(uintptr(x) + uintptr(i)) b := rawptr(uintptr(y) + uintptr(i)) - mem.copy(t, a, rem) - mem.copy(a, b, rem) - mem.copy(b, t, rem) + runtime.mem_copy(t, a, rem) + runtime.mem_copy(a, b, rem) + runtime.mem_copy(b, t, rem) } } @@ -59,9 +59,9 @@ ptr_swap_overlapping :: proc(x, y: rawptr, len: int) { for n := len; n > 0; n -= N { m := builtin.min(n, N) - mem.copy(&buffer, a, m) - mem.copy(a, b, m) - mem.copy(b, &buffer, m) + runtime.mem_copy(&buffer, a, m) + runtime.mem_copy(a, b, m) + runtime.mem_copy(b, &buffer, m) a, b = a[N:], b[N:] } diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 412c90fc8..9a810141d 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -3,12 +3,12 @@ package slice import "core:intrinsics" import "core:builtin" import "core:math/bits" -import "core:mem" +import "core:runtime" _ :: intrinsics _ :: builtin _ :: bits -_ :: mem +_ :: runtime /* Turn a pointer and a length into a slice. @@ -164,7 +164,7 @@ equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) { return false } when intrinsics.type_is_simple_compare(E) { - return mem.compare_ptrs(raw_data(a), raw_data(b), len(a)*size_of(E)) == 0 + return runtime.memory_compare(raw_data(a), raw_data(b), len(a)*size_of(E)) == 0 } else { for i in 0..<len(a) { if a[i] != b[i] { @@ -180,7 +180,7 @@ simple_equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_simple_comp if len(a) != len(b) { return false } - return mem.compare_ptrs(raw_data(a), raw_data(b), len(a)*size_of(E)) == 0 + return runtime.memory_compare(raw_data(a), raw_data(b), len(a)*size_of(E)) == 0 } /* @@ -220,6 +220,12 @@ has_suffix :: proc(array: $T/[]$E, needle: E) -> bool where intrinsics.type_is_c return false } +zero :: proc(array: $T/[]$E) #no_bounds_check { + if len(array) > 0 { + intrinsics.mem_zero(raw_data(array), size_of(E)*len(array)) + } +} + fill :: proc(array: $T/[]$E, value: E) #no_bounds_check { if len(array) <= 0 { return @@ -250,7 +256,7 @@ swap_with_slice :: proc(a, b: $T/[]$E, loc := #caller_location) { } @(require_results) -concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T, err: mem.Allocator_Error) #optional_allocator_error { +concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T, err: runtime.Allocator_Error) #optional_allocator_error { if len(a) == 0 { return } @@ -268,7 +274,7 @@ concatenate :: proc(a: []$T/[]$E, allocator := context.allocator) -> (res: T, er // copies a slice into a new slice @(require_results) -clone :: proc(a: $T/[]$E, allocator := context.allocator) -> ([]E, mem.Allocator_Error) #optional_allocator_error { +clone :: proc(a: $T/[]$E, allocator := context.allocator) -> ([]E, runtime.Allocator_Error) #optional_allocator_error { d, err := make([]E, len(a), allocator) copy(d[:], a) return d, err @@ -276,7 +282,7 @@ clone :: proc(a: $T/[]$E, allocator := context.allocator) -> ([]E, mem.Allocator // copies slice into a new dynamic array -clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> ([dynamic]E, mem.Allocator_Error) #optional_allocator_error { +clone_to_dynamic :: proc(a: $T/[]$E, allocator := context.allocator) -> ([dynamic]E, runtime.Allocator_Error) #optional_allocator_error { d, err := make([dynamic]E, len(a), allocator) copy(d[:], a) return d, err @@ -286,12 +292,12 @@ to_dynamic :: clone_to_dynamic // Converts slice into a dynamic array without cloning or allocating memory @(require_results) into_dynamic :: proc(a: $T/[]$E) -> [dynamic]E { - s := transmute(mem.Raw_Slice)a - d := mem.Raw_Dynamic_Array{ + s := transmute(runtime.Raw_Slice)a + d := runtime.Raw_Dynamic_Array{ data = s.data, len = 0, cap = s.len, - allocator = mem.nil_allocator(), + allocator = runtime.nil_allocator(), } return transmute([dynamic]E)d } @@ -373,7 +379,7 @@ as_ptr :: proc(array: $T/[]$E) -> [^]E { @(require_results) -mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> (r: []V, err: mem.Allocator_Error) #optional_allocator_error { +mapper :: proc(s: $S/[]$U, f: proc(U) -> $V, allocator := context.allocator) -> (r: []V, err: runtime.Allocator_Error) #optional_allocator_error { r = make([]V, len(s), allocator) or_return for v, i in s { r[i] = f(v) @@ -402,7 +408,7 @@ filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) - } @(require_results) -scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> (res: []V, err: mem.Allocator_Error) #optional_allocator_error { +scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := context.allocator) -> (res: []V, err: runtime.Allocator_Error) #optional_allocator_error { if len(s) == 0 { return } res = make([]V, len(s), allocator) or_return diff --git a/core/strings/builder.odin b/core/strings/builder.odin index edde4b297..28c56f6f9 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -164,36 +164,27 @@ builder_init :: proc{ builder_init_len_cap, } @(private) -_builder_stream_vtable_obj := io.Stream_VTable{ - impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - b := (^Builder)(s.stream_data) - n = write_bytes(b, p) - if n < len(p) { +_builder_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + b := (^Builder)(stream_data) + #partial switch mode { + case .Write: + n = i64(write_bytes(b, p)) + if n < i64(len(p)) { err = .EOF } return - }, - impl_write_byte = proc(s: io.Stream, c: byte) -> (err: io.Error) { - b := (^Builder)(s.stream_data) - n := write_byte(b, c) - if n == 0 { - err = .EOF - } + case .Size: + n = i64(len(b.buf)) return - }, - impl_size = proc(s: io.Stream) -> i64 { - b := (^Builder)(s.stream_data) - return i64(len(b.buf)) - }, - impl_destroy = proc(s: io.Stream) -> io.Error { - b := (^Builder)(s.stream_data) + case .Destroy: builder_destroy(b) - return .None - }, + return + case .Query: + return io.query_utility({.Write, .Size, .Destroy, .Query}) + } + return 0, .Empty } -// NOTE(dweiler): Work around a miscompilation bug on Linux still. -@(private) -_builder_stream_vtable := &_builder_stream_vtable_obj + /* Returns an io.Stream from a Builder @@ -204,7 +195,7 @@ Returns: - res: the io.Stream */ to_stream :: proc(b: ^Builder) -> (res: io.Stream) { - return io.Stream{stream_vtable=_builder_stream_vtable, stream_data=b} + return io.Stream{procedure=_builder_stream_proc, data=b} } /* Returns an io.Writer from a Builder diff --git a/core/strings/reader.odin b/core/strings/reader.odin index 081e59b4b..bb49bf917 100644 --- a/core/strings/reader.odin +++ b/core/strings/reader.odin @@ -35,8 +35,8 @@ Returns: - s: An io.Stream for the given Reader */ reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) { - s.stream_data = r - s.stream_vtable = &_reader_vtable + s.data = r + s.procedure = _reader_proc return } /* @@ -294,41 +294,21 @@ This VTable is used by the Reader struct to provide its functionality as an `io.Stream`. */ @(private) -_reader_vtable := io.Stream_VTable{ - impl_size = proc(s: io.Stream) -> i64 { - r := (^Reader)(s.stream_data) - return reader_size(r) - }, - impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) { - r := (^Reader)(s.stream_data) - return reader_read(r, p) - }, - impl_read_at = proc(s: io.Stream, p: []byte, off: i64) -> (n: int, err: io.Error) { - r := (^Reader)(s.stream_data) - return reader_read_at(r, p, off) - }, - impl_read_byte = proc(s: io.Stream) -> (byte, io.Error) { - r := (^Reader)(s.stream_data) - return reader_read_byte(r) - }, - impl_unread_byte = proc(s: io.Stream) -> io.Error { - r := (^Reader)(s.stream_data) - return reader_unread_byte(r) - }, - impl_read_rune = proc(s: io.Stream) -> (ch: rune, size: int, err: io.Error) { - r := (^Reader)(s.stream_data) - return reader_read_rune(r) - }, - impl_unread_rune = proc(s: io.Stream) -> io.Error { - r := (^Reader)(s.stream_data) - return reader_unread_rune(r) - }, - impl_seek = proc(s: io.Stream, offset: i64, whence: io.Seek_From) -> (i64, io.Error) { - r := (^Reader)(s.stream_data) - return reader_seek(r, offset, whence) - }, - impl_write_to = proc(s: io.Stream, w: io.Writer) -> (n: i64, err: io.Error) { - r := (^Reader)(s.stream_data) - return reader_write_to(r, w) - }, +_reader_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) { + r := (^Reader)(stream_data) + #partial switch mode { + case .Size: + n = reader_size(r) + return + case .Read: + return io._i64_err(reader_read(r, p)) + case .Read_At: + return io._i64_err(reader_read_at(r, p, offset)) + case .Seek: + n, err = reader_seek(r, offset, whence) + return + case .Query: + return io.query_utility({.Size, .Read, .Read_At, .Seek, .Query}) + } + return 0, .Empty } diff --git a/core/strings/strings.odin b/core/strings/strings.odin index 6daa5f9c9..66a75f96a 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -1194,7 +1194,7 @@ Output: split_lines :: proc(s: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { sep :: "\n" lines := _split(s, sep, 0, -1, allocator) or_return - for line in &lines { + for &line in lines { line = _trim_cr(line) } return lines, nil @@ -1234,7 +1234,7 @@ Output: split_lines_n :: proc(s: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { sep :: "\n" lines := _split(s, sep, 0, n, allocator) or_return - for line in &lines { + for &line in lines { line = _trim_cr(line) } return lines, nil @@ -1273,7 +1273,7 @@ Output: split_lines_after :: proc(s: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { sep :: "\n" lines := _split(s, sep, len(sep), -1, allocator) or_return - for line in &lines { + for &line in lines { line = _trim_cr(line) } return lines, nil @@ -1314,7 +1314,7 @@ Output: split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { sep :: "\n" lines := _split(s, sep, len(sep), n, allocator) or_return - for line in &lines { + for &line in lines { line = _trim_cr(line) } return lines, nil diff --git a/core/sync/primitives.odin b/core/sync/primitives.odin index b8bcfad70..5e71f6336 100644 --- a/core/sync/primitives.odin +++ b/core/sync/primitives.odin @@ -7,10 +7,21 @@ current_thread_id :: proc "contextless" () -> int { return _current_thread_id() } -// A Mutex is a mutual exclusion lock -// The zero value for a Mutex is an unlocked mutex +// A Mutex is a [[mutual exclusion lock; https://en.wikipedia.org/wiki/Mutual_exclusion]] +// It can be used to prevent more than one thread from executing the same piece of code, +// and thus prevent access to same piece of memory by multiple threads, at the same time. // -// A Mutex must not be copied after first use +// A Mutex's zero value represents an initial, *unlocked* state. +// +// If another thread tries to take the lock while another thread holds it, it will pause +// until the lock is released. Code or memory that is "surrounded" by a mutex lock is said +// to be "guarded by a mutex". +// +// A Mutex must not be copied after first use (e.g., after locking it the first time). +// This is because, in order to coordinate with other threads, all threads must watch +// the same memory address to know when the lock has been released. Trying to use a +// copy of the lock at a different memory address will result in broken and unsafe +// behavior. For this reason, Mutexes are marked as `#no_copy`. Mutex :: struct #no_copy { impl: _Mutex, } diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index abdcf0b92..3083c084b 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1567,6 +1567,23 @@ MADV_HWPOISON :: 100 // pipe2 flags O_CLOEXEC :: 0o2000000 +// poll events +POLLIN :: 0x0001 +POLLPRI :: 0x0002 +POLLOUT :: 0x0004 +POLLERR :: 0x0008 +POLLHUP :: 0x0010 +POLLNVAL :: 0x0020 +POLLRDNORM :: 0x0040 +POLLRDBAND :: 0x0080 +POLLWRNORM :: 0x0100 +POLLWRBAND :: 0x0200 +POLLMSG :: 0x0400 +POLLREMOVE :: 0x1000 +POLLRDHUP :: 0x2000 +POLLFREE :: 0x4000 +POLL_BUSY_LOOP :: 0x8000 + // perf event data Perf_Sample :: struct #raw_union { period: u64, @@ -2057,6 +2074,23 @@ sys_fcntl :: proc "contextless" (fd: int, cmd: int, arg: int) -> int { return int(intrinsics.syscall(SYS_fcntl, uintptr(fd), uintptr(cmd), uintptr(arg))) } +sys_poll :: proc "contextless" (fds: rawptr, nfds: uint, timeout: int) -> int { + // NOTE: specialcased here because `arm64` does not have `poll` + when ODIN_ARCH == .arm64 { + seconds := i64(timeout / 1_000) + nanoseconds := i64((timeout % 1000) * 1_000_000) + timeout_spec := timespec{seconds, nanoseconds} + + return int(intrinsics.syscall(SYS_ppoll, uintptr(fds), uintptr(nfds), uintptr(&timeout_spec), uintptr(0), uintptr(8))) + } else { + return int(intrinsics.syscall(SYS_poll, uintptr(fds), uintptr(nfds), uintptr(timeout))) + } +} + +sys_ppoll :: proc "contextless" (fds: rawptr, nfds: uint, timeout: rawptr, sigmask: rawptr, sigsetsize: uint) -> int { + return int(intrinsics.syscall(SYS_ppoll, uintptr(fds), uintptr(nfds), uintptr(timeout), uintptr(sigmask), uintptr(sigsetsize))) +} + get_errno :: proc "contextless" (res: int) -> i32 { if res < 0 && res > -4096 { return i32(-res) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index beed3a7e5..fcd9e55ed 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -159,6 +159,11 @@ foreign kernel32 { WaitForSingleObject :: proc(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD --- Sleep :: proc(dwMilliseconds: DWORD) --- GetProcessId :: proc(handle: HANDLE) -> DWORD --- + CopyFileW :: proc( + lpExistingFileName: LPCWSTR, + lpNewFileName: LPCWSTR, + bFailIfExists: BOOL, + ) -> BOOL --- CopyFileExW :: proc( lpExistingFileName: LPCWSTR, lpNewFileName: LPCWSTR, diff --git a/core/sys/windows/ws2_32.odin b/core/sys/windows/ws2_32.odin index 631ef4241..7b9cf1b89 100644 --- a/core/sys/windows/ws2_32.odin +++ b/core/sys/windows/ws2_32.odin @@ -206,4 +206,14 @@ foreign ws2_32 { optval: ^c_char, optlen: ^c_int, ) -> c_int --- + // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ntohl) + ntohl :: proc(netlong: c_ulong) -> c_ulong --- + // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ntohs) + ntohs :: proc(netshort: c_ushort) -> c_ushort --- + // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htonl) + @(deprecated="Use endian specific integers instead, https://odin-lang.org/docs/overview/#basic-types") + htonl :: proc(hostlong: c_ulong) -> c_ulong --- + // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htons) + @(deprecated="Use endian specific integers instead, https://odin-lang.org/docs/overview/#basic-types") + htons :: proc(hostshort: c_ushort) -> c_ushort --- } diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin index 525eae685..17bcfce26 100644 --- a/core/testing/runner_windows.odin +++ b/core/testing/runner_windows.odin @@ -191,7 +191,7 @@ run_internal_test :: proc(t: ^T, it: Internal_Test) { global_exception_handler = win32.AddVectoredExceptionHandler(0, exception_handler_proc) context.assertion_failure_proc = proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! { - errorf(t=global_current_t, format="%s %s", args={prefix, message}, loc=loc) + errorf(global_current_t, "%s %s", prefix, message, loc=loc) intrinsics.trap() } diff --git a/core/testing/testing.odin b/core/testing/testing.odin index 37f9fe4d9..1ba05315c 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -4,6 +4,9 @@ import "core:fmt" import "core:io" import "core:time" import "core:intrinsics" +import "core:reflect" + +_ :: reflect // alias reflect to nothing to force visibility for -vet // IMPORTANT NOTE: Compiler requires this layout Test_Signature :: proc(^T) @@ -46,15 +49,15 @@ errorf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { } fail :: proc(t: ^T, loc := #caller_location) { - error(t=t, args={"FAIL"}, loc=loc) + error(t, "FAIL", loc=loc) t.error_count += 1 } fail_now :: proc(t: ^T, msg := "", loc := #caller_location) { if msg != "" { - error(t=t, args={"FAIL:", msg}, loc=loc) + error(t, "FAIL:", msg, loc=loc) } else { - error(t=t, args={"FAIL"}, loc=loc) + error(t, "FAIL", loc=loc) } t.error_count += 1 if t._fail_now != nil { @@ -84,14 +87,14 @@ cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) { expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bool { if !ok { - error(t=t, args={msg}, loc=loc) + error(t, msg, loc=loc) } return ok } expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) { - ok := value == expected + ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected) if !ok { - errorf(t=t, format="expected %v, got %v", args={expected, value}, loc=loc) + errorf(t, "expected %v, got %v", expected, value, loc=loc) } return ok } @@ -100,4 +103,4 @@ expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> boo set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) { _fail_timeout(t, duration, loc) -}
\ No newline at end of file +} diff --git a/core/text/edit/text_edit.odin b/core/text/edit/text_edit.odin index c49a5d0d1..8520ba674 100644 --- a/core/text/edit/text_edit.odin +++ b/core/text/edit/text_edit.odin @@ -113,15 +113,16 @@ set_text :: proc(s: ^State, text: string) { } -undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) { +undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator_Error { text := string(s.builder.buf[:]) - item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator)) + item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator) or_return) item.selection = s.selection item.len = len(text) #no_bounds_check { runtime.copy(item.text[:len(text)], text) } - append(undo, item) + append(undo, item) or_return + return nil } undo :: proc(s: ^State, undo, redo: ^[dynamic]^Undo_State) { diff --git a/core/text/i18n/i18n.odin b/core/text/i18n/i18n.odin index 9d030db16..8513f30c8 100644 --- a/core/text/i18n/i18n.odin +++ b/core/text/i18n/i18n.odin @@ -170,8 +170,8 @@ destroy :: proc(catalog: ^Translation = ACTIVE, allocator := context.allocator) return } - for section in &catalog.k_v { - for key in &catalog.k_v[section] { + for section in catalog.k_v { + for key in catalog.k_v[section] { delete(catalog.k_v[section][key]) } delete(catalog.k_v[section]) diff --git a/core/text/match/strlib.odin b/core/text/match/strlib.odin index b8c2861fa..654996bc7 100644 --- a/core/text/match/strlib.odin +++ b/core/text/match/strlib.odin @@ -266,6 +266,7 @@ match_balance :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) return INVALID, .Invalid_Pattern_Capture } + schar, ssize := utf8_peek(ms.src[s:]) or_return pchar, psize := utf8_peek(ms.pattern[p:]) or_return @@ -274,9 +275,9 @@ match_balance :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) return INVALID, .OK } - s_begin := s cont := 1 - s := s + ssize + s := s + s += ssize begin := pchar end, _ := utf8_peek(ms.pattern[p + psize:]) or_return diff --git a/core/text/table/table.odin b/core/text/table/table.odin index df93ee44e..8d96cb26f 100644 --- a/core/text/table/table.odin +++ b/core/text/table/table.odin @@ -9,12 +9,10 @@ package text_table import "core:io" -import "core:os" import "core:fmt" import "core:mem" import "core:mem/virtual" import "core:runtime" -import "core:strings" Cell :: struct { text: string, @@ -116,7 +114,7 @@ set_cell_alignment :: proc(tbl: ^Table, row, col: int, alignment: Cell_Alignment format :: proc(tbl: ^Table, _fmt: string, args: ..any, loc := #caller_location) -> string { context.allocator = tbl.format_allocator - return fmt.aprintf(fmt = _fmt, args = args) + return fmt.aprintf(_fmt, ..args) } header :: proc(tbl: ^Table, values: ..any, loc := #caller_location) { diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 820de8ad4..1a4119e5f 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -81,7 +81,7 @@ pool_destroy :: proc(pool: ^Pool) { delete(pool.tasks) delete(pool.tasks_done) - for t in &pool.threads { + for &t in pool.threads { destroy(t) } diff --git a/core/unicode/tools/generate_entity_table.odin b/core/unicode/tools/generate_entity_table.odin index 328ba9091..fb4e4c2a4 100644 --- a/core/unicode/tools/generate_entity_table.odin +++ b/core/unicode/tools/generate_entity_table.odin @@ -221,7 +221,7 @@ named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) { delete(entity_map) delete(names) - for name in &names { + for &name in names { free(&name) } } |