mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 17:34:34 +00:00
Merge branch 'odin-lang:master' into master
This commit is contained in:
3
.github/workflows/nightly.yml
vendored
3
.github/workflows/nightly.yml
vendored
@@ -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
3
.gitignore
vendored
@@ -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/
|
||||
|
||||
20
build.bat
20
build.bat
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
//
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package debug_pe
|
||||
|
||||
import "core:runtime"
|
||||
import "core:io"
|
||||
|
||||
Section_Header32 :: struct {
|
||||
name: [8]u8,
|
||||
virtual_size: u32le,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
444
core/io/io.odin
444
core/io/io.odin
@@ -53,137 +53,106 @@ Error :: enum i32 {
|
||||
Empty = -1,
|
||||
}
|
||||
|
||||
Close_Proc :: proc(using s: Stream) -> Error
|
||||
Flush_Proc :: proc(using s: Stream) -> Error
|
||||
Seek_Proc :: proc(using s: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error)
|
||||
Size_Proc :: proc(using s: Stream) -> i64
|
||||
Read_Proc :: proc(using s: Stream, p: []byte) -> (n: int, err: Error)
|
||||
Read_At_Proc :: proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error)
|
||||
Read_From_Proc :: proc(using s: Stream, r: Reader) -> (n: i64, err: Error)
|
||||
Read_Byte_Proc :: proc(using s: Stream) -> (byte, Error)
|
||||
Read_Rune_Proc :: proc(using s: Stream) -> (ch: rune, size: int, err: Error)
|
||||
Unread_Byte_Proc :: proc(using s: Stream) -> Error
|
||||
Unread_Rune_Proc :: proc(using s: Stream) -> Error
|
||||
Write_Proc :: proc(using s: Stream, p: []byte) -> (n: int, err: Error)
|
||||
Write_At_Proc :: proc(using s: Stream, p: []byte, off: i64) -> (n: int, err: Error)
|
||||
Write_To_Proc :: proc(using s: Stream, w: Writer) -> (n: i64, err: Error)
|
||||
Write_Byte_Proc :: proc(using s: Stream, c: byte) -> Error
|
||||
Write_Rune_Proc :: proc(using s: Stream, r: rune) -> (size: int, err: Error)
|
||||
Destroy_Proc :: proc(using s: Stream) -> Error
|
||||
Stream_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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
513
core/math/cmplx/cmplx.odin
Normal 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))
|
||||
}
|
||||
273
core/math/cmplx/cmplx_invtrig.odin
Normal file
273
core/math/cmplx/cmplx_invtrig.odin
Normal 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
|
||||
}
|
||||
409
core/math/cmplx/cmplx_trig.odin
Normal file
409
core/math/cmplx/cmplx_trig.odin
Normal 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
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
308
core/math/math_sincos.odin
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
24
core/mem/virtual/virtual_bsd.odin
Normal file
24
core/mem/virtual/virtual_bsd.odin
Normal 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() {
|
||||
|
||||
}
|
||||
@@ -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[:])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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:]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 ---
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user