mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-06 19:51:38 -07:00
Compare commits
288 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 830c194da5 | |||
| 1830c1e57c | |||
| e5735af6d6 | |||
| a6b0ae71b2 | |||
| 3365baee8f | |||
| cc88dd0b71 | |||
| f050bfe872 | |||
| ab71acc3a5 | |||
| 0a85d1af6b | |||
| 68adadb01a | |||
| d56f458d11 | |||
| a65eadee63 | |||
| 16dfae62bc | |||
| fe680a8b1f | |||
| 54fe9f3eb1 | |||
| cbc6c2666b | |||
| a4d0ac1802 | |||
| 0dc29a7208 | |||
| a9321bc73f | |||
| e3f0ab7c3d | |||
| 5643ea1ba2 | |||
| 3b6523fbd9 | |||
| ffc4f01470 | |||
| e326f41d16 | |||
| 1d0ac72e4a | |||
| b216e44870 | |||
| 7d39b26cf4 | |||
| 884d5fed9f | |||
| ec84188597 | |||
| 85ac95f81b | |||
| 042550cf87 | |||
| b3ebff715a | |||
| 1ee60663bb | |||
| 59da98d3f0 | |||
| 2d41a42f61 | |||
| e1e4a916a5 | |||
| 71f94bff76 | |||
| c7d6467cfa | |||
| 79a3c0b36c | |||
| 966249c10a | |||
| acc010cba5 | |||
| 89f4e7a8db | |||
| 55f4eabecd | |||
| d0fc9aa069 | |||
| 8be9b5082c | |||
| 708907df31 | |||
| 70586b1cf8 | |||
| 877a78d6ba | |||
| 3928614326 | |||
| 5e5f5bfa8d | |||
| 3a1a7b40f9 | |||
| 835d7dcab2 | |||
| 28816dc491 | |||
| ccdc3438be | |||
| 60711dd355 | |||
| fad3947e26 | |||
| d8e5b2d1a4 | |||
| 2d26ad0226 | |||
| 45d3c6c0d3 | |||
| c6bffd7c35 | |||
| 462d81430c | |||
| d3cada5bd6 | |||
| cdbf831a7a | |||
| 0718f14774 | |||
| a6fe656f21 | |||
| dc5da7933a | |||
| 96fc9138d4 | |||
| 6512a3e5f2 | |||
| 49f2124df0 | |||
| a11d6e696a | |||
| 1705ba8069 | |||
| 8d2c4a78a1 | |||
| 8504ff920b | |||
| e34a9e6185 | |||
| c3c7834246 | |||
| 1ab40d8600 | |||
| 92ce02dab0 | |||
| 8abe9ef507 | |||
| d0e04bf569 | |||
| b92599879a | |||
| 0e91298fd1 | |||
| e515220694 | |||
| a55683d287 | |||
| fa4e95105f | |||
| 1e01085ef7 | |||
| 04a1f869b5 | |||
| e04ba7530d | |||
| ea055f1465 | |||
| 3b2c867817 | |||
| 3de23eb0bf | |||
| 5de3b07e2b | |||
| c0ca4d4635 | |||
| efe4b71bae | |||
| bc37bd5429 | |||
| 5f20e04259 | |||
| 9bef5ec01a | |||
| cdf873542b | |||
| 4742690dec | |||
| 3a16f1e854 | |||
| 877400dd12 | |||
| a4e3201113 | |||
| a99cc2fd70 | |||
| 5fe4c33d0e | |||
| 4d9d38cc28 | |||
| 5b71ffd4f9 | |||
| c2ca24a486 | |||
| e5aff6fd6d | |||
| 3eb8aa8268 | |||
| 6d1c32eb77 | |||
| ba776a3c9f | |||
| cd7e260f4e | |||
| ba67e474d3 | |||
| b92a8c513e | |||
| 13572aeef0 | |||
| 5081ea1a0c | |||
| e9e7ce2606 | |||
| 915dcb0c28 | |||
| 8236c6d4b7 | |||
| 555fe37ad8 | |||
| 881f667558 | |||
| 0a99595efe | |||
| 268491b224 | |||
| 49ea9ed722 | |||
| d7108416c9 | |||
| b136630856 | |||
| fa6f31186a | |||
| b027b1d60f | |||
| 7ed1d931cb | |||
| 2570296b01 | |||
| f0a4526250 | |||
| c39332c7e7 | |||
| 3f4b6b22dc | |||
| e0549df03e | |||
| e46662a546 | |||
| 360a74e2fe | |||
| 597c4591bc | |||
| 80833ed703 | |||
| 106302189c | |||
| 05c5f98e8e | |||
| d556fa2cd8 | |||
| 9bd7f023b2 | |||
| 398109ac84 | |||
| 12b870ba66 | |||
| 6202fb8373 | |||
| ced818ad54 | |||
| ccbb6df749 | |||
| 6eb505a677 | |||
| 619783ca1b | |||
| 642aa0bc4b | |||
| 45b3067068 | |||
| b7858a66b9 | |||
| 4e203feaf4 | |||
| a513b47780 | |||
| 547a2831c7 | |||
| 5c52ffe24e | |||
| a5763d6fee | |||
| 95482c554d | |||
| 10758710d4 | |||
| 86cf9383ea | |||
| 307977d4cf | |||
| 1beff539d7 | |||
| df578d6ec5 | |||
| 6aae381e83 | |||
| 7ee9051a56 | |||
| eb11edabe0 | |||
| c067b90403 | |||
| 5b6770f3d2 | |||
| 718b80ba39 | |||
| 4d052d5119 | |||
| 7e4c643401 | |||
| e920338f21 | |||
| af2048570c | |||
| 1ee4f849cb | |||
| 703393fc63 | |||
| 81420ab246 | |||
| c94d19718b | |||
| e25c72ecdd | |||
| 780b81a59f | |||
| 9f1dda701d | |||
| e597a8d72e | |||
| de9a4b5164 | |||
| 319aca3101 | |||
| 9dc2c01aaa | |||
| 6164672421 | |||
| 61906613b0 | |||
| 3b48fa8e7d | |||
| 324b7d65e7 | |||
| 373a60b9ef | |||
| 2ef22e86e0 | |||
| 830f4f540f | |||
| 56ff5496bc | |||
| 20fbece14c | |||
| 9fbfd86cde | |||
| 7547bc66cf | |||
| 18a9fa7355 | |||
| b32af841c5 | |||
| 66b4252931 | |||
| 2c95eaa418 | |||
| 7382f52dc9 | |||
| 49dd299999 | |||
| e391b05513 | |||
| 2de62910fc | |||
| fc77b5b4ac | |||
| a83d916fad | |||
| e71a641379 | |||
| e2eca45188 | |||
| 4d78540658 | |||
| b83c3f265b | |||
| 30f5a3bb93 | |||
| 2e1e1e6034 | |||
| 991479fbf9 | |||
| 5660f98cc3 | |||
| 5bf0f9d630 | |||
| 15b72119eb | |||
| dc30e7a200 | |||
| db2293144a | |||
| 5016f45429 | |||
| 9fa4aa40b7 | |||
| 52f60c706a | |||
| fff4ead96a | |||
| 3574341b6b | |||
| cbabc80d92 | |||
| f4cf88c2ca | |||
| 6db95b554f | |||
| 105de7705a | |||
| 584dffea14 | |||
| 41b6d215bb | |||
| 9274f29ca9 | |||
| 08c87e57f8 | |||
| b21cdd5037 | |||
| 63ab8b2418 | |||
| cb7a343caf | |||
| 40542e6e26 | |||
| 9da05dd4cb | |||
| ae9da0abfb | |||
| d3ea334e7a | |||
| d76132a3fb | |||
| 223c473cf6 | |||
| fd57cfa1ae | |||
| f23bd2dc27 | |||
| 69062ba3ab | |||
| e75563cb32 | |||
| d63885a495 | |||
| f28a34fa99 | |||
| a1e8de4e00 | |||
| d247ba4751 | |||
| 27b7dc336a | |||
| 60a7c68aa6 | |||
| 78c103e62c | |||
| ffec1c77f2 | |||
| 5357181484 | |||
| 33ddb3ad4d | |||
| 1cd453db14 | |||
| 3b5932699c | |||
| bada81159d | |||
| 652da98c70 | |||
| e14e2c3b4d | |||
| f96a897821 | |||
| b74ae77745 | |||
| 564226be02 | |||
| f6c45fc68a | |||
| 35ba5771a5 | |||
| b2461f7192 | |||
| 60a54f404b | |||
| 921f261377 | |||
| d70a555c1c | |||
| 4c339360e9 | |||
| 731dad480d | |||
| a0f2357cb3 | |||
| e86ac75e9c | |||
| f51de2e488 | |||
| 5efefdcf16 | |||
| cabb2bb992 | |||
| d560f6c920 | |||
| 21432ba96e | |||
| c341597657 | |||
| 2a1420d4e7 | |||
| 28d88f6af4 | |||
| c4d2d287fc | |||
| 6a85546b76 | |||
| 2e92d0c821 | |||
| a499a3aa5e | |||
| 23ab3c4713 | |||
| da300aa9c3 | |||
| e225158a6f | |||
| 2ce55783d2 | |||
| 4c06b44315 | |||
| 678b58e0b1 |
@@ -12,7 +12,7 @@ endif
|
||||
all: debug demo
|
||||
|
||||
demo:
|
||||
./odin run examples/demo.odin
|
||||
./odin run examples/demo
|
||||
|
||||
debug:
|
||||
$(CC) src/main.cpp $(DISABLED_WARNINGS) $(CFLAGS) -g $(LDFLAGS) -o odin
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
<img src="misc/logo-slim.png" alt="Odin logo" height="74">
|
||||
<p align="center">
|
||||
<img src="misc/logo-slim.png" alt="Odin logo" height="120">
|
||||
<br/>
|
||||
A fast, concise, readable, pragmatic and open sourced programming language.
|
||||
<br/>
|
||||
<br/>
|
||||
<a href="https://github.com/odin-lang/odin/releases/latest">
|
||||
<img src="https://img.shields.io/github/release/odin-lang/odin.svg">
|
||||
</a>
|
||||
<a href="https://github.com/odin-lang/odin/releases/latest">
|
||||
<img src="https://img.shields.io/badge/platforms-Windows%20|%20Linux%20|%20macOS-green.svg">
|
||||
</a>
|
||||
<a href="https://github.com/odin-lang/odin/blob/master/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/odin-lang/odin.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# The Odin Programming Language
|
||||
|
||||
@@ -12,7 +27,9 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
|
||||
Website: [https://odin.handmade.network/](https://odin.handmade.network/)
|
||||
|
||||
```go
|
||||
import "core:fmt.odin"
|
||||
package main
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
main :: proc() {
|
||||
program := "+ + * 😃 - /";
|
||||
@@ -46,12 +63,18 @@ main :: proc() {
|
||||
* [when, for & procedure overloading](https://www.youtube.com/watch?v=OzeOekzyZK8)
|
||||
* [Context Types, Unexported Entities, Labelled Branches](https://www.youtube.com/watch?v=CkHVwT1Qk-g)
|
||||
* [Bit Fields, i128 & u128, Syntax Changes](https://www.youtube.com/watch?v=NlTutcLyF64)
|
||||
* [Default and Named Arguments; Explicit Parametric Polymorphism](https://www.youtube.com/watch?v=-XQZE6S6zUU)
|
||||
* [Loadsachanges](https://www.youtube.com/watch?v=ar0vFMoMtrI)
|
||||
|
||||
## Documentation
|
||||
* [Tutorial](https://odin.handmade.network/wiki/3329-odin_tutorial)
|
||||
* [Frequently Asked Questions](https://github.com/odin-lang/Odin/wiki/Frequently-Asked-Questions-(FAQ))
|
||||
|
||||
## Requirements to build and run
|
||||
|
||||
- Windows
|
||||
* x86-64
|
||||
* MSVC 2015 installed (C++11 support)
|
||||
* MSVC 2010 installed (C++11 support)
|
||||
* [LLVM binaries](https://github.com/gingerBill/Odin/releases/tag/llvm-4.0-windows) for `opt.exe` and `llc.exe`
|
||||
* Requires MSVC's link.exe as the linker
|
||||
* run `vcvarsall.bat` to setup the path
|
||||
@@ -71,24 +94,3 @@ main :: proc() {
|
||||
|
||||
* This is still highly in development and the language's design is quite volatile.
|
||||
* Syntax is not fixed.
|
||||
|
||||
## Roadmap
|
||||
|
||||
Not in any particular order and not be implemented
|
||||
|
||||
* Compile Time Execution (CTE)
|
||||
- More metaprogramming madness
|
||||
- Compiler as a library
|
||||
- AST inspection and modification
|
||||
* CTE-based build system
|
||||
* Replace LLVM backend with my own custom backend
|
||||
* Improve SSA design to accommodate for lowering to a "bytecode"
|
||||
* SSA optimizations
|
||||
* Documentation Generator for "Entities"
|
||||
* Multiple Architecture support
|
||||
* Debug Information
|
||||
- pdb format too
|
||||
* Command Line Tooling
|
||||
* Compiler Internals:
|
||||
- Big numbers library
|
||||
- Multithreading for performance increase
|
||||
|
||||
@@ -4,28 +4,26 @@
|
||||
set exe_name=odin.exe
|
||||
|
||||
:: Debug = 0, Release = 1
|
||||
set release_mode=0
|
||||
set release_mode=1
|
||||
set compiler_flags= -nologo -Oi -TP -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
set compiler_flags=%compiler_flags% -Od -MDd -Z7
|
||||
rem -DDISPLAY_TIMING
|
||||
) else ( rem Release
|
||||
set compiler_flags=%compiler_flags% -O2 -MT -Z7
|
||||
set compiler_flags=%compiler_flags% -O2 -MT -Z7 -DNO_ARRAY_BOUNDS_CHECK
|
||||
)
|
||||
|
||||
set compiler_warnings= ^
|
||||
-W4 -WX ^
|
||||
-wd4100 -wd4101 -wd4127 -wd4189 ^
|
||||
-wd4201 -wd4204 -wd4244 ^
|
||||
-wd4306 ^
|
||||
-wd4201 -wd4204 ^
|
||||
-wd4456 -wd4457 -wd4480 ^
|
||||
-wd4505 -wd4512 -wd4550
|
||||
-wd4512
|
||||
|
||||
set compiler_includes=
|
||||
set libs= ^
|
||||
kernel32.lib
|
||||
rem "src\dyncall\lib\*.lib"
|
||||
|
||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||
|
||||
@@ -44,8 +42,7 @@ del *.ilk > NUL 2> NUL
|
||||
|
||||
cl %compiler_settings% "src\main.cpp" ^
|
||||
/link %linker_settings% -OUT:%exe_name% ^
|
||||
&& odin run examples/demo.odin
|
||||
rem && odin docs core/fmt.odin
|
||||
&& odin run examples/demo/demo.odin
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
|
||||
@@ -25,4 +25,4 @@ if [[ "$(uname)" == "Darwin" ]]; then
|
||||
other_args="${other_args} -liconv"
|
||||
fi
|
||||
|
||||
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin && ./odin run examples/demo.odin
|
||||
${compiler} src/main.cpp ${warnings_to_disable} ${libraries} ${other_args} -o odin && ./odin run examples/demo/demo.odin
|
||||
|
||||
-1301
File diff suppressed because it is too large
Load Diff
@@ -1,112 +0,0 @@
|
||||
#shared_global_scope
|
||||
|
||||
/*
|
||||
@(link_name="__multi3")
|
||||
__multi3 :: proc "c" (a, b: u128) -> u128 {
|
||||
bits_in_dword_2 :: size_of(i64) * 4;
|
||||
lower_mask :: u128(~u64(0) >> bits_in_dword_2);
|
||||
|
||||
|
||||
when ODIN_ENDIAN == "big" {
|
||||
TWords :: struct #raw_union {
|
||||
all: u128,
|
||||
using _: struct {lo, hi: u64},
|
||||
};
|
||||
} else {
|
||||
TWords :: struct #raw_union {
|
||||
all: u128,
|
||||
using _: struct {hi, lo: u64},
|
||||
};
|
||||
}
|
||||
|
||||
r: TWords;
|
||||
t: u64;
|
||||
|
||||
r.lo = u64(a & lower_mask) * u64(b & lower_mask);
|
||||
t = r.lo >> bits_in_dword_2;
|
||||
r.lo &= u64(lower_mask);
|
||||
t += u64(a >> bits_in_dword_2) * u64(b & lower_mask);
|
||||
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
|
||||
r.hi = t >> bits_in_dword_2;
|
||||
t = r.lo >> bits_in_dword_2;
|
||||
r.lo &= u64(lower_mask);
|
||||
t += u64(b >> bits_in_dword_2) * u64(a & lower_mask);
|
||||
r.lo += u64(t & u64(lower_mask)) << bits_in_dword_2;
|
||||
r.hi += t >> bits_in_dword_2;
|
||||
r.hi += u64(a >> bits_in_dword_2) * u64(b >> bits_in_dword_2);
|
||||
return r.all;
|
||||
}
|
||||
|
||||
@(link_name="__umodti3")
|
||||
__u128_mod :: proc "c" (a, b: u128) -> u128 {
|
||||
r: u128;
|
||||
__u128_quo_mod(a, b, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@(link_name="__udivti3")
|
||||
__u128_quo :: proc "c" (a, b: u128) -> u128 {
|
||||
return __u128_quo_mod(a, b, nil);
|
||||
}
|
||||
|
||||
@(link_name="__modti3")
|
||||
__i128_mod :: proc "c" (a, b: i128) -> i128 {
|
||||
r: i128;
|
||||
__i128_quo_mod(a, b, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@(link_name="__divti3")
|
||||
__i128_quo :: proc "c" (a, b: i128) -> i128 {
|
||||
return __i128_quo_mod(a, b, nil);
|
||||
}
|
||||
|
||||
@(link_name="__divmodti4")
|
||||
__i128_quo_mod :: proc "c" (a, b: i128, rem: ^i128) -> (quo: i128) {
|
||||
s: i128;
|
||||
s = b >> 127;
|
||||
b = (b~s) - s;
|
||||
s = a >> 127;
|
||||
b = (a~s) - s;
|
||||
|
||||
uquo: u128;
|
||||
urem := __u128_quo_mod(transmute(u128)a, transmute(u128)b, &uquo);
|
||||
iquo := transmute(i128)uquo;
|
||||
irem := transmute(i128)urem;
|
||||
|
||||
iquo = (iquo~s) - s;
|
||||
irem = (irem~s) - s;
|
||||
if rem != nil do rem^ = irem;
|
||||
return iquo;
|
||||
}
|
||||
|
||||
|
||||
@(link_name="__udivmodti4")
|
||||
__u128_quo_mod :: proc "c" (a, b: u128, rem: ^u128) -> (quo: u128) {
|
||||
alo := u64(a);
|
||||
blo := u64(b);
|
||||
if b == 0 {
|
||||
if rem != nil do rem^ = 0;
|
||||
return u128(alo/blo);
|
||||
}
|
||||
|
||||
r, d, x, q: u128 = a, b, 1, 0;
|
||||
|
||||
for r >= d && (d>>127)&1 == 0 {
|
||||
x <<= 1;
|
||||
d <<= 1;
|
||||
}
|
||||
|
||||
for x != 0 {
|
||||
if r >= d {
|
||||
r -= d;
|
||||
q |= x;
|
||||
}
|
||||
x >>= 1;
|
||||
d >>= 1;
|
||||
}
|
||||
|
||||
if rem != nil do rem^ = r;
|
||||
return q;
|
||||
}
|
||||
*/
|
||||
@@ -1,10 +1,9 @@
|
||||
package atomics
|
||||
|
||||
// TODO(bill): Use assembly instead here to implement atomics
|
||||
// Inline vs external file?
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
import win32 "core:sys/windows.odin"
|
||||
}
|
||||
_ :: compile_assert(ODIN_ARCH == "amd64"); // TODO(bill): x86 version
|
||||
import "core:sys/win32"
|
||||
|
||||
|
||||
yield_thread :: proc() { win32.mm_pause(); }
|
||||
-244
@@ -1,244 +0,0 @@
|
||||
U8_MIN :: u8(0);
|
||||
U16_MIN :: u16(0);
|
||||
U32_MIN :: u32(0);
|
||||
U64_MIN :: u64(0);
|
||||
|
||||
U8_MAX :: ~u8(0);
|
||||
U16_MAX :: ~u16(0);
|
||||
U32_MAX :: ~u32(0);
|
||||
U64_MAX :: ~u64(0);
|
||||
|
||||
I8_MIN :: i8( ~u8(0) >> 1);
|
||||
I16_MIN :: i16( ~u16(0) >> 1);
|
||||
I32_MIN :: i32( ~u32(0) >> 1);
|
||||
I64_MIN :: i64( ~u64(0) >> 1);
|
||||
|
||||
I8_MAX :: -I8_MIN - 1;
|
||||
I16_MAX :: -I16_MIN - 1;
|
||||
I32_MAX :: -I32_MIN - 1;
|
||||
I64_MAX :: -I64_MIN - 1;
|
||||
|
||||
foreign __llvm_core {
|
||||
@(link_name="llvm.ctpop.i8") __llvm_ctpop8 :: proc(u8) -> u8 ---;
|
||||
@(link_name="llvm.ctpop.i16") __llvm_ctpop16 :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.ctpop.i32") __llvm_ctpop32 :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.ctpop.i64") __llvm_ctpop64 :: proc(u64) -> u64 ---;
|
||||
|
||||
@(link_name="llvm.ctlz.i8") __llvm_ctlz8 :: proc(u8, bool) -> u8 ---;
|
||||
@(link_name="llvm.ctlz.i16") __llvm_ctlz16 :: proc(u16, bool) -> u16 ---;
|
||||
@(link_name="llvm.ctlz.i32") __llvm_ctlz32 :: proc(u32, bool) -> u32 ---;
|
||||
@(link_name="llvm.ctlz.i64") __llvm_ctlz64 :: proc(u64, bool) -> u64 ---;
|
||||
|
||||
@(link_name="llvm.cttz.i8") __llvm_cttz8 :: proc(u8, bool) -> u8 ---;
|
||||
@(link_name="llvm.cttz.i16") __llvm_cttz16 :: proc(u16, bool) -> u16 ---;
|
||||
@(link_name="llvm.cttz.i32") __llvm_cttz32 :: proc(u32, bool) -> u32 ---;
|
||||
@(link_name="llvm.cttz.i64") __llvm_cttz64 :: proc(u64, bool) -> u64 ---;
|
||||
|
||||
@(link_name="llvm.bitreverse.i8") __llvm_bitreverse8 :: proc(u8) -> u8 ---;
|
||||
@(link_name="llvm.bitreverse.i16") __llvm_bitreverse16 :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.bitreverse.i32") __llvm_bitreverse32 :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.bitreverse.i64") __llvm_bitreverse64 :: proc(u64) -> u64 ---;
|
||||
|
||||
@(link_name="llvm.bswap.i16") byte_swap16 :: proc(u16) -> u16 ---;
|
||||
@(link_name="llvm.bswap.i32") byte_swap32 :: proc(u32) -> u32 ---;
|
||||
@(link_name="llvm.bswap.i64") byte_swap64 :: proc(u64) -> u64 ---;
|
||||
}
|
||||
|
||||
byte_swap_uint :: proc(i: uint) -> uint {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
return uint(byte_swap32(u32(i)));
|
||||
} else {
|
||||
return uint(byte_swap64(u64(i)));
|
||||
}
|
||||
}
|
||||
|
||||
byte_swap :: proc[byte_swap16, byte_swap32, byte_swap64, byte_swap_uint];
|
||||
|
||||
count_ones8 :: proc(i: u8) -> u8 { return __llvm_ctpop8(i); }
|
||||
count_ones16 :: proc(i: u16) -> u16 { return __llvm_ctpop16(i); }
|
||||
count_ones32 :: proc(i: u32) -> u32 { return __llvm_ctpop32(i); }
|
||||
count_ones64 :: proc(i: u64) -> u64 { return __llvm_ctpop64(i); }
|
||||
|
||||
count_zeros8 :: proc(i: u8) -> u8 { return 8 - count_ones8(i); }
|
||||
count_zeros16 :: proc(i: u16) -> u16 { return 16 - count_ones16(i); }
|
||||
count_zeros32 :: proc(i: u32) -> u32 { return 32 - count_ones32(i); }
|
||||
count_zeros64 :: proc(i: u64) -> u64 { return 64 - count_ones64(i); }
|
||||
|
||||
|
||||
rotate_left8 :: proc(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
|
||||
rotate_left16 :: proc(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
|
||||
rotate_left32 :: proc(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
|
||||
rotate_left64 :: proc(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
|
||||
|
||||
|
||||
rotate_right8 :: proc(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
|
||||
rotate_right16 :: proc(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
|
||||
rotate_right32 :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
|
||||
rotate_right64 :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
|
||||
|
||||
leading_zeros8 :: proc(i: u8) -> u8 { return __llvm_ctlz8(i, false); }
|
||||
leading_zeros16 :: proc(i: u16) -> u16 { return __llvm_ctlz16(i, false); }
|
||||
leading_zeros32 :: proc(i: u32) -> u32 { return __llvm_ctlz32(i, false); }
|
||||
leading_zeros64 :: proc(i: u64) -> u64 { return __llvm_ctlz64(i, false); }
|
||||
|
||||
trailing_zeros8 :: proc(i: u8) -> u8 { return __llvm_cttz8(i, false); }
|
||||
trailing_zeros16 :: proc(i: u16) -> u16 { return __llvm_cttz16(i, false); }
|
||||
trailing_zeros32 :: proc(i: u32) -> u32 { return __llvm_cttz32(i, false); }
|
||||
trailing_zeros64 :: proc(i: u64) -> u64 { return __llvm_cttz64(i, false); }
|
||||
|
||||
|
||||
reverse_bits8 :: proc(i: u8) -> u8 { return __llvm_bitreverse8(i); }
|
||||
reverse_bits16 :: proc(i: u16) -> u16 { return __llvm_bitreverse16(i); }
|
||||
reverse_bits32 :: proc(i: u32) -> u32 { return __llvm_bitreverse32(i); }
|
||||
reverse_bits64 :: proc(i: u64) -> u64 { return __llvm_bitreverse64(i); }
|
||||
|
||||
from_be_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
from_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
from_le_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
from_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
to_be_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
to_be_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
to_le_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
to_le_u16 :: proc(i: u16) -> u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_u32 :: proc(i: u32) -> u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_u64 :: proc(i: u64) -> u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_uint :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
overflowing_add_u8 :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_i8 :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_u16 :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_i16 :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_u32 :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_i32 :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_u64 :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.uadd.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_i64 :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.sadd.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_add_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_add_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_add_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_add_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_add_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_add_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_add :: proc[
|
||||
overflowing_add_u8, overflowing_add_i8,
|
||||
overflowing_add_u16, overflowing_add_i16,
|
||||
overflowing_add_u32, overflowing_add_i32,
|
||||
overflowing_add_u64, overflowing_add_i64,
|
||||
overflowing_add_uint, overflowing_add_int,
|
||||
];
|
||||
|
||||
overflowing_sub_u8 :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_i8 :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_u16 :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_i16 :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_u32 :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_i32 :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_u64 :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.usub.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_i64 :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.ssub.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_sub_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_sub_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_sub_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_sub_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_sub_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_sub_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_sub :: proc[
|
||||
overflowing_sub_u8, overflowing_sub_i8,
|
||||
overflowing_sub_u16, overflowing_sub_i16,
|
||||
overflowing_sub_u32, overflowing_sub_i32,
|
||||
overflowing_sub_u64, overflowing_sub_i64,
|
||||
overflowing_sub_uint, overflowing_sub_int,
|
||||
];
|
||||
|
||||
|
||||
overflowing_mul_u8 :: proc(lhs, rhs: u8) -> (u8, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i8") op :: proc(u8, u8) -> (u8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_i8 :: proc(lhs, rhs: i8) -> (i8, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i8") op :: proc(i8, i8) -> (i8, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_u16 :: proc(lhs, rhs: u16) -> (u16, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i16") op :: proc(u16, u16) -> (u16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_i16 :: proc(lhs, rhs: i16) -> (i16, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i16") op :: proc(i16, i16) -> (i16, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_u32 :: proc(lhs, rhs: u32) -> (u32, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i32") op :: proc(u32, u32) -> (u32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_i32 :: proc(lhs, rhs: i32) -> (i32, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i32") op :: proc(i32, i32) -> (i32, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_u64 :: proc(lhs, rhs: u64) -> (u64, bool) { foreign __llvm_core @(link_name="llvm.umul.with.overflow.i64") op :: proc(u64, u64) -> (u64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_i64 :: proc(lhs, rhs: i64) -> (i64, bool) { foreign __llvm_core @(link_name="llvm.smul.with.overflow.i64") op :: proc(i64, i64) -> (i64, bool) ---; return op(lhs, rhs); }
|
||||
overflowing_mul_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_mul_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_mul_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_mul_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_mul_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_mul_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_mul :: proc[
|
||||
overflowing_mul_u8, overflowing_mul_i8,
|
||||
overflowing_mul_u16, overflowing_mul_i16,
|
||||
overflowing_mul_u32, overflowing_mul_i32,
|
||||
overflowing_mul_u64, overflowing_mul_i64,
|
||||
overflowing_mul_uint, overflowing_mul_int,
|
||||
];
|
||||
|
||||
is_power_of_two_u8 :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i8 :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u16 :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i16 :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u32 :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i32 :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u64 :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i64 :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_uint :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_int :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
|
||||
is_power_of_two :: proc[
|
||||
is_power_of_two_u8, is_power_of_two_i8,
|
||||
is_power_of_two_u16, is_power_of_two_i16,
|
||||
is_power_of_two_u32, is_power_of_two_i32,
|
||||
is_power_of_two_u64, is_power_of_two_i64,
|
||||
is_power_of_two_uint, is_power_of_two_int,
|
||||
]
|
||||
@@ -0,0 +1,253 @@
|
||||
package bits
|
||||
|
||||
import "core:os"
|
||||
|
||||
U8_MIN :: 0;
|
||||
U16_MIN :: 0;
|
||||
U32_MIN :: 0;
|
||||
U64_MIN :: 0;
|
||||
|
||||
U8_MAX :: 1 << 8 - 1;
|
||||
U16_MAX :: 1 << 16 - 1;
|
||||
U32_MAX :: 1 << 32 - 1;
|
||||
U64_MAX :: 1 << 64 - 1;
|
||||
|
||||
I8_MIN :: - 1 << 7;
|
||||
I16_MIN :: - 1 << 15;
|
||||
I32_MIN :: - 1 << 31;
|
||||
I64_MIN :: - 1 << 63;
|
||||
|
||||
I8_MAX :: 1 << 7 - 1;
|
||||
I16_MAX :: 1 << 15 - 1;
|
||||
I32_MAX :: 1 << 31 - 1;
|
||||
I64_MAX :: 1 << 63 - 1;
|
||||
|
||||
foreign {
|
||||
@(link_name="llvm.ctpop.i8") count_ones8 :: proc(i: u8) -> u8 ---
|
||||
@(link_name="llvm.ctpop.i16") count_ones16 :: proc(i: u16) -> u16 ---
|
||||
@(link_name="llvm.ctpop.i32") count_ones32 :: proc(i: u32) -> u32 ---
|
||||
@(link_name="llvm.ctpop.i64") count_ones64 :: proc(i: u64) -> u64 ---
|
||||
|
||||
@(link_name="llvm.ctlz.i8") leading_zeros8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
|
||||
@(link_name="llvm.ctlz.i16") leading_zeros16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
|
||||
@(link_name="llvm.ctlz.i32") leading_zeros32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
|
||||
@(link_name="llvm.ctlz.i64") leading_zeros64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
|
||||
|
||||
@(link_name="llvm.cttz.i8") trailing_zeros8 :: proc(i: u8, is_zero_undef := false) -> u8 ---
|
||||
@(link_name="llvm.cttz.i16") trailing_zeros16 :: proc(i: u16, is_zero_undef := false) -> u16 ---
|
||||
@(link_name="llvm.cttz.i32") trailing_zeros32 :: proc(i: u32, is_zero_undef := false) -> u32 ---
|
||||
@(link_name="llvm.cttz.i64") trailing_zeros64 :: proc(i: u64, is_zero_undef := false) -> u64 ---
|
||||
|
||||
@(link_name="llvm.bitreverse.i8") reverse_bits8 :: proc(i: u8) -> u8 ---
|
||||
@(link_name="llvm.bitreverse.i16") reverse_bits16 :: proc(i: u16) -> u16 ---
|
||||
@(link_name="llvm.bitreverse.i32") reverse_bits32 :: proc(i: u32) -> u32 ---
|
||||
@(link_name="llvm.bitreverse.i64") reverse_bits64 :: proc(i: u64) -> u64 ---
|
||||
|
||||
@(link_name="llvm.bswap.i16") byte_swap_u16 :: proc(u16) -> u16 ---
|
||||
@(link_name="llvm.bswap.i32") byte_swap_u32 :: proc(u32) -> u32 ---
|
||||
@(link_name="llvm.bswap.i64") byte_swap_u64 :: proc(u64) -> u64 ---
|
||||
@(link_name="llvm.bswap.i16") byte_swap_i16 :: proc(i16) -> i16 ---
|
||||
@(link_name="llvm.bswap.i32") byte_swap_i32 :: proc(i32) -> i32 ---
|
||||
@(link_name="llvm.bswap.i64") byte_swap_i64 :: proc(i64) -> i64 ---
|
||||
}
|
||||
|
||||
byte_swap_uint :: proc(i: uint) -> uint {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
return uint(byte_swap_u32(u32(i)));
|
||||
} else {
|
||||
return uint(byte_swap_u64(u64(i)));
|
||||
}
|
||||
}
|
||||
byte_swap_int :: proc(i: int) -> int {
|
||||
when size_of(int) == size_of(i32) {
|
||||
return int(byte_swap_i32(i32(i)));
|
||||
} else {
|
||||
return int(byte_swap_i64(i64(i)));
|
||||
}
|
||||
}
|
||||
|
||||
byte_swap :: proc[
|
||||
byte_swap_u16,
|
||||
byte_swap_u32,
|
||||
byte_swap_u64,
|
||||
byte_swap_i16,
|
||||
byte_swap_i32,
|
||||
byte_swap_i64,
|
||||
byte_swap_uint,
|
||||
byte_swap_int,
|
||||
];
|
||||
|
||||
count_zeros8 :: proc(i: u8) -> u8 { return 8 - count_ones8(i); }
|
||||
count_zeros16 :: proc(i: u16) -> u16 { return 16 - count_ones16(i); }
|
||||
count_zeros32 :: proc(i: u32) -> u32 { return 32 - count_ones32(i); }
|
||||
count_zeros64 :: proc(i: u64) -> u64 { return 64 - count_ones64(i); }
|
||||
|
||||
|
||||
rotate_left8 :: proc(i: u8, s: uint) -> u8 { return (i << s)|(i >> (8*size_of(u8) - s)); }
|
||||
rotate_left16 :: proc(i: u16, s: uint) -> u16 { return (i << s)|(i >> (8*size_of(u16) - s)); }
|
||||
rotate_left32 :: proc(i: u32, s: uint) -> u32 { return (i << s)|(i >> (8*size_of(u32) - s)); }
|
||||
rotate_left64 :: proc(i: u64, s: uint) -> u64 { return (i << s)|(i >> (8*size_of(u64) - s)); }
|
||||
|
||||
|
||||
rotate_right8 :: proc(i: u8, s: uint) -> u8 { return (i >> s)|(i << (8*size_of(u8) - s)); }
|
||||
rotate_right16 :: proc(i: u16, s: uint) -> u16 { return (i >> s)|(i << (8*size_of(u16) - s)); }
|
||||
rotate_right32 :: proc(i: u32, s: uint) -> u32 { return (i >> s)|(i << (8*size_of(u32) - s)); }
|
||||
rotate_right64 :: proc(i: u64, s: uint) -> u64 { return (i >> s)|(i << (8*size_of(u64) - s)); }
|
||||
|
||||
from_be_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
from_be_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
from_be_uint :: proc(i: uint) -> uint { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
from_le_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
from_le_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
from_le_uint :: proc(i: uint) -> uint { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
to_be_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
to_be_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
to_be_uint :: proc(i: uint) -> uint { when os.ENDIAN == "big" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
to_le_u8 :: proc(i: u8) -> u8 { return i; }
|
||||
to_le_u16 :: proc(i: u16) -> u16 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_u32 :: proc(i: u32) -> u32 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_u64 :: proc(i: u64) -> u64 { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
to_le_uint :: proc(i: uint) -> uint { when os.ENDIAN == "little" { return i; } else { return byte_swap(i); } }
|
||||
|
||||
|
||||
foreign {
|
||||
@(link_name="llvm.uadd.with.overflow.i8") overflowing_add_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
|
||||
@(link_name="llvm.sadd.with.overflow.i8") overflowing_add_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
|
||||
@(link_name="llvm.uadd.with.overflow.i16") overflowing_add_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
|
||||
@(link_name="llvm.sadd.with.overflow.i16") overflowing_add_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
|
||||
@(link_name="llvm.uadd.with.overflow.i32") overflowing_add_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
|
||||
@(link_name="llvm.sadd.with.overflow.i32") overflowing_add_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
|
||||
@(link_name="llvm.uadd.with.overflow.i64") overflowing_add_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
|
||||
@(link_name="llvm.sadd.with.overflow.i64") overflowing_add_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
|
||||
}
|
||||
|
||||
overflowing_add_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_add_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_add_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_add_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_add_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_add_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_add :: proc[
|
||||
overflowing_add_u8, overflowing_add_i8,
|
||||
overflowing_add_u16, overflowing_add_i16,
|
||||
overflowing_add_u32, overflowing_add_i32,
|
||||
overflowing_add_u64, overflowing_add_i64,
|
||||
overflowing_add_uint, overflowing_add_int,
|
||||
];
|
||||
|
||||
foreign {
|
||||
@(link_name="llvm.usub.with.overflow.i8") overflowing_sub_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
|
||||
@(link_name="llvm.ssub.with.overflow.i8") overflowing_sub_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
|
||||
@(link_name="llvm.usub.with.overflow.i16") overflowing_sub_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
|
||||
@(link_name="llvm.ssub.with.overflow.i16") overflowing_sub_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
|
||||
@(link_name="llvm.usub.with.overflow.i32") overflowing_sub_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
|
||||
@(link_name="llvm.ssub.with.overflow.i32") overflowing_sub_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
|
||||
@(link_name="llvm.usub.with.overflow.i64") overflowing_sub_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
|
||||
@(link_name="llvm.ssub.with.overflow.i64") overflowing_sub_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
|
||||
}
|
||||
overflowing_sub_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_sub_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_sub_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_sub_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_sub_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_sub_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_sub :: proc[
|
||||
overflowing_sub_u8, overflowing_sub_i8,
|
||||
overflowing_sub_u16, overflowing_sub_i16,
|
||||
overflowing_sub_u32, overflowing_sub_i32,
|
||||
overflowing_sub_u64, overflowing_sub_i64,
|
||||
overflowing_sub_uint, overflowing_sub_int,
|
||||
];
|
||||
|
||||
|
||||
foreign {
|
||||
@(link_name="llvm.umul.with.overflow.i8") overflowing_mul_u8 :: proc(lhs, rhs: u8) -> (u8, bool) ---
|
||||
@(link_name="llvm.smul.with.overflow.i8") overflowing_mul_i8 :: proc(lhs, rhs: i8) -> (i8, bool) ---
|
||||
@(link_name="llvm.umul.with.overflow.i16") overflowing_mul_u16 :: proc(lhs, rhs: u16) -> (u16, bool) ---
|
||||
@(link_name="llvm.smul.with.overflow.i16") overflowing_mul_i16 :: proc(lhs, rhs: i16) -> (i16, bool) ---
|
||||
@(link_name="llvm.umul.with.overflow.i32") overflowing_mul_u32 :: proc(lhs, rhs: u32) -> (u32, bool) ---
|
||||
@(link_name="llvm.smul.with.overflow.i32") overflowing_mul_i32 :: proc(lhs, rhs: i32) -> (i32, bool) ---
|
||||
@(link_name="llvm.umul.with.overflow.i64") overflowing_mul_u64 :: proc(lhs, rhs: u64) -> (u64, bool) ---
|
||||
@(link_name="llvm.smul.with.overflow.i64") overflowing_mul_i64 :: proc(lhs, rhs: i64) -> (i64, bool) ---
|
||||
}
|
||||
overflowing_mul_uint :: proc(lhs, rhs: uint) -> (uint, bool) {
|
||||
when size_of(uint) == size_of(u32) {
|
||||
x, ok := overflowing_mul_u32(u32(lhs), u32(rhs));
|
||||
return uint(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_mul_u64(u64(lhs), u64(rhs));
|
||||
return uint(x), ok;
|
||||
}
|
||||
}
|
||||
overflowing_mul_int :: proc(lhs, rhs: int) -> (int, bool) {
|
||||
when size_of(int) == size_of(i32) {
|
||||
x, ok := overflowing_mul_i32(i32(lhs), i32(rhs));
|
||||
return int(x), ok;
|
||||
} else {
|
||||
x, ok := overflowing_mul_i64(i64(lhs), i64(rhs));
|
||||
return int(x), ok;
|
||||
}
|
||||
}
|
||||
|
||||
overflowing_mul :: proc[
|
||||
overflowing_mul_u8, overflowing_mul_i8,
|
||||
overflowing_mul_u16, overflowing_mul_i16,
|
||||
overflowing_mul_u32, overflowing_mul_i32,
|
||||
overflowing_mul_u64, overflowing_mul_i64,
|
||||
overflowing_mul_uint, overflowing_mul_int,
|
||||
];
|
||||
|
||||
is_power_of_two_u8 :: proc(i: u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i8 :: proc(i: i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u16 :: proc(i: u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i16 :: proc(i: i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u32 :: proc(i: u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i32 :: proc(i: i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_u64 :: proc(i: u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_i64 :: proc(i: i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_uint :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
is_power_of_two_int :: proc(i: int) -> bool { return i > 0 && (i & (i-1)) == 0; }
|
||||
|
||||
is_power_of_two :: proc[
|
||||
is_power_of_two_u8, is_power_of_two_i8,
|
||||
is_power_of_two_u16, is_power_of_two_i16,
|
||||
is_power_of_two_u32, is_power_of_two_i32,
|
||||
is_power_of_two_u64, is_power_of_two_i64,
|
||||
is_power_of_two_uint, is_power_of_two_int,
|
||||
]
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
CHAR_BIT :: 8;
|
||||
|
||||
c_bool :: bool;
|
||||
c_char :: u8;
|
||||
c_byte :: u8;
|
||||
c_schar :: i8;
|
||||
c_uchar :: u8;
|
||||
c_short :: i16;
|
||||
c_ushort :: u16;
|
||||
c_int :: i32;
|
||||
c_uint :: u32;
|
||||
|
||||
when ODIN_OS == "windows" || size_of(rawptr) == 4 {
|
||||
c_long :: i32;
|
||||
} else {
|
||||
c_long :: i64;
|
||||
}
|
||||
|
||||
when ODIN_OS == "windows" || size_of(rawptr) == 4 {
|
||||
c_ulong :: u32;
|
||||
} else {
|
||||
c_ulong :: u64;
|
||||
}
|
||||
|
||||
c_longlong :: i64;
|
||||
c_ulonglong :: u64;
|
||||
c_float :: f32;
|
||||
c_double :: f64;
|
||||
c_complex_float :: complex64;
|
||||
c_complex_double :: complex128;
|
||||
|
||||
_ :: compile_assert(size_of(uintptr) == size_of(int));
|
||||
|
||||
c_size_t :: uint;
|
||||
c_ssize_t :: int;
|
||||
c_ptrdiff_t :: int;
|
||||
c_uintptr_t :: uintptr;
|
||||
c_intptr_t :: int;
|
||||
@@ -0,0 +1,34 @@
|
||||
package c
|
||||
|
||||
import b "core:builtin"
|
||||
import "core:os"
|
||||
|
||||
CHAR_BIT :: 8;
|
||||
|
||||
bool :: b.bool;
|
||||
char :: b.u8;
|
||||
byte :: b.byte;
|
||||
schar :: b.i8;
|
||||
uchar :: b.u8;
|
||||
short :: b.i16;
|
||||
ushort :: b.u16;
|
||||
int :: b.i32;
|
||||
uint :: b.u32;
|
||||
|
||||
long :: (os.OS == "windows" || size_of(b.rawptr) == 4) ? b.i32 : b.i64;
|
||||
ulong :: (os.OS == "windows" || size_of(b.rawptr) == 4) ? b.u32 : b.u64;
|
||||
|
||||
longlong :: b.i64;
|
||||
ulonglong :: b.u64;
|
||||
float :: b.f32;
|
||||
double :: b.f64;
|
||||
complex_float :: b.complex64;
|
||||
complex_double :: b.complex128;
|
||||
|
||||
#assert(size_of(b.uintptr) == size_of(b.int));
|
||||
|
||||
size_t :: b.uint;
|
||||
ssize_t :: b.int;
|
||||
ptrdiff_t :: b.int;
|
||||
uintptr_t :: b.uintptr;
|
||||
intptr_t :: b.int;
|
||||
@@ -1,5 +1,6 @@
|
||||
// Multiple precision decimal numbers
|
||||
// NOTE: This is only for floating point printing and nothing else
|
||||
package decimal
|
||||
|
||||
Decimal :: struct {
|
||||
digits: [384]byte, // big-endian digits
|
||||
@@ -19,29 +20,29 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string {
|
||||
|
||||
// TODO(bill): make this work with a buffer that's not big enough
|
||||
assert(len(buf) >= n);
|
||||
buf = buf[0..n];
|
||||
buf = buf[0:n];
|
||||
|
||||
if a.count == 0 {
|
||||
buf[0] = '0';
|
||||
return string(buf[0..1]);
|
||||
return string(buf[0:1]);
|
||||
}
|
||||
|
||||
w := 0;
|
||||
if a.decimal_point <= 0 {
|
||||
buf[w] = '0'; w += 1;
|
||||
buf[w] = '.'; w += 1;
|
||||
w += digit_zero(buf[w .. w-a.decimal_point]);
|
||||
w += copy(buf[w..], a.digits[0..a.count]);
|
||||
w += digit_zero(buf[w : w-a.decimal_point]);
|
||||
w += copy(buf[w:], a.digits[0:a.count]);
|
||||
} else if a.decimal_point < a.count {
|
||||
w += copy(buf[w..], a.digits[0..a.decimal_point]);
|
||||
w += copy(buf[w:], a.digits[0:a.decimal_point]);
|
||||
buf[w] = '.'; w += 1;
|
||||
w += copy(buf[w..], a.digits[a.decimal_point .. a.count]);
|
||||
w += copy(buf[w:], a.digits[a.decimal_point : a.count]);
|
||||
} else {
|
||||
w += copy(buf[w..], a.digits[0..a.count]);
|
||||
w += digit_zero(buf[w .. w+a.decimal_point-a.count]);
|
||||
w += copy(buf[w:], a.digits[0:a.count]);
|
||||
w += digit_zero(buf[w : w+a.decimal_point-a.count]);
|
||||
}
|
||||
|
||||
return string(buf[0..w]);
|
||||
return string(buf[0:w]);
|
||||
}
|
||||
|
||||
// trim trailing zeros
|
||||
+366
-161
@@ -1,9 +1,11 @@
|
||||
import "core:os.odin"
|
||||
import "core:mem.odin"
|
||||
import "core:utf8.odin"
|
||||
import "core:types.odin"
|
||||
import "core:strconv.odin"
|
||||
import "core:raw.odin"
|
||||
package fmt
|
||||
|
||||
import "core:runtime"
|
||||
import "core:os"
|
||||
import "core:mem"
|
||||
import "core:unicode/utf8"
|
||||
import "core:types"
|
||||
import "core:strconv"
|
||||
|
||||
|
||||
_BUFFER_SIZE :: 1<<12;
|
||||
@@ -31,19 +33,19 @@ Fmt_Info :: struct {
|
||||
}
|
||||
|
||||
string_buffer_from_slice :: proc(backing: []byte) -> String_Buffer {
|
||||
s := transmute(raw.Slice)backing;
|
||||
d := raw.Dynamic_Array{
|
||||
s := transmute(mem.Raw_Slice)backing;
|
||||
d := mem.Raw_Dynamic_Array{
|
||||
data = s.data,
|
||||
len = 0,
|
||||
cap = s.len,
|
||||
allocator = nil_allocator(),
|
||||
allocator = mem.nil_allocator(),
|
||||
};
|
||||
return transmute(String_Buffer)d;
|
||||
}
|
||||
|
||||
|
||||
to_string :: proc(buf: String_Buffer) -> string {
|
||||
return string(buf[..]);
|
||||
return string(buf[:]);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +53,7 @@ write_string :: proc(buf: ^String_Buffer, s: string) {
|
||||
append_string(buf, s);
|
||||
}
|
||||
write_bytes :: proc(buf: ^String_Buffer, data: []byte) {
|
||||
append(buf, ...data);
|
||||
append(buf, ..data);
|
||||
}
|
||||
write_byte :: proc(buf: ^String_Buffer, data: byte) {
|
||||
append(buf, data);
|
||||
@@ -63,79 +65,112 @@ write_rune :: proc(buf: ^String_Buffer, r: rune) {
|
||||
}
|
||||
|
||||
b, n := utf8.encode_rune(r);
|
||||
write_bytes(buf, b[..n]);
|
||||
write_bytes(buf, b[:n]);
|
||||
}
|
||||
write_encoded_rune :: proc(buf: ^String_Buffer, r: rune) {
|
||||
write_byte(buf, '\'');
|
||||
switch r {
|
||||
case '\a': write_string(buf, "\\a");
|
||||
case '\b': write_string(buf, "\\b");
|
||||
case '\e': write_string(buf, "\\e");
|
||||
case '\f': write_string(buf, "\\f");
|
||||
case '\n': write_string(buf, "\\n");
|
||||
case '\r': write_string(buf, "\\r");
|
||||
case '\t': write_string(buf, "\\t");
|
||||
case '\v': write_string(buf, "\\v");
|
||||
case:
|
||||
if r < 32 {
|
||||
write_string(buf, "\\x");
|
||||
b: [2]byte;
|
||||
s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil);
|
||||
switch len(s) {
|
||||
case 0: write_string(buf, "00");
|
||||
case 1: write_rune(buf, '0');
|
||||
case 2: write_string(buf, s);
|
||||
}
|
||||
} else {
|
||||
write_rune(buf, r);
|
||||
}
|
||||
|
||||
}
|
||||
write_byte(buf, '\'');
|
||||
}
|
||||
|
||||
write_u64 :: proc(buf: ^String_Buffer, i: u64, base: int) {
|
||||
b: [129]byte;
|
||||
s := strconv.append_bits(b[:], u64(i), base, false, 64, strconv.digits, nil);
|
||||
write_string(buf, s);
|
||||
}
|
||||
write_i64 :: proc(buf: ^String_Buffer, i: i64, base: int) {
|
||||
b: [129]byte;
|
||||
s := strconv.append_bits(b[..], u64(i), base, true, 64, strconv.digits, 0);
|
||||
s := strconv.append_bits(b[:], u64(i), base, true, 64, strconv.digits, nil);
|
||||
write_string(buf, s);
|
||||
}
|
||||
|
||||
fprint :: proc(fd: os.Handle, args: ...any) -> int {
|
||||
fprint :: proc(fd: os.Handle, args: ..any) -> int {
|
||||
data: [_BUFFER_SIZE]byte;
|
||||
buf := string_buffer_from_slice(data[..]);
|
||||
res := sbprint(&buf, ...args);
|
||||
buf := string_buffer_from_slice(data[:]);
|
||||
res := sbprint(&buf, ..args);
|
||||
os.write_string(fd, res);
|
||||
return len(res);
|
||||
}
|
||||
|
||||
fprintln :: proc(fd: os.Handle, args: ...any) -> int {
|
||||
fprintln :: proc(fd: os.Handle, args: ..any) -> int {
|
||||
data: [_BUFFER_SIZE]byte;
|
||||
buf := string_buffer_from_slice(data[..]);
|
||||
res := sbprintln(&buf, ...args);
|
||||
buf := string_buffer_from_slice(data[:]);
|
||||
res := sbprintln(&buf, ..args);
|
||||
os.write_string(fd, res);
|
||||
return len(res);
|
||||
}
|
||||
fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int {
|
||||
fprintf :: proc(fd: os.Handle, fmt: string, args: ..any) -> int {
|
||||
data: [_BUFFER_SIZE]byte;
|
||||
buf := string_buffer_from_slice(data[..]);
|
||||
res := sbprintf(&buf, fmt, ...args);
|
||||
buf := string_buffer_from_slice(data[:]);
|
||||
res := sbprintf(&buf, fmt, ..args);
|
||||
os.write_string(fd, res);
|
||||
return len(res);
|
||||
}
|
||||
|
||||
|
||||
// print* procedures return the number of bytes written
|
||||
print :: proc(args: ...any) -> int { return fprint(os.stdout, ...args); }
|
||||
print_err :: proc(args: ...any) -> int { return fprint(os.stderr, ...args); }
|
||||
println :: proc(args: ...any) -> int { return fprintln(os.stdout, ...args); }
|
||||
println_err :: proc(args: ...any) -> int { return fprintln(os.stderr, ...args); }
|
||||
printf :: proc(fmt: string, args: ...any) -> int { return fprintf(os.stdout, fmt, ...args); }
|
||||
printf_err :: proc(fmt: string, args: ...any) -> int { return fprintf(os.stderr, fmt, ...args); }
|
||||
print :: proc(args: ..any) -> int { return fprint(os.stdout, ..args); }
|
||||
print_err :: proc(args: ..any) -> int { return fprint(os.stderr, ..args); }
|
||||
println :: proc(args: ..any) -> int { return fprintln(os.stdout, ..args); }
|
||||
println_err :: proc(args: ..any) -> int { return fprintln(os.stderr, ..args); }
|
||||
printf :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stdout, fmt, ..args); }
|
||||
printf_err :: proc(fmt: string, args: ..any) -> int { return fprintf(os.stderr, fmt, ..args); }
|
||||
|
||||
|
||||
// aprint* procedures return a string that was allocated with the current context
|
||||
// They must be freed accordingly
|
||||
aprint :: proc(args: ...any) -> string {
|
||||
aprint :: proc(args: ..any) -> string {
|
||||
buf := String_Buffer(make([dynamic]byte));
|
||||
sbprint(&buf, ...args);
|
||||
sbprint(&buf, ..args);
|
||||
return to_string(buf);
|
||||
}
|
||||
aprintln :: proc(args: ...any) -> string {
|
||||
aprintln :: proc(args: ..any) -> string {
|
||||
buf := String_Buffer(make([dynamic]byte));
|
||||
sbprintln(&buf, ...args);
|
||||
sbprintln(&buf, ..args);
|
||||
return to_string(buf);
|
||||
}
|
||||
aprintf :: proc(fmt: string, args: ...any) -> string {
|
||||
aprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
buf := String_Buffer(make([dynamic]byte));
|
||||
sbprintf(&buf, fmt, ...args);
|
||||
sbprintf(&buf, fmt, ..args);
|
||||
return to_string(buf);
|
||||
}
|
||||
|
||||
|
||||
// bprint* procedures return a string using a buffer from an array
|
||||
bprint :: proc(buf: []byte, args: ...any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0..len(buf)]);
|
||||
return sbprint(&sb, ...args);
|
||||
bprint :: proc(buf: []byte, args: ..any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0:len(buf)]);
|
||||
return sbprint(&sb, ..args);
|
||||
}
|
||||
bprintln :: proc(buf: []byte, args: ...any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0..len(buf)]);
|
||||
return sbprintln(&sb, ...args);
|
||||
bprintln :: proc(buf: []byte, args: ..any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0:len(buf)]);
|
||||
return sbprintln(&sb, ..args);
|
||||
}
|
||||
bprintf :: proc(buf: []byte, fmt: string, args: ...any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0..len(buf)]);
|
||||
return sbprintf(&sb, fmt, ...args);
|
||||
bprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string {
|
||||
sb := string_buffer_from_slice(buf[0:len(buf)]);
|
||||
return sbprintf(&sb, fmt, ..args);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,25 +178,29 @@ bprintf :: proc(buf: []byte, fmt: string, args: ...any) -> string {
|
||||
|
||||
|
||||
|
||||
fprint_type :: proc(fd: os.Handle, info: ^Type_Info) {
|
||||
fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info) {
|
||||
data: [_BUFFER_SIZE]byte;
|
||||
buf := string_buffer_from_slice(data[..]);
|
||||
buf := string_buffer_from_slice(data[:]);
|
||||
write_type(&buf, info);
|
||||
os.write(fd, buf[..]);
|
||||
os.write(fd, buf[:]);
|
||||
}
|
||||
|
||||
write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
write_typeid :: proc(buf: ^String_Buffer, id: typeid) {
|
||||
write_type(buf, type_info_of(id));
|
||||
}
|
||||
|
||||
write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
|
||||
if ti == nil {
|
||||
write_string(buf, "nil");
|
||||
return;
|
||||
}
|
||||
|
||||
switch info in ti.variant {
|
||||
case Type_Info_Named:
|
||||
case runtime.Type_Info_Named:
|
||||
write_string(buf, info.name);
|
||||
case Type_Info_Integer:
|
||||
a := any{type_info = ti};
|
||||
switch _ in a {
|
||||
case runtime.Type_Info_Integer:
|
||||
a := any{typeid = typeid_of(ti)};
|
||||
switch in a {
|
||||
case int: write_string(buf, "int");
|
||||
case uint: write_string(buf, "uint");
|
||||
case uintptr: write_string(buf, "uintptr");
|
||||
@@ -169,40 +208,47 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
write_byte(buf, info.signed ? 'i' : 'u');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
}
|
||||
case Type_Info_Rune:
|
||||
case runtime.Type_Info_Rune:
|
||||
write_string(buf, "rune");
|
||||
case Type_Info_Float:
|
||||
case runtime.Type_Info_Float:
|
||||
write_byte(buf, 'f');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case Type_Info_Complex:
|
||||
case runtime.Type_Info_Complex:
|
||||
write_string(buf, "complex");
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
case Type_Info_String:
|
||||
write_string(buf, "string");
|
||||
case Type_Info_Boolean:
|
||||
a := any{type_info = ti};
|
||||
switch _ in a {
|
||||
case runtime.Type_Info_String:
|
||||
if info.is_cstring {
|
||||
write_string(buf, "cstring");
|
||||
} else {
|
||||
write_string(buf, "string");
|
||||
}
|
||||
case runtime.Type_Info_Boolean:
|
||||
a := any{typeid = typeid_of(ti)};
|
||||
switch in a {
|
||||
case bool: write_string(buf, "bool");
|
||||
case:
|
||||
write_byte(buf, 'b');
|
||||
write_i64(buf, i64(8*ti.size), 10);
|
||||
}
|
||||
case Type_Info_Any:
|
||||
case runtime.Type_Info_Any:
|
||||
write_string(buf, "any");
|
||||
|
||||
case Type_Info_Pointer:
|
||||
case runtime.Type_Info_Type_Id:
|
||||
write_string(buf, "typeid");
|
||||
|
||||
case runtime.Type_Info_Pointer:
|
||||
if info.elem == nil {
|
||||
write_string(buf, "rawptr");
|
||||
} else {
|
||||
write_string(buf, "^");
|
||||
write_type(buf, info.elem);
|
||||
}
|
||||
case Type_Info_Procedure:
|
||||
case runtime.Type_Info_Procedure:
|
||||
write_string(buf, "proc");
|
||||
if info.params == nil {
|
||||
write_string(buf, "()");
|
||||
} else {
|
||||
t := info.params.variant.(Type_Info_Tuple);
|
||||
t := info.params.variant.(runtime.Type_Info_Tuple);
|
||||
write_string(buf, "(");
|
||||
for t, i in t.types {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
@@ -214,7 +260,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
write_string(buf, " -> ");
|
||||
write_type(buf, info.results);
|
||||
}
|
||||
case Type_Info_Tuple:
|
||||
case runtime.Type_Info_Tuple:
|
||||
count := len(info.names);
|
||||
if count != 1 do write_string(buf, "(");
|
||||
for name, i in info.names {
|
||||
@@ -230,25 +276,25 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
}
|
||||
if count != 1 do write_string(buf, ")");
|
||||
|
||||
case Type_Info_Array:
|
||||
case runtime.Type_Info_Array:
|
||||
write_string(buf, "[");
|
||||
write_i64(buf, i64(info.count), 10);
|
||||
write_string(buf, "]");
|
||||
write_type(buf, info.elem);
|
||||
case Type_Info_Dynamic_Array:
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
write_string(buf, "[dynamic]");
|
||||
write_type(buf, info.elem);
|
||||
case Type_Info_Slice:
|
||||
case runtime.Type_Info_Slice:
|
||||
write_string(buf, "[]");
|
||||
write_type(buf, info.elem);
|
||||
|
||||
case Type_Info_Map:
|
||||
case runtime.Type_Info_Map:
|
||||
write_string(buf, "map[");
|
||||
write_type(buf, info.key);
|
||||
write_byte(buf, ']');
|
||||
write_type(buf, info.value);
|
||||
|
||||
case Type_Info_Struct:
|
||||
case runtime.Type_Info_Struct:
|
||||
write_string(buf, "struct ");
|
||||
if info.is_packed do write_string(buf, "#packed ");
|
||||
if info.is_raw_union do write_string(buf, "#raw_union ");
|
||||
@@ -266,7 +312,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
}
|
||||
write_byte(buf, '}');
|
||||
|
||||
case Type_Info_Union:
|
||||
case runtime.Type_Info_Union:
|
||||
write_string(buf, "union {");
|
||||
for variant, i in info.variants {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
@@ -274,10 +320,9 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
}
|
||||
write_string(buf, "}");
|
||||
|
||||
case Type_Info_Enum:
|
||||
case runtime.Type_Info_Enum:
|
||||
write_string(buf, "enum ");
|
||||
write_type(buf, info.base);
|
||||
if info.is_export do write_string(buf, " #export");
|
||||
write_string(buf, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do write_string(buf, ", ");
|
||||
@@ -285,7 +330,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
}
|
||||
write_string(buf, "}");
|
||||
|
||||
case Type_Info_Bit_Field:
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
write_string(buf, "bit_field ");
|
||||
if ti.align != 1 {
|
||||
write_string(buf, "#align ");
|
||||
@@ -300,6 +345,26 @@ write_type :: proc(buf: ^String_Buffer, ti: ^Type_Info) {
|
||||
write_i64(buf, i64(info.bits[i]), 10);
|
||||
}
|
||||
write_string(buf, "}");
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
write_string(buf, "bit_set[");
|
||||
switch {
|
||||
case types.is_enum(info.elem):
|
||||
write_type(buf, info.elem);
|
||||
case types.is_rune(info.elem):
|
||||
write_encoded_rune(buf, rune(info.lower));
|
||||
write_string(buf, "..");
|
||||
write_encoded_rune(buf, rune(info.upper));
|
||||
case:
|
||||
write_i64(buf, info.lower, 10);
|
||||
write_string(buf, "..");
|
||||
write_i64(buf, info.upper, 10);
|
||||
}
|
||||
if info.underlying != nil {
|
||||
write_string(buf, "; ");
|
||||
write_type(buf, info.underlying);
|
||||
}
|
||||
write_byte(buf, ']');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +389,7 @@ _arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset, arg_c
|
||||
parse_arg_number :: proc(format: string) -> (int, int, bool) {
|
||||
if len(format) < 3 do return 0, 1, false;
|
||||
|
||||
for i in 1...len(format) {
|
||||
for i in 1..len(format)-1 {
|
||||
if format[i] == ']' {
|
||||
width, new_index, ok := _parse_int(format, 1);
|
||||
if !ok || new_index != i {
|
||||
@@ -344,7 +409,7 @@ _arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset, arg_c
|
||||
fi.reordered = true;
|
||||
|
||||
width: int;
|
||||
index, width, ok = parse_arg_number(format[offset..]);
|
||||
index, width, ok = parse_arg_number(format[offset:]);
|
||||
if ok && 0 <= index && index < arg_count {
|
||||
return index, offset+width, true;
|
||||
}
|
||||
@@ -358,7 +423,7 @@ int_from_arg :: proc(args: []any, arg_index: int) -> (int, int, bool) {
|
||||
ok := true;
|
||||
if arg_index < len(args) {
|
||||
arg := args[arg_index];
|
||||
arg.type_info = type_info_base(arg.type_info);
|
||||
arg.typeid = runtime.typeid_base(arg.typeid);
|
||||
switch i in arg {
|
||||
case int: num = i;
|
||||
case i8: num = int(i);
|
||||
@@ -383,8 +448,8 @@ fmt_bad_verb :: proc(using fi: ^Fmt_Info, verb: rune) {
|
||||
write_string(buf, "%!");
|
||||
write_rune(buf, verb);
|
||||
write_byte(buf, '(');
|
||||
if arg.type_info != nil {
|
||||
write_type(buf, arg.type_info);
|
||||
if arg.typeid != nil {
|
||||
write_typeid(buf, arg.typeid);
|
||||
write_byte(buf, '=');
|
||||
fmt_value(fi, arg, 'v');
|
||||
} else {
|
||||
@@ -409,7 +474,7 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
|
||||
pad_byte: byte = '0';
|
||||
if fi.space do pad_byte = ' ';
|
||||
|
||||
for _ in 0..width {
|
||||
for _ in 0..width-1 {
|
||||
write_byte(fi.buf, pad_byte);
|
||||
}
|
||||
}
|
||||
@@ -454,11 +519,12 @@ _fmt_int :: proc(fi: ^Fmt_Info, u: u64, base: int, is_signed: bool, bit_size: in
|
||||
buf: [256]byte;
|
||||
start := 0;
|
||||
|
||||
flags: strconv.Int_Flag;
|
||||
if fi.hash && !fi.zero do flags |= strconv.Int_Flag.Prefix;
|
||||
if fi.plus do flags |= strconv.Int_Flag.Plus;
|
||||
if fi.space do flags |= strconv.Int_Flag.Space;
|
||||
s := strconv.append_bits(buf[start..], u, base, is_signed, bit_size, digits, flags);
|
||||
using strconv.Int_Flag;
|
||||
flags: strconv.Int_Flags;
|
||||
if fi.hash && !fi.zero do flags |= {Prefix};
|
||||
if fi.plus do flags |= {Plus};
|
||||
if fi.space do flags |= {Space};
|
||||
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags);
|
||||
|
||||
if fi.hash && fi.zero {
|
||||
c: byte = 0;
|
||||
@@ -545,10 +611,10 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
|
||||
if fi.prec_set do prec = fi.prec;
|
||||
buf: [386]byte;
|
||||
|
||||
str := strconv.append_float(buf[1..], v, 'f', prec, bit_size);
|
||||
str = string(buf[...len(str)]);
|
||||
str := strconv.append_float(buf[1:], v, 'f', prec, bit_size);
|
||||
str = string(buf[:len(str)+1]);
|
||||
if str[1] == '+' || str[1] == '-' {
|
||||
str = str[1..];
|
||||
str = str[1:];
|
||||
} else {
|
||||
str[0] = '+';
|
||||
}
|
||||
@@ -566,12 +632,12 @@ fmt_float :: proc(fi: ^Fmt_Info, v: f64, bit_size: int, verb: rune) {
|
||||
if fi.zero && fi.width_set && fi.width > len(str) {
|
||||
write_byte(fi.buf, str[0]);
|
||||
fmt_write_padding(fi, fi.width - len(str));
|
||||
write_string(fi.buf, str[1..]);
|
||||
write_string(fi.buf, str[1:]);
|
||||
} else {
|
||||
_pad(fi, str);
|
||||
}
|
||||
} else {
|
||||
_pad(fi, str[1..]);
|
||||
_pad(fi, str[1:]);
|
||||
}
|
||||
|
||||
case:
|
||||
@@ -588,7 +654,7 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
|
||||
fi.space = false;
|
||||
defer fi.space = space;
|
||||
|
||||
for i in 0..len(s) {
|
||||
for i in 0..len(s)-1 {
|
||||
if i > 0 && space do write_byte(fi.buf, ' ');
|
||||
char_set := __DIGITS_UPPER;
|
||||
if verb == 'x' do char_set = __DIGITS_LOWER;
|
||||
@@ -599,6 +665,9 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) {
|
||||
fmt_bad_verb(fi, verb);
|
||||
}
|
||||
}
|
||||
fmt_cstring :: proc(fi: ^Fmt_Info, s: cstring, verb: rune) {
|
||||
fmt_string(fi, string(s), verb);
|
||||
}
|
||||
|
||||
fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
|
||||
switch verb {
|
||||
@@ -614,12 +683,13 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
|
||||
}
|
||||
|
||||
enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||
v.type_info = type_info_base(v.type_info);
|
||||
v.typeid = runtime.typeid_base(v.typeid);
|
||||
type_info := type_info_of(v.typeid);
|
||||
|
||||
switch e in v.type_info.variant {
|
||||
switch e in type_info.variant {
|
||||
case: return "", false;
|
||||
case Type_Info_Enum:
|
||||
get_str :: proc(i: $T, e: Type_Info_Enum) -> (string, bool) {
|
||||
case runtime.Type_Info_Enum:
|
||||
get_str :: proc(i: $T, e: runtime.Type_Info_Enum) -> (string, bool) {
|
||||
if types.is_string(e.base) {
|
||||
for val, idx in e.values {
|
||||
if v, ok := val.(T); ok && v == i {
|
||||
@@ -638,7 +708,7 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||
return "", false;
|
||||
}
|
||||
|
||||
a := any{v.data, type_info_base(e.base)};
|
||||
a := any{v.data, typeid_of(runtime.type_info_base(e.base))};
|
||||
switch v in a {
|
||||
case rune: return get_str(v, e);
|
||||
case i8: return get_str(v, e);
|
||||
@@ -652,9 +722,6 @@ enum_value_to_string :: proc(v: any) -> (string, bool) {
|
||||
case u64: return get_str(v, e);
|
||||
case uint: return get_str(v, e);
|
||||
case uintptr: return get_str(v, e);
|
||||
|
||||
case f32: return get_str(v, e);
|
||||
case f64: return get_str(v, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,18 +743,19 @@ string_to_enum_value :: proc(T: type, s: string) -> (T, bool) {
|
||||
}
|
||||
|
||||
fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
if v.type_info == nil || v.data == nil {
|
||||
if v.typeid == nil || v.data == nil {
|
||||
write_string(fi.buf, "<nil>");
|
||||
return;
|
||||
}
|
||||
|
||||
switch e in v.type_info.variant {
|
||||
type_info := type_info_of(v.typeid);
|
||||
switch e in type_info.variant {
|
||||
case: fmt_bad_verb(fi, verb);
|
||||
case Type_Info_Enum:
|
||||
case runtime.Type_Info_Enum:
|
||||
switch verb {
|
||||
case: fmt_bad_verb(fi, verb);
|
||||
case 'd', 'f':
|
||||
fmt_arg(fi, any{v.data, type_info_base(e.base)}, verb);
|
||||
fmt_arg(fi, any{v.data, typeid_of(runtime.type_info_base(e.base))}, verb);
|
||||
case 's', 'v':
|
||||
str, ok := enum_value_to_string(v);
|
||||
if !ok do str = "!%(BAD ENUM VALUE)";
|
||||
@@ -697,16 +765,136 @@ fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 {
|
||||
switch i in ev {
|
||||
case rune: return u64(i);
|
||||
case i8: return u64(i);
|
||||
case i16: return u64(i);
|
||||
case i32: return u64(i);
|
||||
case i64: return u64(i);
|
||||
case int: return u64(i);
|
||||
case u8: return u64(i);
|
||||
case u16: return u64(i);
|
||||
case u32: return u64(i);
|
||||
case u64: return u64(i);
|
||||
case uint: return u64(i);
|
||||
case uintptr: return u64(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
|
||||
type_info := type_info_of(v.typeid);
|
||||
switch info in type_info.variant {
|
||||
case runtime.Type_Info_Named:
|
||||
val := v;
|
||||
val.typeid = info.base.id;
|
||||
fmt_bit_set(fi, val, info.name);
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
bits: u64;
|
||||
bit_size := u64(8*type_info.size);
|
||||
verb := 'b';
|
||||
|
||||
switch bit_size {
|
||||
case 0: bits = 0;
|
||||
case 8: bits = u64( (^u8)(v.data)^);
|
||||
case 16: bits = u64((^u16)(v.data)^);
|
||||
case 32: bits = u64((^u32)(v.data)^);
|
||||
case 64: bits = u64((^u64)(v.data)^);
|
||||
case: panic("unknown bit_size size");
|
||||
}
|
||||
|
||||
et := runtime.type_info_base(info.elem);
|
||||
|
||||
if name != "" {
|
||||
write_string(fi.buf, name);
|
||||
} else {
|
||||
write_type(fi.buf, type_info);
|
||||
}
|
||||
write_byte(fi.buf, '{');
|
||||
defer write_byte(fi.buf, '}');
|
||||
|
||||
e, is_enum := et.variant.(runtime.Type_Info_Enum);
|
||||
commas := 0;
|
||||
loop: for i in 0 .. bit_size-1 {
|
||||
if bits & (1<<i) == 0 {
|
||||
continue loop;
|
||||
}
|
||||
|
||||
if commas > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
defer commas += 1;
|
||||
|
||||
if is_enum do for ev, evi in e.values {
|
||||
v := enum_value_to_u64(ev);
|
||||
if v == i {
|
||||
write_string(fi.buf, e.names[evi]);
|
||||
continue loop;
|
||||
}
|
||||
}
|
||||
write_i64(fi.buf, i64(i), 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt_bit_field :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
|
||||
type_info := type_info_of(v.typeid);
|
||||
switch info in type_info.variant {
|
||||
case runtime.Type_Info_Named:
|
||||
val := v;
|
||||
val.typeid = info.base.id;
|
||||
fmt_bit_field(fi, val, info.name);
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
data: u64 = 0;
|
||||
switch type_info.size {
|
||||
case 1: data = cast(u64) (^u8)(v.data)^;
|
||||
case 2: data = cast(u64)(^u16)(v.data)^;
|
||||
case 4: data = cast(u64)(^u32)(v.data)^;
|
||||
case 8: data = cast(u64)(^u64)(v.data)^;
|
||||
}
|
||||
|
||||
if name != "" {
|
||||
write_string(fi.buf, name);
|
||||
write_byte(fi.buf, '{');
|
||||
} else {
|
||||
write_string(fi.buf, "bit_field{");
|
||||
}
|
||||
for name, i in info.names {
|
||||
if i > 0 {
|
||||
write_string(fi.buf, ", ");
|
||||
}
|
||||
bits := u64(info.bits[i]);
|
||||
offset := u64(info.offsets[i]);
|
||||
write_string(fi.buf, name);
|
||||
write_string(fi.buf, " = ");
|
||||
|
||||
n := 8*u64(size_of(u64));
|
||||
sa := n - bits;
|
||||
u := data>>offset;
|
||||
u <<= sa;
|
||||
u >>= sa;
|
||||
|
||||
write_u64(fi.buf, u, 10);
|
||||
|
||||
}
|
||||
write_byte(fi.buf, '}');
|
||||
case:
|
||||
write_string(fi.buf, "HERE");
|
||||
}
|
||||
}
|
||||
|
||||
fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
if v.data == nil || v.type_info == nil {
|
||||
if v.data == nil || v.typeid == nil {
|
||||
write_string(fi.buf, "<nil>");
|
||||
return;
|
||||
}
|
||||
|
||||
switch info in v.type_info.variant {
|
||||
case Type_Info_Named:
|
||||
type_info := type_info_of(v.typeid);
|
||||
switch info in type_info.variant {
|
||||
case runtime.Type_Info_Named:
|
||||
switch b in info.base.variant {
|
||||
case Type_Info_Struct:
|
||||
case runtime.Type_Info_Struct:
|
||||
if verb != 'v' {
|
||||
fmt_bad_verb(fi, verb);
|
||||
return;
|
||||
@@ -729,7 +917,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
|
||||
for _, i in b.names {
|
||||
if !hash && i > 0 do write_string(fi.buf, ", ");
|
||||
if hash do for in 0..fi.indent do write_byte(fi.buf, '\t');
|
||||
if hash do for in 0..fi.indent-1 do write_byte(fi.buf, '\t');
|
||||
|
||||
write_string(fi.buf, b.names[i]);
|
||||
write_string(fi.buf, " = ");
|
||||
@@ -737,67 +925,71 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
if t := b.types[i]; types.is_any(t) {
|
||||
write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := uintptr(v.data) + b.offsets[i];
|
||||
fmt_arg(fi, any{rawptr(data), t}, 'v');
|
||||
data := rawptr(uintptr(v.data) + b.offsets[i]);
|
||||
fmt_arg(fi, any{data, typeid_of(t)}, 'v');
|
||||
}
|
||||
|
||||
if hash do write_string(fi.buf, ",\n");
|
||||
}
|
||||
|
||||
if hash do for in 0..indent do write_byte(fi.buf, '\t');
|
||||
if hash do for in 0..indent-1 do write_byte(fi.buf, '\t');
|
||||
write_byte(fi.buf, '}');
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
fmt_bit_set(fi, v);
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
fmt_bit_field(fi, v);
|
||||
case:
|
||||
fmt_value(fi, any{v.data, info.base}, verb);
|
||||
fmt_value(fi, any{v.data, typeid_of(info.base)}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Boolean: fmt_arg(fi, v, verb);
|
||||
case Type_Info_Integer: fmt_arg(fi, v, verb);
|
||||
case Type_Info_Rune: fmt_arg(fi, v, verb);
|
||||
case Type_Info_Float: fmt_arg(fi, v, verb);
|
||||
case Type_Info_Complex: fmt_arg(fi, v, verb);
|
||||
case Type_Info_String: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Boolean: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Integer: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Rune: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Float: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_Complex: fmt_arg(fi, v, verb);
|
||||
case runtime.Type_Info_String: fmt_arg(fi, v, verb);
|
||||
|
||||
case Type_Info_Pointer:
|
||||
if v.type_info == type_info_of(^Type_Info) {
|
||||
write_type(fi.buf, (^^Type_Info)(v.data)^);
|
||||
case runtime.Type_Info_Pointer:
|
||||
if v.typeid == typeid_of(^runtime.Type_Info) {
|
||||
write_type(fi.buf, (^^runtime.Type_Info)(v.data)^);
|
||||
} else {
|
||||
fmt_pointer(fi, (^rawptr)(v.data)^, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Array:
|
||||
case runtime.Type_Info_Array:
|
||||
write_byte(fi.buf, '[');
|
||||
defer write_byte(fi.buf, ']');
|
||||
for i in 0..info.count {
|
||||
for i in 0..info.count-1 {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := uintptr(v.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
case runtime.Type_Info_Dynamic_Array:
|
||||
write_byte(fi.buf, '[');
|
||||
defer write_byte(fi.buf, ']');
|
||||
array := cast(^raw.Dynamic_Array)v.data;
|
||||
for i in 0..array.len {
|
||||
array := cast(^mem.Raw_Dynamic_Array)v.data;
|
||||
for i in 0..array.len-1 {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := uintptr(array.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Slice:
|
||||
case runtime.Type_Info_Slice:
|
||||
write_byte(fi.buf, '[');
|
||||
defer write_byte(fi.buf, ']');
|
||||
slice := cast(^raw.Slice)v.data;
|
||||
for i in 0..slice.len {
|
||||
slice := cast(^mem.Raw_Slice)v.data;
|
||||
for i in 0..slice.len-1 {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := uintptr(slice.data) + uintptr(i*info.elem_size);
|
||||
fmt_arg(fi, any{rawptr(data), info.elem}, verb);
|
||||
fmt_arg(fi, any{rawptr(data), typeid_of(info.elem)}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Map:
|
||||
case runtime.Type_Info_Map:
|
||||
if verb != 'v' {
|
||||
fmt_bad_verb(fi, verb);
|
||||
return;
|
||||
@@ -806,36 +998,36 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
write_string(fi.buf, "map[");
|
||||
defer write_byte(fi.buf, ']');
|
||||
|
||||
m := (^raw.Map)(v.data);
|
||||
m := (^mem.Raw_Map)(v.data);
|
||||
if m != nil {
|
||||
assert(info.generated_struct != nil);
|
||||
entries := &m.entries;
|
||||
gs := type_info_base(info.generated_struct).variant.(Type_Info_Struct);
|
||||
ed := type_info_base(gs.types[1]).variant.(Type_Info_Dynamic_Array);
|
||||
entry_type := ed.elem.variant.(Type_Info_Struct);
|
||||
gs := runtime.type_info_base(info.generated_struct).variant.(runtime.Type_Info_Struct);
|
||||
ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array);
|
||||
entry_type := ed.elem.variant.(runtime.Type_Info_Struct);
|
||||
entry_size := ed.elem_size;
|
||||
|
||||
for i in 0..entries.len {
|
||||
for i in 0..entries.len-1 {
|
||||
if i > 0 do write_string(fi.buf, ", ");
|
||||
|
||||
data := uintptr(entries.data) + uintptr(i*entry_size);
|
||||
header := cast(^__Map_Entry_Header)data;
|
||||
header := cast(^runtime.Map_Entry_Header)data;
|
||||
|
||||
if types.is_string(info.key) {
|
||||
write_string(fi.buf, header.key.str);
|
||||
} else {
|
||||
fi := Fmt_Info{buf = fi.buf};
|
||||
fmt_arg(&fi, any{rawptr(&header.key.hash), info.key}, 'v');
|
||||
fmt_arg(&fi, any{rawptr(&header.key.hash), typeid_of(info.key)}, 'v');
|
||||
}
|
||||
|
||||
write_string(fi.buf, "=");
|
||||
|
||||
value := data + entry_type.offsets[2];
|
||||
fmt_arg(fi, any{rawptr(value), info.value}, 'v');
|
||||
fmt_arg(fi, any{rawptr(value), typeid_of(info.value)}, 'v');
|
||||
}
|
||||
}
|
||||
|
||||
case Type_Info_Struct:
|
||||
case runtime.Type_Info_Struct:
|
||||
if info.is_raw_union {
|
||||
write_string(fi.buf, "(raw_union)");
|
||||
return;
|
||||
@@ -854,7 +1046,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
for _, i in info.names {
|
||||
if !hash && i > 0 do write_string(fi.buf, ", ");
|
||||
if hash {
|
||||
for in 0..fi.indent {
|
||||
for in 0..fi.indent-1 {
|
||||
write_byte(fi.buf, '\t');
|
||||
}
|
||||
}
|
||||
@@ -866,14 +1058,14 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
write_string(fi.buf, "any{}");
|
||||
} else {
|
||||
data := uintptr(v.data) + info.offsets[i];
|
||||
fmt_arg(fi, any{rawptr(data), t}, 'v');
|
||||
fmt_arg(fi, any{rawptr(data), typeid_of(t)}, 'v');
|
||||
}
|
||||
if hash do write_string(fi.buf, ",\n");
|
||||
}
|
||||
|
||||
case Type_Info_Union:
|
||||
case runtime.Type_Info_Union:
|
||||
tag_ptr := uintptr(v.data) + info.tag_offset;
|
||||
tag_any := any{rawptr(tag_ptr), info.tag_type};
|
||||
tag_any := any{rawptr(tag_ptr), typeid_of(info.tag_type)};
|
||||
|
||||
tag: i64 = -1;
|
||||
switch i in tag_any {
|
||||
@@ -891,22 +1083,32 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
|
||||
if v.data == nil || tag == 0 {
|
||||
write_string(fi.buf, "nil");
|
||||
} else {
|
||||
ti := info.variants[tag-1];
|
||||
fmt_arg(fi, any{v.data, ti}, verb);
|
||||
id := typeid_of(info.variants[tag-1]);
|
||||
fmt_arg(fi, any{v.data, id}, verb);
|
||||
}
|
||||
|
||||
case Type_Info_Enum:
|
||||
case runtime.Type_Info_Enum:
|
||||
fmt_enum(fi, v, verb);
|
||||
|
||||
case Type_Info_Procedure:
|
||||
case runtime.Type_Info_Procedure:
|
||||
ptr := (^rawptr)(v.data)^;
|
||||
if ptr == nil {
|
||||
write_string(fi.buf, "nil");
|
||||
} else {
|
||||
write_type(fi.buf, v.type_info);
|
||||
write_typeid(fi.buf, v.typeid);
|
||||
write_string(fi.buf, " @ ");
|
||||
fmt_pointer(fi, ptr, 'p');
|
||||
}
|
||||
|
||||
case runtime.Type_Info_Type_Id:
|
||||
id := (^typeid)(v.data)^;
|
||||
write_typeid(fi.buf, id);
|
||||
|
||||
case runtime.Type_Info_Bit_Field:
|
||||
fmt_bit_field(fi, v);
|
||||
|
||||
case runtime.Type_Info_Bit_Set:
|
||||
fmt_bit_set(fi, v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,16 +1137,16 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
||||
fi.arg = arg;
|
||||
|
||||
if verb == 'T' {
|
||||
ti := arg.type_info;
|
||||
ti := type_info_of(arg.typeid);
|
||||
switch a in arg {
|
||||
case ^Type_Info: ti = a;
|
||||
case ^runtime.Type_Info: ti = a;
|
||||
}
|
||||
write_type(fi.buf, ti);
|
||||
return;
|
||||
}
|
||||
|
||||
base_arg := arg;
|
||||
base_arg.type_info = type_info_base(base_arg.type_info);
|
||||
base_arg.typeid = runtime.typeid_base(base_arg.typeid);
|
||||
switch a in base_arg {
|
||||
case bool: fmt_bool(fi, bool(a), verb);
|
||||
case b8: fmt_bool(fi, bool(a), verb);
|
||||
@@ -974,22 +1176,25 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
|
||||
case uintptr: fmt_int(fi, u64(a), false, 8*size_of(uintptr), verb);
|
||||
|
||||
case string: fmt_string(fi, a, verb);
|
||||
case cstring: fmt_cstring(fi, a, verb);
|
||||
|
||||
case: fmt_value(fi, arg, verb);
|
||||
case typeid: write_typeid(fi.buf, a);
|
||||
|
||||
case: fmt_value(fi, arg, verb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
sbprint :: proc(buf: ^String_Buffer, args: ...any) -> string {
|
||||
sbprint :: proc(buf: ^String_Buffer, args: ..any) -> string {
|
||||
fi: Fmt_Info;
|
||||
prev_string := false;
|
||||
|
||||
fi.buf = buf;
|
||||
|
||||
for arg, i in args {
|
||||
is_string := arg != nil && types.is_string(arg.type_info);
|
||||
is_string := arg != nil && types.is_string(type_info_of(arg.typeid));
|
||||
if i > 0 && !is_string && !prev_string {
|
||||
write_byte(buf, ' ');
|
||||
}
|
||||
@@ -999,7 +1204,7 @@ sbprint :: proc(buf: ^String_Buffer, args: ...any) -> string {
|
||||
return to_string(buf^);
|
||||
}
|
||||
|
||||
sbprintln :: proc(buf: ^String_Buffer, args: ...any) -> string {
|
||||
sbprintln :: proc(buf: ^String_Buffer, args: ..any) -> string {
|
||||
fi: Fmt_Info;
|
||||
fi.buf = buf;
|
||||
|
||||
@@ -1012,7 +1217,7 @@ sbprintln :: proc(buf: ^String_Buffer, args: ...any) -> string {
|
||||
return to_string(buf^);
|
||||
}
|
||||
|
||||
sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ...any) -> string {
|
||||
sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ..any) -> string {
|
||||
fi: Fmt_Info;
|
||||
arg_index: int = 0;
|
||||
end := len(fmt);
|
||||
@@ -1027,7 +1232,7 @@ sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ...any) -> string {
|
||||
i += 1;
|
||||
}
|
||||
if i > prev_i {
|
||||
write_string(b, fmt[prev_i..i]);
|
||||
write_string(b, fmt[prev_i:i]);
|
||||
}
|
||||
if i >= end {
|
||||
break loop;
|
||||
@@ -1113,7 +1318,7 @@ sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ...any) -> string {
|
||||
break loop;
|
||||
}
|
||||
|
||||
verb, w := utf8.decode_rune_from_string(fmt[i..]);
|
||||
verb, w := utf8.decode_rune_from_string(fmt[i:]);
|
||||
i += w;
|
||||
|
||||
switch {
|
||||
@@ -1131,7 +1336,7 @@ sbprintf :: proc(b: ^String_Buffer, fmt: string, args: ...any) -> string {
|
||||
|
||||
if !fi.reordered && arg_index < len(args) {
|
||||
write_string(b, "%!(EXTRA ");
|
||||
for arg, index in args[arg_index..] {
|
||||
for arg, index in args[arg_index:] {
|
||||
if index > 0 do write_string(b, ", ");
|
||||
|
||||
if arg == nil do write_string(b, "<nil>");
|
||||
@@ -1,4 +1,6 @@
|
||||
import "core:mem.odin"
|
||||
package hash
|
||||
|
||||
import "core:mem"
|
||||
|
||||
adler32 :: proc(data: []byte) -> u32 {
|
||||
ADLER_CONST :: 65521;
|
||||
@@ -64,9 +66,9 @@ murmur32 :: proc(data: []byte) -> u32 {
|
||||
h1: u32 = 0;
|
||||
nblocks := len(data)/4;
|
||||
p := &data[0];
|
||||
p1 := p + 4*nblocks;
|
||||
p1 := mem.ptr_offset(p, 4*nblocks);
|
||||
|
||||
for ; p < p1; p += 4 {
|
||||
for ; p < p1; p = mem.ptr_offset(p, 4) {
|
||||
k1 := (cast(^u32)p)^;
|
||||
|
||||
k1 *= c1_32;
|
||||
@@ -78,7 +80,7 @@ murmur32 :: proc(data: []byte) -> u32 {
|
||||
h1 = h1*5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
tail := data[nblocks*4 ..];
|
||||
tail := data[nblocks*4:];
|
||||
k1: u32;
|
||||
switch len(tail)&3 {
|
||||
case 3:
|
||||
@@ -185,7 +187,7 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
}
|
||||
|
||||
// TODO(bill): Fix this
|
||||
#no_bounds_check data8 := slice_to_bytes(data32[i..])[..3];
|
||||
#no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3];
|
||||
switch len {
|
||||
case 3:
|
||||
h2 ~= u32(data8[2]) << 16;
|
||||
@@ -1,3 +1,5 @@
|
||||
package math
|
||||
|
||||
TAU :: 6.28318530717958647692528676655900576;
|
||||
PI :: 3.14159265358979323846264338327950288;
|
||||
|
||||
@@ -23,10 +25,13 @@ Mat2 :: distinct [2][2]f32;
|
||||
Mat3 :: distinct [3][3]f32;
|
||||
Mat4 :: distinct [4][4]f32;
|
||||
|
||||
Quat :: struct {x, y, z: f32, w: f32 = 1};
|
||||
Quat :: struct {x, y, z, w: f32};
|
||||
|
||||
QUAT_IDENTITY := Quat{x = 0, y = 0, z = 0, w = 1};
|
||||
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign __llvm_core {
|
||||
foreign _ {
|
||||
@(link_name="llvm.sqrt.f32")
|
||||
sqrt_f32 :: proc(x: f32) -> f32 ---;
|
||||
@(link_name="llvm.sqrt.f64")
|
||||
@@ -51,8 +56,15 @@ foreign __llvm_core {
|
||||
fmuladd_f32 :: proc(a, b, c: f32) -> f32 ---;
|
||||
@(link_name="llvm.fmuladd.f64")
|
||||
fmuladd_f64 :: proc(a, b, c: f64) -> f64 ---;
|
||||
|
||||
@(link_name="llvm.log.f32")
|
||||
log_f32 :: proc(x: f32) -> f32 ---;
|
||||
@(link_name="llvm.log.f64")
|
||||
log_f64 :: proc(x: f64) -> f64 ---;
|
||||
}
|
||||
|
||||
log :: proc[log_f32, log_f64];
|
||||
|
||||
tan_f32 :: proc "c" (θ: f32) -> f32 { return sin(θ)/cos(θ); }
|
||||
tan_f64 :: proc "c" (θ: f64) -> f64 { return sin(θ)/cos(θ); }
|
||||
|
||||
@@ -137,6 +149,7 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
|
||||
|
||||
|
||||
mul :: proc[
|
||||
mat3_mul,
|
||||
mat4_mul, mat4_mul_vec4,
|
||||
quat_mul, quat_mulf,
|
||||
];
|
||||
@@ -151,7 +164,7 @@ cross :: proc[cross2, cross3];
|
||||
|
||||
vec_dot :: proc(a, b: $T/[$N]$E) -> E {
|
||||
res: E;
|
||||
for i in 0..N {
|
||||
for i in 0..N-1 {
|
||||
res += a[i] * b[i];
|
||||
}
|
||||
return res;
|
||||
@@ -181,23 +194,35 @@ norm0 :: proc(v: $T/[$N]$E) -> T {
|
||||
|
||||
identity :: proc(T: type/[$N][N]$E) -> T {
|
||||
m: T;
|
||||
for i in 0..N do m[i][i] = E(1);
|
||||
for i in 0..N-1 do m[i][i] = E(1);
|
||||
return m;
|
||||
}
|
||||
|
||||
transpose :: proc(m: Mat4) -> Mat4 {
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
transpose :: proc(m: $M/[$N][N]f32) -> M {
|
||||
for j in 0..N-1 {
|
||||
for i in 0..N-1 {
|
||||
m[i][j], m[j][i] = m[j][i], m[i][j];
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
mat3_mul :: proc(a, b: Mat3) -> Mat3 {
|
||||
c: Mat3;
|
||||
for j in 0..2 {
|
||||
for i in 0..2 {
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
mat4_mul :: proc(a, b: Mat4) -> Mat4 {
|
||||
c: Mat4;
|
||||
for j in 0..4 {
|
||||
for i in 0..4 {
|
||||
for j in 0..3 {
|
||||
for i in 0..3 {
|
||||
c[j][i] = a[0][i]*b[j][0] +
|
||||
a[1][i]*b[j][1] +
|
||||
a[2][i]*b[j][2] +
|
||||
@@ -216,7 +241,6 @@ mat4_mul_vec4 :: proc(m: Mat4, v: Vec4) -> Vec4 {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
mat4_inverse :: proc(m: Mat4) -> Mat4 {
|
||||
o: Mat4;
|
||||
|
||||
@@ -413,8 +437,8 @@ axis_angle :: proc(axis: Vec3, angle_radians: f32) -> Quat {
|
||||
|
||||
euler_angles :: proc(pitch, yaw, roll: f32) -> Quat {
|
||||
p := axis_angle(Vec3{1, 0, 0}, pitch);
|
||||
y := axis_angle(Vec3{0, 1, 0}, pitch);
|
||||
r := axis_angle(Vec3{0, 0, 1}, pitch);
|
||||
y := axis_angle(Vec3{0, 1, 0}, yaw);
|
||||
r := axis_angle(Vec3{0, 0, 1}, roll);
|
||||
return mul(mul(y, p), r);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package rand
|
||||
|
||||
Rand :: struct {
|
||||
state: u64,
|
||||
inc: u64,
|
||||
@@ -0,0 +1,337 @@
|
||||
package mem
|
||||
|
||||
import "core:runtime"
|
||||
|
||||
DEFAULT_ALIGNMENT :: 2*align_of(rawptr);
|
||||
|
||||
Allocator_Mode :: enum byte {
|
||||
Alloc,
|
||||
Free,
|
||||
Free_All,
|
||||
Resize,
|
||||
}
|
||||
|
||||
Allocator_Proc :: #type proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64 = 0, location := #caller_location) -> rawptr;
|
||||
|
||||
|
||||
Allocator :: struct {
|
||||
procedure: Allocator_Proc,
|
||||
data: rawptr,
|
||||
}
|
||||
|
||||
|
||||
|
||||
alloc_with_allocator :: inline proc(a: Allocator, size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr {
|
||||
if size == 0 do return nil;
|
||||
return a.procedure(a.data, Allocator_Mode.Alloc, size, alignment, nil, 0, 0, loc);
|
||||
}
|
||||
alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr {
|
||||
return alloc_with_allocator(context.allocator, size, alignment, loc);
|
||||
}
|
||||
|
||||
free_ptr_with_allocator :: inline proc(a: Allocator, ptr: rawptr, loc := #caller_location) {
|
||||
if ptr == nil do return;
|
||||
if a.procedure == nil do return;
|
||||
a.procedure(a.data, Allocator_Mode.Free, 0, 0, ptr, 0, 0, loc);
|
||||
}
|
||||
free :: inline proc(ptr: rawptr, loc := #caller_location) do free_ptr_with_allocator(context.allocator, ptr, loc);
|
||||
|
||||
free_all_with_allocator :: inline proc(a: Allocator, loc := #caller_location) {
|
||||
a.procedure(a.data, Allocator_Mode.Free_All, 0, 0, nil, 0, 0, loc);
|
||||
}
|
||||
free_all :: inline proc(loc := #caller_location) {
|
||||
free_all_with_allocator(context.allocator, loc);
|
||||
}
|
||||
|
||||
resize_with_allocator :: inline proc(a: Allocator, ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr {
|
||||
if new_size == 0 {
|
||||
free_ptr_with_allocator(a, ptr, loc);
|
||||
return nil;
|
||||
}
|
||||
return a.procedure(a.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, 0, loc);
|
||||
}
|
||||
resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr {
|
||||
return resize_with_allocator(context.allocator, ptr, old_size, new_size, alignment, loc);
|
||||
}
|
||||
|
||||
|
||||
delete_string :: proc(str: string, loc := #caller_location) {
|
||||
free(raw_data(str), loc);
|
||||
}
|
||||
delete_cstring :: proc(str: cstring, loc := #caller_location) {
|
||||
free((^byte)(str), loc);
|
||||
}
|
||||
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) {
|
||||
free(raw_data(array), loc);
|
||||
}
|
||||
delete_slice :: proc(array: $T/[]$E, loc := #caller_location) {
|
||||
free(raw_data(array), loc);
|
||||
}
|
||||
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) {
|
||||
raw := transmute(Raw_Map)m;
|
||||
delete_dynamic_array(raw.hashes, loc);
|
||||
free(raw.entries.data, loc);
|
||||
}
|
||||
|
||||
|
||||
delete :: proc[
|
||||
delete_string,
|
||||
delete_cstring,
|
||||
delete_dynamic_array,
|
||||
delete_slice,
|
||||
delete_map,
|
||||
];
|
||||
|
||||
|
||||
new :: inline proc(T: type, loc := #caller_location) -> ^T {
|
||||
ptr := (^T)(alloc(size_of(T), align_of(T), loc));
|
||||
if ptr != nil do ptr^ = T{};
|
||||
return ptr;
|
||||
}
|
||||
new_clone :: inline proc(data: $T, loc := #caller_location) -> ^T {
|
||||
ptr := (^T)(alloc(size_of(T), align_of(T), loc));
|
||||
if ptr != nil do ptr^ = data;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
new_with_allocator :: inline proc(a: Allocator, T: type, loc := #caller_location) -> ^T {
|
||||
ptr := (^T)(alloc_with_allocator(a, size_of(T), align_of(T), loc));
|
||||
if ptr != nil do ptr^ = T{};
|
||||
return ptr;
|
||||
}
|
||||
|
||||
new_clone_with_allocator :: inline proc(a: Allocator, data: $T, loc := #caller_location) -> ^T {
|
||||
ptr := (^T)(alloc_with_allocator(a, size_of(T), align_of(T), loc));
|
||||
if ptr != nil do ptr^ = data;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
make_slice :: proc(T: type/[]$E, auto_cast len: int, loc := #caller_location) -> T {
|
||||
runtime.make_slice_error_loc(loc, len);
|
||||
data := alloc(size_of(E)*len, align_of(E));
|
||||
s := Raw_Slice{data, len};
|
||||
return transmute(T)s;
|
||||
}
|
||||
make_dynamic_array :: proc(T: type/[dynamic]$E, loc := #caller_location) -> T {
|
||||
return make_dynamic_array_len_cap(T, 0, 16, loc);
|
||||
}
|
||||
make_dynamic_array_len :: proc(T: type/[dynamic]$E, auto_cast len: int, loc := #caller_location) -> T {
|
||||
return make_dynamic_array_len_cap(T, len, len, loc);
|
||||
}
|
||||
make_dynamic_array_len_cap :: proc(T: type/[dynamic]$E, auto_cast len: int, auto_cast cap: int, loc := #caller_location) -> T {
|
||||
runtime.make_dynamic_array_error_loc(loc, len, cap);
|
||||
data := alloc(size_of(E)*cap, align_of(E));
|
||||
s := Raw_Dynamic_Array{data, len, cap, context.allocator};
|
||||
return transmute(T)s;
|
||||
}
|
||||
make_map :: proc(T: type/map[$K]$E, auto_cast cap: int = 16, loc := #caller_location) -> T {
|
||||
runtime.make_map_expr_error_loc(loc, cap);
|
||||
m: T;
|
||||
reserve_map(&m, cap);
|
||||
return m;
|
||||
}
|
||||
|
||||
make :: proc[
|
||||
make_slice,
|
||||
make_dynamic_array,
|
||||
make_dynamic_array_len,
|
||||
make_dynamic_array_len_cap,
|
||||
make_map,
|
||||
];
|
||||
|
||||
|
||||
|
||||
default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr {
|
||||
if old_memory == nil do return alloc(new_size, alignment, loc);
|
||||
|
||||
if new_size == 0 {
|
||||
free(old_memory, loc);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if new_size == old_size do return old_memory;
|
||||
|
||||
new_memory := alloc(new_size, alignment, loc);
|
||||
if new_memory == nil do return nil;
|
||||
|
||||
copy(new_memory, old_memory, min(old_size, new_size));;
|
||||
free(old_memory, loc);
|
||||
return new_memory;
|
||||
}
|
||||
|
||||
|
||||
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
||||
return nil;
|
||||
}
|
||||
|
||||
nil_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = nil_allocator_proc,
|
||||
data = nil,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Pool :: struct {
|
||||
block_size: int,
|
||||
out_band_size: int,
|
||||
alignment: int,
|
||||
|
||||
unused_blocks: [dynamic]rawptr,
|
||||
used_blocks: [dynamic]rawptr,
|
||||
out_band_allocations: [dynamic]rawptr,
|
||||
|
||||
current_block: rawptr,
|
||||
current_pos: rawptr,
|
||||
bytes_left: int,
|
||||
|
||||
block_allocator: Allocator,
|
||||
}
|
||||
|
||||
|
||||
POOL_BLOCK_SIZE_DEFAULT :: 65536;
|
||||
POOL_OUT_OF_BAND_SIZE_DEFAULT :: 6554;
|
||||
|
||||
|
||||
|
||||
pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
||||
pool := (^Pool)(allocator_data);
|
||||
|
||||
switch mode {
|
||||
case Allocator_Mode.Alloc:
|
||||
return pool_alloc(pool, size);
|
||||
case Allocator_Mode.Free:
|
||||
panic("Allocator_Mode.Free is not supported for a pool");
|
||||
case Allocator_Mode.Free_All:
|
||||
pool_free_all(pool);
|
||||
case Allocator_Mode.Resize:
|
||||
panic("Allocator_Mode.Resize is not supported for a pool");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
pool_allocator :: proc(pool: ^Pool) -> Allocator {
|
||||
return Allocator{
|
||||
procedure = pool_allocator_proc,
|
||||
data = pool,
|
||||
};
|
||||
}
|
||||
|
||||
pool_init :: proc(pool: ^Pool,
|
||||
block_allocator := Allocator{} , array_allocator := Allocator{},
|
||||
block_size := POOL_BLOCK_SIZE_DEFAULT, out_band_size := POOL_OUT_OF_BAND_SIZE_DEFAULT,
|
||||
alignment := 8) {
|
||||
pool.block_size = block_size;
|
||||
pool.out_band_size = out_band_size;
|
||||
pool.alignment = alignment;
|
||||
|
||||
if block_allocator.procedure == nil {
|
||||
block_allocator = context.allocator;
|
||||
}
|
||||
if array_allocator.procedure == nil {
|
||||
array_allocator = context.allocator;
|
||||
}
|
||||
|
||||
pool.block_allocator = block_allocator;
|
||||
|
||||
pool.out_band_allocations.allocator = array_allocator;
|
||||
pool. unused_blocks.allocator = array_allocator;
|
||||
pool. used_blocks.allocator = array_allocator;
|
||||
}
|
||||
|
||||
pool_destroy :: proc(using pool: ^Pool) {
|
||||
pool_free_all(pool);
|
||||
delete(unused_blocks);
|
||||
delete(used_blocks);
|
||||
|
||||
zero(pool, size_of(pool^));
|
||||
}
|
||||
|
||||
|
||||
pool_alloc :: proc(using pool: ^Pool, bytes: int) -> rawptr {
|
||||
cycle_new_block :: proc(using pool: ^Pool) {
|
||||
if block_allocator.procedure == nil {
|
||||
panic("You must call pool_init on a Pool before using it");
|
||||
}
|
||||
|
||||
if current_block != nil {
|
||||
append(&used_blocks, current_block);
|
||||
}
|
||||
|
||||
new_block: rawptr;
|
||||
if len(unused_blocks) > 0 {
|
||||
new_block = pop(&unused_blocks);
|
||||
} else {
|
||||
new_block = block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
|
||||
block_size, alignment,
|
||||
nil, 0);
|
||||
}
|
||||
|
||||
bytes_left = block_size;
|
||||
current_pos = new_block;
|
||||
current_block = new_block;
|
||||
}
|
||||
|
||||
|
||||
extra := alignment - (bytes % alignment);
|
||||
bytes += extra;
|
||||
if bytes >= out_band_size {
|
||||
assert(block_allocator.procedure != nil);
|
||||
memory := block_allocator.procedure(block_allocator.data, Allocator_Mode.Alloc,
|
||||
block_size, alignment,
|
||||
nil, 0);
|
||||
if memory != nil {
|
||||
append(&out_band_allocations, (^byte)(memory));
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
if bytes_left < bytes {
|
||||
cycle_new_block(pool);
|
||||
if current_block == nil {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
memory := current_pos;
|
||||
current_pos = ptr_offset((^byte)(current_pos), bytes);
|
||||
bytes_left -= bytes;
|
||||
return memory;
|
||||
}
|
||||
|
||||
|
||||
pool_reset :: proc(using pool: ^Pool) {
|
||||
if current_block != nil {
|
||||
append(&unused_blocks, current_block);
|
||||
current_block = nil;
|
||||
}
|
||||
|
||||
for block in used_blocks {
|
||||
append(&unused_blocks, block);
|
||||
}
|
||||
clear(&used_blocks);
|
||||
|
||||
for a in out_band_allocations {
|
||||
free_ptr_with_allocator(block_allocator, a);
|
||||
}
|
||||
clear(&out_band_allocations);
|
||||
}
|
||||
|
||||
pool_free_all :: proc(using pool: ^Pool) {
|
||||
pool_reset(pool);
|
||||
|
||||
for block in unused_blocks {
|
||||
free_ptr_with_allocator(block_allocator, block);
|
||||
}
|
||||
clear(&unused_blocks);
|
||||
}
|
||||
+103
-133
@@ -1,6 +1,8 @@
|
||||
import "core:raw.odin"
|
||||
package mem
|
||||
|
||||
foreign __llvm_core {
|
||||
import "core:runtime"
|
||||
|
||||
foreign _ {
|
||||
@(link_name = "llvm.bswap.i16") swap16 :: proc(b: u16) -> u16 ---;
|
||||
@(link_name = "llvm.bswap.i32") swap32 :: proc(b: u32) -> u32 ---;
|
||||
@(link_name = "llvm.bswap.i64") swap64 :: proc(b: u64) -> u64 ---;
|
||||
@@ -9,37 +11,110 @@ swap :: proc[swap16, swap32, swap64];
|
||||
|
||||
|
||||
set :: proc "contextless" (data: rawptr, value: i32, len: int) -> rawptr {
|
||||
return __mem_set(data, value, len);
|
||||
if data == nil do return nil;
|
||||
foreign _ {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memset.p0i8.i64")
|
||||
llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memset.p0i8.i32")
|
||||
llvm_memset :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) ---;
|
||||
}
|
||||
}
|
||||
llvm_memset(data, byte(value), len, 1, false);
|
||||
return data;
|
||||
}
|
||||
zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
|
||||
return __mem_zero(data, len);
|
||||
return set(data, 0, len);
|
||||
}
|
||||
copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
return __mem_copy(dst, src, len);
|
||||
if src == nil do return dst;
|
||||
// NOTE(bill): This _must_ be implemented like C's memmove
|
||||
foreign _ {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i64")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memmove.p0i8.p0i8.i32")
|
||||
llvm_memmove :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
}
|
||||
}
|
||||
llvm_memmove(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
|
||||
return __mem_copy_non_overlapping(dst, src, len);
|
||||
if src == nil do return dst;
|
||||
// NOTE(bill): This _must_ be implemented like C's memcpy
|
||||
foreign _ {
|
||||
when size_of(rawptr) == 8 {
|
||||
@(link_name="llvm.memcpy.p0i8.p0i8.i64")
|
||||
llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
} else {
|
||||
@(link_name="llvm.memcpy.p0i8.p0i8.i32")
|
||||
llvm_memcpy :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) ---;
|
||||
}
|
||||
}
|
||||
llvm_memcpy(dst, src, len, 1, false);
|
||||
return dst;
|
||||
}
|
||||
compare :: proc "contextless" (a, b: []byte) -> int {
|
||||
return __mem_compare(&a[0], &b[0], min(len(a), len(b)));
|
||||
return compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
|
||||
}
|
||||
compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int {
|
||||
pa :: ptr_offset;
|
||||
for i in 0..n-1 do switch {
|
||||
case pa(a, i)^ < pa(b, i)^: return -1;
|
||||
case pa(a, i)^ > pa(b, i)^: return +1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
compare_ptrs :: inline proc "contextless" (a, b: rawptr, n: int) -> int {
|
||||
return compare_byte_ptrs((^byte)(a), (^byte)(b), n);
|
||||
}
|
||||
|
||||
ptr_offset :: proc "contextless" (ptr: $P/^$T, n: int) -> P {
|
||||
new := int(uintptr(ptr)) + size_of(T)*n;
|
||||
return P(uintptr(new));
|
||||
}
|
||||
|
||||
ptr_sub :: proc "contextless" (a, b: $P/^$T) -> int {
|
||||
return (int(uintptr(a)) - int(uintptr(b)))/size_of(T);
|
||||
}
|
||||
|
||||
slice_ptr :: proc "contextless" (ptr: ^$T, len: int) -> []T {
|
||||
assert(len >= 0);
|
||||
slice := raw.Slice{data = ptr, len = len};
|
||||
slice := Raw_Slice{data = ptr, len = len};
|
||||
return transmute([]T)slice;
|
||||
}
|
||||
|
||||
slice_to_bytes :: proc "contextless" (slice: $E/[]$T) -> []byte {
|
||||
s := transmute(raw.Slice)slice;
|
||||
s := transmute(Raw_Slice)slice;
|
||||
s.len *= size_of(T);
|
||||
return transmute([]byte)s;
|
||||
}
|
||||
|
||||
|
||||
buffer_from_slice :: proc(backing: $T/[]$E) -> [dynamic]E {
|
||||
s := transmute(Raw_Slice)backing;
|
||||
d := Raw_Dynamic_Array{
|
||||
data = s.data,
|
||||
len = 0,
|
||||
cap = s.len,
|
||||
allocator = nil_allocator(),
|
||||
};
|
||||
return transmute([dynamic]E)d;
|
||||
}
|
||||
|
||||
ptr_to_bytes :: proc "contextless" (ptr: ^$T, len := 1) -> []byte {
|
||||
assert(len >= 0);
|
||||
return transmute([]byte)raw.Slice{ptr, len*size_of(T)};
|
||||
assert(len >= 0);
|
||||
return transmute([]byte)Raw_Slice{ptr, len*size_of(T)};
|
||||
}
|
||||
|
||||
any_to_bytes :: proc "contextless" (val: any) -> []byte {
|
||||
ti := type_info_of(val.typeid);
|
||||
size := ti != nil ? ti.size : 0;
|
||||
return transmute([]byte)Raw_Slice{val.data, size};
|
||||
}
|
||||
|
||||
|
||||
@@ -69,26 +144,26 @@ AllocationHeader :: struct {size: int};
|
||||
|
||||
allocation_header_fill :: proc(header: ^AllocationHeader, data: rawptr, size: int) {
|
||||
header.size = size;
|
||||
ptr := cast(^uint)(header+1);
|
||||
n := cast(^uint)data - ptr;
|
||||
ptr := cast(^uint)(ptr_offset(header, 1));
|
||||
n := ptr_sub(cast(^uint)data, ptr);
|
||||
|
||||
for i in 0..n {
|
||||
(ptr+i)^ = ~uint(0);
|
||||
for i in 0..n-1 {
|
||||
ptr_offset(ptr, i)^ = ~uint(0);
|
||||
}
|
||||
}
|
||||
allocation_header :: proc(data: rawptr) -> ^AllocationHeader {
|
||||
if data == nil do return nil;
|
||||
p := cast(^uint)data;
|
||||
for (p-1)^ == ~uint(0) do p = (p-1);
|
||||
return cast(^AllocationHeader)(p-1);
|
||||
for ptr_offset(p, -1)^ == ~uint(0) do p = ptr_offset(p, -1);
|
||||
return (^AllocationHeader)(ptr_offset(p, -1));
|
||||
}
|
||||
|
||||
|
||||
Fixed_Byte_Buffer :: distinct [dynamic]byte;
|
||||
|
||||
make_fixed_byte_buffer :: proc(backing: []byte) -> Fixed_Byte_Buffer {
|
||||
s := transmute(raw.Slice)backing;
|
||||
d: raw.Dynamic_Array;
|
||||
s := transmute(Raw_Slice)backing;
|
||||
d: Raw_Dynamic_Array;
|
||||
d.data = s.data;
|
||||
d.len = 0;
|
||||
d.cap = s.len;
|
||||
@@ -128,7 +203,7 @@ init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||
}
|
||||
|
||||
|
||||
context_from_allocator :: proc(a: Allocator) -> Context {
|
||||
context_from_allocator :: proc(a: Allocator) -> runtime.Context {
|
||||
c := context;
|
||||
c.allocator = a;
|
||||
return c;
|
||||
@@ -136,12 +211,11 @@ context_from_allocator :: proc(a: Allocator) -> Context {
|
||||
|
||||
destroy_arena :: proc(using a: ^Arena) {
|
||||
if backing.procedure != nil {
|
||||
context <- context_from_allocator(backing) {
|
||||
if memory != nil {
|
||||
free(&memory[0]);
|
||||
}
|
||||
memory = nil;
|
||||
context = context_from_allocator(backing);
|
||||
if memory != nil {
|
||||
free(&memory[0]);
|
||||
}
|
||||
memory = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,15 +244,15 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
#no_bounds_check end := &arena.memory[len(arena.memory)];
|
||||
|
||||
ptr := align_forward(end, uintptr(alignment));
|
||||
(^raw.Slice)(&arena.memory).len += total_size;
|
||||
(^Raw_Slice)(&arena.memory).len += total_size;
|
||||
return zero(ptr, size);
|
||||
|
||||
case Free:
|
||||
// NOTE(bill): Free all at once
|
||||
// Use ArenaTempMemory if you want to free a block
|
||||
|
||||
case FreeAll:
|
||||
(^raw.Slice)(&arena.memory).len = 0;
|
||||
case Free_All:
|
||||
(^Raw_Slice)(&arena.memory).len = 0;
|
||||
|
||||
case Resize:
|
||||
return default_resize_align(old_memory, old_size, size, alignment);
|
||||
@@ -198,117 +272,13 @@ begin_arena_temp_memory :: proc(a: ^Arena) -> ArenaTempMemory {
|
||||
end_arena_temp_memory :: proc(using tmp: ArenaTempMemory) {
|
||||
assert(len(arena.memory) >= original_count);
|
||||
assert(arena.temp_count > 0);
|
||||
(^raw.Dynamic_Array)(&arena.memory).len = original_count;
|
||||
(^Raw_Dynamic_Array)(&arena.memory).len = original_count;
|
||||
arena.temp_count -= 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
align_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
prev_pow2 :: proc(n: i64) -> i64 {
|
||||
if n <= 0 do return 0;
|
||||
n |= n >> 1;
|
||||
n |= n >> 2;
|
||||
n |= n >> 4;
|
||||
n |= n >> 8;
|
||||
n |= n >> 16;
|
||||
n |= n >> 32;
|
||||
return n - (n >> 1);
|
||||
}
|
||||
|
||||
WORD_SIZE :: size_of(int);
|
||||
MAX_ALIGN :: 2*align_of(rawptr); // TODO(bill): Should these constants be builtin constants?
|
||||
switch info in type_info.variant {
|
||||
case Type_Info_Named:
|
||||
return align_of_type_info(info.base);
|
||||
case Type_Info_Integer:
|
||||
return type_info.align;
|
||||
case Type_Info_Rune:
|
||||
return type_info.align;
|
||||
case Type_Info_Float:
|
||||
return type_info.align;
|
||||
case Type_Info_String:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Boolean:
|
||||
return 1;
|
||||
case Type_Info_Any:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Pointer:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Procedure:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Array:
|
||||
return align_of_type_info(info.elem);
|
||||
case Type_Info_Dynamic_Array:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Slice:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Tuple:
|
||||
return type_info.align;
|
||||
case Type_Info_Struct:
|
||||
return type_info.align;
|
||||
case Type_Info_Union:
|
||||
return type_info.align;
|
||||
case Type_Info_Enum:
|
||||
return align_of_type_info(info.base);
|
||||
case Type_Info_Map:
|
||||
return align_of_type_info(info.generated_struct);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
align_formula :: proc(size, align: int) -> int {
|
||||
result := size + align-1;
|
||||
return result - result%align;
|
||||
}
|
||||
|
||||
size_of_type_info :: proc(type_info: ^Type_Info) -> int {
|
||||
WORD_SIZE :: size_of(int);
|
||||
switch info in type_info.variant {
|
||||
case Type_Info_Named:
|
||||
return size_of_type_info(info.base);
|
||||
case Type_Info_Integer:
|
||||
return type_info.size;
|
||||
case Type_Info_Rune:
|
||||
return type_info.size;
|
||||
case Type_Info_Float:
|
||||
return type_info.size;
|
||||
case Type_Info_String:
|
||||
return 2*WORD_SIZE;
|
||||
case Type_Info_Boolean:
|
||||
return 1;
|
||||
case Type_Info_Any:
|
||||
return 2*WORD_SIZE;
|
||||
case Type_Info_Pointer:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Procedure:
|
||||
return WORD_SIZE;
|
||||
case Type_Info_Array:
|
||||
count := info.count;
|
||||
if count == 0 do return 0;
|
||||
size := size_of_type_info(info.elem);
|
||||
align := align_of_type_info(info.elem);
|
||||
alignment := align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
case Type_Info_Dynamic_Array:
|
||||
return size_of(rawptr) + 2*size_of(int) + size_of(Allocator);
|
||||
case Type_Info_Slice:
|
||||
return 2*WORD_SIZE;
|
||||
case Type_Info_Struct:
|
||||
return type_info.size;
|
||||
case Type_Info_Union:
|
||||
return type_info.size;
|
||||
case Type_Info_Enum:
|
||||
return size_of_type_info(info.base);
|
||||
case Type_Info_Map:
|
||||
return size_of_type_info(info.generated_struct);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package mem
|
||||
|
||||
Raw_Any :: struct {
|
||||
data: rawptr,
|
||||
typeid: typeid,
|
||||
}
|
||||
|
||||
Raw_String :: struct {
|
||||
data: ^byte,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Raw_Cstring :: struct {
|
||||
data: ^byte,
|
||||
}
|
||||
|
||||
Raw_Slice :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Raw_Dynamic_Array :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
cap: int,
|
||||
allocator: Allocator,
|
||||
}
|
||||
|
||||
Raw_Map :: struct {
|
||||
hashes: [dynamic]int,
|
||||
entries: Raw_Dynamic_Array,
|
||||
}
|
||||
|
||||
|
||||
make_any :: inline proc(data: rawptr, id: typeid) -> any {
|
||||
return transmute(any)Raw_Any{data, id};
|
||||
}
|
||||
|
||||
raw_string_data :: inline proc(s: $T/string) -> ^byte {
|
||||
return (^Raw_String)(&s).data;
|
||||
}
|
||||
raw_slice_data :: inline proc(a: $T/[]$E) -> ^E {
|
||||
return cast(^E)(^Raw_Slice)(&a).data;
|
||||
}
|
||||
raw_dynamic_array_data :: inline proc(a: $T/[dynamic]$E) -> ^E {
|
||||
return cast(^E)(^Raw_Dynamic_Array)(&a).data;
|
||||
}
|
||||
|
||||
raw_data :: proc[raw_string_data, raw_slice_data, raw_dynamic_array_data];
|
||||
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
when ODIN_OS == "windows" {
|
||||
foreign import lib "system:opengl32.lib"
|
||||
import win32 "core:sys/windows.odin"
|
||||
import "core:sys/wgl.odin"
|
||||
} else when ODIN_OS == "linux" {
|
||||
foreign import lib "system:gl"
|
||||
}
|
||||
|
||||
export "core:opengl_constants.odin"
|
||||
|
||||
_ := compile_assert(ODIN_OS != "osx");
|
||||
|
||||
@(default_calling_convention="c", link_prefix="gl")
|
||||
foreign lib {
|
||||
Clear :: proc(mask: u32) ---;
|
||||
ClearColor :: proc(r, g, b, a: f32) ---;
|
||||
Begin :: proc(mode: i32) ---;
|
||||
End :: proc() ---;
|
||||
Finish :: proc() ---;
|
||||
BlendFunc :: proc(sfactor, dfactor: i32) ---;
|
||||
Enable :: proc(cap: i32) ---;
|
||||
Disable :: proc(cap: i32) ---;
|
||||
GenTextures :: proc(count: i32, result: ^u32) ---;
|
||||
DeleteTextures :: proc(count: i32, result: ^u32) ---;
|
||||
TexParameteri :: proc(target, pname, param: i32) ---;
|
||||
TexParameterf :: proc(target: i32, pname: i32, param: f32) ---;
|
||||
BindTexture :: proc(target: i32, texture: u32) ---;
|
||||
LoadIdentity :: proc() ---;
|
||||
Viewport :: proc(x, y, width, height: i32) ---;
|
||||
Ortho :: proc(left, right, bottom, top, near, far: f64) ---;
|
||||
Color3f :: proc(r, g, b: f32) ---;
|
||||
Vertex3f :: proc(x, y, z: f32) ---;
|
||||
GetError :: proc() -> i32 ---;
|
||||
GetString :: proc(name: i32) -> ^u8 ---;
|
||||
GetIntegerv :: proc(name: i32, v: ^i32) ---;
|
||||
TexCoord2f :: proc(x, y: f32) ---;
|
||||
TexImage2D :: proc(target, level, internal_format: i32,
|
||||
width, height, border: i32,
|
||||
format, type_: i32, pixels: rawptr) ---;
|
||||
}
|
||||
|
||||
|
||||
_string_data :: inline proc(s: string) -> ^u8 do return &s[0];
|
||||
|
||||
_libgl := win32.load_library_a(_string_data("opengl32.dll\x00"));
|
||||
|
||||
get_gl_proc_address :: proc(name: string) -> rawptr {
|
||||
if name[len(name)-1] == 0 {
|
||||
name = name[..len(name)-1];
|
||||
}
|
||||
// NOTE(bill): null terminated
|
||||
assert((&name[0] + len(name))^ == 0);
|
||||
res := wgl.get_gl_proc_address(&name[0]);
|
||||
if res == nil {
|
||||
res = win32.get_proc_address(_libgl, &name[0]);
|
||||
}
|
||||
return rawptr(res);
|
||||
}
|
||||
|
||||
// Procedures
|
||||
GenBuffers: proc "c" (count: i32, buffers: ^u32);
|
||||
GenVertexArrays: proc "c" (count: i32, buffers: ^u32);
|
||||
GenSamplers: proc "c" (count: i32, buffers: ^u32);
|
||||
DeleteBuffers: proc "c" (count: i32, buffers: ^u32);
|
||||
BindBuffer: proc "c" (target: i32, buffer: u32);
|
||||
BindVertexArray: proc "c" (buffer: u32);
|
||||
DeleteVertexArrays: proc "c" (count: i32, arrays: ^u32);
|
||||
BindSampler: proc "c" (position: i32, sampler: u32);
|
||||
BufferData: proc "c" (target: i32, size: int, data: rawptr, usage: i32);
|
||||
BufferSubData: proc "c" (target: i32, offset, size: int, data: rawptr);
|
||||
|
||||
DrawArrays: proc "c" (mode, first: i32, count: u32);
|
||||
DrawElements: proc "c" (mode: i32, count: u32, type_: i32, indices: rawptr);
|
||||
|
||||
MapBuffer: proc "c" (target, access: i32) -> rawptr;
|
||||
UnmapBuffer: proc "c" (target: i32);
|
||||
|
||||
VertexAttribPointer: proc "c" (index: u32, size, type_: i32, normalized: i32, stride: u32, pointer: rawptr);
|
||||
EnableVertexAttribArray: proc "c" (index: u32);
|
||||
|
||||
CreateShader: proc "c" (shader_type: i32) -> u32;
|
||||
ShaderSource: proc "c" (shader: u32, count: u32, str: ^^u8, length: ^i32);
|
||||
CompileShader: proc "c" (shader: u32);
|
||||
CreateProgram: proc "c" () -> u32;
|
||||
AttachShader: proc "c" (program, shader: u32);
|
||||
DetachShader: proc "c" (program, shader: u32);
|
||||
DeleteShader: proc "c" (shader: u32);
|
||||
LinkProgram: proc "c" (program: u32);
|
||||
UseProgram: proc "c" (program: u32);
|
||||
DeleteProgram: proc "c" (program: u32);
|
||||
|
||||
|
||||
GetShaderiv: proc "c" (shader: u32, pname: i32, params: ^i32);
|
||||
GetProgramiv: proc "c" (program: u32, pname: i32, params: ^i32);
|
||||
GetShaderInfoLog: proc "c" (shader: u32, max_length: u32, length: ^u32, info_long: ^u8);
|
||||
GetProgramInfoLog: proc "c" (program: u32, max_length: u32, length: ^u32, info_long: ^u8);
|
||||
|
||||
ActiveTexture: proc "c" (texture: i32);
|
||||
GenerateMipmap: proc "c" (target: i32);
|
||||
|
||||
SamplerParameteri: proc "c" (sampler: u32, pname: i32, param: i32);
|
||||
SamplerParameterf: proc "c" (sampler: u32, pname: i32, param: f32);
|
||||
SamplerParameteriv: proc "c" (sampler: u32, pname: i32, params: ^i32);
|
||||
SamplerParameterfv: proc "c" (sampler: u32, pname: i32, params: ^f32);
|
||||
SamplerParameterIiv: proc "c" (sampler: u32, pname: i32, params: ^i32);
|
||||
SamplerParameterIuiv: proc "c" (sampler: u32, pname: i32, params: ^u32);
|
||||
|
||||
|
||||
Uniform1i: proc "c" (loc: i32, v0: i32);
|
||||
Uniform2i: proc "c" (loc: i32, v0, v1: i32);
|
||||
Uniform3i: proc "c" (loc: i32, v0, v1, v2: i32);
|
||||
Uniform4i: proc "c" (loc: i32, v0, v1, v2, v3: i32);
|
||||
Uniform1f: proc "c" (loc: i32, v0: f32);
|
||||
Uniform2f: proc "c" (loc: i32, v0, v1: f32);
|
||||
Uniform3f: proc "c" (loc: i32, v0, v1, v2: f32);
|
||||
Uniform4f: proc "c" (loc: i32, v0, v1, v2, v3: f32);
|
||||
UniformMatrix4fv: proc "c" (loc: i32, count: u32, transpose: i32, value: ^f32);
|
||||
|
||||
GetUniformLocation: proc "c" (program: u32, name: ^u8) -> i32;
|
||||
|
||||
|
||||
init :: proc() {
|
||||
set_proc_address :: proc(p: rawptr, name: string) {
|
||||
x := cast(^rawptr)p;
|
||||
x^ = get_gl_proc_address(name);
|
||||
}
|
||||
|
||||
set_proc_address(&GenBuffers, "glGenBuffers\x00");
|
||||
set_proc_address(&GenVertexArrays, "glGenVertexArrays\x00");
|
||||
set_proc_address(&GenSamplers, "glGenSamplers\x00");
|
||||
set_proc_address(&DeleteBuffers, "glDeleteBuffers\x00");
|
||||
set_proc_address(&BindBuffer, "glBindBuffer\x00");
|
||||
set_proc_address(&BindSampler, "glBindSampler\x00");
|
||||
set_proc_address(&BindVertexArray, "glBindVertexArray\x00");
|
||||
set_proc_address(&DeleteVertexArrays, "glDeleteVertexArrays\x00");
|
||||
set_proc_address(&BufferData, "glBufferData\x00");
|
||||
set_proc_address(&BufferSubData, "glBufferSubData\x00");
|
||||
|
||||
set_proc_address(&DrawArrays, "glDrawArrays\x00");
|
||||
set_proc_address(&DrawElements, "glDrawElements\x00");
|
||||
|
||||
set_proc_address(&MapBuffer, "glMapBuffer\x00");
|
||||
set_proc_address(&UnmapBuffer, "glUnmapBuffer\x00");
|
||||
|
||||
set_proc_address(&VertexAttribPointer, "glVertexAttribPointer\x00");
|
||||
set_proc_address(&EnableVertexAttribArray, "glEnableVertexAttribArray\x00");
|
||||
|
||||
set_proc_address(&CreateShader, "glCreateShader\x00");
|
||||
set_proc_address(&ShaderSource, "glShaderSource\x00");
|
||||
set_proc_address(&CompileShader, "glCompileShader\x00");
|
||||
set_proc_address(&CreateProgram, "glCreateProgram\x00");
|
||||
set_proc_address(&AttachShader, "glAttachShader\x00");
|
||||
set_proc_address(&DetachShader, "glDetachShader\x00");
|
||||
set_proc_address(&DeleteShader, "glDeleteShader\x00");
|
||||
set_proc_address(&LinkProgram, "glLinkProgram\x00");
|
||||
set_proc_address(&UseProgram, "glUseProgram\x00");
|
||||
set_proc_address(&DeleteProgram, "glDeleteProgram\x00");
|
||||
|
||||
set_proc_address(&GetShaderiv, "glGetShaderiv\x00");
|
||||
set_proc_address(&GetProgramiv, "glGetProgramiv\x00");
|
||||
set_proc_address(&GetShaderInfoLog, "glGetShaderInfoLog\x00");
|
||||
set_proc_address(&GetProgramInfoLog, "glGetProgramInfoLog\x00");
|
||||
|
||||
set_proc_address(&ActiveTexture, "glActiveTexture\x00");
|
||||
set_proc_address(&GenerateMipmap, "glGenerateMipmap\x00");
|
||||
|
||||
set_proc_address(&Uniform1i, "glUniform1i\x00");
|
||||
set_proc_address(&UniformMatrix4fv, "glUniformMatrix4fv\x00");
|
||||
|
||||
set_proc_address(&GetUniformLocation, "glGetUniformLocation\x00");
|
||||
|
||||
set_proc_address(&SamplerParameteri, "glSamplerParameteri\x00");
|
||||
set_proc_address(&SamplerParameterf, "glSamplerParameterf\x00");
|
||||
set_proc_address(&SamplerParameteriv, "glSamplerParameteriv\x00");
|
||||
set_proc_address(&SamplerParameterfv, "glSamplerParameterfv\x00");
|
||||
set_proc_address(&SamplerParameterIiv, "glSamplerParameterIiv\x00");
|
||||
set_proc_address(&SamplerParameterIuiv, "glSamplerParameterIuiv\x00");
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,6 @@
|
||||
when ODIN_OS == "windows" do export "core:os_windows.odin";
|
||||
when ODIN_OS == "osx" do export "core:os_x.odin";
|
||||
when ODIN_OS == "linux" do export "core:os_linux.odin";
|
||||
when ODIN_OS == "essence" do export "core:os_essence.odin";
|
||||
package os
|
||||
|
||||
import "mem.odin";
|
||||
import "core:mem"
|
||||
|
||||
write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
|
||||
return write(fd, cast([]byte)str);
|
||||
@@ -37,10 +34,10 @@ read_entire_file :: proc(name: string) -> (data: []byte, success: bool) {
|
||||
|
||||
bytes_read, read_err := read(fd, data);
|
||||
if read_err != 0 {
|
||||
free(data);
|
||||
delete(data);
|
||||
return nil, false;
|
||||
}
|
||||
return data[0..bytes_read], true;
|
||||
return data[0:bytes_read], true;
|
||||
}
|
||||
|
||||
write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (success: bool) {
|
||||
@@ -59,9 +56,44 @@ write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (succ
|
||||
}
|
||||
|
||||
write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
||||
return write(fd, mem.slice_ptr(cast(^byte)data, len));
|
||||
s := transmute([]byte)mem.Raw_Slice{data, len};
|
||||
return write(fd, s);
|
||||
}
|
||||
|
||||
read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
|
||||
return read(fd, mem.slice_ptr(cast(^byte)data, len));
|
||||
s := transmute([]byte)mem.Raw_Slice{data, len};
|
||||
return read(fd, s);
|
||||
}
|
||||
|
||||
|
||||
heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
size, alignment: int,
|
||||
old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
|
||||
using mem.Allocator_Mode;
|
||||
|
||||
switch mode {
|
||||
case Alloc:
|
||||
return heap_alloc(size);
|
||||
|
||||
case Free:
|
||||
heap_free(old_memory);
|
||||
return nil;
|
||||
|
||||
case Free_All:
|
||||
// NOTE(bill): Does nothing
|
||||
|
||||
case Resize:
|
||||
ptr := heap_resize(old_memory, size);
|
||||
assert(ptr != nil);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
heap_allocator :: proc() -> mem.Allocator {
|
||||
return mem.Allocator{
|
||||
procedure = heap_allocator_proc,
|
||||
data = nil,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package os;
|
||||
|
||||
ARCH :: "x86";
|
||||
ENDIAN :: "little";
|
||||
@@ -0,0 +1,4 @@
|
||||
package os;
|
||||
|
||||
ARCH :: "amd64";
|
||||
ENDIAN :: "little";
|
||||
@@ -0,0 +1,176 @@
|
||||
package os
|
||||
|
||||
OS :: "essence";
|
||||
|
||||
foreign import api "system:api"
|
||||
|
||||
Handle :: distinct int;
|
||||
Errno :: distinct int;
|
||||
|
||||
O_RDONLY :: 0x00001;
|
||||
O_WRONLY :: 0x00002;
|
||||
O_RDWR :: 0x00003;
|
||||
O_CREATE :: 0x00040;
|
||||
O_EXCL :: 0x00080;
|
||||
O_TRUNC :: 0x00200;
|
||||
O_APPEND :: 0x00400;
|
||||
|
||||
ERROR_NONE :: Errno(-1);
|
||||
ERROR_UNKNOWN_OPERATION_FAILURE :: Errno(-7);
|
||||
ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: Errno(-14);
|
||||
ERROR_PATH_NOT_FOUND :: Errno(-15);
|
||||
ERROR_FILE_EXISTS :: Errno(-19);
|
||||
ERROR_FILE_NOT_FOUND :: Errno(-20);
|
||||
ERROR_DRIVE_ERROR_FILE_DAMAGED :: Errno(-21);
|
||||
ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: Errno(-22);
|
||||
ERROR_ACCESS_DENIED :: Errno(-23);
|
||||
ERROR_FILE_IN_EXCLUSIVE_USE :: Errno(-24);
|
||||
ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: Errno(-25);
|
||||
ERROR_INCORRECT_NODE_TYPE :: Errno(-26);
|
||||
ERROR_EVENT_NOT_SET :: Errno(-27);
|
||||
ERROR_TIMEOUT_REACHED :: Errno(-29);
|
||||
ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: Errno(-30);
|
||||
ERROR_NO_CHARACTER_AT_COORDINATE :: Errno(-31);
|
||||
ERROR_FILE_ON_READ_ONLY_VOLUME :: Errno(-32);
|
||||
ERROR_USER_CANCELED_IO :: Errno(-33);
|
||||
ERROR_DRIVE_CONTROLLER_REPORTED :: Errno(-35);
|
||||
ERROR_COULD_NOT_ISSUE_PACKET :: Errno(-36);
|
||||
|
||||
ERROR_NOT_IMPLEMENTED :: Errno(1);
|
||||
|
||||
OS_Node_Type :: enum i32 {
|
||||
File = 0,
|
||||
Directory = 1,
|
||||
}
|
||||
|
||||
OS_Node_Information :: struct {
|
||||
handle: Handle,
|
||||
id: [16]byte,
|
||||
ntype: OS_Node_Type,
|
||||
size: i64,
|
||||
|
||||
// Our additions..
|
||||
position: i64,
|
||||
}
|
||||
|
||||
foreign api {
|
||||
@(link_name="OSPrintDirect") OSPrintDirect :: proc(str: ^u8, length: int) ---;
|
||||
@(link_name="malloc") OSMalloc :: proc(bytes: int) -> rawptr ---;
|
||||
@(link_name="free") OSFree :: proc(address: rawptr) ---;
|
||||
@(link_name="OSOpenNode") OSOpenNode :: proc(path: ^u8, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---;
|
||||
@(link_name="OSResizeFile") OSResizeFile :: proc(handle: Handle, new_size: u64) -> Errno ---;
|
||||
@(link_name="OSCloseHandle") OSCloseHandle :: proc(handle: Handle) ---;
|
||||
@(link_name="OSWriteFileSync") OSWriteFileSync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
|
||||
@(link_name="OSReadFileSync") OSReadFileSync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
|
||||
@(link_name="realloc") OSRealloc :: proc(address: rawptr, size: int) -> rawptr ---;
|
||||
@(link_name="OSGetThreadID") OSGetThreadID :: proc(handle: Handle) -> int ---;
|
||||
@(link_name="OSRefreshNodeInformation") OSRefreshNodeInformation :: proc(information: ^OS_Node_Information) ---;
|
||||
}
|
||||
|
||||
stdin := Handle(-1); // Not implemented
|
||||
stdout := Handle(0);
|
||||
stderr := Handle(0);
|
||||
|
||||
current_thread_id :: proc() -> int {
|
||||
return OSGetThreadID(Handle(0x1000));
|
||||
}
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
return OSMalloc(size);
|
||||
}
|
||||
|
||||
heap_free :: proc(address: rawptr) {
|
||||
OSFree(address);
|
||||
}
|
||||
|
||||
heap_resize :: proc(address: rawptr, new_size: int) -> rawptr {
|
||||
return OSRealloc(address, new_size);
|
||||
}
|
||||
|
||||
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
flags : u64 = 0;
|
||||
|
||||
if mode & O_CREATE == O_CREATE {
|
||||
flags = flags | 0x9000; // Fail if found and create directories leading to the file if they don't exist
|
||||
} else {
|
||||
flags = flags | 0x2000; // Fail if not found
|
||||
}
|
||||
|
||||
if mode & O_EXCL == O_EXCL {
|
||||
flags = flags | 0x111; // Block opening the node for any reason
|
||||
}
|
||||
|
||||
if mode & O_RDONLY == O_RDONLY {
|
||||
flags = flags | 0x2; // Read access
|
||||
}
|
||||
|
||||
if mode & O_WRONLY == O_WRONLY {
|
||||
flags = flags | 0x220; // Write and resize access
|
||||
}
|
||||
|
||||
if mode & O_TRUNC == O_TRUNC {
|
||||
flags = flags | 0x200; // Resize access
|
||||
}
|
||||
|
||||
information := new(OS_Node_Information);
|
||||
error := OSOpenNode(&path[0], len(path), flags, information);
|
||||
|
||||
if error < ERROR_NONE {
|
||||
free(information);
|
||||
return 0, error;
|
||||
}
|
||||
|
||||
if mode & O_TRUNC == O_TRUNC {
|
||||
error := OSResizeFile(information.handle, 0);
|
||||
if error < ERROR_NONE do return 0, ERROR_UNKNOWN_OPERATION_FAILURE;
|
||||
}
|
||||
|
||||
if mode & O_APPEND == O_APPEND {
|
||||
information.position = information.size;
|
||||
} else {
|
||||
information.position = 0;
|
||||
}
|
||||
|
||||
return Handle(uintptr(information)), ERROR_NONE;
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) {
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
OSCloseHandle(information.handle);
|
||||
free(information);
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
x: OS_Node_Information;
|
||||
OSRefreshNodeInformation(&x);
|
||||
return x.size, ERROR_NONE;
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if fd == 0 {
|
||||
OSPrintDirect(&data[0], len(data));
|
||||
return len(data), ERROR_NONE;
|
||||
} else if fd == 1 {
|
||||
assert(false);
|
||||
return 0, ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
count := OSWriteFileSync(information.handle, information.position, i64(len(data)), &data[0]);
|
||||
if count < 0 do return 0, 1;
|
||||
information.position += count;
|
||||
return int(count), 0;
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if (fd == 0 || fd == 1) {
|
||||
assert(false);
|
||||
return 0, ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
count := OSReadFileSync(information.handle, information.position, i64(len(data)), &data[0]);
|
||||
if count < 0 do return 0, ERROR_UNKNOWN_OPERATION_FAILURE;
|
||||
information.position += count;
|
||||
return int(count), ERROR_NONE;
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package os
|
||||
|
||||
foreign import dl "system:dl"
|
||||
foreign import libc "system:c"
|
||||
|
||||
import "core:strings.odin"
|
||||
import "core:mem.odin"
|
||||
import "core:runtime"
|
||||
import "core:strings"
|
||||
|
||||
OS :: "linux";
|
||||
|
||||
Handle :: distinct i32;
|
||||
File_Time :: distinct u64;
|
||||
@@ -70,7 +74,7 @@ Stat :: struct {
|
||||
_reserve1,
|
||||
_reserve2,
|
||||
_reserve3: i64,
|
||||
serial_numbe: u64, // File serial number...? Maybe.
|
||||
serial_numbe: u64, // File serial number..? Maybe.
|
||||
_reserve4: i64,
|
||||
};
|
||||
|
||||
@@ -122,36 +126,35 @@ W_OK :: 2; // Test for write permission
|
||||
R_OK :: 4; // Test for read permission
|
||||
|
||||
foreign libc {
|
||||
@(link_name="open") _unix_open :: proc(path: ^byte, mode: int) -> Handle ---;
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, mode: int) -> Handle ---;
|
||||
@(link_name="close") _unix_close :: proc(fd: Handle) -> i32 ---;
|
||||
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
|
||||
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int ---;
|
||||
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---;
|
||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
|
||||
@(link_name="stat") _unix_stat :: proc(path: ^byte, stat: ^Stat) -> i32 ---;
|
||||
@(link_name="access") _unix_access :: proc(path: ^byte, mask: int) -> i32 ---;
|
||||
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> i32 ---;
|
||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> i32 ---;
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(^byte) -> ^byte ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---;
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: int) ---;
|
||||
}
|
||||
foreign dl {
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^byte, flags: int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^byte) -> rawptr ---;
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> ^byte ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
|
||||
}
|
||||
|
||||
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
||||
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
|
||||
|
||||
cstr := strings.new_c_string(path);
|
||||
cstr := strings.new_cstring(path);
|
||||
handle := _unix_open(cstr, mode);
|
||||
free(cstr);
|
||||
delete(cstr);
|
||||
if(handle == -1) {
|
||||
return 0, 1;
|
||||
}
|
||||
@@ -201,8 +204,8 @@ last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||
*/
|
||||
|
||||
stat :: inline proc(path: string) -> (Stat, int) {
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(path);
|
||||
defer delete(cstr);
|
||||
|
||||
s: Stat;
|
||||
ret_int := _unix_stat(cstr, &s);
|
||||
@@ -210,8 +213,8 @@ stat :: inline proc(path: string) -> (Stat, int) {
|
||||
}
|
||||
|
||||
access :: inline proc(path: string, mask: int) -> bool {
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(path);
|
||||
defer delete(cstr);
|
||||
return _unix_access(cstr, mask) == 0;
|
||||
}
|
||||
|
||||
@@ -229,13 +232,13 @@ heap_free :: proc(ptr: rawptr) {
|
||||
}
|
||||
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.new_c_string(name);
|
||||
defer free(path_str);
|
||||
path_str := strings.new_cstring(name);
|
||||
defer delete(path_str);
|
||||
cstr := _unix_getenv(path_str);
|
||||
if cstr == nil {
|
||||
return "", false;
|
||||
}
|
||||
return strings.to_odin_string(cstr), true;
|
||||
return string(cstr), true;
|
||||
}
|
||||
|
||||
exit :: proc(code: int) {
|
||||
@@ -248,15 +251,15 @@ current_thread_id :: proc() -> int {
|
||||
}
|
||||
|
||||
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
|
||||
cstr := strings.new_c_string(filename);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(filename);
|
||||
defer delete(cstr);
|
||||
handle := _unix_dlopen(cstr, flags);
|
||||
return handle;
|
||||
}
|
||||
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil);
|
||||
cstr := strings.new_c_string(symbol);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(symbol);
|
||||
defer delete(cstr);
|
||||
proc_handle := _unix_dlsym(handle, cstr);
|
||||
return proc_handle;
|
||||
}
|
||||
@@ -265,14 +268,14 @@ dlclose :: inline proc(handle: rawptr) -> bool {
|
||||
return _unix_dlclose(handle) == 0;
|
||||
}
|
||||
dlerror :: proc() -> string {
|
||||
return strings.to_odin_string(_unix_dlerror());
|
||||
return string(_unix_dlerror());
|
||||
}
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
args := make([]string, __argc__);
|
||||
for i in 0..__argc__ {
|
||||
args[i] = strings.to_odin_string((__argv__+i)^);
|
||||
args := make([]string, len(runtime.args__));
|
||||
for arg, i in runtime.args__ {
|
||||
args[i] = string(arg);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package os
|
||||
|
||||
foreign import dl "system:dl"
|
||||
foreign import libc "system:c"
|
||||
|
||||
import "core:strings.odin"
|
||||
import "core:mem.odin"
|
||||
import "core:runtime"
|
||||
import "core:strings"
|
||||
|
||||
OS :: "osx";
|
||||
|
||||
Handle :: distinct i32;
|
||||
File_Time :: distinct u64;
|
||||
@@ -69,7 +73,7 @@ Stat :: struct {
|
||||
blocks: i64, // Number of blocks allocated for the file
|
||||
block_size: i32, // Optimal blocksize for I/O
|
||||
flags: u32, // User-defined flags for the file
|
||||
gen_num: u32, // File generation number ...?
|
||||
gen_num: u32, // File generation number ..?
|
||||
_spare: i32, // RESERVED
|
||||
_reserve1,
|
||||
_reserve2: i64, // RESERVED
|
||||
@@ -122,35 +126,35 @@ X_OK :: 1; // Test for execute permission
|
||||
F_OK :: 0; // Test for file existance
|
||||
|
||||
foreign libc {
|
||||
@(link_name="open") _unix_open :: proc(path: ^byte, mode: int) -> Handle ---;
|
||||
@(link_name="open") _unix_open :: proc(path: cstring, mode: int) -> Handle ---;
|
||||
@(link_name="close") _unix_close :: proc(handle: Handle) ---;
|
||||
@(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
|
||||
@(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---;
|
||||
@(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int ---;
|
||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---;
|
||||
@(link_name="stat") _unix_stat :: proc(path: ^byte, stat: ^Stat) -> int ---;
|
||||
@(link_name="access") _unix_access :: proc(path: ^byte, mask: int) -> int ---;
|
||||
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> int ---;
|
||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---;
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---;
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---;
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---;
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(^byte) -> ^byte ---;
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---;
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: int) ---;
|
||||
}
|
||||
|
||||
foreign dl {
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: ^byte, flags: int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: ^byte) -> rawptr ---;
|
||||
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr ---;
|
||||
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---;
|
||||
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> ^byte ---;
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---;
|
||||
}
|
||||
|
||||
// TODO(zangent): Change this to just `open` when Bill fixes overloading.
|
||||
open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(path);
|
||||
defer delete(cstr);
|
||||
handle := _unix_open(cstr, mode);
|
||||
if handle == -1 {
|
||||
return 0, 1;
|
||||
@@ -218,15 +222,15 @@ last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||
|
||||
stat :: inline proc(path: string) -> (Stat, bool) {
|
||||
s: Stat;
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(path);
|
||||
defer delete(cstr);
|
||||
ret_int := _unix_stat(cstr, &s);
|
||||
return s, ret_int==0;
|
||||
}
|
||||
|
||||
access :: inline proc(path: string, mask: int) -> bool {
|
||||
cstr := strings.new_c_string(path);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(path);
|
||||
defer delete(cstr);
|
||||
return _unix_access(cstr, mask) == 0;
|
||||
}
|
||||
|
||||
@@ -242,13 +246,13 @@ heap_free :: inline proc(ptr: rawptr) {
|
||||
}
|
||||
|
||||
getenv :: proc(name: string) -> (string, bool) {
|
||||
path_str := strings.new_c_string(name);
|
||||
defer free(path_str);
|
||||
path_str := strings.new_cstring(name);
|
||||
defer delete(path_str);
|
||||
cstr := _unix_getenv(path_str);
|
||||
if cstr == nil {
|
||||
return "", false;
|
||||
}
|
||||
return strings.to_odin_string(cstr), true;
|
||||
return string(cstr), true;
|
||||
}
|
||||
|
||||
exit :: inline proc(code: int) {
|
||||
@@ -262,15 +266,15 @@ current_thread_id :: proc() -> int {
|
||||
}
|
||||
|
||||
dlopen :: inline proc(filename: string, flags: int) -> rawptr {
|
||||
cstr := strings.new_c_string(filename);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(filename);
|
||||
defer delete(cstr);
|
||||
handle := _unix_dlopen(cstr, flags);
|
||||
return handle;
|
||||
}
|
||||
dlsym :: inline proc(handle: rawptr, symbol: string) -> rawptr {
|
||||
assert(handle != nil);
|
||||
cstr := strings.new_c_string(symbol);
|
||||
defer free(cstr);
|
||||
cstr := strings.new_cstring(symbol);
|
||||
defer delete(cstr);
|
||||
proc_handle := _unix_dlsym(handle, cstr);
|
||||
return proc_handle;
|
||||
}
|
||||
@@ -279,14 +283,14 @@ dlclose :: inline proc(handle: rawptr) -> bool {
|
||||
return _unix_dlclose(handle) == 0;
|
||||
}
|
||||
dlerror :: proc() -> string {
|
||||
return strings.to_odin_string(_unix_dlerror());
|
||||
return string(_unix_dlerror());
|
||||
}
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
args := make([]string, __argc__);
|
||||
for i in 0..__argc__ {
|
||||
args[i] = strings.to_odin_string((__argv__+i)^);
|
||||
args := make([]string, len(runtime.args__));
|
||||
for arg, i in runtime.args__ {
|
||||
args[i] = string(arg);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import win32 "core:sys/windows.odin"
|
||||
import "core:mem.odin"
|
||||
// +build windows
|
||||
package os
|
||||
|
||||
import "core:sys/win32"
|
||||
|
||||
OS :: "windows";
|
||||
|
||||
Handle :: distinct uintptr;
|
||||
File_Time :: distinct u64;
|
||||
@@ -96,9 +100,9 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errn
|
||||
}
|
||||
|
||||
buf: [300]byte;
|
||||
copy(buf[..], cast([]byte)path);
|
||||
copy(buf[:], cast([]byte)path);
|
||||
|
||||
handle := Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
|
||||
handle := Handle(win32.create_file_a(cstring(&buf[0]), access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
|
||||
if handle != INVALID_HANDLE do return handle, ERROR_NONE;
|
||||
|
||||
err := Errno(win32.get_last_error());
|
||||
@@ -217,9 +221,9 @@ last_write_time_by_name :: proc(name: string) -> File_Time {
|
||||
|
||||
assert(len(buf) > len(name));
|
||||
|
||||
copy(buf[..], cast([]byte)name);
|
||||
copy(buf[:], cast([]byte)name);
|
||||
|
||||
if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) {
|
||||
if win32.get_file_attributes_ex_a(cstring(&buf[0]), win32.GetFileExInfoStandard, &data) {
|
||||
last_write_time = data.last_write_time;
|
||||
}
|
||||
|
||||
@@ -260,54 +264,24 @@ current_thread_id :: proc() -> int {
|
||||
|
||||
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string {
|
||||
wstr_len := 0;
|
||||
for (wstr+wstr_len)^ != 0 do wstr_len += 1;
|
||||
|
||||
len := 2*wstr_len-1;
|
||||
buf := make([]byte, len+1);
|
||||
str := mem.slice_ptr(wstr, wstr_len+1);
|
||||
|
||||
i, j := 0, 0;
|
||||
for str[j] != 0 {
|
||||
switch {
|
||||
case str[j] < 0x80:
|
||||
if i+1 > len do return "";
|
||||
buf[i] = byte(str[j]); i += 1;
|
||||
j += 1;
|
||||
case str[j] < 0x800:
|
||||
if i+2 > len do return "";
|
||||
buf[i] = byte(0xc0 + (str[j]>>6)); i += 1;
|
||||
buf[i] = byte(0x80 + (str[j]&0x3f)); i += 1;
|
||||
j += 1;
|
||||
case 0xd800 <= str[j] && str[j] < 0xdc00:
|
||||
if i+4 > len do return "";
|
||||
c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
|
||||
buf[i] = byte(0xf0 + (c >> 18)); i += 1;
|
||||
buf[i] = byte(0x80 + ((c >> 12) & 0x3f)); i += 1;
|
||||
buf[i] = byte(0x80 + ((c >> 6) & 0x3f)); i += 1;
|
||||
buf[i] = byte(0x80 + ((c ) & 0x3f)); i += 1;
|
||||
j += 2;
|
||||
case 0xdc00 <= str[j] && str[j] < 0xe000:
|
||||
return "";
|
||||
case:
|
||||
if i+3 > len do return "";
|
||||
buf[i] = 0xe0 + byte (str[j] >> 12); i += 1;
|
||||
buf[i] = 0x80 + byte((str[j] >> 6) & 0x3f); i += 1;
|
||||
buf[i] = 0x80 + byte((str[j] ) & 0x3f); i += 1;
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return string(buf[..i]);
|
||||
}
|
||||
|
||||
arg_count: i32;
|
||||
arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
|
||||
arg_list := make([]string, int(arg_count));
|
||||
for _, i in arg_list do arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
|
||||
for _, i in arg_list {
|
||||
wc_str := (^win32.Wstring)(uintptr(arg_list_ptr) + size_of(win32.Wstring)*uintptr(i))^;
|
||||
olen := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1,
|
||||
nil, 0, nil, nil);
|
||||
|
||||
buf := make([]byte, int(olen));
|
||||
n := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1,
|
||||
cstring(&buf[0]), olen, nil, nil);
|
||||
if n > 0 {
|
||||
n -= 1;
|
||||
}
|
||||
arg_list[i] = string(buf[:n]);
|
||||
}
|
||||
|
||||
return arg_list;
|
||||
}
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
foreign import api "system:api"
|
||||
|
||||
Handle :: distinct int;
|
||||
Errno :: distinct int;
|
||||
|
||||
O_RDONLY :: 1;
|
||||
O_WRONLY :: 2;
|
||||
O_CREATE :: 4;
|
||||
O_TRUNC :: 4;
|
||||
|
||||
OS_Node_Type :: enum i32 {
|
||||
File = 0,
|
||||
Directory = 1,
|
||||
}
|
||||
|
||||
OS_Node_Information :: struct {
|
||||
handle: Handle,
|
||||
id: [16]byte,
|
||||
ntype: OS_Node_Type,
|
||||
size: i64,
|
||||
position: i64,
|
||||
}
|
||||
|
||||
foreign api {
|
||||
@(link_name="OSHelloWorld") os_hello_world :: proc() ---;
|
||||
@(link_name="OSPrintDirect") os_print_direct :: proc(string: ^byte, length: int) ---;
|
||||
@(link_name="OSHeapAllocate") os_heap_allocate :: proc(bytes: int, zero: bool) -> rawptr ---;
|
||||
@(link_name="OSHeapFree") os_heap_free :: proc(address: rawptr) ---;
|
||||
@(link_name="OSOpenNode") os_open_node :: proc(path: ^byte, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---;
|
||||
@(link_name="OSResizeFile") os_resize_file :: proc(handle: Handle, new_size: u64) -> Errno ---;
|
||||
@(link_name="OSCloseHandle") os_close_handle :: proc(handle: Handle) ---;
|
||||
@(link_name="OSWriteFileSync") os_write_file_sync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
|
||||
@(link_name="OSReadFileSync") os_read_file_sync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---;
|
||||
@(link_name="OSInitialiseAPI") os_initialise_api :: proc() -> int ---;
|
||||
@(link_name="OSTerminateProcess") os_terminate_process :: proc(handle: Handle) ---;
|
||||
@(link_name="realloc") os_heap_reallocate :: proc(address: rawptr, size: int) -> rawptr ---;
|
||||
}
|
||||
|
||||
stdin := Handle(-1); // Not implemented
|
||||
stdout := Handle(0);
|
||||
stderr := Handle(0);
|
||||
|
||||
current_thread_id :: proc() -> int {
|
||||
// Not implemented
|
||||
return -1;
|
||||
}
|
||||
|
||||
heap_alloc :: proc(size: int) -> rawptr {
|
||||
return os_heap_allocate(size, true);
|
||||
}
|
||||
|
||||
heap_free :: proc(address: rawptr) {
|
||||
os_heap_free(address);
|
||||
}
|
||||
|
||||
heap_resize :: proc(address: rawptr, new_size: int) -> rawptr {
|
||||
return os_heap_reallocate(address, new_size);
|
||||
}
|
||||
|
||||
open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
|
||||
information := new(OS_Node_Information);
|
||||
error := os_open_node(&path[0], len(path), u64(mode), information);
|
||||
if error < -1 do return 0, 1;
|
||||
information.position = 0;
|
||||
if mode&O_TRUNC==O_TRUNC {
|
||||
error := os_resize_file(information.handle, 0);
|
||||
if error < -1 do return 0, 1;
|
||||
}
|
||||
return Handle(uintptr(information)), 0;
|
||||
}
|
||||
|
||||
close :: proc(fd: Handle) {
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
os_close_handle(information.handle);
|
||||
free(information);
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
// Not (properly) implemented
|
||||
information := cast(^OS_Node_Information)uintptr(fd);
|
||||
return information.size,0;
|
||||
}
|
||||
|
||||
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if fd == 0 {
|
||||
os_print_direct(&data[0], len(data));
|
||||
return len(data), 0;
|
||||
} else if fd == 1 {
|
||||
assert(false);
|
||||
return 0, 1;
|
||||
}
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
count := os_write_file_sync(information.handle, information.position, i64(len(data)), &data[0]);
|
||||
if count < 0 do return 0, 1;
|
||||
information.position += count;
|
||||
return int(count), 0;
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
|
||||
if (fd == 0 || fd == 1) {
|
||||
assert(false);
|
||||
return 0, 1;
|
||||
}
|
||||
information := (^OS_Node_Information)(uintptr(fd));
|
||||
count := os_read_file_sync(information.handle, information.position, i64(len(data)), &data[0]);
|
||||
if count < 0 do return 0, 1;
|
||||
information.position += count;
|
||||
return int(count), 0;
|
||||
}
|
||||
|
||||
os_terminate_this_process :: proc() {
|
||||
os_terminate_process(0x1001);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
Any :: struct {
|
||||
data: rawptr,
|
||||
type_info: ^Type_Info,
|
||||
}
|
||||
|
||||
String :: struct {
|
||||
data: ^byte,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Slice :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Dynamic_Array :: struct {
|
||||
data: rawptr,
|
||||
len: int,
|
||||
cap: int,
|
||||
allocator: Allocator,
|
||||
}
|
||||
|
||||
Map :: struct {
|
||||
hashes: [dynamic]int,
|
||||
entries: Dynamic_Array,
|
||||
}
|
||||
|
||||
|
||||
make_any :: inline proc(data: rawptr, type_info: ^Type_Info) -> any {
|
||||
return transmute(any)Any{data, type_info};
|
||||
}
|
||||
|
||||
string_data :: inline proc(s: $T/string) -> ^byte {
|
||||
return (^String)(&s).data;
|
||||
}
|
||||
slice_data :: inline proc(a: $T/[]$E) -> ^E {
|
||||
return cast(^E)(^Slice)(&a).data;
|
||||
}
|
||||
dynamic_array_data :: inline proc(a: $T/[dynamic]$E) -> ^E {
|
||||
return cast(^E)(^Dynamic_Array)(&a).data;
|
||||
}
|
||||
|
||||
data :: proc[string_data, slice_data, dynamic_array_data];
|
||||
|
||||
|
||||
@@ -0,0 +1,877 @@
|
||||
// This is the runtime code required by the compiler
|
||||
// IMPORTANT NOTE(bill): Do not change the order of any of this data
|
||||
// The compiler relies upon this _exact_ order
|
||||
package runtime
|
||||
|
||||
import "core:os"
|
||||
import "core:mem"
|
||||
|
||||
// Naming Conventions:
|
||||
// In general, Ada_Case for types and snake_case for values
|
||||
//
|
||||
// Package Name: snake_case (but prefer single word)
|
||||
// Import Name: snake_case (but prefer single word)
|
||||
// Types: Ada_Case
|
||||
// Enum Values: Ada_Case
|
||||
// Procedures: snake_case
|
||||
// Local Variables: snake_case
|
||||
// Constant Variables: SCREAMING_SNAKE_CASE
|
||||
|
||||
|
||||
// IMPORTANT NOTE(bill): `type_info_of` cannot be used within a
|
||||
// #shared_global_scope due to the internals of the compiler.
|
||||
// This could change at a later date if the all these data structures are
|
||||
// implemented within the compiler rather than in this "preload" file
|
||||
|
||||
// NOTE(bill): This must match the compiler's
|
||||
Calling_Convention :: enum {
|
||||
Invalid = 0,
|
||||
Odin = 1,
|
||||
Contextless = 2,
|
||||
C = 3,
|
||||
Std = 4,
|
||||
Fast = 5,
|
||||
}
|
||||
|
||||
Type_Info_Enum_Value :: union {
|
||||
rune,
|
||||
i8, i16, i32, i64, int,
|
||||
u8, u16, u32, u64, uint, uintptr,
|
||||
};
|
||||
|
||||
// Variant Types
|
||||
Type_Info_Named :: struct {name: string, base: ^Type_Info};
|
||||
Type_Info_Integer :: struct {signed: bool};
|
||||
Type_Info_Rune :: struct {};
|
||||
Type_Info_Float :: struct {};
|
||||
Type_Info_Complex :: struct {};
|
||||
Type_Info_String :: struct {is_cstring: bool};
|
||||
Type_Info_Boolean :: struct {};
|
||||
Type_Info_Any :: struct {};
|
||||
Type_Info_Type_Id :: struct {};
|
||||
Type_Info_Pointer :: struct {
|
||||
elem: ^Type_Info // nil -> rawptr
|
||||
};
|
||||
Type_Info_Procedure :: struct {
|
||||
params: ^Type_Info, // Type_Info_Tuple
|
||||
results: ^Type_Info, // Type_Info_Tuple
|
||||
variadic: bool,
|
||||
convention: Calling_Convention,
|
||||
};
|
||||
Type_Info_Array :: struct {
|
||||
elem: ^Type_Info,
|
||||
elem_size: int,
|
||||
count: int,
|
||||
};
|
||||
Type_Info_Dynamic_Array :: struct {elem: ^Type_Info, elem_size: int};
|
||||
Type_Info_Slice :: struct {elem: ^Type_Info, elem_size: int};
|
||||
Type_Info_Tuple :: struct { // Only really used for procedures
|
||||
types: []^Type_Info,
|
||||
names: []string,
|
||||
};
|
||||
Type_Info_Struct :: struct {
|
||||
types: []^Type_Info,
|
||||
names: []string,
|
||||
offsets: []uintptr, // offsets may not be used in tuples
|
||||
usings: []bool, // usings may not be used in tuples
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
custom_align: bool,
|
||||
};
|
||||
Type_Info_Union :: struct {
|
||||
variants: []^Type_Info,
|
||||
tag_offset: uintptr,
|
||||
tag_type: ^Type_Info,
|
||||
};
|
||||
Type_Info_Enum :: struct {
|
||||
base: ^Type_Info,
|
||||
names: []string,
|
||||
values: []Type_Info_Enum_Value,
|
||||
};
|
||||
Type_Info_Map :: struct {
|
||||
key: ^Type_Info,
|
||||
value: ^Type_Info,
|
||||
generated_struct: ^Type_Info,
|
||||
};
|
||||
Type_Info_Bit_Field :: struct {
|
||||
names: []string,
|
||||
bits: []i32,
|
||||
offsets: []i32,
|
||||
};
|
||||
Type_Info_Bit_Set :: struct {
|
||||
elem: ^Type_Info,
|
||||
underlying: ^Type_Info, // Possibly nil
|
||||
lower: i64,
|
||||
upper: i64,
|
||||
};
|
||||
|
||||
Type_Info :: struct {
|
||||
size: int,
|
||||
align: int,
|
||||
id: typeid,
|
||||
|
||||
variant: union {
|
||||
Type_Info_Named,
|
||||
Type_Info_Integer,
|
||||
Type_Info_Rune,
|
||||
Type_Info_Float,
|
||||
Type_Info_Complex,
|
||||
Type_Info_String,
|
||||
Type_Info_Boolean,
|
||||
Type_Info_Any,
|
||||
Type_Info_Type_Id,
|
||||
Type_Info_Pointer,
|
||||
Type_Info_Procedure,
|
||||
Type_Info_Array,
|
||||
Type_Info_Dynamic_Array,
|
||||
Type_Info_Slice,
|
||||
Type_Info_Tuple,
|
||||
Type_Info_Struct,
|
||||
Type_Info_Union,
|
||||
Type_Info_Enum,
|
||||
Type_Info_Map,
|
||||
Type_Info_Bit_Field,
|
||||
Type_Info_Bit_Set,
|
||||
},
|
||||
}
|
||||
|
||||
// NOTE(bill): This must match the compiler's
|
||||
Typeid_Kind :: enum u8 {
|
||||
Invalid,
|
||||
Integer,
|
||||
Rune,
|
||||
Float,
|
||||
Complex,
|
||||
String,
|
||||
Boolean,
|
||||
Any,
|
||||
Type_Id,
|
||||
Pointer,
|
||||
Procedure,
|
||||
Array,
|
||||
Dynamic_Array,
|
||||
Slice,
|
||||
Tuple,
|
||||
Struct,
|
||||
Union,
|
||||
Enum,
|
||||
Map,
|
||||
Bit_Field,
|
||||
Bit_Set,
|
||||
}
|
||||
|
||||
Typeid_Bit_Field :: bit_field #align align_of(uintptr) {
|
||||
index: 8*size_of(align_of(uintptr)) - 8,
|
||||
kind: 5, // Typeid_Kind
|
||||
named: 1,
|
||||
special: 1, // signed, cstring, etc
|
||||
reserved: 1,
|
||||
}
|
||||
|
||||
// NOTE(bill): only the ones that are needed (not all types)
|
||||
// This will be set by the compiler
|
||||
type_table: []Type_Info;
|
||||
|
||||
args__: []cstring;
|
||||
|
||||
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
|
||||
|
||||
|
||||
Source_Code_Location :: struct {
|
||||
file_path: string,
|
||||
line, column: int,
|
||||
procedure: string,
|
||||
}
|
||||
|
||||
Context :: struct {
|
||||
allocator: mem.Allocator,
|
||||
thread_id: int,
|
||||
|
||||
user_data: any,
|
||||
user_index: int,
|
||||
|
||||
parent: ^Context,
|
||||
derived: any, // May be used for derived data types
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
INITIAL_MAP_CAP :: 16;
|
||||
|
||||
Map_Key :: struct {
|
||||
hash: u64,
|
||||
str: string,
|
||||
}
|
||||
|
||||
Map_Find_Result :: struct {
|
||||
hash_index: int,
|
||||
entry_prev: int,
|
||||
entry_index: int,
|
||||
}
|
||||
|
||||
Map_Entry_Header :: struct {
|
||||
key: Map_Key,
|
||||
next: int,
|
||||
/*
|
||||
value: Value_Type,
|
||||
*/
|
||||
}
|
||||
|
||||
Map_Header :: struct {
|
||||
m: ^mem.Raw_Map,
|
||||
is_key_string: bool,
|
||||
entry_size: int,
|
||||
entry_align: int,
|
||||
value_offset: uintptr,
|
||||
value_size: int,
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
type_info_base :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil do return nil;
|
||||
|
||||
base := info;
|
||||
loop: for {
|
||||
switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base;
|
||||
case: break loop;
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
type_info_base_without_enum :: proc "contextless" (info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil do return nil;
|
||||
|
||||
base := info;
|
||||
loop: for {
|
||||
switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base;
|
||||
case Type_Info_Enum: base = i.base;
|
||||
case: break loop;
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
__typeid_of :: proc "contextless" (ti: ^Type_Info) -> typeid {
|
||||
if ti == nil do return nil;
|
||||
return ti.id;
|
||||
}
|
||||
__type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info {
|
||||
data := transmute(Typeid_Bit_Field)id;
|
||||
n := int(data.index);
|
||||
if n < 0 || n >= len(type_table) {
|
||||
n = 0;
|
||||
}
|
||||
return &type_table[n];
|
||||
}
|
||||
|
||||
typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_of(id);
|
||||
ti = type_info_base(ti);
|
||||
return typeid_of(ti);
|
||||
}
|
||||
typeid_base_without_enum :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_base_without_enum(type_info_of(id));
|
||||
return typeid_of(ti);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(default_calling_convention = "c")
|
||||
foreign {
|
||||
@(link_name="llvm.assume")
|
||||
assume :: proc(cond: bool) ---;
|
||||
|
||||
@(link_name="llvm.debugtrap")
|
||||
debug_trap :: proc() ---;
|
||||
|
||||
@(link_name="llvm.trap")
|
||||
trap :: proc() ---;
|
||||
|
||||
@(link_name="llvm.readcyclecounter")
|
||||
read_cycle_counter :: proc() -> u64 ---;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
__init_context_from_ptr :: proc "contextless" (c: ^Context, other: ^Context) {
|
||||
if c == nil do return;
|
||||
c^ = other^;
|
||||
__init_context(c);
|
||||
}
|
||||
|
||||
__init_context :: proc "contextless" (c: ^Context) {
|
||||
if c == nil do return;
|
||||
|
||||
c.allocator = os.heap_allocator();
|
||||
c.thread_id = os.current_thread_id();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(builtin)
|
||||
copy :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
n := max(0, min(len(dst), len(src)));
|
||||
if n > 0 do mem.copy(&dst[0], &src[0], n*size_of(E));
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(builtin)
|
||||
pop :: proc "contextless" (array: ^$T/[dynamic]$E) -> E {
|
||||
if array == nil do return E{};
|
||||
assert(len(array) > 0);
|
||||
res := array[len(array)-1];
|
||||
(^mem.Raw_Dynamic_Array)(array).len -= 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@(builtin)
|
||||
clear :: proc[clear_dynamic_array, clear_map];
|
||||
|
||||
@(builtin)
|
||||
reserve :: proc[reserve_dynamic_array, reserve_map];
|
||||
|
||||
|
||||
@(builtin)
|
||||
new :: proc[mem.new];
|
||||
|
||||
@(builtin)
|
||||
new_clone :: proc[mem.new_clone];
|
||||
|
||||
@(builtin)
|
||||
free :: proc[mem.free];
|
||||
|
||||
@(builtin)
|
||||
delete :: proc[
|
||||
mem.delete_string,
|
||||
mem.delete_cstring,
|
||||
mem.delete_dynamic_array,
|
||||
mem.delete_slice,
|
||||
mem.delete_map,
|
||||
];
|
||||
|
||||
@(builtin)
|
||||
make :: proc[
|
||||
mem.make_slice,
|
||||
mem.make_dynamic_array,
|
||||
mem.make_dynamic_array_len,
|
||||
mem.make_dynamic_array_len_cap,
|
||||
mem.make_map,
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
@(builtin)
|
||||
clear_map :: inline proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
if m == nil do return;
|
||||
raw_map := (^mem.Raw_Map)(m);
|
||||
hashes := (^mem.Raw_Dynamic_Array)(&raw_map.hashes);
|
||||
entries := (^mem.Raw_Dynamic_Array)(&raw_map.entries);
|
||||
hashes.len = 0;
|
||||
entries.len = 0;
|
||||
}
|
||||
|
||||
@(builtin)
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) {
|
||||
if m != nil do __dynamic_map_reserve(__get_map_header(m), capacity);
|
||||
}
|
||||
|
||||
@(builtin)
|
||||
delete_key :: proc(m: ^$T/map[$K]$V, key: K) {
|
||||
if m != nil do __dynamic_map_delete_key(__get_map_header(m), __get_map_key(key));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(builtin)
|
||||
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int {
|
||||
if array == nil do return 0;
|
||||
|
||||
arg_len := 1;
|
||||
|
||||
if cap(array) <= len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len);
|
||||
_ = reserve(array, cap, loc);
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
if arg_len > 0 {
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
data := (^E)(a.data);
|
||||
assert(data != nil);
|
||||
mem.copy(mem.ptr_offset(data, a.len), &arg, size_of(E));
|
||||
a.len += arg_len;
|
||||
}
|
||||
return len(array);
|
||||
}
|
||||
@(builtin)
|
||||
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int {
|
||||
if array == nil do return 0;
|
||||
|
||||
arg_len := len(args);
|
||||
if arg_len <= 0 do return len(array);
|
||||
|
||||
|
||||
if cap(array) <= len(array)+arg_len {
|
||||
cap := 2 * cap(array) + max(8, arg_len);
|
||||
_ = reserve(array, cap, loc);
|
||||
}
|
||||
arg_len = min(cap(array)-len(array), arg_len);
|
||||
if arg_len > 0 {
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
data := (^E)(a.data);
|
||||
assert(data != nil);
|
||||
mem.copy(mem.ptr_offset(data, a.len), &args[0], size_of(E) * arg_len);
|
||||
a.len += arg_len;
|
||||
}
|
||||
return len(array);
|
||||
}
|
||||
@(builtin) append :: proc[append_elem, append_elems];
|
||||
|
||||
|
||||
|
||||
@(builtin)
|
||||
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> int {
|
||||
for arg in args {
|
||||
append(array = array, args = ([]E)(arg), loc = loc);
|
||||
}
|
||||
return len(array);
|
||||
}
|
||||
|
||||
@(builtin)
|
||||
clear_dynamic_array :: inline proc "contextless" (array: ^$T/[dynamic]$E) {
|
||||
if array != nil do (^mem.Raw_Dynamic_Array)(array).len = 0;
|
||||
}
|
||||
|
||||
@(builtin)
|
||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
|
||||
if array == nil do return false;
|
||||
a := (^mem.Raw_Dynamic_Array)(array);
|
||||
|
||||
if capacity <= a.cap do return true;
|
||||
|
||||
if a.allocator.procedure == nil {
|
||||
a.allocator = context.allocator;
|
||||
}
|
||||
assert(a.allocator.procedure != nil);
|
||||
|
||||
old_size := a.cap * size_of(E);
|
||||
new_size := capacity * size_of(E);
|
||||
allocator := a.allocator;
|
||||
|
||||
new_data := allocator.procedure(
|
||||
allocator.data, mem.Allocator_Mode.Resize, new_size, align_of(E),
|
||||
a.data, old_size, 0, loc,
|
||||
);
|
||||
if new_data == nil do return false;
|
||||
|
||||
a.data = new_data;
|
||||
a.cap = capacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@(builtin)
|
||||
incl_elem :: inline proc(s: ^$S/bit_set[$E; $U], elem: E) -> S {
|
||||
s^ |= {elem};
|
||||
return s^;
|
||||
}
|
||||
@(builtin)
|
||||
incl_elems :: inline proc(s: ^$S/bit_set[$E; $U], elems: ..E) -> S {
|
||||
for elem in elems do s^ |= {elem};
|
||||
return s^;
|
||||
}
|
||||
@(builtin)
|
||||
incl_bit_set :: inline proc(s: ^$S/bit_set[$E; $U], other: S) -> S {
|
||||
s^ |= other;
|
||||
return s^;
|
||||
}
|
||||
@(builtin)
|
||||
excl_elem :: inline proc(s: ^$S/bit_set[$E; $U], elem: E) -> S {
|
||||
s^ &~= {elem};
|
||||
return s^;
|
||||
}
|
||||
@(builtin)
|
||||
excl_elems :: inline proc(s: ^$S/bit_set[$E; $U], elems: ..E) -> S {
|
||||
for elem in elems do s^ &~= {elem};
|
||||
return s^;
|
||||
}
|
||||
@(builtin)
|
||||
excl_bit_set :: inline proc(s: ^$S/bit_set[$E; $U], other: S) -> S {
|
||||
s^ &~= other;
|
||||
return s^;
|
||||
}
|
||||
|
||||
@(builtin) incl :: proc[incl_elem, incl_elems, incl_bit_set];
|
||||
@(builtin) excl :: proc[excl_elem, excl_elems, excl_bit_set];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@(builtin)
|
||||
assert :: proc "contextless" (condition: bool, message := "", using loc := #caller_location) -> bool {
|
||||
if !condition {
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, loc);
|
||||
os.write_string(fd, " Runtime assertion");
|
||||
if len(message) > 0 {
|
||||
os.write_string(fd, ": ");
|
||||
os.write_string(fd, message);
|
||||
}
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
@(builtin)
|
||||
panic :: proc "contextless" (message := "", using loc := #caller_location) {
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, loc);
|
||||
os.write_string(fd, " Panic");
|
||||
if len(message) > 0 {
|
||||
os.write_string(fd, ": ");
|
||||
os.write_string(fd, message);
|
||||
}
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Dynamic Array
|
||||
|
||||
|
||||
__dynamic_array_make :: proc(array_: rawptr, elem_size, elem_align: int, len, cap: int, loc := #caller_location) {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
array.allocator = context.allocator;
|
||||
assert(array.allocator.procedure != nil);
|
||||
|
||||
if cap > 0 {
|
||||
__dynamic_array_reserve(array_, elem_size, elem_align, cap, loc);
|
||||
array.len = len;
|
||||
}
|
||||
}
|
||||
|
||||
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: int, loc := #caller_location) -> bool {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
|
||||
if cap <= array.cap do return true;
|
||||
|
||||
if array.allocator.procedure == nil {
|
||||
array.allocator = context.allocator;
|
||||
}
|
||||
assert(array.allocator.procedure != nil);
|
||||
|
||||
old_size := array.cap * elem_size;
|
||||
new_size := cap * elem_size;
|
||||
allocator := array.allocator;
|
||||
|
||||
new_data := allocator.procedure(allocator.data, mem.Allocator_Mode.Resize, new_size, elem_align, array.data, old_size, 0, loc);
|
||||
if new_data == nil do return false;
|
||||
|
||||
array.data = new_data;
|
||||
array.cap = cap;
|
||||
return true;
|
||||
}
|
||||
|
||||
__dynamic_array_resize :: proc(array_: rawptr, elem_size, elem_align: int, len: int, loc := #caller_location) -> bool {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
|
||||
ok := __dynamic_array_reserve(array_, elem_size, elem_align, len, loc);
|
||||
if ok do array.len = len;
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
items: rawptr, item_count: int, loc := #caller_location) -> int {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
|
||||
if items == nil do return 0;
|
||||
if item_count <= 0 do return 0;
|
||||
|
||||
|
||||
ok := true;
|
||||
if array.cap <= array.len+item_count {
|
||||
cap := 2 * array.cap + max(8, item_count);
|
||||
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc);
|
||||
}
|
||||
// TODO(bill): Better error handling for failed reservation
|
||||
if !ok do return array.len;
|
||||
|
||||
assert(array.data != nil);
|
||||
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
||||
|
||||
mem.copy(rawptr(data), items, elem_size * item_count);
|
||||
array.len += item_count;
|
||||
return array.len;
|
||||
}
|
||||
|
||||
__dynamic_array_append_nothing :: proc(array_: rawptr, elem_size, elem_align: int, loc := #caller_location) -> int {
|
||||
array := (^mem.Raw_Dynamic_Array)(array_);
|
||||
|
||||
ok := true;
|
||||
if array.cap <= array.len+1 {
|
||||
cap := 2 * array.cap + max(8, 1);
|
||||
ok = __dynamic_array_reserve(array, elem_size, elem_align, cap, loc);
|
||||
}
|
||||
// TODO(bill): Better error handling for failed reservation
|
||||
if !ok do return array.len;
|
||||
|
||||
assert(array.data != nil);
|
||||
data := uintptr(array.data) + uintptr(elem_size*array.len);
|
||||
mem.zero(rawptr(data), elem_size);
|
||||
array.len += 1;
|
||||
return array.len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Map
|
||||
|
||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
header := Map_Header{m = (^mem.Raw_Map)(m)};
|
||||
Entry :: struct {
|
||||
key: Map_Key,
|
||||
next: int,
|
||||
value: V,
|
||||
}
|
||||
|
||||
_, is_string := type_info_base(type_info_of(K)).variant.(Type_Info_String);
|
||||
header.is_key_string = is_string;
|
||||
header.entry_size = int(size_of(Entry));
|
||||
header.entry_align = int(align_of(Entry));
|
||||
header.value_offset = uintptr(offset_of(Entry, value));
|
||||
header.value_size = int(size_of(V));
|
||||
return header;
|
||||
}
|
||||
|
||||
__get_map_key :: proc "contextless" (key: $K) -> Map_Key {
|
||||
map_key: Map_Key;
|
||||
ti := type_info_base_without_enum(type_info_of(K));
|
||||
switch _ in ti.variant {
|
||||
case Type_Info_Integer:
|
||||
switch 8*size_of(key) {
|
||||
case 8: map_key.hash = u64(( ^u8)(&key)^);
|
||||
case 16: map_key.hash = u64(( ^u16)(&key)^);
|
||||
case 32: map_key.hash = u64(( ^u32)(&key)^);
|
||||
case 64: map_key.hash = u64(( ^u64)(&key)^);
|
||||
case: panic("Unhandled integer size");
|
||||
}
|
||||
case Type_Info_Rune:
|
||||
map_key.hash = u64((^rune)(&key)^);
|
||||
case Type_Info_Pointer:
|
||||
map_key.hash = u64(uintptr((^rawptr)(&key)^));
|
||||
case Type_Info_Float:
|
||||
switch 8*size_of(key) {
|
||||
case 32: map_key.hash = u64((^u32)(&key)^);
|
||||
case 64: map_key.hash = u64((^u64)(&key)^);
|
||||
case: panic("Unhandled float size");
|
||||
}
|
||||
case Type_Info_String:
|
||||
str := (^string)(&key)^;
|
||||
map_key.hash = __default_hash_string(str);
|
||||
map_key.str = str;
|
||||
case:
|
||||
panic("Unhandled map key type");
|
||||
}
|
||||
return map_key;
|
||||
}
|
||||
|
||||
|
||||
__default_hash :: proc(data: []byte) -> u64 {
|
||||
fnv64a :: proc(data: []byte) -> u64 {
|
||||
h: u64 = 0xcbf29ce484222325;
|
||||
for b in data {
|
||||
h = (h ~ u64(b)) * 0x100000001b3;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
return fnv64a(data);
|
||||
}
|
||||
__default_hash_string :: proc(s: string) -> u64 do return __default_hash(([]byte)(s));
|
||||
|
||||
__dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller_location) {
|
||||
__dynamic_array_reserve(&m.hashes, size_of(int), align_of(int), cap, loc);
|
||||
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc);
|
||||
}
|
||||
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) #no_bounds_check {
|
||||
new_header: Map_Header = header;
|
||||
nm := mem.Raw_Map{};
|
||||
new_header.m = &nm;
|
||||
|
||||
header_hashes := (^mem.Raw_Dynamic_Array)(&header.m.hashes);
|
||||
nm_hashes := (^mem.Raw_Dynamic_Array)(&nm.hashes);
|
||||
|
||||
__dynamic_array_resize(nm_hashes, size_of(int), align_of(int), new_count, loc);
|
||||
__dynamic_array_reserve(&nm.entries, entry_size, entry_align, m.entries.len, loc);
|
||||
for i in 0 .. new_count-1 do nm.hashes[i] = -1;
|
||||
|
||||
for i in 0 .. m.entries.len-1 {
|
||||
if len(nm.hashes) == 0 do __dynamic_map_grow(new_header, loc);
|
||||
|
||||
entry_header := __dynamic_map_get_entry(header, i);
|
||||
data := uintptr(entry_header);
|
||||
|
||||
fr := __dynamic_map_find(new_header, entry_header.key);
|
||||
j := __dynamic_map_add_entry(new_header, entry_header.key, loc);
|
||||
if fr.entry_prev < 0 {
|
||||
nm.hashes[fr.hash_index] = j;
|
||||
} else {
|
||||
e := __dynamic_map_get_entry(new_header, fr.entry_prev);
|
||||
e.next = j;
|
||||
}
|
||||
|
||||
e := __dynamic_map_get_entry(new_header, j);
|
||||
e.next = fr.entry_index;
|
||||
ndata := uintptr(e);
|
||||
mem.copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size);
|
||||
|
||||
if __dynamic_map_full(new_header) do __dynamic_map_grow(new_header, loc);
|
||||
}
|
||||
mem.free_ptr_with_allocator(header_hashes.allocator, header_hashes.data, loc);
|
||||
mem.free_ptr_with_allocator(header.m.entries.allocator, header.m.entries.data, loc);
|
||||
header.m^ = nm;
|
||||
}
|
||||
|
||||
__dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr {
|
||||
index := __dynamic_map_find(h, key).entry_index;
|
||||
if index >= 0 {
|
||||
data := uintptr(__dynamic_map_get_entry(h, index));
|
||||
return rawptr(data + h.value_offset);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
__dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #caller_location) #no_bounds_check {
|
||||
|
||||
index: int;
|
||||
assert(value != nil);
|
||||
|
||||
if len(h.m.hashes) == 0 {
|
||||
__dynamic_map_reserve(h, INITIAL_MAP_CAP, loc);
|
||||
__dynamic_map_grow(h, loc);
|
||||
}
|
||||
|
||||
fr := __dynamic_map_find(h, key);
|
||||
if fr.entry_index >= 0 {
|
||||
index = fr.entry_index;
|
||||
} else {
|
||||
index = __dynamic_map_add_entry(h, key, loc);
|
||||
if fr.entry_prev >= 0 {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_prev);
|
||||
entry.next = index;
|
||||
} else {
|
||||
h.m.hashes[fr.hash_index] = index;
|
||||
}
|
||||
}
|
||||
{
|
||||
e := __dynamic_map_get_entry(h, index);
|
||||
e.key = key;
|
||||
val := (^byte)(uintptr(e) + h.value_offset);
|
||||
mem.copy(val, value, h.value_size);
|
||||
}
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
__dynamic_map_grow(h, loc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_grow :: proc(using h: Map_Header, loc := #caller_location) {
|
||||
// TODO(bill): Determine an efficient growing rate
|
||||
new_count := max(4*m.entries.cap + 7, INITIAL_MAP_CAP);
|
||||
__dynamic_map_rehash(h, new_count, loc);
|
||||
}
|
||||
|
||||
__dynamic_map_full :: inline proc(using h: Map_Header) -> bool {
|
||||
return int(0.75 * f64(len(m.hashes))) <= m.entries.cap;
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool {
|
||||
if a.hash == b.hash {
|
||||
if h.is_key_string do return a.str == b.str;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
__dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result #no_bounds_check {
|
||||
fr := Map_Find_Result{-1, -1, -1};
|
||||
if n := u64(len(m.hashes)); n > 0 {
|
||||
fr.hash_index = int(key.hash % n);
|
||||
fr.entry_index = m.hashes[fr.hash_index];
|
||||
for fr.entry_index >= 0 {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index);
|
||||
if __dynamic_map_hash_equal(h, entry.key, key) do return fr;
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = entry.next;
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key, loc := #caller_location) -> int {
|
||||
prev := m.entries.len;
|
||||
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc);
|
||||
if c != prev {
|
||||
end := __dynamic_map_get_entry(h, c-1);
|
||||
end.key = key;
|
||||
end.next = -1;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
__dynamic_map_delete_key :: proc(using h: Map_Header, key: Map_Key) {
|
||||
fr := __dynamic_map_find(h, key);
|
||||
if fr.entry_index >= 0 {
|
||||
__dynamic_map_erase(h, fr);
|
||||
}
|
||||
}
|
||||
|
||||
__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header {
|
||||
assert(0 <= index && index < m.entries.len);
|
||||
return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size));
|
||||
}
|
||||
|
||||
__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
|
||||
if fr.entry_prev < 0 {
|
||||
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next;
|
||||
} else {
|
||||
prev := __dynamic_map_get_entry(h, fr.entry_prev);
|
||||
curr := __dynamic_map_get_entry(h, fr.entry_index);
|
||||
prev.next = curr.next;
|
||||
}
|
||||
if (fr.entry_index == m.entries.len-1) {
|
||||
m.entries.len -= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
last := __dynamic_map_find(h, __dynamic_map_get_entry(h, fr.entry_index).key);
|
||||
if last.entry_prev >= 0 {
|
||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev);
|
||||
last_entry.next = fr.entry_index;
|
||||
} else {
|
||||
m.hashes[last.hash_index] = fr.entry_index;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
package runtime
|
||||
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:unicode/utf8"
|
||||
|
||||
|
||||
__print_u64 :: proc(fd: os.Handle, u: u64) {
|
||||
digits := "0123456789";
|
||||
|
||||
a: [129]byte;
|
||||
i := len(a);
|
||||
b := u64(10);
|
||||
for u >= b {
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
u /= b;
|
||||
}
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
|
||||
os.write(fd, a[i:]);
|
||||
}
|
||||
|
||||
__print_i64 :: proc(fd: os.Handle, u: i64) {
|
||||
digits := "0123456789";
|
||||
|
||||
neg := u < 0;
|
||||
u = abs(u);
|
||||
|
||||
a: [129]byte;
|
||||
i := len(a);
|
||||
b := i64(10);
|
||||
for u >= b {
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
u /= b;
|
||||
}
|
||||
i -= 1; a[i] = digits[u % b];
|
||||
if neg {
|
||||
i -= 1; a[i] = '-';
|
||||
}
|
||||
|
||||
os.write(fd, a[i:]);
|
||||
}
|
||||
|
||||
__print_caller_location :: proc(fd: os.Handle, using loc: Source_Code_Location) {
|
||||
os.write_string(fd, file_path);
|
||||
os.write_byte(fd, '(');
|
||||
__print_u64(fd, u64(line));
|
||||
os.write_byte(fd, ':');
|
||||
__print_u64(fd, u64(column));
|
||||
os.write_byte(fd, ')');
|
||||
}
|
||||
__print_typeid :: proc(fd: os.Handle, id: typeid) {
|
||||
ti := type_info_of(id);
|
||||
__print_type(fd, ti);
|
||||
}
|
||||
__print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
|
||||
if ti == nil {
|
||||
os.write_string(fd, "nil");
|
||||
return;
|
||||
}
|
||||
|
||||
switch info in ti.variant {
|
||||
case Type_Info_Named:
|
||||
os.write_string(fd, info.name);
|
||||
case Type_Info_Integer:
|
||||
a := any{typeid = typeid_of(ti)};
|
||||
switch _ in a {
|
||||
case int: os.write_string(fd, "int");
|
||||
case uint: os.write_string(fd, "uint");
|
||||
case uintptr: os.write_string(fd, "uintptr");
|
||||
case:
|
||||
os.write_byte(fd, info.signed ? 'i' : 'u');
|
||||
__print_u64(fd, u64(8*ti.size));
|
||||
}
|
||||
case Type_Info_Rune:
|
||||
os.write_string(fd, "rune");
|
||||
case Type_Info_Float:
|
||||
os.write_byte(fd, 'f');
|
||||
__print_u64(fd, u64(8*ti.size));
|
||||
case Type_Info_Complex:
|
||||
os.write_string(fd, "complex");
|
||||
__print_u64(fd, u64(8*ti.size));
|
||||
case Type_Info_String:
|
||||
os.write_string(fd, "string");
|
||||
case Type_Info_Boolean:
|
||||
a := any{typeid = typeid_of(ti)};
|
||||
switch _ in a {
|
||||
case bool: os.write_string(fd, "bool");
|
||||
case:
|
||||
os.write_byte(fd, 'b');
|
||||
__print_u64(fd, u64(8*ti.size));
|
||||
}
|
||||
case Type_Info_Any:
|
||||
os.write_string(fd, "any");
|
||||
case Type_Info_Type_Id:
|
||||
os.write_string(fd, "typeid");
|
||||
|
||||
case Type_Info_Pointer:
|
||||
if info.elem == nil {
|
||||
os.write_string(fd, "rawptr");
|
||||
} else {
|
||||
os.write_string(fd, "^");
|
||||
__print_type(fd, info.elem);
|
||||
}
|
||||
case Type_Info_Procedure:
|
||||
os.write_string(fd, "proc");
|
||||
if info.params == nil {
|
||||
os.write_string(fd, "()");
|
||||
} else {
|
||||
t := info.params.variant.(Type_Info_Tuple);
|
||||
os.write_string(fd, "(");
|
||||
for t, i in t.types {
|
||||
if i > 0 do os.write_string(fd, ", ");
|
||||
__print_type(fd, t);
|
||||
}
|
||||
os.write_string(fd, ")");
|
||||
}
|
||||
if info.results != nil {
|
||||
os.write_string(fd, " -> ");
|
||||
__print_type(fd, info.results);
|
||||
}
|
||||
case Type_Info_Tuple:
|
||||
count := len(info.names);
|
||||
if count != 1 do os.write_string(fd, "(");
|
||||
for name, i in info.names {
|
||||
if i > 0 do os.write_string(fd, ", ");
|
||||
|
||||
t := info.types[i];
|
||||
|
||||
if len(name) > 0 {
|
||||
os.write_string(fd, name);
|
||||
os.write_string(fd, ": ");
|
||||
}
|
||||
__print_type(fd, t);
|
||||
}
|
||||
if count != 1 do os.write_string(fd, ")");
|
||||
|
||||
case Type_Info_Array:
|
||||
os.write_string(fd, "[");
|
||||
__print_u64(fd, u64(info.count));
|
||||
os.write_string(fd, "]");
|
||||
__print_type(fd, info.elem);
|
||||
case Type_Info_Dynamic_Array:
|
||||
os.write_string(fd, "[dynamic]");
|
||||
__print_type(fd, info.elem);
|
||||
case Type_Info_Slice:
|
||||
os.write_string(fd, "[]");
|
||||
__print_type(fd, info.elem);
|
||||
|
||||
case Type_Info_Map:
|
||||
os.write_string(fd, "map[");
|
||||
__print_type(fd, info.key);
|
||||
os.write_byte(fd, ']');
|
||||
__print_type(fd, info.value);
|
||||
|
||||
case Type_Info_Struct:
|
||||
os.write_string(fd, "struct ");
|
||||
if info.is_packed do os.write_string(fd, "#packed ");
|
||||
if info.is_raw_union do os.write_string(fd, "#raw_union ");
|
||||
if info.custom_align {
|
||||
os.write_string(fd, "#align ");
|
||||
__print_u64(fd, u64(ti.align));
|
||||
os.write_byte(fd, ' ');
|
||||
}
|
||||
os.write_byte(fd, '{');
|
||||
for name, i in info.names {
|
||||
if i > 0 do os.write_string(fd, ", ");
|
||||
os.write_string(fd, name);
|
||||
os.write_string(fd, ": ");
|
||||
__print_type(fd, info.types[i]);
|
||||
}
|
||||
os.write_byte(fd, '}');
|
||||
|
||||
case Type_Info_Union:
|
||||
os.write_string(fd, "union {");
|
||||
for variant, i in info.variants {
|
||||
if i > 0 do os.write_string(fd, ", ");
|
||||
__print_type(fd, variant);
|
||||
}
|
||||
os.write_string(fd, "}");
|
||||
|
||||
case Type_Info_Enum:
|
||||
os.write_string(fd, "enum ");
|
||||
__print_type(fd, info.base);
|
||||
os.write_string(fd, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do os.write_string(fd, ", ");
|
||||
os.write_string(fd, name);
|
||||
}
|
||||
os.write_string(fd, "}");
|
||||
|
||||
case Type_Info_Bit_Field:
|
||||
os.write_string(fd, "bit_field ");
|
||||
if ti.align != 1 {
|
||||
os.write_string(fd, "#align ");
|
||||
__print_u64(fd, u64(ti.align));
|
||||
os.write_byte(fd, ' ');
|
||||
}
|
||||
os.write_string(fd, " {");
|
||||
for name, i in info.names {
|
||||
if i > 0 do os.write_string(fd, ", ");
|
||||
os.write_string(fd, name);
|
||||
os.write_string(fd, ": ");
|
||||
__print_u64(fd, u64(info.bits[i]));
|
||||
}
|
||||
os.write_string(fd, "}");
|
||||
}
|
||||
}
|
||||
|
||||
__string_eq :: proc "contextless" (a, b: string) -> bool {
|
||||
switch {
|
||||
case len(a) != len(b): return false;
|
||||
case len(a) == 0: return true;
|
||||
case &a[0] == &b[0]: return true;
|
||||
}
|
||||
return __string_cmp(a, b) == 0;
|
||||
}
|
||||
|
||||
__string_cmp :: proc "contextless" (a, b: string) -> int {
|
||||
return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
|
||||
}
|
||||
|
||||
__string_ne :: inline proc "contextless" (a, b: string) -> bool { return !__string_eq(a, b); }
|
||||
__string_lt :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) < 0; }
|
||||
__string_gt :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) > 0; }
|
||||
__string_le :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) <= 0; }
|
||||
__string_ge :: inline proc "contextless" (a, b: string) -> bool { return __string_cmp(a, b) >= 0; }
|
||||
|
||||
__cstring_len :: proc "contextless" (s: cstring) -> int {
|
||||
n := 0;
|
||||
for p := (^byte)(s); p != nil && p^ != 0; p = mem.ptr_offset(p, 1) {
|
||||
n += 1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
__cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
if s == nil do return "";
|
||||
ptr := (^byte)(s);
|
||||
n := __cstring_len(s);
|
||||
return transmute(string)mem.Raw_String{ptr, n};
|
||||
}
|
||||
|
||||
|
||||
__complex64_eq :: inline proc "contextless" (a, b: complex64) -> bool { return real(a) == real(b) && imag(a) == imag(b); }
|
||||
__complex64_ne :: inline proc "contextless" (a, b: complex64) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
|
||||
|
||||
__complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) == real(b) && imag(a) == imag(b); }
|
||||
__complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); }
|
||||
|
||||
|
||||
bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) {
|
||||
if 0 <= index && index < count do return;
|
||||
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, Source_Code_Location{file, line, column, ""});
|
||||
os.write_string(fd, " Index ");
|
||||
__print_i64(fd, i64(index));
|
||||
os.write_string(fd, " is out of bounds range 0:");
|
||||
__print_i64(fd, i64(count));
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
|
||||
slice_expr_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) {
|
||||
if 0 <= lo && lo <= hi && hi <= len do return;
|
||||
|
||||
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, Source_Code_Location{file, line, column, ""});
|
||||
os.write_string(fd, " Invalid slice indices: ");
|
||||
__print_i64(fd, i64(lo));
|
||||
os.write_string(fd, ":");
|
||||
__print_i64(fd, i64(hi));
|
||||
os.write_string(fd, ":");
|
||||
__print_i64(fd, i64(len));
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
|
||||
dynamic_array_expr_error :: proc "contextless" (file: string, line, column: int, low, high, max: int) {
|
||||
if 0 <= low && low <= high && high <= max do return;
|
||||
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, Source_Code_Location{file, line, column, ""});
|
||||
os.write_string(fd, " Invalid dynamic array values: ");
|
||||
__print_i64(fd, i64(low));
|
||||
os.write_string(fd, ":");
|
||||
__print_i64(fd, i64(high));
|
||||
os.write_string(fd, ":");
|
||||
__print_i64(fd, i64(max));
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
|
||||
|
||||
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: int, from, to: typeid) {
|
||||
if ok do return;
|
||||
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, Source_Code_Location{file, line, column, ""});
|
||||
os.write_string(fd, " Invalid type assertion from ");
|
||||
__print_typeid(fd, from);
|
||||
os.write_string(fd, " to ");
|
||||
__print_typeid(fd, to);
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
|
||||
__string_decode_rune :: inline proc "contextless" (s: string) -> (rune, int) {
|
||||
return utf8.decode_rune_from_string(s);
|
||||
}
|
||||
|
||||
bounds_check_error_loc :: inline proc "contextless" (using loc := #caller_location, index, count: int) {
|
||||
bounds_check_error(file_path, int(line), int(column), index, count);
|
||||
}
|
||||
|
||||
slice_expr_error_loc :: inline proc "contextless" (using loc := #caller_location, lo, hi: int, len: int) {
|
||||
slice_expr_error(file_path, int(line), int(column), lo, hi, len);
|
||||
}
|
||||
|
||||
dynamic_array_expr_error_loc :: inline proc "contextless" (using loc := #caller_location, low, high, max: int) {
|
||||
dynamic_array_expr_error(file_path, int(line), int(column), low, high, max);
|
||||
}
|
||||
|
||||
|
||||
make_slice_error_loc :: inline proc "contextless" (using loc := #caller_location, len: int) {
|
||||
if 0 <= len do return;
|
||||
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, loc);
|
||||
os.write_string(fd, " Invalid slice length for make: ");
|
||||
__print_i64(fd, i64(len));
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
|
||||
make_dynamic_array_error_loc :: inline proc "contextless" (using loc := #caller_location, len, cap: int) {
|
||||
if 0 <= len && len <= cap do return;
|
||||
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, loc);
|
||||
os.write_string(fd, " Invalid dynamic array parameters for make: ");
|
||||
__print_i64(fd, i64(len));
|
||||
os.write_byte(fd, ':');
|
||||
__print_i64(fd, i64(cap));
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
|
||||
make_map_expr_error_loc :: inline proc "contextless" (using loc := #caller_location, cap: int) {
|
||||
if 0 <= cap do return;
|
||||
|
||||
fd := os.stderr;
|
||||
__print_caller_location(fd, loc);
|
||||
os.write_string(fd, " Invalid map capacity for make: ");
|
||||
__print_i64(fd, i64(cap));
|
||||
os.write_byte(fd, '\n');
|
||||
debug_trap();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@(default_calling_convention = "c")
|
||||
foreign {
|
||||
@(link_name="llvm.sqrt.f32") __sqrt_f32 :: proc(x: f32) -> f32 ---
|
||||
@(link_name="llvm.sqrt.f64") __sqrt_f64 :: proc(x: f64) -> f64 ---
|
||||
|
||||
@(link_name="llvm.sin.f32") __sin_f32 :: proc(θ: f32) -> f32 ---
|
||||
@(link_name="llvm.sin.f64") __sin_f64 :: proc(θ: f64) -> f64 ---
|
||||
|
||||
@(link_name="llvm.cos.f32") __cos_f32 :: proc(θ: f32) -> f32 ---
|
||||
@(link_name="llvm.cos.f64") __cos_f64 :: proc(θ: f64) -> f64 ---
|
||||
|
||||
@(link_name="llvm.pow.f32") __pow_f32 :: proc(x, power: f32) -> f32 ---
|
||||
@(link_name="llvm.pow.f64") __pow_f64 :: proc(x, power: f64) -> f64 ---
|
||||
|
||||
@(link_name="llvm.fmuladd.f32") fmuladd32 :: proc(a, b, c: f32) -> f32 ---
|
||||
@(link_name="llvm.fmuladd.f64") fmuladd64 :: proc(a, b, c: f64) -> f64 ---
|
||||
}
|
||||
__abs_f32 :: inline proc "contextless" (x: f32) -> f32 {
|
||||
foreign {
|
||||
@(link_name="llvm.fabs.f32") _abs :: proc "c" (x: f32) -> f32 ---
|
||||
}
|
||||
return _abs(x);
|
||||
}
|
||||
__abs_f64 :: inline proc "contextless" (x: f64) -> f64 {
|
||||
foreign {
|
||||
@(link_name="llvm.fabs.f64") _abs :: proc "c" (x: f64) -> f64 ---
|
||||
}
|
||||
return _abs(x);
|
||||
}
|
||||
|
||||
__min_f32 :: proc(a, b: f32) -> f32 {
|
||||
foreign {
|
||||
@(link_name="llvm.minnum.f32") _min :: proc "c" (a, b: f32) -> f32 ---
|
||||
}
|
||||
return _min(a, b);
|
||||
}
|
||||
__min_f64 :: proc(a, b: f64) -> f64 {
|
||||
foreign {
|
||||
@(link_name="llvm.minnum.f64") _min :: proc "c" (a, b: f64) -> f64 ---
|
||||
}
|
||||
return _min(a, b);
|
||||
}
|
||||
__max_f32 :: proc(a, b: f32) -> f32 {
|
||||
foreign {
|
||||
@(link_name="llvm.maxnum.f32") _max :: proc "c" (a, b: f32) -> f32 ---
|
||||
}
|
||||
return _max(a, b);
|
||||
}
|
||||
__max_f64 :: proc(a, b: f64) -> f64 {
|
||||
foreign {
|
||||
@(link_name="llvm.maxnum.f64") _max :: proc "c" (a, b: f64) -> f64 ---
|
||||
}
|
||||
return _max(a, b);
|
||||
}
|
||||
|
||||
__abs_complex64 :: inline proc "contextless" (x: complex64) -> f32 {
|
||||
r, i := real(x), imag(x);
|
||||
return __sqrt_f32(r*r + i*i);
|
||||
}
|
||||
__abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 {
|
||||
r, i := real(x), imag(x);
|
||||
return __sqrt_f64(r*r + i*i);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package runtime
|
||||
|
||||
foreign import kernel32 "system:Kernel32.lib"
|
||||
|
||||
@(link_name="memcpy")
|
||||
memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||
foreign kernel32 {
|
||||
RtlCopyMemory :: proc "c" (dst, src: rawptr, len: int) ---
|
||||
}
|
||||
RtlCopyMemory(dst, src, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
@(link_name="memmove")
|
||||
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||
foreign kernel32 {
|
||||
RtlMoveMemory :: proc "c" (dst, src: rawptr, len: int) ---
|
||||
}
|
||||
RtlMoveMemory(dst, src, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
@(link_name="memset")
|
||||
memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
|
||||
foreign kernel32 {
|
||||
RtlFillMemory :: proc "c" (dst: rawptr, len: int, fill: byte) ---
|
||||
}
|
||||
RtlFillMemory(ptr, len, byte(val));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// @(link_name="memcmp")
|
||||
// memcmp :: proc "c" (dst, src: rawptr, len: int) -> i32 {
|
||||
// if dst == nil || src == nil {
|
||||
// return 0;
|
||||
// }
|
||||
// if dst == src {
|
||||
// return 0;
|
||||
// }
|
||||
// d, s := uintptr(dst), uintptr(src);
|
||||
// n := uintptr(len);
|
||||
|
||||
// for i := uintptr(0); i < n; i += 1 {
|
||||
// x, y := (^byte)(d+i)^, (^byte)(s+i)^;
|
||||
// if x != y {
|
||||
// return x < y ? -1 : +1;
|
||||
// }
|
||||
// }
|
||||
// return 0;
|
||||
// }
|
||||
@@ -1,3 +1,7 @@
|
||||
package sort
|
||||
|
||||
import "core:mem"
|
||||
|
||||
bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
assert(f != nil);
|
||||
count := len(array);
|
||||
@@ -7,7 +11,7 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
for {
|
||||
init_swap, prev_swap := -1, -1;
|
||||
|
||||
for j in init_j..last_j {
|
||||
for j in init_j..last_j-1 {
|
||||
if f(array[j], array[j+1]) > 0 {
|
||||
array[j], array[j+1] = array[j+1], array[j];
|
||||
prev_swap = j;
|
||||
@@ -30,7 +34,7 @@ bubble_sort :: proc(array: $A/[]$T) {
|
||||
for {
|
||||
init_swap, prev_swap := -1, -1;
|
||||
|
||||
for j in init_j..last_j {
|
||||
for j in init_j..last_j-1 {
|
||||
if array[j] > array[j+1] {
|
||||
array[j], array[j+1] = array[j+1], array[j];
|
||||
prev_swap = j;
|
||||
@@ -65,8 +69,8 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
j -= 1;
|
||||
}
|
||||
|
||||
quick_sort(a[0..i], f);
|
||||
quick_sort(a[i..n], f);
|
||||
quick_sort_proc(a[0:i], f);
|
||||
quick_sort_proc(a[i:n], f);
|
||||
}
|
||||
|
||||
quick_sort :: proc(array: $A/[]$T) {
|
||||
@@ -88,8 +92,8 @@ quick_sort :: proc(array: $A/[]$T) {
|
||||
j -= 1;
|
||||
}
|
||||
|
||||
quick_sort(a[0..i]);
|
||||
quick_sort(a[i..n]);
|
||||
quick_sort(a[0:i]);
|
||||
quick_sort(a[i:n]);
|
||||
}
|
||||
|
||||
_log2 :: proc(n: int) -> int {
|
||||
@@ -102,7 +106,7 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
merge_slices :: proc(arr1, arr2, out: A, f: proc(T, T) -> int) {
|
||||
N1, N2 := len(arr1), len(arr2);
|
||||
i, j := 0, 0;
|
||||
for k in 0..N1+N2 {
|
||||
for k in 0..N1+N2-1 {
|
||||
if j == N2 || i < N1 && j < N2 && f(arr1[i], arr2[j]) < 0 {
|
||||
out[k] = arr1[i];
|
||||
i += 1;
|
||||
@@ -122,16 +126,16 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) {
|
||||
|
||||
a, b, m, M := N/2, N, 1, _log2(N);
|
||||
|
||||
for i in 0..M+1 {
|
||||
for j in 0..a {
|
||||
for i in 0..M {
|
||||
for j in 0..a-1 {
|
||||
k := 2*j*m;
|
||||
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..], f);
|
||||
merge_slices(arr1[k:k+m], arr1[k+m:k+m+m], arr2[k:], f);
|
||||
}
|
||||
if N-b > m {
|
||||
k := 2*a*m;
|
||||
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..], f);
|
||||
merge_slices(arr1[k:k+m], arr1[k+m : k+m+(N-b)&(m-1)], arr2[k:], f);
|
||||
} else {
|
||||
copy(arr2[b..N], arr1[b..N]);
|
||||
copy(arr2[b:N], arr1[b:N]);
|
||||
}
|
||||
arr1, arr2 = arr2, arr1;
|
||||
m <<= 1;
|
||||
@@ -146,7 +150,7 @@ merge_sort :: proc(array: $A/[]$T) {
|
||||
merge_slices :: proc(arr1, arr2, out: A) {
|
||||
N1, N2 := len(arr1), len(arr2);
|
||||
i, j := 0, 0;
|
||||
for k in 0..N1+N2 {
|
||||
for k in 0..N1+N2-1 {
|
||||
if j == N2 || i < N1 && j < N2 && arr1[i] < arr2[j] {
|
||||
out[k] = arr1[i];
|
||||
i += 1;
|
||||
@@ -164,16 +168,16 @@ merge_sort :: proc(array: $A/[]$T) {
|
||||
|
||||
a, b, m, M := N/2, N, 1, _log2(N);
|
||||
|
||||
for i in 0..M+1 {
|
||||
for j in 0..a {
|
||||
for i in 0..M {
|
||||
for j in 0..a-1 {
|
||||
k := 2*j*m;
|
||||
merge_slices(arr1[k..k+m], arr1[k+m..k+m+m], arr2[k..]);
|
||||
merge_slices(arr1[k:k+m], arr1[k+m:k+m+m], arr2[k:]);
|
||||
}
|
||||
if N-b > m {
|
||||
k := 2*a*m;
|
||||
merge_slices(arr1[k..k+m], arr1[k+m..k+m+(N-b)&(m-1)], arr2[k..]);
|
||||
merge_slices(arr1[k:k+m], arr1[k+m : k+m+(N-b)&(m-1)], arr2[k:]);
|
||||
} else {
|
||||
copy(arr2[b..N], arr1[b..N]);
|
||||
copy(arr2[b:N], arr1[b:N]);
|
||||
}
|
||||
arr1, arr2 = arr2, arr1;
|
||||
m <<= 1;
|
||||
@@ -209,5 +213,5 @@ compare_f64s :: proc(a, b: f64) -> int {
|
||||
return 0;
|
||||
}
|
||||
compare_strings :: proc(a, b: string) -> int {
|
||||
return __string_cmp(a, b);
|
||||
return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b)));
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
using import "core:decimal.odin"
|
||||
package strconv
|
||||
|
||||
using import "core:decimal"
|
||||
|
||||
Int_Flag :: enum {
|
||||
Prefix = 1<<0,
|
||||
Plus = 1<<1,
|
||||
Space = 1<<2,
|
||||
Prefix,
|
||||
Plus,
|
||||
Space,
|
||||
}
|
||||
Int_Flags :: bit_set[Int_Flag];
|
||||
|
||||
|
||||
parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
|
||||
@@ -21,9 +24,9 @@ _digit_value :: proc(r: rune) -> int {
|
||||
ri := int(r);
|
||||
v: int = 16;
|
||||
switch r {
|
||||
case '0'...'9': v = ri-'0';
|
||||
case 'a'...'z': v = ri-'a'+10;
|
||||
case 'A'...'Z': v = ri-'A'+10;
|
||||
case '0'..'9': v = ri-'0';
|
||||
case 'a'..'z': v = ri-'a'+10;
|
||||
case 'A'..'Z': v = ri-'A'+10;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@@ -34,9 +37,9 @@ parse_i64 :: proc(s: string) -> i64 {
|
||||
switch s[0] {
|
||||
case '-':
|
||||
neg = true;
|
||||
s = s[1..];
|
||||
s = s[1:];
|
||||
case '+':
|
||||
s = s[1..];
|
||||
s = s[1:];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +47,11 @@ parse_i64 :: proc(s: string) -> i64 {
|
||||
base: i64 = 10;
|
||||
if len(s) > 2 && s[0] == '0' {
|
||||
switch s[1] {
|
||||
case 'b': base = 2; s = s[2..];
|
||||
case 'o': base = 8; s = s[2..];
|
||||
case 'd': base = 10; s = s[2..];
|
||||
case 'z': base = 12; s = s[2..];
|
||||
case 'x': base = 16; s = s[2..];
|
||||
case 'b': base = 2; s = s[2:];
|
||||
case 'o': base = 8; s = s[2:];
|
||||
case 'd': base = 10; s = s[2:];
|
||||
case 'z': base = 12; s = s[2:];
|
||||
case 'x': base = 16; s = s[2:];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,18 +77,18 @@ parse_i64 :: proc(s: string) -> i64 {
|
||||
parse_u64 :: proc(s: string) -> u64 {
|
||||
neg := false;
|
||||
if len(s) > 1 && s[0] == '+' {
|
||||
s = s[1..];
|
||||
s = s[1:];
|
||||
}
|
||||
|
||||
|
||||
base := u64(10);
|
||||
if len(s) > 2 && s[0] == '0' {
|
||||
switch s[1] {
|
||||
case 'b': base = 2; s = s[2..];
|
||||
case 'o': base = 8; s = s[2..];
|
||||
case 'd': base = 10; s = s[2..];
|
||||
case 'z': base = 12; s = s[2..];
|
||||
case 'x': base = 16; s = s[2..];
|
||||
case 'b': base = 2; s = s[2:];
|
||||
case 'o': base = 8; s = s[2:];
|
||||
case 'd': base = 10; s = s[2:];
|
||||
case 'z': base = 12; s = s[2:];
|
||||
case 'x': base = 16; s = s[2:];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,14 +195,14 @@ append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
n := 0;
|
||||
if b do n = copy(buf, cast([]byte)"true");
|
||||
else do n = copy(buf, cast([]byte)"false");
|
||||
return string(buf[..n]);
|
||||
return string(buf[:n]);
|
||||
}
|
||||
|
||||
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
|
||||
return append_bits(buf, u64(u), base, false, 8*size_of(uint), digits, 0);
|
||||
return append_bits(buf, u64(u), base, false, 8*size_of(uint), digits, nil);
|
||||
}
|
||||
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
|
||||
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, 0);
|
||||
return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil);
|
||||
}
|
||||
itoa :: proc(buf: []byte, i: int) -> string do return append_int(buf, i64(i), 10);
|
||||
|
||||
@@ -258,7 +261,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
||||
s = "+Inf";
|
||||
}
|
||||
n := copy(buf, cast([]byte)s);
|
||||
return buf[..n];
|
||||
return buf[:n];
|
||||
|
||||
case 0: // denormalized
|
||||
exp += 1;
|
||||
@@ -277,7 +280,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
||||
shortest := prec < 0;
|
||||
if shortest {
|
||||
round_shortest(d, mant, exp, flt);
|
||||
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||
digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
||||
switch fmt {
|
||||
case 'e', 'E': prec = digs.count-1;
|
||||
case 'f', 'F': prec = max(digs.count-digs.decimal_point, 0);
|
||||
@@ -294,7 +297,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, prec, bit_size: int) -> [
|
||||
round(d, prec);
|
||||
}
|
||||
|
||||
digs = DecimalSlice{digits = d.digits[..], count = d.count, decimal_point = d.decimal_point};
|
||||
digs = DecimalSlice{digits = d.digits[:], count = d.count, decimal_point = d.decimal_point};
|
||||
}
|
||||
return format_digits(buf, shortest, neg, digs, prec, fmt);
|
||||
}
|
||||
@@ -307,9 +310,9 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
|
||||
n: int,
|
||||
}
|
||||
|
||||
to_bytes :: proc(b: Buffer) -> []byte do return b.b[..b.n];
|
||||
add_bytes :: proc(buf: ^Buffer, bytes: ...byte) {
|
||||
buf.n += copy(buf.b[buf.n..], bytes);
|
||||
to_bytes :: proc(b: Buffer) -> []byte do return b.b[:b.n];
|
||||
add_bytes :: proc(buf: ^Buffer, bytes: ..byte) {
|
||||
buf.n += copy(buf.b[buf.n:], bytes);
|
||||
}
|
||||
|
||||
b := Buffer{b = buf};
|
||||
@@ -321,7 +324,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
|
||||
// integer, padded with zeros when needed
|
||||
if digs.decimal_point > 0 {
|
||||
m := min(digs.count, digs.decimal_point);
|
||||
add_bytes(&b, ...digs.digits[0..m]);
|
||||
add_bytes(&b, ..digs.digits[0:m]);
|
||||
for ; m < digs.decimal_point; m += 1 {
|
||||
add_bytes(&b, '0');
|
||||
}
|
||||
@@ -333,7 +336,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: DecimalSlice
|
||||
// fractional part
|
||||
if prec > 0 {
|
||||
add_bytes(&b, '.');
|
||||
for i in 0..prec {
|
||||
for i in 0..prec-1 {
|
||||
c: byte = '0';
|
||||
if j := digs.decimal_point + i; 0 <= j && j < digs.count {
|
||||
c = digs.digits[j];
|
||||
@@ -396,7 +399,7 @@ round_shortest :: proc(d: ^Decimal, mant: u64, exp: int, flt: ^FloatInfo) {
|
||||
|
||||
inclusive := mant%2 == 0;
|
||||
|
||||
for i in 0..d.count {
|
||||
for i in 0..d.count-1 {
|
||||
l: byte = '0'; // lower digit
|
||||
if i < lower.count {
|
||||
l = lower.digits[i];
|
||||
@@ -456,7 +459,7 @@ is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned
|
||||
return u, neg;
|
||||
}
|
||||
|
||||
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
|
||||
append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
|
||||
if base < 2 || base > MAX_BASE {
|
||||
panic("strconv: illegal base passed to append_bits");
|
||||
}
|
||||
@@ -472,7 +475,7 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
|
||||
}
|
||||
i-=1; a[i] = digits[u % b];
|
||||
|
||||
if flags&Int_Flag.Prefix != 0 {
|
||||
if Int_Flag.Prefix in flags {
|
||||
ok := true;
|
||||
switch base {
|
||||
case 2: i-=1; a[i] = 'b';
|
||||
@@ -490,14 +493,14 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
|
||||
switch {
|
||||
case neg:
|
||||
i-=1; a[i] = '-';
|
||||
case flags&Int_Flag.Plus != 0:
|
||||
case Int_Flag.Plus in flags:
|
||||
i-=1; a[i] = '+';
|
||||
case flags&Int_Flag.Space != 0:
|
||||
case Int_Flag.Space in flags:
|
||||
i-=1; a[i] = ' ';
|
||||
}
|
||||
|
||||
out := a[i..];
|
||||
out := a[i:];
|
||||
copy(buf, out);
|
||||
return string(buf[0..len(out)]);
|
||||
return string(buf[0:len(out)]);
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import "core:mem.odin"
|
||||
|
||||
new_string :: proc(s: string) -> string {
|
||||
c := make([]byte, len(s)+1);
|
||||
copy(c, cast([]byte)s);
|
||||
c[len(s)] = 0;
|
||||
return string(c[..len(s)]);
|
||||
}
|
||||
|
||||
new_c_string :: proc(s: string) -> ^byte {
|
||||
c := make([]byte, len(s)+1);
|
||||
copy(c, cast([]byte)s);
|
||||
c[len(s)] = 0;
|
||||
return &c[0];
|
||||
}
|
||||
|
||||
to_odin_string :: proc(str: ^byte) -> string {
|
||||
if str == nil do return "";
|
||||
end := str;
|
||||
for end^ != 0 do end+=1;
|
||||
return string(mem.slice_ptr(str, end-str));
|
||||
}
|
||||
|
||||
contains_rune :: proc(s: string, r: rune) -> int {
|
||||
for c, offset in s {
|
||||
if c == r do return offset;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package strings
|
||||
|
||||
import "core:mem"
|
||||
|
||||
new_string :: proc(s: string) -> string {
|
||||
c := make([]byte, len(s)+1);
|
||||
copy(c, cast([]byte)s);
|
||||
c[len(s)] = 0;
|
||||
return string(c[:len(s)]);
|
||||
}
|
||||
|
||||
new_cstring :: proc(s: string) -> cstring {
|
||||
c := make([]byte, len(s)+1);
|
||||
copy(c, cast([]byte)s);
|
||||
c[len(s)] = 0;
|
||||
return cstring(&c[0]);
|
||||
}
|
||||
|
||||
@(deprecated="Please use a standard cast for cstring to string")
|
||||
to_odin_string :: proc(str: cstring) -> string {
|
||||
return string(str);
|
||||
}
|
||||
|
||||
string_from_ptr :: proc(ptr: ^byte, len: int) -> string {
|
||||
return transmute(string)mem.Raw_String{ptr, len};
|
||||
}
|
||||
|
||||
contains_rune :: proc(s: string, r: rune) -> int {
|
||||
for c, offset in s {
|
||||
if c == r do return offset;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
when ODIN_OS == "windows" do export "core:sync_windows.odin";
|
||||
when ODIN_OS == "linux" do export "core:sync_linux.odin";
|
||||
@@ -1,5 +1,9 @@
|
||||
import "core:atomics.odin"
|
||||
import "core:os.odin"
|
||||
package sync
|
||||
|
||||
/*
|
||||
|
||||
import "core:atomics"
|
||||
import "core:os"
|
||||
|
||||
Semaphore :: struct {
|
||||
// _handle: win32.Handle,
|
||||
@@ -91,3 +95,4 @@ mutex_unlock :: proc(m: ^Mutex) {
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,84 @@
|
||||
package sync
|
||||
|
||||
import "core:sys/win32"
|
||||
import "core:atomics"
|
||||
|
||||
Semaphore :: struct {
|
||||
_handle: win32.Handle,
|
||||
}
|
||||
|
||||
Mutex :: struct {
|
||||
_critical_section: win32.Critical_Section,
|
||||
}
|
||||
|
||||
Condition :: struct {
|
||||
event: win32.Handle,
|
||||
}
|
||||
|
||||
current_thread_id :: proc() -> i32 {
|
||||
return i32(win32.get_current_thread_id());
|
||||
}
|
||||
|
||||
semaphore_init :: proc(s: ^Semaphore) {
|
||||
s._handle = win32.create_semaphore_a(nil, 0, 1<<31-1, nil);
|
||||
}
|
||||
|
||||
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||
win32.close_handle(s._handle);
|
||||
}
|
||||
|
||||
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
||||
win32.release_semaphore(s._handle, i32(count), nil);
|
||||
}
|
||||
|
||||
semaphore_release :: inline proc(s: ^Semaphore) {
|
||||
semaphore_post(s, 1);
|
||||
}
|
||||
|
||||
semaphore_wait :: proc(s: ^Semaphore) {
|
||||
result := win32.wait_for_single_object(s._handle, win32.INFINITE);
|
||||
assert(result != win32.WAIT_FAILED);
|
||||
}
|
||||
|
||||
|
||||
mutex_init :: proc(m: ^Mutex, spin_count := 0) {
|
||||
win32.initialize_critical_section_and_spin_count(&m._critical_section, u32(spin_count));
|
||||
}
|
||||
|
||||
mutex_destroy :: proc(m: ^Mutex) {
|
||||
win32.delete_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
win32.enter_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
return bool(win32.try_enter_critical_section(&m._critical_section));
|
||||
}
|
||||
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
win32.leave_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
|
||||
condition_init :: proc(using c: ^Condition) {
|
||||
event = win32.create_event_a(nil, false, false, nil);
|
||||
assert(event != nil);
|
||||
}
|
||||
|
||||
condition_signal :: proc(using c: ^Condition) {
|
||||
ok := win32.set_event(event);
|
||||
assert(bool(ok));
|
||||
}
|
||||
|
||||
condition_wait_for :: proc(using c: ^Condition) {
|
||||
result := win32.wait_for_single_object(event, win32.INFINITE);
|
||||
assert(result != win32.WAIT_FAILED);
|
||||
}
|
||||
|
||||
condition_destroy :: proc(using c: ^Condition) {
|
||||
if event != nil {
|
||||
win32.close_handle(event);
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
when ODIN_OS == "windows" {
|
||||
import win32 "core:sys/windows.odin";
|
||||
}
|
||||
import "core:atomics.odin"
|
||||
|
||||
Semaphore :: struct {
|
||||
_handle: win32.Handle,
|
||||
}
|
||||
|
||||
/*
|
||||
Mutex :: struct {
|
||||
_semaphore: Semaphore,
|
||||
_counter: i32,
|
||||
_owner: i32,
|
||||
_recursion: i32,
|
||||
}
|
||||
*/
|
||||
|
||||
Mutex :: struct {
|
||||
_critical_section: win32.Critical_Section,
|
||||
}
|
||||
|
||||
current_thread_id :: proc() -> i32 {
|
||||
return i32(win32.get_current_thread_id());
|
||||
}
|
||||
|
||||
semaphore_init :: proc(s: ^Semaphore) {
|
||||
s._handle = win32.create_semaphore_a(nil, 0, 1<<31-1, nil);
|
||||
}
|
||||
|
||||
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||
win32.close_handle(s._handle);
|
||||
}
|
||||
|
||||
semaphore_post :: proc(s: ^Semaphore, count: int) {
|
||||
win32.release_semaphore(s._handle, i32(count), nil);
|
||||
}
|
||||
|
||||
semaphore_release :: inline proc(s: ^Semaphore) {
|
||||
semaphore_post(s, 1);
|
||||
}
|
||||
|
||||
semaphore_wait :: proc(s: ^Semaphore) {
|
||||
win32.wait_for_single_object(s._handle, win32.INFINITE);
|
||||
}
|
||||
|
||||
|
||||
mutex_init :: proc(m: ^Mutex, spin_count := 0) {
|
||||
win32.initialize_critical_section_and_spin_count(&m._critical_section, u32(spin_count));
|
||||
}
|
||||
|
||||
mutex_destroy :: proc(m: ^Mutex) {
|
||||
win32.delete_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
win32.enter_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
return bool(win32.try_enter_critical_section(&m._critical_section));
|
||||
}
|
||||
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
win32.leave_critical_section(&m._critical_section);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
mutex_init :: proc(m: ^Mutex) {
|
||||
atomics.store(&m._counter, 0);
|
||||
atomics.store(&m._owner, current_thread_id());
|
||||
semaphore_init(&m._semaphore);
|
||||
m._recursion = 0;
|
||||
}
|
||||
mutex_destroy :: proc(m: ^Mutex) {
|
||||
semaphore_destroy(&m._semaphore);
|
||||
}
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
thread_id := current_thread_id();
|
||||
if atomics.fetch_add(&m._counter, 1) > 0 {
|
||||
if thread_id != atomics.load(&m._owner) {
|
||||
semaphore_wait(&m._semaphore);
|
||||
}
|
||||
}
|
||||
atomics.store(&m._owner, thread_id);
|
||||
m._recursion++;
|
||||
}
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
thread_id := current_thread_id();
|
||||
if atomics.load(&m._owner) == thread_id {
|
||||
atomics.fetch_add(&m._counter, 1);
|
||||
} else {
|
||||
expected: i32 = 0;
|
||||
if atomics.load(&m._counter) != 0 {
|
||||
return false;
|
||||
}
|
||||
if atomics.compare_exchange(&m._counter, expected, 1) == 0 {
|
||||
return false;
|
||||
}
|
||||
atomics.store(&m._owner, thread_id);
|
||||
}
|
||||
m._recursion++;
|
||||
return true;
|
||||
}
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
recursion: i32;
|
||||
thread_id := current_thread_id();
|
||||
assert(thread_id == atomics.load(&m._owner));
|
||||
|
||||
m._recursion--;
|
||||
recursion = m._recursion;
|
||||
if recursion == 0 {
|
||||
atomics.store(&m._owner, thread_id);
|
||||
}
|
||||
|
||||
if atomics.fetch_add(&m._counter, -1) > 1 {
|
||||
if recursion == 0 {
|
||||
semaphore_release(&m._semaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -1,8 +1,7 @@
|
||||
when ODIN_OS == "windows" {
|
||||
foreign import "system:opengl32.lib"
|
||||
using import "core:sys/windows.odin"
|
||||
}
|
||||
// +build windows
|
||||
package win32
|
||||
|
||||
foreign import "system:opengl32.lib"
|
||||
|
||||
CONTEXT_MAJOR_VERSION_ARB :: 0x2091;
|
||||
CONTEXT_MINOR_VERSION_ARB :: 0x2092;
|
||||
@@ -55,7 +54,7 @@ Glyph_Metrics_Float :: struct {
|
||||
Create_Context_Attribs_ARB_Type :: #type proc "c" (hdc: Hdc, h_share_context: rawptr, attribList: ^i32) -> Hglrc;
|
||||
Choose_Pixel_Format_ARB_Type :: #type proc "c" (hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool;
|
||||
Swap_Interval_EXT_Type :: #type proc "c" (interval: i32) -> bool;
|
||||
Get_Extensions_String_ARB_Type :: #type proc "c" (Hdc) -> ^byte;
|
||||
Get_Extensions_String_ARB_Type :: #type proc "c" (Hdc) -> cstring;
|
||||
|
||||
// Procedures
|
||||
create_context_attribs_arb: Create_Context_Attribs_ARB_Type;
|
||||
@@ -72,7 +71,7 @@ foreign opengl32 {
|
||||
make_current :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool ---;
|
||||
|
||||
@(link_name="wglGetProcAddress")
|
||||
get_gl_proc_address :: proc(c_str: ^byte) -> rawptr ---;
|
||||
get_gl_proc_address :: proc(c_str: cstring) -> rawptr ---;
|
||||
|
||||
@(link_name="wglDeleteContext")
|
||||
delete_context :: proc(hglrc: Hglrc) -> Bool ---;
|
||||
@@ -1,10 +1,11 @@
|
||||
when ODIN_OS == "windows" {
|
||||
foreign import "system:kernel32.lib"
|
||||
foreign import "system:user32.lib"
|
||||
foreign import "system:gdi32.lib"
|
||||
foreign import "system:winmm.lib"
|
||||
foreign import "system:shell32.lib"
|
||||
}
|
||||
// +build windows
|
||||
package win32
|
||||
|
||||
foreign import "system:kernel32.lib"
|
||||
foreign import "system:user32.lib"
|
||||
foreign import "system:gdi32.lib"
|
||||
foreign import "system:winmm.lib"
|
||||
foreign import "system:shell32.lib"
|
||||
|
||||
Handle :: distinct rawptr;
|
||||
Hwnd :: distinct Handle;
|
||||
@@ -28,6 +29,8 @@ Long_Ptr :: distinct int;
|
||||
|
||||
Bool :: distinct b32;
|
||||
|
||||
Wstring :: ^u16;
|
||||
|
||||
Point :: struct {
|
||||
x, y: i32,
|
||||
}
|
||||
@@ -40,7 +43,7 @@ Wnd_Class_Ex_A :: struct {
|
||||
icon: Hicon,
|
||||
cursor: Hcursor,
|
||||
background: Hbrush,
|
||||
menu_name, class_name: ^byte,
|
||||
menu_name, class_name: cstring,
|
||||
sm: Hicon,
|
||||
}
|
||||
|
||||
@@ -52,7 +55,7 @@ Wnd_Class_Ex_W :: struct {
|
||||
icon: Hicon,
|
||||
cursor: Hcursor,
|
||||
background: Hbrush,
|
||||
menu_name, class_name: ^u16,
|
||||
menu_name, class_name: Wstring,
|
||||
sm: Hicon,
|
||||
}
|
||||
|
||||
@@ -105,7 +108,20 @@ File_Attribute_Data :: struct {
|
||||
file_size_low: u32,
|
||||
}
|
||||
|
||||
Find_Data :: struct{
|
||||
Find_Data_W :: struct{
|
||||
file_attributes: u32,
|
||||
creation_time: Filetime,
|
||||
last_access_time: Filetime,
|
||||
last_write_time: Filetime,
|
||||
file_size_high: u32,
|
||||
file_size_low: u32,
|
||||
reserved0: u32,
|
||||
reserved1: u32,
|
||||
file_name: [MAX_PATH]u16,
|
||||
alternate_file_name: [14]u16,
|
||||
}
|
||||
|
||||
Find_Data_A :: struct{
|
||||
file_attributes: u32,
|
||||
creation_time: Filetime,
|
||||
last_access_time: Filetime,
|
||||
@@ -132,24 +148,24 @@ Process_Information :: struct {
|
||||
}
|
||||
|
||||
Startup_Info :: struct {
|
||||
cb : u32,
|
||||
reserved : ^u16,
|
||||
desktop : ^u16,
|
||||
title : ^u16,
|
||||
x : u32,
|
||||
y : u32,
|
||||
x_size : u32,
|
||||
y_size : u32,
|
||||
x_count_chars : u32,
|
||||
y_count_chars : u32,
|
||||
fill_attribute : u32,
|
||||
flags : u32,
|
||||
show_window : u16,
|
||||
_ : u16,
|
||||
_ : ^byte,
|
||||
stdin : Handle,
|
||||
stdout : Handle,
|
||||
stderr : Handle,
|
||||
cb: u32,
|
||||
reserved: Wstring,
|
||||
desktop: Wstring,
|
||||
title: Wstring,
|
||||
x: u32,
|
||||
y: u32,
|
||||
x_size: u32,
|
||||
y_size: u32,
|
||||
x_count_chars: u32,
|
||||
y_count_chars: u32,
|
||||
fill_attribute: u32,
|
||||
flags: u32,
|
||||
show_window: u16,
|
||||
_: u16,
|
||||
_: cstring,
|
||||
stdin: Handle,
|
||||
stdout: Handle,
|
||||
stderr: Handle,
|
||||
}
|
||||
|
||||
Pixel_Format_Descriptor :: struct {
|
||||
@@ -263,16 +279,16 @@ Raw_Input :: struct {
|
||||
|
||||
|
||||
Overlapped :: struct {
|
||||
internal : ^u64,
|
||||
internal_high : ^u64,
|
||||
using _ : struct #raw_union {
|
||||
using _ : struct {
|
||||
offset : u32,
|
||||
offset_high : u32,
|
||||
internal: ^u64,
|
||||
internal_high: ^u64,
|
||||
using _: struct #raw_union {
|
||||
using _: struct {
|
||||
offset: u32,
|
||||
offset_high: u32,
|
||||
},
|
||||
pointer : rawptr,
|
||||
pointer: rawptr,
|
||||
},
|
||||
event : Handle,
|
||||
event: Handle,
|
||||
}
|
||||
|
||||
File_Notify_Information :: struct {
|
||||
@@ -376,7 +392,7 @@ Hwnd_TOP :: Hwnd(uintptr(0));
|
||||
|
||||
BI_RGB :: 0;
|
||||
DIB_RGB_COLORS :: 0x00;
|
||||
SRCCOPY: u32 : 0x00cc0020;
|
||||
SRCCOPY: u32 : 0x00cc0020;
|
||||
|
||||
|
||||
MONITOR_DEFAULTTONULL :: 0x00000000;
|
||||
@@ -537,22 +553,27 @@ CP_UTF8 :: 65001; // UTF-8 translation
|
||||
@(default_calling_convention = "std")
|
||||
foreign kernel32 {
|
||||
@(link_name="GetLastError") get_last_error :: proc() -> i32 ---;
|
||||
@(link_name="CreateProcessA") create_process_a :: proc(application_name, command_line: ^byte,
|
||||
@(link_name="CreateProcessA") create_process_a :: proc(application_name, command_line: cstring,
|
||||
process_attributes, thread_attributes: ^Security_Attributes,
|
||||
inherit_handle: Bool, creation_flags: u32, environment: rawptr,
|
||||
current_direcotry: ^byte, startup_info : ^Startup_Info,
|
||||
process_information : ^Process_Information) -> Bool ---;
|
||||
current_direcotry: cstring, startup_info: ^Startup_Info,
|
||||
process_information: ^Process_Information) -> Bool ---;
|
||||
@(link_name="CreateProcessW") create_process_w :: proc(application_name, command_line: Wstring,
|
||||
process_attributes, thread_attributes: ^Security_Attributes,
|
||||
inherit_handle: Bool, creation_flags: u32, environment: rawptr,
|
||||
current_direcotry: cstring, startup_info: ^Startup_Info,
|
||||
process_information: ^Process_Information) -> Bool ---;
|
||||
@(link_name="GetExitCodeProcess") get_exit_code_process :: proc(process: Handle, exit: ^u32) -> Bool ---;
|
||||
@(link_name="ExitProcess") exit_process :: proc(exit_code: u32) ---;
|
||||
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: ^byte) -> Hinstance ---;
|
||||
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: ^u16) -> Hinstance ---;
|
||||
@(link_name="GetModuleHandleA") get_module_handle_a :: proc(module_name: cstring) -> Hinstance ---;
|
||||
@(link_name="GetModuleHandleW") get_module_handle_w :: proc(module_name: Wstring) -> Hinstance ---;
|
||||
@(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---;
|
||||
@(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---;
|
||||
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: ^byte) ---;
|
||||
@(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: cstring) ---;
|
||||
|
||||
@(link_name="GetCommandLineA") get_command_line_a :: proc() -> ^byte ---;
|
||||
@(link_name="GetCommandLineW") get_command_line_w :: proc() -> ^u16 ---;
|
||||
@(link_name="GetCommandLineA") get_command_line_a :: proc() -> cstring ---;
|
||||
@(link_name="GetCommandLineW") get_command_line_w :: proc() -> Wstring ---;
|
||||
@(link_name="GetSystemMetrics") get_system_metrics :: proc(index: i32) -> i32 ---;
|
||||
@(link_name="GetCurrentThreadId") get_current_thread_id :: proc() -> u32 ---;
|
||||
|
||||
@@ -565,44 +586,59 @@ foreign kernel32 {
|
||||
@(link_name="GetStdHandle") get_std_handle :: proc(h: i32) -> Handle ---;
|
||||
|
||||
@(link_name="CreateFileA")
|
||||
create_file_a :: proc(filename: ^byte, desired_access, share_module: u32,
|
||||
create_file_a :: proc(filename: cstring, desired_access, share_module: u32,
|
||||
security: rawptr,
|
||||
creation, flags_and_attribs: u32, template_file: Handle) -> Handle ---;
|
||||
|
||||
@(link_name="CreateFileW")
|
||||
create_file_w :: proc(filename: Wstring, desired_access, share_module: u32,
|
||||
security: rawptr,
|
||||
creation, flags_and_attribs: u32, template_file: Handle) -> Handle ---;
|
||||
|
||||
|
||||
@(link_name="ReadFile") read_file :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool ---;
|
||||
@(link_name="WriteFile") write_file :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool ---;
|
||||
|
||||
@(link_name="GetFileSizeEx") get_file_size_ex :: proc(file_handle: Handle, file_size: ^i64) -> Bool ---;
|
||||
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: ^byte) -> u32 ---;
|
||||
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: ^byte, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---;
|
||||
@(link_name="GetFileAttributesA") get_file_attributes_a :: proc(filename: cstring) -> u32 ---;
|
||||
@(link_name="GetFileAttributesW") get_file_attributes_w :: proc(filename: Wstring) -> u32 ---;
|
||||
@(link_name="GetFileAttributesExA") get_file_attributes_ex_a :: proc(filename: cstring, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool ---;
|
||||
@(link_name="GetFileInformationByHandle") get_file_information_by_handle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool ---;
|
||||
|
||||
@(link_name="CreateDirectoryA") create_directory_a :: proc(path: ^byte, security_attributes: ^Security_Attributes) -> Bool ---;
|
||||
@(link_name="CreateDirectoryW") create_directory_w :: proc(path: ^u16, security_attributes: ^Security_Attributes) -> Bool ---;
|
||||
@(link_name="CreateDirectoryA") create_directory_a :: proc(path: cstring, security_attributes: ^Security_Attributes) -> Bool ---;
|
||||
@(link_name="CreateDirectoryW") create_directory_w :: proc(path: Wstring, security_attributes: ^Security_Attributes) -> Bool ---;
|
||||
|
||||
@(link_name="GetFileType") get_file_type :: proc(file_handle: Handle) -> u32 ---;
|
||||
@(link_name="SetFilePointer") set_file_pointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 ---;
|
||||
|
||||
@(link_name="SetHandleInformation") set_handle_information :: proc(obj: Handle, mask, flags: u32) -> Bool ---;
|
||||
|
||||
@(link_name="FindFirstFileA") find_first_file_a :: proc(file_name : ^byte, data : ^Find_Data) -> Handle ---;
|
||||
@(link_name="FindNextFileA") find_next_file_a :: proc(file : Handle, data : ^Find_Data) -> Bool ---;
|
||||
@(link_name="FindClose") find_close :: proc(file : Handle) -> Bool ---;
|
||||
@(link_name="FindFirstFileA") find_first_file_a :: proc(file_name: cstring, data: ^Find_Data_A) -> Handle ---;
|
||||
@(link_name="FindNextFileA") find_next_file_a :: proc(file: Handle, data: ^Find_Data_A) -> Bool ---;
|
||||
|
||||
@(link_name="MoveFileExA") move_file_ex_a :: proc(existing, new: ^byte, flags: u32) -> Bool ---;
|
||||
@(link_name="DeleteFileA") delete_file_a :: proc(file_name : ^byte) -> Bool ---;
|
||||
@(link_name="CopyFileA") copy_file_a :: proc(existing, new: ^byte, fail_if_exists: Bool) -> Bool ---;
|
||||
@(link_name="FindFirstFileW") find_first_file_w :: proc(file_name: Wstring, data: ^Find_Data_W) -> Handle ---;
|
||||
@(link_name="FindNextFileW") find_next_file_w :: proc(file: Handle, data: ^Find_Data_W) -> Bool ---;
|
||||
|
||||
@(link_name="MoveFileExW") move_file_ex_w :: proc(existing, new: ^u16, flags: u32) -> Bool ---;
|
||||
@(link_name="DeleteFileW") delete_file_w :: proc(file_name : ^u16) -> Bool ---;
|
||||
@(link_name="CopyFileW") copy_file_w :: proc(existing, new: ^u16, fail_if_exists: Bool) -> Bool ---;
|
||||
@(link_name="FindClose") find_close :: proc(file: Handle) -> Bool ---;
|
||||
|
||||
@(link_name="MoveFileExA") move_file_ex_a :: proc(existing, new: cstring, flags: u32) -> Bool ---;
|
||||
@(link_name="DeleteFileA") delete_file_a :: proc(file_name: cstring) -> Bool ---;
|
||||
@(link_name="CopyFileA") copy_file_a :: proc(existing, new: cstring, fail_if_exists: Bool) -> Bool ---;
|
||||
|
||||
@(link_name="MoveFileExW") move_file_ex_w :: proc(existing, new: Wstring, flags: u32) -> Bool ---;
|
||||
@(link_name="DeleteFileW") delete_file_w :: proc(file_name: Wstring) -> Bool ---;
|
||||
@(link_name="CopyFileW") copy_file_w :: proc(existing, new: Wstring, fail_if_exists: Bool) -> Bool ---;
|
||||
|
||||
@(link_name="HeapAlloc") heap_alloc :: proc(h: Handle, flags: u32, bytes: int) -> rawptr ---;
|
||||
@(link_name="HeapReAlloc") heap_realloc :: proc(h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr ---;
|
||||
@(link_name="HeapFree") heap_free :: proc(h: Handle, flags: u32, memory: rawptr) -> Bool ---;
|
||||
@(link_name="GetProcessHeap") get_process_heap :: proc() -> Handle ---;
|
||||
|
||||
@(link_name="FindFirstChangeNotificationA") find_first_change_notification_a :: proc(path: ^byte, watch_subtree: Bool, filter: u32) -> Handle ---;
|
||||
@(link_name="LocalAlloc") local_alloc :: proc(flags: u32, bytes: int) -> rawptr ---;
|
||||
@(link_name="LocalReAlloc") local_realloc :: proc(mem: rawptr, bytes: int, flags: uint) -> rawptr ---;
|
||||
@(link_name="LocalFree") local_free :: proc(mem: rawptr) -> rawptr ---;
|
||||
|
||||
@(link_name="FindFirstChangeNotificationA") find_first_change_notification_a :: proc(path: cstring, watch_subtree: Bool, filter: u32) -> Handle ---;
|
||||
@(link_name="FindNextChangeNotification") find_next_change_notification :: proc(h: Handle) -> Bool ---;
|
||||
@(link_name="FindCloseChangeNotification") find_close_change_notification :: proc(h: Handle) -> Bool ---;
|
||||
|
||||
@@ -611,12 +647,16 @@ foreign kernel32 {
|
||||
bytes_returned: ^u32, overlapped: ^Overlapped,
|
||||
completion: rawptr) -> Bool ---;
|
||||
|
||||
@(link_name="WideCharToMultiByte") wide_char_to_multi_byte :: proc(code_page: u32, flags : u32,
|
||||
wchar_str: ^u16, wchar: i32,
|
||||
multi_str: ^byte, multi: i32,
|
||||
default_char: ^byte, used_default_char: ^Bool) -> i32 ---;
|
||||
@(link_name="WideCharToMultiByte") wide_char_to_multi_byte :: proc(code_page: u32, flags: u32,
|
||||
wchar_str: Wstring, wchar: i32,
|
||||
multi_str: cstring, multi: i32,
|
||||
default_char: cstring, used_default_char: ^Bool) -> i32 ---;
|
||||
|
||||
@(link_name="CreateSemaphoreA") create_semaphore_a :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^byte) -> Handle ---;
|
||||
@(link_name="MultiByteToWideChar") multi_byte_to_wide_char :: proc(code_page: u32, flags: u32,
|
||||
mb_str: cstring, mb: i32,
|
||||
wc_str: Wstring, wc: i32) -> i32 ---;
|
||||
|
||||
@(link_name="CreateSemaphoreA") create_semaphore_a :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: cstring) -> Handle ---;
|
||||
@(link_name="ReleaseSemaphore") release_semaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool ---;
|
||||
@(link_name="WaitForSingleObject") wait_for_single_object :: proc(handle: Handle, milliseconds: u32) -> u32 ---;
|
||||
}
|
||||
@@ -649,7 +689,8 @@ foreign kernel32 {
|
||||
@(link_name="ResumeThread") resume_thread :: proc(thread: Handle) -> u32 ---;
|
||||
@(link_name="GetThreadPriority") get_thread_priority :: proc(thread: Handle) -> i32 ---;
|
||||
@(link_name="SetThreadPriority") set_thread_priority :: proc(thread: Handle, priority: i32) -> Bool ---;
|
||||
@(link_name="GetExitCodeThread") get_exit_code_thread :: proc(thread: Handle, exit_code: ^u32) -> Bool ---;
|
||||
@(link_name="GetExitCodeThread") get_exit_code_thread :: proc(thread: Handle, exit_code: ^u32) -> Bool ---;
|
||||
@(link_name="TerminateThread") terminate_thread :: proc(thread: Handle, exit_code: u32) -> Bool ---;
|
||||
|
||||
@(link_name="InitializeCriticalSection") initialize_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||
@(link_name="InitializeCriticalSectionAndSpinCount") initialize_critical_section_and_spin_count :: proc(critical_section: ^Critical_Section, spin_count: u32) ---;
|
||||
@@ -659,31 +700,34 @@ foreign kernel32 {
|
||||
@(link_name="EnterCriticalSection") enter_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||
@(link_name="LeaveCriticalSection") leave_critical_section :: proc(critical_section: ^Critical_Section) ---;
|
||||
|
||||
@(link_name="CreateEventA") create_event_a :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: ^byte) -> Handle ---;
|
||||
@(link_name="CreateEventA") create_event_a :: proc(event_attributes: ^Security_Attributes, manual_reset, initial_state: Bool, name: cstring) -> Handle ---;
|
||||
@(link_name="PulseEvent") pulse_event :: proc(event: Handle) -> Bool ---;
|
||||
@(link_name="SetEvent") set_event :: proc(event: Handle) -> Bool ---;
|
||||
@(link_name="ResetEvent") reset_event :: proc(event: Handle) -> Bool ---;
|
||||
|
||||
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: ^byte) -> Hmodule ---;
|
||||
@(link_name="LoadLibraryW") load_library_w :: proc(c_str: ^u16) -> Hmodule ---;
|
||||
@(link_name="LoadLibraryA") load_library_a :: proc(c_str: cstring) -> Hmodule ---;
|
||||
@(link_name="LoadLibraryW") load_library_w :: proc(c_str: Wstring) -> Hmodule ---;
|
||||
@(link_name="FreeLibrary") free_library :: proc(h: Hmodule) ---;
|
||||
@(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: ^byte) -> rawptr ---;
|
||||
@(link_name="GetProcAddress") get_proc_address :: proc(h: Hmodule, c_str: cstring) -> rawptr ---;
|
||||
|
||||
}
|
||||
|
||||
@(default_calling_convention = "std")
|
||||
foreign user32 {
|
||||
@(link_name="GetDesktopWindow") get_desktop_window :: proc() -> Hwnd ---;
|
||||
@(link_name="ShowCursor") show_cursor :: proc(show : Bool) ---;
|
||||
@(link_name="ShowCursor") show_cursor :: proc(show: Bool) ---;
|
||||
@(link_name="GetCursorPos") get_cursor_pos :: proc(p: ^Point) -> Bool ---;
|
||||
@(link_name="SetCursorPos") set_cursor_pos :: proc(x, y: i32) -> Bool ---;
|
||||
@(link_name="ScreenToClient") screen_to_client :: proc(h: Hwnd, p: ^Point) -> Bool ---;
|
||||
@(link_name="ClientToScreen") client_to_screen :: proc(h: Hwnd, p: ^Point) -> Bool ---;
|
||||
@(link_name="PostQuitMessage") post_quit_message :: proc(exit_code: i32) ---;
|
||||
@(link_name="SetWindowTextA") set_window_text_a :: proc(hwnd: Hwnd, c_string: ^byte) -> Bool ---;
|
||||
@(link_name="SetWindowTextA") set_window_text_a :: proc(hwnd: Hwnd, c_string: cstring) -> Bool ---;
|
||||
@(link_name="RegisterClassExA") register_class_ex_a :: proc(wc: ^Wnd_Class_Ex_A) -> i16 ---;
|
||||
@(link_name="RegisterClassExW") register_class_ex_w :: proc(wc: ^Wnd_Class_Ex_W) -> i16 ---;
|
||||
|
||||
@(link_name="CreateWindowExA")
|
||||
create_window_ex_a :: proc(ex_style: u32,
|
||||
class_name, title: ^byte,
|
||||
class_name, title: cstring,
|
||||
style: u32,
|
||||
x, y, w, h: i32,
|
||||
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
||||
@@ -691,7 +735,7 @@ foreign user32 {
|
||||
|
||||
@(link_name="CreateWindowExW")
|
||||
create_window_ex_w :: proc(ex_style: u32,
|
||||
class_name, title: ^u16,
|
||||
class_name, title: Wstring,
|
||||
style: u32,
|
||||
x, y, w, h: i32,
|
||||
parent: Hwnd, menu: Hmenu, instance: Hinstance,
|
||||
@@ -702,14 +746,14 @@ foreign user32 {
|
||||
@(link_name="DispatchMessageA") dispatch_message_a :: proc(msg: ^Msg) -> Lresult ---;
|
||||
@(link_name="DispatchMessageW") dispatch_message_w :: proc(msg: ^Msg) -> Lresult ---;
|
||||
@(link_name="UpdateWindow") update_window :: proc(hwnd: Hwnd) -> Bool ---;
|
||||
@(link_name="GetMessageA") get_message_a :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max : u32) -> Bool ---;
|
||||
@(link_name="GetMessageW") get_message_w :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max : u32) -> Bool ---;
|
||||
@(link_name="GetMessageA") get_message_a :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max: u32) -> Bool ---;
|
||||
@(link_name="GetMessageW") get_message_w :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max: u32) -> Bool ---;
|
||||
|
||||
@(link_name="PeekMessageA") peek_message_a :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool ---;
|
||||
@(link_name="PeekMessageW") peek_message_w :: proc(msg: ^Msg, hwnd: Hwnd, msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool ---;
|
||||
|
||||
|
||||
@(link_name="PostMessageA") post_message :: proc(hwnd: Hwnd, msg, wparam, lparam : u32) -> Bool ---;
|
||||
@(link_name="PostMessageA") post_message :: proc(hwnd: Hwnd, msg, wparam, lparam: u32) -> Bool ---;
|
||||
|
||||
@(link_name="DefWindowProcA") def_window_proc_a :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult ---;
|
||||
|
||||
@@ -720,7 +764,7 @@ foreign user32 {
|
||||
@(link_name="DescribePixelFormat") describe_pixel_format :: proc(dc: Hdc, pixel_format: i32, bytes: u32, pfd: ^Pixel_Format_Descriptor) -> i32 ---;
|
||||
|
||||
@(link_name="GetMonitor_InfoA") get_monitor_info_a :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> Bool ---;
|
||||
@(link_name="MonitorFromWindow") monitor_from_window :: proc(wnd: Hwnd, flags : u32) -> Hmonitor ---;
|
||||
@(link_name="MonitorFromWindow") monitor_from_window :: proc(wnd: Hwnd, flags: u32) -> Hmonitor ---;
|
||||
|
||||
@(link_name="SetWindowPos") set_window_pos :: proc(wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) ---;
|
||||
|
||||
@@ -733,15 +777,15 @@ foreign user32 {
|
||||
@(link_name="GetWindowLongPtrW") get_window_long_ptr_w :: proc(wnd: Hwnd, index: i32) -> Long_Ptr ---;
|
||||
@(link_name="SetWindowLongPtrW") set_window_long_ptr_w :: proc(wnd: Hwnd, index: i32, new: Long_Ptr) -> Long_Ptr ---;
|
||||
|
||||
@(link_name="GetWindowText") get_window_text :: proc(wnd: Hwnd, str: ^byte, maxCount: i32) -> i32 ---;
|
||||
@(link_name="GetWindowText") get_window_text :: proc(wnd: Hwnd, str: cstring, maxCount: i32) -> i32 ---;
|
||||
|
||||
@(link_name="GetClientRect") get_client_rect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool ---;
|
||||
|
||||
@(link_name="GetDC") get_dc :: proc(h: Hwnd) -> Hdc ---;
|
||||
@(link_name="ReleaseDC") release_dc :: proc(wnd: Hwnd, hdc: Hdc) -> i32 ---;
|
||||
|
||||
@(link_name="MapVirtualKeyA") map_virtual_key_a :: proc(scancode : u32, map_type : u32) -> u32 ---;
|
||||
@(link_name="MapVirtualKeyW") map_virtual_key_w :: proc(scancode : u32, map_type : u32) -> u32 ---;
|
||||
@(link_name="MapVirtualKeyA") map_virtual_key_a :: proc(scancode: u32, map_type: u32) -> u32 ---;
|
||||
@(link_name="MapVirtualKeyW") map_virtual_key_w :: proc(scancode: u32, map_type: u32) -> u32 ---;
|
||||
|
||||
@(link_name="GetKeyState") get_key_state :: proc(v_key: i32) -> i16 ---;
|
||||
@(link_name="GetAsyncKeyState") get_async_key_state :: proc(v_key: i32) -> i16 ---;
|
||||
@@ -750,6 +794,13 @@ foreign user32 {
|
||||
@(link_name="SetFocus") set_focus :: proc(h: Hwnd) -> Hwnd ---;
|
||||
|
||||
|
||||
@(link_name="LoadImageA") load_image_a :: proc(instance: Hinstance, name: cstring, type_: u32, x_desired, y_desired : i32, load : u32) -> Handle ---;
|
||||
@(link_name="LoadIconA") load_icon_a :: proc(instance: Hinstance, icon_name: cstring) -> Hicon ---;
|
||||
@(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---;
|
||||
|
||||
@(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---;
|
||||
@(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---;
|
||||
@(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---;
|
||||
|
||||
@(link_name="RegisterRawInputDevices") register_raw_input_devices :: proc(raw_input_device: ^Raw_Input_Device, num_devices, size: u32) -> Bool ---;
|
||||
|
||||
@@ -779,7 +830,7 @@ foreign gdi32 {
|
||||
|
||||
@(default_calling_convention = "std")
|
||||
foreign shell32 {
|
||||
@(link_name="CommandLineToArgvW") command_line_to_argv_w :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 ---;
|
||||
@(link_name="CommandLineToArgvW") command_line_to_argv_w :: proc(cmd_list: Wstring, num_args: ^i32) -> ^Wstring ---;
|
||||
}
|
||||
|
||||
@(default_calling_convention = "std")
|
||||
@@ -1,8 +1,7 @@
|
||||
_ :: compile_assert(ODIN_OS == "windows");
|
||||
package thread
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
import win32 "core:sys/windows.odin"
|
||||
}
|
||||
import "core:runtime"
|
||||
import "core:sys/win32"
|
||||
|
||||
Thread_Proc :: #type proc(^Thread) -> int;
|
||||
|
||||
@@ -17,7 +16,7 @@ Thread :: struct {
|
||||
data: rawptr,
|
||||
user_index: int,
|
||||
|
||||
init_context: Context,
|
||||
init_context: runtime.Context,
|
||||
use_init_context: bool,
|
||||
}
|
||||
|
||||
@@ -30,13 +29,9 @@ create :: proc(procedure: Thread_Proc) -> ^Thread {
|
||||
if t.use_init_context {
|
||||
c = t.init_context;
|
||||
}
|
||||
context = c;
|
||||
|
||||
exit := 0;
|
||||
context <- c {
|
||||
exit = t.procedure(t);
|
||||
}
|
||||
|
||||
return i32(exit);
|
||||
return i32(t.procedure(t));
|
||||
}
|
||||
|
||||
|
||||
@@ -74,3 +69,7 @@ destroy :: proc(thread: ^Thread) {
|
||||
join(thread);
|
||||
free(thread);
|
||||
}
|
||||
|
||||
terminate :: proc(using thread : ^Thread, exit_code : u32) {
|
||||
win32.terminate_thread(win32_thread, exit_code);
|
||||
}
|
||||
-252
@@ -1,252 +0,0 @@
|
||||
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
if a == b do return true;
|
||||
|
||||
if (a == nil && b != nil) ||
|
||||
(a != nil && b == nil) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch {
|
||||
case a.size != b.size, a.align != b.align:
|
||||
return false;
|
||||
}
|
||||
|
||||
switch x in a.variant {
|
||||
case Type_Info_Named:
|
||||
y, ok := b.variant.(Type_Info_Named);
|
||||
if !ok do return false;
|
||||
return x.base == y.base;
|
||||
|
||||
case Type_Info_Integer:
|
||||
y, ok := b.variant.(Type_Info_Integer);
|
||||
if !ok do return false;
|
||||
return x.signed == y.signed;
|
||||
|
||||
case Type_Info_Rune:
|
||||
_, ok := b.variant.(Type_Info_Rune);
|
||||
return ok;
|
||||
|
||||
case Type_Info_Float:
|
||||
_, ok := b.variant.(Type_Info_Float);
|
||||
return ok;
|
||||
|
||||
case Type_Info_Complex:
|
||||
_, ok := b.variant.(Type_Info_Complex);
|
||||
return ok;
|
||||
|
||||
case Type_Info_String:
|
||||
_, ok := b.variant.(Type_Info_String);
|
||||
return ok;
|
||||
|
||||
case Type_Info_Boolean:
|
||||
_, ok := b.variant.(Type_Info_Boolean);
|
||||
return ok;
|
||||
|
||||
case Type_Info_Any:
|
||||
_, ok := b.variant.(Type_Info_Any);
|
||||
return ok;
|
||||
|
||||
case Type_Info_Pointer:
|
||||
y, ok := b.variant.(Type_Info_Pointer);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case Type_Info_Procedure:
|
||||
y, ok := b.variant.(Type_Info_Procedure);
|
||||
if !ok do return false;
|
||||
switch {
|
||||
case x.variadic != y.variadic,
|
||||
x.convention != y.convention:
|
||||
return false;
|
||||
}
|
||||
|
||||
return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
|
||||
|
||||
case Type_Info_Array:
|
||||
y, ok := b.variant.(Type_Info_Array);
|
||||
if !ok do return false;
|
||||
if x.count != y.count do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case Type_Info_Dynamic_Array:
|
||||
y, ok := b.variant.(Type_Info_Dynamic_Array);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case Type_Info_Slice:
|
||||
y, ok := b.variant.(Type_Info_Slice);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case Type_Info_Tuple:
|
||||
y, ok := b.variant.(Type_Info_Tuple);
|
||||
if !ok do return false;
|
||||
if len(x.types) != len(y.types) do return false;
|
||||
for _, i in x.types {
|
||||
xt, yt := x.types[i], y.types[i];
|
||||
if !are_types_identical(xt, yt) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_Info_Struct:
|
||||
y, ok := b.variant.(Type_Info_Struct);
|
||||
if !ok do return false;
|
||||
switch {
|
||||
case len(x.types) != len(y.types),
|
||||
x.is_packed != y.is_packed,
|
||||
x.is_raw_union != y.is_raw_union,
|
||||
x.custom_align != y.custom_align:
|
||||
return false;
|
||||
}
|
||||
for _, i in x.types {
|
||||
xn, yn := x.names[i], y.names[i];
|
||||
xt, yt := x.types[i], y.types[i];
|
||||
|
||||
if xn != yn do return false;
|
||||
if !are_types_identical(xt, yt) do return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_Info_Union:
|
||||
y, ok := b.variant.(Type_Info_Union);
|
||||
if !ok do return false;
|
||||
if len(x.variants) != len(y.variants) do return false;
|
||||
|
||||
for _, i in x.variants {
|
||||
xv, yv := x.variants[i], y.variants[i];
|
||||
if !are_types_identical(xv, yv) do return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case Type_Info_Enum:
|
||||
// NOTE(bill): Should be handled above
|
||||
return false;
|
||||
|
||||
case Type_Info_Map:
|
||||
y, ok := b.variant.(Type_Info_Map);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
|
||||
|
||||
case Type_Info_Bit_Field:
|
||||
y, ok := b.variant.(Type_Info_Bit_Field);
|
||||
if !ok do return false;
|
||||
if len(x.names) != len(y.names) do return false;
|
||||
|
||||
for _, i in x.names {
|
||||
xb, yb := x.bits[i], y.bits[i];
|
||||
xo, yo := x.offsets[i], y.offsets[i];
|
||||
xn, yn := x.names[i], y.names[i];
|
||||
|
||||
if xb != yb do return false;
|
||||
if xo != yo do return false;
|
||||
if xn != yn do return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
switch i in type_info_base(info).variant {
|
||||
case Type_Info_Integer: return i.signed;
|
||||
case Type_Info_Float: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_integer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Integer);
|
||||
return ok;
|
||||
}
|
||||
is_rune :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Rune);
|
||||
return ok;
|
||||
}
|
||||
is_float :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Float);
|
||||
return ok;
|
||||
}
|
||||
is_complex :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Complex);
|
||||
return ok;
|
||||
}
|
||||
is_any :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Any);
|
||||
return ok;
|
||||
}
|
||||
is_string :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_String);
|
||||
return ok;
|
||||
}
|
||||
is_boolean :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Boolean);
|
||||
return ok;
|
||||
}
|
||||
is_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Pointer);
|
||||
return ok;
|
||||
}
|
||||
is_procedure :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Procedure);
|
||||
return ok;
|
||||
}
|
||||
is_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Array);
|
||||
return ok;
|
||||
}
|
||||
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array);
|
||||
return ok;
|
||||
}
|
||||
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Map);
|
||||
return ok;
|
||||
}
|
||||
is_slice :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Slice);
|
||||
return ok;
|
||||
}
|
||||
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Tuple);
|
||||
return ok;
|
||||
}
|
||||
is_struct :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
s, ok := type_info_base(info).variant.(Type_Info_Struct);
|
||||
return ok && !s.is_raw_union;
|
||||
}
|
||||
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
s, ok := type_info_base(info).variant.(Type_Info_Struct);
|
||||
return ok && s.is_raw_union;
|
||||
}
|
||||
is_union :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Union);
|
||||
return ok;
|
||||
}
|
||||
is_enum :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Enum);
|
||||
return ok;
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
package types
|
||||
|
||||
import rt "core:runtime"
|
||||
|
||||
are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
|
||||
if a == b do return true;
|
||||
|
||||
if (a == nil && b != nil) ||
|
||||
(a != nil && b == nil) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
switch {
|
||||
case a.size != b.size, a.align != b.align:
|
||||
return false;
|
||||
}
|
||||
|
||||
switch x in a.variant {
|
||||
case rt.Type_Info_Named:
|
||||
y, ok := b.variant.(rt.Type_Info_Named);
|
||||
if !ok do return false;
|
||||
return x.base == y.base;
|
||||
|
||||
case rt.Type_Info_Integer:
|
||||
y, ok := b.variant.(rt.Type_Info_Integer);
|
||||
if !ok do return false;
|
||||
return x.signed == y.signed;
|
||||
|
||||
case rt.Type_Info_Rune:
|
||||
_, ok := b.variant.(rt.Type_Info_Rune);
|
||||
return ok;
|
||||
|
||||
case rt.Type_Info_Float:
|
||||
_, ok := b.variant.(rt.Type_Info_Float);
|
||||
return ok;
|
||||
|
||||
case rt.Type_Info_Complex:
|
||||
_, ok := b.variant.(rt.Type_Info_Complex);
|
||||
return ok;
|
||||
|
||||
case rt.Type_Info_String:
|
||||
_, ok := b.variant.(rt.Type_Info_String);
|
||||
return ok;
|
||||
|
||||
case rt.Type_Info_Boolean:
|
||||
_, ok := b.variant.(rt.Type_Info_Boolean);
|
||||
return ok;
|
||||
|
||||
case rt.Type_Info_Any:
|
||||
_, ok := b.variant.(rt.Type_Info_Any);
|
||||
return ok;
|
||||
|
||||
case rt.Type_Info_Pointer:
|
||||
y, ok := b.variant.(rt.Type_Info_Pointer);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case rt.Type_Info_Procedure:
|
||||
y, ok := b.variant.(rt.Type_Info_Procedure);
|
||||
if !ok do return false;
|
||||
switch {
|
||||
case x.variadic != y.variadic,
|
||||
x.convention != y.convention:
|
||||
return false;
|
||||
}
|
||||
|
||||
return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
|
||||
|
||||
case rt.Type_Info_Array:
|
||||
y, ok := b.variant.(rt.Type_Info_Array);
|
||||
if !ok do return false;
|
||||
if x.count != y.count do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case rt.Type_Info_Dynamic_Array:
|
||||
y, ok := b.variant.(rt.Type_Info_Dynamic_Array);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case rt.Type_Info_Slice:
|
||||
y, ok := b.variant.(rt.Type_Info_Slice);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.elem, y.elem);
|
||||
|
||||
case rt.Type_Info_Tuple:
|
||||
y, ok := b.variant.(rt.Type_Info_Tuple);
|
||||
if !ok do return false;
|
||||
if len(x.types) != len(y.types) do return false;
|
||||
for _, i in x.types {
|
||||
xt, yt := x.types[i], y.types[i];
|
||||
if !are_types_identical(xt, yt) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
case rt.Type_Info_Struct:
|
||||
y, ok := b.variant.(rt.Type_Info_Struct);
|
||||
if !ok do return false;
|
||||
switch {
|
||||
case len(x.types) != len(y.types),
|
||||
x.is_packed != y.is_packed,
|
||||
x.is_raw_union != y.is_raw_union,
|
||||
x.custom_align != y.custom_align:
|
||||
return false;
|
||||
}
|
||||
for _, i in x.types {
|
||||
xn, yn := x.names[i], y.names[i];
|
||||
xt, yt := x.types[i], y.types[i];
|
||||
|
||||
if xn != yn do return false;
|
||||
if !are_types_identical(xt, yt) do return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case rt.Type_Info_Union:
|
||||
y, ok := b.variant.(rt.Type_Info_Union);
|
||||
if !ok do return false;
|
||||
if len(x.variants) != len(y.variants) do return false;
|
||||
|
||||
for _, i in x.variants {
|
||||
xv, yv := x.variants[i], y.variants[i];
|
||||
if !are_types_identical(xv, yv) do return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case rt.Type_Info_Enum:
|
||||
// NOTE(bill): Should be handled above
|
||||
return false;
|
||||
|
||||
case rt.Type_Info_Map:
|
||||
y, ok := b.variant.(rt.Type_Info_Map);
|
||||
if !ok do return false;
|
||||
return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
|
||||
|
||||
case rt.Type_Info_Bit_Field:
|
||||
y, ok := b.variant.(rt.Type_Info_Bit_Field);
|
||||
if !ok do return false;
|
||||
if len(x.names) != len(y.names) do return false;
|
||||
|
||||
for _, i in x.names {
|
||||
xb, yb := x.bits[i], y.bits[i];
|
||||
xo, yo := x.offsets[i], y.offsets[i];
|
||||
xn, yn := x.names[i], y.names[i];
|
||||
|
||||
if xb != yb do return false;
|
||||
if xo != yo do return false;
|
||||
if xn != yn do return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case rt.Type_Info_Bit_Set:
|
||||
y, ok := b.variant.(rt.Type_Info_Bit_Set);
|
||||
if !ok do return false;
|
||||
return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
is_signed :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
switch i in rt.type_info_base(info).variant {
|
||||
case rt.Type_Info_Integer: return i.signed;
|
||||
case rt.Type_Info_Float: return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
is_integer :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Integer);
|
||||
return ok;
|
||||
}
|
||||
is_rune :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Rune);
|
||||
return ok;
|
||||
}
|
||||
is_float :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Float);
|
||||
return ok;
|
||||
}
|
||||
is_complex :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Complex);
|
||||
return ok;
|
||||
}
|
||||
is_any :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Any);
|
||||
return ok;
|
||||
}
|
||||
is_string :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_String);
|
||||
return ok;
|
||||
}
|
||||
is_boolean :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Boolean);
|
||||
return ok;
|
||||
}
|
||||
is_pointer :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Pointer);
|
||||
return ok;
|
||||
}
|
||||
is_procedure :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Procedure);
|
||||
return ok;
|
||||
}
|
||||
is_array :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Array);
|
||||
return ok;
|
||||
}
|
||||
is_dynamic_array :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Dynamic_Array);
|
||||
return ok;
|
||||
}
|
||||
is_dynamic_map :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Map);
|
||||
return ok;
|
||||
}
|
||||
is_slice :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Slice);
|
||||
return ok;
|
||||
}
|
||||
is_tuple :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Tuple);
|
||||
return ok;
|
||||
}
|
||||
is_struct :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct);
|
||||
return ok && !s.is_raw_union;
|
||||
}
|
||||
is_raw_union :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct);
|
||||
return ok && s.is_raw_union;
|
||||
}
|
||||
is_union :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Union);
|
||||
return ok;
|
||||
}
|
||||
is_enum :: proc(info: ^rt.Type_Info) -> bool {
|
||||
if info == nil do return false;
|
||||
_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Enum);
|
||||
return ok;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import "utf8.odin"
|
||||
package utf16
|
||||
|
||||
REPLACEMENT_CHAR :: '\uFFFD';
|
||||
MAX_RUNE :: '\U0010FFFF';
|
||||
REPLACEMENT_CHAR :: '\ufffd';
|
||||
MAX_RUNE :: '\U0010ffff';
|
||||
|
||||
_surr1 :: 0xd800;
|
||||
_surr2 :: 0xdc00;
|
||||
@@ -33,7 +33,7 @@ encode :: proc(d: []u16, s: []rune) -> int {
|
||||
n, m := 0, len(d);
|
||||
loop: for r in s {
|
||||
switch r {
|
||||
case 0.._surr1, _surr3 .. _surr_self:
|
||||
case 0.._surr1-1, _surr3 .. _surr_self-1:
|
||||
if m+1 < n do break loop;
|
||||
d[n] = u16(r);
|
||||
n += 1;
|
||||
@@ -59,7 +59,7 @@ encode_string :: proc(d: []u16, s: string) -> int {
|
||||
n, m := 0, len(d);
|
||||
loop: for r in s {
|
||||
switch r {
|
||||
case 0.._surr1, _surr3 .. _surr_self:
|
||||
case 0.._surr1-1, _surr3 .. _surr_self-1:
|
||||
if m+1 < n do break loop;
|
||||
d[n] = u16(r);
|
||||
n += 1;
|
||||
@@ -1,3 +1,5 @@
|
||||
package utf8
|
||||
|
||||
RUNE_ERROR :: '\ufffd';
|
||||
RUNE_SELF :: 0x80;
|
||||
RUNE_BOM :: 0xfeff;
|
||||
@@ -24,7 +26,7 @@ RUNE1_MAX :: 1<<7 - 1;
|
||||
RUNE2_MAX :: 1<<11 - 1;
|
||||
RUNE3_MAX :: 1<<16 - 1;
|
||||
|
||||
// The default lowest and highest continuation byte.
|
||||
// The default lowest and highest continuation byte.
|
||||
LOCB :: 0b1000_0000;
|
||||
HICB :: 0b1011_1111;
|
||||
|
||||
@@ -156,7 +158,7 @@ decode_last_rune :: proc(s: []u8) -> (rune, int) {
|
||||
}
|
||||
|
||||
start = max(start, 0);
|
||||
r, size = decode_rune(s[start..end]);
|
||||
r, size = decode_rune(s[start:end]);
|
||||
if start+size != end {
|
||||
return RUNE_ERROR, 1;
|
||||
}
|
||||
@@ -1,29 +1,32 @@
|
||||
import "core:fmt.odin"
|
||||
import "core:strconv.odin"
|
||||
import "core:mem.odin"
|
||||
import "core:bits.odin"
|
||||
import "core:hash.odin"
|
||||
import "core:math.odin"
|
||||
import "core:math/rand.odin"
|
||||
import "core:os.odin"
|
||||
import "core:raw.odin"
|
||||
import "core:sort.odin"
|
||||
import "core:strings.odin"
|
||||
import "core:types.odin"
|
||||
import "core:utf16.odin"
|
||||
import "core:utf8.odin"
|
||||
package main
|
||||
|
||||
// File scope `when` statements
|
||||
when ODIN_OS == "windows" {
|
||||
import "core:atomics.odin"
|
||||
import "core:thread.odin"
|
||||
import win32 "core:sys/windows.odin"
|
||||
import "core:fmt"
|
||||
import "core:strconv"
|
||||
import "core:mem"
|
||||
import "core:bits"
|
||||
import "core:hash"
|
||||
import "core:math"
|
||||
import "core:math/rand"
|
||||
import "core:os"
|
||||
import "core:sort"
|
||||
import "core:strings"
|
||||
import "core:types"
|
||||
import "core:unicode/utf16"
|
||||
import "core:unicode/utf8"
|
||||
import "core:c"
|
||||
import "core:runtime"
|
||||
|
||||
when os.OS == "windows" {
|
||||
import "core:atomics"
|
||||
import "core:sync"
|
||||
import "core:thread"
|
||||
import "core:sys/win32"
|
||||
}
|
||||
|
||||
@(link_name="general_stuff")
|
||||
general_stuff :: proc() {
|
||||
fmt.println("# general_stuff");
|
||||
{ // `do` for inline statments rather than block
|
||||
{ // `do` for inline statements rather than block
|
||||
foo :: proc() do fmt.println("Foo!");
|
||||
if false do foo();
|
||||
for false do foo();
|
||||
@@ -71,11 +74,9 @@ general_stuff :: proc() {
|
||||
}
|
||||
|
||||
{
|
||||
// .. half-closed range
|
||||
// ... open range
|
||||
// .. open range
|
||||
|
||||
for in 0..2 {} // 0, 1
|
||||
for in 0...2 {} // 0, 1, 2
|
||||
for in 0..2 {} // 0, 1, 2
|
||||
}
|
||||
|
||||
{ // Multiple sized booleans
|
||||
@@ -86,6 +87,7 @@ general_stuff :: proc() {
|
||||
x3: b32 = true;
|
||||
x4: b64 = false;
|
||||
|
||||
fmt.printf("x0: %T = %v;\n", x0, x0);
|
||||
fmt.printf("x1: %T = %v;\n", x1, x1);
|
||||
fmt.printf("x2: %T = %v;\n", x2, x2);
|
||||
fmt.printf("x3: %T = %v;\n", x3, x3);
|
||||
@@ -101,77 +103,16 @@ general_stuff :: proc() {
|
||||
// If the type expression is `struct`, `union`, `enum`, `proc`, or `bit_field`, the types will always been distinct.
|
||||
|
||||
Int32 :: i32;
|
||||
compile_assert(Int32 == i32);
|
||||
#assert(Int32 == i32);
|
||||
|
||||
My_Int32 :: distinct i32;
|
||||
compile_assert(My_Int32 != i32);
|
||||
#assert(My_Int32 != i32);
|
||||
|
||||
My_Struct :: struct{x: int};
|
||||
compile_assert(My_Struct != struct{x: int});
|
||||
#assert(My_Struct != struct{x: int});
|
||||
}
|
||||
}
|
||||
|
||||
default_struct_values :: proc() {
|
||||
fmt.println("# default_struct_values");
|
||||
{
|
||||
Vector3 :: struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
}
|
||||
v: Vector3;
|
||||
fmt.println(v);
|
||||
}
|
||||
{
|
||||
// Default values must be constants
|
||||
Vector3 :: struct {
|
||||
x: f32 = 1,
|
||||
y: f32 = 4,
|
||||
z: f32 = 9,
|
||||
}
|
||||
v: Vector3;
|
||||
fmt.println(v);
|
||||
|
||||
v = Vector3{};
|
||||
fmt.println(v);
|
||||
|
||||
// Uses the same semantics as a default values in a procedure
|
||||
v = Vector3{137};
|
||||
fmt.println(v);
|
||||
|
||||
v = Vector3{z = 137};
|
||||
fmt.println(v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 :: struct {
|
||||
x := 1.0,
|
||||
y := 4.0,
|
||||
z := 9.0,
|
||||
}
|
||||
stack_default: Vector3;
|
||||
stack_literal := Vector3{};
|
||||
heap_one := new(Vector3); defer free(heap_one);
|
||||
heap_two := new_clone(Vector3{}); defer free(heap_two);
|
||||
|
||||
fmt.println("stack_default - ", stack_default);
|
||||
fmt.println("stack_literal - ", stack_literal);
|
||||
fmt.println("heap_one - ", heap_one^);
|
||||
fmt.println("heap_two - ", heap_two^);
|
||||
|
||||
|
||||
N :: 4;
|
||||
stack_array: [N]Vector3;
|
||||
heap_array := new([N]Vector3); defer free(heap_array);
|
||||
heap_slice := make([]Vector3, N); defer free(heap_slice);
|
||||
fmt.println("stack_array[1] - ", stack_array[1]);
|
||||
fmt.println("heap_array[1] - ", heap_array[1]);
|
||||
fmt.println("heap_slice[1] - ", heap_slice[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
union_type :: proc() {
|
||||
fmt.println("\n# union_type");
|
||||
@@ -215,7 +156,7 @@ union_type :: proc() {
|
||||
}
|
||||
|
||||
Vector3 :: struct {x, y, z: f32};
|
||||
Quaternion :: struct {x, y, z: f32, w: f32 = 1};
|
||||
Quaternion :: struct {x, y, z, w: f32};
|
||||
|
||||
// More realistic examples
|
||||
{
|
||||
@@ -324,17 +265,17 @@ union_type :: proc() {
|
||||
|
||||
/*
|
||||
Entity :: struct {
|
||||
...
|
||||
..
|
||||
derived: union{^Frog, ^Monster},
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: Entity,
|
||||
...
|
||||
..
|
||||
}
|
||||
Monster :: struct {
|
||||
using entity: Entity,
|
||||
...
|
||||
..
|
||||
|
||||
}
|
||||
new_entity :: proc(T: type) -> ^Entity {
|
||||
@@ -384,7 +325,11 @@ parametric_polymorphism :: proc() {
|
||||
}
|
||||
|
||||
copy_slice :: proc(dst, src: []$T) -> int {
|
||||
return mem.copy(&dst[0], &src[0], n*size_of(T));
|
||||
n := min(len(dst), len(src));
|
||||
if n > 0 {
|
||||
mem.copy(&dst[0], &src[0], n*size_of(T));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
double_params :: proc(a: $A, b: $B) -> A {
|
||||
@@ -405,7 +350,7 @@ parametric_polymorphism :: proc() {
|
||||
TABLE_SIZE_MIN :: 32;
|
||||
Table :: struct(Key, Value: type) {
|
||||
count: int,
|
||||
allocator: Allocator,
|
||||
allocator: mem.Allocator,
|
||||
slots: []Table_Slot(Key, Value),
|
||||
}
|
||||
|
||||
@@ -419,27 +364,24 @@ parametric_polymorphism :: proc() {
|
||||
allocate :: proc(table: ^$T/Table, capacity: int) {
|
||||
c := context;
|
||||
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
||||
context = c;
|
||||
|
||||
context <- c {
|
||||
table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
|
||||
}
|
||||
table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
|
||||
}
|
||||
|
||||
expand :: proc(table: ^$T/Table) {
|
||||
c := context;
|
||||
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
||||
context = c;
|
||||
|
||||
context <- c {
|
||||
old_slots := table.slots;
|
||||
old_slots := table.slots;
|
||||
defer delete(old_slots);
|
||||
|
||||
cap := max(2*len(table.slots), TABLE_SIZE_MIN);
|
||||
allocate(table, cap);
|
||||
cap := max(2*len(table.slots), TABLE_SIZE_MIN);
|
||||
allocate(table, cap);
|
||||
|
||||
for s in old_slots do if s.occupied {
|
||||
put(table, s.key, s.value);
|
||||
}
|
||||
|
||||
free(old_slots);
|
||||
for s in old_slots do if s.occupied {
|
||||
put(table, s.key, s.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +447,7 @@ parametric_polymorphism :: proc() {
|
||||
|
||||
get_hash :: proc(s: string) -> u32 { // fnv32a
|
||||
h: u32 = 0x811c9dc5;
|
||||
for i in 0..len(s) {
|
||||
for i in 0..len(s)-1 {
|
||||
h = (h ~ u32(s[i])) * 0x01000193;
|
||||
}
|
||||
return h;
|
||||
@@ -534,7 +476,7 @@ parametric_polymorphism :: proc() {
|
||||
|
||||
|
||||
|
||||
prefix_table := [...]string{
|
||||
prefix_table := [?]string{
|
||||
"White",
|
||||
"Red",
|
||||
"Green",
|
||||
@@ -544,22 +486,22 @@ prefix_table := [...]string{
|
||||
};
|
||||
|
||||
threading_example :: proc() {
|
||||
when ODIN_OS == "windows" {
|
||||
when os.OS == "windows" {
|
||||
fmt.println("# threading_example");
|
||||
|
||||
unordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
|
||||
__bounds_check_error_loc(loc, index, len(array));
|
||||
runtime.bounds_check_error_loc(loc, index, len(array));
|
||||
array[index] = array[len(array)-1];
|
||||
pop(array);
|
||||
}
|
||||
ordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
|
||||
__bounds_check_error_loc(loc, index, len(array));
|
||||
copy(array[index..], array[index+1..]);
|
||||
runtime.bounds_check_error_loc(loc, index, len(array));
|
||||
copy(array[index:], array[index+1:]);
|
||||
pop(array);
|
||||
}
|
||||
|
||||
worker_proc :: proc(t: ^thread.Thread) -> int {
|
||||
for iteration in 1...5 {
|
||||
for iteration in 1..5 {
|
||||
fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
|
||||
fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
|
||||
// win32.sleep(1);
|
||||
@@ -568,7 +510,7 @@ threading_example :: proc() {
|
||||
}
|
||||
|
||||
threads := make([dynamic]^thread.Thread, 0, len(prefix_table));
|
||||
defer free(threads);
|
||||
defer delete(threads);
|
||||
|
||||
for in prefix_table {
|
||||
if t := thread.create(worker_proc); t != nil {
|
||||
@@ -640,28 +582,6 @@ array_programming :: proc() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using println in import "core:fmt.odin"
|
||||
|
||||
using_in :: proc() {
|
||||
fmt.println("# using in");
|
||||
using print in fmt;
|
||||
|
||||
println("Hellope1");
|
||||
print("Hellope2\n");
|
||||
|
||||
Foo :: struct {
|
||||
x, y: int,
|
||||
b: bool,
|
||||
}
|
||||
f: Foo;
|
||||
f.x, f.y = 123, 321;
|
||||
println(f);
|
||||
using x, y in f;
|
||||
f.x, f.y = 456, 654;
|
||||
println(f);
|
||||
}
|
||||
|
||||
named_proc_return_parameters :: proc() {
|
||||
fmt.println("# named proc return parameters");
|
||||
|
||||
@@ -684,15 +604,21 @@ named_proc_return_parameters :: proc() {
|
||||
}
|
||||
|
||||
|
||||
enum_export :: proc() {
|
||||
fmt.println("# enum #export");
|
||||
using_enum :: proc() {
|
||||
fmt.println("# using enum");
|
||||
|
||||
Foo :: enum #export {A, B, C};
|
||||
using Foo :: enum {A, B, C};
|
||||
|
||||
f0 := A;
|
||||
f1 := B;
|
||||
f2 := C;
|
||||
fmt.println(f0, f1, f2);
|
||||
fmt.println(len(Foo));
|
||||
|
||||
// Non-comparsion operations are not allowed with enum
|
||||
// You must convert to an integer if you want to do this
|
||||
// x := f0 + f1;
|
||||
y := int(f0) + int(f1);
|
||||
}
|
||||
|
||||
explicit_procedure_overloading :: proc() {
|
||||
@@ -729,17 +655,128 @@ explicit_procedure_overloading :: proc() {
|
||||
// add(1, 2.0);
|
||||
}
|
||||
|
||||
complete_switch :: proc() {
|
||||
fmt.println("# complete_switch");
|
||||
{ // enum
|
||||
using Foo :: enum {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
}
|
||||
|
||||
b := Foo.B;
|
||||
f := Foo.A;
|
||||
#complete switch f {
|
||||
case A: fmt.println("A");
|
||||
case B: fmt.println("B");
|
||||
case C: fmt.println("C");
|
||||
case D: fmt.println("D");
|
||||
case: fmt.println("?");
|
||||
}
|
||||
}
|
||||
{ // union
|
||||
Foo :: union {int, bool};
|
||||
f: Foo = 123;
|
||||
#complete switch in f {
|
||||
case int: fmt.println("int");
|
||||
case bool: fmt.println("bool");
|
||||
case:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cstring_example :: proc() {
|
||||
W :: "Hellope";
|
||||
X :: cstring(W);
|
||||
Y :: string(X);
|
||||
|
||||
w := W;
|
||||
x: cstring = X;
|
||||
y: string = Y;
|
||||
z := string(x);
|
||||
fmt.println(x, y, z);
|
||||
fmt.println(len(x), len(y), len(z));
|
||||
fmt.println(len(W), len(X), len(Y));
|
||||
// IMPORTANT NOTE for cstring variables
|
||||
// len(cstring) is O(N)
|
||||
// cast(cstring)string is O(N)
|
||||
}
|
||||
|
||||
deprecated_attribute :: proc() {
|
||||
@(deprecated="Use foo_v2 instead")
|
||||
foo_v1 :: proc(x: int) {
|
||||
fmt.println("foo_v1");
|
||||
}
|
||||
foo_v2 :: proc(x: int) {
|
||||
fmt.println("foo_v2");
|
||||
}
|
||||
|
||||
// NOTE: Uncomment to see the warning messages
|
||||
// foo_v1(1);
|
||||
}
|
||||
|
||||
bit_set_type :: proc() {
|
||||
{
|
||||
using Day :: enum {
|
||||
Sunday,
|
||||
Monday,
|
||||
Tuesday,
|
||||
Wednesday,
|
||||
Thursday,
|
||||
Friday,
|
||||
Saturday,
|
||||
}
|
||||
|
||||
Days :: distinct bit_set[Day];
|
||||
WEEKEND :: Days{Sunday, Saturday};
|
||||
|
||||
d: Days;
|
||||
d = {Sunday, Monday};
|
||||
x := Tuesday;
|
||||
e := d | WEEKEND;
|
||||
e |= {Monday};
|
||||
fmt.println(d, e);
|
||||
|
||||
ok := Saturday in e; // `in` is only allowed for `map` and `bit_set` types
|
||||
fmt.println(ok);
|
||||
if Saturday in e {
|
||||
fmt.println("Saturday in", e);
|
||||
}
|
||||
X :: Saturday in WEEKEND; // Constant evaluation
|
||||
fmt.println(X);
|
||||
}
|
||||
{
|
||||
x: bit_set['A'..'Z'];
|
||||
assert(size_of(x) == size_of(u32));
|
||||
y: bit_set[0..8; u16];
|
||||
fmt.println(typeid_of(type_of(x))); // bit_set[A..Z]
|
||||
fmt.println(typeid_of(type_of(y))); // bit_set[0..8l u16]
|
||||
|
||||
incl(&x, 'F');
|
||||
assert('F' in x);
|
||||
excl(&x, 'F');
|
||||
assert(!('F' in x));
|
||||
|
||||
y |= {1, 4, 2};
|
||||
assert(2 in y);
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
when true {
|
||||
general_stuff();
|
||||
default_struct_values();
|
||||
union_type();
|
||||
parametric_polymorphism();
|
||||
threading_example();
|
||||
array_programming();
|
||||
using_in();
|
||||
named_proc_return_parameters();
|
||||
enum_export();
|
||||
using_enum();
|
||||
explicit_procedure_overloading();
|
||||
complete_switch();
|
||||
cstring_example();
|
||||
deprecated_attribute();
|
||||
bit_set_type();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import "core:fmt.odin";
|
||||
|
||||
main :: proc() {
|
||||
recursive_factorial :: proc(i: u64) -> u64 {
|
||||
if i < 2 do return 1;
|
||||
return i * recursive_factorial(i-1);
|
||||
}
|
||||
|
||||
loop_factorial :: proc(i: u64) -> u64 {
|
||||
result: u64 = 1;
|
||||
for n in 2..i {
|
||||
result *= n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fmt.println(recursive_factorial(12));
|
||||
fmt.println(loop_factorial(12));
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
when ODIN_OS == "windows" do import win32 "core:sys/windows.odin";
|
||||
when ODIN_OS == "windows" import wgl "core:sys/wgl.odin";
|
||||
import "core:fmt.odin";
|
||||
import "core:math.odin";
|
||||
import "core:os.odin";
|
||||
import gl "core:opengl.odin";
|
||||
|
||||
TWO_HEARTS :: '💕';
|
||||
|
||||
win32_perf_count_freq := win32.get_query_performance_frequency();
|
||||
time_now :: proc() -> f64 {
|
||||
assert(win32_perf_count_freq != 0);
|
||||
|
||||
counter: i64;
|
||||
win32.query_performance_counter(&counter);
|
||||
return f64(counter) / f64(win32_perf_count_freq);
|
||||
}
|
||||
win32_print_last_error :: proc() {
|
||||
err_code := win32.get_last_error();
|
||||
if err_code != 0 {
|
||||
fmt.println("get_last_error: ", err_code);
|
||||
}
|
||||
}
|
||||
|
||||
// Yuk!
|
||||
to_c_string :: proc(s: string) -> []u8 {
|
||||
c_str := make([]u8, len(s)+1);
|
||||
copy(c_str, cast([]u8)s);
|
||||
c_str[len(s)] = 0;
|
||||
return c_str;
|
||||
}
|
||||
|
||||
|
||||
Window :: struct {
|
||||
width, height: int,
|
||||
wc: win32.Wnd_Class_Ex_A,
|
||||
dc: win32.Hdc,
|
||||
hwnd: win32.Hwnd,
|
||||
opengl_context, rc: wgl.Hglrc,
|
||||
c_title: []u8,
|
||||
}
|
||||
|
||||
make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) {
|
||||
using win32;
|
||||
|
||||
w: Window;
|
||||
w.width, w.height = msg, height;
|
||||
|
||||
class_name := "Win32-Odin-Window\x00";
|
||||
c_class_name := &class_name[0];
|
||||
if title[len(title)-1] != 0 {
|
||||
w.c_title = to_c_string(title);
|
||||
} else {
|
||||
w.c_title = cast([]u8)title;
|
||||
}
|
||||
|
||||
instance := get_module_handle_a(nil);
|
||||
|
||||
w.wc = Wnd_Class_Ex_A{
|
||||
size = size_of(Wnd_Class_Ex_A),
|
||||
style = CS_VREDRAW | CS_HREDRAW,
|
||||
instance = Hinstance(instance),
|
||||
class_name = c_class_name,
|
||||
wnd_proc = window_proc,
|
||||
};
|
||||
|
||||
if register_class_ex_a(&w.wc) == 0 {
|
||||
win32_print_last_error();
|
||||
return w, false;
|
||||
}
|
||||
|
||||
w.hwnd = create_window_ex_a(0,
|
||||
c_class_name, &w.c_title[0],
|
||||
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
i32(w.width), i32(w.height),
|
||||
nil, nil, instance, nil);
|
||||
|
||||
if w.hwnd == nil {
|
||||
win32_print_last_error();
|
||||
return w, false;
|
||||
}
|
||||
|
||||
w.dc = get_dc(w.hwnd);
|
||||
|
||||
{
|
||||
pfd := Pixel_Format_Descriptor{
|
||||
size = size_of(Pixel_Format_Descriptor),
|
||||
version = 1,
|
||||
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
|
||||
pixel_type = PFD_TYPE_RGBA,
|
||||
color_bits = 32,
|
||||
alpha_bits = 8,
|
||||
depth_bits = 24,
|
||||
stencil_bits = 8,
|
||||
layer_type = PFD_MAIN_PLANE,
|
||||
};
|
||||
|
||||
set_pixel_format(w.dc, choose_pixel_format(w.dc, &pfd), nil);
|
||||
w.opengl_context = wgl.create_context(w.dc);
|
||||
wgl.make_current(w.dc, w.opengl_context);
|
||||
|
||||
attribs := [8]i32{
|
||||
wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
|
||||
wgl.CONTEXT_MINOR_VERSION_ARB, 1,
|
||||
wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||
0, // NOTE(bill): tells the that :: proc this is the end of attribs
|
||||
};
|
||||
|
||||
wgl_str := "wglCreateContextAttribsARB\x00";
|
||||
wglCreateContextAttribsARB := cast(wgl.Create_Context_Attribs_ARB_Type)wgl.get_proc_address(&wgl_str[0]);
|
||||
w.rc = wglCreateContextAttribsARB(w.dc, nil, &attribs[0]);
|
||||
wgl.make_current(w.dc, w.rc);
|
||||
swap_buffers(w.dc);
|
||||
}
|
||||
|
||||
return w, true;
|
||||
}
|
||||
|
||||
destroy_window :: proc(w: ^Window) {
|
||||
free(w.c_title);
|
||||
}
|
||||
|
||||
display_window :: proc(w: ^Window) {
|
||||
win32.swap_buffers(w.dc);
|
||||
}
|
||||
|
||||
|
||||
run :: proc() {
|
||||
using math;
|
||||
|
||||
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
|
||||
using win32;
|
||||
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
||||
os.exit(0);
|
||||
return 0;
|
||||
}
|
||||
return def_window_proc_a(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
window, window_success := make_window("Odin Language Demo", 854, 480, cast(win32.Wnd_Proc)win32_proc);
|
||||
if !window_success {
|
||||
return;
|
||||
}
|
||||
defer destroy_window(&window);
|
||||
|
||||
gl.init();
|
||||
|
||||
using win32;
|
||||
|
||||
prev_time := time_now();
|
||||
running := true;
|
||||
|
||||
pos := Vec2{100, 100};
|
||||
|
||||
for running {
|
||||
curr_time := time_now();
|
||||
dt := f32(curr_time - prev_time);
|
||||
prev_time = curr_time;
|
||||
|
||||
msg: Msg;
|
||||
for peek_message_a(&msg, nil, 0, 0, PM_REMOVE) > 0 {
|
||||
if msg.message == WM_QUIT {
|
||||
running = false;
|
||||
}
|
||||
translate_message(&msg);
|
||||
dispatch_message_a(&msg);
|
||||
}
|
||||
|
||||
if is_key_down(Key_Code.Escape) {
|
||||
running = false;
|
||||
}
|
||||
|
||||
{
|
||||
SPEED :: 500;
|
||||
v: Vec2;
|
||||
|
||||
if is_key_down(Key_Code.Right) do v[0] += 1;
|
||||
if is_key_down(Key_Code.Left) do v[0] -= 1;
|
||||
if is_key_down(Key_Code.Up) do v[1] += 1;
|
||||
if is_key_down(Key_Code.Down) do v[1] -= 1;
|
||||
|
||||
v = norm(v);
|
||||
|
||||
pos += v * Vec2{SPEED * dt};
|
||||
}
|
||||
|
||||
|
||||
gl.ClearColor(0.5, 0.7, 1.0, 1.0);
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
gl.LoadIdentity();
|
||||
gl.Ortho(0, f64(window.width),
|
||||
0, f64(window.height), 0, 1);
|
||||
|
||||
draw_rect :: proc(x, y, w, h: f32) {
|
||||
gl.Begin(gl.TRIANGLES);
|
||||
defer gl.End();
|
||||
|
||||
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
|
||||
gl.Color3f(0, 1, 0); gl.Vertex3f(x+w, y, 0);
|
||||
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
|
||||
|
||||
gl.Color3f(0, 0, 1); gl.Vertex3f(x+w, y+h, 0);
|
||||
gl.Color3f(1, 1, 0); gl.Vertex3f(x, y+h, 0);
|
||||
gl.Color3f(1, 0, 0); gl.Vertex3f(x, y, 0);
|
||||
}
|
||||
|
||||
draw_rect(pos.x, pos.y, 50, 50);
|
||||
|
||||
display_window(&window);
|
||||
if ms_to_sleep := i32(16 - 1000*dt); ms_to_sleep > 0 {
|
||||
win32.sleep(ms_to_sleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main :: proc() {
|
||||
run();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import "core:fmt.odin";
|
||||
|
||||
main :: proc() {
|
||||
fmt.println("Hellope, world!");
|
||||
}
|
||||
@@ -328,7 +328,7 @@ miscellany :: proc() {
|
||||
*/
|
||||
|
||||
// assert(false)
|
||||
// compile_assert(false)
|
||||
// #assert(false)
|
||||
// panic("Panic message goes here")
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ enumerations :: proc() {
|
||||
}
|
||||
|
||||
variadic_procedures :: proc() {
|
||||
print_ints :: proc(args: ...int) {
|
||||
print_ints :: proc(args: ..int) {
|
||||
for arg, i in args {
|
||||
if i > 0 do print(", ");
|
||||
print(arg);
|
||||
@@ -106,7 +106,7 @@ variadic_procedures :: proc() {
|
||||
print_ints(1); nl();
|
||||
print_ints(1, 2, 3); nl();
|
||||
|
||||
print_prefix_f32s :: proc(prefix: string, args: ...f32) {
|
||||
print_prefix_f32s :: proc(prefix: string, args: ..f32) {
|
||||
print(prefix);
|
||||
print(": ");
|
||||
for arg, i in args {
|
||||
@@ -171,8 +171,8 @@ new_builtins :: proc() {
|
||||
{
|
||||
// Compile time assert
|
||||
COND :: true;
|
||||
compile_assert(COND);
|
||||
// compile_assert(!COND)
|
||||
#assert(COND);
|
||||
// #assert(!COND)
|
||||
|
||||
// Runtime assert
|
||||
x := true;
|
||||
@@ -323,7 +323,7 @@ match_statement :: proc() {
|
||||
|
||||
Vector3 :: struct {x, y, z: f32}
|
||||
|
||||
print_floats :: proc(args: ...f32) {
|
||||
print_floats :: proc(args: ..f32) {
|
||||
for arg, i in args {
|
||||
if i > 0 do print(", ");
|
||||
print(arg);
|
||||
|
||||
@@ -32,7 +32,7 @@ main :: proc() {
|
||||
|
||||
/*
|
||||
push_allocator x {
|
||||
...
|
||||
..
|
||||
}
|
||||
|
||||
is equivalent to:
|
||||
@@ -42,7 +42,7 @@ main :: proc() {
|
||||
__context.allocator = x
|
||||
defer __context.allocator = prev_allocator
|
||||
|
||||
...
|
||||
..
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ syntax :: proc() {
|
||||
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
||||
|
||||
// Slice interals are now just a `ptr+len+cap`
|
||||
slice: []int; compile_assert(size_of(slice) == 3*size_of(int));
|
||||
slice: []int; #assert(size_of(slice) == 3*size_of(int));
|
||||
|
||||
// Helper type - Help the reader understand what it is quicker
|
||||
My_Int :: #type int;
|
||||
@@ -202,7 +202,7 @@ loops :: proc() {
|
||||
fmt.println(val, idx);
|
||||
}
|
||||
|
||||
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||
primes := [?]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||
|
||||
for p in primes {
|
||||
fmt.println(p);
|
||||
@@ -218,7 +218,7 @@ loops :: proc() {
|
||||
name := "你好,世界";
|
||||
fmt.println(name);
|
||||
for r in name {
|
||||
compile_assert(type_of(r) == rune);
|
||||
#assert(type_of(r) == rune);
|
||||
fmt.printf("%r\n", r);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ when true {
|
||||
Removed:
|
||||
* Maybe/option types
|
||||
* Remove `type` keyword and other "reserved" keywords
|
||||
* ..< and ... removed and replace with .. (half-closed range)
|
||||
* ..< and .. removed and replace with .. (half-closed range)
|
||||
|
||||
Changed:
|
||||
* `compile_assert` and `assert` return the value of the condition for semantic reasons
|
||||
* `#assert` and `assert` return the value of the condition for semantic reasons
|
||||
* thread_local -> #thread_local
|
||||
* #include -> #load
|
||||
* Files only get checked if they are actually used
|
||||
@@ -51,7 +51,7 @@ when true {
|
||||
}
|
||||
|
||||
{
|
||||
// Removal of ..< and ...
|
||||
// Removal of ..< and ..
|
||||
for i in 0..16 {
|
||||
}
|
||||
// Is similar to
|
||||
@@ -159,8 +159,8 @@ when true {
|
||||
fmt.println(i);
|
||||
}
|
||||
|
||||
compile_assert(size_of([vector 7]bool) >= size_of([7]bool));
|
||||
compile_assert(size_of([vector 7]i32) >= size_of([7]i32));
|
||||
#assert(size_of([vector 7]bool) >= size_of([7]bool));
|
||||
#assert(size_of([vector 7]i32) >= size_of([7]i32));
|
||||
// align_of([vector 7]i32) != align_of([7]i32) // this may be the case
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,570 @@
|
||||
import "core:fmt.odin"
|
||||
import "core:strconv.odin"
|
||||
import "core:mem.odin"
|
||||
import "core:bits.odin"
|
||||
import "core:hash.odin"
|
||||
import "core:math.odin"
|
||||
import "core:os.odin"
|
||||
import "core:raw.odin"
|
||||
import "core:sort.odin"
|
||||
import "core:strings.odin"
|
||||
import "core:types.odin"
|
||||
import "core:utf16.odin"
|
||||
import "core:utf8.odin"
|
||||
|
||||
when ODIN_OS == "windows" {
|
||||
import "core:atomics.odin"
|
||||
import "core:opengl.odin"
|
||||
import "core:thread.odin"
|
||||
import win32 "core:sys/windows.odin"
|
||||
}
|
||||
|
||||
general_stuff :: proc() {
|
||||
{ // `do` for inline statmes rather than block
|
||||
foo :: proc() do fmt.println("Foo!");
|
||||
if false do foo();
|
||||
for false do foo();
|
||||
when false do foo();
|
||||
|
||||
if false do foo();
|
||||
else do foo();
|
||||
}
|
||||
|
||||
{ // Removal of `++` and `--` (again)
|
||||
x: int;
|
||||
x += 1;
|
||||
x -= 1;
|
||||
}
|
||||
{ // Casting syntaxes
|
||||
i := i32(137);
|
||||
ptr := &i;
|
||||
|
||||
fp1 := (^f32)(ptr);
|
||||
// ^f32(ptr) == ^(f32(ptr))
|
||||
fp2 := cast(^f32)ptr;
|
||||
|
||||
f1 := (^f32)(ptr)^;
|
||||
f2 := (cast(^f32)ptr)^;
|
||||
|
||||
// Questions: Should there be two ways to do it?
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove *_val_of built-in procedures
|
||||
* size_of, align_of, offset_of
|
||||
* type_of, type_info_of
|
||||
*/
|
||||
|
||||
{ // `expand_to_tuple` built-in procedure
|
||||
Foo :: struct {
|
||||
x: int,
|
||||
b: bool,
|
||||
}
|
||||
f := Foo{137, true};
|
||||
x, b := expand_to_tuple(f);
|
||||
fmt.println(f);
|
||||
fmt.println(x, b);
|
||||
fmt.println(expand_to_tuple(f));
|
||||
}
|
||||
|
||||
{
|
||||
// .. half-closed range
|
||||
// .. open range
|
||||
|
||||
for in 0..2 {} // 0, 1
|
||||
for in 0..2 {} // 0, 1, 2
|
||||
}
|
||||
}
|
||||
|
||||
default_struct_values :: proc() {
|
||||
{
|
||||
Vector3 :: struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
}
|
||||
v: Vector3;
|
||||
fmt.println(v);
|
||||
}
|
||||
{
|
||||
// Default values must be constants
|
||||
Vector3 :: struct {
|
||||
x: f32 = 1,
|
||||
y: f32 = 4,
|
||||
z: f32 = 9,
|
||||
}
|
||||
v: Vector3;
|
||||
fmt.println(v);
|
||||
|
||||
v = Vector3{};
|
||||
fmt.println(v);
|
||||
|
||||
// Uses the same semantics as a default values in a procedure
|
||||
v = Vector3{137};
|
||||
fmt.println(v);
|
||||
|
||||
v = Vector3{z = 137};
|
||||
fmt.println(v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 :: struct {
|
||||
x := 1.0,
|
||||
y := 4.0,
|
||||
z := 9.0,
|
||||
}
|
||||
stack_default: Vector3;
|
||||
stack_literal := Vector3{};
|
||||
heap_one := new(Vector3); defer free(heap_one);
|
||||
heap_two := new_clone(Vector3{}); defer free(heap_two);
|
||||
|
||||
fmt.println("stack_default - ", stack_default);
|
||||
fmt.println("stack_literal - ", stack_literal);
|
||||
fmt.println("heap_one - ", heap_one^);
|
||||
fmt.println("heap_two - ", heap_two^);
|
||||
|
||||
|
||||
N :: 4;
|
||||
stack_array: [N]Vector3;
|
||||
heap_array := new([N]Vector3); defer free(heap_array);
|
||||
heap_slice := make([]Vector3, N); defer free(heap_slice);
|
||||
fmt.println("stack_array[1] - ", stack_array[1]);
|
||||
fmt.println("heap_array[1] - ", heap_array[1]);
|
||||
fmt.println("heap_slice[1] - ", heap_slice[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
union_type :: proc() {
|
||||
{
|
||||
val: union{int, bool};
|
||||
val = 137;
|
||||
if i, ok := val.(int); ok {
|
||||
fmt.println(i);
|
||||
}
|
||||
val = true;
|
||||
fmt.println(val);
|
||||
|
||||
val = nil;
|
||||
|
||||
switch v in val {
|
||||
case int: fmt.println("int", v);
|
||||
case bool: fmt.println("bool", v);
|
||||
case: fmt.println("nil");
|
||||
}
|
||||
}
|
||||
{
|
||||
// There is a duality between `any` and `union`
|
||||
// An `any` has a pointer to the data and allows for any type (open)
|
||||
// A `union` has as binary blob to store the data and allows only certain types (closed)
|
||||
// The following code is with `any` but has the same syntax
|
||||
val: any;
|
||||
val = 137;
|
||||
if i, ok := val.(int); ok {
|
||||
fmt.println(i);
|
||||
}
|
||||
val = true;
|
||||
fmt.println(val);
|
||||
|
||||
val = nil;
|
||||
|
||||
switch v in val {
|
||||
case int: fmt.println("int", v);
|
||||
case bool: fmt.println("bool", v);
|
||||
case: fmt.println("nil");
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 :: struct {x, y, z: f32};
|
||||
Quaternion :: struct {x, y, z: f32, w: f32 = 1};
|
||||
|
||||
// More realistic examples
|
||||
{
|
||||
// NOTE(bill): For the above basic examples, you may not have any
|
||||
// particular use for it. However, my main use for them is not for these
|
||||
// simple cases. My main use is for hierarchical types. Many prefer
|
||||
// subtyping, embedding the base data into the derived types. Below is
|
||||
// an example of this for a basic game Entity.
|
||||
|
||||
Entity :: struct {
|
||||
id: u64,
|
||||
name: string,
|
||||
position: Vector3,
|
||||
orientation: Quaternion,
|
||||
|
||||
derived: any,
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: Entity,
|
||||
jump_height: f32,
|
||||
}
|
||||
|
||||
Monster :: struct {
|
||||
using entity: Entity,
|
||||
is_robot: bool,
|
||||
is_zombie: bool,
|
||||
}
|
||||
|
||||
// See `parametric_polymorphism` procedure for details
|
||||
new_entity :: proc(T: type) -> ^Entity {
|
||||
t := new(T);
|
||||
t.derived = t^;
|
||||
return t;
|
||||
}
|
||||
|
||||
entity := new_entity(Monster);
|
||||
|
||||
switch e in entity.derived {
|
||||
case Frog:
|
||||
fmt.println("Ribbit");
|
||||
case Monster:
|
||||
if e.is_robot do fmt.println("Robotic");
|
||||
if e.is_zombie do fmt.println("Grrrr!");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// NOTE(bill): A union can be used to achieve something similar. Instead
|
||||
// of embedding the base data into the derived types, the derived data
|
||||
// in embedded into the base type. Below is the same example of the
|
||||
// basic game Entity but using an union.
|
||||
|
||||
Entity :: struct {
|
||||
id: u64,
|
||||
name: string,
|
||||
position: Vector3,
|
||||
orientation: Quaternion,
|
||||
|
||||
derived: union {Frog, Monster},
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: ^Entity,
|
||||
jump_height: f32,
|
||||
}
|
||||
|
||||
Monster :: struct {
|
||||
using entity: ^Entity,
|
||||
is_robot: bool,
|
||||
is_zombie: bool,
|
||||
}
|
||||
|
||||
// See `parametric_polymorphism` procedure for details
|
||||
new_entity :: proc(T: type) -> ^Entity {
|
||||
t := new(Entity);
|
||||
t.derived = T{entity = t};
|
||||
return t;
|
||||
}
|
||||
|
||||
entity := new_entity(Monster);
|
||||
|
||||
switch e in entity.derived {
|
||||
case Frog:
|
||||
fmt.println("Ribbit");
|
||||
case Monster:
|
||||
if e.is_robot do fmt.println("Robotic");
|
||||
if e.is_zombie do fmt.println("Grrrr!");
|
||||
}
|
||||
|
||||
// NOTE(bill): As you can see, the usage code has not changed, only its
|
||||
// memory layout. Both approaches have their own advantages but they can
|
||||
// be used together to achieve different results. The subtyping approach
|
||||
// can allow for a greater control of the memory layout and memory
|
||||
// allocation, e.g. storing the derivatives together. However, this is
|
||||
// also its disadvantage. You must either preallocate arrays for each
|
||||
// derivative separation (which can be easily missed) or preallocate a
|
||||
// bunch of "raw" memory; determining the maximum size of the derived
|
||||
// types would require the aid of metaprogramming. Unions solve this
|
||||
// particular problem as the data is stored with the base data.
|
||||
// Therefore, it is possible to preallocate, e.g. [100]Entity.
|
||||
|
||||
// It should be noted that the union approach can have the same memory
|
||||
// layout as the any and with the same type restrictions by using a
|
||||
// pointer type for the derivatives.
|
||||
|
||||
/*
|
||||
Entity :: struct {
|
||||
..
|
||||
derived: union{^Frog, ^Monster};
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: Entity;
|
||||
..
|
||||
}
|
||||
Monster :: struct {
|
||||
using entity: Entity;
|
||||
..
|
||||
|
||||
}
|
||||
new_entity :: proc(T: type) -> ^Entity {
|
||||
t := new(T);
|
||||
t.derived = t;
|
||||
return t;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
parametric_polymorphism :: proc() {
|
||||
print_value :: proc(value: $T) {
|
||||
fmt.printf("print_value: %T %v\n", value, value);
|
||||
}
|
||||
|
||||
v1: int = 1;
|
||||
v2: f32 = 2.1;
|
||||
v3: f64 = 3.14;
|
||||
v4: string = "message";
|
||||
|
||||
print_value(v1);
|
||||
print_value(v2);
|
||||
print_value(v3);
|
||||
print_value(v4);
|
||||
|
||||
fmt.println();
|
||||
|
||||
add :: proc(p, q: $T) -> T {
|
||||
x: T = p + q;
|
||||
return x;
|
||||
}
|
||||
|
||||
a := add(3, 4);
|
||||
fmt.printf("a: %T = %v\n", a, a);
|
||||
|
||||
b := add(3.2, 4.3);
|
||||
fmt.printf("b: %T = %v\n", b, b);
|
||||
|
||||
// This is how `new` is implemented
|
||||
alloc_type :: proc(T: type) -> ^T {
|
||||
t := cast(^T)alloc(size_of(T), align_of(T));
|
||||
t^ = T{}; // Use default initialization value
|
||||
return t;
|
||||
}
|
||||
|
||||
copy_slice :: proc(dst, src: []$T) -> int {
|
||||
n := min(len(dst), len(src));
|
||||
if n > 0 {
|
||||
mem.copy(&dst[0], &src[0], n*size_of(T));
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
double_params :: proc(a: $A, b: $B) -> A {
|
||||
return a + A(b);
|
||||
}
|
||||
|
||||
fmt.println(double_params(12, 1.345));
|
||||
|
||||
|
||||
|
||||
{ // Polymorphic Types and Type Specialization
|
||||
Table_Slot :: struct(Key, Value: type) {
|
||||
occupied: bool,
|
||||
hash: u32,
|
||||
key: Key,
|
||||
value: Value,
|
||||
}
|
||||
TABLE_SIZE_MIN :: 32;
|
||||
Table :: struct(Key, Value: type) {
|
||||
count: int,
|
||||
allocator: Allocator,
|
||||
slots: []Table_Slot(Key, Value),
|
||||
}
|
||||
|
||||
// Only allow types that are specializations of a (polymorphic) slice
|
||||
make_slice :: proc(T: type/[]$E, len: int) -> T {
|
||||
return make(T, len);
|
||||
}
|
||||
|
||||
|
||||
// Only allow types that are specializations of `Table`
|
||||
allocate :: proc(table: ^$T/Table, capacity: int) {
|
||||
c := context;
|
||||
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
||||
|
||||
push_context c {
|
||||
table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
|
||||
}
|
||||
}
|
||||
|
||||
expand :: proc(table: ^$T/Table) {
|
||||
c := context;
|
||||
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
||||
|
||||
push_context c {
|
||||
old_slots := table.slots;
|
||||
|
||||
cap := max(2*cap(table.slots), TABLE_SIZE_MIN);
|
||||
allocate(table, cap);
|
||||
|
||||
for s in old_slots do if s.occupied {
|
||||
put(table, s.key, s.value);
|
||||
}
|
||||
|
||||
free(old_slots);
|
||||
}
|
||||
}
|
||||
|
||||
// Polymorphic determination of a polymorphic struct
|
||||
// put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
|
||||
put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
|
||||
hash := get_hash(key); // Ad-hoc method which would fail in a different scope
|
||||
index := find_index(table, key, hash);
|
||||
if index < 0 {
|
||||
if f64(table.count) >= 0.75*f64(cap(table.slots)) {
|
||||
expand(table);
|
||||
}
|
||||
assert(table.count <= cap(table.slots));
|
||||
|
||||
hash := get_hash(key);
|
||||
index = int(hash % u32(cap(table.slots)));
|
||||
|
||||
for table.slots[index].occupied {
|
||||
if index += 1; index >= cap(table.slots) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
table.count += 1;
|
||||
}
|
||||
|
||||
slot := &table.slots[index];
|
||||
slot.occupied = true;
|
||||
slot.hash = hash;
|
||||
slot.key = key;
|
||||
slot.value = value;
|
||||
}
|
||||
|
||||
|
||||
// find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
|
||||
find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
|
||||
hash := get_hash(key);
|
||||
index := find_index(table, key, hash);
|
||||
if index < 0 {
|
||||
return Value{}, false;
|
||||
}
|
||||
return table.slots[index].value, true;
|
||||
}
|
||||
|
||||
find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
|
||||
if cap(table.slots) <= 0 do return -1;
|
||||
|
||||
index := int(hash % u32(cap(table.slots)));
|
||||
for table.slots[index].occupied {
|
||||
if table.slots[index].hash == hash {
|
||||
if table.slots[index].key == key {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
if index += 1; index >= cap(table.slots) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
get_hash :: proc(s: string) -> u32 { // fnv32a
|
||||
h: u32 = 0x811c9dc5;
|
||||
for i in 0..len(s) {
|
||||
h = (h ~ u32(s[i])) * 0x01000193;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
table: Table(string, int);
|
||||
|
||||
for i in 0..36 do put(&table, "Hellope", i);
|
||||
for i in 0..42 do put(&table, "World!", i);
|
||||
|
||||
found, _ := find(&table, "Hellope");
|
||||
fmt.printf("`found` is %v\n", found);
|
||||
|
||||
found, _ = find(&table, "World!");
|
||||
fmt.printf("`found` is %v\n", found);
|
||||
|
||||
// I would not personally design a hash table like this in production
|
||||
// but this is a nice basic example
|
||||
// A better approach would either use a `u64` or equivalent for the key
|
||||
// and let the user specify the hashing function or make the user store
|
||||
// the hashing procedure with the table
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
prefix_table := [?]string{
|
||||
"White",
|
||||
"Red",
|
||||
"Green",
|
||||
"Blue",
|
||||
"Octarine",
|
||||
"Black",
|
||||
};
|
||||
|
||||
threading_example :: proc() {
|
||||
when ODIN_OS == "windows" {
|
||||
unordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
|
||||
__bounds_check_error_loc(loc, index, len(array));
|
||||
array[index] = array[len(array)-1];
|
||||
pop(array);
|
||||
}
|
||||
ordered_remove :: proc(array: ^[]$T, index: int, loc := #caller_location) {
|
||||
__bounds_check_error_loc(loc, index, len(array));
|
||||
copy(array[index..], array[index+1..]);
|
||||
pop(array);
|
||||
}
|
||||
|
||||
worker_proc :: proc(t: ^thread.Thread) -> int {
|
||||
for iteration in 1..5 {
|
||||
fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
|
||||
fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
|
||||
// win32.sleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
threads := make([]^thread.Thread, 0, len(prefix_table));
|
||||
defer free(threads);
|
||||
|
||||
for i in 0..len(prefix_table) {
|
||||
if t := thread.create(worker_proc); t != nil {
|
||||
t.init_context = context;
|
||||
t.use_init_context = true;
|
||||
t.user_index = len(threads);
|
||||
append(&threads, t);
|
||||
thread.start(t);
|
||||
}
|
||||
}
|
||||
|
||||
for len(threads) > 0 {
|
||||
for i := 0; i < len(threads); /**/ {
|
||||
if t := threads[i]; thread.is_done(t) {
|
||||
fmt.printf("Thread %d is done\n", t.user_index);
|
||||
thread.destroy(t);
|
||||
|
||||
ordered_remove(&threads, i);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
when false {
|
||||
fmt.println("\n# general_stuff"); general_stuff();
|
||||
fmt.println("\n# default_struct_values"); default_struct_values();
|
||||
fmt.println("\n# union_type"); union_type();
|
||||
fmt.println("\n# parametric_polymorphism"); parametric_polymorphism();
|
||||
fmt.println("\n# threading_example"); threading_example();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,778 @@
|
||||
import "core:fmt.odin"
|
||||
import "core:strconv.odin"
|
||||
import "core:mem.odin"
|
||||
import "core:bits.odin"
|
||||
import "core:hash.odin"
|
||||
import "core:math.odin"
|
||||
import "core:math/rand.odin"
|
||||
import "core:os.odin"
|
||||
import "core:raw.odin"
|
||||
import "core:sort.odin"
|
||||
import "core:strings.odin"
|
||||
import "core:types.odin"
|
||||
import "core:utf16.odin"
|
||||
import "core:utf8.odin"
|
||||
|
||||
// File scope `when` statements
|
||||
when ODIN_OS == "windows" {
|
||||
import "core:atomics.odin"
|
||||
import "core:thread.odin"
|
||||
import win32 "core:sys/windows.odin"
|
||||
}
|
||||
|
||||
@(link_name="general_stuff")
|
||||
general_stuff :: proc() {
|
||||
fmt.println("# general_stuff");
|
||||
{ // `do` for inline statements rather than block
|
||||
foo :: proc() do fmt.println("Foo!");
|
||||
if false do foo();
|
||||
for false do foo();
|
||||
when false do foo();
|
||||
|
||||
if false do foo();
|
||||
else do foo();
|
||||
}
|
||||
|
||||
{ // Removal of `++` and `--` (again)
|
||||
x: int;
|
||||
x += 1;
|
||||
x -= 1;
|
||||
}
|
||||
{ // Casting syntaxes
|
||||
i := i32(137);
|
||||
ptr := &i;
|
||||
|
||||
_ = (^f32)(ptr);
|
||||
// ^f32(ptr) == ^(f32(ptr))
|
||||
_ = cast(^f32)ptr;
|
||||
|
||||
_ = (^f32)(ptr)^;
|
||||
_ = (cast(^f32)ptr)^;
|
||||
|
||||
// Questions: Should there be two ways to do it?
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove *_val_of built-in procedures
|
||||
* size_of, align_of, offset_of
|
||||
* type_of, type_info_of
|
||||
*/
|
||||
|
||||
{ // `expand_to_tuple` built-in procedure
|
||||
Foo :: struct {
|
||||
x: int,
|
||||
b: bool,
|
||||
}
|
||||
f := Foo{137, true};
|
||||
x, b := expand_to_tuple(f);
|
||||
fmt.println(f);
|
||||
fmt.println(x, b);
|
||||
fmt.println(expand_to_tuple(f));
|
||||
}
|
||||
|
||||
{
|
||||
// .. half-closed range
|
||||
// .. open range
|
||||
|
||||
for in 0..2 {} // 0, 1
|
||||
for in 0..2 {} // 0, 1, 2
|
||||
}
|
||||
|
||||
{ // Multiple sized booleans
|
||||
|
||||
x0: bool; // default
|
||||
x1: b8 = true;
|
||||
x2: b16 = false;
|
||||
x3: b32 = true;
|
||||
x4: b64 = false;
|
||||
|
||||
fmt.printf("x1: %T = %v;\n", x1, x1);
|
||||
fmt.printf("x2: %T = %v;\n", x2, x2);
|
||||
fmt.printf("x3: %T = %v;\n", x3, x3);
|
||||
fmt.printf("x4: %T = %v;\n", x4, x4);
|
||||
|
||||
// Having specific sized booleans is very useful when dealing with foreign code
|
||||
// and to enforce specific alignment for a boolean, especially within a struct
|
||||
}
|
||||
|
||||
{ // `distinct` types
|
||||
// Originally, all type declarations would create a distinct type unless #type_alias was present.
|
||||
// Now the behaviour has been reversed. All type declarations create a type alias unless `distinct` is present.
|
||||
// If the type expression is `struct`, `union`, `enum`, `proc`, or `bit_field`, the types will always been distinct.
|
||||
|
||||
Int32 :: i32;
|
||||
#assert(Int32 == i32);
|
||||
|
||||
My_Int32 :: distinct i32;
|
||||
#assert(My_Int32 != i32);
|
||||
|
||||
My_Struct :: struct{x: int};
|
||||
#assert(My_Struct != struct{x: int});
|
||||
}
|
||||
}
|
||||
|
||||
default_struct_values :: proc() {
|
||||
fmt.println("# default_struct_values");
|
||||
{
|
||||
Vector3 :: struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
}
|
||||
v: Vector3;
|
||||
fmt.println(v);
|
||||
}
|
||||
{
|
||||
// Default values must be constants
|
||||
Vector3 :: struct {
|
||||
x: f32 = 1,
|
||||
y: f32 = 4,
|
||||
z: f32 = 9,
|
||||
}
|
||||
v: Vector3;
|
||||
fmt.println(v);
|
||||
|
||||
v = Vector3{};
|
||||
fmt.println(v);
|
||||
|
||||
// Uses the same semantics as a default values in a procedure
|
||||
v = Vector3{137};
|
||||
fmt.println(v);
|
||||
|
||||
v = Vector3{z = 137};
|
||||
fmt.println(v);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 :: struct {
|
||||
x := 1.0,
|
||||
y := 4.0,
|
||||
z := 9.0,
|
||||
}
|
||||
stack_default: Vector3;
|
||||
stack_literal := Vector3{};
|
||||
heap_one := new(Vector3); defer free(heap_one);
|
||||
heap_two := new_clone(Vector3{}); defer free(heap_two);
|
||||
|
||||
fmt.println("stack_default - ", stack_default);
|
||||
fmt.println("stack_literal - ", stack_literal);
|
||||
fmt.println("heap_one - ", heap_one^);
|
||||
fmt.println("heap_two - ", heap_two^);
|
||||
|
||||
|
||||
N :: 4;
|
||||
stack_array: [N]Vector3;
|
||||
heap_array := new([N]Vector3); defer free(heap_array);
|
||||
heap_slice := make([]Vector3, N); defer free(heap_slice);
|
||||
fmt.println("stack_array[1] - ", stack_array[1]);
|
||||
fmt.println("heap_array[1] - ", heap_array[1]);
|
||||
fmt.println("heap_slice[1] - ", heap_slice[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
union_type :: proc() {
|
||||
fmt.println("\n# union_type");
|
||||
{
|
||||
val: union{int, bool};
|
||||
val = 137;
|
||||
if i, ok := val.(int); ok {
|
||||
fmt.println(i);
|
||||
}
|
||||
val = true;
|
||||
fmt.println(val);
|
||||
|
||||
val = nil;
|
||||
|
||||
switch v in val {
|
||||
case int: fmt.println("int", v);
|
||||
case bool: fmt.println("bool", v);
|
||||
case: fmt.println("nil");
|
||||
}
|
||||
}
|
||||
{
|
||||
// There is a duality between `any` and `union`
|
||||
// An `any` has a pointer to the data and allows for any type (open)
|
||||
// A `union` has as binary blob to store the data and allows only certain types (closed)
|
||||
// The following code is with `any` but has the same syntax
|
||||
val: any;
|
||||
val = 137;
|
||||
if i, ok := val.(int); ok {
|
||||
fmt.println(i);
|
||||
}
|
||||
val = true;
|
||||
fmt.println(val);
|
||||
|
||||
val = nil;
|
||||
|
||||
switch v in val {
|
||||
case int: fmt.println("int", v);
|
||||
case bool: fmt.println("bool", v);
|
||||
case: fmt.println("nil");
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 :: struct {x, y, z: f32};
|
||||
Quaternion :: struct {x, y, z: f32, w: f32 = 1};
|
||||
|
||||
// More realistic examples
|
||||
{
|
||||
// NOTE(bill): For the above basic examples, you may not have any
|
||||
// particular use for it. However, my main use for them is not for these
|
||||
// simple cases. My main use is for hierarchical types. Many prefer
|
||||
// subtyping, embedding the base data into the derived types. Below is
|
||||
// an example of this for a basic game Entity.
|
||||
|
||||
Entity :: struct {
|
||||
id: u64,
|
||||
name: string,
|
||||
position: Vector3,
|
||||
orientation: Quaternion,
|
||||
|
||||
derived: any,
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: Entity,
|
||||
jump_height: f32,
|
||||
}
|
||||
|
||||
Monster :: struct {
|
||||
using entity: Entity,
|
||||
is_robot: bool,
|
||||
is_zombie: bool,
|
||||
}
|
||||
|
||||
// See `parametric_polymorphism` procedure for details
|
||||
new_entity :: proc(T: type) -> ^Entity {
|
||||
t := new(T);
|
||||
t.derived = t^;
|
||||
return t;
|
||||
}
|
||||
|
||||
entity := new_entity(Monster);
|
||||
|
||||
switch e in entity.derived {
|
||||
case Frog:
|
||||
fmt.println("Ribbit");
|
||||
case Monster:
|
||||
if e.is_robot do fmt.println("Robotic");
|
||||
if e.is_zombie do fmt.println("Grrrr!");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// NOTE(bill): A union can be used to achieve something similar. Instead
|
||||
// of embedding the base data into the derived types, the derived data
|
||||
// in embedded into the base type. Below is the same example of the
|
||||
// basic game Entity but using an union.
|
||||
|
||||
Entity :: struct {
|
||||
id: u64,
|
||||
name: string,
|
||||
position: Vector3,
|
||||
orientation: Quaternion,
|
||||
|
||||
derived: union {Frog, Monster},
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: ^Entity,
|
||||
jump_height: f32,
|
||||
}
|
||||
|
||||
Monster :: struct {
|
||||
using entity: ^Entity,
|
||||
is_robot: bool,
|
||||
is_zombie: bool,
|
||||
}
|
||||
|
||||
// See `parametric_polymorphism` procedure for details
|
||||
new_entity :: proc(T: type) -> ^Entity {
|
||||
t := new(Entity);
|
||||
t.derived = T{entity = t};
|
||||
return t;
|
||||
}
|
||||
|
||||
entity := new_entity(Monster);
|
||||
|
||||
switch e in entity.derived {
|
||||
case Frog:
|
||||
fmt.println("Ribbit");
|
||||
case Monster:
|
||||
if e.is_robot do fmt.println("Robotic");
|
||||
if e.is_zombie do fmt.println("Grrrr!");
|
||||
}
|
||||
|
||||
// NOTE(bill): As you can see, the usage code has not changed, only its
|
||||
// memory layout. Both approaches have their own advantages but they can
|
||||
// be used together to achieve different results. The subtyping approach
|
||||
// can allow for a greater control of the memory layout and memory
|
||||
// allocation, e.g. storing the derivatives together. However, this is
|
||||
// also its disadvantage. You must either preallocate arrays for each
|
||||
// derivative separation (which can be easily missed) or preallocate a
|
||||
// bunch of "raw" memory; determining the maximum size of the derived
|
||||
// types would require the aid of metaprogramming. Unions solve this
|
||||
// particular problem as the data is stored with the base data.
|
||||
// Therefore, it is possible to preallocate, e.g. [100]Entity.
|
||||
|
||||
// It should be noted that the union approach can have the same memory
|
||||
// layout as the any and with the same type restrictions by using a
|
||||
// pointer type for the derivatives.
|
||||
|
||||
/*
|
||||
Entity :: struct {
|
||||
..
|
||||
derived: union{^Frog, ^Monster},
|
||||
}
|
||||
|
||||
Frog :: struct {
|
||||
using entity: Entity,
|
||||
..
|
||||
}
|
||||
Monster :: struct {
|
||||
using entity: Entity,
|
||||
..
|
||||
|
||||
}
|
||||
new_entity :: proc(T: type) -> ^Entity {
|
||||
t := new(T);
|
||||
t.derived = t;
|
||||
return t;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
parametric_polymorphism :: proc() {
|
||||
fmt.println("# parametric_polymorphism");
|
||||
|
||||
print_value :: proc(value: $T) {
|
||||
fmt.printf("print_value: %T %v\n", value, value);
|
||||
}
|
||||
|
||||
v1: int = 1;
|
||||
v2: f32 = 2.1;
|
||||
v3: f64 = 3.14;
|
||||
v4: string = "message";
|
||||
|
||||
print_value(v1);
|
||||
print_value(v2);
|
||||
print_value(v3);
|
||||
print_value(v4);
|
||||
|
||||
fmt.println();
|
||||
|
||||
add :: proc(p, q: $T) -> T {
|
||||
x: T = p + q;
|
||||
return x;
|
||||
}
|
||||
|
||||
a := add(3, 4);
|
||||
fmt.printf("a: %T = %v\n", a, a);
|
||||
|
||||
b := add(3.2, 4.3);
|
||||
fmt.printf("b: %T = %v\n", b, b);
|
||||
|
||||
// This is how `new` is implemented
|
||||
alloc_type :: proc(T: type) -> ^T {
|
||||
t := cast(^T)alloc(size_of(T), align_of(T));
|
||||
t^ = T{}; // Use default initialization value
|
||||
return t;
|
||||
}
|
||||
|
||||
copy_slice :: proc(dst, src: []$T) -> int {
|
||||
return mem.copy(&dst[0], &src[0], n*size_of(T));
|
||||
}
|
||||
|
||||
double_params :: proc(a: $A, b: $B) -> A {
|
||||
return a + A(b);
|
||||
}
|
||||
|
||||
fmt.println(double_params(12, 1.345));
|
||||
|
||||
|
||||
|
||||
{ // Polymorphic Types and Type Specialization
|
||||
Table_Slot :: struct(Key, Value: type) {
|
||||
occupied: bool,
|
||||
hash: u32,
|
||||
key: Key,
|
||||
value: Value,
|
||||
}
|
||||
TABLE_SIZE_MIN :: 32;
|
||||
Table :: struct(Key, Value: type) {
|
||||
count: int,
|
||||
allocator: Allocator,
|
||||
slots: []Table_Slot(Key, Value),
|
||||
}
|
||||
|
||||
// Only allow types that are specializations of a (polymorphic) slice
|
||||
make_slice :: proc(T: type/[]$E, len: int) -> T {
|
||||
return make(T, len);
|
||||
}
|
||||
|
||||
|
||||
// Only allow types that are specializations of `Table`
|
||||
allocate :: proc(table: ^$T/Table, capacity: int) {
|
||||
c := context;
|
||||
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
||||
|
||||
context <- c {
|
||||
table.slots = make_slice(type_of(table.slots), max(capacity, TABLE_SIZE_MIN));
|
||||
}
|
||||
}
|
||||
|
||||
expand :: proc(table: ^$T/Table) {
|
||||
c := context;
|
||||
if table.allocator.procedure != nil do c.allocator = table.allocator;
|
||||
|
||||
context <- c {
|
||||
old_slots := table.slots;
|
||||
|
||||
cap := max(2*len(table.slots), TABLE_SIZE_MIN);
|
||||
allocate(table, cap);
|
||||
|
||||
for s in old_slots do if s.occupied {
|
||||
put(table, s.key, s.value);
|
||||
}
|
||||
|
||||
free(old_slots);
|
||||
}
|
||||
}
|
||||
|
||||
// Polymorphic determination of a polymorphic struct
|
||||
// put :: proc(table: ^$T/Table, key: T.Key, value: T.Value) {
|
||||
put :: proc(table: ^Table($Key, $Value), key: Key, value: Value) {
|
||||
hash := get_hash(key); // Ad-hoc method which would fail in a different scope
|
||||
index := find_index(table, key, hash);
|
||||
if index < 0 {
|
||||
if f64(table.count) >= 0.75*f64(len(table.slots)) {
|
||||
expand(table);
|
||||
}
|
||||
assert(table.count <= len(table.slots));
|
||||
|
||||
hash := get_hash(key);
|
||||
index = int(hash % u32(len(table.slots)));
|
||||
|
||||
for table.slots[index].occupied {
|
||||
if index += 1; index >= len(table.slots) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
table.count += 1;
|
||||
}
|
||||
|
||||
slot := &table.slots[index];
|
||||
slot.occupied = true;
|
||||
slot.hash = hash;
|
||||
slot.key = key;
|
||||
slot.value = value;
|
||||
}
|
||||
|
||||
|
||||
// find :: proc(table: ^$T/Table, key: T.Key) -> (T.Value, bool) {
|
||||
find :: proc(table: ^Table($Key, $Value), key: Key) -> (Value, bool) {
|
||||
hash := get_hash(key);
|
||||
index := find_index(table, key, hash);
|
||||
if index < 0 {
|
||||
return Value{}, false;
|
||||
}
|
||||
return table.slots[index].value, true;
|
||||
}
|
||||
|
||||
find_index :: proc(table: ^Table($Key, $Value), key: Key, hash: u32) -> int {
|
||||
if len(table.slots) <= 0 do return -1;
|
||||
|
||||
index := int(hash % u32(len(table.slots)));
|
||||
for table.slots[index].occupied {
|
||||
if table.slots[index].hash == hash {
|
||||
if table.slots[index].key == key {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
if index += 1; index >= len(table.slots) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
get_hash :: proc(s: string) -> u32 { // fnv32a
|
||||
h: u32 = 0x811c9dc5;
|
||||
for i in 0..len(s) {
|
||||
h = (h ~ u32(s[i])) * 0x01000193;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
table: Table(string, int);
|
||||
|
||||
for i in 0..36 do put(&table, "Hellope", i);
|
||||
for i in 0..42 do put(&table, "World!", i);
|
||||
|
||||
found, _ := find(&table, "Hellope");
|
||||
fmt.printf("`found` is %v\n", found);
|
||||
|
||||
found, _ = find(&table, "World!");
|
||||
fmt.printf("`found` is %v\n", found);
|
||||
|
||||
// I would not personally design a hash table like this in production
|
||||
// but this is a nice basic example
|
||||
// A better approach would either use a `u64` or equivalent for the key
|
||||
// and let the user specify the hashing function or make the user store
|
||||
// the hashing procedure with the table
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
prefix_table := [?]string{
|
||||
"White",
|
||||
"Red",
|
||||
"Green",
|
||||
"Blue",
|
||||
"Octarine",
|
||||
"Black",
|
||||
};
|
||||
|
||||
threading_example :: proc() {
|
||||
when ODIN_OS == "windows" {
|
||||
fmt.println("# threading_example");
|
||||
|
||||
unordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
|
||||
__bounds_check_error_loc(loc, index, len(array));
|
||||
array[index] = array[len(array)-1];
|
||||
pop(array);
|
||||
}
|
||||
ordered_remove :: proc(array: ^[dynamic]$T, index: int, loc := #caller_location) {
|
||||
__bounds_check_error_loc(loc, index, len(array));
|
||||
copy(array[index..], array[index+1..]);
|
||||
pop(array);
|
||||
}
|
||||
|
||||
worker_proc :: proc(t: ^thread.Thread) -> int {
|
||||
for iteration in 1..5 {
|
||||
fmt.printf("Thread %d is on iteration %d\n", t.user_index, iteration);
|
||||
fmt.printf("`%s`: iteration %d\n", prefix_table[t.user_index], iteration);
|
||||
// win32.sleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
threads := make([dynamic]^thread.Thread, 0, len(prefix_table));
|
||||
defer free(threads);
|
||||
|
||||
for in prefix_table {
|
||||
if t := thread.create(worker_proc); t != nil {
|
||||
t.init_context = context;
|
||||
t.use_init_context = true;
|
||||
t.user_index = len(threads);
|
||||
append(&threads, t);
|
||||
thread.start(t);
|
||||
}
|
||||
}
|
||||
|
||||
for len(threads) > 0 {
|
||||
for i := 0; i < len(threads); /**/ {
|
||||
if t := threads[i]; thread.is_done(t) {
|
||||
fmt.printf("Thread %d is done\n", t.user_index);
|
||||
thread.destroy(t);
|
||||
|
||||
ordered_remove(&threads, i);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array_programming :: proc() {
|
||||
fmt.println("# array_programming");
|
||||
{
|
||||
a := [3]f32{1, 2, 3};
|
||||
b := [3]f32{5, 6, 7};
|
||||
c := a * b;
|
||||
d := a + b;
|
||||
e := 1 + (c - d) / 2;
|
||||
fmt.printf("%.1f\n", e); // [0.5, 3.0, 6.5]
|
||||
}
|
||||
|
||||
{
|
||||
a := [3]f32{1, 2, 3};
|
||||
b := swizzle(a, 2, 1, 0);
|
||||
assert(b == [3]f32{3, 2, 1});
|
||||
|
||||
c := swizzle(a, 0, 0);
|
||||
assert(c == [2]f32{1, 1});
|
||||
assert(c == 1);
|
||||
}
|
||||
|
||||
{
|
||||
Vector3 :: distinct [3]f32;
|
||||
a := Vector3{1, 2, 3};
|
||||
b := Vector3{5, 6, 7};
|
||||
c := (a * b)/2 + 1;
|
||||
d := c.x + c.y + c.z;
|
||||
fmt.printf("%.1f\n", d); // 22.0
|
||||
|
||||
cross :: proc(a, b: Vector3) -> Vector3 {
|
||||
i := swizzle(a, 1, 2, 0) * swizzle(b, 2, 0, 1);
|
||||
j := swizzle(a, 2, 0, 1) * swizzle(b, 1, 2, 0);
|
||||
return i - j;
|
||||
}
|
||||
|
||||
blah :: proc(a: Vector3) -> f32 {
|
||||
return a.x + a.y + a.z;
|
||||
}
|
||||
|
||||
x := cross(a, b);
|
||||
fmt.println(x);
|
||||
fmt.println(blah(x));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using println in import "core:fmt.odin"
|
||||
|
||||
using_in :: proc() {
|
||||
fmt.println("# using in");
|
||||
using print in fmt;
|
||||
|
||||
println("Hellope1");
|
||||
print("Hellope2\n");
|
||||
|
||||
Foo :: struct {
|
||||
x, y: int,
|
||||
b: bool,
|
||||
}
|
||||
f: Foo;
|
||||
f.x, f.y = 123, 321;
|
||||
println(f);
|
||||
using x, y in f;
|
||||
x, y = 456, 654;
|
||||
println(f);
|
||||
}
|
||||
|
||||
named_proc_return_parameters :: proc() {
|
||||
fmt.println("# named proc return parameters");
|
||||
|
||||
foo0 :: proc() -> int {
|
||||
return 123;
|
||||
}
|
||||
foo1 :: proc() -> (a: int) {
|
||||
a = 123;
|
||||
return;
|
||||
}
|
||||
foo2 :: proc() -> (a, b: int) {
|
||||
// Named return values act like variables within the scope
|
||||
a = 321;
|
||||
b = 567;
|
||||
return b, a;
|
||||
}
|
||||
fmt.println("foo0 =", foo0()); // 123
|
||||
fmt.println("foo1 =", foo1()); // 123
|
||||
fmt.println("foo2 =", foo2()); // 567 321
|
||||
}
|
||||
|
||||
|
||||
enum_export :: proc() {
|
||||
fmt.println("# enum #export");
|
||||
|
||||
Foo :: enum #export {A, B, C};
|
||||
|
||||
f0 := A;
|
||||
f1 := B;
|
||||
f2 := C;
|
||||
fmt.println(f0, f1, f2);
|
||||
}
|
||||
|
||||
explicit_procedure_overloading :: proc() {
|
||||
fmt.println("# explicit procedure overloading");
|
||||
|
||||
add_ints :: proc(a, b: int) -> int {
|
||||
x := a + b;
|
||||
fmt.println("add_ints", x);
|
||||
return x;
|
||||
}
|
||||
add_floats :: proc(a, b: f32) -> f32 {
|
||||
x := a + b;
|
||||
fmt.println("add_floats", x);
|
||||
return x;
|
||||
}
|
||||
add_numbers :: proc(a: int, b: f32, c: u8) -> int {
|
||||
x := int(a) + int(b) + int(c);
|
||||
fmt.println("add_numbers", x);
|
||||
return x;
|
||||
}
|
||||
|
||||
add :: proc[add_ints, add_floats, add_numbers];
|
||||
|
||||
add(int(1), int(2));
|
||||
add(f32(1), f32(2));
|
||||
add(int(1), f32(2), u8(3));
|
||||
|
||||
add(1, 2); // untyped ints coerce to int tighter than f32
|
||||
add(1.0, 2.0); // untyped floats coerce to f32 tighter than int
|
||||
add(1, 2, 3); // three parameters
|
||||
|
||||
// Ambiguous answers
|
||||
// add(1.0, 2);
|
||||
// add(1, 2.0);
|
||||
}
|
||||
|
||||
complete_switch :: proc() {
|
||||
fmt.println("# complete_switch");
|
||||
{ // enum
|
||||
Foo :: enum #export {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
}
|
||||
|
||||
b := Foo.B;
|
||||
f := Foo.A;
|
||||
#complete switch f {
|
||||
case A: fmt.println("A");
|
||||
case B: fmt.println("B");
|
||||
case C: fmt.println("C");
|
||||
case D: fmt.println("D");
|
||||
case: fmt.println("?");
|
||||
}
|
||||
}
|
||||
{ // union
|
||||
Foo :: union {int, bool};
|
||||
f: Foo = 123;
|
||||
#complete switch in f {
|
||||
case int: fmt.println("int");
|
||||
case bool: fmt.println("bool");
|
||||
case:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main :: proc() {
|
||||
when true {
|
||||
general_stuff();
|
||||
default_struct_values();
|
||||
union_type();
|
||||
parametric_polymorphism();
|
||||
threading_example();
|
||||
array_programming();
|
||||
using_in();
|
||||
named_proc_return_parameters();
|
||||
enum_export();
|
||||
explicit_procedure_overloading();
|
||||
complete_switch();
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ memory_copy :: proc(dst, src: rawptr, n: int) #inline {
|
||||
}
|
||||
|
||||
v128b :: type {4}u32
|
||||
compile_assert(align_of(v128b) == 16)
|
||||
#assert(align_of(v128b) == 16)
|
||||
|
||||
d, s: ^byte = dst, src
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ general_stuff :: proc() {
|
||||
// C-style variadic procedures
|
||||
foreign __llvm_core {
|
||||
// The variadic part allows for extra type checking too which C does not provide
|
||||
c_printf :: proc(fmt: ^u8, #c_vararg args: ...any) -> i32 #link_name "printf" ---;
|
||||
c_printf :: proc(fmt: ^u8, #c_vararg args: ..any) -> i32 #link_name "printf" ---;
|
||||
}
|
||||
str := "%d\n\x00";
|
||||
// c_printf(&str[0], i32(789456123));
|
||||
@@ -50,9 +50,9 @@ general_stuff :: proc() {
|
||||
foo := Foo{123, 0.513, "A string"};
|
||||
x, y, z := expand_to_tuple(foo);
|
||||
fmt.println(x, y, z);
|
||||
compile_assert(type_of(x) == int);
|
||||
compile_assert(type_of(y) == f32);
|
||||
compile_assert(type_of(z) == string);
|
||||
#assert(type_of(x) == int);
|
||||
#assert(type_of(y) == f32);
|
||||
#assert(type_of(z) == string);
|
||||
|
||||
|
||||
// By default, all variables are zeroed
|
||||
@@ -154,8 +154,8 @@ default_return_values :: proc() {
|
||||
match x {
|
||||
case 0: return;
|
||||
case 1: return "Goodbye";
|
||||
case 2: return "Goodbye", "cruel world...";
|
||||
case 3: return second = "cruel world...", first = "Goodbye";
|
||||
case 2: return "Goodbye", "cruel world..";
|
||||
case 3: return second = "cruel world..", first = "Goodbye";
|
||||
}
|
||||
|
||||
return second = "my old friend.";
|
||||
@@ -231,7 +231,7 @@ explicit_parametric_polymorphic_procedures :: proc() {
|
||||
defer free(another_ptr);
|
||||
|
||||
|
||||
add :: proc(T: type, args: ...T) -> T {
|
||||
add :: proc(T: type, args: ..T) -> T {
|
||||
res: T;
|
||||
for arg in args do res += arg;
|
||||
return res;
|
||||
|
||||
@@ -1,479 +0,0 @@
|
||||
import win32 "core:sys/windows.odin";
|
||||
import "core:fmt.odin";
|
||||
import "core:os.odin";
|
||||
import "core:mem.odin";
|
||||
|
||||
|
||||
CANVAS_WIDTH :: 128;
|
||||
CANVAS_HEIGHT :: 128;
|
||||
CANVAS_SCALE :: 3;
|
||||
FRAME_TIME :: 1.0/30.0;
|
||||
WINDOW_TITLE :: "Punity\x00";
|
||||
|
||||
_ :: compile_assert(CANVAS_WIDTH % 16 == 0);
|
||||
|
||||
|
||||
WINDOW_WIDTH :: CANVAS_WIDTH * CANVAS_SCALE;
|
||||
WINDOW_HEIGHT :: CANVAS_HEIGHT * CANVAS_SCALE;
|
||||
|
||||
|
||||
STACK_CAPACITY :: 1<<20;
|
||||
STORAGE_CAPACITY :: 1<<20;
|
||||
|
||||
DRAW_LIST_RESERVE :: 128;
|
||||
|
||||
MAX_KEYS :: 256;
|
||||
|
||||
Core :: struct {
|
||||
stack: ^Bank,
|
||||
storage: ^Bank,
|
||||
|
||||
running: bool,
|
||||
key_modifiers: u32,
|
||||
key_states: [MAX_KEYS]u8,
|
||||
key_deltas: [MAX_KEYS]u8,
|
||||
|
||||
perf_frame,
|
||||
perf_frame_inner,
|
||||
perf_step,
|
||||
perf_audio,
|
||||
perf_blit,
|
||||
perf_blit_cvt,
|
||||
perf_blit_gdi: Perf_Span,
|
||||
|
||||
frame: i64,
|
||||
|
||||
canvas: Canvas,
|
||||
draw_list: ^Draw_List,
|
||||
}
|
||||
|
||||
Perf_Span :: struct {
|
||||
stamp: f64,
|
||||
delta: f32,
|
||||
}
|
||||
|
||||
Bank :: struct {
|
||||
memory: []u8,
|
||||
cursor: int,
|
||||
}
|
||||
|
||||
Bank_State :: struct {
|
||||
state: Bank,
|
||||
bank: ^Bank,
|
||||
}
|
||||
|
||||
|
||||
Color :: struct #raw_union {
|
||||
using channels: struct{a, b, g, r: u8},
|
||||
rgba: u32,
|
||||
}
|
||||
|
||||
Palette :: struct {
|
||||
colors: [256]Color,
|
||||
colors_count: u8,
|
||||
}
|
||||
|
||||
|
||||
Rect :: struct #raw_union {
|
||||
using minmax: struct {min_x, min_y, max_x, max_y: int},
|
||||
using pos: struct {left, top, right, bottom: int},
|
||||
e: [4]int,
|
||||
}
|
||||
|
||||
Bitmap :: struct {
|
||||
pixels: []u8,
|
||||
width: int,
|
||||
height: int,
|
||||
}
|
||||
|
||||
Font :: struct {
|
||||
using bitmap: Bitmap,
|
||||
char_width: int,
|
||||
char_height: int,
|
||||
}
|
||||
|
||||
Canvas :: struct {
|
||||
using bitmap: ^Bitmap,
|
||||
palette: Palette,
|
||||
translate_x: int,
|
||||
translate_y: int,
|
||||
clip: Rect,
|
||||
font: ^Font,
|
||||
}
|
||||
|
||||
DrawFlag :: enum {
|
||||
NONE = 0,
|
||||
FLIP_H = 1<<0,
|
||||
FLIP_V = 1<<1,
|
||||
MASK = 1<<2,
|
||||
}
|
||||
|
||||
Draw_Item :: struct {}
|
||||
Draw_List :: struct {
|
||||
items: []Draw_Item,
|
||||
}
|
||||
|
||||
Key :: enum {
|
||||
Mod_Shift = 0x0001,
|
||||
Mod_Control = 0x0002,
|
||||
Mod_Alt = 0x0004,
|
||||
Mod_Super = 0x0008,
|
||||
|
||||
|
||||
Unknown =-1,
|
||||
Invalid =-2,
|
||||
|
||||
|
||||
Lbutton = 1,
|
||||
Rbutton = 2,
|
||||
Cancel = 3,
|
||||
Mbutton = 4,
|
||||
|
||||
|
||||
Back = 8,
|
||||
Tab = 9,
|
||||
Clear = 12,
|
||||
Return = 13,
|
||||
Shift = 16,
|
||||
Control = 17,
|
||||
Menu = 18,
|
||||
Pause = 19,
|
||||
Capital = 20,
|
||||
Kana = 0x15,
|
||||
Hangeul = 0x15,
|
||||
Hangul = 0x15,
|
||||
Junja = 0x17,
|
||||
Final = 0x18,
|
||||
Hanja = 0x19,
|
||||
Kanji = 0x19,
|
||||
Escape = 0x1B,
|
||||
Convert = 0x1C,
|
||||
Non_Convert = 0x1D,
|
||||
Accept = 0x1E,
|
||||
Mode_Change = 0x1F,
|
||||
Space = 32,
|
||||
Prior = 33,
|
||||
Next = 34,
|
||||
End = 35,
|
||||
Home = 36,
|
||||
Left = 37,
|
||||
Up = 38,
|
||||
Right = 39,
|
||||
Down = 40,
|
||||
Select = 41,
|
||||
Print = 42,
|
||||
Exec = 43,
|
||||
Snapshot = 44,
|
||||
Insert = 45,
|
||||
Delete = 46,
|
||||
Help = 47,
|
||||
Lwin = 0x5B,
|
||||
Rwin = 0x5C,
|
||||
Apps = 0x5D,
|
||||
Sleep = 0x5F,
|
||||
Numpad0 = 0x60,
|
||||
Numpad1 = 0x61,
|
||||
Numpad2 = 0x62,
|
||||
Numpad3 = 0x63,
|
||||
Numpad4 = 0x64,
|
||||
Numpad5 = 0x65,
|
||||
Numpad6 = 0x66,
|
||||
Numpad7 = 0x67,
|
||||
Numpad8 = 0x68,
|
||||
Numpad9 = 0x69,
|
||||
Multiply = 0x6A,
|
||||
Add = 0x6B,
|
||||
Separator = 0x6C,
|
||||
Subtract = 0x6D,
|
||||
Decimal = 0x6E,
|
||||
Divide = 0x6F,
|
||||
F1 = 0x70,
|
||||
F2 = 0x71,
|
||||
F3 = 0x72,
|
||||
F4 = 0x73,
|
||||
F5 = 0x74,
|
||||
F6 = 0x75,
|
||||
F7 = 0x76,
|
||||
F8 = 0x77,
|
||||
F9 = 0x78,
|
||||
F10 = 0x79,
|
||||
F11 = 0x7A,
|
||||
F12 = 0x7B,
|
||||
F13 = 0x7C,
|
||||
F14 = 0x7D,
|
||||
F15 = 0x7E,
|
||||
F16 = 0x7F,
|
||||
F17 = 0x80,
|
||||
F18 = 0x81,
|
||||
F19 = 0x82,
|
||||
F20 = 0x83,
|
||||
F21 = 0x84,
|
||||
F22 = 0x85,
|
||||
F23 = 0x86,
|
||||
F24 = 0x87,
|
||||
Numlock = 0x90,
|
||||
Scroll = 0x91,
|
||||
Lshift = 0xA0,
|
||||
Rshift = 0xA1,
|
||||
Lcontrol = 0xA2,
|
||||
Rcontrol = 0xA3,
|
||||
Lmenu = 0xA4,
|
||||
Rmenu = 0xA5,
|
||||
|
||||
|
||||
Apostrophe = 39, /* ' */
|
||||
Comma = 44, /* , */
|
||||
Minus = 45, /* - */
|
||||
Period = 46, /* . */
|
||||
Slash = 47, /* / */
|
||||
Num0 = 48,
|
||||
Num1 = 49,
|
||||
Num2 = 50,
|
||||
Num3 = 51,
|
||||
Num4 = 52,
|
||||
Num5 = 53,
|
||||
Num6 = 54,
|
||||
Num7 = 55,
|
||||
Num8 = 56,
|
||||
Num9 = 57,
|
||||
Semicolon = 59, /* ; */
|
||||
Equal = 61, /* = */
|
||||
A = 65,
|
||||
B = 66,
|
||||
C = 67,
|
||||
D = 68,
|
||||
E = 69,
|
||||
F = 70,
|
||||
G = 71,
|
||||
H = 72,
|
||||
I = 73,
|
||||
J = 74,
|
||||
K = 75,
|
||||
L = 76,
|
||||
M = 77,
|
||||
N = 78,
|
||||
O = 79,
|
||||
P = 80,
|
||||
Q = 81,
|
||||
R = 82,
|
||||
S = 83,
|
||||
T = 84,
|
||||
U = 85,
|
||||
V = 86,
|
||||
W = 87,
|
||||
X = 88,
|
||||
Y = 89,
|
||||
Z = 90,
|
||||
Left_Bracket = 91, /* [ */
|
||||
Backslash = 92, /* \ */
|
||||
Right_Bracket = 93, /* ] */
|
||||
Grave_Accent = 96, /* ` */
|
||||
};
|
||||
|
||||
|
||||
key_down :: proc(k: Key) -> bool {
|
||||
return _core.key_states[k] != 0;
|
||||
}
|
||||
|
||||
key_pressed :: proc(k: Key) -> bool {
|
||||
return (_core.key_deltas[k] != 0) && key_down(k);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
win32_perf_count_freq := win32.get_query_performance_frequency();
|
||||
time_now :: proc() -> f64 {
|
||||
assert(win32_perf_count_freq != 0);
|
||||
|
||||
counter: i64;
|
||||
win32.query_performance_counter(&counter);
|
||||
return f64(counter) / f64(win32_perf_count_freq);
|
||||
}
|
||||
|
||||
_core: Core;
|
||||
|
||||
run :: proc(user_init, user_step: proc(c: ^Core)) {
|
||||
using win32;
|
||||
|
||||
_core.running = true;
|
||||
|
||||
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline #cc_c {
|
||||
win32_app_key_mods :: proc() -> u32 {
|
||||
mods: u32 = 0;
|
||||
|
||||
if is_key_down(Key_Code.Shift) do mods |= u32(Key.Mod_Shift);
|
||||
if is_key_down(Key_Code.Control) do mods |= u32(Key.Mod_Control);
|
||||
if is_key_down(Key_Code.Menu) do mods |= u32(Key.Mod_Alt);
|
||||
if is_key_down(Key_Code.Lwin) do mods |= u32(Key.Mod_Super);
|
||||
if is_key_down(Key_Code.Rwin) do mods |= u32(Key.Mod_Super);
|
||||
|
||||
return mods;
|
||||
}
|
||||
|
||||
match msg {
|
||||
case WM_KEYDOWN:
|
||||
_core.key_modifiers = win32_app_key_mods();
|
||||
if wparam < MAX_KEYS {
|
||||
_core.key_states[wparam] = 1;
|
||||
_core.key_deltas[wparam] = 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_KEYUP:
|
||||
_core.key_modifiers = win32_app_key_mods();
|
||||
if wparam < MAX_KEYS {
|
||||
_core.key_states[wparam] = 0;
|
||||
_core.key_deltas[wparam] = 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_CLOSE:
|
||||
post_quit_message(0);
|
||||
_core.running = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return def_window_proc_a(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
|
||||
class_name := "Punity\x00";
|
||||
window_class := Wnd_Class_Ex_A{
|
||||
class_name = &class_name[0],
|
||||
size = size_of(Wnd_Class_Ex_A),
|
||||
style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||
instance = Hinstance(get_module_handle_a(nil)),
|
||||
wnd_proc = win32_proc,
|
||||
background = Hbrush(get_stock_object(BLACK_BRUSH)),
|
||||
};
|
||||
|
||||
if register_class_ex_a(&window_class) == 0 {
|
||||
fmt.fprintln(os.stderr, "register_class_ex_a failed");
|
||||
return;
|
||||
}
|
||||
|
||||
screen_width := get_system_metrics(SM_CXSCREEN);
|
||||
screen_height := get_system_metrics(SM_CYSCREEN);
|
||||
|
||||
rc: Rect;
|
||||
rc.left = (screen_width - WINDOW_WIDTH) / 2;
|
||||
rc.top = (screen_height - WINDOW_HEIGHT) / 2;
|
||||
rc.right = rc.left + WINDOW_WIDTH;
|
||||
rc.bottom = rc.top + WINDOW_HEIGHT;
|
||||
|
||||
style: u32 = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
|
||||
assert(adjust_window_rect(&rc, style, 0) != 0);
|
||||
|
||||
wt := WINDOW_TITLE;
|
||||
|
||||
win32_window := create_window_ex_a(0,
|
||||
window_class.class_name,
|
||||
&wt[0],
|
||||
style,
|
||||
rc.left, rc.top,
|
||||
rc.right-rc.left, rc.bottom-rc.top,
|
||||
nil, nil, window_class.instance,
|
||||
nil);
|
||||
|
||||
if win32_window == nil {
|
||||
fmt.fprintln(os.stderr, "create_window_ex_a failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
window_bmi: Bitmap_Info;
|
||||
window_bmi.size = size_of(Bitmap_Info_Header);
|
||||
window_bmi.width = CANVAS_WIDTH;
|
||||
window_bmi.height = CANVAS_HEIGHT;
|
||||
window_bmi.planes = 1;
|
||||
window_bmi.bit_count = 32;
|
||||
window_bmi.compression = BI_RGB;
|
||||
|
||||
|
||||
user_init(&_core);
|
||||
|
||||
show_window(win32_window, SW_SHOW);
|
||||
|
||||
window_buffer := make([]u32, CANVAS_WIDTH * CANVAS_HEIGHT);
|
||||
defer free(window_buffer);
|
||||
|
||||
for _, i in window_buffer do window_buffer[i] = 0xff00ff;
|
||||
|
||||
dt: f64;
|
||||
prev_time := time_now();
|
||||
curr_time := time_now();
|
||||
total_time: f64 = 0;
|
||||
offset_x := 0;
|
||||
offset_y := 0;
|
||||
|
||||
message: Msg;
|
||||
for _core.running {
|
||||
curr_time = time_now();
|
||||
dt = curr_time - prev_time;
|
||||
prev_time = curr_time;
|
||||
total_time += dt;
|
||||
|
||||
offset_x += 1;
|
||||
offset_y += 2;
|
||||
|
||||
{
|
||||
buf: [128]u8;
|
||||
s := fmt.bprintf(buf[..], "Punity: %.4f ms\x00", dt*1000);
|
||||
win32.set_window_text_a(win32_window, &s[0]);
|
||||
}
|
||||
|
||||
|
||||
for y in 0..CANVAS_HEIGHT {
|
||||
for x in 0..CANVAS_WIDTH {
|
||||
g := (x % 32) * 8;
|
||||
b := (y % 32) * 8;
|
||||
window_buffer[x + y*CANVAS_WIDTH] = u32(g << 8 | b);
|
||||
}
|
||||
}
|
||||
|
||||
mem.zero(&_core.key_deltas[0], size_of(_core.key_deltas));
|
||||
|
||||
for peek_message_a(&message, nil, 0, 0, PM_REMOVE) != 0 {
|
||||
if message.message == WM_QUIT {
|
||||
_core.running = false;
|
||||
}
|
||||
translate_message(&message);
|
||||
dispatch_message_a(&message);
|
||||
}
|
||||
|
||||
user_step(&_core);
|
||||
|
||||
dc := get_dc(win32_window);
|
||||
stretch_dibits(dc,
|
||||
0, 0, CANVAS_WIDTH * CANVAS_SCALE, CANVAS_HEIGHT * CANVAS_SCALE,
|
||||
0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
|
||||
&window_buffer[0],
|
||||
&window_bmi,
|
||||
DIB_RGB_COLORS,
|
||||
SRCCOPY);
|
||||
release_dc(win32_window, dc);
|
||||
|
||||
|
||||
|
||||
delta := time_now() - prev_time;
|
||||
if ms := i32((FRAME_TIME - delta) * 1000); ms > 0 {
|
||||
win32.sleep(ms);
|
||||
}
|
||||
|
||||
_core.frame += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main :: proc() {
|
||||
user_init :: proc(c: ^Core) {
|
||||
|
||||
}
|
||||
|
||||
user_step :: proc(c: ^Core) {
|
||||
|
||||
}
|
||||
|
||||
run(user_init, user_step);
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 72 KiB |
+89
-22
@@ -24,36 +24,57 @@ struct Array {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> void array_init (Array<T> *array, gbAllocator a, isize init_capacity = ARRAY_GROW_FORMULA(0));
|
||||
template <typename T> void array_init_count (Array<T> *array, gbAllocator a, isize count);
|
||||
template <typename T> Array<T> array_make (T *data, isize count, isize capacity);
|
||||
template <typename T> void array_free (Array<T> *array);
|
||||
template <typename T> void array_add (Array<T> *array, T const &t);
|
||||
template <typename T> T array_pop (Array<T> *array);
|
||||
template <typename T> void array_clear (Array<T> *array);
|
||||
template <typename T> void array_reserve (Array<T> *array, isize capacity);
|
||||
template <typename T> void array_resize (Array<T> *array, isize count);
|
||||
template <typename T> void array_set_capacity(Array<T> *array, isize capacity);
|
||||
template <typename T> void array_init (Array<T> *array, gbAllocator const &a);
|
||||
template <typename T> void array_init (Array<T> *array, gbAllocator const &a, isize count);
|
||||
template <typename T> void array_init (Array<T> *array, gbAllocator const &a, isize count, isize capacity);
|
||||
template <typename T> Array<T> array_make (gbAllocator const &a);
|
||||
template <typename T> Array<T> array_make (gbAllocator const &a, isize count);
|
||||
template <typename T> Array<T> array_make (gbAllocator const &a, isize count, isize capacity);
|
||||
template <typename T> Array<T> array_make_from_ptr(T *data, isize count, isize capacity);
|
||||
template <typename T> void array_free (Array<T> *array);
|
||||
template <typename T> void array_add (Array<T> *array, T const &t);
|
||||
template <typename T> T array_pop (Array<T> *array);
|
||||
template <typename T> void array_clear (Array<T> *array);
|
||||
template <typename T> void array_reserve (Array<T> *array, isize capacity);
|
||||
template <typename T> void array_resize (Array<T> *array, isize count);
|
||||
template <typename T> void array_set_capacity (Array<T> *array, isize capacity);
|
||||
template <typename T> Array<T> array_slice (Array<T> const &array, isize lo, isize hi);
|
||||
|
||||
template <typename T>
|
||||
void array_init(Array<T> *array, gbAllocator a, isize init_capacity) {
|
||||
array->allocator = a;
|
||||
array->data = gb_alloc_array(a, T, init_capacity);
|
||||
array->count = 0;
|
||||
array->capacity = init_capacity;
|
||||
T *array_end_ptr(Array<T> *array) {
|
||||
if (array->count > 0) {
|
||||
return &array->data[array->count-1];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline void array_init(Array<T> *array, gbAllocator const &a) {
|
||||
isize cap = ARRAY_GROW_FORMULA(0);
|
||||
array_init(array, a, 0, cap);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array_init_count(Array<T> *array, gbAllocator a, isize count) {
|
||||
gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count) {
|
||||
array_init(array, a, count, count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count, isize capacity) {
|
||||
array->allocator = a;
|
||||
array->data = gb_alloc_array(a, T, count);
|
||||
array->data = nullptr;
|
||||
if (capacity > 0) {
|
||||
array->data = gb_alloc_array(a, T, capacity);
|
||||
}
|
||||
array->count = count;
|
||||
array->capacity = count;
|
||||
array->capacity = capacity;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
Array<T> array_make(T *data, isize count, isize capacity) {
|
||||
gb_inline Array<T> array_make_from_ptr(T *data, isize count, isize capacity) {
|
||||
Array<T> a = {0};
|
||||
a.data = data;
|
||||
a.count = count;
|
||||
@@ -63,7 +84,38 @@ Array<T> array_make(T *data, isize count, isize capacity) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void array_free(Array<T> *array) {
|
||||
gb_inline Array<T> array_make(gbAllocator const &a) {
|
||||
isize capacity = ARRAY_GROW_FORMULA(0);
|
||||
Array<T> array = {};
|
||||
array.allocator = a;
|
||||
array.data = gb_alloc_array(a, T, capacity);
|
||||
array.count = 0;
|
||||
array.capacity = capacity;
|
||||
return array;
|
||||
}
|
||||
template <typename T>
|
||||
gb_inline Array<T> array_make(gbAllocator const &a, isize count) {
|
||||
Array<T> array = {};
|
||||
array.allocator = a;
|
||||
array.data = gb_alloc_array(a, T, count);
|
||||
array.count = count;
|
||||
array.capacity = count;
|
||||
return array;
|
||||
}
|
||||
template <typename T>
|
||||
gb_inline Array<T> array_make(gbAllocator const &a, isize count, isize capacity) {
|
||||
Array<T> array = {};
|
||||
array.allocator = a;
|
||||
array.data = gb_alloc_array(a, T, capacity);
|
||||
array.count = count;
|
||||
array.capacity = capacity;
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline void array_free(Array<T> *array) {
|
||||
if (array->allocator.proc != nullptr) {
|
||||
gb_free(array->allocator, array->data);
|
||||
}
|
||||
@@ -90,7 +142,7 @@ void array_add(Array<T> *array, T const &t) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T array_pop(Array<T> *array) {
|
||||
gb_inline T array_pop(Array<T> *array) {
|
||||
GB_ASSERT(array->count > 0);
|
||||
array->count--;
|
||||
return array->data[array->count];
|
||||
@@ -136,11 +188,26 @@ void array_set_capacity(Array<T> *array, isize capacity) {
|
||||
array->capacity = capacity;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline Array<T> array_slice(Array<T> const &array, isize lo, isize hi) {
|
||||
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
|
||||
Array<T> out = {};
|
||||
isize len = hi-lo;
|
||||
if (len > 0) {
|
||||
out.data = array.data+lo;
|
||||
out.count = len;
|
||||
out.capacity = len;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define Array(Type_) struct { \
|
||||
gbAllocator allocator; \
|
||||
gbAllocator const &allocator; \
|
||||
Type_ * e; \
|
||||
isize count; \
|
||||
isize capacity; \
|
||||
|
||||
+1420
File diff suppressed because it is too large
Load Diff
+242
-77
@@ -1,3 +1,58 @@
|
||||
enum TargetOsKind {
|
||||
TargetOs_Invalid,
|
||||
|
||||
TargetOs_windows,
|
||||
TargetOs_osx,
|
||||
TargetOs_linux,
|
||||
TargetOs_essence,
|
||||
|
||||
TargetOs_COUNT,
|
||||
};
|
||||
|
||||
enum TargetArchKind {
|
||||
TargetArch_Invalid,
|
||||
|
||||
TargetArch_amd64,
|
||||
TargetArch_386,
|
||||
|
||||
TargetArch_COUNT,
|
||||
};
|
||||
|
||||
String target_os_names[TargetOs_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("windows"),
|
||||
str_lit("osx"),
|
||||
str_lit("linux"),
|
||||
str_lit("essence"),
|
||||
};
|
||||
|
||||
String target_arch_names[TargetArch_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("amd64"),
|
||||
str_lit("386"),
|
||||
};
|
||||
|
||||
String target_arch_endian[TargetArch_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("little"),
|
||||
str_lit("little"),
|
||||
};
|
||||
|
||||
|
||||
String const ODIN_VERSION = str_lit("0.9.0");
|
||||
String cross_compile_target = str_lit("");
|
||||
String cross_compile_lib_dir = str_lit("");
|
||||
|
||||
|
||||
|
||||
struct TargetMetrics {
|
||||
TargetOsKind os;
|
||||
TargetArchKind arch;
|
||||
isize word_size;
|
||||
isize max_align;
|
||||
};
|
||||
|
||||
|
||||
// This stores the information for the specify architecture of this build
|
||||
struct BuildContext {
|
||||
// Constants
|
||||
@@ -15,6 +70,11 @@ struct BuildContext {
|
||||
|
||||
String command;
|
||||
|
||||
TargetMetrics metrics;
|
||||
|
||||
String out_filepath;
|
||||
String resource_filepath;
|
||||
bool has_resource;
|
||||
String opt_flags;
|
||||
String llc_flags;
|
||||
String link_flags;
|
||||
@@ -24,15 +84,121 @@ struct BuildContext {
|
||||
bool show_timings;
|
||||
bool keep_temp_files;
|
||||
bool no_bounds_check;
|
||||
bool no_output_files;
|
||||
bool no_crt;
|
||||
|
||||
gbAffinity affinity;
|
||||
isize thread_count;
|
||||
};
|
||||
|
||||
|
||||
|
||||
gb_global BuildContext build_context = {0};
|
||||
|
||||
|
||||
|
||||
gb_global TargetMetrics target_windows_386 = {
|
||||
TargetOs_windows,
|
||||
TargetArch_386,
|
||||
4,
|
||||
8,
|
||||
};
|
||||
gb_global TargetMetrics target_windows_amd64 = {
|
||||
TargetOs_windows,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_linux_386 = {
|
||||
TargetOs_linux,
|
||||
TargetArch_386,
|
||||
4,
|
||||
8,
|
||||
};
|
||||
gb_global TargetMetrics target_linux_amd64 = {
|
||||
TargetOs_linux,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_osx_amd64 = {
|
||||
TargetOs_osx,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
TargetOsKind get_target_os_from_string(String str) {
|
||||
for (isize i = 0; i < TargetOs_COUNT; i++) {
|
||||
if (str_eq_ignore_case(target_os_names[i], str)) {
|
||||
return cast(TargetOsKind)i;
|
||||
}
|
||||
}
|
||||
return TargetOs_Invalid;
|
||||
}
|
||||
|
||||
TargetArchKind get_target_arch_from_string(String str) {
|
||||
for (isize i = 0; i < TargetArch_COUNT; i++) {
|
||||
if (str_eq_ignore_case(target_arch_names[i], str)) {
|
||||
return cast(TargetArchKind)i;
|
||||
}
|
||||
}
|
||||
return TargetArch_Invalid;
|
||||
}
|
||||
|
||||
|
||||
bool is_excluded_target_filename(String name) {
|
||||
String const ext = str_lit(".odin");
|
||||
String original_name = name;
|
||||
GB_ASSERT(string_ends_with(name, ext));
|
||||
name = substring(name, 0, name.len-ext.len);
|
||||
|
||||
String str1 = {};
|
||||
String str2 = {};
|
||||
isize n = 0;
|
||||
|
||||
str1 = name;
|
||||
n = str1.len;
|
||||
for (isize i = str1.len-1; i >= 0 && str1[i] != '_'; i--) {
|
||||
n -= 1;
|
||||
}
|
||||
str1 = substring(str1, n, str1.len);
|
||||
|
||||
str2 = substring(name, 0, gb_max(n-1, 0));
|
||||
n = str2.len;
|
||||
for (isize i = str2.len-1; i >= 0 && str2[i] != '_'; i--) {
|
||||
n -= 1;
|
||||
}
|
||||
str2 = substring(str2, n, str2.len);
|
||||
|
||||
if (str1 == name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TargetOsKind os1 = get_target_os_from_string(str1);
|
||||
TargetArchKind arch1 = get_target_arch_from_string(str1);
|
||||
TargetOsKind os2 = get_target_os_from_string(str2);
|
||||
TargetArchKind arch2 = get_target_arch_from_string(str2);
|
||||
|
||||
if (os1 != TargetOs_Invalid && arch2 != TargetArch_Invalid) {
|
||||
return os1 != build_context.metrics.os || arch2 != build_context.metrics.arch;
|
||||
} else if (arch1 != TargetArch_Invalid && os2 != TargetOs_Invalid) {
|
||||
return arch1 != build_context.metrics.arch || os2 != build_context.metrics.os;
|
||||
} else if (os1 != TargetOs_Invalid) {
|
||||
return os1 != build_context.metrics.os;
|
||||
} else if (arch1 != TargetArch_Invalid) {
|
||||
return arch1 != build_context.metrics.arch;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
struct LibraryCollections {
|
||||
String name;
|
||||
String path;
|
||||
@@ -70,7 +236,6 @@ String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
String odin_root_dir(void) {
|
||||
String path = global_module_path;
|
||||
Array<wchar_t> path_buf;
|
||||
isize len, i;
|
||||
gbTempArenaMemory tmp;
|
||||
wchar_t *text;
|
||||
@@ -79,7 +244,7 @@ String odin_root_dir(void) {
|
||||
return global_module_path;
|
||||
}
|
||||
|
||||
array_init_count(&path_buf, heap_allocator(), 300);
|
||||
auto path_buf = array_make<wchar_t>(heap_allocator(), 300);
|
||||
|
||||
len = 0;
|
||||
for (;;) {
|
||||
@@ -128,7 +293,6 @@ String odin_root_dir(void) {
|
||||
|
||||
String odin_root_dir(void) {
|
||||
String path = global_module_path;
|
||||
Array<char> path_buf;
|
||||
isize len, i;
|
||||
gbTempArenaMemory tmp;
|
||||
u8 *text;
|
||||
@@ -137,7 +301,7 @@ String odin_root_dir(void) {
|
||||
return global_module_path;
|
||||
}
|
||||
|
||||
array_init_count(&path_buf, heap_allocator(), 300);
|
||||
auto path_buf = array_make<char>(heap_allocator(), 300);
|
||||
|
||||
len = 0;
|
||||
for (;;) {
|
||||
@@ -184,7 +348,6 @@ String odin_root_dir(void) {
|
||||
|
||||
String odin_root_dir(void) {
|
||||
String path = global_module_path;
|
||||
Array<char> path_buf;
|
||||
isize len, i;
|
||||
gbTempArenaMemory tmp;
|
||||
u8 *text;
|
||||
@@ -193,7 +356,7 @@ String odin_root_dir(void) {
|
||||
return global_module_path;
|
||||
}
|
||||
|
||||
array_init_count(&path_buf, heap_allocator(), 300);
|
||||
auto path_buf = array_make<char>(heap_allocator(), 300);
|
||||
defer (array_free(&path_buf));
|
||||
|
||||
len = 0;
|
||||
@@ -246,6 +409,7 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
defer (gb_mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
String16 string16 = string_to_string16(string_buffer_allocator, s);
|
||||
|
||||
DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
|
||||
@@ -254,8 +418,9 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
GetFullPathNameW(&string16[0], len, text, nullptr);
|
||||
text[len] = 0;
|
||||
result = string16_to_string(a, make_string16(text, len));
|
||||
result = string_trim_whitespace(result);
|
||||
}
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
|
||||
return result;
|
||||
}
|
||||
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||
@@ -309,9 +474,6 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
}
|
||||
|
||||
|
||||
String const ODIN_VERSION = str_lit("0.8.1");
|
||||
String cross_compile_target = str_lit("");
|
||||
String cross_compile_lib_dir = str_lit("");
|
||||
|
||||
void init_build_context(void) {
|
||||
BuildContext *bc = &build_context;
|
||||
@@ -325,95 +487,98 @@ void init_build_context(void) {
|
||||
bc->ODIN_VERSION = ODIN_VERSION;
|
||||
bc->ODIN_ROOT = odin_root_dir();
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
bc->ODIN_OS = str_lit("windows");
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
bc->ODIN_OS = str_lit("osx");
|
||||
#else
|
||||
bc->ODIN_OS = str_lit("linux");
|
||||
#endif
|
||||
TargetMetrics metrics = {};
|
||||
|
||||
#if defined(GB_ARCH_64_BIT)
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
metrics = target_windows_amd64;
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
metrics = target_osx_amd64;
|
||||
#else
|
||||
metrics = target_linux_amd64;
|
||||
#endif
|
||||
#else
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
metrics = target_windows_386;
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
#error "Unsupported architecture"
|
||||
#else
|
||||
metrics = target_linux_386;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (cross_compile_target.len) {
|
||||
bc->ODIN_OS = cross_compile_target;
|
||||
}
|
||||
|
||||
#if defined(GB_ARCH_64_BIT)
|
||||
bc->ODIN_ARCH = str_lit("amd64");
|
||||
#else
|
||||
bc->ODIN_ARCH = str_lit("x86");
|
||||
#endif
|
||||
GB_ASSERT(metrics.os != TargetOs_Invalid);
|
||||
GB_ASSERT(metrics.arch != TargetArch_Invalid);
|
||||
GB_ASSERT(metrics.word_size > 1);
|
||||
GB_ASSERT(metrics.max_align > 1);
|
||||
|
||||
{
|
||||
u16 x = 1;
|
||||
bool big = !(*cast(u8 *)&x);
|
||||
bc->ODIN_ENDIAN = big ? str_lit("big") : str_lit("little");
|
||||
|
||||
bc->metrics = metrics;
|
||||
bc->ODIN_OS = target_os_names[metrics.os];
|
||||
bc->ODIN_ARCH = target_arch_names[metrics.arch];
|
||||
bc->ODIN_ENDIAN = target_arch_endian[metrics.arch];
|
||||
bc->word_size = metrics.word_size;
|
||||
bc->max_align = metrics.max_align;
|
||||
bc->link_flags = str_lit(" ");
|
||||
bc->opt_flags = str_lit(" ");
|
||||
|
||||
|
||||
gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64);
|
||||
if (bc->ODIN_DEBUG) {
|
||||
// llc_flags = gb_string_appendc(llc_flags, "-debug-compile ");
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zangent): The linker flags to set the build architecture are different
|
||||
// across OSs. It doesn't make sense to allocate extra data on the heap
|
||||
// here, so I just #defined the linker flags to keep things concise.
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#define LINK_FLAG_X64 "/machine:x64"
|
||||
#define LINK_FLAG_X86 "/machine:x86"
|
||||
if (bc->metrics.arch == TargetArch_amd64) {
|
||||
llc_flags = gb_string_appendc(llc_flags, "-march=x86-64 ");
|
||||
|
||||
#elif defined(GB_SYSTEM_OSX)
|
||||
// NOTE(zangent): MacOS systems are x64 only, so ld doesn't have
|
||||
// an architecture option. All compilation done on MacOS must be x64.
|
||||
GB_ASSERT(bc->ODIN_ARCH == "amd64");
|
||||
|
||||
#define LINK_FLAG_X64 ""
|
||||
#define LINK_FLAG_X86 ""
|
||||
#else
|
||||
// Linux, but also BSDs and the like.
|
||||
// NOTE(zangent): When clang is swapped out with ld as the linker,
|
||||
// the commented flags here should be used. Until then, we'll have
|
||||
// to use alternative build flags made for clang.
|
||||
/*
|
||||
#define LINK_FLAG_X64 "-m elf_x86_64"
|
||||
#define LINK_FLAG_X86 "-m elf_i386"
|
||||
*/
|
||||
#define LINK_FLAG_X64 "-arch x86-64"
|
||||
#define LINK_FLAG_X86 "-arch x86"
|
||||
#endif
|
||||
|
||||
|
||||
if (bc->ODIN_ARCH == "amd64") {
|
||||
bc->word_size = 8;
|
||||
bc->max_align = 16;
|
||||
|
||||
bc->llc_flags = str_lit("-march=x86-64 ");
|
||||
if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) {
|
||||
bc->link_flags = str_lit(" ");
|
||||
} else {
|
||||
bc->link_flags = str_lit(LINK_FLAG_X64 " ");
|
||||
switch (bc->metrics.os) {
|
||||
case TargetOs_windows:
|
||||
bc->link_flags = str_lit("/machine:x64 ");
|
||||
break;
|
||||
case TargetOs_osx:
|
||||
break;
|
||||
case TargetOs_linux:
|
||||
bc->link_flags = str_lit("-arch x86-64 ");
|
||||
break;
|
||||
}
|
||||
} else if (bc->metrics.arch == TargetArch_386) {
|
||||
llc_flags = gb_string_appendc(llc_flags, "-march=x86 ");
|
||||
|
||||
switch (bc->metrics.os) {
|
||||
case TargetOs_windows:
|
||||
bc->link_flags = str_lit("/machine:x86 ");
|
||||
break;
|
||||
case TargetOs_osx:
|
||||
gb_printf_err("Unsupported architecture\n");
|
||||
gb_exit(1);
|
||||
break;
|
||||
case TargetOs_linux:
|
||||
bc->link_flags = str_lit("-arch x86 ");
|
||||
break;
|
||||
}
|
||||
} else if (bc->ODIN_ARCH == "x86") {
|
||||
bc->word_size = 4;
|
||||
bc->max_align = 8;
|
||||
bc->llc_flags = str_lit("-march=x86 ");
|
||||
bc->link_flags = str_lit(LINK_FLAG_X86 " ");
|
||||
} else {
|
||||
gb_printf_err("This current architecture is not supported");
|
||||
gb_printf_err("Unsupported architecture\n");;
|
||||
gb_exit(1);
|
||||
}
|
||||
|
||||
bc->llc_flags = make_string_c(llc_flags);
|
||||
|
||||
isize opt_max = 1023;
|
||||
char *opt_flags_string = gb_alloc_array(heap_allocator(), char, opt_max+1);
|
||||
isize opt_len = 0;
|
||||
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
|
||||
|
||||
gbString opt_flags = gb_string_make_reserve(heap_allocator(), 16);
|
||||
if (bc->optimization_level != 0) {
|
||||
opt_len = gb_snprintf(opt_flags_string, opt_max, "-O%d", bc->optimization_level);
|
||||
} else {
|
||||
opt_len = gb_snprintf(opt_flags_string, opt_max, "");
|
||||
opt_flags = gb_string_append_fmt(opt_flags, "-O%d", bc->optimization_level);
|
||||
}
|
||||
if (opt_len > 0) {
|
||||
opt_len--;
|
||||
}
|
||||
bc->opt_flags = make_string(cast(u8 *)opt_flags_string, opt_len);
|
||||
bc->opt_flags = make_string_c(opt_flags);
|
||||
|
||||
|
||||
#undef LINK_FLAG_X64
|
||||
#undef LINK_FLAG_X86
|
||||
#undef LINK_FLAG_386
|
||||
}
|
||||
|
||||
+216
-195
@@ -1,8 +1,8 @@
|
||||
bool check_is_terminating(AstNode *node);
|
||||
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
||||
bool check_is_terminating(Ast *node);
|
||||
void check_stmt (CheckerContext *ctx, Ast *node, u32 flags);
|
||||
|
||||
// NOTE(bill): 'content_name' is for debugging and error messages
|
||||
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
|
||||
Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, String context_name) {
|
||||
if (operand->mode == Addressing_Invalid ||
|
||||
operand->type == t_invalid ||
|
||||
e->type == t_invalid) {
|
||||
@@ -27,7 +27,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
if (e->type == nullptr) {
|
||||
error(operand->expr, "Cannot determine type from overloaded procedure '%.*s'", LIT(operand->proc_group->token.string));
|
||||
} else {
|
||||
check_assignment(c, operand, e->type, str_lit("variable assignment"));
|
||||
check_assignment(ctx, operand, e->type, str_lit("variable assignment"));
|
||||
if (operand->mode != Addressing_Type) {
|
||||
return operand->type;
|
||||
}
|
||||
@@ -79,9 +79,9 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
e->type = t;
|
||||
}
|
||||
|
||||
e->parent_proc_decl = c->context.curr_proc_decl;
|
||||
e->parent_proc_decl = ctx->curr_proc_decl;
|
||||
|
||||
check_assignment(c, operand, e->type, context_name);
|
||||
check_assignment(ctx, operand, e->type, context_name);
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -89,20 +89,17 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
return e->type;
|
||||
}
|
||||
|
||||
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNode *> inits, String context_name) {
|
||||
void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array<Ast *> const &inits, String context_name) {
|
||||
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
Array<Operand> operands = {};
|
||||
array_init(&operands, c->tmp_allocator, 2*lhs_count);
|
||||
check_unpack_arguments(c, lhs, lhs_count, &operands, inits, true);
|
||||
auto operands = array_make<Operand>(ctx->allocator, 0, 2*lhs_count);
|
||||
defer (array_free(&operands));
|
||||
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true);
|
||||
|
||||
isize rhs_count = operands.count;
|
||||
for_array(i, operands) {
|
||||
@@ -114,9 +111,9 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
|
||||
isize max = gb_min(lhs_count, rhs_count);
|
||||
for (isize i = 0; i < max; i++) {
|
||||
Entity *e = lhs[i];
|
||||
DeclInfo *d = decl_info_of_entity(&c->info, e);
|
||||
DeclInfo *d = decl_info_of_entity(e);
|
||||
Operand *o = &operands[i];
|
||||
check_init_variable(c, e, o, context_name);
|
||||
check_init_variable(ctx, e, o, context_name);
|
||||
if (d != nullptr) {
|
||||
d->init_expr = o->expr;
|
||||
}
|
||||
@@ -126,7 +123,7 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, Array<AstNo
|
||||
}
|
||||
}
|
||||
|
||||
void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||
void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
|
||||
if (operand->mode == Addressing_Invalid ||
|
||||
operand->type == t_invalid ||
|
||||
e->type == t_invalid) {
|
||||
@@ -160,25 +157,25 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
|
||||
e->type = operand->type;
|
||||
}
|
||||
|
||||
check_assignment(c, operand, e->type, str_lit("constant declaration"));
|
||||
check_assignment(ctx, operand, e->type, str_lit("constant declaration"));
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
e->parent_proc_decl = c->context.curr_proc_decl;
|
||||
e->parent_proc_decl = ctx->curr_proc_decl;
|
||||
|
||||
e->Constant.value = operand->value;
|
||||
}
|
||||
|
||||
|
||||
bool is_type_distinct(AstNode *node) {
|
||||
bool is_type_distinct(Ast *node) {
|
||||
for (;;) {
|
||||
if (node == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (node->kind == AstNode_ParenExpr) {
|
||||
if (node->kind == Ast_ParenExpr) {
|
||||
node = node->ParenExpr.expr;
|
||||
} else if (node->kind == AstNode_HelperType) {
|
||||
} else if (node->kind == Ast_HelperType) {
|
||||
node = node->HelperType.type;
|
||||
} else {
|
||||
break;
|
||||
@@ -186,33 +183,33 @@ bool is_type_distinct(AstNode *node) {
|
||||
}
|
||||
|
||||
switch (node->kind) {
|
||||
case AstNode_DistinctType:
|
||||
case Ast_DistinctType:
|
||||
return true;
|
||||
|
||||
case AstNode_StructType:
|
||||
case AstNode_UnionType:
|
||||
case AstNode_EnumType:
|
||||
case AstNode_BitFieldType:
|
||||
case AstNode_ProcType:
|
||||
case Ast_StructType:
|
||||
case Ast_UnionType:
|
||||
case Ast_EnumType:
|
||||
case Ast_BitFieldType:
|
||||
case Ast_ProcType:
|
||||
return true;
|
||||
|
||||
case AstNode_PointerType:
|
||||
case AstNode_ArrayType:
|
||||
case AstNode_DynamicArrayType:
|
||||
case AstNode_MapType:
|
||||
return true;
|
||||
case Ast_PointerType:
|
||||
case Ast_ArrayType:
|
||||
case Ast_DynamicArrayType:
|
||||
case Ast_MapType:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
AstNode *remove_type_alias_clutter(AstNode *node) {
|
||||
Ast *remove_type_alias_clutter(Ast *node) {
|
||||
for (;;) {
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (node->kind == AstNode_ParenExpr) {
|
||||
if (node->kind == Ast_ParenExpr) {
|
||||
node = node->ParenExpr.expr;
|
||||
} else if (node->kind == AstNode_DistinctType) {
|
||||
} else if (node->kind == Ast_DistinctType) {
|
||||
node = node->DistinctType.type;
|
||||
} else {
|
||||
return node;
|
||||
@@ -220,44 +217,80 @@ AstNode *remove_type_alias_clutter(AstNode *node) {
|
||||
}
|
||||
}
|
||||
|
||||
void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) {
|
||||
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
if (decl != nullptr && decl->attributes.count > 0) {
|
||||
error(decl->attributes[0], "Attributes are not allowed on type declarations");
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool is_distinct = is_type_distinct(type_expr);
|
||||
AstNode *te = remove_type_alias_clutter(type_expr);
|
||||
Ast *te = remove_type_alias_clutter(type_expr);
|
||||
e->type = t_invalid;
|
||||
String name = e->token.string;
|
||||
Type *named = make_type_named(c->allocator, name, nullptr, e);
|
||||
Type *named = alloc_type_named(name, nullptr, e);
|
||||
named->Named.type_name = e;
|
||||
if (def != nullptr && def->kind == Type_Named) {
|
||||
def->Named.base = named;
|
||||
}
|
||||
e->type = named;
|
||||
|
||||
Type *bt = check_type(c, te, named);
|
||||
check_type_path_push(ctx, e);
|
||||
Type *bt = check_type_expr(ctx, te, named);
|
||||
check_type_path_pop(ctx);
|
||||
|
||||
named->Named.base = base_type(bt);
|
||||
if (!is_distinct) {
|
||||
e->type = bt;
|
||||
named->Named.base = bt;
|
||||
e->TypeName.is_type_alias = true;
|
||||
}
|
||||
// if (is_alias) {
|
||||
// if (is_type_named(bt)) {
|
||||
// e->type = bt;
|
||||
// e->TypeName.is_type_alias = true;
|
||||
// } else {
|
||||
// gbString str = type_to_string(bt);
|
||||
// error(type_expr, "Type alias declaration with a non-named type '%s'", str);
|
||||
// gb_string_free(str);
|
||||
// }
|
||||
// }
|
||||
|
||||
// using decl
|
||||
if (decl->is_using) {
|
||||
// NOTE(bill): Must be an enum declaration
|
||||
if (te->kind == Ast_EnumType) {
|
||||
Scope *parent = e->scope;
|
||||
if (parent->flags&ScopeFlag_File) {
|
||||
// NOTE(bill): Use package scope
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
Type *t = base_type(e->type);
|
||||
if (t->kind == Type_Enum) {
|
||||
for_array(i, t->Enum.fields) {
|
||||
Entity *f = t->Enum.fields[i];
|
||||
if (f->kind != Entity_Constant) {
|
||||
continue;
|
||||
}
|
||||
String name = f->token.string;
|
||||
if (is_blank_ident(name)) {
|
||||
continue;
|
||||
}
|
||||
add_entity(ctx->checker, parent, nullptr, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, Type *named_type) {
|
||||
|
||||
void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
|
||||
// NOTE(bill): The original_entity's scope may not be same scope that it was inserted into
|
||||
// e.g. file entity inserted into its package scope
|
||||
String original_name = original_entity->token.string;
|
||||
Scope *found_scope = nullptr;
|
||||
Entity *found_entity = nullptr;
|
||||
scope_lookup_parent(original_entity->scope, original_name, &found_scope, &found_entity);
|
||||
GB_ASSERT(found_entity == original_entity);
|
||||
|
||||
map_set(&found_scope->elements, hash_string(original_name), new_entity);
|
||||
}
|
||||
|
||||
void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Constant);
|
||||
|
||||
@@ -268,7 +301,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
e->flags |= EntityFlag_Visited;
|
||||
|
||||
if (type_expr) {
|
||||
Type *t = check_type(c, type_expr);
|
||||
Type *t = check_type(ctx, type_expr);
|
||||
if (!is_type_constant_type(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
error(type_expr, "Invalid constant type '%s'", str);
|
||||
@@ -283,12 +316,12 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
|
||||
if (init != nullptr) {
|
||||
Entity *entity = nullptr;
|
||||
if (init->kind == AstNode_Ident) {
|
||||
entity = check_ident(c, &operand, init, nullptr, e->type, true);
|
||||
} else if (init->kind == AstNode_SelectorExpr) {
|
||||
entity = check_selector(c, &operand, init, e->type);
|
||||
if (init->kind == Ast_Ident) {
|
||||
entity = check_ident(ctx, &operand, init, nullptr, e->type, true);
|
||||
} else if (init->kind == Ast_SelectorExpr) {
|
||||
entity = check_selector(ctx, &operand, init, e->type);
|
||||
} else {
|
||||
check_expr_or_type(c, &operand, init, e->type);
|
||||
check_expr_or_type(ctx, &operand, init, e->type);
|
||||
}
|
||||
|
||||
switch (operand.mode) {
|
||||
@@ -296,12 +329,12 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
e->kind = Entity_TypeName;
|
||||
e->type = nullptr;
|
||||
|
||||
DeclInfo *d = c->context.decl;
|
||||
DeclInfo *d = ctx->decl;
|
||||
if (d->type_expr != nullptr) {
|
||||
error(e->token, "A type declaration cannot have an type parameter");
|
||||
}
|
||||
d->type_expr = d->init_expr;
|
||||
check_type_decl(c, e, d->type_expr, named_type);
|
||||
check_type_decl(ctx, e, d->type_expr, named_type);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -318,49 +351,25 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
case Addressing_ProcGroup:
|
||||
GB_ASSERT(operand.proc_group != nullptr);
|
||||
GB_ASSERT(operand.proc_group->kind == Entity_ProcGroup);
|
||||
|
||||
e->kind = Entity_ProcGroup;
|
||||
e->type = t_invalid;
|
||||
gb_memmove(&e->ProcGroup, &operand.proc_group->ProcGroup, gb_size_of(e->ProcGroup));
|
||||
override_entity_in_scope(e, operand.proc_group);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity != nullptr) {
|
||||
|
||||
// NOTE(bill): Override aliased entity
|
||||
switch (entity->kind) {
|
||||
case Entity_Alias:
|
||||
e->kind = Entity_Alias;
|
||||
e->type = entity->type;
|
||||
e->Alias.base = entity->Alias.base;
|
||||
return;
|
||||
case Entity_ProcGroup:
|
||||
case Entity_Procedure:
|
||||
e->kind = Entity_Alias;
|
||||
e->type = entity->type;
|
||||
e->Alias.base = entity;
|
||||
return;
|
||||
case Entity_ImportName:
|
||||
e->kind = Entity_ImportName;
|
||||
e->type = entity->type;
|
||||
e->ImportName.path = entity->ImportName.path;
|
||||
e->ImportName.name = entity->ImportName.path;
|
||||
e->ImportName.scope = entity->ImportName.scope;
|
||||
e->ImportName.used = false;
|
||||
return;
|
||||
case Entity_LibraryName:
|
||||
e->kind = Entity_LibraryName;
|
||||
e->type = entity->type;
|
||||
e->LibraryName.path = entity->LibraryName.path;
|
||||
e->LibraryName.name = entity->LibraryName.path;
|
||||
e->LibraryName.used = false;
|
||||
case Entity_ImportName:
|
||||
override_entity_in_scope(e, entity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (init != nullptr) {
|
||||
check_expr_or_type(c, &operand, init, e->type);
|
||||
}
|
||||
|
||||
check_init_constant(c, e, &operand);
|
||||
check_init_constant(ctx, e, &operand);
|
||||
|
||||
if (operand.mode == Addressing_Invalid ||
|
||||
base_type(operand.type) == t_invalid) {
|
||||
@@ -370,7 +379,7 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
|
||||
}
|
||||
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
if (decl != nullptr && decl->attributes.count > 0) {
|
||||
error(decl->attributes[0], "Attributes are not allowed on constant value declarations");
|
||||
}
|
||||
@@ -400,8 +409,8 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
if (is_type_integer(x) && is_type_integer(y)) {
|
||||
GB_ASSERT(x->kind == Type_Basic);
|
||||
GB_ASSERT(y->kind == Type_Basic);
|
||||
i64 sx = type_size_of(heap_allocator(), x);
|
||||
i64 sy = type_size_of(heap_allocator(), y);
|
||||
i64 sx = type_size_of(x);
|
||||
i64 sy = type_size_of(y);
|
||||
if (sx == sy) continue;
|
||||
}
|
||||
|
||||
@@ -417,8 +426,8 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
if (is_type_integer(x) && is_type_integer(y)) {
|
||||
GB_ASSERT(x->kind == Type_Basic);
|
||||
GB_ASSERT(y->kind == Type_Basic);
|
||||
i64 sx = type_size_of(heap_allocator(), x);
|
||||
i64 sy = type_size_of(heap_allocator(), y);
|
||||
i64 sx = type_size_of(x);
|
||||
i64 sy = type_size_of(y);
|
||||
if (sx == sy) continue;
|
||||
}
|
||||
|
||||
@@ -430,8 +439,8 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void init_entity_foreign_library(Checker *c, Entity *e) {
|
||||
AstNode *ident = nullptr;
|
||||
void init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
|
||||
Ast *ident = nullptr;
|
||||
Entity **foreign_library = nullptr;
|
||||
|
||||
switch (e->kind) {
|
||||
@@ -449,14 +458,14 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
|
||||
|
||||
if (ident == nullptr) {
|
||||
error(e->token, "foreign entiies must declare which library they are from");
|
||||
} else if (ident->kind != AstNode_Ident) {
|
||||
} else if (ident->kind != Ast_Ident) {
|
||||
error(ident, "foreign library names must be an identifier");
|
||||
} else {
|
||||
String name = ident->Ident.token.string;
|
||||
Entity *found = scope_lookup_entity(c->context.scope, name);
|
||||
Entity *found = scope_lookup(ctx->scope, name);
|
||||
if (found == nullptr) {
|
||||
if (is_blank_ident(name)) {
|
||||
error(ident, "'_' cannot be used as a value type");
|
||||
// NOTE(bill): link against nothing
|
||||
} else {
|
||||
error(ident, "Undeclared name: %.*s", LIT(name));
|
||||
}
|
||||
@@ -465,19 +474,19 @@ void init_entity_foreign_library(Checker *c, Entity *e) {
|
||||
} else {
|
||||
// TODO(bill): Extra stuff to do with library names?
|
||||
*foreign_library = found;
|
||||
found->LibraryName.used = true;
|
||||
add_entity_use(c, ident, found);
|
||||
found->flags |= EntityFlag_Used;
|
||||
add_entity_use(ctx, ident, found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String handle_link_name(Checker *c, Token token, String link_name, String link_prefix) {
|
||||
String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) {
|
||||
if (link_prefix.len > 0) {
|
||||
if (link_name.len > 0) {
|
||||
error(token, "'link_name' and 'link_prefix' cannot be used together");
|
||||
} else {
|
||||
isize len = link_prefix.len + token.string.len;
|
||||
u8 *name = gb_alloc_array(c->allocator, u8, len+1);
|
||||
u8 *name = gb_alloc_array(ctx->allocator, u8, len+1);
|
||||
gb_memmove(name, &link_prefix[0], link_prefix.len);
|
||||
gb_memmove(name+link_prefix.len, &token.string[0], token.string.len);
|
||||
name[len] = 0;
|
||||
@@ -488,9 +497,9 @@ String handle_link_name(Checker *c, Token token, String link_name, String link_p
|
||||
return link_name;
|
||||
}
|
||||
|
||||
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
if (d->proc_lit->kind != AstNode_ProcLit) {
|
||||
if (d->proc_lit->kind != Ast_ProcLit) {
|
||||
// TOOD(bill): Better error message
|
||||
error(d->proc_lit, "Expected a procedure to check");
|
||||
return;
|
||||
@@ -500,19 +509,18 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
if (d->gen_proc_type != nullptr) {
|
||||
proc_type = d->gen_proc_type;
|
||||
} else {
|
||||
proc_type = make_type_proc(c->allocator, e->scope, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
|
||||
proc_type = alloc_type_proc(e->scope, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
|
||||
}
|
||||
e->type = proc_type;
|
||||
ast_node(pl, ProcLit, d->proc_lit);
|
||||
|
||||
check_open_scope(c, pl->type);
|
||||
defer (check_close_scope(c));
|
||||
check_open_scope(ctx, pl->type);
|
||||
defer (check_close_scope(ctx));
|
||||
|
||||
|
||||
auto prev_context = c->context;
|
||||
c->context.allow_polymorphic_types = true;
|
||||
check_procedure_type(c, proc_type, pl->type);
|
||||
c->context = prev_context;
|
||||
auto tmp_ctx = *ctx;
|
||||
tmp_ctx.allow_polymorphic_types = true;
|
||||
check_procedure_type(&tmp_ctx, proc_type, pl->type);
|
||||
|
||||
TypeProc *pt = &proc_type->Proc;
|
||||
|
||||
@@ -523,13 +531,13 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
AttributeContext ac = make_attribute_context(e->Procedure.link_prefix);
|
||||
|
||||
if (d != nullptr) {
|
||||
check_decl_attributes(c, d->attributes, proc_decl_attribute, &ac);
|
||||
check_decl_attributes(ctx, d->attributes, proc_decl_attribute, &ac);
|
||||
}
|
||||
|
||||
e->deprecated_message = ac.deprecated_message;
|
||||
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
||||
|
||||
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
|
||||
|
||||
if (d->scope->file != nullptr && e->token.string == "main") {
|
||||
if (e->pkg != nullptr && e->token.string == "main") {
|
||||
if (pt->param_count != 0 ||
|
||||
pt->result_count != 0) {
|
||||
gbString str = type_to_string(proc_type);
|
||||
@@ -541,11 +549,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
error(e->token, "Procedure 'main' cannot have a custom calling convention");
|
||||
}
|
||||
pt->calling_convention = ProcCC_Contextless;
|
||||
if (d->scope->is_init) {
|
||||
if (c->info.entry_point != nullptr) {
|
||||
if (e->pkg->kind == Package_Init) {
|
||||
if (ctx->info->entry_point != nullptr) {
|
||||
error(e->token, "Redeclaration of the entry pointer procedure 'main'");
|
||||
} else {
|
||||
c->info.entry_point = e;
|
||||
ctx->info->entry_point = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,11 +581,11 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
error(pl->body, "A procedure with a '#c_vararg' field cannot have a body and must be foreign");
|
||||
}
|
||||
|
||||
d->scope = c->context.scope;
|
||||
d->scope = ctx->scope;
|
||||
|
||||
GB_ASSERT(pl->body->kind == AstNode_BlockStmt);
|
||||
GB_ASSERT(pl->body->kind == Ast_BlockStmt);
|
||||
if (!pt->is_polymorphic) {
|
||||
check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pl->body, pl->tags);
|
||||
check_procedure_later(ctx->checker, ctx->file, e->token, d, proc_type, pl->body, pl->tags);
|
||||
}
|
||||
} else if (!is_foreign) {
|
||||
if (e->Procedure.is_export) {
|
||||
@@ -605,9 +613,9 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
e->Procedure.is_foreign = true;
|
||||
e->Procedure.link_name = name;
|
||||
|
||||
init_entity_foreign_library(c, e);
|
||||
init_entity_foreign_library(ctx, e);
|
||||
|
||||
auto *fp = &c->info.foreigns;
|
||||
auto *fp = &ctx->info->foreigns;
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_get(fp, key);
|
||||
if (found) {
|
||||
@@ -639,7 +647,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
name = e->Procedure.link_name;
|
||||
}
|
||||
if (e->Procedure.link_name.len > 0 || is_export) {
|
||||
auto *fp = &c->info.foreigns;
|
||||
auto *fp = &ctx->info->foreigns;
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_get(fp, key);
|
||||
if (found) {
|
||||
@@ -659,7 +667,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
}
|
||||
|
||||
void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, Array<AstNode *> init_expr_list) {
|
||||
void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
@@ -670,20 +678,20 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
e->flags |= EntityFlag_Visited;
|
||||
|
||||
AttributeContext ac = make_attribute_context(e->Variable.link_prefix);
|
||||
ac.init_expr_list_count = init_expr_list.count;
|
||||
ac.init_expr_list_count = init_expr != nullptr ? 1 : 0;
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(&c->info, e);
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
if (decl != nullptr) {
|
||||
check_decl_attributes(c, decl->attributes, var_decl_attribute, &ac);
|
||||
check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac);
|
||||
}
|
||||
|
||||
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
|
||||
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
||||
e->Variable.thread_local_model = ac.thread_local_model;
|
||||
|
||||
String context_name = str_lit("variable declaration");
|
||||
|
||||
if (type_expr != nullptr) {
|
||||
e->type = check_type(c, type_expr);
|
||||
e->type = check_type(ctx, type_expr);
|
||||
}
|
||||
if (e->type != nullptr) {
|
||||
if (is_type_polymorphic(base_type(e->type))) {
|
||||
@@ -701,10 +709,10 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
|
||||
|
||||
if (e->Variable.is_foreign) {
|
||||
if (init_expr_list.count > 0) {
|
||||
if (init_expr != nullptr) {
|
||||
error(e->token, "A foreign variable declaration cannot have a default value");
|
||||
}
|
||||
init_entity_foreign_library(c, e);
|
||||
init_entity_foreign_library(ctx, e);
|
||||
}
|
||||
if (ac.link_name.len > 0) {
|
||||
e->Variable.link_name = ac.link_name;
|
||||
@@ -715,7 +723,8 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
if (e->Variable.link_name.len > 0) {
|
||||
name = e->Variable.link_name;
|
||||
}
|
||||
auto *fp = &c->info.foreigns;
|
||||
|
||||
auto *fp = &ctx->info->foreigns;
|
||||
HashKey key = hash_string(name);
|
||||
Entity **found = map_get(fp, key);
|
||||
if (found) {
|
||||
@@ -734,50 +743,45 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
}
|
||||
}
|
||||
|
||||
if (init_expr_list.count == 0) {
|
||||
if (init_expr == nullptr) {
|
||||
if (type_expr == nullptr) {
|
||||
e->type = t_invalid;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (type_expr != nullptr) {
|
||||
for (isize i = 0; i < entity_count; i++) {
|
||||
entities[i]->type = e->type;
|
||||
}
|
||||
}
|
||||
|
||||
check_init_variables(c, entities, entity_count, init_expr_list, context_name);
|
||||
Operand o = {};
|
||||
check_expr(ctx, &o, init_expr);
|
||||
check_init_variable(ctx, e, &o, str_lit("variable declaration"));
|
||||
}
|
||||
|
||||
void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
|
||||
void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d) {
|
||||
GB_ASSERT(pg_entity->kind == Entity_ProcGroup);
|
||||
auto *pge = &pg_entity->ProcGroup;
|
||||
String proc_group_name = pg_entity->token.string;
|
||||
|
||||
ast_node(pg, ProcGroup, d->init_expr);
|
||||
|
||||
array_init(&pge->entities, c->allocator, pg->args.count);
|
||||
pge->entities = array_make<Entity*>(ctx->allocator, 0, pg->args.count);
|
||||
|
||||
// NOTE(bill): This must be set here to prevent cycles in checking if someone
|
||||
// places the entity within itself
|
||||
pg_entity->type = t_invalid;
|
||||
|
||||
PtrSet<Entity *> entity_map = {};
|
||||
ptr_set_init(&entity_map, heap_allocator());
|
||||
defer (ptr_set_destroy(&entity_map));
|
||||
PtrSet<Entity *> entity_set = {};
|
||||
ptr_set_init(&entity_set, heap_allocator(), 2*pg->args.count);
|
||||
|
||||
for_array(i, pg->args) {
|
||||
AstNode *arg = pg->args[i];
|
||||
Ast *arg = pg->args[i];
|
||||
Entity *e = nullptr;
|
||||
Operand o = {};
|
||||
if (arg->kind == AstNode_Ident) {
|
||||
e = check_ident(c, &o, arg, nullptr, nullptr, true);
|
||||
} else if (arg->kind == AstNode_SelectorExpr) {
|
||||
e = check_selector(c, &o, arg, nullptr);
|
||||
if (arg->kind == Ast_Ident) {
|
||||
e = check_ident(ctx, &o, arg, nullptr, nullptr, true);
|
||||
} else if (arg->kind == Ast_SelectorExpr) {
|
||||
e = check_selector(ctx, &o, arg, nullptr);
|
||||
}
|
||||
if (e == nullptr) {
|
||||
error(arg, "Expected a valid entity name in procedure group, got %.*s", LIT(ast_node_strings[arg->kind]));
|
||||
error(arg, "Expected a valid entity name in procedure group, got %.*s", LIT(ast_strings[arg->kind]));
|
||||
continue;
|
||||
}
|
||||
if (e->kind == Entity_Variable) {
|
||||
@@ -792,14 +796,17 @@ void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ptr_set_exists(&entity_map, e)) {
|
||||
if (ptr_set_exists(&entity_set, e)) {
|
||||
error(arg, "Previous use of `%.*s` in procedure group", LIT(e->token.string));
|
||||
continue;
|
||||
}
|
||||
ptr_set_add(&entity_map, e);
|
||||
ptr_set_add(&entity_set, e);
|
||||
array_add(&pge->entities, e);
|
||||
}
|
||||
|
||||
ptr_set_destroy(&entity_set);
|
||||
|
||||
|
||||
for_array(j, pge->entities) {
|
||||
Entity *p = pge->entities[j];
|
||||
if (p->type == t_invalid) {
|
||||
@@ -862,14 +869,22 @@ void check_proc_group_decl(Checker *c, Entity *pg_entity, DeclInfo *d) {
|
||||
|
||||
}
|
||||
|
||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
if (e->type != nullptr) {
|
||||
void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
if (e->state == EntityState_Resolved) {
|
||||
return;
|
||||
}
|
||||
String name = e->token.string;
|
||||
|
||||
if (e->type != nullptr || e->state != EntityState_Unresolved) {
|
||||
error(e->token, "Illegal declaration cycle of `%.*s`", LIT(name));
|
||||
return;
|
||||
}
|
||||
|
||||
GB_ASSERT(e->state == EntityState_Unresolved);
|
||||
|
||||
#if 0
|
||||
char buf[256] = {};
|
||||
isize n = gb_snprintf(buf, 256, "%.*s %d", LIT(e->token.string), e->kind);
|
||||
isize n = gb_snprintf(buf, 256, "%.*s %d", LIT(name), e->kind);
|
||||
Timings timings = {};
|
||||
timings_init(&timings, make_string(cast(u8 *)buf, n-1), 16);
|
||||
defer ({
|
||||
@@ -882,53 +897,56 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
#endif
|
||||
|
||||
if (d == nullptr) {
|
||||
d = decl_info_of_entity(&c->info, e);
|
||||
d = decl_info_of_entity(e);
|
||||
if (d == nullptr) {
|
||||
// TODO(bill): Err here?
|
||||
e->type = t_invalid;
|
||||
e->state = EntityState_Resolved;
|
||||
set_base_type(named_type, t_invalid);
|
||||
return;
|
||||
// GB_PANIC("'%.*s' should been declared!", LIT(e->token.string));
|
||||
// GB_PANIC("'%.*s' should been declared!", LIT(name));
|
||||
}
|
||||
}
|
||||
|
||||
CheckerContext prev = c->context;
|
||||
c->context.scope = d->scope;
|
||||
c->context.decl = d;
|
||||
CheckerContext c = *ctx;
|
||||
c.scope = d->scope;
|
||||
c.decl = d;
|
||||
c.type_level = 0;
|
||||
|
||||
e->parent_proc_decl = c->context.curr_proc_decl;
|
||||
e->parent_proc_decl = c.curr_proc_decl;
|
||||
e->state = EntityState_InProgress;
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_Variable:
|
||||
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr_list);
|
||||
check_var_decl(&c, e, d->type_expr, d->init_expr);
|
||||
break;
|
||||
case Entity_Constant:
|
||||
check_const_decl(c, e, d->type_expr, d->init_expr, named_type);
|
||||
check_const_decl(&c, e, d->type_expr, d->init_expr, named_type);
|
||||
break;
|
||||
case Entity_TypeName: {
|
||||
check_type_decl(c, e, d->type_expr, named_type);
|
||||
check_type_decl(&c, e, d->type_expr, named_type);
|
||||
break;
|
||||
}
|
||||
case Entity_Procedure:
|
||||
check_proc_decl(c, e, d);
|
||||
check_proc_decl(&c, e, d);
|
||||
break;
|
||||
case Entity_ProcGroup:
|
||||
check_proc_group_decl(c, e, d);
|
||||
check_proc_group_decl(&c, e, d);
|
||||
break;
|
||||
}
|
||||
|
||||
c->context = prev;
|
||||
e->state = EntityState_Resolved;
|
||||
|
||||
#undef TIME_SECTION
|
||||
}
|
||||
|
||||
|
||||
|
||||
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||
void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
|
||||
if (body == nullptr) {
|
||||
return;
|
||||
}
|
||||
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
||||
GB_ASSERT(body->kind == Ast_BlockStmt);
|
||||
|
||||
String proc_name = {};
|
||||
if (token.kind == Token_Ident) {
|
||||
@@ -938,13 +956,14 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
proc_name = str_lit("(anonymous-procedure)");
|
||||
}
|
||||
|
||||
CheckerContext old_context = c->context;
|
||||
defer (c->context = old_context);
|
||||
CheckerContext new_ctx = *ctx_;
|
||||
CheckerContext *ctx = &new_ctx;
|
||||
|
||||
c->context.scope = decl->scope;
|
||||
c->context.decl = decl;
|
||||
c->context.proc_name = proc_name;
|
||||
c->context.curr_proc_decl = decl;
|
||||
ctx->scope = decl->scope;
|
||||
ctx->decl = decl;
|
||||
ctx->proc_name = proc_name;
|
||||
ctx->curr_proc_decl = decl;
|
||||
ctx->curr_proc_sig = type;
|
||||
|
||||
GB_ASSERT(type->kind == Type_Proc);
|
||||
if (type->Proc.param_count > 0) {
|
||||
@@ -964,17 +983,17 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
if (t->kind == Type_Struct) {
|
||||
Scope *scope = t->Struct.scope;
|
||||
if (scope == nullptr) {
|
||||
scope = scope_of_node(&c->info, t->Struct.node);
|
||||
scope = scope_of_node(t->Struct.node);
|
||||
}
|
||||
GB_ASSERT(scope != nullptr);
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type);
|
||||
uvar->Variable.is_immutable = is_immutable;
|
||||
if (is_value) uvar->flags |= EntityFlag_Value;
|
||||
|
||||
Entity *prev = scope_insert_entity(c->context.scope, uvar);
|
||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
error(e->token, "Namespace collision while 'using' '%.*s' of: %.*s", LIT(name), LIT(prev->token.string));
|
||||
break;
|
||||
@@ -988,23 +1007,20 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
}
|
||||
}
|
||||
|
||||
push_procedure(c, type);
|
||||
{
|
||||
ast_node(bs, BlockStmt, body);
|
||||
check_stmt_list(c, bs->stmts, Stmt_CheckScopeDecls);
|
||||
if (type->Proc.result_count > 0) {
|
||||
if (!check_is_terminating(body)) {
|
||||
if (token.kind == Token_Ident) {
|
||||
error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
|
||||
} else {
|
||||
error(bs->close, "Missing return statement at the end of the procedure");
|
||||
}
|
||||
ast_node(bs, BlockStmt, body);
|
||||
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
|
||||
if (type->Proc.result_count > 0) {
|
||||
if (!check_is_terminating(body)) {
|
||||
if (token.kind == Token_Ident) {
|
||||
error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string));
|
||||
} else {
|
||||
// NOTE(bill): Anonymous procedure (lambda)
|
||||
error(bs->close, "Missing return statement at the end of the procedure");
|
||||
}
|
||||
}
|
||||
}
|
||||
pop_procedure(c);
|
||||
|
||||
check_scope_usage(c, c->context.scope);
|
||||
check_scope_usage(ctx->checker, ctx->scope);
|
||||
|
||||
if (decl->parent != nullptr) {
|
||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||
@@ -1012,8 +1028,13 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
Entity *e = decl->deps.entries[i].ptr;
|
||||
ptr_set_add(&decl->parent->deps, e);
|
||||
}
|
||||
for_array(i, decl->type_info_deps.entries) {
|
||||
Type *t = decl->type_info_deps.entries[i].ptr;
|
||||
ptr_set_add(&decl->parent->type_info_deps, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+1388
-1280
File diff suppressed because it is too large
Load Diff
+446
-558
File diff suppressed because it is too large
Load Diff
+774
-723
File diff suppressed because it is too large
Load Diff
+1300
-1079
File diff suppressed because it is too large
Load Diff
+177
-183
@@ -5,44 +5,27 @@ struct Entity;
|
||||
struct Scope;
|
||||
struct DeclInfo;
|
||||
struct AstFile;
|
||||
struct Checker;
|
||||
struct CheckerInfo;
|
||||
struct CheckerContext;
|
||||
|
||||
enum AddressingMode {
|
||||
Addressing_Invalid, // invalid addressing mode
|
||||
Addressing_NoValue, // no value (void in C)
|
||||
Addressing_Value, // computed value (rvalue)
|
||||
Addressing_Immutable, // immutable computed value (const rvalue)
|
||||
Addressing_Variable, // addressable variable (lvalue)
|
||||
Addressing_Constant, // constant
|
||||
Addressing_Type, // type
|
||||
Addressing_Builtin, // built-in procedure
|
||||
Addressing_ProcGroup, // procedure group (overloaded procedure)
|
||||
Addressing_MapIndex, // map index expression -
|
||||
// lhs: acts like a Variable
|
||||
// rhs: acts like OptionalOk
|
||||
Addressing_OptionalOk, // rhs: acts like a value with an optional boolean part (for existence check)
|
||||
};
|
||||
|
||||
struct TypeAndValue {
|
||||
AddressingMode mode;
|
||||
Type * type;
|
||||
ExactValue value;
|
||||
};
|
||||
|
||||
enum AddressingMode;
|
||||
struct TypeAndValue;
|
||||
|
||||
// ExprInfo stores information used for "untyped" expressions
|
||||
struct ExprInfo {
|
||||
AddressingMode mode;
|
||||
Type * type; // Type_Basic
|
||||
Type * type;
|
||||
ExactValue value;
|
||||
bool is_lhs; // Debug info
|
||||
bool is_lhs; // Debug info
|
||||
};
|
||||
|
||||
gb_inline ExprInfo make_expr_info(AddressingMode mode, Type *type, ExactValue value, bool is_lhs) {
|
||||
ExprInfo ei = {};
|
||||
ei.is_lhs = is_lhs;
|
||||
ei.mode = mode;
|
||||
ei.type = type;
|
||||
ei.value = value;
|
||||
ei.is_lhs = is_lhs;
|
||||
return ei;
|
||||
}
|
||||
|
||||
@@ -75,22 +58,12 @@ enum BuiltinProcId {
|
||||
BuiltinProc_len,
|
||||
BuiltinProc_cap,
|
||||
|
||||
// BuiltinProc_new,
|
||||
BuiltinProc_make,
|
||||
// BuiltinProc_free,
|
||||
|
||||
// BuiltinProc_reserve,
|
||||
// BuiltinProc_clear,
|
||||
// BuiltinProc_append,
|
||||
// BuiltinProc_delete,
|
||||
|
||||
BuiltinProc_size_of,
|
||||
BuiltinProc_align_of,
|
||||
BuiltinProc_offset_of,
|
||||
BuiltinProc_type_of,
|
||||
BuiltinProc_type_info_of,
|
||||
|
||||
BuiltinProc_compile_assert,
|
||||
BuiltinProc_typeid_of,
|
||||
|
||||
BuiltinProc_swizzle,
|
||||
|
||||
@@ -99,9 +72,6 @@ enum BuiltinProcId {
|
||||
BuiltinProc_imag,
|
||||
BuiltinProc_conj,
|
||||
|
||||
// BuiltinProc_slice_ptr,
|
||||
// BuiltinProc_slice_to_bytes,
|
||||
|
||||
BuiltinProc_expand_to_tuple,
|
||||
|
||||
BuiltinProc_min,
|
||||
@@ -119,22 +89,12 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("len"), 1, false, Expr_Expr},
|
||||
{STR_LIT("cap"), 1, false, Expr_Expr},
|
||||
|
||||
// {STR_LIT("new"), 1, false, Expr_Expr},
|
||||
{STR_LIT("make"), 1, true, Expr_Expr},
|
||||
// {STR_LIT("free"), 1, false, Expr_Stmt},
|
||||
|
||||
// {STR_LIT("reserve"), 2, false, Expr_Stmt},
|
||||
// {STR_LIT("clear"), 1, false, Expr_Stmt},
|
||||
// {STR_LIT("append"), 1, true, Expr_Expr},
|
||||
// {STR_LIT("delete"), 2, false, Expr_Stmt},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("align_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("offset_of"), 2, false, Expr_Expr},
|
||||
{STR_LIT("type_of"), 1, false, Expr_Expr},
|
||||
{STR_LIT("type_info_of"), 1, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("compile_assert"), 1, false, Expr_Expr},
|
||||
{STR_LIT("typeid_of"), 1, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("swizzle"), 1, true, Expr_Expr},
|
||||
|
||||
@@ -143,13 +103,10 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("imag"), 1, false, Expr_Expr},
|
||||
{STR_LIT("conj"), 1, false, Expr_Expr},
|
||||
|
||||
// {STR_LIT("slice_ptr"), 2, true, Expr_Expr},
|
||||
// {STR_LIT("slice_to_bytes"), 1, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("expand_to_tuple"), 1, false, Expr_Expr},
|
||||
|
||||
{STR_LIT("min"), 2, false, Expr_Expr},
|
||||
{STR_LIT("max"), 2, false, Expr_Expr},
|
||||
{STR_LIT("min"), 2, true, Expr_Expr},
|
||||
{STR_LIT("max"), 2, true, Expr_Expr},
|
||||
{STR_LIT("abs"), 1, false, Expr_Expr},
|
||||
{STR_LIT("clamp"), 3, false, Expr_Expr},
|
||||
|
||||
@@ -166,7 +123,7 @@ struct Operand {
|
||||
AddressingMode mode;
|
||||
Type * type;
|
||||
ExactValue value;
|
||||
AstNode * expr;
|
||||
Ast * expr;
|
||||
BuiltinProcId builtin_id;
|
||||
Entity * proc_group;
|
||||
};
|
||||
@@ -174,62 +131,92 @@ struct Operand {
|
||||
|
||||
struct BlockLabel {
|
||||
String name;
|
||||
AstNode *label; // AstNode_Label;
|
||||
Ast *label; // Ast_Label;
|
||||
};
|
||||
|
||||
struct AttributeContext {
|
||||
String link_name;
|
||||
String link_prefix;
|
||||
isize init_expr_list_count;
|
||||
String thread_local_model;
|
||||
String deprecated_message;
|
||||
};
|
||||
|
||||
AttributeContext make_attribute_context(String link_prefix) {
|
||||
AttributeContext ac = {};
|
||||
ac.link_prefix = link_prefix;
|
||||
return ac;
|
||||
}
|
||||
|
||||
#define DECL_ATTRIBUTE_PROC(_name) bool _name(CheckerContext *c, Ast *elem, String name, ExactValue value, AttributeContext *ac)
|
||||
typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
|
||||
|
||||
void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, DeclAttributeProc *proc, AttributeContext *ac);
|
||||
|
||||
|
||||
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
|
||||
struct DeclInfo {
|
||||
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
|
||||
Scope * scope;
|
||||
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
|
||||
Scope * scope;
|
||||
|
||||
Entity ** entities;
|
||||
isize entity_count;
|
||||
Entity *entity;
|
||||
|
||||
AstNode * type_expr;
|
||||
AstNode * init_expr;
|
||||
Array<AstNode *> init_expr_list;
|
||||
Array<AstNode *> attributes;
|
||||
AstNode * proc_lit; // AstNode_ProcLit
|
||||
Type * gen_proc_type; // Precalculated
|
||||
Ast * type_expr;
|
||||
Ast * init_expr;
|
||||
Array<Ast *> attributes;
|
||||
Ast * proc_lit; // Ast_ProcLit
|
||||
Type * gen_proc_type; // Precalculated
|
||||
bool is_using;
|
||||
|
||||
PtrSet<Entity *> deps;
|
||||
PtrSet<Type *> type_info_deps;
|
||||
Array<BlockLabel> labels;
|
||||
};
|
||||
|
||||
// ProcedureInfo stores the information needed for checking a procedure
|
||||
|
||||
|
||||
struct ProcedureInfo {
|
||||
AstFile * file;
|
||||
Token token;
|
||||
DeclInfo * decl;
|
||||
Type * type; // Type_Procedure
|
||||
AstNode * body; // AstNode_BlockStmt
|
||||
u64 tags;
|
||||
bool generated_from_polymorphic;
|
||||
// ProcInfo stores the information needed for checking a procedure
|
||||
struct ProcInfo {
|
||||
AstFile * file;
|
||||
Token token;
|
||||
DeclInfo *decl;
|
||||
Type * type; // Type_Procedure
|
||||
Ast * body; // Ast_BlockStmt
|
||||
u64 tags;
|
||||
bool generated_from_polymorphic;
|
||||
Ast * poly_def_node;
|
||||
};
|
||||
|
||||
|
||||
struct Scope {
|
||||
AstNode * node;
|
||||
Scope * parent;
|
||||
Scope * prev, *next;
|
||||
Scope * first_child;
|
||||
Scope * last_child;
|
||||
Map<Entity *> elements; // Key: String
|
||||
PtrSet<Entity *> implicit;
|
||||
|
||||
Array<Scope *> shared;
|
||||
Array<AstNode *> delayed_file_decls;
|
||||
PtrSet<Scope *> imported;
|
||||
PtrSet<Scope *> exported; // NOTE(bhall): Contains 'using import' too
|
||||
bool is_proc;
|
||||
bool is_global;
|
||||
bool is_file;
|
||||
bool is_init;
|
||||
bool is_struct;
|
||||
bool has_been_imported; // This is only applicable to file scopes
|
||||
AstFile * file;
|
||||
enum ScopeFlag {
|
||||
ScopeFlag_Pkg = 1<<1,
|
||||
ScopeFlag_Global = 1<<2,
|
||||
ScopeFlag_File = 1<<3,
|
||||
ScopeFlag_Init = 1<<4,
|
||||
ScopeFlag_Proc = 1<<5,
|
||||
ScopeFlag_Type = 1<<6,
|
||||
|
||||
|
||||
ScopeFlag_HasBeenImported = 1<<10, // This is only applicable to file scopes
|
||||
};
|
||||
|
||||
struct Scope {
|
||||
Ast * node;
|
||||
Scope * parent;
|
||||
Scope * prev;
|
||||
Scope * next;
|
||||
Scope * first_child;
|
||||
Scope * last_child;
|
||||
Map<Entity *> elements; // Key: String
|
||||
|
||||
Array<Ast *> delayed_directives;
|
||||
Array<Ast *> delayed_imports;
|
||||
PtrSet<Scope *> imported;
|
||||
|
||||
i32 flags; // ScopeFlag
|
||||
union {
|
||||
AstPackage *pkg;
|
||||
AstFile * file;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -253,9 +240,8 @@ typedef PtrSet<ImportGraphNode *> ImportGraphNodeSet;
|
||||
|
||||
|
||||
struct ImportGraphNode {
|
||||
AstPackage * pkg;
|
||||
Scope * scope;
|
||||
String path;
|
||||
isize file_id;
|
||||
ImportGraphNodeSet pred;
|
||||
ImportGraphNodeSet succ;
|
||||
isize index; // Index in array/queue
|
||||
@@ -264,81 +250,94 @@ struct ImportGraphNode {
|
||||
|
||||
|
||||
struct ForeignContext {
|
||||
AstNode * curr_library;
|
||||
Ast * curr_library;
|
||||
ProcCallingConvention default_cc;
|
||||
String link_prefix;
|
||||
bool in_export;
|
||||
};
|
||||
|
||||
struct CheckerContext {
|
||||
Scope * file_scope;
|
||||
Scope * scope;
|
||||
DeclInfo * decl;
|
||||
u32 stmt_state_flags;
|
||||
bool in_defer; // TODO(bill): Actually handle correctly
|
||||
String proc_name;
|
||||
Type * type_hint;
|
||||
DeclInfo * curr_proc_decl;
|
||||
Type * curr_proc_sig;
|
||||
ForeignContext foreign_context;
|
||||
|
||||
bool collect_delayed_decls;
|
||||
bool allow_polymorphic_types;
|
||||
bool no_polymorphic_errors;
|
||||
Scope * polymorphic_scope;
|
||||
};
|
||||
|
||||
typedef Array<Entity *> CheckerTypePath;
|
||||
typedef Array<Type *> CheckerPolyPath;
|
||||
|
||||
// CheckerInfo stores all the symbol information for a type-checked program
|
||||
struct CheckerInfo {
|
||||
Map<TypeAndValue> types; // Key: AstNode * | Expression -> Type (and value)
|
||||
Map<ExprInfo> untyped; // Key: AstNode * | Expression -> ExprInfo
|
||||
Map<ExprInfo> untyped; // Key: Ast * | Expression -> ExprInfo
|
||||
// NOTE(bill): This needs to be a map and not on the Ast
|
||||
// as it needs to be iterated across
|
||||
Map<AstFile *> files; // Key: String (full path)
|
||||
Map<AstPackage *> packages; // Key: String (full path)
|
||||
Map<Entity *> foreigns; // Key: String
|
||||
Array<Entity *> definitions;
|
||||
Array<Entity *> entities;
|
||||
Array<DeclInfo *> variable_init_order;
|
||||
|
||||
Map<Array<Entity *> > gen_procs; // Key: AstNode * | Identifier -> Entity
|
||||
Map<Array<Entity *> > gen_procs; // Key: Ast * | Identifier -> Entity
|
||||
Map<Array<Entity *> > gen_types; // Key: Type *
|
||||
|
||||
Array<Type *> type_info_types;
|
||||
Map<isize> type_info_map; // Key: Type *
|
||||
|
||||
|
||||
AstPackage * builtin_package;
|
||||
AstPackage * runtime_package;
|
||||
Scope * init_scope;
|
||||
Entity * entry_point;
|
||||
PtrSet<Entity *> minimum_dependency_set;
|
||||
PtrSet<isize> minimum_dependency_type_info_set;
|
||||
};
|
||||
|
||||
struct CheckerContext {
|
||||
Checker * checker;
|
||||
CheckerInfo * info;
|
||||
AstPackage * pkg;
|
||||
AstFile * file;
|
||||
Scope * scope;
|
||||
DeclInfo * decl;
|
||||
|
||||
u32 stmt_state_flags;
|
||||
bool in_defer; // TODO(bill): Actually handle correctly
|
||||
Type * type_hint;
|
||||
|
||||
String proc_name;
|
||||
DeclInfo * curr_proc_decl;
|
||||
Type * curr_proc_sig;
|
||||
ForeignContext foreign_context;
|
||||
gbAllocator allocator;
|
||||
|
||||
CheckerTypePath *type_path;
|
||||
isize type_level; // TODO(bill): Actually handle correctly
|
||||
CheckerPolyPath *poly_path;
|
||||
isize poly_level; // TODO(bill): Actually handle correctly
|
||||
|
||||
bool in_enum_type;
|
||||
bool collect_delayed_decls;
|
||||
bool allow_polymorphic_types;
|
||||
bool no_polymorphic_errors;
|
||||
bool in_polymorphic_specialization;
|
||||
Scope * polymorphic_scope;
|
||||
};
|
||||
|
||||
struct Checker {
|
||||
Parser * parser;
|
||||
CheckerInfo info;
|
||||
gbMutex mutex;
|
||||
|
||||
AstFile * curr_ast_file;
|
||||
Scope * global_scope;
|
||||
// NOTE(bill): Procedures to check
|
||||
Array<ProcedureInfo> procs;
|
||||
Map<Scope *> file_scopes; // Key: String (fullpath)
|
||||
Array<ImportGraphNode *> file_order;
|
||||
|
||||
gbAllocator allocator;
|
||||
gbArena arena;
|
||||
gbArena tmp_arena;
|
||||
gbAllocator tmp_allocator;
|
||||
|
||||
CheckerContext context;
|
||||
|
||||
Array<Type *> proc_stack;
|
||||
bool done_preload;
|
||||
|
||||
PtrSet<AstFile *> checked_files;
|
||||
Array<ProcInfo> procs_to_check;
|
||||
PtrSet<AstPackage *> checked_packages;
|
||||
|
||||
gbAllocator allocator;
|
||||
CheckerContext init_ctx;
|
||||
};
|
||||
|
||||
|
||||
|
||||
HashKey hash_node (AstNode *node) { return hash_pointer(node); }
|
||||
|
||||
|
||||
gb_global AstPackage *builtin_pkg = nullptr;
|
||||
gb_global Scope * builtin_scope = nullptr;
|
||||
|
||||
|
||||
|
||||
HashKey hash_node (Ast *node) { return hash_pointer(node); }
|
||||
HashKey hash_ast_file (AstFile *file) { return hash_pointer(file); }
|
||||
HashKey hash_entity (Entity *e) { return hash_pointer(e); }
|
||||
HashKey hash_type (Type *t) { return hash_pointer(t); }
|
||||
@@ -347,59 +346,54 @@ HashKey hash_decl_info(DeclInfo *decl) { return hash_pointer(decl); }
|
||||
|
||||
|
||||
// CheckerInfo API
|
||||
TypeAndValue type_and_value_of_expr (CheckerInfo *i, AstNode *expr);
|
||||
Type * type_of_expr (CheckerInfo *i, AstNode *expr);
|
||||
Entity * entity_of_ident (CheckerInfo *i, AstNode *identifier);
|
||||
Entity * implicit_entity_of_node(CheckerInfo *i, AstNode *clause);
|
||||
Scope * scope_of_node (CheckerInfo *i, AstNode *node);
|
||||
DeclInfo * decl_info_of_ident (CheckerInfo *i, AstNode *ident);
|
||||
DeclInfo * decl_info_of_entity (CheckerInfo *i, Entity * e);
|
||||
TypeAndValue type_and_value_of_expr (Ast *expr);
|
||||
Type * type_of_expr (Ast *expr);
|
||||
Entity * entity_of_ident (Ast *identifier);
|
||||
Entity * implicit_entity_of_node(Ast *clause);
|
||||
Scope * scope_of_node (Ast *node);
|
||||
DeclInfo * decl_info_of_ident (Ast *ident);
|
||||
DeclInfo * decl_info_of_entity (Entity * e);
|
||||
AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
|
||||
// IMPORTANT: Only to use once checking is done
|
||||
isize type_info_index (CheckerInfo *i, Type * type, bool error_on_failure = true);
|
||||
|
||||
|
||||
Entity *current_scope_lookup_entity(Scope *s, String name);
|
||||
Entity *scope_lookup_entity (Scope *s, String name);
|
||||
void scope_lookup_parent_entity (Scope *s, String name, Scope **scope_, Entity **entity_);
|
||||
Entity *scope_insert_entity (Scope *s, Entity *entity);
|
||||
// Will return nullptr if not found
|
||||
Entity *entity_of_node(CheckerInfo *i, Ast *expr);
|
||||
|
||||
|
||||
ExprInfo *check_get_expr_info (CheckerInfo *i, AstNode *expr);
|
||||
void check_set_expr_info (CheckerInfo *i, AstNode *expr, ExprInfo info);
|
||||
void check_remove_expr_info (CheckerInfo *i, AstNode *expr);
|
||||
void add_untyped (CheckerInfo *i, AstNode *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value);
|
||||
void add_type_and_value (CheckerInfo *i, AstNode *expression, AddressingMode mode, Type *type, ExactValue value);
|
||||
void add_entity_use (Checker *c, AstNode *identifier, Entity *entity);
|
||||
void add_implicit_entity (Checker *c, AstNode *node, Entity *e);
|
||||
void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d);
|
||||
|
||||
void check_add_import_decl(Checker *c, AstNodeImportDecl *id);
|
||||
void check_add_export_decl(Checker *c, AstNodeExportDecl *ed);
|
||||
void check_add_foreign_import_decl(Checker *c, AstNode *decl);
|
||||
Entity *scope_lookup_current(Scope *s, String name);
|
||||
Entity *scope_lookup (Scope *s, String name);
|
||||
void scope_lookup_parent (Scope *s, String name, Scope **scope_, Entity **entity_);
|
||||
Entity *scope_insert (Scope *s, Entity *entity);
|
||||
|
||||
|
||||
ExprInfo *check_get_expr_info (CheckerInfo *i, Ast *expr);
|
||||
void check_set_expr_info (CheckerInfo *i, Ast *expr, ExprInfo info);
|
||||
void check_remove_expr_info (CheckerInfo *i, Ast *expr);
|
||||
void add_untyped (CheckerInfo *i, Ast *expression, bool lhs, AddressingMode mode, Type *basic_type, ExactValue value);
|
||||
void add_type_and_value (CheckerInfo *i, Ast *expression, AddressingMode mode, Type *type, ExactValue value);
|
||||
void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
|
||||
void add_implicit_entity (CheckerContext *c, Ast *node, Entity *e);
|
||||
void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d);
|
||||
void add_type_info_type (CheckerContext *c, Type *t);
|
||||
|
||||
bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global = false);
|
||||
void check_collect_entities(Checker *c, Array<AstNode *> nodes);
|
||||
void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws);
|
||||
void check_delayed_file_import_entity(Checker *c, AstNode *decl);
|
||||
void check_add_import_decl(CheckerContext *c, Ast *decl);
|
||||
void check_add_foreign_import_decl(CheckerContext *c, Ast *decl);
|
||||
|
||||
|
||||
struct AttributeContext {
|
||||
String link_name;
|
||||
String link_prefix;
|
||||
isize init_expr_list_count;
|
||||
String thread_local_model;
|
||||
};
|
||||
bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false);
|
||||
void check_collect_entities(CheckerContext *c, Array<Ast *> const &nodes);
|
||||
void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
|
||||
void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
|
||||
|
||||
AttributeContext make_attribute_context(String link_prefix) {
|
||||
AttributeContext ac = {};
|
||||
ac.link_prefix = link_prefix;
|
||||
return ac;
|
||||
}
|
||||
CheckerTypePath *new_checker_type_path();
|
||||
void destroy_checker_type_path(CheckerTypePath *tp);
|
||||
|
||||
#define DECL_ATTRIBUTE_PROC(_name) bool _name(Checker *c, AstNode *elem, String name, ExactValue value, AttributeContext *ac)
|
||||
typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
|
||||
void check_type_path_push(CheckerContext *c, Entity *e);
|
||||
Entity *check_type_path_pop (CheckerContext *c);
|
||||
|
||||
void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttributeProc *proc, AttributeContext *ac);
|
||||
CheckerPolyPath *new_checker_poly_path();
|
||||
void destroy_checker_poly_path(CheckerPolyPath *);
|
||||
|
||||
void check_poly_path_push(CheckerContext *c, Type *t);
|
||||
Type *check_poly_path_pop (CheckerContext *c);
|
||||
|
||||
+382
-131
@@ -3,6 +3,10 @@
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(GB_COMPILER_MSVC)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#define GB_IMPLEMENTATION
|
||||
#include "gb/gb.h"
|
||||
|
||||
@@ -12,6 +16,14 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
template <typename U, typename V>
|
||||
gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
|
||||
|
||||
template <typename U, typename V>
|
||||
gb_inline U const &bit_cast(V const &v) { return reinterpret_cast<U const &>(v); }
|
||||
|
||||
|
||||
gb_inline i64 align_formula(i64 size, i64 align) {
|
||||
if (align > 0) {
|
||||
i64 result = size + align-1;
|
||||
@@ -32,13 +44,13 @@ GB_ALLOCATOR_PROC(heap_allocator_proc);
|
||||
gbAllocator heap_allocator(void) {
|
||||
gbAllocator a;
|
||||
a.proc = heap_allocator_proc;
|
||||
a.data = NULL;
|
||||
a.data = nullptr;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
void *ptr = NULL;
|
||||
void *ptr = nullptr;
|
||||
gb_unused(allocator_data);
|
||||
gb_unused(old_size);
|
||||
|
||||
@@ -164,6 +176,7 @@ u64 u64_from_string(String string) {
|
||||
case 'd': base = 10; has_prefix = true; break;
|
||||
case 'z': base = 12; has_prefix = true; break;
|
||||
case 'x': base = 16; has_prefix = true; break;
|
||||
case 'h': base = 16; has_prefix = true; break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +204,7 @@ u64 u64_from_string(String string) {
|
||||
}
|
||||
|
||||
String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
||||
char buf[200] = {0};
|
||||
char buf[32] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
|
||||
u64 b = 10;
|
||||
@@ -202,11 +215,11 @@ String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
||||
buf[--i] = gb__num_to_char_table[v%b];
|
||||
|
||||
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
|
||||
gb_memcopy(out_buf, &buf[i], len);
|
||||
gb_memmove(out_buf, &buf[i], len);
|
||||
return make_string(cast(u8 *)out_buf, len);
|
||||
}
|
||||
String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
|
||||
char buf[200] = {0};
|
||||
char buf[32] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
bool negative = false;
|
||||
if (a < 0) {
|
||||
@@ -227,11 +240,82 @@ String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
|
||||
}
|
||||
|
||||
isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
|
||||
gb_memcopy(out_buf, &buf[i], len);
|
||||
gb_memmove(out_buf, &buf[i], len);
|
||||
return make_string(cast(u8 *)out_buf, len);
|
||||
}
|
||||
|
||||
|
||||
gb_global i64 const signed_integer_mins[] = {
|
||||
0,
|
||||
-128ll,
|
||||
-32768ll,
|
||||
0,
|
||||
-2147483648ll,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
(-9223372036854775807ll - 1ll),
|
||||
};
|
||||
gb_global i64 const signed_integer_maxs[] = {
|
||||
0,
|
||||
127ll,
|
||||
32767ll,
|
||||
0,
|
||||
2147483647ll,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
9223372036854775807ll,
|
||||
};
|
||||
gb_global u64 const unsigned_integer_maxs[] = {
|
||||
0,
|
||||
255ull,
|
||||
65535ull,
|
||||
0,
|
||||
4294967295ull,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
18446744073709551615ull,
|
||||
};
|
||||
|
||||
|
||||
bool add_overflow_u64(u64 x, u64 y, u64 *result) {
|
||||
*result = x + y;
|
||||
return *result < x || *result < y;
|
||||
}
|
||||
|
||||
bool sub_overflow_u64(u64 x, u64 y, u64 *result) {
|
||||
*result = x - y;
|
||||
return *result > x;
|
||||
}
|
||||
|
||||
void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
|
||||
#if defined(GB_COMPILER_MSVC)
|
||||
*lo = _umul128(x, y, hi);
|
||||
#else
|
||||
// URL(bill): https://stackoverflow.com/questions/25095741/how-can-i-multiply-64-bit-operands-and-get-128-bit-result-portably#25096197
|
||||
u64 u1, v1, w1, t, w3, k;
|
||||
|
||||
u1 = (x & 0xffffffff);
|
||||
v1 = (y & 0xffffffff);
|
||||
t = (u1 * v1);
|
||||
w3 = (t & 0xffffffff);
|
||||
k = (t >> 32);
|
||||
|
||||
x >>= 32;
|
||||
t = (x * v1) + k;
|
||||
k = (t & 0xffffffff);
|
||||
w1 = (t >> 32);
|
||||
|
||||
y >>= 32;
|
||||
t = (u1 * y) + k;
|
||||
k = (t >> 32);
|
||||
|
||||
*hi = (x * y) + w1 + k;
|
||||
*lo = (t << 32) + w3;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -245,158 +329,118 @@ String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
|
||||
gb_global String global_module_path = {0};
|
||||
gb_global bool global_module_path_set = false;
|
||||
|
||||
gb_global gbScratchMemory scratch_memory = {0};
|
||||
// Arena from Per Vognsen
|
||||
#define ALIGN_DOWN(n, a) ((n) & ~((a) - 1))
|
||||
#define ALIGN_UP(n, a) ALIGN_DOWN((n) + (a) - 1, (a))
|
||||
#define ALIGN_DOWN_PTR(p, a) (cast(void *)ALIGN_DOWN(cast(uintptr)(p), (a)))
|
||||
#define ALIGN_UP_PTR(p, a) (cast(void *)ALIGN_UP(cast(uintptr)(p), (a)))
|
||||
|
||||
void init_scratch_memory(isize size) {
|
||||
void *memory = gb_alloc(heap_allocator(), size);
|
||||
gb_scratch_memory_init(&scratch_memory, memory, size);
|
||||
typedef struct Arena {
|
||||
u8 * ptr;
|
||||
u8 * end;
|
||||
u8 * prev;
|
||||
Array<u8 *> blocks;
|
||||
gbAllocator backing;
|
||||
isize block_size;
|
||||
gbMutex mutex;
|
||||
|
||||
isize total_used;
|
||||
} Arena;
|
||||
|
||||
#define ARENA_MIN_ALIGNMENT 16
|
||||
#define ARENA_DEFAULT_BLOCK_SIZE (8*1024*1024)
|
||||
|
||||
void arena_init(Arena *arena, gbAllocator backing, isize block_size=ARENA_DEFAULT_BLOCK_SIZE) {
|
||||
arena->backing = backing;
|
||||
arena->block_size = block_size;
|
||||
array_init(&arena->blocks, backing);
|
||||
gb_mutex_init(&arena->mutex);
|
||||
}
|
||||
|
||||
gbAllocator scratch_allocator(void) {
|
||||
return gb_scratch_allocator(&scratch_memory);
|
||||
void arena_grow(Arena *arena, isize min_size) {
|
||||
gb_mutex_lock(&arena->mutex);
|
||||
defer (gb_mutex_unlock(&arena->mutex));
|
||||
|
||||
isize size = gb_max(arena->block_size, min_size);
|
||||
size = ALIGN_UP(size, ARENA_MIN_ALIGNMENT);
|
||||
void *new_ptr = gb_alloc(arena->backing, size);
|
||||
arena->ptr = cast(u8 *)new_ptr;
|
||||
gb_zero_size(arena->ptr, size);
|
||||
GB_ASSERT(arena->ptr == ALIGN_DOWN_PTR(arena->ptr, ARENA_MIN_ALIGNMENT));
|
||||
arena->end = arena->ptr + size;
|
||||
array_add(&arena->blocks, arena->ptr);
|
||||
}
|
||||
|
||||
struct Pool {
|
||||
isize memblock_size;
|
||||
isize out_of_band_size;
|
||||
isize alignment;
|
||||
void *arena_alloc(Arena *arena, isize size, isize alignment) {
|
||||
gb_mutex_lock(&arena->mutex);
|
||||
defer (gb_mutex_unlock(&arena->mutex));
|
||||
|
||||
Array<u8 *> unused_memblock;
|
||||
Array<u8 *> used_memblock;
|
||||
Array<u8 *> out_of_band_allocations;
|
||||
arena->total_used += size;
|
||||
|
||||
u8 * current_memblock;
|
||||
u8 * current_pos;
|
||||
isize bytes_left;
|
||||
if (size > (arena->end - arena->ptr)) {
|
||||
arena_grow(arena, size);
|
||||
GB_ASSERT(size <= (arena->end - arena->ptr));
|
||||
}
|
||||
|
||||
gbAllocator block_allocator;
|
||||
};
|
||||
|
||||
enum {
|
||||
POOL_BUCKET_SIZE_DEFAULT = 65536,
|
||||
POOL_OUT_OF_BAND_SIZE_DEFAULT = 6554,
|
||||
};
|
||||
|
||||
void pool_init(Pool *pool,
|
||||
isize memblock_size = POOL_BUCKET_SIZE_DEFAULT,
|
||||
isize out_of_band_size = POOL_OUT_OF_BAND_SIZE_DEFAULT,
|
||||
isize alignment = 8,
|
||||
gbAllocator block_allocator = heap_allocator(),
|
||||
gbAllocator array_allocator = heap_allocator()) {
|
||||
pool->memblock_size = memblock_size;
|
||||
pool->out_of_band_size = out_of_band_size;
|
||||
pool->alignment = alignment;
|
||||
pool->block_allocator = block_allocator;
|
||||
|
||||
array_init(&pool->unused_memblock, array_allocator);
|
||||
array_init(&pool->used_memblock, array_allocator);
|
||||
array_init(&pool->out_of_band_allocations, array_allocator);
|
||||
isize align = gb_max(alignment, ARENA_MIN_ALIGNMENT);
|
||||
void *ptr = arena->ptr;
|
||||
arena->prev = arena->ptr;
|
||||
arena->ptr = cast(u8 *)ALIGN_UP_PTR(arena->ptr + size, align);
|
||||
GB_ASSERT(arena->ptr <= arena->end);
|
||||
GB_ASSERT(ptr == ALIGN_DOWN_PTR(ptr, align));
|
||||
gb_zero_size(ptr, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void pool_free_all(Pool *p) {
|
||||
if (p->current_memblock != nullptr) {
|
||||
array_add(&p->unused_memblock, p->current_memblock);
|
||||
p->current_memblock = nullptr;
|
||||
void arena_free_all(Arena *arena) {
|
||||
gb_mutex_lock(&arena->mutex);
|
||||
defer (gb_mutex_unlock(&arena->mutex));
|
||||
|
||||
for_array(i, arena->blocks) {
|
||||
gb_free(arena->backing, arena->blocks[i]);
|
||||
}
|
||||
|
||||
for_array(i, p->used_memblock) {
|
||||
array_add(&p->unused_memblock, p->used_memblock[i]);
|
||||
}
|
||||
array_clear(&p->unused_memblock);
|
||||
|
||||
for_array(i, p->out_of_band_allocations) {
|
||||
gb_free(p->block_allocator, p->out_of_band_allocations[i]);
|
||||
}
|
||||
array_clear(&p->out_of_band_allocations);
|
||||
}
|
||||
|
||||
void pool_destroy(Pool *p) {
|
||||
pool_free_all(p);
|
||||
|
||||
for_array(i, p->unused_memblock) {
|
||||
gb_free(p->block_allocator, p->unused_memblock[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void pool_cycle_new_block(Pool *p) {
|
||||
GB_ASSERT_MSG(p->block_allocator.proc != nullptr,
|
||||
"You must call pool_init on a Pool before using it!");
|
||||
|
||||
if (p->current_memblock != nullptr) {
|
||||
array_add(&p->used_memblock, p->current_memblock);
|
||||
}
|
||||
|
||||
u8 *new_block = nullptr;
|
||||
|
||||
if (p->unused_memblock.count > 0) {
|
||||
new_block = array_pop(&p->unused_memblock);
|
||||
} else {
|
||||
GB_ASSERT(p->block_allocator.proc != nullptr);
|
||||
new_block = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, p->alignment);
|
||||
}
|
||||
|
||||
p->bytes_left = p->memblock_size;
|
||||
p->current_memblock = new_block;
|
||||
p->current_memblock = new_block;
|
||||
}
|
||||
|
||||
void *pool_get(Pool *p,
|
||||
isize size, isize alignment = 0) {
|
||||
if (alignment <= 0) alignment = p->alignment;
|
||||
|
||||
isize extra = alignment - (size & alignment);
|
||||
size += extra;
|
||||
if (size >= p->out_of_band_size) {
|
||||
GB_ASSERT(p->block_allocator.proc != nullptr);
|
||||
u8 *memory = cast(u8 *)gb_alloc_align(p->block_allocator, p->memblock_size, alignment);
|
||||
if (memory != nullptr) {
|
||||
array_add(&p->out_of_band_allocations, memory);
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
if (p->bytes_left < size) {
|
||||
pool_cycle_new_block(p);
|
||||
if (p->current_memblock != nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
u8 *res = p->current_pos;
|
||||
p->current_pos += size;
|
||||
p->bytes_left -= size;
|
||||
return res;
|
||||
array_clear(&arena->blocks);
|
||||
arena->ptr = nullptr;
|
||||
arena->end = nullptr;
|
||||
}
|
||||
|
||||
|
||||
gbAllocator pool_allocator(Pool *pool);
|
||||
|
||||
GB_ALLOCATOR_PROC(pool_allocator_procedure) {
|
||||
Pool *p = cast(Pool *)allocator_data;
|
||||
|
||||
GB_ALLOCATOR_PROC(arena_allocator_proc);
|
||||
|
||||
gbAllocator arena_allocator(Arena *arena) {
|
||||
gbAllocator a;
|
||||
a.proc = arena_allocator_proc;
|
||||
a.data = arena;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
GB_ALLOCATOR_PROC(arena_allocator_proc) {
|
||||
void *ptr = nullptr;
|
||||
Arena *arena = cast(Arena *)allocator_data;
|
||||
GB_ASSERT_NOT_NULL(arena);
|
||||
|
||||
switch (type) {
|
||||
case gbAllocation_Alloc:
|
||||
return pool_get(p, size, alignment);
|
||||
case gbAllocation_Free:
|
||||
// Does nothing
|
||||
ptr = arena_alloc(arena, size, alignment);
|
||||
break;
|
||||
case gbAllocation_FreeAll:
|
||||
pool_free_all(p);
|
||||
case gbAllocation_Free:
|
||||
GB_PANIC("gbAllocation_Free not supported");
|
||||
break;
|
||||
case gbAllocation_Resize:
|
||||
return gb_default_resize_align(pool_allocator(p), old_memory, old_size, size, alignment);
|
||||
GB_PANIC("gbAllocation_Resize: not supported");
|
||||
break;
|
||||
case gbAllocation_FreeAll:
|
||||
arena_free_all(arena);
|
||||
break;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
gbAllocator pool_allocator(Pool *pool) {
|
||||
gbAllocator allocator;
|
||||
allocator.proc = pool_allocator_procedure;
|
||||
allocator.data = pool;
|
||||
return allocator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -683,3 +727,210 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
String path_to_full_path(gbAllocator a, String path) {
|
||||
gbAllocator ha = heap_allocator();
|
||||
char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
|
||||
defer (gb_free(ha, path_c));
|
||||
|
||||
char *fullpath = gb_path_get_full_name(a, path_c);
|
||||
return make_string_c(fullpath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct FileInfo {
|
||||
String name;
|
||||
String fullpath;
|
||||
i64 size;
|
||||
bool is_dir;
|
||||
};
|
||||
|
||||
enum ReadDirectoryError {
|
||||
ReadDirectory_None,
|
||||
|
||||
ReadDirectory_InvalidPath,
|
||||
ReadDirectory_NotExists,
|
||||
ReadDirectory_Permission,
|
||||
ReadDirectory_NotDir,
|
||||
ReadDirectory_Empty,
|
||||
ReadDirectory_Unknown,
|
||||
|
||||
ReadDirectory_COUNT,
|
||||
};
|
||||
|
||||
i64 get_file_size(String path) {
|
||||
char *c_str = alloc_cstring(heap_allocator(), path);
|
||||
defer (gb_free(heap_allocator(), c_str));
|
||||
|
||||
gbFile f = {};
|
||||
gbFileError err = gb_file_open(&f, c_str);
|
||||
defer (gb_file_close(&f));
|
||||
if (err != gbFileError_None) {
|
||||
return -1;
|
||||
}
|
||||
return gb_file_size(&f);
|
||||
}
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
GB_ASSERT(fi != nullptr);
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
while (path.len > 0) {
|
||||
Rune end = path[path.len-1];
|
||||
if (end == '/') {
|
||||
path.len -= 1;
|
||||
} else if (end == '\\') {
|
||||
path.len -= 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (path.len == 0) {
|
||||
return ReadDirectory_InvalidPath;
|
||||
}
|
||||
{
|
||||
char *c_str = alloc_cstring(a, path);
|
||||
defer (gb_free(a, c_str));
|
||||
|
||||
gbFile f = {};
|
||||
gbFileError file_err = gb_file_open(&f, c_str);
|
||||
defer (gb_file_close(&f));
|
||||
|
||||
switch (file_err) {
|
||||
case gbFileError_Invalid: return ReadDirectory_InvalidPath;
|
||||
case gbFileError_NotExists: return ReadDirectory_NotExists;
|
||||
// case gbFileError_Permission: return ReadDirectory_Permission;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path_is_directory(path)) {
|
||||
return ReadDirectory_NotDir;
|
||||
}
|
||||
|
||||
|
||||
char *new_path = gb_alloc_array(a, char, path.len+3);
|
||||
defer (gb_free(a, new_path));
|
||||
|
||||
gb_memmove(new_path, path.text, path.len);
|
||||
gb_memmove(new_path+path.len, "/*", 2);
|
||||
new_path[path.len+2] = 0;
|
||||
|
||||
String np = make_string(cast(u8 *)new_path, path.len+2);
|
||||
String16 wstr = string_to_string16(a, np);
|
||||
defer (gb_free(a, wstr.text));
|
||||
|
||||
WIN32_FIND_DATAW file_data = {};
|
||||
HANDLE find_file = FindFirstFileW(wstr.text, &file_data);
|
||||
if (find_file == INVALID_HANDLE_VALUE) {
|
||||
return ReadDirectory_Unknown;
|
||||
}
|
||||
defer (FindClose(find_file));
|
||||
|
||||
array_init(fi, a, 0, 100);
|
||||
|
||||
do {
|
||||
wchar_t *filename_w = file_data.cFileName;
|
||||
i64 size = cast(i64)file_data.nFileSizeLow;
|
||||
size |= (cast(i64)file_data.nFileSizeHigh) << 32;
|
||||
String name = string16_to_string(a, make_string16_c(filename_w));
|
||||
if (name == "." || name == "..") {
|
||||
gb_free(a, name.text);
|
||||
continue;
|
||||
}
|
||||
|
||||
String filepath = {};
|
||||
filepath.len = path.len+1+name.len;
|
||||
filepath.text = gb_alloc_array(a, u8, filepath.len+1);
|
||||
defer (gb_free(a, filepath.text));
|
||||
gb_memmove(filepath.text, path.text, path.len);
|
||||
gb_memmove(filepath.text+path.len, "/", 1);
|
||||
gb_memmove(filepath.text+path.len+1, name.text, name.len);
|
||||
|
||||
FileInfo info = {};
|
||||
info.name = name;
|
||||
info.fullpath = path_to_full_path(a, filepath);
|
||||
info.size = size;
|
||||
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
array_add(fi, info);
|
||||
|
||||
} while (FindNextFileW(find_file, &file_data));
|
||||
|
||||
if (fi->count == 0) {
|
||||
return ReadDirectory_Empty;
|
||||
}
|
||||
|
||||
return ReadDirectory_None;
|
||||
}
|
||||
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX)
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
GB_ASSERT(fi != nullptr);
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
char *c_path = alloc_cstring(a, path);
|
||||
defer (gb_free(a, c_path));
|
||||
|
||||
DIR *dir = opendir(c_path);
|
||||
if (!dir) {
|
||||
return ReadDirectory_NotDir;
|
||||
}
|
||||
|
||||
array_init(fi, a, 0, 100);
|
||||
|
||||
for (;;) {
|
||||
struct dirent *entry = readdir(dir);
|
||||
if (entry == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
String name = make_string_c(entry->d_name);
|
||||
if (name == "." || name == "..") {
|
||||
continue;
|
||||
}
|
||||
|
||||
String filepath = {};
|
||||
filepath.len = path.len+1+name.len;
|
||||
filepath.text = gb_alloc_array(a, u8, filepath.len+1);
|
||||
defer (gb_free(a, filepath.text));
|
||||
gb_memmove(filepath.text, path.text, path.len);
|
||||
gb_memmove(filepath.text+path.len, "/", 1);
|
||||
gb_memmove(filepath.text+path.len+1, name.text, name.len);
|
||||
filepath.text[filepath.len] = 0;
|
||||
|
||||
|
||||
struct stat dir_stat = {};
|
||||
|
||||
if (stat((char *)filepath.text, &dir_stat)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_ISDIR(dir_stat.st_mode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i64 size = dir_stat.st_size;
|
||||
|
||||
FileInfo info = {};
|
||||
info.name = name;
|
||||
info.fullpath = path_to_full_path(a, filepath);
|
||||
info.size = size;
|
||||
array_add(fi, info);
|
||||
}
|
||||
|
||||
if (fi->count == 0) {
|
||||
return ReadDirectory_Empty;
|
||||
}
|
||||
|
||||
return ReadDirectory_None;
|
||||
}
|
||||
#else
|
||||
#error Implement read_directory
|
||||
#endif
|
||||
|
||||
+16
-16
@@ -1,6 +1,6 @@
|
||||
// Generates Documentation
|
||||
|
||||
gbString expr_to_string(AstNode *expression);
|
||||
gbString expr_to_string(Ast *expression);
|
||||
|
||||
String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
|
||||
isize len = 0;
|
||||
@@ -33,9 +33,9 @@ String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
|
||||
}
|
||||
|
||||
#if 0
|
||||
void print_type_spec(AstNode *spec) {
|
||||
void print_type_spec(Ast *spec) {
|
||||
ast_node(ts, TypeSpec, spec);
|
||||
GB_ASSERT(ts->name->kind == AstNode_Ident);
|
||||
GB_ASSERT(ts->name->kind == Ast_Ident);
|
||||
String name = ts->name->Ident.string;
|
||||
if (name.len == 0) {
|
||||
return;
|
||||
@@ -46,8 +46,8 @@ void print_type_spec(AstNode *spec) {
|
||||
gb_printf("type %.*s\n", LIT(name));
|
||||
}
|
||||
|
||||
void print_proc_decl(AstNodeProcDecl *pd) {
|
||||
GB_ASSERT(pd->name->kind == AstNode_Ident);
|
||||
void print_proc_decl(AstProcDecl *pd) {
|
||||
GB_ASSERT(pd->name->kind == Ast_Ident);
|
||||
String name = pd->name->Ident.string;
|
||||
if (name.len == 0) {
|
||||
return;
|
||||
@@ -89,19 +89,19 @@ void print_proc_decl(AstNodeProcDecl *pd) {
|
||||
gb_printf("\n\n");
|
||||
}
|
||||
#endif
|
||||
void print_declaration(AstNode *decl) {
|
||||
void print_declaration(Ast *decl) {
|
||||
}
|
||||
|
||||
void generate_documentation(Parser *parser) {
|
||||
for_array(file_index, parser->files) {
|
||||
AstFile *file = parser->files[file_index];
|
||||
Tokenizer *tokenizer = &file->tokenizer;
|
||||
String fullpath = tokenizer->fullpath;
|
||||
gb_printf("%.*s\n", LIT(fullpath));
|
||||
// for_array(file_index, parser->files) {
|
||||
// AstFile *file = parser->files[file_index];
|
||||
// Tokenizer *tokenizer = &file->tokenizer;
|
||||
// String fullpath = tokenizer->fullpath;
|
||||
// gb_printf("%.*s\n", LIT(fullpath));
|
||||
|
||||
for_array(decl_index, file->decls) {
|
||||
AstNode *decl = file->decls[decl_index];
|
||||
print_declaration(decl);
|
||||
}
|
||||
}
|
||||
// for_array(decl_index, file->decls) {
|
||||
// Ast *decl = file->decls[decl_index];
|
||||
// print_declaration(decl);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncall
|
||||
File: dyncall/dyncall.h
|
||||
Description: public header for library dyncall
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
dyncall C API
|
||||
|
||||
REVISION
|
||||
2015/07/08 added SYS_PPC64 system call
|
||||
2015/01/16 added SYS_PPC32 system call
|
||||
2007/12/11 initial
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNCALL_H
|
||||
#define DYNCALL_H
|
||||
|
||||
#include "dyncall_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct DCCallVM_ DCCallVM;
|
||||
typedef struct DCstruct_ DCstruct;
|
||||
|
||||
/* Supported Calling Convention Modes */
|
||||
|
||||
#define DC_CALL_C_DEFAULT 0
|
||||
#define DC_CALL_C_ELLIPSIS 100
|
||||
#define DC_CALL_C_ELLIPSIS_VARARGS 101
|
||||
#define DC_CALL_C_X86_CDECL 1
|
||||
#define DC_CALL_C_X86_WIN32_STD 2
|
||||
#define DC_CALL_C_X86_WIN32_FAST_MS 3
|
||||
#define DC_CALL_C_X86_WIN32_FAST_GNU 4
|
||||
#define DC_CALL_C_X86_WIN32_THIS_MS 5
|
||||
#define DC_CALL_C_X86_WIN32_THIS_GNU 6
|
||||
#define DC_CALL_C_X64_WIN64 7
|
||||
#define DC_CALL_C_X64_SYSV 8
|
||||
#define DC_CALL_C_PPC32_DARWIN 9
|
||||
#define DC_CALL_C_PPC32_OSX DC_CALL_C_PPC32_DARWIN /* alias */
|
||||
#define DC_CALL_C_ARM_ARM_EABI 10
|
||||
#define DC_CALL_C_ARM_THUMB_EABI 11
|
||||
#define DC_CALL_C_ARM_ARMHF 30
|
||||
#define DC_CALL_C_MIPS32_EABI 12
|
||||
#define DC_CALL_C_MIPS32_PSPSDK DC_CALL_C_MIPS32_EABI /* alias - deprecated. */
|
||||
#define DC_CALL_C_PPC32_SYSV 13
|
||||
#define DC_CALL_C_PPC32_LINUX DC_CALL_C_PPC32_SYSV /* alias */
|
||||
#define DC_CALL_C_ARM_ARM 14
|
||||
#define DC_CALL_C_ARM_THUMB 15
|
||||
#define DC_CALL_C_MIPS32_O32 16
|
||||
#define DC_CALL_C_MIPS64_N32 17
|
||||
#define DC_CALL_C_MIPS64_N64 18
|
||||
#define DC_CALL_C_X86_PLAN9 19
|
||||
#define DC_CALL_C_SPARC32 20
|
||||
#define DC_CALL_C_SPARC64 21
|
||||
#define DC_CALL_C_ARM64 22
|
||||
#define DC_CALL_C_PPC64 23
|
||||
#define DC_CALL_C_PPC64_LINUX DC_CALL_C_PPC64 /* alias */
|
||||
#define DC_CALL_SYS_DEFAULT 200
|
||||
#define DC_CALL_SYS_X86_INT80H_LINUX 201
|
||||
#define DC_CALL_SYS_X86_INT80H_BSD 202
|
||||
#define DC_CALL_SYS_PPC32 210
|
||||
#define DC_CALL_SYS_PPC64 211
|
||||
|
||||
/* Error codes. */
|
||||
|
||||
#define DC_ERROR_NONE 0
|
||||
#define DC_ERROR_UNSUPPORTED_MODE -1
|
||||
|
||||
DC_API DCCallVM* dcNewCallVM (DCsize size);
|
||||
DC_API void dcFree (DCCallVM* vm);
|
||||
DC_API void dcReset (DCCallVM* vm);
|
||||
|
||||
DC_API void dcMode (DCCallVM* vm, DCint mode);
|
||||
|
||||
DC_API void dcArgBool (DCCallVM* vm, DCbool value);
|
||||
DC_API void dcArgChar (DCCallVM* vm, DCchar value);
|
||||
DC_API void dcArgShort (DCCallVM* vm, DCshort value);
|
||||
DC_API void dcArgInt (DCCallVM* vm, DCint value);
|
||||
DC_API void dcArgLong (DCCallVM* vm, DClong value);
|
||||
DC_API void dcArgLongLong (DCCallVM* vm, DClonglong value);
|
||||
DC_API void dcArgFloat (DCCallVM* vm, DCfloat value);
|
||||
DC_API void dcArgDouble (DCCallVM* vm, DCdouble value);
|
||||
DC_API void dcArgPointer (DCCallVM* vm, DCpointer value);
|
||||
DC_API void dcArgStruct (DCCallVM* vm, DCstruct* s, DCpointer value);
|
||||
|
||||
DC_API void dcCallVoid (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DCbool dcCallBool (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DCchar dcCallChar (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DCshort dcCallShort (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DCint dcCallInt (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DClong dcCallLong (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DClonglong dcCallLongLong (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DCfloat dcCallFloat (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DCdouble dcCallDouble (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API DCpointer dcCallPointer (DCCallVM* vm, DCpointer funcptr);
|
||||
DC_API void dcCallStruct (DCCallVM* vm, DCpointer funcptr, DCstruct* s, DCpointer returnValue);
|
||||
|
||||
DC_API DCint dcGetError (DCCallVM* vm);
|
||||
|
||||
#define DEFAULT_ALIGNMENT 0
|
||||
DC_API DCstruct* dcNewStruct (DCsize fieldCount, DCint alignment);
|
||||
DC_API void dcStructField (DCstruct* s, DCint type, DCint alignment, DCsize arrayLength);
|
||||
DC_API void dcSubStruct (DCstruct* s, DCsize fieldCount, DCint alignment, DCsize arrayLength);
|
||||
/* Each dcNewStruct or dcSubStruct call must be paired with a dcCloseStruct. */
|
||||
DC_API void dcCloseStruct (DCstruct* s);
|
||||
DC_API DCsize dcStructSize (DCstruct* s);
|
||||
DC_API DCsize dcStructAlignment(DCstruct* s);
|
||||
DC_API void dcFreeStruct (DCstruct* s);
|
||||
|
||||
DC_API DCstruct* dcDefineStruct (const char* signature);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DYNCALL_H */
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_alloc_wx.h
|
||||
Description: Allocate write/executable memory - Interface
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALL_ALLOC_WX_HPP
|
||||
#define DYNCALL_ALLOC_WX_HPP
|
||||
|
||||
#include "dyncall_types.h"
|
||||
|
||||
typedef int DCerror;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DCerror dcAllocWX(DCsize size, void** p);
|
||||
void dcFreeWX (void* p, DCsize size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* DYNCALL_ALLOC_WX_HPP */
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args.h
|
||||
Description: Callback's Arguments VM - Interface
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALL_ARGS_H
|
||||
#define DYNCALL_ARGS_H
|
||||
|
||||
/*
|
||||
* dyncall args C API
|
||||
*
|
||||
* dyncall args provides serialized access to arguments of a function call.
|
||||
* related concepts: callback
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dyncall.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct DCArgs DCArgs;
|
||||
|
||||
DC_API DCbool dcbArgBool (DCArgs*);
|
||||
DC_API DCchar dcbArgChar (DCArgs*);
|
||||
DC_API DCshort dcbArgShort (DCArgs*);
|
||||
DC_API DCint dcbArgInt (DCArgs*);
|
||||
DC_API DClong dcbArgLong (DCArgs*);
|
||||
DC_API DClonglong dcbArgLongLong (DCArgs*);
|
||||
DC_API DCuchar dcbArgUChar (DCArgs*);
|
||||
DC_API DCushort dcbArgUShort (DCArgs*);
|
||||
DC_API DCuint dcbArgUInt (DCArgs*);
|
||||
DC_API DCulong dcbArgULong (DCArgs*);
|
||||
DC_API DCulonglong dcbArgULongLong(DCArgs*);
|
||||
DC_API DCfloat dcbArgFloat (DCArgs*);
|
||||
DC_API DCdouble dcbArgDouble (DCArgs*);
|
||||
DC_API DCpointer dcbArgPointer (DCArgs*);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DYNCALL_ARGS_H */
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_arm32_arm.h
|
||||
Description: Callback's Arguments VM - Header for ARM32 (ARM mode)
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALLBACK_ARGS_ARM32_ARM_H
|
||||
#define DYNCALLBACK_ARGS_ARM32_ARM_H
|
||||
|
||||
#include "dyncall_args.h"
|
||||
|
||||
struct DCArgs
|
||||
{
|
||||
/* Don't change order! */
|
||||
long reg_data[4];
|
||||
int reg_count;
|
||||
long* stack_ptr;
|
||||
#if defined(DC__ABI_ARM_HF)
|
||||
DCfloat f[16];
|
||||
int freg_count;
|
||||
int dreg_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* DYNCALLBACK_ARGS_ARM32_ARM_H */
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_arm32_thumb.h
|
||||
Description: Callback's Arguments VM - Header for ARM32 (THUMB mode)
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALLBACK_ARGS_ARM32_THUMB_H
|
||||
#define DYNCALLBACK_ARGS_ARM32_THUMB_H
|
||||
|
||||
#include "dyncall_args_arm32_arm.h" /* Uses same code as ARM mode. */
|
||||
|
||||
#endif /* DYNCALLBACK_ARGS_ARM32_THUMB_H */
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_mips.h
|
||||
Description: Callback's Arguments VM - Header for MIPS
|
||||
License:
|
||||
|
||||
Copyright (c) 2013-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALLBACK_ARGS_MIPS_H
|
||||
#define DYNCALLBACK_ARGS_MIPS_H
|
||||
|
||||
#include "dyncall_args.h"
|
||||
|
||||
struct DCArgs
|
||||
{
|
||||
int ireg_data[8];
|
||||
float freg_data[8];
|
||||
int ireg_count;
|
||||
int freg_count;
|
||||
unsigned char* stackptr;
|
||||
};
|
||||
|
||||
#endif /* DYNCALLBACK_ARGS_MIPS_H */
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_ppc32.h
|
||||
Description: Callback's Arguments VM - Header for ppc32
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNCALLBACK_ARGS_PPC32_H
|
||||
#define DYNCALLBACK_ARGS_PPC32_H
|
||||
|
||||
#include "dyncall_args.h"
|
||||
|
||||
/* Common Args iterator for Apple and System V ABI. */
|
||||
|
||||
struct DCArgs
|
||||
{
|
||||
int ireg_data[8]; /* offset: 0 size: 4*8 = 32 */
|
||||
double freg_data[13]; /* offset: 32 size: 8*13= 104 */
|
||||
unsigned char* stackptr; /* offset: 136 size: 4 */
|
||||
int ireg_count; /* offset: 140 size: 4 */
|
||||
int freg_count; /* offset: 144 size: 4 */
|
||||
}; /* total size: 148 */
|
||||
|
||||
#endif /* DYNCALLBACK_ARGS_PPC32_H */
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_ppc64.h
|
||||
Description: Callback's Arguments VM - Header for ppc64
|
||||
License:
|
||||
|
||||
Copyright (c) 2014-2015 Masanori Mitsugi <mitsugi@linux.vnet.ibm.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNCALLBACK_ARGS_PPC64_H
|
||||
#define DYNCALLBACK_ARGS_PPC64_H
|
||||
|
||||
#include "dyncall_args.h"
|
||||
|
||||
struct DCArgs
|
||||
{
|
||||
long long ireg_data[8];
|
||||
double freg_data[13];
|
||||
unsigned char* stackptr;
|
||||
int ireg_count;
|
||||
int freg_count;
|
||||
};
|
||||
|
||||
#endif /* DYNCALLBACK_ARGS_PPC64_H */
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_sparc32.h
|
||||
Description: Callback's Arguments VM - Header for sparc32
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALLBACK_ARGS_SPARC32_H
|
||||
#define DYNCALLBACK_ARGS_SPARC32_H
|
||||
|
||||
#include "dyncall_args.h"
|
||||
|
||||
struct DCArgs
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
#endif /* DYNCALLBACK_ARGS_SPARC32_H */
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_sparc64.h
|
||||
Description: Callback's Arguments VM - Header for sparc32 - not yet
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALLBACK_ARGS_SPARC64_H
|
||||
#define DYNCALLBACK_ARGS_SPARC64_H
|
||||
|
||||
#include "dyncall_args.h"
|
||||
|
||||
struct DCArgs
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
#endif /* DYNCALLBACK_ARGS_SPARC64_H */
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_x64.h
|
||||
Description: Callback's Arguments VM - Header for x64
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALLBACK_ARGS_X64_H
|
||||
#define DYNCALLBACK_ARGS_X64_H
|
||||
|
||||
#include "dyncall_args.h"
|
||||
#include "dyncall_callvm_x64.h" /* reuse structures */
|
||||
|
||||
|
||||
struct DCArgs
|
||||
{
|
||||
/* state */
|
||||
int64* stack_ptr;
|
||||
DCRegCount_x64 reg_count; /* @@@ win64 version should maybe force alignment to 8 in order to be secure */
|
||||
|
||||
/* reg data */
|
||||
DCRegData_x64_s reg_data;
|
||||
};
|
||||
|
||||
#endif /* DYNCALLBACK_ARGS_X64_H */
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_args_x86.h
|
||||
Description: Callback's Arguments VM - Header for x86
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef DYNCALL_ARGS_X86_H_
|
||||
#define DYNCALL_ARGS_X86_H_
|
||||
|
||||
#include "dyncall_args.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DCint (*i32)(DCArgs*);
|
||||
DClonglong (*i64)(DCArgs*);
|
||||
DCfloat (*f32)(DCArgs*);
|
||||
DCdouble (*f64)(DCArgs*);
|
||||
} DCArgsVT;
|
||||
|
||||
extern DCArgsVT dcArgsVT_default;
|
||||
extern DCArgsVT dcArgsVT_this_ms;
|
||||
extern DCArgsVT dcArgsVT_fast_ms;
|
||||
extern DCArgsVT dcArgsVT_fast_gnu;
|
||||
|
||||
struct DCArgs
|
||||
{
|
||||
/* callmode */
|
||||
DCArgsVT* vt;
|
||||
|
||||
/* state */
|
||||
int* stack_ptr;
|
||||
|
||||
/* fast data / 'this-ptr' info */
|
||||
int fast_data[2];
|
||||
int fast_count;
|
||||
};
|
||||
|
||||
#endif /* DYNCALL_ARGS_X86_H_ */
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback.h
|
||||
Description: Callback - Interface
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_H
|
||||
#define DYNCALL_CALLBACK_H
|
||||
|
||||
#include "dyncall_args.h"
|
||||
#include "dyncall_signature.h"
|
||||
#include "dyncall_value.h"
|
||||
|
||||
typedef struct DCCallback DCCallback;
|
||||
|
||||
// TODO: return value is the type encoded as a signature char (character of the set [vBcCsSiIjJlLfd]).
|
||||
|
||||
typedef char (DCCallbackHandler)(DCCallback* pcb, DCArgs* args, DCValue* result, void* userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DCCallback* dcbNewCallback(const char* signature, DCCallbackHandler* funcptr, void* userdata);
|
||||
void dcbInitCallback(DCCallback* pcb, const char* signature, DCCallbackHandler* handler, void* userdata);
|
||||
void dcbFreeCallback(DCCallback* pcb);
|
||||
void* dcbGetUserData (DCCallback* pcb);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_H */
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback_arm32_arm.h
|
||||
Description: Callback - Header for ARM32 (ARM mode)
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_ARM32_ARM_H_
|
||||
#define DYNCALL_CALLBACK_ARM32_ARM_H_
|
||||
|
||||
#include "dyncall_callback.h"
|
||||
|
||||
#include "dyncall_thunk.h"
|
||||
#include "dyncall_args_arm32_arm.h"
|
||||
|
||||
|
||||
struct DCCallback
|
||||
{
|
||||
DCThunk thunk; // offset 0
|
||||
DCCallbackHandler* handler; // offset 12
|
||||
void* userdata; // offset 16
|
||||
};
|
||||
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_ARM32_ARM_H_ */
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback_arm32_thumb.h
|
||||
Description: Callback - Header for ARM32 (THUMB mode)
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_ARM32_THUMB_H_
|
||||
#define DYNCALL_CALLBACK_ARM32_THUMB_H_
|
||||
|
||||
#include "dyncall_callback_arm32_arm.h" /* Uses same code as ARM mode. */
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_ARM32_THUMB_H_ */
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback_mips.h
|
||||
Description: Callback - Header for MIPS
|
||||
License:
|
||||
|
||||
Copyright (c) 2013-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_MIPS_H
|
||||
#define DYNCALL_CALLBACK_MIPS_H
|
||||
|
||||
#include "dyncall_callback.h"
|
||||
|
||||
#include "dyncall_thunk.h"
|
||||
#include "dyncall_args_mips.h"
|
||||
|
||||
struct DCCallback
|
||||
{
|
||||
DCThunk thunk; /* offset 0, size 20 */
|
||||
DCCallbackHandler* handler; /* offset 20, size 4 */
|
||||
void* userdata; /* offset 24, size 4 */
|
||||
};
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_MIPS_H */
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback_ppc32.h
|
||||
Description: Callback - Header for ppc32
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_PPC32_H
|
||||
#define DYNCALL_CALLBACK_PPC32_H
|
||||
|
||||
#include "dyncall_callback.h"
|
||||
|
||||
#include "dyncall_thunk.h"
|
||||
#include "dyncall_args_ppc32.h"
|
||||
|
||||
struct DCCallback
|
||||
{
|
||||
DCThunk thunk; /* offset 0, size 24 */
|
||||
DCCallbackHandler* handler; /* offset 24, size 4 */
|
||||
size_t stack_cleanup; /* offset 28, size 4 */
|
||||
void* userdata; /* offset 32, size 4 */
|
||||
}; /* total size 36 */
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_PPC32_H */
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback_ppc64.h
|
||||
Description: Callback - Header for ppc64
|
||||
License:
|
||||
|
||||
Copyright (c) 2014-2015 Masanori Mitsugi <mitsugi@linux.vnet.ibm.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_PPC64_H
|
||||
#define DYNCALL_CALLBACK_PPC64_H
|
||||
|
||||
#include "dyncall_callback.h"
|
||||
|
||||
#include "dyncall_thunk.h"
|
||||
#include "dyncall_args_ppc64.h"
|
||||
|
||||
/*
|
||||
ELF v2
|
||||
thunk : offset 0, size 48
|
||||
handler : offset 48, size 8
|
||||
stack_cleanup : offset 56, size 8
|
||||
userdata : offset 64, size 8
|
||||
|
||||
ELF v1
|
||||
thunk : offset 0, size 64
|
||||
handler : offset 64, size 8
|
||||
stack_cleanup : offset 72, size 8
|
||||
userdata : offset 80, size 8
|
||||
*/
|
||||
|
||||
struct DCCallback
|
||||
{
|
||||
DCThunk thunk;
|
||||
DCCallbackHandler* handler;
|
||||
size_t stack_cleanup;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_PPC64_H */
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback_sparc32.h
|
||||
Description: Callback - Header for sparc32
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_SPARC32_H
|
||||
#define DYNCALL_CALLBACK_SPARC32_H
|
||||
|
||||
#include "dyncall_callback.h"
|
||||
|
||||
#include "dyncall_thunk.h"
|
||||
#include "dyncall_args_sparc32.h"
|
||||
|
||||
struct DCCallback
|
||||
{
|
||||
DCThunk thunk; /* offset 0, size ?? */
|
||||
DCCallbackHandler* handler; /* offset ??, size 4 */
|
||||
size_t stack_cleanup; /* offset ??, size 4 */
|
||||
void* userdata; /* offset ??, size 4 */
|
||||
};
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_SPARC32_H */
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback_x64.h
|
||||
Description: Callback - Header for x64
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_X64_H_
|
||||
#define DYNCALL_CALLBACK_X64_H_
|
||||
|
||||
#include "dyncall_callback.h"
|
||||
|
||||
#include "dyncall_thunk.h"
|
||||
#include "dyncall_args_x64.h"
|
||||
|
||||
|
||||
struct DCCallback
|
||||
{
|
||||
DCThunk thunk; // offset 0, size 24
|
||||
DCCallbackHandler* handler; // offset 24
|
||||
void* userdata; // offset 32
|
||||
};
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_X64_H_ */
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncallback
|
||||
File: dyncallback/dyncall_callback_x86.h
|
||||
Description: Callback - Header for x86
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef DYNCALL_CALLBACK_X86_H_
|
||||
#define DYNCALL_CALLBACK_X86_H_
|
||||
|
||||
#include "dyncall_callback.h"
|
||||
|
||||
#include "dyncall_thunk.h"
|
||||
#include "dyncall_args_x86.h"
|
||||
|
||||
struct DCCallback
|
||||
{
|
||||
DCThunk thunk; /* offset 0, size 16 */
|
||||
DCCallbackHandler* handler; /* offset 16 */
|
||||
DCArgsVT* args_vt; /* offset 20 */
|
||||
size_t stack_cleanup; /* offset 24 */
|
||||
void* userdata; /* offset 28 */
|
||||
};
|
||||
|
||||
int dcCleanupSize_x86_cdecl (const char* args_signature);
|
||||
int dcCleanupSize_x86_std (const char* args_signature);
|
||||
int dcCleanupSize_x86_fast_ms (const char* args_signature);
|
||||
int dcCleanupSize_x86_fast_gnu(const char* args_signature);
|
||||
|
||||
#endif /* DYNCALL_CALLBACK_X86_H_ */
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncall
|
||||
File: dyncall/dyncall_callf.h
|
||||
Description: formatted call interface to dyncall
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
dyncall formatted calls C API
|
||||
|
||||
REVISION
|
||||
2007/12/11 initial
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALL_CALLF_H
|
||||
#define DYNCALL_CALLF_H
|
||||
|
||||
/* dyncall formatted calls */
|
||||
|
||||
#include "dyncall.h"
|
||||
#include "dyncall_signature.h"
|
||||
#include "dyncall_value.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void dcArgF (DCCallVM* vm, const DCsigchar* signature, ...);
|
||||
void dcVArgF(DCCallVM* vm, const DCsigchar* signature, va_list args);
|
||||
|
||||
void dcCallF (DCCallVM* vm, DCValue* result, DCpointer funcptr, const DCsigchar* signature, ...);
|
||||
void dcVCallF(DCCallVM* vm, DCValue* result, DCpointer funcptr, const DCsigchar* signature, va_list args);
|
||||
|
||||
#endif /* DYNCALL_CALLF_H */
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncall
|
||||
File: dyncall/dyncall_config.h
|
||||
Description: Macro configuration file for non-standard C types
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
dyncall type configuration
|
||||
|
||||
REVISION
|
||||
2007/12/11 initial
|
||||
|
||||
*/
|
||||
|
||||
#ifndef DYNCALL_CONFIG_H
|
||||
#define DYNCALL_CONFIG_H
|
||||
|
||||
#include "dyncall_macros.h"
|
||||
|
||||
#define DC_BOOL int
|
||||
#define DC_LONG_LONG long long
|
||||
#define DC_POINTER void*
|
||||
|
||||
#endif /* DYNCALL_CONFIG_H */
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncall
|
||||
File: dyncall/dyncall_macros.h
|
||||
Description: Platform detection macros
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
dyncall macros
|
||||
|
||||
Platform detection, specific defines and configuration.
|
||||
The purpose of this file is to provide coherent platform and compiler
|
||||
specific defines. So instead of defines like WIN32, _OpenBSD_ or
|
||||
__GNUC__, one should use DC__OS_Win32, DC__OS_OpenBSD or DC__C_GNU,
|
||||
respectively.
|
||||
|
||||
REVISION
|
||||
2007/12/11 initial
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALL_MACROS_H
|
||||
#define DYNCALL_MACROS_H
|
||||
|
||||
|
||||
/* Platform specific defines. */
|
||||
|
||||
/* MS Windows XP x64/Vista64 or later. */
|
||||
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
|
||||
#define DC__OS_Win64
|
||||
|
||||
/* MS Windows NT/95/98/ME/2000/XP/Vista32. */
|
||||
#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__WINDOWS__) || defined(_WINDOWS)
|
||||
#define DC__OS_Win32
|
||||
|
||||
/* All the OS' based on Darwin OS (MacOS X, OpenDarwin). Note that '__APPLE__' may be defined for classic MacOS, too. */
|
||||
/* __MACOSX__ is not defined in gcc assembler mode (switch: -S) */
|
||||
/* @@@ TODO: Check for Classic OS */
|
||||
|
||||
#elif defined(__APPLE__) || defined(__Darwin__)
|
||||
# define DC__OS_Darwin
|
||||
# if defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
|
||||
# define DC__OS_IPhone
|
||||
# else /* defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) */
|
||||
# define DC__OS_MacOSX
|
||||
# endif
|
||||
|
||||
/* The most popular open source Unix-like OS - Linux. */
|
||||
#elif defined(__linux__) || defined(__linux) || defined(__gnu_linux__)
|
||||
#define DC__OS_Linux
|
||||
|
||||
/* The most powerful open source Unix-like OS - FreeBSD. */
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#define DC__OS_FreeBSD
|
||||
|
||||
/* The most secure open source Unix-like OS - OpenBSD. */
|
||||
#elif defined(__OpenBSD__)
|
||||
#define DC__OS_OpenBSD
|
||||
|
||||
/* The most portable open source Unix-like OS - NetBSD. */
|
||||
#elif defined(__NetBSD__)
|
||||
#define DC__OS_NetBSD
|
||||
|
||||
/* The FreeBSD fork having heavy clusterization in mind - DragonFlyBSD. */
|
||||
#elif defined(__DragonFly__)
|
||||
#define DC__OS_DragonFlyBSD
|
||||
|
||||
/* Sun's Unix-like OS - SunOS / Solaris. */
|
||||
#elif defined(__sun__) || defined(__sun) || defined(sun)
|
||||
#define DC__OS_SunOS
|
||||
|
||||
/* The "Linux-like environment for Windows" - Cygwin. */
|
||||
#elif defined(__CYGWIN__)
|
||||
#define DC__OS_Cygwin
|
||||
|
||||
/* The "Minimalist GNU for Windows" - MinGW. */
|
||||
#elif defined(__MINGW__)/*@@@*/
|
||||
#define DC__OS_MinGW
|
||||
|
||||
/* The Nintendo DS (homebrew) using devkitpro. */
|
||||
#elif defined(__nds__)
|
||||
#define DC__OS_NDS
|
||||
|
||||
/* The PlayStation Portable (homebrew) SDK. */
|
||||
#elif defined(__psp__) || defined(PSP)
|
||||
#define DC__OS_PSP
|
||||
|
||||
/* Haiku (BeOS alike). */
|
||||
#elif defined(__HAIKU__)
|
||||
#define DC__OS_BeOS
|
||||
|
||||
/* The Unix successor - Plan9 from Bell Labs */
|
||||
#elif defined(Plan9) || defined(__Plan9__)
|
||||
#define DC__OS_Plan9
|
||||
|
||||
/* Digital's Unix-like OS - VMS */
|
||||
#elif defined(__vms)
|
||||
#define DC__OS_VMS
|
||||
|
||||
#elif defined(__minix)
|
||||
#define DC__OS_Minix
|
||||
|
||||
#else
|
||||
#error Unsupported OS.
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Compiler specific defines. Do not change the order, because */
|
||||
/* some of the compilers define flags for compatible ones, too. */
|
||||
|
||||
/* Intel's C/C++ compiler. */
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#define DC__C_Intel
|
||||
|
||||
/* MS C/C++ compiler. */
|
||||
#elif defined(_MSC_VER)
|
||||
#define DC__C_MSVC
|
||||
|
||||
/* LLVM clang. */
|
||||
#elif defined(__clang__)
|
||||
#define DC__C_CLANG
|
||||
|
||||
/* The GNU Compiler Collection - GCC. */
|
||||
#elif defined(__GNUC__)
|
||||
#define DC__C_GNU
|
||||
|
||||
/* Watcom compiler. */
|
||||
#elif defined(__WATCOMC__)
|
||||
#define DC__C_WATCOM
|
||||
|
||||
/* Portable C Compiler. */
|
||||
#elif defined(__PCC__)
|
||||
#define DC__C_PCC
|
||||
|
||||
/* Sun Pro C. */
|
||||
#elif defined(__SUNPRO_C)
|
||||
#define DC__C_SUNPRO
|
||||
|
||||
/* Undetected C Compiler. */
|
||||
#else
|
||||
#define DC__C_UNKNOWN
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Architecture. */
|
||||
|
||||
/* Check architecture. */
|
||||
#if defined(_M_X64_) || defined(_M_AMD64) || defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||
# define DC__Arch_AMD64
|
||||
#elif defined(_M_IX86) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__386__) || defined(__i386)
|
||||
# define DC__Arch_Intel_x86
|
||||
#elif defined(_M_IA64) || defined(__ia64__)
|
||||
# define DC__Arch_Itanium
|
||||
#elif defined(_M_PPC) || defined(__powerpc__) || defined(__powerpc) || defined(__POWERPC__) || defined(__ppc__) || defined(__power__)
|
||||
# if defined(__ppc64__) || defined(_ARCH_PPC64) || defined(__power64__) || defined(__powerpc64__)
|
||||
# define DC__Arch_PPC64
|
||||
# else
|
||||
# define DC__Arch_PPC32
|
||||
# endif
|
||||
#elif defined(__mips64__) || defined(__mips64)
|
||||
# define DC__Arch_MIPS64
|
||||
#elif defined(_M_MRX000) || defined(__mips__) || defined(__mips) || defined(_mips)
|
||||
# define DC__Arch_MIPS
|
||||
#elif defined(__arm__)
|
||||
# define DC__Arch_ARM
|
||||
#elif defined(__aarch64__)
|
||||
# define DC__Arch_ARM64
|
||||
#elif defined(__sh__)
|
||||
# define DC__Arch_SuperH
|
||||
#elif defined(__sparcv9) || defined(__sparc64__) || ( defined(__sparc) && defined(__arch64__) )
|
||||
/* this could be needed on Linux/GNU sparc64 in the future: || ( defined(__sparc) && defined(__arch64__) ) */
|
||||
# define DC__Arch_Sparcv9
|
||||
#elif defined(__sparc)
|
||||
# define DC__Arch_Sparc
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Rough OS classification. */
|
||||
|
||||
#if defined(DC__OS_Win32) || defined(DC__OS_Win64)
|
||||
# define DC_WINDOWS
|
||||
#elif defined(DC__OS_Plan9)
|
||||
# define DC_PLAN9
|
||||
#elif defined(DC__OS_NDS) || defined(DC__OS_PSP)
|
||||
# define DC_OTHER
|
||||
#else
|
||||
# define DC_UNIX
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Misc machine-dependent modes, ABIs, etc.. */
|
||||
|
||||
#if defined(__arm__) && !defined(__thumb__)
|
||||
# define DC__Arch_ARM_ARM
|
||||
#elif defined(__arm__) && defined(__thumb__)
|
||||
# define DC__Arch_ARM_THUMB
|
||||
#endif
|
||||
|
||||
#if defined(DC__Arch_ARM_ARM) || defined(DC__Arch_ARM_THUMB)
|
||||
# if defined(__ARM_EABI__) || defined(DC__OS_NDS)
|
||||
# if defined (__ARM_PCS_VFP) && (__ARM_PCS_VFP == 1)
|
||||
# define DC__ABI_ARM_HF
|
||||
# else
|
||||
# define DC__ABI_ARM_EABI
|
||||
# endif
|
||||
# elif defined(__APCS_32__)
|
||||
# define DC__ABI_ARM_OABI
|
||||
# endif
|
||||
#endif /* ARM */
|
||||
|
||||
#if defined(DC__Arch_MIPS) || defined(DC__Arch_MIPS64)
|
||||
# if defined(_ABIO32) || defined(_MIPS_ARCH_MIPS1) || defined(_MIPS_ARCH_MIPS2)
|
||||
# define DC__ABI_MIPS_O32
|
||||
# elif defined(_ABIN32)
|
||||
# define DC__ABI_MIPS_N32
|
||||
# elif defined(_ABI64)
|
||||
# define DC__ABI_MIPS_N64
|
||||
# else
|
||||
# define DC__ABI_MIPS_EABI
|
||||
# endif
|
||||
#endif /* MIPS */
|
||||
|
||||
#if defined(DC__Arch_PPC64)
|
||||
# if defined(_CALL_ELF)
|
||||
# define DC__ABI_PPC64_ELF_V _CALL_ELF
|
||||
# else
|
||||
# define DC__ABI_PPC64_ELF_V 0 /* 0 means not explicitly set, otherwise this is 1 (big endian) and 2 (little endian) */
|
||||
# endif
|
||||
#endif /* MIPS */
|
||||
|
||||
|
||||
/* Endian detection. */
|
||||
#if defined(DC__Arch_Intel_x86) || defined(DC__Arch_AMD64) /* always little */
|
||||
# define DC__Endian_LITTLE
|
||||
#elif defined(DC__Arch_Sparc) /*always big until v9*/
|
||||
# define DC__Endian_BIG
|
||||
#else /* all others are bi-endian */
|
||||
/* @@@check flags used on following bi-endianness archs:
|
||||
DC__Arch_ARM
|
||||
DC__Arch_ARM64
|
||||
DC__Arch_Itanium
|
||||
DC__Arch_MIPS
|
||||
DC__Arch_MIPS64
|
||||
DC__Arch_PPC32
|
||||
DC__Arch_PPC64
|
||||
DC__Arch_Sparcv9
|
||||
DC__Arch_SuperH
|
||||
*/
|
||||
# if (defined(DC__Arch_PPC64) && (DC__ABI_PPC64_ELF_V == 1)) || defined(_BIG_ENDIAN) || defined(MIPSEB)
|
||||
# define DC__Endian_BIG
|
||||
# elif (defined(DC__Arch_PPC64) && (DC__ABI_PPC64_ELF_V == 2)) || defined(_LITTLE_ENDIAN) || defined(MIPSEL)
|
||||
# define DC__Endian_LITTLE
|
||||
# endif /* no else, leave unset if not sure */
|
||||
#endif
|
||||
|
||||
|
||||
/* Internal macro/tag. */
|
||||
#if !defined(DC_API)
|
||||
#define DC_API
|
||||
#endif
|
||||
|
||||
#endif /* DYNCALL_MACROS_H */
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
|
||||
Package: dyncall
|
||||
Library: dyncall
|
||||
File: dyncall/dyncall_signature.h
|
||||
Description: Type and calling-convention signature character defines
|
||||
License:
|
||||
|
||||
Copyright (c) 2007-2015 Daniel Adler <dadler@uni-goettingen.de>,
|
||||
Tassilo Philipp <tphilipp@potion-studios.com>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
dyncall signature characters
|
||||
|
||||
REVISION
|
||||
2007/12/11 initial
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DYNCALL_SIGNATURE_H
|
||||
#define DYNCALL_SIGNATURE_H
|
||||
|
||||
typedef char DCsigchar;
|
||||
|
||||
#define DC_SIGCHAR_VOID 'v'
|
||||
#define DC_SIGCHAR_BOOL 'B'
|
||||
#define DC_SIGCHAR_CHAR 'c'
|
||||
#define DC_SIGCHAR_UCHAR 'C'
|
||||
#define DC_SIGCHAR_SHORT 's'
|
||||
#define DC_SIGCHAR_USHORT 'S'
|
||||
#define DC_SIGCHAR_INT 'i'
|
||||
#define DC_SIGCHAR_UINT 'I'
|
||||
#define DC_SIGCHAR_LONG 'j'
|
||||
#define DC_SIGCHAR_ULONG 'J'
|
||||
#define DC_SIGCHAR_LONGLONG 'l'
|
||||
#define DC_SIGCHAR_ULONGLONG 'L'
|
||||
#define DC_SIGCHAR_FLOAT 'f'
|
||||
#define DC_SIGCHAR_DOUBLE 'd'
|
||||
#define DC_SIGCHAR_POINTER 'p'
|
||||
#define DC_SIGCHAR_STRING 'Z'
|
||||
#define DC_SIGCHAR_STRUCT 'T'
|
||||
#define DC_SIGCHAR_ENDARG ')' /* also works for end struct */
|
||||
|
||||
/* callback signatures */
|
||||
|
||||
#define DC_SIGCHAR_CC_PREFIX '_'
|
||||
#define DC_SIGCHAR_CC_ELLIPSIS 'e'
|
||||
#define DC_SIGCHAR_CC_STDCALL 's'
|
||||
#define DC_SIGCHAR_CC_FASTCALL_GNU 'f'
|
||||
#define DC_SIGCHAR_CC_FASTCALL_MS 'F'
|
||||
#define DC_SIGCHAR_CC_THISCALL_MS '+'
|
||||
|
||||
#endif /* DYNCALL_SIGNATURE_H */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user