Merge branch 'odin-lang:master' into master

This commit is contained in:
ftphikari
2023-07-25 15:32:18 +03:00
committed by GitHub
170 changed files with 11751 additions and 5071 deletions

View File

@@ -7,6 +7,7 @@ on:
jobs:
build_windows:
if: github.repository == 'odin-lang/Odin'
runs-on: windows-2022
steps:
- uses: actions/checkout@v1
@@ -37,6 +38,7 @@ jobs:
name: windows_artifacts
path: dist
build_ubuntu:
if: github.repository == 'odin-lang/Odin'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
@@ -61,6 +63,7 @@ jobs:
name: ubuntu_artifacts
path: dist
build_macos:
if: github.repository == 'odin-lang/Odin'
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1

3
.gitignore vendored
View File

@@ -270,6 +270,7 @@ bin/
# - Linux/MacOS
odin
!odin/
odin.dSYM
*.bin
demo.bin
@@ -286,4 +287,4 @@ shared/
*.sublime-workspace
examples/bug/
build.sh
!core/debug/
!core/debug/

View File

@@ -3,18 +3,20 @@
setlocal EnableDelayedExpansion
where /Q cl.exe || (
set __VSCMD_ARG_NO_LOGO=1
for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i
if "!VS!" equ "" (
echo ERROR: Visual Studio installation not found
exit /b 1
)
call "!VS!\VC\Auxiliary\Build\vcvarsall.bat" amd64 || exit /b 1
set __VSCMD_ARG_NO_LOGO=1
for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i
if "!VS!" equ "" (
echo ERROR: Visual Studio installation not found
exit /b 1
)
call "!VS!\VC\Auxiliary\Build\vcvarsall.bat" amd64 || exit /b 1
)
if "%VSCMD_ARG_TGT_ARCH%" neq "x64" (
echo ERROR: please run this from MSVC x64 native tools command prompt, 32-bit target is not supported!
exit /b 1
if "%ODIN_IGNORE_MSVC_CHECK%" == "" (
echo ERROR: please run this from MSVC x64 native tools command prompt, 32-bit target is not supported!
exit /b 1
)
)
for /f "usebackq tokens=1,2 delims=,=- " %%i in (`wmic os get LocalDateTime /value`) do @if %%i==LocalDateTime (

View File

@@ -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
}

View File

@@ -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
//

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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}

View File

@@ -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 {

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -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])
}

View File

@@ -1,8 +1,5 @@
package debug_pe
import "core:runtime"
import "core:io"
Section_Header32 :: struct {
name: [8]u8,
virtual_size: u32le,

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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) }

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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_Mode :: enum {
Close,
Flush,
Read,
Read_At,
Write,
Write_At,
Seek,
Size,
Destroy,
Query, // query what modes are available
}
Stream_Mode_Set :: distinct bit_set[Stream_Mode; i64]
Stream_Proc :: #type proc(stream_data: rawptr, mode: Stream_Mode, p: []byte, offset: i64, whence: Seek_From) -> (n: i64, err: Error)
Stream :: struct {
using stream_vtable: ^Stream_VTable,
stream_data: rawptr,
}
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,
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,
impl_unread_byte: Unread_Byte_Proc,
impl_unread_rune: Unread_Rune_Proc,
impl_destroy: Destroy_Proc,
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 :: Stream
Read_Closer :: Stream
Read_Write_Closer :: Stream
Read_Write_Seeker :: 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}
Write_Closer :: Stream
Write_Seeker :: Stream
Write_Flusher :: Stream
Write_Flush_Closer :: 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}
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 .Empty
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
}
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
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
}
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
}
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

View File

@@ -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)
}
return 0, .EOF
},
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
}
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
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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,
)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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)
}
}

513
core/math/cmplx/cmplx.odin Normal file
View File

@@ -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))
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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.

View File

@@ -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

View File

@@ -3,44 +3,110 @@ 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)

308
core/math/math_sincos.odin Normal file
View File

@@ -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
}

View File

@@ -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

View File

@@ -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,

View File

@@ -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() {
}

View File

@@ -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[:])
}
}

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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,

View File

@@ -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,54 +66,68 @@ 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
}
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 :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
return _read(f, p)
if f != nil {
return io.read(f.impl.stream, p)
}
return 0, .Invalid_File
}
read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
return _read_at(f, p, offset)
}
read_from :: proc(f: ^File, r: io.Reader) -> (n: i64, err: Error) {
return _read_from(f, r)
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)
}
sync :: proc(f: ^File) -> Error {
return _sync(f)
if f != nil {
return io.size(f.impl.stream)
}
return 0, .Invalid_File
}
flush :: proc(f: ^File) -> Error {
return _flush(f)
if f != nil {
return io.flush(f.impl.stream)
}
return nil
}
sync :: proc(f: ^File) -> Error {
return _sync(f)
}
truncate :: proc(f: ^File, size: i64) -> Error {

View File

@@ -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
}

View File

@@ -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)
},
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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())
}

View File

@@ -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
}
}
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
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -35,4 +35,52 @@ nil_allocator :: proc() -> Allocator {
when ODIN_OS == .Freestanding {
default_allocator_proc :: nil_allocator_proc
default_allocator :: nil_allocator
}
}
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,
}
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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))

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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:]
}

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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,
}

View File

@@ -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)

View File

@@ -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,

View File

@@ -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 ---
}

View File

@@ -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()
}

View File

@@ -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)
}
}

View File

@@ -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) {

View File

@@ -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])

View File

@@ -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

View File

@@ -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) {

Some files were not shown because too many files have changed in this diff Show More