Compare commits
458
Commits
master
..
2d79790d83
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d79790d83 | ||
|
|
a351d2eb41 | ||
|
|
0424ca62f2 | ||
|
|
83d5ddff9d | ||
|
|
b600361278 | ||
|
|
9d29a1c187 | ||
|
|
20207e6040 | ||
|
|
ef6a7be285 | ||
|
|
df84d1605d | ||
|
|
88a5adaa0a | ||
|
|
e6e1ae0223 | ||
|
|
05f0197d50 | ||
|
|
e34c2b0cef | ||
|
|
c2f4686bc4 | ||
|
|
c19c60fe22 | ||
|
|
d72485a137 | ||
|
|
e9e8751981 | ||
|
|
781c2dc53c | ||
|
|
38b9b7df10 | ||
|
|
a2cf5f2284 | ||
|
|
38a20bd97a | ||
|
|
fcefe9f827 | ||
|
|
56cdb9557d | ||
|
|
166f06d1fb | ||
|
|
24533dfe7f | ||
|
|
8408f400c8 | ||
|
|
48574d634c | ||
|
|
ad3e58d455 | ||
|
|
0dc020c429 | ||
|
|
2e70d33364 | ||
|
|
b0f314c9e3 | ||
|
|
1276c565da | ||
|
|
955d92bcc7 | ||
|
|
4e330de1d5 | ||
|
|
77b337aed8 | ||
|
|
b6ef63e817 | ||
|
|
e6414908b7 | ||
|
|
55eecf3177 | ||
|
|
12ac285456 | ||
|
|
a911707613 | ||
|
|
3e7f09f33f | ||
|
|
4b55faa41e | ||
|
|
720fdd9f34 | ||
|
|
76d52d9e1c | ||
|
|
c74c256968 | ||
|
|
aa5b51b88c | ||
|
|
cf72182d56 | ||
|
|
2e9147c47d | ||
|
|
f7f2aafc56 | ||
|
|
7eec390752 | ||
|
|
0c7a424f5e | ||
|
|
6aaff7573a | ||
|
|
70858fdec5 | ||
|
|
a94b914e06 | ||
|
|
fd842a1f70 | ||
|
|
872c46c43d | ||
|
|
a79f11d137 | ||
|
|
3b48954bc1 | ||
|
|
9884ba7dab | ||
|
|
78ea184868 | ||
|
|
a2b081ec15 | ||
|
|
c139c44503 | ||
|
|
8370a2ae67 | ||
|
|
1590f12b43 | ||
|
|
3180625a41 | ||
|
|
d2ca655178 | ||
|
|
c57eedce49 | ||
|
|
bc9be4927b | ||
|
|
a1282af0b5 | ||
|
|
46c109dce4 | ||
|
|
abb2cfb1c4 | ||
|
|
9ddfed92ff | ||
|
|
c4419490b6 | ||
|
|
20422d9023 | ||
|
|
2c29df0171 | ||
|
|
8fc1081cef | ||
|
|
556b05cb78 | ||
|
|
4a1554ce28 | ||
|
|
542b0f0a0a | ||
|
|
101e844ac5 | ||
|
|
dec70c10e7 | ||
|
|
7a5d949a12 | ||
|
|
93c1ba606a | ||
|
|
4871494c50 | ||
|
|
d7908bee54 | ||
|
|
fd8a319b18 | ||
|
|
d1d9b39200 | ||
|
|
6374f3cd1a | ||
|
|
e652d5b0e2 | ||
|
|
dc3861adfe | ||
|
|
a00f8acd9a | ||
|
|
46dcd1cc4e | ||
|
|
a5d99ffb9a | ||
|
|
daa0d2d4c4 | ||
|
|
92139cf799 | ||
|
|
ed9ec06eee | ||
|
|
f1e674ca37 | ||
|
|
35cc5ae48d | ||
|
|
9ea1e254e0 | ||
|
|
1c0063e834 | ||
|
|
afd4e1d21c | ||
|
|
2065c9ded7 | ||
|
|
bafe0af407 | ||
|
|
d0bc7bdc4a | ||
|
|
fbe34b2d40 | ||
|
|
e49838b974 | ||
|
|
7ed46b9724 | ||
|
|
41a05fb08c | ||
|
|
8f09e25710 | ||
|
|
a28c172ac1 | ||
|
|
b5772fa52c | ||
|
|
d4ac1dd817 | ||
|
|
5e51e2fbad | ||
|
|
a3e87b2508 | ||
|
|
eeb6caa58d | ||
|
|
212392386c | ||
|
|
a84a7073dc | ||
|
|
8cd754c923 | ||
|
|
225d1ffc06 | ||
|
|
f38c20b975 | ||
|
|
a0315f161c | ||
|
|
cac092a344 | ||
|
|
5fd790bd54 | ||
|
|
b60f846209 | ||
|
|
2b4a43ddc1 | ||
|
|
f125a38c50 | ||
|
|
40cb8582fd | ||
|
|
7db1fc7bd6 | ||
|
|
50e642483d | ||
|
|
915679b87b | ||
|
|
2ada434925 | ||
|
|
26c1180fad | ||
|
|
9cac98d961 | ||
|
|
c0877bfe1d | ||
|
|
5ce418995f | ||
|
|
7b21cba834 | ||
|
|
b3e95a705f | ||
|
|
da80e2c731 | ||
|
|
fcabf96347 | ||
|
|
2b48f30cfe | ||
|
|
3251df6068 | ||
|
|
d6dd7c9eab | ||
|
|
3fd728543c | ||
|
|
b4bc061b76 | ||
|
|
f10212f4a0 | ||
|
|
08a385b050 | ||
|
|
d5f903eaa2 | ||
|
|
26b0ba4828 | ||
|
|
90aaa375d0 | ||
|
|
a12a10ee0b | ||
|
|
97b1cf9e73 | ||
|
|
3aa4806515 | ||
|
|
4e1ae87a8e | ||
|
|
6bc8c549fc | ||
|
|
2137a0990e | ||
|
|
7f8b22ff43 | ||
|
|
d1e645b17e | ||
|
|
8bf32a557b | ||
|
|
93cfe71c21 | ||
|
|
65ef0b1b0f | ||
|
|
d98086d869 | ||
|
|
00c1f405c6 | ||
|
|
19546eea4d | ||
|
|
6d9792b1a6 | ||
|
|
47ec2b55c7 | ||
|
|
68ff6dc2b5 | ||
|
|
ad847a3eaa | ||
|
|
4564e7bbc2 | ||
|
|
3fb0c131f1 | ||
|
|
91ba202562 | ||
|
|
93530bd089 | ||
|
|
a7dc343fd6 | ||
|
|
4c179e3965 | ||
|
|
a5756ab2f5 | ||
|
|
95b7ded031 | ||
|
|
a004976c6b | ||
|
|
eecff81093 | ||
|
|
d47482bc04 | ||
|
|
4434cd5764 | ||
|
|
3488c71155 | ||
|
|
ad2efab7c8 | ||
|
|
28a9656db1 | ||
|
|
58db05fcb3 | ||
|
|
bfff188726 | ||
|
|
080669b5e9 | ||
|
|
161a9e3965 | ||
|
|
bb44eab406 | ||
|
|
b3b50715b4 | ||
|
|
2565cefe70 | ||
|
|
8e73057cfb | ||
|
|
74ab76344b | ||
|
|
38afbe8816 | ||
|
|
6d66986b5b | ||
|
|
327f352872 | ||
|
|
7b8b8c751d | ||
|
|
fe20d05e13 | ||
|
|
b036e48cee | ||
|
|
4aaae7773d | ||
|
|
1145a13987 | ||
|
|
f8c9e8fd3e | ||
|
|
f419ffd1ca | ||
|
|
fa99475912 | ||
|
|
6e61816e1c | ||
|
|
b552f73ac9 | ||
|
|
f0df0b69f0 | ||
|
|
f7100ae8ee | ||
|
|
e514c29de4 | ||
|
|
d81c403a5d | ||
|
|
956f2319b5 | ||
|
|
bb2c9a2f32 | ||
|
|
3928e2eb96 | ||
|
|
c4bc48bba1 | ||
|
|
8eb58e7dd8 | ||
|
|
e4af56e3eb | ||
|
|
331f75c7ab | ||
|
|
55465ad6de | ||
|
|
10f0d7dca2 | ||
|
|
c9aabdec68 | ||
|
|
da1def101b | ||
|
|
4d22995ea3 | ||
|
|
d3b89d22fb | ||
|
|
9215205aba | ||
|
|
7fc071154f | ||
|
|
e3c1bcb56e | ||
|
|
7e35e0cbed | ||
|
|
d59a8d9c8b | ||
|
|
605f3aa68d | ||
|
|
c6a415f642 | ||
|
|
edff7a4267 | ||
|
|
48bbef0b10 | ||
|
|
b267000394 | ||
|
|
c3bd96d5d6 | ||
|
|
28dbac4a35 | ||
|
|
22dc4be100 | ||
|
|
ffb38664b8 | ||
|
|
3f16888fe0 | ||
|
|
2b5f441e92 | ||
|
|
e761761108 | ||
|
|
324e5e1ea1 | ||
|
|
cc04fec1de | ||
|
|
b68b80f317 | ||
|
|
cfad821e8e | ||
|
|
815e3c9670 | ||
|
|
0c4dc62170 | ||
|
|
7655ece178 | ||
|
|
22899c2523 | ||
|
|
7f85f8348e | ||
|
|
ee863e3b09 | ||
|
|
1ebe8d9929 | ||
|
|
6c975b98a1 | ||
|
|
e4a248bb60 | ||
|
|
d382735b80 | ||
|
|
a42a4e435d | ||
|
|
f79fce83ca | ||
|
|
4c7f6340d6 | ||
|
|
f3059ec8ea | ||
|
|
4f12887a91 | ||
|
|
03b6b80568 | ||
|
|
cbf1cb8c4a | ||
|
|
7fc8e6e8bb | ||
|
|
48dc808dcb | ||
|
|
95dc31be91 | ||
|
|
55223b763a | ||
|
|
cff301499f | ||
|
|
4cdb8a986a | ||
|
|
0ae0c03775 | ||
|
|
d6378922cf | ||
|
|
6ce5fd59a3 | ||
|
|
b93cdd8f4c | ||
|
|
cadf7742ab | ||
|
|
5f8021c570 | ||
|
|
1b0d0520bc | ||
|
|
be99b0aabb | ||
|
|
2ab1917b73 | ||
|
|
111781dc71 | ||
|
|
7df09a9ebd | ||
|
|
7b13dff29c | ||
|
|
c48abbf5c9 | ||
|
|
12b459507a | ||
|
|
77a6cc5e53 | ||
|
|
978d2d603a | ||
|
|
01a0d5f05f | ||
|
|
0569d64cc9 | ||
|
|
f55f895cfd | ||
|
|
de7f084633 | ||
|
|
0c2683afaa | ||
|
|
d6b850178e | ||
|
|
a486a09d9e | ||
|
|
07a41e0266 | ||
|
|
052894a628 | ||
|
|
60f26ca40e | ||
|
|
d5e392c3bc | ||
|
|
8b00f15710 | ||
|
|
0ebe63eff3 | ||
|
|
9955181b0d | ||
|
|
477b485a34 | ||
|
|
03eece4e41 | ||
|
|
a43fe1789b | ||
|
|
1e0c5dac83 | ||
|
|
680c782a56 | ||
|
|
dfe8aa56e9 | ||
|
|
71494984de | ||
|
|
8117d043aa | ||
|
|
9d02d5ab78 | ||
|
|
7803bc87a6 | ||
|
|
27b322bf25 | ||
|
|
def8b6bdc2 | ||
|
|
ee6df45e2d | ||
|
|
a74409c3ec | ||
|
|
672a0b3561 | ||
|
|
48b918a551 | ||
|
|
4aa738fcc9 | ||
|
|
7eefa2e6c2 | ||
|
|
d4136ef0e3 | ||
|
|
469cf3dd24 | ||
|
|
2d60e795c0 | ||
|
|
754d6cd3bd | ||
|
|
d1b4053205 | ||
|
|
1cd5e71904 | ||
|
|
cb4f380313 | ||
|
|
93e0104c1e | ||
|
|
c9aed019d5 | ||
|
|
8b8229f73a | ||
|
|
039d2f9350 | ||
|
|
bb3044d168 | ||
|
|
8dace27f56 | ||
|
|
30932b0d7c | ||
|
|
afdd3834b9 | ||
|
|
02b63bf8d2 | ||
|
|
fb19abb69f | ||
|
|
1528ecac52 | ||
|
|
4cb892133f | ||
|
|
5864b060a9 | ||
|
|
0ebfedbf4d | ||
|
|
45c6495121 | ||
|
|
24ad9464b5 | ||
|
|
0f34416726 | ||
|
|
7249bbf92b | ||
|
|
5f18779f1d | ||
|
|
740b0f217f | ||
|
|
bc4fbfd28a | ||
|
|
37a0c73dc3 | ||
|
|
53e153a696 | ||
|
|
06082f2273 | ||
|
|
b1c123977d | ||
|
|
535b6d00c4 | ||
|
|
5594b55e5c | ||
|
|
9229135588 | ||
|
|
9f2aafb95e | ||
|
|
ce20a1d940 | ||
|
|
c2b2c2a6ae | ||
|
|
b2d9688fbe | ||
|
|
254407e89e | ||
|
|
a5069cd148 | ||
|
|
91d2db6116 | ||
|
|
4c9366d495 | ||
|
|
915620da34 | ||
|
|
5d3f1fcf08 | ||
|
|
9554160edc | ||
|
|
fc928da75b | ||
|
|
8c1118b429 | ||
|
|
846d4e7ab5 | ||
|
|
816c24c1b6 | ||
|
|
6ac1c8711c | ||
|
|
c9cd2e6c1e | ||
|
|
4c1630d61d | ||
|
|
ddbee2f0ec | ||
|
|
8de8938be1 | ||
|
|
675e4a10dd | ||
|
|
2b2cc9cf6c | ||
|
|
0b74fd81e3 | ||
|
|
941652b4bc | ||
|
|
2ba9d991bf | ||
|
|
ba5930b585 | ||
|
|
3868afce93 | ||
|
|
ba4ed9afff | ||
|
|
adeb2de366 | ||
|
|
0071136146 | ||
|
|
cd48094a18 | ||
|
|
e0ac9654c3 | ||
|
|
196d5353c8 | ||
|
|
e9783b2317 | ||
|
|
47d92dba14 | ||
|
|
24eeca8f79 | ||
|
|
f7ac92cd01 | ||
|
|
63bd416e7c | ||
|
|
e6b23b2a98 | ||
|
|
83bc33015d | ||
|
|
c660118f8b | ||
|
|
1ec217905d | ||
|
|
bd97ecb9eb | ||
|
|
9891a302ac | ||
|
|
37982e0448 | ||
|
|
22828c9d23 | ||
|
|
e3a176b2f9 | ||
|
|
30fa22aed5 | ||
|
|
0dd6289509 | ||
|
|
e23a7b9c02 | ||
|
|
b48cffd880 | ||
|
|
2f52c018cd | ||
|
|
143a88ac1d | ||
|
|
21df381d12 | ||
|
|
e7f53d2c07 | ||
|
|
a77a149664 | ||
|
|
0a75cde80c | ||
|
|
8250058296 | ||
|
|
d3c4c4cd02 | ||
|
|
aa41d9e15b | ||
|
|
186ec3c11d | ||
|
|
620954631a | ||
|
|
e0505dc974 | ||
|
|
ce13f83d46 | ||
|
|
1a420e2f22 | ||
|
|
d1f83fa669 | ||
|
|
4425db7ca3 | ||
|
|
ceecb6cc81 | ||
|
|
c8ad9222fd | ||
|
|
7e68e09b22 | ||
|
|
e3150f8203 | ||
|
|
93ef620448 | ||
|
|
ba711b7f14 | ||
|
|
0d3cb029d8 | ||
|
|
2807573012 | ||
|
|
8528bfefc1 | ||
|
|
d561883144 | ||
|
|
2dacc969a3 | ||
|
|
63adca1fac | ||
|
|
4dfa9b432e | ||
|
|
b8cdb49ea5 | ||
|
|
ffe1ca643e | ||
|
|
95cafa3200 | ||
|
|
784028c7a9 | ||
|
|
fcb4d361bc | ||
|
|
ceb9985242 | ||
|
|
03644c0561 | ||
|
|
7ef502f3b0 | ||
|
|
84f0b65fa9 | ||
|
|
66b9a5d15f | ||
|
|
e82edb89ae | ||
|
|
37518ed7b0 | ||
|
|
b76d825f55 | ||
|
|
10afbd3e4f | ||
|
|
c0d69521fe | ||
|
|
e54596809e | ||
|
|
6347b56751 | ||
|
|
48eca55a4c | ||
|
|
5ba9975c10 | ||
|
|
7b818c5cde | ||
|
|
443e88b4a9 | ||
|
|
64540d2d36 | ||
|
|
94555d2a60 | ||
|
|
a329bc2424 | ||
|
|
b3b8a54f7f | ||
|
|
5539bbd3b9 | ||
|
|
b919678913 | ||
|
|
7fe6aa2a97 | ||
|
|
055be9b058 | ||
|
|
a75c8a2e4f |
+17
-14
@@ -1,16 +1,19 @@
|
||||
build/
|
||||
backup
|
||||
subl.bat
|
||||
multimedia.c
|
||||
multimedia.h
|
||||
playground.py
|
||||
ui_notes.txt
|
||||
run_linux.bat
|
||||
l.log
|
||||
vendor
|
||||
x64/Debug
|
||||
x64/Release
|
||||
.vs/
|
||||
|
||||
*.10x
|
||||
src/external/SDL/
|
||||
build/
|
||||
package/
|
||||
|
||||
*.rdbg
|
||||
*.spall
|
||||
*.sublime-workspace
|
||||
*.pdb
|
||||
te
|
||||
te_debug
|
||||
*.wasm
|
||||
*.o
|
||||
*sublime-project*
|
||||
*sublime-workspace*
|
||||
*.html
|
||||
text_editor.js
|
||||
*.map
|
||||
*.exe
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
@echo off
|
||||
|
||||
for %%a in (%*) do set "%%~a=1"
|
||||
|
||||
set common=-I ../src/ -g -fdiagnostics-absolute-paths -Wno-unsequenced -Wno-single-bit-bitfield-constant-conversion -Wall -Wno-missing-braces -Wextra -Wno-missing-field-initializers
|
||||
set wasm_flags=--target=wasm32 -nostdlib -mbulk-memory -msimd128 -Wl,-export-dynamic,--allow-undefined,--import-memory,--no-entry,--initial-memory=131072000,--max-memory=4294967296
|
||||
|
||||
if not exist build (
|
||||
mkdir build
|
||||
)
|
||||
pushd build
|
||||
if "%testing%"=="1" echo [testing] && set didbuild=1 && clang ../src/testing/testing_main.c -o testing.exe %common% || exit 1 /b
|
||||
if "%scratch%"=="1" echo [scratch] && set didbuild=1 && clang ../src/scratch/scratch_main.c -o ../src/scratch/main.wasm %common% %wasm_flags% || exit 1 /b
|
||||
popd
|
||||
cd build
|
||||
|
||||
if "%didbuild%"=="" (
|
||||
echo [WARNING] no valid build target specified
|
||||
exit /b 1
|
||||
)
|
||||
set flags=/EHsc- /MD /Zi /FC /nologo /WX /W3 /wd4200 /wd4334 /diagnostics:column -DDEBUG_BUILD=1
|
||||
|
||||
cl %flags% -Fe:metaprogram.exe -I../src ../src/metaprogram/metaprogram.cpp
|
||||
metaprogram.exe
|
||||
|
||||
set libs=../src/external/SDL/win32-static/SDL3-static.lib ../src/external/SDL/win32-static/SDL_uclibc.lib kernel32.lib gdi32.lib user32.lib Imm32.lib ole32.lib Shell32.lib OleAut32.lib Cfgmgr32.lib Setupapi.lib Advapi32.lib version.lib winmm.lib
|
||||
cl %flags% ../src/text_editor/text_editor.cpp -Fe:te.exe -I../src/external/SDL/include -I../src/external/lua/src -I../src/external/glad -I../src/ %libs% -link /SUBSYSTEM:WINDOWS /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:MSVCRTD
|
||||
|
||||
copy te.exe ..\data\te.exe
|
||||
copy te.pdb ..\data\te.pdb
|
||||
echo written ..\data\te.exe
|
||||
cd ..
|
||||
rem /fsanitize=address
|
||||
@@ -1,9 +1,81 @@
|
||||
cd "$(dirname "$0")"
|
||||
#!/usr/bin/bash
|
||||
|
||||
if [ ! -d build ]; then
|
||||
mkdir build
|
||||
fi
|
||||
cd build
|
||||
# clang ../src/testing/testing_main.c -o testing_main -I../src/ -ldl -lm -lbacktrace -g -Wall -Wextra -Wno-missing-braces -Wno-missing-field-initializers -Wno-single-bit-bitfield-constant-conversion -fdiagnostics-absolute-paths -Wno-writable-strings -Wno-unsequenced
|
||||
tcc $(realpath ../src/testing/testing_main.c) -o testing_main -I$(realpath ../src/) -b -g -ldl -lm -Wall -Wextra
|
||||
./testing_main
|
||||
|
||||
if [ "$1" = "release" ]; then
|
||||
profile_flags="-DDEBUG_BUILD=0 -O2"
|
||||
else
|
||||
profile_flags="-DDEBUG_BUILD=1"
|
||||
fi
|
||||
|
||||
if [ ! -f "lbaselib.o" ]; then
|
||||
clang -g -I../src/external/lua/src -I../src/external/glad \
|
||||
../src/external/lua/src/lbaselib.c \
|
||||
../src/external/lua/src/lctype.c \
|
||||
../src/external/lua/src/ldo.c \
|
||||
../src/external/lua/src/lgc.c \
|
||||
../src/external/lua/src/liolib.c \
|
||||
../src/external/lua/src/lmem.c \
|
||||
../src/external/lua/src/lopcodes.c \
|
||||
../src/external/lua/src/lstate.c \
|
||||
../src/external/lua/src/ltable.c \
|
||||
../src/external/lua/src/lundump.c \
|
||||
../src/external/lua/src/lzio.c \
|
||||
../src/external/lua/src/lapi.c \
|
||||
../src/external/lua/src/lcode.c \
|
||||
../src/external/lua/src/ldblib.c \
|
||||
../src/external/lua/src/ldump.c \
|
||||
../src/external/lua/src/llex.c \
|
||||
../src/external/lua/src/loadlib.c \
|
||||
../src/external/lua/src/loslib.c \
|
||||
../src/external/lua/src/lstring.c \
|
||||
../src/external/lua/src/ltablib.c \
|
||||
../src/external/lua/src/lutf8lib.c \
|
||||
../src/external/lua/src/lauxlib.c \
|
||||
../src/external/lua/src/lcorolib.c \
|
||||
../src/external/lua/src/ldebug.c \
|
||||
../src/external/lua/src/lfunc.c \
|
||||
../src/external/lua/src/linit.c \
|
||||
../src/external/lua/src/lmathlib.c \
|
||||
../src/external/lua/src/lobject.c \
|
||||
../src/external/lua/src/lparser.c \
|
||||
../src/external/lua/src/lstrlib.c \
|
||||
../src/external/lua/src/ltm.c \
|
||||
../src/external/lua/src/lvm.c \
|
||||
../src/external/glad/glad.c \
|
||||
-c
|
||||
fi
|
||||
|
||||
if [ ! -f "metaprogram.exe" ]; then
|
||||
clang ../src/metaprogram/metaprogram.cpp ../src/basic/unix.cpp -o metaprogram.exe \
|
||||
-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g \
|
||||
-Wno-writable-strings \
|
||||
-I../src
|
||||
fi
|
||||
./metaprogram.exe
|
||||
|
||||
clang ../src/text_editor/text_editor.cpp ../src/basic/unix.cpp -o te_linux.exe \
|
||||
-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g \
|
||||
$profile_flags \
|
||||
-Wno-writable-strings \
|
||||
-I../src/external/SDL/include \
|
||||
-I../src/external/lua/src \
|
||||
-I../src/external/glad \
|
||||
-I../src/ \
|
||||
-lm \
|
||||
../src/external/SDL/build/libSDL3.a \
|
||||
lbaselib.o lctype.o ldo.o lgc.o liolib.o lmem.o \
|
||||
lopcodes.o lstate.o ltable.o lundump.o lzio.o lapi.o lcode.o ldblib.o ldump.o \
|
||||
llex.o loadlib.o loslib.o lstring.o ltablib.o lutf8lib.o lauxlib.o lcorolib.o ldebug.o \
|
||||
lfunc.o linit.o lmathlib.o lobject.o lparser.o lstrlib.o ltm.o lvm.o \
|
||||
glad.o \
|
||||
|
||||
|
||||
if [ "$1" = "release" ]; then
|
||||
cp te_linux.exe ../data/te
|
||||
echo written ../data/te
|
||||
else
|
||||
cp te_linux.exe ../data/te_debug
|
||||
echo written ../data/te_debug
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
|
||||
set incs=-Isrc/external/SDL/include -Isrc/external/lua/src -Isrc/external/glad -Lsrc/external/SDL/build_web -Isrc
|
||||
set wasmflags=-sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=1gb -msimd128 -sTOTAL_STACK=5MB -sINITIAL_MEMORY=256mb -sUSE_WEBGL2 -sFULL_ES3=1 -sASYNCIFY -sASSERTIONS=2
|
||||
set flags=-Wall -Wno-missing-braces -Wno-writable-strings -nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths
|
||||
set dbg=-g -DDEBUG_BUILD=1 -gsource-map
|
||||
set rel=-O3 -DDEBUG_BUILD=0
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
clang ../src/metaprogram/metaprogram.cpp -o metaprogram.exe %flags% -g -DDEBUG_BUILD=1 -I../src
|
||||
metaprogram.exe
|
||||
cd ..
|
||||
|
||||
emcc -o text_editor.html --shell-file=data/shell.html %flags% %incs% %wasmflags% %dbg% -lm -lSDL3 src/text_editor/text_editor.cpp
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
if [ ! -f "metaprogram.exe" ]; then
|
||||
clang ../src/metaprogram/metaprogram.cpp ../src/basic/unix.cpp -o metaprogram.exe \
|
||||
-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g \
|
||||
-Wno-writable-strings \
|
||||
-I../src
|
||||
fi
|
||||
./metaprogram.exe
|
||||
|
||||
emcc -o ../text_editor.html \
|
||||
-nostdlib++ -fno-exceptions -fdiagnostics-absolute-paths -g -gsource-map \
|
||||
--shell-file=../data/shell.html\
|
||||
$profile_flags \
|
||||
-Wno-writable-strings \
|
||||
-I../src/external/SDL/include \
|
||||
-I../src/external/lua/src \
|
||||
-I../src/external/glad \
|
||||
-I../src/ \
|
||||
-L../src/external/SDL/build_web \
|
||||
-lm \
|
||||
-lSDL3 \
|
||||
-s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=1gb -msimd128 -s TOTAL_STACK=5MB -s INITIAL_MEMORY=256mb \
|
||||
../src/text_editor/text_editor.cpp \
|
||||
../src/basic/unix.cpp \
|
||||
../src/external/lua/src/lbaselib.c \
|
||||
../src/external/lua/src/lctype.c \
|
||||
../src/external/lua/src/ldo.c \
|
||||
../src/external/lua/src/lgc.c \
|
||||
../src/external/lua/src/liolib.c \
|
||||
../src/external/lua/src/lmem.c \
|
||||
../src/external/lua/src/lopcodes.c \
|
||||
../src/external/lua/src/lstate.c \
|
||||
../src/external/lua/src/ltable.c \
|
||||
../src/external/lua/src/lundump.c \
|
||||
../src/external/lua/src/lzio.c \
|
||||
../src/external/lua/src/lapi.c \
|
||||
../src/external/lua/src/lcode.c \
|
||||
../src/external/lua/src/ldblib.c \
|
||||
../src/external/lua/src/ldump.c \
|
||||
../src/external/lua/src/llex.c \
|
||||
../src/external/lua/src/loadlib.c \
|
||||
../src/external/lua/src/loslib.c \
|
||||
../src/external/lua/src/lstring.c \
|
||||
../src/external/lua/src/ltablib.c \
|
||||
../src/external/lua/src/lutf8lib.c \
|
||||
../src/external/lua/src/lauxlib.c \
|
||||
../src/external/lua/src/lcorolib.c \
|
||||
../src/external/lua/src/ldebug.c \
|
||||
../src/external/lua/src/lfunc.c \
|
||||
../src/external/lua/src/linit.c \
|
||||
../src/external/lua/src/lmathlib.c \
|
||||
../src/external/lua/src/lobject.c \
|
||||
../src/external/lua/src/lparser.c \
|
||||
../src/external/lua/src/lstrlib.c \
|
||||
../src/external/lua/src/ltm.c \
|
||||
../src/external/lua/src/lvm.c \
|
||||
../src/external/glad/glad.c \
|
||||
|
||||
|
||||
cd ..
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1 @@
|
||||
id ICON "icon.ico"
|
||||
+481
@@ -0,0 +1,481 @@
|
||||
local GruvboxDark0Hard = 0x1d2021ff
|
||||
local GruvboxDark0 = 0x282828ff
|
||||
local GruvboxDark0Soft = 0x32302fff
|
||||
local GruvboxDark1 = 0x3c3836ff
|
||||
local GruvboxDark2 = 0x504945ff
|
||||
local GruvboxDark3 = 0x665c54ff
|
||||
local GruvboxDark4 = 0x7c6f64ff
|
||||
local GruvboxGray245 = 0x928374ff
|
||||
local GruvboxGray244 = 0x928374ff
|
||||
local GruvboxLight0Hard = 0xf9f5d7ff
|
||||
local GruvboxLight0 = 0xfbf1c7ff
|
||||
local GruvboxLight0Soft = 0xf2e5bcff
|
||||
local GruvboxLight1 = 0xebdbb2ff
|
||||
local GruvboxLight2 = 0xd5c4a1ff
|
||||
local GruvboxLight3 = 0xbdae93ff
|
||||
local GruvboxLight4 = 0xa89984ff
|
||||
local GruvboxBrightRed = 0xfb4934ff
|
||||
local GruvboxBrightGreen = 0xb8bb26ff
|
||||
local GruvboxBrightYellow = 0xfabd2fff
|
||||
local GruvboxBrightBlue = 0x83a598ff
|
||||
local GruvboxBrightPurple = 0xd3869bff
|
||||
local GruvboxBrightAqua = 0x8ec07cff
|
||||
local GruvboxBrightOrange = 0xfe8019ff
|
||||
local GruvboxNeutralRed = 0xcc241dff
|
||||
local GruvboxNeutralGreen = 0x98971aff
|
||||
local GruvboxNeutralYellow = 0xd79921ff
|
||||
local GruvboxNeutralBlue = 0x458588ff
|
||||
local GruvboxNeutralPurple = 0xb16286ff
|
||||
local GruvboxNeutralAqua = 0x689d6aff
|
||||
local GruvboxNeutralOrange = 0xd65d0eff
|
||||
local GruvboxFadedRed = 0x9d0006ff
|
||||
local GruvboxFadedGreen = 0x79740eff
|
||||
local GruvboxFadedYellow = 0xb57614ff
|
||||
local GruvboxFadedBlue = 0x076678ff
|
||||
local GruvboxFadedPurple = 0x8f3f71ff
|
||||
local GruvboxFadedAqua = 0x427b58ff
|
||||
local GruvboxFadedOrange = 0xaf3a03ff
|
||||
Color = {}
|
||||
Color.Text = GruvboxDark0Hard
|
||||
Color.LoadTextHighlight = 0x0000000F
|
||||
Color.Background = GruvboxLight0Hard
|
||||
Color.InactiveWindow = 0x0000000F
|
||||
Color.TextLineNumbers = GruvboxDark4
|
||||
Color.LineHighlight = GruvboxLight0Soft
|
||||
Color.MainCaret = GruvboxDark0Hard
|
||||
Color.SubCaret = GruvboxGray245
|
||||
Color.Selection = GruvboxLight1
|
||||
Color.WhitespaceDuringSelection = GruvboxLight4
|
||||
Color.MouseUnderline = GruvboxDark0Hard
|
||||
Color.CaretUnderline = GruvboxGray245
|
||||
Color.FuzzySearchLineHighlight = GruvboxDark0
|
||||
Color.ScrollbarBackground = GruvboxLight2
|
||||
Color.ScrollbarScroller = GruvboxLight1
|
||||
Color.ScrollbarScrollerSelected = GruvboxLight0Hard
|
||||
Color.TitleBarText = GruvboxDark2
|
||||
Color.TitleBarBackground = GruvboxLight1
|
||||
Color.TitleBarActiveBackground = 0xfefefefe
|
||||
Color.TitleBarSelection = GruvboxLight3
|
||||
Color.ResizerBackground = GruvboxLight0Hard
|
||||
Color.ResizerOutline = GruvboxLight3
|
||||
Style = {}
|
||||
Style.WaitForEvents = 1
|
||||
Style.DrawLineNumbers = 1
|
||||
Style.DrawScrollbar = 1
|
||||
Style.IndentSize = 4
|
||||
Style.FontSize = 15
|
||||
Style.Font = GetExeDir().."/CascadiaMono.ttf"
|
||||
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
|
||||
Style.TrimWhitespaceOnSave = true
|
||||
Style.ClangFormatOnSave = false
|
||||
Style.StyleUndoMergeTimeout = 0.3
|
||||
|
||||
INTERNET_BROWSER = 'C:/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe'
|
||||
OS_WINDOWS = 0
|
||||
OS_UNIX = 1
|
||||
|
||||
SDLK_CTRL = 1073742048
|
||||
SDLK_PAGE_DOWN = 1073741902
|
||||
SDLK_PAGE_UP = 1073741899
|
||||
SDLK_DOWN = 1073741905 -- 0x40000051
|
||||
SDLK_UP = 1073741906 -- 0x40000052u
|
||||
SDLK_RIGHT = 1073741903
|
||||
SDLK_LEFT = 1073741904
|
||||
SDLK_Q = 113
|
||||
SDLK_BACKSLASH = 0x5c
|
||||
SDLK_RETURN = 13
|
||||
|
||||
SDLK_EQUALS = 0x0000003d
|
||||
SDLK_MINUS = 0x0000002d
|
||||
|
||||
SDLK_F1 = 0x4000003a
|
||||
SDLK_F2 = 0x4000003b
|
||||
SDLK_F3 = 0x4000003c
|
||||
SDLK_F4 = 0x4000003d
|
||||
SDLK_F5 = 0x4000003e
|
||||
SDLK_F6 = 0x4000003f
|
||||
SDLK_F7 = 0x40000040
|
||||
SDLK_F8 = 0x40000041
|
||||
SDLK_F9 = 0x40000042
|
||||
SDLK_F10 = 0x40000043
|
||||
SDLK_F11 = 0x40000044
|
||||
SDLK_F12 = 0x40000045
|
||||
|
||||
SDLK_A = 0x00000061
|
||||
SDLK_B = 0x00000062
|
||||
SDLK_C = 0x00000063
|
||||
SDLK_D = 0x00000064
|
||||
SDLK_E = 0x00000065
|
||||
SDLK_F = 0x00000066
|
||||
SDLK_G = 0x00000067
|
||||
SDLK_H = 0x00000068
|
||||
SDLK_I = 0x00000069
|
||||
SDLK_J = 0x0000006a
|
||||
SDLK_K = 0x0000006b
|
||||
SDLK_L = 0x0000006c
|
||||
SDLK_M = 0x0000006d
|
||||
SDLK_N = 0x0000006e
|
||||
SDLK_O = 0x0000006f
|
||||
SDLK_P = 0x00000070
|
||||
SDLK_Q = 0x00000071
|
||||
SDLK_R = 0x00000072
|
||||
SDLK_S = 0x00000073
|
||||
SDLK_T = 0x00000074
|
||||
SDLK_U = 0x00000075
|
||||
SDLK_V = 0x00000076
|
||||
SDLK_W = 0x00000077
|
||||
SDLK_X = 0x00000078
|
||||
SDLK_Y = 0x00000079
|
||||
SDLK_Z = 0x0000007a
|
||||
|
||||
VERTICAL = 1
|
||||
HORIZONTAL = 2
|
||||
|
||||
function IsAlpha(a)
|
||||
if a == nil then
|
||||
return false
|
||||
end
|
||||
local x = string.byte(a)
|
||||
local result = (x >= string.byte('a') and x <= string.byte('z')) or (x >= string.byte('A') and x <= string.byte('Z'))
|
||||
return result
|
||||
end
|
||||
|
||||
function SkipLineAndColumn(s)
|
||||
local line, col = "-1", "-1"
|
||||
|
||||
function parse_line_and_column(line_and_col, delimiter)
|
||||
ic, jc = line_and_col:find(delimiter)
|
||||
line = line_and_col:sub(1, ic - 1)
|
||||
col = line_and_col:sub(ic + 1)
|
||||
return line, col
|
||||
end
|
||||
|
||||
do -- :line:column
|
||||
local i, j = s:find("^:%d+:%d+")
|
||||
if i then
|
||||
skip_pattern = s:sub(j + 1)
|
||||
line, col = parse_line_and_column(s:sub(2, j), ":")
|
||||
return line, col, skip_pattern
|
||||
end
|
||||
end
|
||||
|
||||
do -- :line
|
||||
local i, j = s:find("^:%d+")
|
||||
if i then
|
||||
skip_pattern = s:sub(j + 1)
|
||||
line = s:sub(2, j)
|
||||
return line, col, skip_pattern
|
||||
end
|
||||
end
|
||||
|
||||
do -- (line,column)
|
||||
local i, j = s:find("^%(%d+,%d+%)")
|
||||
if i then
|
||||
skip_pattern = s:sub(j + 1)
|
||||
line, col = parse_line_and_column(s:sub(2, j - 1), ",")
|
||||
return line, col, skip_pattern
|
||||
end
|
||||
end
|
||||
|
||||
do -- (line)
|
||||
local i, j = s:find("^%(%d+%)")
|
||||
if i then
|
||||
skip_pattern = s:sub(j + 1)
|
||||
line = s:sub(2, j - 1)
|
||||
return line, col, skip_pattern
|
||||
end
|
||||
end
|
||||
|
||||
return line, col, s
|
||||
end
|
||||
|
||||
function SkipSlashes(s)
|
||||
found_slash = false
|
||||
while s:sub(1,1) == '/' or s:sub(1,1) == '\\' do
|
||||
s = s:sub(2)
|
||||
found_slash = true
|
||||
end
|
||||
return s, found_slash
|
||||
end
|
||||
|
||||
function SkipDrive(s)
|
||||
local i, j = s:find("^%a:")
|
||||
if not i then
|
||||
return s, nil, true
|
||||
end
|
||||
|
||||
local drive = s:sub(i, j)
|
||||
local new_s = s:sub(j + 1)
|
||||
|
||||
new_s, found_slash = SkipSlashes(new_s)
|
||||
if not found_slash then
|
||||
return s, drive, false
|
||||
end
|
||||
|
||||
return new_s, drive, true
|
||||
end
|
||||
|
||||
function WindowsSkipPathCell(s)
|
||||
local i, j = s:find("^[%w_%.-% +]+")
|
||||
if not i then return s, nil, false end
|
||||
|
||||
local word = s:sub(i, j)
|
||||
local new_s = s:sub(j + 1)
|
||||
local new_s, found_slash = SkipSlashes(new_s)
|
||||
|
||||
return new_s, word, found_slash
|
||||
end
|
||||
|
||||
function WindowsSkipPath(s)
|
||||
local input_s = s
|
||||
local s, drive, ok = SkipDrive(s)
|
||||
if not ok then return s end
|
||||
|
||||
local cells = {}
|
||||
if drive ~= nil then
|
||||
table.insert(cells, drive)
|
||||
end
|
||||
|
||||
while true do
|
||||
s, word, slash_eaten = WindowsSkipPathCell(s)
|
||||
if word then cells[#cells + 1] = word end
|
||||
if not slash_eaten then break end
|
||||
end
|
||||
|
||||
if #cells == 0 then return s end
|
||||
|
||||
local skip_size = input_s:len() - s:len()
|
||||
local path = input_s:sub(1, skip_size)
|
||||
return s, path, drive, cells
|
||||
end
|
||||
|
||||
function MatchWindowsPath(_s, meta)
|
||||
local s, file_path, drive = WindowsSkipPath(_s)
|
||||
|
||||
if not file_path and FileExists(drive) then
|
||||
return {kind = "text", file_path = drive, line = line, col = col}
|
||||
end
|
||||
|
||||
if not file_path then
|
||||
return nil
|
||||
end
|
||||
|
||||
if not drive then
|
||||
local d = GetMainDir()
|
||||
file_path = d..'/'..file_path
|
||||
end
|
||||
local line, col, s = SkipLineAndColumn(s)
|
||||
|
||||
local exists = FileExists(file_path) or BufferExists(file_path)
|
||||
if not exists then return nil end
|
||||
|
||||
return {kind = "text", file_path = file_path, line = line, col = col}
|
||||
end
|
||||
|
||||
function MatchUnixPath(s, meta)
|
||||
local i, j = s:find("^[%w_%.-% %/]+")
|
||||
local path = s:sub(i, j)
|
||||
local rest = s:sub(j + 1, -1)
|
||||
local line, col, s = SkipLineAndColumn(rest)
|
||||
Print(path, rest, line, col)
|
||||
|
||||
return {kind = "text", file_path = path, line = line, col = col}
|
||||
end
|
||||
|
||||
if OS_VALUE == OS_WINDOWS then
|
||||
MatchPath = MatchWindowsPath
|
||||
else
|
||||
MatchPath = MatchUnixPath
|
||||
end
|
||||
|
||||
function MatchGitCommit(s, meta)
|
||||
local i, j = string.find(s, "^commit ([a-zA-Z0-9]+)")
|
||||
if i then
|
||||
s = s:sub(8)
|
||||
local command = "git --no-pager show "..s
|
||||
return {kind = "exec", cmd = command, working_dir = GetMainDir()}
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function MatchURL(s, meta)
|
||||
local i, j = string.find(s, "^https://")
|
||||
if i then
|
||||
return {kind = "exec_console", cmd = '"'..INTERNET_BROWSER..'" '..s, working_dir = GetMainDir()}
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function MatchGotoBuild(s, meta)
|
||||
if meta ~= "goto_build" then
|
||||
return nil
|
||||
end
|
||||
|
||||
local windows_path = IsAlpha(s:sub(1,1)) and s:sub(2,2) == ':'
|
||||
local windows_rela = s:sub(1,1) == '.' and s:sub(2,2) == '\\'
|
||||
local unix_path = s:sub(1,1) == '/'
|
||||
local unix_rela = s:sub(1,1) == '.' and s:sub(2,2) == '/'
|
||||
|
||||
if not windows_path and not windows_rela and not unix_path and not windows_rela then
|
||||
return {kind = "skip"}
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function MatchExec(s, meta)
|
||||
if s:match(".exe$") or s:match(".bat$") or s:match(".sh$") then
|
||||
return {kind = "exec_console", cmd = s, working_dir = GetMainDir()}
|
||||
end
|
||||
|
||||
if s:match("^%$") then
|
||||
return {kind = "exec_console", cmd = s:sub(2, -1), working_dir = GetMainDir()}
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
BuiltinOnOpenMatchers = {
|
||||
MatchPath,
|
||||
MatchGitCommit,
|
||||
MatchURL,
|
||||
|
||||
MatchGotoBuild,
|
||||
|
||||
MatchExec,
|
||||
}
|
||||
OnOpenMatchers = BuiltinOnOpenMatchers
|
||||
|
||||
function OnOpen(path, meta)
|
||||
for i = #OnOpenMatchers,1,-1 do
|
||||
rule = OnOpenMatchers[i]
|
||||
result = rule(path, meta)
|
||||
if result then
|
||||
return result
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
Coroutines = {}
|
||||
function CoAdd(f)
|
||||
local i = #Coroutines + 1
|
||||
Coroutines[i] = coroutine.create(f)
|
||||
coroutine.resume(Coroutines[i])
|
||||
return Coroutines[i]
|
||||
end
|
||||
|
||||
function OnUpdate(e)
|
||||
local new_co_list = {}
|
||||
for key, co in pairs(Coroutines) do
|
||||
local status = coroutine.status(co)
|
||||
if status ~= "dead" then
|
||||
coroutine.resume(co, e)
|
||||
new_co_list[#new_co_list + 1] = co
|
||||
end
|
||||
end
|
||||
Coroutines = new_co_list
|
||||
end
|
||||
|
||||
|
||||
function KeybindsBasic(e)
|
||||
if e.key == SDLK_F and e.ctrl == 1 and e.shift == 1 then
|
||||
C("git grep -n "..GetLoadWord().." :/")
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function BasicBuild()
|
||||
SaveAll()
|
||||
if OS_VALUE == OS_WINDOWS then
|
||||
return "build.bat"
|
||||
else
|
||||
return "./build.sh"
|
||||
end
|
||||
end
|
||||
|
||||
FKey = {BasicBuild, "", "", "", "", "", "", "", "", "", "", ""}
|
||||
FKeySDLK = {SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_F11, SDLK_F12}
|
||||
|
||||
|
||||
function KeybindsFKeys(e)
|
||||
for i = #FKey,1,-1 do
|
||||
if FKey[i] ~= "" then
|
||||
if e.key == FKeySDLK[i] then
|
||||
local cmdline = FKey[i]
|
||||
if type(cmdline) == "function" then cmdline = FKey[i]() end
|
||||
Cmd { working_dir = GetWorkDir(), kind = "console", cmd = cmdline }
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
BuiltinOnCommandCallbacks = {
|
||||
KeybindsBasic,
|
||||
KeybindsFKeys,
|
||||
}
|
||||
OnCommandCallbacks = BuiltinOnCommandCallbacks
|
||||
|
||||
function OnCommand(e)
|
||||
for i = #OnCommandCallbacks,1,-1 do
|
||||
on_command = OnCommandCallbacks[i]
|
||||
local result = on_command(e)
|
||||
if result then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function OnInit()
|
||||
end
|
||||
|
||||
function OnSave(buffer_id)
|
||||
local dont_trim_lines_with_caret = false
|
||||
ConvertLineEndingsToLF(buffer_id, dont_trim_lines_with_caret)
|
||||
if Style.TrimWhitespaceOnSave then
|
||||
TrimTrailingWhitespace(buffer_id, dont_trim_lines_with_caret)
|
||||
end
|
||||
|
||||
local name = GetBufferNameByID(buffer_id)
|
||||
if Style.ClangFormatOnSave and (name:match(".c$") or name:match(".h$") or name:match(".cpp$") or name:match(".hpp$")) then
|
||||
ApplyClangFormat(buffer_id)
|
||||
end
|
||||
end
|
||||
|
||||
function IsCodeExclude(s, meta)
|
||||
if s:match("/.git$") or s:match("\\.git$") or
|
||||
s:match(".exe$") or
|
||||
s:match(".bin$") or
|
||||
s:match(".obj$") or
|
||||
s:match(".o$") or
|
||||
s:match(".lib$") or
|
||||
s:match(".ilk$") or
|
||||
s:match(".cache$") or
|
||||
s:match(".exp$") or
|
||||
s:match(".pdb$") or
|
||||
s:match("/external/") or s:match("\\external\\")
|
||||
then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
BuiltinIsCodeMatchers = {
|
||||
IsCodeExclude,
|
||||
}
|
||||
IsCodeMatchers = BuiltinIsCodeMatchers
|
||||
|
||||
function IsCode(path, meta)
|
||||
for i = #IsCodeMatchers,1,-1 do
|
||||
rule = IsCodeMatchers[i]
|
||||
result = rule(path, meta)
|
||||
if result then
|
||||
return result
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -0,0 +1,42 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/>
|
||||
<title>Emscripten-Generated Code</title>
|
||||
<style>
|
||||
body { margin: 0; background-color: black }
|
||||
.game {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
margin: 0px;
|
||||
border: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
image-rendering: optimizeSpeed;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: -o-crisp-edges;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: optimize-contrast;
|
||||
image-rendering: crisp-edges;
|
||||
image-rendering: pixelated;
|
||||
-ms-interpolation-mode: nearest-neighbor;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas class="game" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||
<script type='text/javascript'>
|
||||
var Module = {
|
||||
preRun: [],
|
||||
print: (...args) => console.log('[stdout]: ' + args.join(' ')),
|
||||
printErr: (...args) => console.log('[stderr]: ' + args.join(' ')),
|
||||
};
|
||||
window.onerror = (event) => console.log('[onerror]: ' + event.message);
|
||||
</script>
|
||||
{{{ SCRIPT }}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Style.WaitForEvents = 0
|
||||
|
||||
-- CoAdd(function()
|
||||
-- Play{
|
||||
-- {kind = 10, key = KEY_DOWN, xwindow = 1280, ywindow = 720},
|
||||
-- {kind = 10, key = KEY_DOWN, xwindow = 1280, ywindow = 720},
|
||||
-- {kind = 10, key = KEY_DOWN, xwindow = 1280, ywindow = 720},
|
||||
-- {kind = 10, key = KEY_DOWN, xwindow = 1280, ywindow = 720},
|
||||
-- {kind = 10, key = KEY_DOWN, xwindow = 1280, ywindow = 720},
|
||||
-- {kind = 10, key = KEY_DOWN, xwindow = 1280, ywindow = 720},
|
||||
-- {kind = 10, key = KEY_DOWN, xwindow = 1280, ywindow = 720},
|
||||
-- {kind = 10, key = KEY_Q , xwindow = 1280, ywindow = 720, ctrl = 1},
|
||||
-- {kind = 10, key = KEY_PAGE_DOWN, xmouse = 0, ymouse = 0, xwindow = 1280, ywindow = 720},
|
||||
-- {kind = 111},
|
||||
-- }
|
||||
-- -- for i = 1,8 do coroutine.CoYield() end
|
||||
-- while coroutine.CoYield().kind ~= 111 do end
|
||||
|
||||
-- local buffer_name = GetActiveMainWindowBufferName()
|
||||
-- Print("buffer name = "..buffer_name)
|
||||
-- if buffer_name == "C:/Work/text_editor/src/text_editor/buffer_history.cpp" then
|
||||
-- Play{{kind = 2}}
|
||||
-- end
|
||||
-- end)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
left_mouse :: ctrl add cursor, selections work, alt load word
|
||||
right_mouse :: ctrl exec word,alt go back
|
||||
ctrl+q exec alt+q load
|
||||
alt+w go back
|
||||
|
||||
|
||||
ctrl mleft - add cursor
|
||||
ctrl shift mleft - add cursor and set selection
|
||||
alt mleft -
|
||||
alt ctrl mleft -
|
||||
alt shift mleft -
|
||||
mright - destroy pointed at selection and copy | copy line
|
||||
alt mright - go back
|
||||
ctrl mright - load word
|
||||
shift mright -
|
||||
alt shift mright -
|
||||
alt ctrl mright - go forward
|
||||
ctrl shift mright - exec word
|
||||
mmiddle -
|
||||
@@ -0,0 +1,26 @@
|
||||
https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe
|
||||
https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
|
||||
https://github.com/sheredom/subprocess.h
|
||||
https://github.com/4coder-archive/4coder/blob/master/platform_win32/win32_4ed.cpp :486
|
||||
|
||||
https://stackoverflow.com/questions/67551213/read-processs-stdout-output-in-win32-c-desktop-application
|
||||
https://handmade.network/forums/t/1219-win32_asynchronous_pipes_question
|
||||
|
||||
|
||||
|
||||
- I guess you can just do color matching in rendering, have a table and try matching words etc.
|
||||
- maybe I should disallow somehow taking pointers to dynamic array items? Just references!
|
||||
|
||||
|
||||
- create process with buffer (append to end)
|
||||
- create process and put it at specific cursor position in buffer?
|
||||
- create process without buffer attached (maybe for error?) (we want some notification that it failed or something)
|
||||
|
||||
- code indexing: maybe we can do that line based since you want to jump to line not a particular place.
|
||||
- on edit we could reparse the line for symbol
|
||||
- I think 4coder first tries to offset the index file on immediate edit, on frame tick it tries to reparse the modified file in entirety
|
||||
- offseting things doesn't seem that hard since we already figured it out with cursors
|
||||
- would it be fast enough to just reparse the entire file of certain size every time?
|
||||
- coloring seems even more hairy to do correctly because there are multiline comments etc.
|
||||
- it honestly seems no matter what you do it's a very hairy problem, text was not meant for this
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
absolute path C:/notes
|
||||
lower case c:/notes
|
||||
backwards slash C:\
|
||||
go back ../notes
|
||||
current dir ./notes
|
||||
file without slash notes
|
||||
allows spaces C:\Program Files/
|
||||
multiple slashes C:\\\\\\\\\\\\\\\\\\\\\\\\\thing
|
||||
you can combine the slashes C:\/Work
|
||||
disallowed characters for names * \ / ? > < | : "
|
||||
|
||||
There is literally no way to consistently skip the windows path, you always have to relay on heuristics
|
||||
@@ -0,0 +1,98 @@
|
||||
REDESIGN and DELETE CODE
|
||||
- Reduce the amount of actions needed to navigate using keyboard
|
||||
- Make mouse important but much less so
|
||||
|
||||
Needs to change:
|
||||
- Make it more similar to sublime like editors
|
||||
- Need Ctrl + P
|
||||
- Clickable title bar may be cool or whatever but it's pretty bad
|
||||
- Executing lua commands is clunky, need a real Ctrl+P and keybind actions, popups: remove a lot of the lua functionality, just for config files
|
||||
- Window, View, Buffer + flags design (or is completely new kind based approach needed for Windows/Views?)
|
||||
- How to make non-editable, informative, with different font size, title bar. Which might also contain tabs
|
||||
- How to design clickable tree view in this way?
|
||||
- How to design Command view?
|
||||
- How to design popup view (input field)?
|
||||
- How to design search view? or search and replace view?
|
||||
|
||||
Things I like:
|
||||
- Basic editing
|
||||
- Configurable Open
|
||||
- Lua config files work pretty well
|
||||
|
||||
Splits:
|
||||
- Buffer16 Buffer8?
|
||||
- Why constraint that name of buffer needs to be unique? For Open() and default behavior but is this required?
|
||||
- Try to add Tracking Allocator and rewrite the app, free all memory at the end of the app and check all is well
|
||||
- move titlebar, search to splits?
|
||||
|
||||
|
||||
Linux
|
||||
- Add backtrace
|
||||
|
||||
|
||||
|
||||
Commands TODO:
|
||||
- Search
|
||||
- Ctrl + F
|
||||
- Next occurence: Enter
|
||||
- Prev occurence: Shift + Enter
|
||||
- next occurence: F3
|
||||
- prev occurence: Shift + F3
|
||||
- Console: OK concept but constrain
|
||||
- Turned off by default
|
||||
- Special: non editable, hotkeys don't work etc.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DESIGN try to make console less special, make stuff reusable etc.
|
||||
DESIGN Config file versions, when loading should be checked, at the top of the file, what to do when old version?
|
||||
ISSUE Ctrl+Alt+Down (DuplicateLine) doesn't work on ubuntu
|
||||
DESIGN Moving vertically between splits, which keys???
|
||||
DESIGN Console, when writing commands and evaling in console it should properly insert a new line after our thing when writing on last line
|
||||
DESIGN The cursor hopping history needs a bit of fixing, probably needs to be more complicated with collapsing commands
|
||||
FEATURE KillConsole, or maybe some window targetting but how??
|
||||
ISSUE I hit a case where GC tried deleting a buffer which was not attached to the buffer list, it had zeroed next, prev. It happened after iterating through directories using the ctrl + period
|
||||
FEATURE Search whole words, case sensitive etc.
|
||||
FEATURE Select all searched occurences
|
||||
PLATFORM Fix windows build
|
||||
ISSUE What to do / how should Reopen work after we delete the file on disk in some other program?
|
||||
DESIGN Changing window properties by changing the window name?
|
||||
FEATURE commands for scrolling: center, cursor_at_bottom_of_screen, cursor_at_top
|
||||
FEATURE Kill buffer command (it should be marked for deletion and deleted at the end of frame!)
|
||||
DESIGN Check. Convert more commands to taking buffer instead of view
|
||||
DESIGN Check. Rewrite more commands to use already implemented commands?
|
||||
FEATURE Lua namespaces for different kinds of commands (by ids, using main_set, using active_set)?
|
||||
FEATURE Some decl/function indexing in fuzzy format
|
||||
ISSUE? Fix jump scroll, the query ends up the last line on screen, kind of wacky
|
||||
FEATURE dump text editor state to file, restore state
|
||||
DESIGN ask user if he really wants to quit even though he has an unsaved buffer - popup window | we could just show ForceClose() in the titlebar
|
||||
FEATURE Find matches using grep, change things in that buffer then apply those changes to all items
|
||||
FEATURE group history entries so the you can rollback through multiple ones at once and not waste time on skipping whitespace trimming or deleting every character
|
||||
- Search and replace
|
||||
- word complete
|
||||
- Search all buffers in 10X style, incrementally searched results popping up on every key press (maybe we need coroutine library in C so this is easier?)
|
||||
- escapeing multiple cursor after ctrl + d should put the cursor where it was (probably will need to swap secondary and primary cursor for new cursor
|
||||
- draw indentation levels like in sublime (those lines) - we render chars one by one so seems relatively easy to figure out if whitespace belongs to beginning of line (make sure to add max value like 40 because of big files)
|
||||
- code sections, visual demarkation if beginning of line has a very specific text + goto next / goto prev section hotkey!
|
||||
- combine glyph and selection rendering
|
||||
|
||||
backlog
|
||||
- expose a coroutine based scripting enviorment where user can execute shell commands wait for them and perform actions in very linear manner
|
||||
- Test stdin writing code
|
||||
- Implement shell interaction (the valid cmd lines should start with '>' or '$', user can add more lines like this to expand the command size maybe?, if we have a case where we have a line with '>' but the last line doesn't have (just a space) then it should execute?)
|
||||
- drop text into window
|
||||
- I think the way sublime text and we display line highlights is confusing with multiple cursors (line highlight can be confused with selection)
|
||||
- make the editor replayable, store events and then replay, be careful about globals
|
||||
- maybe open should return multiple options if there are many more? (like in sublime if many symbols you get a window and you choose and it automatically jumps you to the symbol in the background)
|
||||
- I want a way to assign flags to buffers/views/windows from user perspective so that console window concept can be created from user space
|
||||
- font cache and on demand unicode loads
|
||||
- color parens, braces
|
||||
- redo tree
|
||||
- gap buffer
|
||||
- optimize rendering - command buffer, and vertice buffer instead of vertice buffer with scissor
|
||||
|
||||
|
||||
!!As little lua code as possible, but lua code should be powerful just in case of quick edits
|
||||
@@ -0,0 +1,98 @@
|
||||
Basic Latin
|
||||
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
|
||||
Latin-1 Supplement
|
||||
¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ
|
||||
Latin Extended-A
|
||||
Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ Ġ ġ Ģ ģ Ĥ ĥ Ħ ħ Ĩ ĩ Ī ī Ĭ ĭ Į į İ ı IJ ij Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ Ŀ ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ō ō Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ Ş ş Š š Ţ ţ Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž ž ſ
|
||||
Latin Extended-B
|
||||
ƀ Ɓ Ƃ ƃ Ƅ ƅ Ɔ Ƈ ƈ Ɖ Ɗ Ƌ ƌ ƍ Ǝ Ə Ɛ Ƒ ƒ Ɠ Ɣ ƕ Ɩ Ɨ Ƙ ƙ ƚ ƛ Ɯ Ɲ ƞ Ɵ Ơ ơ Ƣ ƣ Ƥ ƥ Ʀ Ƨ ƨ Ʃ ƪ ƫ Ƭ ƭ Ʈ Ư ư Ʊ Ʋ Ƴ ƴ Ƶ ƶ Ʒ Ƹ ƹ ƺ ƻ Ƽ ƽ ƾ ƿ ǀ ǁ ǂ ǃ DŽ Dž dž LJ Lj lj NJ Nj nj Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ Ǖ ǖ Ǘ ǘ Ǚ ǚ Ǜ ǜ ǝ Ǟ ǟ Ǡ ǡ Ǣ ǣ Ǥ ǥ Ǧ ǧ Ǩ ǩ Ǫ ǫ Ǭ ǭ Ǯ ǯ ǰ DZ Dz dz Ǵ ǵ Ǻ ǻ Ǽ ǽ Ǿ ǿ Ȁ ȁ Ȃ ȃ ...
|
||||
IPA Extensions
|
||||
ɐ ɑ ɒ ɓ ɔ ɕ ɖ ɗ ɘ ə ɚ ɛ ɜ ɝ ɞ ɟ ɠ ɡ ɢ ɣ ɤ ɥ ɦ ɧ ɨ ɩ ɪ ɫ ɬ ɭ ɮ ɯ ɰ ɱ ɲ ɳ ɴ ɵ ɶ ɷ ɸ ɹ ɺ ɻ ɼ ɽ ɾ ɿ ʀ ʁ ʂ ʃ ʄ ʅ ʆ ʇ ʈ ʉ ʊ ʋ ʌ ʍ ʎ ʏ ʐ ʑ ʒ ʓ ʔ ʕ ʖ ʗ ʘ ʙ ʚ ʛ ʜ ʝ ʞ ʟ ʠ ʡ ʢ ʣ ʤ ʥ ʦ ʧ ʨ
|
||||
Spacing Modifier Letters
|
||||
ʰ ʱ ʲ ʳ ʴ ʵ ʶ ʷ ʸ ʹ ʺ ʻ ʼ ʽ ʾ ʿ ˀ ˁ ˂ ˃ ˄ ˅ ˆ ˇ ˈ ˉ ˊ ˋ ˌ ˍ ˎ ˏ ː ˑ ˒ ˓ ˔ ˕ ˖ ˗ ˘ ˙ ˚ ˛ ˜ ˝ ˞ ˠ ˡ ˢ ˣ ˤ ˥ ˦ ˧ ˨ ˩
|
||||
Combining Diacritical Marks
|
||||
̀ ́ ̂ ̃ ̄ ̅ ̆ ̇ ̈ ̉ ̊ ̋ ̌ ̍ ̎ ̏ ̐ ̑ ̒ ̓ ̔ ̕ ̖ ̗ ̘ ̙ ̚ ̛ ̜ ̝ ̞ ̟ ̠ ̡ ̢ ̣ ̤ ̥ ̦ ̧ ̨ ̩ ̪ ̫ ̬ ̭ ̮ ̯ ̰ ̱ ̲ ̳ ̴ ̵ ̶ ̷ ̸ ̹ ̺ ̻ ̼ ̽ ̾ ̿ ̀ ́ ͂ ̓ ̈́ ͅ ͠ ͡
|
||||
Greek
|
||||
ʹ ͵ ͺ ; ΄ ΅ Ά · Έ Ή Ί Ό Ύ Ώ ΐ Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω Ϊ Ϋ ά έ ή ί ΰ α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ ς σ τ υ φ χ ψ ω ϊ ϋ ό ύ ώ ϐ ϑ ϒ ϓ ϔ ϕ ϖ Ϛ Ϝ Ϟ Ϡ Ϣ ϣ Ϥ ϥ Ϧ ϧ Ϩ ϩ Ϫ ϫ Ϭ ϭ Ϯ ϯ ϰ ϱ ϲ ϳ
|
||||
Cyrillic
|
||||
Ё Ђ Ѓ Є Ѕ І Ї Ј Љ Њ Ћ Ќ Ў Џ А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я а б в г д е ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я ё ђ ѓ є ѕ і ї ј љ њ ћ ќ ў џ Ѡ ѡ Ѣ ѣ Ѥ ѥ Ѧ ѧ Ѩ ѩ Ѫ ѫ Ѭ ѭ Ѯ ѯ Ѱ ѱ Ѳ ѳ Ѵ ѵ Ѷ ѷ Ѹ ѹ Ѻ ѻ Ѽ ѽ Ѿ ѿ Ҁ ҁ ҂ ҃ ...
|
||||
Armenian
|
||||
Ա Բ Գ Դ Ե Զ Է Ը Թ Ժ Ի Լ Խ Ծ Կ Հ Ձ Ղ Ճ Մ Յ Ն Շ Ո Չ Պ Ջ Ռ Ս Վ Տ Ր Ց Ւ Փ Ք Օ Ֆ ՙ ՚ ՛ ՜ ՝ ՞ ՟ ա բ գ դ ե զ է ը թ ժ ի լ խ ծ կ հ ձ ղ ճ մ յ ն շ ո չ պ ջ ռ ս վ տ ր ց ւ փ ք օ ֆ և ։
|
||||
Hebrew
|
||||
֑ ֒ ֓ ֔ ֕ ֖ ֗ ֘ ֙ ֚ ֛ ֜ ֝ ֞ ֟ ֠ ֡ ֣ ֤ ֥ ֦ ֧ ֨ ֩ ֪ ֫ ֬ ֭ ֮ ֯ ְ ֱ ֲ ֳ ִ ֵ ֶ ַ ָ ֹ ֻ ּ ֽ ־ ֿ ׀ ׁ ׂ ׃ ׄ א ב ג ד ה ו ז ח ט י ך כ ל ם מ ן נ ס ע ף פ ץ צ ק ר ש ת װ ױ ײ ׳ ״
|
||||
Arabic
|
||||
، ؛ ؟ ء آ أ ؤ إ ئ ا ب ة ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ـ ف ق ك ل م ن ه و ى ي ً ٌ ٍ َ ُ ِ ّ ْ ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ٪ ٫ ٬ ٭ ٰ ٱ ٲ ٳ ٴ ٵ ٶ ٷ ٸ ٹ ٺ ٻ ټ ٽ پ ٿ ڀ ځ ڂ ڃ ڄ څ چ ڇ ڈ ډ ڊ ڋ ڌ ڍ ڎ ڏ ڐ ڑ ڒ ړ ڔ ڕ ږ ڗ ژ ڙ ښ ڛ ڜ ڝ ڞ ڟ ڠ ڡ ڢ ڣ ڤ ڥ ڦ ڧ ڨ ک ڪ ګ ڬ ڭ ڮ گ ڰ ڱ ...
|
||||
Devanagari
|
||||
ँ ं ः अ आ इ ई उ ऊ ऋ ऌ ऍ ऎ ए ऐ ऑ ऒ ओ औ क ख ग घ ङ च छ ज झ ञ ट ठ ड ढ ण त थ द ध न ऩ प फ ब भ म य र ऱ ल ळ ऴ व श ष स ह ़ ऽ ा ि ी ु ू ृ ॄ ॅ ॆ े ै ॉ ॊ ो ौ ् ॐ ॑ ॒ ॓ ॔ क़ ख़ ग़ ज़ ड़ ढ़ फ़ य़ ॠ ॡ ॢ ॣ । ॥ ० १ २ ३ ४ ५ ६ ७ ८ ९ ॰
|
||||
Bengali
|
||||
ঁ ং ঃ অ আ ই ঈ উ ঊ ঋ ঌ এ ঐ ও ঔ ক খ গ ঘ ঙ চ ছ জ ঝ ঞ ট ঠ ড ঢ ণ ত থ দ ধ ন প ফ ব ভ ম য র ল শ ষ স হ ় া ি ী ু ূ ৃ ৄ ে ৈ ো ৌ ্ ৗ ড় ঢ় য় ৠ ৡ ৢ ৣ ০ ১ ২ ৩ ৪ ৫ ৬ ৭ ৮ ৯ ৰ ৱ ৲ ৳ ৴ ৵ ৶ ৷ ৸ ৹ ৺
|
||||
Gurmukhi
|
||||
ਂ ਅ ਆ ਇ ਈ ਉ ਊ ਏ ਐ ਓ ਔ ਕ ਖ ਗ ਘ ਙ ਚ ਛ ਜ ਝ ਞ ਟ ਠ ਡ ਢ ਣ ਤ ਥ ਦ ਧ ਨ ਪ ਫ ਬ ਭ ਮ ਯ ਰ ਲ ਲ਼ ਵ ਸ਼ ਸ ਹ ਼ ਾ ਿ ੀ ੁ ੂ ੇ ੈ ੋ ੌ ੍ ਖ਼ ਗ਼ ਜ਼ ੜ ਫ਼ ੦ ੧ ੨ ੩ ੪ ੫ ੬ ੭ ੮ ੯ ੰ ੱ ੲ ੳ ੴ
|
||||
Gujarati
|
||||
ઁ ં ઃ અ આ ઇ ઈ ઉ ઊ ઋ ઍ એ ઐ ઑ ઓ ઔ ક ખ ગ ઘ ઙ ચ છ જ ઝ ઞ ટ ઠ ડ ઢ ણ ત થ દ ધ ન પ ફ બ ભ મ ય ર લ ળ વ શ ષ સ હ ઼ ઽ ા િ ી ુ ૂ ૃ ૄ ૅ ે ૈ ૉ ો ૌ ્ ૐ ૠ ૦ ૧ ૨ ૩ ૪ ૫ ૬ ૭ ૮ ૯
|
||||
Oriya
|
||||
ଁ ଂ ଃ ଅ ଆ ଇ ଈ ଉ ଊ ଋ ଌ ଏ ଐ ଓ ଔ କ ଖ ଗ ଘ ଙ ଚ ଛ ଜ ଝ ଞ ଟ ଠ ଡ ଢ ଣ ତ ଥ ଦ ଧ ନ ପ ଫ ବ ଭ ମ ଯ ର ଲ ଳ ଶ ଷ ସ ହ ଼ ଽ ା ି ୀ ୁ ୂ ୃ େ ୈ ୋ ୌ ୍ ୖ ୗ ଡ଼ ଢ଼ ୟ ୠ ୡ ୦ ୧ ୨ ୩ ୪ ୫ ୬ ୭ ୮ ୯ ୰
|
||||
Tamil
|
||||
ஂ ஃ அ ஆ இ ஈ உ ஊ எ ஏ ஐ ஒ ஓ ஔ க ங ச ஜ ஞ ட ண த ந ன ப ம ய ர ற ல ள ழ வ ஷ ஸ ஹ ா ி ீ ு ூ ெ ே ை ொ ோ ௌ ் ௗ ௧ ௨ ௩ ௪ ௫ ௬ ௭ ௮ ௯ ௰ ௱ ௲
|
||||
Telugu
|
||||
ఁ ం ః అ ఆ ఇ ఈ ఉ ఊ ఋ ఌ ఎ ఏ ఐ ఒ ఓ ఔ క ఖ గ ఘ ఙ చ ఛ జ ఝ ఞ ట ఠ డ ఢ ణ త థ ద ధ న ప ఫ బ భ మ య ర ఱ ల ళ వ శ ష స హ ా ి ీ ు ూ ృ ౄ ె ే ై ొ ో ౌ ్ ౕ ౖ ౠ ౡ ౦ ౧ ౨ ౩ ౪ ౫ ౬ ౭ ౮ ౯
|
||||
Kannada
|
||||
ಂ ಃ ಅ ಆ ಇ ಈ ಉ ಊ ಋ ಌ ಎ ಏ ಐ ಒ ಓ ಔ ಕ ಖ ಗ ಘ ಙ ಚ ಛ ಜ ಝ ಞ ಟ ಠ ಡ ಢ ಣ ತ ಥ ದ ಧ ನ ಪ ಫ ಬ ಭ ಮ ಯ ರ ಱ ಲ ಳ ವ ಶ ಷ ಸ ಹ ಾ ಿ ೀ ು ೂ ೃ ೄ ೆ ೇ ೈ ೊ ೋ ೌ ್ ೕ ೖ ೞ ೠ ೡ ೦ ೧ ೨ ೩ ೪ ೫ ೬ ೭ ೮ ೯
|
||||
Malayalam
|
||||
ം ഃ അ ആ ഇ ഈ ഉ ഊ ഋ ഌ എ ഏ ഐ ഒ ഓ ഔ ക ഖ ഗ ഘ ങ ച ഛ ജ ഝ ഞ ട ഠ ഡ ഢ ണ ത ഥ ദ ധ ന പ ഫ ബ ഭ മ യ ര റ ല ള ഴ വ ശ ഷ സ ഹ ാ ി ീ ു ൂ ൃ െ േ ൈ ൊ ോ ൌ ് ൗ ൠ ൡ ൦ ൧ ൨ ൩ ൪ ൫ ൬ ൭ ൮ ൯
|
||||
Thai
|
||||
ก ข ฃ ค ฅ ฆ ง จ ฉ ช ซ ฌ ญ ฎ ฏ ฐ ฑ ฒ ณ ด ต ถ ท ธ น บ ป ผ ฝ พ ฟ ภ ม ย ร ฤ ล ฦ ว ศ ษ ส ห ฬ อ ฮ ฯ ะ ั า ำ ิ ี ึ ื ุ ู ฺ ฿ เ แ โ ใ ไ ๅ ๆ ็ ่ ้ ๊ ๋ ์ ํ ๎ ๏ ๐ ๑ ๒ ๓ ๔ ๕ ๖ ๗ ๘ ๙ ๚ ๛
|
||||
Lao
|
||||
ກ ຂ ຄ ງ ຈ ຊ ຍ ດ ຕ ຖ ທ ນ ບ ປ ຜ ຝ ພ ຟ ມ ຢ ຣ ລ ວ ສ ຫ ອ ຮ ຯ ະ ັ າ ຳ ິ ີ ຶ ື ຸ ູ ົ ຼ ຽ ເ ແ ໂ ໃ ໄ ໆ ່ ້ ໊ ໋ ໌ ໍ ໐ ໑ ໒ ໓ ໔ ໕ ໖ ໗ ໘ ໙ ໜ ໝ
|
||||
Tibetan
|
||||
ༀ ༁ ༂ ༃ ༄ ༅ ༆ ༇ ༈ ༉ ༊ ་ ༌ ། ༎ ༏ ༐ ༑ ༒ ༓ ༔ ༕ ༖ ༗ ༘ ༙ ༚ ༛ ༜ ༝ ༞ ༟ ༠ ༡ ༢ ༣ ༤ ༥ ༦ ༧ ༨ ༩ ༪ ༫ ༬ ༭ ༮ ༯ ༰ ༱ ༲ ༳ ༴ ༵ ༶ ༷ ༸ ༹ ༺ ༻ ༼ ༽ ༾ ༿ ཀ ཁ ག གྷ ང ཅ ཆ ཇ ཉ ཊ ཋ ཌ ཌྷ ཎ ཏ ཐ ད དྷ ན པ ཕ བ བྷ མ ཙ ཚ ཛ ཛྷ ཝ ཞ ཟ འ ཡ ར ལ ཤ ཥ ས ཧ ཨ ཀྵ ཱ ི ཱི ུ ཱུ ྲྀ ཷ ླྀ ཹ ེ ཻ ོ ཽ ཾ ཿ ྀ ཱྀ ྂ ྃ ྄ ྅ ྆ ྇ ...
|
||||
Georgian
|
||||
Ⴀ Ⴁ Ⴂ Ⴃ Ⴄ Ⴅ Ⴆ Ⴇ Ⴈ Ⴉ Ⴊ Ⴋ Ⴌ Ⴍ Ⴎ Ⴏ Ⴐ Ⴑ Ⴒ Ⴓ Ⴔ Ⴕ Ⴖ Ⴗ Ⴘ Ⴙ Ⴚ Ⴛ Ⴜ Ⴝ Ⴞ Ⴟ Ⴠ Ⴡ Ⴢ Ⴣ Ⴤ Ⴥ ა ბ გ დ ე ვ ზ თ ი კ ლ მ ნ ო პ ჟ რ ს ტ უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ ჯ ჰ ჱ ჲ ჳ ჴ ჵ ჶ ჻
|
||||
Hangul Jamo
|
||||
ᄀ ᄁ ᄂ ᄃ ᄄ ᄅ ᄆ ᄇ ᄈ ᄉ ᄊ ᄋ ᄌ ᄍ ᄎ ᄏ ᄐ ᄑ ᄒ ᄓ ᄔ ᄕ ᄖ ᄗ ᄘ ᄙ ᄚ ᄛ ᄜ ᄝ ᄞ ᄟ ᄠ ᄡ ᄢ ᄣ ᄤ ᄥ ᄦ ᄧ ᄨ ᄩ ᄪ ᄫ ᄬ ᄭ ᄮ ᄯ ᄰ ᄱ ᄲ ᄳ ᄴ ᄵ ᄶ ᄷ ᄸ ᄹ ᄺ ᄻ ᄼ ᄽ ᄾ ᄿ ᅀ ᅁ ᅂ ᅃ ᅄ ᅅ ᅆ ᅇ ᅈ ᅉ ᅊ ᅋ ᅌ ᅍ ᅎ ᅏ ᅐ ᅑ ᅒ ᅓ ᅔ ᅕ ᅖ ᅗ ᅘ ᅙ ᅟ ᅠ ᅡ ᅢ ᅣ ᅤ ᅥ ᅦ ᅧ ᅨ ᅩ ᅪ ᅫ ᅬ ᅭ ᅮ ᅯ ᅰ ᅱ ᅲ ᅳ ᅴ ᅵ ᅶ ᅷ ᅸ ᅹ ᅺ ᅻ ᅼ ᅽ ᅾ ᅿ ᆀ ᆁ ᆂ ᆃ ᆄ ...
|
||||
Latin Extended Additional
|
||||
Ḁ ḁ Ḃ ḃ Ḅ ḅ Ḇ ḇ Ḉ ḉ Ḋ ḋ Ḍ ḍ Ḏ ḏ Ḑ ḑ Ḓ ḓ Ḕ ḕ Ḗ ḗ Ḙ ḙ Ḛ ḛ Ḝ ḝ Ḟ ḟ Ḡ ḡ Ḣ ḣ Ḥ ḥ Ḧ ḧ Ḩ ḩ Ḫ ḫ Ḭ ḭ Ḯ ḯ Ḱ ḱ Ḳ ḳ Ḵ ḵ Ḷ ḷ Ḹ ḹ Ḻ ḻ Ḽ ḽ Ḿ ḿ Ṁ ṁ Ṃ ṃ Ṅ ṅ Ṇ ṇ Ṉ ṉ Ṋ ṋ Ṍ ṍ Ṏ ṏ Ṑ ṑ Ṓ ṓ Ṕ ṕ Ṗ ṗ Ṙ ṙ Ṛ ṛ Ṝ ṝ Ṟ ṟ Ṡ ṡ Ṣ ṣ Ṥ ṥ Ṧ ṧ Ṩ ṩ Ṫ ṫ Ṭ ṭ Ṯ ṯ Ṱ ṱ Ṳ ṳ Ṵ ṵ Ṷ ṷ Ṹ ṹ Ṻ ṻ Ṽ ṽ Ṿ ṿ ...
|
||||
Greek Extended
|
||||
ἀ ἁ ἂ ἃ ἄ ἅ ἆ ἇ Ἀ Ἁ Ἂ Ἃ Ἄ Ἅ Ἆ Ἇ ἐ ἑ ἒ ἓ ἔ ἕ Ἐ Ἑ Ἒ Ἓ Ἔ Ἕ ἠ ἡ ἢ ἣ ἤ ἥ ἦ ἧ Ἠ Ἡ Ἢ Ἣ Ἤ Ἥ Ἦ Ἧ ἰ ἱ ἲ ἳ ἴ ἵ ἶ ἷ Ἰ Ἱ Ἲ Ἳ Ἴ Ἵ Ἶ Ἷ ὀ ὁ ὂ ὃ ὄ ὅ Ὀ Ὁ Ὂ Ὃ Ὄ Ὅ ὐ ὑ ὒ ὓ ὔ ὕ ὖ ὗ Ὑ Ὓ Ὕ Ὗ ὠ ὡ ὢ ὣ ὤ ὥ ὦ ὧ Ὠ Ὡ Ὢ Ὣ Ὤ Ὥ Ὦ Ὧ ὰ ά ὲ έ ὴ ή ὶ ί ὸ ό ὺ ύ ὼ ώ ᾀ ᾁ ᾂ ᾃ ᾄ ᾅ ᾆ ᾇ ᾈ ᾉ ᾊ ᾋ ᾌ ᾍ ...
|
||||
General Punctuation
|
||||
‐ ‑ ‒ – — ― ‖ ‗ ‘ ’ ‚ ‛ “ ” „ ‟ † ‡ • ‣ ․ ‥ … ‧
‰ ‱ ′ ″ ‴ ‵ ‶ ‷ ‸ ‹ › ※ ‼ ‽ ‾ ‿ ⁀ ⁁ ⁂ ⁃ ⁄ ⁅ ⁆
|
||||
Superscripts and Subscripts
|
||||
⁰ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁺ ⁻ ⁼ ⁽ ⁾ ⁿ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉ ₊ ₋ ₌ ₍ ₎
|
||||
Currency Symbols
|
||||
₠ ₡ ₢ ₣ ₤ ₥ ₦ ₧ ₨ ₩ ₪ ₫
|
||||
Combining Marks for Symbols
|
||||
⃐ ⃑ ⃒ ⃓ ⃔ ⃕ ⃖ ⃗ ⃘ ⃙ ⃚ ⃛ ⃜ ⃝ ⃞ ⃟ ⃠ ⃡
|
||||
Letterlike Symbols
|
||||
℀ ℁ ℂ ℃ ℄ ℅ ℆ ℇ ℈ ℉ ℊ ℋ ℌ ℍ ℎ ℏ ℐ ℑ ℒ ℓ ℔ ℕ № ℗ ℘ ℙ ℚ ℛ ℜ ℝ ℞ ℟ ℠ ℡ ™ ℣ ℤ ℥ Ω ℧ ℨ ℩ K Å ℬ ℭ ℮ ℯ ℰ ℱ Ⅎ ℳ ℴ ℵ ℶ ℷ ℸ
|
||||
Number Forms
|
||||
⅓ ⅔ ⅕ ⅖ ⅗ ⅘ ⅙ ⅚ ⅛ ⅜ ⅝ ⅞ ⅟ Ⅰ Ⅱ Ⅲ Ⅳ Ⅴ Ⅵ Ⅶ Ⅷ Ⅸ Ⅹ Ⅺ Ⅻ Ⅼ Ⅽ Ⅾ Ⅿ ⅰ ⅱ ⅲ ⅳ ⅴ ⅵ ⅶ ⅷ ⅸ ⅹ ⅺ ⅻ ⅼ ⅽ ⅾ ⅿ ↀ ↁ ↂ
|
||||
Arrows
|
||||
← ↑ → ↓ ↔ ↕ ↖ ↗ ↘ ↙ ↚ ↛ ↜ ↝ ↞ ↟ ↠ ↡ ↢ ↣ ↤ ↥ ↦ ↧ ↨ ↩ ↪ ↫ ↬ ↭ ↮ ↯ ↰ ↱ ↲ ↳ ↴ ↵ ↶ ↷ ↸ ↹ ↺ ↻ ↼ ↽ ↾ ↿ ⇀ ⇁ ⇂ ⇃ ⇄ ⇅ ⇆ ⇇ ⇈ ⇉ ⇊ ⇋ ⇌ ⇍ ⇎ ⇏ ⇐ ⇑ ⇒ ⇓ ⇔ ⇕ ⇖ ⇗ ⇘ ⇙ ⇚ ⇛ ⇜ ⇝ ⇞ ⇟ ⇠ ⇡ ⇢ ⇣ ⇤ ⇥ ⇦ ⇧ ⇨ ⇩ ⇪
|
||||
Mathematical Operators
|
||||
∀ ∁ ∂ ∃ ∄ ∅ ∆ ∇ ∈ ∉ ∊ ∋ ∌ ∍ ∎ ∏ ∐ ∑ − ∓ ∔ ∕ ∖ ∗ ∘ ∙ √ ∛ ∜ ∝ ∞ ∟ ∠ ∡ ∢ ∣ ∤ ∥ ∦ ∧ ∨ ∩ ∪ ∫ ∬ ∭ ∮ ∯ ∰ ∱ ∲ ∳ ∴ ∵ ∶ ∷ ∸ ∹ ∺ ∻ ∼ ∽ ∾ ∿ ≀ ≁ ≂ ≃ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≏ ≐ ≑ ≒ ≓ ≔ ≕ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≠ ≡ ≢ ≣ ≤ ≥ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿ ...
|
||||
Miscellaneous Technical
|
||||
⌀ ⌂ ⌃ ⌄ ⌅ ⌆ ⌇ ⌈ ⌉ ⌊ ⌋ ⌌ ⌍ ⌎ ⌏ ⌐ ⌑ ⌒ ⌓ ⌔ ⌕ ⌖ ⌗ ⌘ ⌙ ⌚ ⌛ ⌜ ⌝ ⌞ ⌟ ⌠ ⌡ ⌢ ⌣ ⌤ ⌥ ⌦ ⌧ ⌨ 〈 〉 ⌫ ⌬ ⌭ ⌮ ⌯ ⌰ ⌱ ⌲ ⌳ ⌴ ⌵ ⌶ ⌷ ⌸ ⌹ ⌺ ⌻ ⌼ ⌽ ⌾ ⌿ ⍀ ⍁ ⍂ ⍃ ⍄ ⍅ ⍆ ⍇ ⍈ ⍉ ⍊ ⍋ ⍌ ⍍ ⍎ ⍏ ⍐ ⍑ ⍒ ⍓ ⍔ ⍕ ⍖ ⍗ ⍘ ⍙ ⍚ ⍛ ⍜ ⍝ ⍞ ⍟ ⍠ ⍡ ⍢ ⍣ ⍤ ⍥ ⍦ ⍧ ⍨ ⍩ ⍪ ⍫ ⍬ ⍭ ⍮ ⍯ ⍰ ⍱ ⍲ ⍳ ⍴ ⍵ ⍶ ⍷ ⍸ ⍹ ⍺
|
||||
Control Pictures
|
||||
␀ ␁ ␂ ␃ ␄ ␅ ␆ ␇ ␈ ␉ ␊ ␋ ␌ ␍ ␎ ␏ ␐ ␑ ␒ ␓ ␔ ␕ ␖ ␗ ␘ ␙ ␚ ␛ ␜ ␝ ␞ ␟ ␠ ␡ ␢ ␣ 
|
||||
Optical Character Recognition
|
||||
⑀ ⑁ ⑂ ⑃ ⑄ ⑅ ⑆ ⑇ ⑈ ⑉ ⑊
|
||||
Enclosed Alphanumerics
|
||||
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ...
|
||||
Box Drawing
|
||||
─ ━ │ ┃ ┄ ┅ ┆ ┇ ┈ ┉ ┊ ┋ ┌ ┍ ┎ ┏ ┐ ┑ ┒ ┓ └ ┕ ┖ ┗ ┘ ┙ ┚ ┛ ├ ┝ ┞ ┟ ┠ ┡ ┢ ┣ ┤ ┥ ┦ ┧ ┨ ┩ ┪ ┫ ┬ ┭ ┮ ┯ ┰ ┱ ┲ ┳ ┴ ┵ ┶ ┷ ┸ ┹ ┺ ┻ ┼ ┽ ┾ ┿ ╀ ╁ ╂ ╃ ╄ ╅ ╆ ╇ ╈ ╉ ╊ ╋ ╌ ╍ ╎ ╏ ═ ║ ╒ ╓ ╔ ╕ ╖ ╗ ╘ ╙ ╚ ╛ ╜ ╝ ╞ ╟ ╠ ╡ ╢ ╣ ╤ ╥ ╦ ╧ ╨ ╩ ╪ ╫ ╬ ╭ ╮ ╯ ╰ ╱ ╲ ╳ ╴ ╵ ╶ ╷ ╸ ╹ ╺ ╻ ╼ ╽ ╾ ╿
|
||||
Block Elements
|
||||
▀ ▁ ▂ ▃ ▄ ▅ ▆ ▇ █ ▉ ▊ ▋ ▌ ▍ ▎ ▏ ▐ ░ ▒ ▓ ▔ ▕
|
||||
Geometric Shapes
|
||||
■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ ▩ ▪ ▫ ▬ ▭ ▮ ▯ ▰ ▱ ▲ △ ▴ ▵ ▶ ▷ ▸ ▹ ► ▻ ▼ ▽ ▾ ▿ ◀ ◁ ◂ ◃ ◄ ◅ ◆ ◇ ◈ ◉ ◊ ○ ◌ ◍ ◎ ● ◐ ◑ ◒ ◓ ◔ ◕ ◖ ◗ ◘ ◙ ◚ ◛ ◜ ◝ ◞ ◟ ◠ ◡ ◢ ◣ ◤ ◥ ◦ ◧ ◨ ◩ ◪ ◫ ◬ ◭ ◮ ◯
|
||||
Miscellaneous Symbols
|
||||
☀ ☁ ☂ ☃ ☄ ★ ☆ ☇ ☈ ☉ ☊ ☋ ☌ ☍ ☎ ☏ ☐ ☑ ☒ ☓ ☚ ☛ ☜ ☝ ☞ ☟ ☠ ☡ ☢ ☣ ☤ ☥ ☦ ☧ ☨ ☩ ☪ ☫ ☬ ☭ ☮ ☯ ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ ☸ ☹ ☺ ☻ ☼ ☽ ☾ ☿ ♀ ♁ ♂ ♃ ♄ ♅ ♆ ♇ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓ ♔ ♕ ♖ ♗ ♘ ♙ ♚ ♛ ♜ ♝ ♞ ♟ ♠ ♡ ♢ ♣ ♤ ♥ ♦ ♧ ♨ ♩ ♪ ♫ ♬ ♭ ♮ ♯
|
||||
Dingbats
|
||||
✁ ✂ ✃ ✄ ✆ ✇ ✈ ✉ ✌ ✍ ✎ ✏ ✐ ✑ ✒ ✓ ✔ ✕ ✖ ✗ ✘ ✙ ✚ ✛ ✜ ✝ ✞ ✟ ✠ ✡ ✢ ✣ ✤ ✥ ✦ ✧ ✩ ✪ ✫ ✬ ✭ ✮ ✯ ✰ ✱ ✲ ✳ ✴ ✵ ✶ ✷ ✸ ✹ ✺ ✻ ✼ ✽ ✾ ✿ ❀ ❁ ❂ ❃ ❄ ❅ ❆ ❇ ❈ ❉ ❊ ❋ ❍ ❏ ❐ ❑ ❒ ❖ ❘ ❙ ❚ ❛ ❜ ❝ ❞ ❡ ❢ ❣ ❤ ❥ ❦ ❧ ❶ ❷ ❸ ❹ ❺ ❻ ❼ ❽ ❾ ❿ ➀ ➁ ➂ ➃ ➄ ➅ ➆ ➇ ➈ ➉ ➊ ➋ ➌ ➍ ➎ ➏ ➐ ➑ ➒ ➓ ➔ ➘ ➙ ➚ ➛ ➜ ➝ ...
|
||||
CJK Symbols and Punctuation
|
||||
、 。 〃 〄 々 〆 〇 〈 〉 《 》 「 」 『 』 【 】 〒 〓 〔 〕 〖 〗 〘 〙 〚 〛 〜 〝 〞 〟 〠 〡 〢 〣 〤 〥 〦 〧 〨 〩 〪 〫 〬 〭 〮 〯 〰 〱 〲 〳 〴 〵 〶 〷 〿
|
||||
Hiragana
|
||||
ぁ あ ぃ い ぅ う ぇ え ぉ お か が き ぎ く ぐ け げ こ ご さ ざ し じ す ず せ ぜ そ ぞ た だ ち ぢ っ つ づ て で と ど な に ぬ ね の は ば ぱ ひ び ぴ ふ ぶ ぷ へ べ ぺ ほ ぼ ぽ ま み む め も ゃ や ゅ ゆ ょ よ ら り る れ ろ ゎ わ ゐ ゑ を ん ゔ ゙ ゚ ゛ ゜ ゝ ゞ
|
||||
Katakana
|
||||
ァ ア ィ イ ゥ ウ ェ エ ォ オ カ ガ キ ギ ク グ ケ ゲ コ ゴ サ ザ シ ジ ス ズ セ ゼ ソ ゾ タ ダ チ ヂ ッ ツ ヅ テ デ ト ド ナ ニ ヌ ネ ノ ハ バ パ ヒ ビ ピ フ ブ プ ヘ ベ ペ ホ ボ ポ マ ミ ム メ モ ャ ヤ ュ ユ ョ ヨ ラ リ ル レ ロ ヮ ワ ヰ ヱ ヲ ン ヴ ヵ ヶ ヷ ヸ ヹ ヺ ・ ー ヽ ヾ
|
||||
Bopomofo
|
||||
ㄅ ㄆ ㄇ ㄈ ㄉ ㄊ ㄋ ㄌ ㄍ ㄎ ㄏ ㄐ ㄑ ㄒ ㄓ ㄔ ㄕ ㄖ ㄗ ㄘ ㄙ ㄚ ㄛ ㄜ ㄝ ㄞ ㄟ ㄠ ㄡ ㄢ ㄣ ㄤ ㄥ ㄦ ㄧ ㄨ ㄩ ㄪ ㄫ ㄬ
|
||||
@@ -0,0 +1,9 @@
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "stb_sprintf.h"
|
||||
#include "basic_string.cpp"
|
||||
#include "basic_string16.cpp"
|
||||
#include "basic_unicode.cpp"
|
||||
#include "basic_alloc.cpp"
|
||||
#include "basic_os.cpp"
|
||||
#include "math.cpp"
|
||||
#include "math_int.cpp"
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "basic_head.h"
|
||||
#include "basic_alloc.h"
|
||||
#include "basic_array.h"
|
||||
#include "basic_string.h"
|
||||
#include "basic_table.h"
|
||||
#include "basic_string16.h"
|
||||
#include "basic_unicode.h"
|
||||
#include "basic_os.h"
|
||||
#include "basic_list.h"
|
||||
#include "basic_math.h"
|
||||
@@ -0,0 +1,384 @@
|
||||
#if defined(USE_ADDRESS_SANITIZER)
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#endif
|
||||
|
||||
#if !defined(ASAN_POISON_MEMORY_REGION)
|
||||
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#else
|
||||
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ASAN_POISON_MEMORY_REGION(addr, size)
|
||||
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#if OS_WINDOWS
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
|
||||
API void *VReserve(size_t size) {
|
||||
void *result = (uint8_t *)VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool VCommit(void *p, size_t size) {
|
||||
void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
API bool VRelease(void *p, size_t size) {
|
||||
BOOL result = VirtualFree(p, 0, MEM_RELEASE);
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
API bool VDecommit(void *p, size_t size) {
|
||||
BOOL result = VirtualFree(p, size, MEM_DECOMMIT);
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
#elif OS_LINUX || OS_MAC
|
||||
|
||||
API void *VReserve(size_t size) {
|
||||
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t)0);
|
||||
return result == (void *)-1 ? 0 : result;
|
||||
}
|
||||
|
||||
API bool VCommit(void *p, size_t size) {
|
||||
int result = mprotect(p, size, PROT_READ | PROT_WRITE);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
API bool VRelease(void *p, size_t size) {
|
||||
int result = munmap(p, size);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
API bool VDecommit(void *p, size_t size) {
|
||||
mprotect(p, size, PROT_NONE);
|
||||
madvise(p, size, MADV_DONTNEED);
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
API void *VReserve(size_t size) {
|
||||
InvalidCodepath();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
API bool VCommit(void *p, size_t size) {
|
||||
InvalidCodepath();
|
||||
return false;
|
||||
}
|
||||
|
||||
API bool VRelease(void *p, size_t size) {
|
||||
InvalidCodepath();
|
||||
return false;
|
||||
}
|
||||
|
||||
API bool VDecommit(void *p, size_t size) {
|
||||
InvalidCodepath();
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
API void *SystemAllocatorProc(void *object, int kind, void *p, size_t size) {
|
||||
void *result = NULL;
|
||||
if (kind == AllocatorKind_Allocate) {
|
||||
result = malloc(size);
|
||||
Assert(result);
|
||||
} else if (kind == AllocatorKind_Deallocate) {
|
||||
free(p);
|
||||
} else {
|
||||
InvalidCodepath();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API Allocator GetSystemAllocator() {
|
||||
Allocator result = {SystemAllocatorProc};
|
||||
return result;
|
||||
}
|
||||
|
||||
API void *_AllocSize_(Allocator alo, size_t size) {
|
||||
void *result = alo.proc(alo.object, AllocatorKind_Allocate, NULL, size);
|
||||
memset(result, 0, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct MemoryRecord {
|
||||
size_t size;
|
||||
void *addr;
|
||||
char *file;
|
||||
int line;
|
||||
};
|
||||
thread_local Array<MemoryRecord> MemoryTrackingRecord;
|
||||
|
||||
|
||||
API void *TrackingAllocatorProc(void *object, int kind, void *p, size_t size) {
|
||||
void *result = NULL;
|
||||
|
||||
if (kind == AllocatorKind_Allocate) {
|
||||
result = malloc(size);
|
||||
Add(&MemoryTrackingRecord, {size, result, LocationTraceO.file, LocationTraceO.line});
|
||||
Assert(result);
|
||||
} else if (kind == AllocatorKind_Deallocate) {
|
||||
free(p);
|
||||
|
||||
bool found = false;
|
||||
For(IterateInReverse(&MemoryTrackingRecord)) {
|
||||
if (it.addr == p) {
|
||||
found = true;
|
||||
UnorderedRemove(&MemoryTrackingRecord, it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert(found);
|
||||
} else {
|
||||
InvalidCodepath();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API void TrackingAllocatorCheck() {
|
||||
// For (MemoryTrackingRecord) {
|
||||
// ReportConsolef("%s(%d): error: memory leak");
|
||||
// }
|
||||
Assert(MemoryTrackingRecord.len == 0);
|
||||
}
|
||||
|
||||
API Allocator GetTrackingAllocator() {
|
||||
Allocator result = {TrackingAllocatorProc};
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// Virtual Arena
|
||||
|
||||
API void InitArena(VirtualArena *arena, size_t reserve) {
|
||||
reserve = AlignUp(reserve, PAGE_SIZE);
|
||||
arena->align = DEFAULT_ALIGNMENT;
|
||||
arena->data = (uint8_t *)VReserve(reserve);
|
||||
if (arena->data) {
|
||||
arena->reserve = reserve;
|
||||
}
|
||||
}
|
||||
|
||||
API VirtualArena *AllocArena(Allocator allocator, size_t size) {
|
||||
VirtualArena *result = AllocType(allocator, VirtualArena);
|
||||
result->data = (uint8_t *)AllocSize(allocator, size);
|
||||
result->reserve = size;
|
||||
result->commit = size;
|
||||
result->align = DEFAULT_ALIGNMENT;
|
||||
return result;
|
||||
}
|
||||
|
||||
API VirtualArena *AllocArena(size_t reserve) {
|
||||
VirtualArena *result = NULL;
|
||||
|
||||
void *data = VReserve(reserve);
|
||||
if (!data) return result;
|
||||
|
||||
bool success = VCommit(data, PAGE_SIZE);
|
||||
if (!success) {
|
||||
VRelease(data, reserve);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (VirtualArena *)data;
|
||||
result->data = (uint8_t *)data;
|
||||
result->reserve = reserve;
|
||||
result->commit = PAGE_SIZE;
|
||||
result->len = result->base_len = sizeof(VirtualArena);
|
||||
result->align = DEFAULT_ALIGNMENT;
|
||||
return result;
|
||||
}
|
||||
|
||||
API void *PushSize(VirtualArena *arena, size_t size) {
|
||||
// base_len is used for bootstraping arenas, it denotes the
|
||||
// space occupied by the arena. If len is smaller then base_len then
|
||||
// we start to overwrite the arena itself - pure barbarism.
|
||||
Assert(arena->len >= arena->base_len);
|
||||
|
||||
size_t align_offset = 0;
|
||||
if (arena->align) {
|
||||
align_offset = GetAlignOffset((uintptr_t)arena->data + arena->len, arena->align);
|
||||
}
|
||||
size_t size_with_alignment = size + align_offset;
|
||||
size_t new_len = arena->len + size_with_alignment;
|
||||
if (new_len > arena->commit) {
|
||||
size_t new_len_aligned_to_page_size = AlignUp(new_len, PAGE_SIZE);
|
||||
size_t to_commit = new_len_aligned_to_page_size - arena->commit;
|
||||
size_t to_commit_clamped = ClampTop(to_commit, arena->reserve);
|
||||
if (to_commit_clamped > 0) {
|
||||
bool success = VCommit(arena->data + arena->commit, to_commit_clamped);
|
||||
if (success) {
|
||||
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->commit, to_commit_clamped);
|
||||
arena->commit += to_commit_clamped;
|
||||
}
|
||||
}
|
||||
if (new_len > arena->commit) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
uint8_t *result = arena->data + arena->len + align_offset;
|
||||
arena->len = new_len;
|
||||
MA_ASAN_UNPOISON_MEMORY_REGION(result, size);
|
||||
return (void *)result;
|
||||
}
|
||||
|
||||
API void Release(VirtualArena *arena) {
|
||||
if (arena == NULL || arena->data == NULL) return;
|
||||
bool zero_memory = (uint8_t *)arena != arena->data;
|
||||
VRelease(arena->data, arena->reserve);
|
||||
if (zero_memory) MemoryZero(arena, sizeof(VirtualArena));
|
||||
}
|
||||
|
||||
API void PopToPos(VirtualArena *arena, size_t pos) {
|
||||
// base_len is used for bootstraping arenas, it denotes the
|
||||
// space occupied by the arena. If len is smaller then base_len then
|
||||
// we start to overwrite the arena itself - pure barbarism.
|
||||
Assert(arena->len >= arena->base_len);
|
||||
|
||||
pos = Clamp(pos, arena->base_len, arena->len);
|
||||
size_t size = arena->len - pos;
|
||||
arena->len = pos;
|
||||
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->len, size);
|
||||
}
|
||||
|
||||
API void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size) {
|
||||
if (kind == AllocatorKind_Allocate) {
|
||||
return PushSize((VirtualArena *)object, size);
|
||||
} else if (AllocatorKind_Deallocate) {
|
||||
} else {
|
||||
Assert(!"invalid codepath");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// Block Arena
|
||||
|
||||
API void *PushSize(BlockArena *arena, size_t size) {
|
||||
if (size > (size_t)(arena->end - arena->start)) {
|
||||
size_t block_size = MiB(1);
|
||||
if (size > block_size) {
|
||||
block_size = size;
|
||||
}
|
||||
if (arena->allocator.proc == NULL) {
|
||||
arena->allocator = GetSystemAllocator();
|
||||
}
|
||||
BlockArenaNode *new_block = (BlockArenaNode *)AllocSize(arena->allocator, block_size + sizeof(BlockArenaNode));
|
||||
Assert(GetAlignOffset((size_t)new_block->start, DEFAULT_ALIGNMENT) == 0);
|
||||
arena->start = new_block->start;
|
||||
new_block->end = arena->end = new_block->start + block_size;
|
||||
SLL_STACK_ADD(arena->blocks, new_block);
|
||||
}
|
||||
U8 *result = arena->start;
|
||||
Assert(GetAlignOffset((size_t)result, DEFAULT_ALIGNMENT) == 0);
|
||||
arena->start = (U8 *)AlignUp((size_t)(arena->start + size), DEFAULT_ALIGNMENT);
|
||||
return result;
|
||||
}
|
||||
|
||||
API void Release(BlockArena *arena) {
|
||||
for (BlockArenaNode *it = arena->blocks, *next = NULL; it; it = next) {
|
||||
next = it->next;
|
||||
Dealloc(arena->allocator, it);
|
||||
}
|
||||
MemoryZero(arena, sizeof(BlockArena));
|
||||
}
|
||||
|
||||
API void Unwind(BlockArena *arena, U8 *pos) {
|
||||
bool contains = false;
|
||||
for (BlockArenaNode *it = arena->blocks, *next = NULL; it; it = next) {
|
||||
next = it->next;
|
||||
if ((pos >= it->start) && (pos < it->end)) {
|
||||
contains = true;
|
||||
break;
|
||||
} else {
|
||||
arena->blocks = arena->blocks->next;
|
||||
Dealloc(arena->allocator, it);
|
||||
}
|
||||
}
|
||||
Assert(contains || pos == NULL);
|
||||
arena->start = pos;
|
||||
}
|
||||
|
||||
API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size) {
|
||||
BlockArena *arena = (BlockArena *)object;
|
||||
if (kind == AllocatorKind_Allocate) {
|
||||
return PushSize(arena, size);
|
||||
} else if (AllocatorKind_Deallocate) {
|
||||
} else {
|
||||
Assert(!"invalid codepath");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RunArenaTest() {
|
||||
Allocator memory_tracking_allocator = GetTrackingAllocator();
|
||||
{
|
||||
BlockArena arena = {};
|
||||
arena.allocator = memory_tracking_allocator;
|
||||
for (int i = 0; i < 10000; i += 1) {
|
||||
int *vals = (int *)PushSize(&arena, sizeof(int)*i);
|
||||
for (int j = 0; j < i; j += 1) {
|
||||
vals[j] = j;
|
||||
}
|
||||
}
|
||||
Release(&arena);
|
||||
TrackingAllocatorCheck();
|
||||
}
|
||||
|
||||
{
|
||||
BlockArena arena = {};
|
||||
U8 *start = arena.start;
|
||||
arena.allocator = memory_tracking_allocator;
|
||||
int *vals = (int *)PushSize(&arena, sizeof(int) * 32);
|
||||
for (int i = 0; i < 32; i += 1) vals[i] = i;
|
||||
Unwind(&arena, (U8 *)vals);
|
||||
Assert(arena.blocks);
|
||||
Assert(arena.blocks->next == NULL);
|
||||
Assert(arena.start == (U8 *)vals);
|
||||
Assert(arena.blocks[0].start == (U8 *)vals);
|
||||
Unwind(&arena, NULL);
|
||||
Dealloc(arena.allocator, arena.blocks);
|
||||
TrackingAllocatorCheck();
|
||||
}
|
||||
|
||||
{
|
||||
BlockArena arena = {};
|
||||
arena.allocator = memory_tracking_allocator;
|
||||
int *vals = (int *)PushSize(&arena, sizeof(int) * 32);
|
||||
for (int i = 0; i < 32; i += 1) vals[i] = i;
|
||||
|
||||
U8 *p = arena.start;
|
||||
U8 *a = (U8 *)PushSize(&arena, KiB(32));
|
||||
U8 *b = (U8 *)PushSize(&arena, KiB(1000));
|
||||
Assert(arena.blocks);
|
||||
Assert(arena.blocks->next);
|
||||
Assert(arena.blocks->next->next == NULL);
|
||||
Unwind(&arena, a);
|
||||
Assert(arena.blocks);
|
||||
Assert(arena.blocks->next == NULL);
|
||||
Assert(arena.start == p);
|
||||
|
||||
Release(&arena);
|
||||
TrackingAllocatorCheck();
|
||||
}
|
||||
|
||||
{
|
||||
BlockArena arena = {};
|
||||
arena.allocator = memory_tracking_allocator;
|
||||
U8 *a = (U8 *)PushSize(&arena, KiB(2000));
|
||||
Assert((size_t)(arena.blocks[0].end - arena.blocks[0].start) == KiB(2000));
|
||||
Release(&arena);
|
||||
TrackingAllocatorCheck();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
|
||||
struct LocationTrace {
|
||||
char *file;
|
||||
int line;
|
||||
};
|
||||
|
||||
#if DEBUG_BUILD
|
||||
thread_local LocationTrace LocationTraceO;
|
||||
#define LOCATION_TRACE (LocationTraceO.file = __FILE__, LocationTraceO.line = __LINE__)
|
||||
#else
|
||||
#define LOCATION_TRACE
|
||||
#endif
|
||||
|
||||
const int AllocatorKind_Allocate = 1;
|
||||
const int AllocatorKind_Deallocate = 2;
|
||||
|
||||
struct Allocator {
|
||||
void *(*proc)(void *object, int kind, void *p, size_t size);
|
||||
void *object;
|
||||
};
|
||||
|
||||
#define AllocType(alo, Type) (Type *)AllocSize(alo, sizeof(Type))
|
||||
#define AllocArray(alo, Type, count) (Type *)AllocSize(alo, sizeof(Type) * (count))
|
||||
#define AllocSize(alo, size) (LOCATION_TRACE, _AllocSize_(alo, size))
|
||||
API void *_AllocSize_(Allocator alo, size_t size);
|
||||
inline void Dealloc(Allocator alo, void *p) { if (p) (alo).proc((alo).object, AllocatorKind_Deallocate, (p), 0); }
|
||||
|
||||
API Allocator GetSystemAllocator();
|
||||
API void TrackingAllocatorCheck();
|
||||
API Allocator GetTrackingAllocator();
|
||||
|
||||
#define MemoryZero(x, size) memset(x, 0, size)
|
||||
#define MemoryZeroStruct(x) memset(x, 0, sizeof(*x))
|
||||
#define MemoryCopy(dst, src, size) memcpy(dst, src, size)
|
||||
#define MemoryMove(dst, src, size) memmove(dst, src, size)
|
||||
|
||||
///////////////////
|
||||
// Block Arena
|
||||
///////////////////
|
||||
API void *BlockArenaAllocatorProc(void *object, int kind, void *p, size_t size);
|
||||
|
||||
struct BlockArenaNode {
|
||||
BlockArenaNode *next;
|
||||
U8 *end;
|
||||
U8 start[0];
|
||||
};
|
||||
|
||||
struct BlockArena {
|
||||
U8 *start;
|
||||
U8 *end;
|
||||
BlockArenaNode *blocks;
|
||||
Allocator allocator;
|
||||
|
||||
operator Allocator() { return {BlockArenaAllocatorProc, this}; }
|
||||
};
|
||||
|
||||
API void *PushSize(BlockArena *arena, size_t size);
|
||||
API void Release(BlockArena *arena);
|
||||
API void Unwind(BlockArena *arena, U8 *pos);
|
||||
|
||||
///////////////////
|
||||
// Virtual Arena
|
||||
///////////////////
|
||||
|
||||
struct VirtualArena {
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
size_t base_len; // to prevent self deleting the arena
|
||||
size_t reserve;
|
||||
size_t commit;
|
||||
size_t align;
|
||||
|
||||
operator Allocator() {
|
||||
void *ArenaAllocatorProc(void *object, int kind, void *p, size_t size);
|
||||
return {ArenaAllocatorProc, this};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline void SetLen(VirtualArena *arena, size_t len) { arena->len = Clamp(len, arena->base_len, arena->len); }
|
||||
inline void Pop(VirtualArena *arena, size_t size) { SetLen(arena, arena->len - size); }
|
||||
inline void Clear(VirtualArena *arena) { SetLen(arena, 0); }
|
||||
|
||||
API void *VReserve(size_t size);
|
||||
API bool VCommit(void *p, size_t size);
|
||||
API bool VRelease(void *p, size_t size);
|
||||
API bool VDecommit(void *p, size_t size);
|
||||
|
||||
API void InitArena(VirtualArena *arena, size_t reserve = MiB(256));
|
||||
API VirtualArena *AllocArena(size_t reserve = MiB(256));
|
||||
API VirtualArena *AllocArena(Allocator allocator, size_t size);
|
||||
API void *PushSize(VirtualArena *arena, size_t size);
|
||||
API void Release(VirtualArena *arena);
|
||||
|
||||
///////////////////////////////
|
||||
// Scratch
|
||||
|
||||
struct Scratch {
|
||||
BlockArena arena = {};
|
||||
Scratch() {}
|
||||
Scratch(BlockArena *conflict) {}
|
||||
Scratch(BlockArena *c1, BlockArena *c2) {}
|
||||
Scratch(Allocator conflict) {}
|
||||
Scratch(Allocator c1, Allocator c2) {}
|
||||
~Scratch() { Release(&arena); }
|
||||
operator BlockArena *() { return &arena; }
|
||||
operator Allocator() { return arena; }
|
||||
|
||||
private: // @Note: Disable copy constructors, cause its error prone
|
||||
Scratch(Scratch &arena);
|
||||
Scratch(Scratch &arena, Scratch &a2);
|
||||
};
|
||||
|
||||
const int PAGE_SIZE = 4096;
|
||||
const int DEFAULT_ALIGNMENT = sizeof(void *);
|
||||
@@ -0,0 +1,500 @@
|
||||
#pragma once
|
||||
/*
|
||||
// Iterating and removing elements
|
||||
for (int i = 0; i < array.len; i += 1) {
|
||||
auto &it = array[i];
|
||||
bool remove_item = false;
|
||||
defer {
|
||||
if (remove_item) {
|
||||
array.ordered_remove(it);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Simple delete
|
||||
IterRemove(arr) {
|
||||
IterRemovePrepare(arr);
|
||||
|
||||
remove_item = true;
|
||||
}
|
||||
|
||||
// Deleting backwards
|
||||
For(arr.reverse_iter()) {
|
||||
defer{ arr.unordered_remove(it); };
|
||||
}
|
||||
*/
|
||||
#define IterRemove(a) for (int i = 0; i < (a).len; i += 1)
|
||||
#define IterRemovePrepare(a) \
|
||||
auto &it = (a)[i]; \
|
||||
bool remove_item = false; \
|
||||
defer { \
|
||||
if (remove_item) { \
|
||||
Remove(&(a), it); \
|
||||
i -= 1; \
|
||||
} \
|
||||
}
|
||||
#define ForItem(it, array) for (auto &it : (array))
|
||||
#define For(array) ForItem(it, array)
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
struct Slice {
|
||||
T *data;
|
||||
int64_t len;
|
||||
|
||||
Slice() = default;
|
||||
Slice(T *s, int64_t l) : data(s), len(l) {}
|
||||
|
||||
T &operator[](int64_t index) {
|
||||
Assert(index < len);
|
||||
return data[index];
|
||||
}
|
||||
T *begin() { return data; }
|
||||
T *end() { return data + len; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Slice<T> Copy(Allocator alo, Slice<T> array) {
|
||||
Slice<T> result = {};
|
||||
result.data = AllocArray(alo, T, array.len);
|
||||
memcpy(result.data, array.data, sizeof(T) * array.len);
|
||||
result.len = array.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Pop(Slice<T> *arr) {
|
||||
Assert(arr->len > 0);
|
||||
return arr->data[--arr->len];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool Contains(Slice<T> &arr, T item) {
|
||||
For(arr) if (it == item) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int64_t GetIndex(Slice<T> &arr, const T &item) {
|
||||
ptrdiff_t index = (ptrdiff_t)(&item - arr.data);
|
||||
Assert(index >= 0 && index < arr.len);
|
||||
return (int64_t)index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Get(Slice<T> &arr, int64_t i, T default_value = {}) {
|
||||
T result = default_value;
|
||||
if (i >= 0 && i < arr.len) result = arr[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IsLast(Slice<T> &arr, T &item) {
|
||||
bool result = arr.last() == &item;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IsFirst(Slice<T> &arr, T &item) {
|
||||
bool result = arr.first() == &item;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *GetFirst(Slice<T> &arr) {
|
||||
Assert(arr.len > 0);
|
||||
return arr.data;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *GetLast(Slice<T> &arr) {
|
||||
Assert(arr.len > 0);
|
||||
return arr.data + arr.len - 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> Chop(Slice<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data, arr.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> Skip(Slice<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data + len, arr.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetPostfix(Slice<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
int64_t remain_len = arr.len - len;
|
||||
Slice<T> result = {arr.data + remain_len, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetPrefix(Slice<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetSlice(Slice<T> &arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST) {
|
||||
// Negative indexes work in python style, they return you the index counting from end of list
|
||||
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
|
||||
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
|
||||
|
||||
if (first_index == SLICE_LAST) first_index = arr.len;
|
||||
if (first_index < 0) first_index = arr.len + first_index;
|
||||
|
||||
Slice<T> result = {arr.data, arr.len};
|
||||
if (arr.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = ClampTop(first_index, arr.len - 1);
|
||||
one_past_last_index = ClampTop(one_past_last_index, arr.len);
|
||||
result.data += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
} else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Make arrays resize on every item
|
||||
#define ARRAY_DEBUG 0
|
||||
#if ARRAY_DEBUG
|
||||
#define ARRAY_IF_DEBUG_ELSE(IF, ELSE) IF
|
||||
#else
|
||||
#define ARRAY_IF_DEBUG_ELSE(IF, ELSE) ELSE
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
struct Array {
|
||||
Allocator allocator;
|
||||
int64_t cap;
|
||||
union {
|
||||
Slice<T> slice;
|
||||
struct {
|
||||
T *data;
|
||||
int64_t len;
|
||||
};
|
||||
};
|
||||
|
||||
T &operator[](int64_t index) {
|
||||
Assert(index >= 0 && index < len);
|
||||
return data[index];
|
||||
}
|
||||
T *begin() { return data; }
|
||||
T *end() { return data + len; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T *GetFirst(Array<T> &arr) {
|
||||
Assert(arr.len > 0);
|
||||
return arr.data;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *GetLast(Array<T> &arr) {
|
||||
Assert(arr.len > 0);
|
||||
return arr.data + arr.len - 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Reserve(Array<T> *arr, int64_t size) {
|
||||
if (size > arr->cap) {
|
||||
if (!arr->allocator.proc) arr->allocator = GetSystemAllocator();
|
||||
|
||||
T *new_data = AllocArray(arr->allocator, T, size);
|
||||
Assert(new_data);
|
||||
memcpy(new_data, arr->data, arr->len * sizeof(T));
|
||||
Dealloc(arr->allocator, arr->data);
|
||||
|
||||
arr->data = new_data;
|
||||
arr->cap = size;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void TryGrowing(Array<T> *arr) {
|
||||
if (arr->len + 1 > arr->cap) {
|
||||
int64_t initial_size = (int64_t)ARRAY_IF_DEBUG_ELSE(1, 16);
|
||||
int64_t new_size = ClampBottom(initial_size, arr->cap ARRAY_IF_DEBUG_ELSE(+1, *2));
|
||||
Reserve(arr, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void TryGrowing(Array<T> *arr, int64_t item_count) {
|
||||
if (arr->len + item_count > arr->cap) {
|
||||
int64_t initial_size = (int64_t)ARRAY_IF_DEBUG_ELSE(1, 16);
|
||||
int64_t new_size = ClampBottom(initial_size, (arr->cap + item_count) ARRAY_IF_DEBUG_ELSE(+1, *2));
|
||||
Reserve(arr, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Add(Array<T> *arr, T item) {
|
||||
TryGrowing(arr);
|
||||
arr->data[arr->len++] = item;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Add(Array<T> *arr, Array<T> &another) {
|
||||
For(another) Add(arr, it);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Add(Array<T> *arr, T *items, int64_t item_count) {
|
||||
for (int64_t i = 0; i < item_count; i += 1) Add(arr, items[i]);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BoundedAdd(Array<T> *arr, T item) {
|
||||
if (arr->len + 1 <= arr->cap) arr->data[arr->len++] = item;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void BoundedAddError(Array<T> *arr, T item) {
|
||||
Assert(arr->len + 1 <= arr->cap);
|
||||
if (arr->len + 1 <= arr->cap) arr->data[arr->len++] = item;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Insert(Array<T> *arr, T item, int64_t index) {
|
||||
if (index == arr->len) {
|
||||
Add(arr, item);
|
||||
return;
|
||||
}
|
||||
|
||||
Assert(index < arr->len);
|
||||
Assert(index >= 0);
|
||||
TryGrowing(arr);
|
||||
int64_t right_len = arr->len - index;
|
||||
memmove(arr->data + index + 1, arr->data + index, sizeof(T) * right_len);
|
||||
arr->data[index] = item;
|
||||
arr->len += 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Array<T> Copy(Allocator alo, Array<T> array) {
|
||||
Array<T> result = {alo};
|
||||
Reserve(&result, array.cap);
|
||||
memcpy(result.data, array.data, sizeof(T) * array.len);
|
||||
result.len = array.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Array<T> TightCopy(Allocator alo, Array<T> array) {
|
||||
Array<T> result = {alo};
|
||||
Reserve(&result, array.len);
|
||||
memcpy(result.data, array.data, sizeof(T) * array.len);
|
||||
result.len = array.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Pop(Array<T> *arr) {
|
||||
Assert(arr->len > 0);
|
||||
return arr->data[--arr->len];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool Contains(Array<T> &arr, T item) {
|
||||
For(arr) if (it == item) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int64_t GetIndex(Array<T> &arr, const T &item) {
|
||||
ptrdiff_t index = (ptrdiff_t)(&item - arr.data);
|
||||
Assert(index >= 0 && index < arr.len);
|
||||
return (int64_t)index;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void RemoveByIndex(Array<T> *arr, int64_t index) {
|
||||
Assert(index >= 0 && index < arr->len);
|
||||
int64_t right_len = arr->len - index - 1;
|
||||
memmove(arr->data + index, arr->data + index + 1, right_len * sizeof(T));
|
||||
arr->len -= 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void RemoveManyByIndex(Array<T> *arr, int64_t index, int64_t count) {
|
||||
if (count == 0) return;
|
||||
Assert(index >= 0 && index < arr->len);
|
||||
Assert((index + count) > 0 && (index + count) <= arr->len);
|
||||
int64_t right_len = arr->len - index - count;
|
||||
memmove(arr->data + index, arr->data + index + count, right_len * sizeof(T));
|
||||
arr->len -= count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void RemoveMany(Array<T> *arr, T &item, int64_t count) {
|
||||
Assert(arr->len > 0);
|
||||
Assert(&item >= arr->begin() && &item < arr->end());
|
||||
int64_t index = GetIndex(*arr, item);
|
||||
RemoveManyByIndex(arr, index, count);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Remove(Array<T> *arr, T &item) {
|
||||
Assert(arr->len > 0);
|
||||
Assert(&item >= arr->begin() && &item < arr->end());
|
||||
int64_t index = GetIndex(*arr, item);
|
||||
RemoveByIndex(arr, index);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void UnorderedRemove(Array<T> *arr, T &item) {
|
||||
Assert(arr->len > 0);
|
||||
Assert((&item >= arr->begin()) && (&item < arr->end()));
|
||||
item = arr->data[--arr->len];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void UnorderedRemoveByIndex(Array<T> *arr, int64_t index) {
|
||||
Assert(arr->len > 0);
|
||||
Assert(index >= 0 && index < arr->len);
|
||||
arr->data[index] = arr->data[--arr->len];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void InsertArray(Array<T> *arr, T *items, int64_t count, int64_t index) {
|
||||
if (index == arr->len) {
|
||||
Add(arr, items, count);
|
||||
return;
|
||||
}
|
||||
Assert(index < arr->len);
|
||||
|
||||
TryGrowing(arr, count);
|
||||
T *gap_begin = arr->data + index;
|
||||
T *gap_end = gap_begin + count;
|
||||
int64_t item_count = arr->len - index;
|
||||
memmove(gap_end, gap_begin, item_count * sizeof(T));
|
||||
for (int64_t i = 0; i < count; i += 1) arr->data[index + i] = items[i];
|
||||
arr->len += count;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Get(Array<T> &arr, int64_t i, T default_value = {}) {
|
||||
T result = default_value;
|
||||
if (i >= 0 && i < arr.len) result = arr[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Dealloc(Array<T> *arr) {
|
||||
if (arr->data) {
|
||||
Dealloc(arr->allocator, arr->data);
|
||||
arr->data = NULL;
|
||||
}
|
||||
arr->len = arr->cap = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IsLast(Array<T> &arr, T &item) {
|
||||
bool result = GetLast(arr) == &item;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool IsFirst(Array<T> &arr, T &item) {
|
||||
bool result = GetFirst(arr) == &item;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> Chop(Array<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data, arr.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> Skip(Array<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data + len, arr.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetPostfix(Array<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
int64_t remain_len = arr.len - len;
|
||||
Slice<T> result = {arr.data + remain_len, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetPrefix(Array<T> &arr, int64_t len) {
|
||||
len = ClampTop(len, arr.len);
|
||||
Slice<T> result = {arr.data, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Slice<T> GetSlice(Array<T> &arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST) {
|
||||
// Negative indexes work in python style, they return you the index counting from end of list
|
||||
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
|
||||
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
|
||||
|
||||
if (first_index == SLICE_LAST) first_index = arr.len;
|
||||
if (first_index < 0) first_index = arr.len + first_index;
|
||||
|
||||
Slice<T> result = {arr.data, arr.len};
|
||||
if (arr.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = ClampTop(first_index, arr.len - 1);
|
||||
one_past_last_index = ClampTop(one_past_last_index, arr.len);
|
||||
result.data += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
} else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct ReverseIter {
|
||||
T *data;
|
||||
Slice<T> *arr;
|
||||
|
||||
ReverseIter operator++(int) {
|
||||
ReverseIter ret = *this;
|
||||
data -= 1;
|
||||
return ret;
|
||||
}
|
||||
ReverseIter &operator++() {
|
||||
data -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T &operator*() { return data[0]; }
|
||||
T *operator->() { return data; }
|
||||
|
||||
friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; };
|
||||
friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; };
|
||||
|
||||
ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; }
|
||||
ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ReverseIter<T> IterateInReverse(Array<T> *arr) {
|
||||
return {arr->end() - 1, &arr->slice};
|
||||
}
|
||||
template <class T>
|
||||
ReverseIter<T> IterateInReverse(Slice<T> *slice) {
|
||||
return {slice->end() - 1, slice};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
#pragma once
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define OS_POSIX 1
|
||||
#define OS_MAC 1
|
||||
#elif defined(_WIN32)
|
||||
#define OS_WINDOWS 1
|
||||
#elif defined(__linux__)
|
||||
#define OS_POSIX 1
|
||||
#define OS_LINUX 1
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define OS_WASM 1
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#define COMPILER_CLANG 1
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#define COMPILER_GCC 1
|
||||
#elif defined(_MSC_VER)
|
||||
#define COMPILER_MSVC 1
|
||||
#else
|
||||
#error Unsupported compiler
|
||||
#endif
|
||||
|
||||
#ifndef OS_WASM
|
||||
#define OS_WASM 0
|
||||
#endif
|
||||
|
||||
#ifndef OS_MAC
|
||||
#define OS_MAC 0
|
||||
#endif
|
||||
|
||||
#ifndef OS_WINDOWS
|
||||
#define OS_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#ifndef OS_LINUX
|
||||
#define OS_LINUX 0
|
||||
#endif
|
||||
|
||||
#ifndef OS_POSIX
|
||||
#define OS_POSIX 0
|
||||
#endif
|
||||
|
||||
#ifndef COMPILER_MSVC
|
||||
#define COMPILER_MSVC 0
|
||||
#endif
|
||||
|
||||
#ifndef COMPILER_CLANG
|
||||
#define COMPILER_CLANG 0
|
||||
#endif
|
||||
|
||||
#ifndef COMPILER_GCC
|
||||
#define COMPILER_GCC 0
|
||||
#endif
|
||||
|
||||
#if OS_WINDOWS
|
||||
#define BREAK() __debugbreak()
|
||||
#elif OS_LINUX
|
||||
#define BREAK() raise(SIGTRAP)
|
||||
#elif OS_WASM
|
||||
#include <emscripten.h>
|
||||
EM_JS(void, JS_Breakpoint, (), {
|
||||
debugger;
|
||||
})
|
||||
#define BREAK() JS_Breakpoint()
|
||||
#endif
|
||||
|
||||
#define API
|
||||
#define Assert(x) \
|
||||
if (!(x)) { \
|
||||
BREAK(); \
|
||||
}
|
||||
#define InvalidCodepath() Assert(!"invalid codepath")
|
||||
#define ElseInvalidCodepath() else {InvalidCodepath()}
|
||||
|
||||
#define KiB(x) ((x##ull) * 1024ull)
|
||||
#define MiB(x) (KiB(x) * 1024ull)
|
||||
#define GiB(x) (MiB(x) * 1024ull)
|
||||
#define TiB(x) (GiB(x) * 1024ull)
|
||||
#define Lengthof(x) ((int64_t)((sizeof(x) / sizeof((x)[0]))))
|
||||
#define SLICE_LAST INT64_MAX
|
||||
|
||||
using U8 = uint8_t;
|
||||
using U16 = uint16_t;
|
||||
using U32 = uint32_t;
|
||||
using U64 = uint64_t;
|
||||
using S8 = int8_t;
|
||||
using S16 = int16_t;
|
||||
using S32 = int32_t;
|
||||
using S64 = int64_t;
|
||||
using Int = S64;
|
||||
using UInt = U64;
|
||||
|
||||
template <class T>
|
||||
T Min(T a, T b) {
|
||||
if (a > b) return b;
|
||||
return a;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T ClampTop(T a, T top) {
|
||||
return Min(a, top);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Max(T a, T b) {
|
||||
if (a > b) return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T ClampBottom(T bottom, T b) {
|
||||
return Max(bottom, b);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T Clamp(T value, T min, T max) {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Swap(T *a, T *b) {
|
||||
T temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
}
|
||||
|
||||
inline bool IsPowerOf2(size_t x) {
|
||||
size_t result = (((x) & ((x)-1)) == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t WrapAroundPowerOf2(size_t x, size_t pow2) {
|
||||
Assert(IsPowerOf2(pow2));
|
||||
size_t result = (((x) & ((pow2)-1llu)));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint64_t HashBytes(void *data, unsigned size) {
|
||||
uint8_t *data8 = (uint8_t *)data;
|
||||
uint64_t hash = (uint64_t)14695981039346656037ULL;
|
||||
for (unsigned i = 0; i < size; i++) {
|
||||
hash = hash ^ (uint64_t)(data8[i]);
|
||||
hash = hash * (uint64_t)1099511628211ULL;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
inline size_t GetAlignOffset(size_t size, size_t align) {
|
||||
Assert(IsPowerOf2(align));
|
||||
size_t mask = align - 1;
|
||||
size_t val = size & mask;
|
||||
if (val) {
|
||||
val = align - val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
inline size_t AlignUp(size_t size, size_t align) {
|
||||
size_t result = size + GetAlignOffset(size, align);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t AlignDown(size_t size, size_t align) {
|
||||
size += 1; // Make sure when align is 8 doesn't get rounded down to 0
|
||||
size_t result = size - (align - GetAlignOffset(size, align));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct DEFER_ExitScope {
|
||||
T lambda;
|
||||
DEFER_ExitScope(T lambda) : lambda(lambda) {}
|
||||
~DEFER_ExitScope() { lambda(); }
|
||||
DEFER_ExitScope(const DEFER_ExitScope &i) : lambda(i.lambda){};
|
||||
|
||||
private:
|
||||
DEFER_ExitScope &operator=(const DEFER_ExitScope &);
|
||||
};
|
||||
|
||||
class DEFER_ExitScopeHelp {
|
||||
public:
|
||||
template <typename T>
|
||||
DEFER_ExitScope<T> operator+(T t) { return t; }
|
||||
};
|
||||
|
||||
#define DEFER_CONCAT_INTERNAL(x, y) x##y
|
||||
#define DEFER_CONCAT(x, y) DEFER_CONCAT_INTERNAL(x, y)
|
||||
#define defer const auto DEFER_CONCAT(defer__, __LINE__) = DEFER_ExitScopeHelp() + [&]()
|
||||
|
||||
struct RandomSeed {
|
||||
uint64_t a;
|
||||
};
|
||||
|
||||
inline uint64_t GetRandomU64(RandomSeed *state) {
|
||||
uint64_t x = state->a;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
return state->a = x;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
#define SLL_QUEUE_ADD_MOD(f, l, n, next) \
|
||||
do { \
|
||||
(n)->next = 0; \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
(l) = (l)->next = (n); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLL_QUEUE_ADD(f, l, n) SLL_QUEUE_ADD_MOD(f, l, n, next)
|
||||
|
||||
#define SLL_QUEUE_POP_FIRST_MOD(f, l, next) \
|
||||
do { \
|
||||
if ((f) == (l)) { \
|
||||
(f) = (l) = 0; \
|
||||
} else { \
|
||||
(f) = (f)->next; \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLL_QUEUE_POP_FIRST(f, l) SLL_QUEUE_POP_FIRST_MOD(f, l, next)
|
||||
|
||||
#define SLL_STACK_ADD_MOD(stack_base, new_stack_base, next) \
|
||||
do { \
|
||||
(new_stack_base)->next = (stack_base); \
|
||||
(stack_base) = (new_stack_base); \
|
||||
} while (0)
|
||||
#define SLL_STACK_ADD(stack_base, new_stack_base) \
|
||||
SLL_STACK_ADD_MOD(stack_base, new_stack_base, next)
|
||||
|
||||
#define SLL_STACK_POP_AND_STORE(stack_base, out_node) \
|
||||
do { \
|
||||
if (stack_base) { \
|
||||
(out_node) = (stack_base); \
|
||||
(stack_base) = (stack_base)->next; \
|
||||
(out_node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DLL_QUEUE_ADD_MOD(f, l, node, next, prev) \
|
||||
do { \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} else { \
|
||||
(l)->next = (node); \
|
||||
(node)->prev = (l); \
|
||||
(node)->next = 0; \
|
||||
(l) = (node); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLL_QUEUE_ADD(f, l, node) DLL_QUEUE_ADD_MOD(f, l, node, next, prev)
|
||||
#define DLL_QUEUE_ADD_FRONT(f, l, node) DLL_QUEUE_ADD_MOD(l, f, node, prev, next)
|
||||
#define DLL_QUEUE_REMOVE_MOD(first, last, node, next, prev) \
|
||||
do { \
|
||||
if ((first) == (last)) { \
|
||||
(first) = (last) = 0; \
|
||||
} else if ((last) == (node)) { \
|
||||
(last) = (last)->prev; \
|
||||
(last)->next = 0; \
|
||||
} else if ((first) == (node)) { \
|
||||
(first) = (first)->next; \
|
||||
(first)->prev = 0; \
|
||||
} else { \
|
||||
(node)->prev->next = (node)->next; \
|
||||
(node)->next->prev = (node)->prev; \
|
||||
} \
|
||||
if (node) { \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLL_QUEUE_REMOVE(first, last, node) DLL_QUEUE_REMOVE_MOD(first, last, node, next, prev)
|
||||
|
||||
#define DLL_STACK_ADD_MOD(first, node, next, prev) \
|
||||
do { \
|
||||
(node)->next = (first); \
|
||||
if ((first)) \
|
||||
(first)->prev = (node); \
|
||||
(first) = (node); \
|
||||
(node)->prev = 0; \
|
||||
} while (0)
|
||||
#define DLL_STACK_ADD(first, node) DLL_STACK_ADD_MOD(first, node, next, prev)
|
||||
#define DLL_STACK_REMOVE_MOD(first, node, next, prev) \
|
||||
do { \
|
||||
if ((node) == (first)) { \
|
||||
(first) = (first)->next; \
|
||||
if ((first)) \
|
||||
(first)->prev = 0; \
|
||||
} else { \
|
||||
(node)->prev->next = (node)->next; \
|
||||
if ((node)->next) \
|
||||
(node)->next->prev = (node)->prev; \
|
||||
} \
|
||||
if (node) { \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLL_STACK_REMOVE(first, node) DLL_STACK_REMOVE_MOD(first, node, next, prev)
|
||||
|
||||
#define DLL_INSERT_NEXT_MOD(base, new, next, prev) \
|
||||
do { \
|
||||
if ((base) == 0) { \
|
||||
(base) = (new); \
|
||||
(new)->next = 0; \
|
||||
(new)->prev = 0; \
|
||||
} else { \
|
||||
(new)->next = (base)->next; \
|
||||
(base)->next = (new); \
|
||||
(new)->prev = (base); \
|
||||
if ((new)->next) (new)->next->prev = (new); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLL_INSERT_NEXT(base, new) DLL_INSERT_NEXT_MOD(base, new, next, prev)
|
||||
#define DLL_INSERT_PREV(base, new) DLL_INSERT_NEXT_MOD(base, new, next, prev)
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include <math.h>
|
||||
|
||||
struct Vec2 {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
union Vec4 {
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
};
|
||||
};
|
||||
|
||||
union Vec3 {
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
};
|
||||
};
|
||||
|
||||
struct Rect2 {
|
||||
Vec2 min;
|
||||
Vec2 max;
|
||||
};
|
||||
|
||||
struct Vec2I {
|
||||
Int x;
|
||||
Int y;
|
||||
};
|
||||
|
||||
struct Rect2I {
|
||||
Vec2I min;
|
||||
Vec2I max;
|
||||
};
|
||||
|
||||
union Color {
|
||||
struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
#define PI32 3.14159265359f
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
struct FileIter {
|
||||
bool is_valid;
|
||||
bool is_directory;
|
||||
String absolute_path;
|
||||
String relative_path;
|
||||
String filename;
|
||||
|
||||
String path;
|
||||
Allocator allocator;
|
||||
union {
|
||||
struct Win32_FileIter *w32;
|
||||
void *dir;
|
||||
};
|
||||
};
|
||||
|
||||
String ReadFile(Allocator arena, String path);
|
||||
bool WriteFile(String path, String data);
|
||||
String GetAbsolutePath(Allocator arena, String relative);
|
||||
bool IsValid(const FileIter &it);
|
||||
void Advance(FileIter *it);
|
||||
FileIter IterateFiles(Allocator allocator, String path);
|
||||
void InitOS(void (*error_proc)(const char *, ...));
|
||||
|
||||
bool DeleteFile(String path);
|
||||
String GetExePath(Allocator allocator);
|
||||
String GetExeDir(Allocator allocator);
|
||||
bool FileExists(String path);
|
||||
bool IsDir(String path);
|
||||
bool IsFile(String path);
|
||||
String GetWorkingDir(Allocator arena);
|
||||
bool IsAbsolute(String path);
|
||||
int64_t GetFileModTime(String file);
|
||||
|
||||
struct Process {
|
||||
bool is_valid;
|
||||
int exit_code;
|
||||
char platform[6 * 8];
|
||||
int64_t id;
|
||||
|
||||
int64_t view_id; // text editor view
|
||||
bool scroll_to_end;
|
||||
};
|
||||
|
||||
Process SpawnProcess(String command_line, String working_dir, String write_stdin = {}, Array<String> enviroment = {});
|
||||
bool IsValid(Process *process);
|
||||
void KillProcess(Process *process);
|
||||
String PollStdout(Allocator allocator, Process *process, bool force_read);
|
||||
void WriteStdin(Process *process, String string);
|
||||
void CloseStdin(Process *process);
|
||||
double GetTimeMicros(void);
|
||||
|
||||
enum MakeDirResult {
|
||||
MakeDirResult_Success,
|
||||
MakeDirResult_Exists,
|
||||
MakeDirResult_NotFound,
|
||||
MakeDirResult_ErrorOther,
|
||||
};
|
||||
|
||||
MakeDirResult MakeDir(String path);
|
||||
@@ -0,0 +1,336 @@
|
||||
API char ToLowerCase(char a) {
|
||||
if (a >= 'A' && a <= 'Z') a += 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
API char ToUpperCase(char a) {
|
||||
if (a >= 'a' && a <= 'z') a -= 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
API bool IsWhitespace(char w) {
|
||||
bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsAlphabetic(char a) {
|
||||
bool result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsIdent(char a) {
|
||||
bool result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsDigit(char a) {
|
||||
bool result = a >= '0' && a <= '9';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsAlphanumeric(char a) {
|
||||
bool result = IsDigit(a) || IsAlphabetic(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsSymbol(char w) {
|
||||
bool result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsNonWord(char w) {
|
||||
if (w == '_') return false;
|
||||
bool result = IsSymbol(w) || IsWhitespace(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsWord(char w) {
|
||||
bool result = !IsNonWord(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsBrace(char c) {
|
||||
bool result = c == '{' || c == '}';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsParen(char c) {
|
||||
bool result = c == '(' || c == ')';
|
||||
return result;
|
||||
}
|
||||
|
||||
API String Chop(String a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String result = {a.data, a.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String Skip(String a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String result = {a.data + len, a.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String GetPostfix(String a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
int64_t remain_len = a.len - len;
|
||||
String result = {a.data + remain_len, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String GetPrefix(String a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String result = {a.data, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String GetSlice(String arr, int64_t first_index, int64_t one_past_last_index) {
|
||||
// Negative indexes work in python style, they return you the index counting from end of list
|
||||
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
|
||||
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
|
||||
|
||||
if (first_index == SLICE_LAST) first_index = arr.len;
|
||||
if (first_index < 0) first_index = arr.len + first_index;
|
||||
|
||||
String result = {arr.data, arr.len};
|
||||
if (arr.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = ClampTop(first_index, arr.len - 1);
|
||||
one_past_last_index = ClampTop(one_past_last_index, arr.len);
|
||||
result.data += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
} else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool AreEqual(String a, String b, unsigned ignore_case) {
|
||||
if (a.len != b.len) return false;
|
||||
for (int64_t i = 0; i < a.len; i++) {
|
||||
char A = a.data[i];
|
||||
char B = b.data[i];
|
||||
if (ignore_case) {
|
||||
A = ToLowerCase(A);
|
||||
B = ToLowerCase(B);
|
||||
}
|
||||
if (A != B)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
API bool EndsWith(String a, String end, unsigned ignore_case) {
|
||||
String a_end = GetPostfix(a, end.len);
|
||||
bool result = AreEqual(end, a_end, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool StartsWith(String a, String start, unsigned ignore_case) {
|
||||
String a_start = GetPrefix(a, start.len);
|
||||
bool result = AreEqual(start, a_start, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String Trim(String string) {
|
||||
if (string.len == 0)
|
||||
return string;
|
||||
|
||||
int64_t whitespace_begin = 0;
|
||||
for (; whitespace_begin < string.len; whitespace_begin++) {
|
||||
if (!IsWhitespace(string.data[whitespace_begin])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != whitespace_begin; whitespace_end--) {
|
||||
if (!IsWhitespace(string.data[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (whitespace_begin == whitespace_end) {
|
||||
string.len = 0;
|
||||
} else {
|
||||
string = GetSlice(string, whitespace_begin, whitespace_end);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
API String TrimEnd(String string) {
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != 0; whitespace_end--) {
|
||||
if (!IsWhitespace(string.data[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String result = GetPrefix(string, whitespace_end);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String Copy(Allocator allocator, String string) {
|
||||
char *copy = (char *)AllocSize(allocator, sizeof(char) * (string.len + 1));
|
||||
memcpy(copy, string.data, string.len);
|
||||
copy[string.len] = 0;
|
||||
String result = {copy, string.len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String Copy(Allocator allocator, char *string) {
|
||||
return Copy(allocator, {string, (int64_t)strlen(string)});
|
||||
}
|
||||
|
||||
API void NormalizePathInPlace(String s) {
|
||||
for (int64_t i = 0; i < s.len; i++) {
|
||||
if (s.data[i] == '\\')
|
||||
s.data[i] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
API String NormalizePath(Allocator allocator, String s) {
|
||||
String copy = Copy(allocator, s);
|
||||
NormalizePathInPlace(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
API bool Seek(String string, String find, int64_t *index_out, SeekFlag flags) {
|
||||
bool ignore_case = flags & SeekFlag_IgnoreCase ? true : false;
|
||||
bool result = false;
|
||||
if (flags & SeekFlag_MatchFindLast) {
|
||||
for (int64_t i = string.len; i != 0; i--) {
|
||||
int64_t index = i - 1;
|
||||
String substring = GetSlice(string, index, index + find.len);
|
||||
if (AreEqual(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = index;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int64_t i = 0; i < string.len; i++) {
|
||||
String substring = GetSlice(string, i, i + find.len);
|
||||
if (AreEqual(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = i;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
API String CutLastSlash(String *s) {
|
||||
String result = *s;
|
||||
Seek(*s, "/", &s->len, SeekFlag_MatchFindLast);
|
||||
result = Skip(result, s->len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String ChopLastSlash(String s) {
|
||||
String result = s;
|
||||
Seek(s, "/", &result.len, SeekFlag_MatchFindLast);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String ChopLastPeriod(String s) {
|
||||
String result = s;
|
||||
Seek(s, ".", &result.len, SeekFlag_MatchFindLast);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String SkipToLastSlash(String s) {
|
||||
int64_t pos;
|
||||
String result = s;
|
||||
if (Seek(s, "/", &pos, SeekFlag_MatchFindLast)) {
|
||||
result = Skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API String SkipToLastPeriod(String s) {
|
||||
int64_t pos;
|
||||
String result = s;
|
||||
if (Seek(s, ".", &pos, SeekFlag_MatchFindLast)) {
|
||||
result = Skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API String CutPrefix(String *string, int64_t len) {
|
||||
String result = GetPrefix(*string, len);
|
||||
*string = Skip(*string, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String CutPostfix(String *string, int64_t len) {
|
||||
String result = GetPostfix(*string, len);
|
||||
*string = Chop(*string, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String FormatV(Allocator allocator, const char *data, va_list args1) {
|
||||
va_list args2;
|
||||
va_copy(args2, args1);
|
||||
int64_t len = stbsp_vsnprintf(0, 0, data, args2);
|
||||
va_end(args2);
|
||||
|
||||
char *result = (char *)AllocSize(allocator, sizeof(char) * (len + 1));
|
||||
stbsp_vsnprintf(result, (int)(len + 1), data, args1);
|
||||
String res = {result, len};
|
||||
return res;
|
||||
}
|
||||
|
||||
API String Format(Allocator allocator, const char *data, ...) {
|
||||
STRING_FORMAT(allocator, data, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
API Array<String> Split(Allocator allocator, String string, String delimiter) {
|
||||
Array<String> result = {allocator};
|
||||
int64_t index = 0;
|
||||
while (Seek(string, delimiter, &index)) {
|
||||
String before_match = {string.data, index};
|
||||
Add(&result, before_match);
|
||||
string = Skip(string, index + delimiter.len);
|
||||
}
|
||||
Add(&result, string);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String Merge(Allocator allocator, Array<String> list, String separator) {
|
||||
int64_t char_count = 0;
|
||||
For(list) char_count += it.len;
|
||||
if (char_count == 0) return {};
|
||||
int64_t node_count = list.len;
|
||||
|
||||
int64_t base_size = (char_count + 1);
|
||||
int64_t sep_size = (node_count - 1) * separator.len;
|
||||
int64_t size = base_size + sep_size;
|
||||
char *buff = (char *)AllocSize(allocator, sizeof(char) * (size + 1));
|
||||
String string = {buff, 0};
|
||||
For(list) {
|
||||
Assert(string.len + it.len <= size);
|
||||
memcpy(string.data + string.len, it.data, it.len);
|
||||
string.len += it.len;
|
||||
if (!IsLast(list, it)) {
|
||||
memcpy(string.data + string.len, separator.data, separator.len);
|
||||
string.len += separator.len;
|
||||
}
|
||||
}
|
||||
Assert(string.len == size - 1);
|
||||
string.data[size] = 0;
|
||||
return string;
|
||||
}
|
||||
|
||||
API Int GetSize(Array<String> array) {
|
||||
Int result = 0;
|
||||
For (array) result += it.len;
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
struct String {
|
||||
char *data;
|
||||
int64_t len;
|
||||
|
||||
String() = default;
|
||||
String(char *s) : data(s), len(strlen(s)) {}
|
||||
String(char *s, int64_t l) : data((char *)s), len(l) {}
|
||||
String(const char *s) : data((char *)s), len(strlen((char *)s)) {}
|
||||
String(const char *s, int64_t l) : data((char *)s), len(l) {}
|
||||
|
||||
|
||||
char &operator[](int64_t index) {
|
||||
Assert(index < len);
|
||||
return data[index];
|
||||
}
|
||||
char *begin() { return data; }
|
||||
char *end() { return data + len; }
|
||||
|
||||
struct ReverseIter {
|
||||
char *data;
|
||||
String *arr;
|
||||
|
||||
ReverseIter operator++(int) {
|
||||
ReverseIter ret = *this;
|
||||
data -= 1;
|
||||
return ret;
|
||||
}
|
||||
ReverseIter &operator++() {
|
||||
data -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
char &operator*() { return data[0]; }
|
||||
char *operator->() { return data; }
|
||||
|
||||
friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; };
|
||||
friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; };
|
||||
|
||||
ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; }
|
||||
ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; }
|
||||
};
|
||||
ReverseIter reverse() { return {this->end() - 1, this}; }
|
||||
};
|
||||
|
||||
API char ToLowerCase(char a);
|
||||
API char ToUpperCase(char a);
|
||||
API bool IsWhitespace(char w);
|
||||
API bool IsAlphabetic(char a);
|
||||
API bool IsIdent(char a);
|
||||
API bool IsDigit(char a);
|
||||
API bool IsAlphanumeric(char a);
|
||||
API bool IsSymbol(char w);
|
||||
API bool IsNonWord(char w);
|
||||
API bool IsWord(char w);
|
||||
API bool IsBrace(char c);
|
||||
API bool IsParen(char c);
|
||||
|
||||
API bool EndsWith(String a, String end, unsigned ignore_case = false);
|
||||
API bool StartsWith(String a, String start, unsigned ignore_case = false);
|
||||
API bool AreEqual(String a, String b, unsigned ignore_case = false);
|
||||
inline bool operator==(String a, String b) { return AreEqual(a, b); }
|
||||
inline bool operator!=(String a, String b) { return !AreEqual(a, b); }
|
||||
|
||||
API String Trim(String string);
|
||||
API String TrimEnd(String string);
|
||||
API String Chop(String a, int64_t len);
|
||||
API String Skip(String a, int64_t len);
|
||||
API String GetPostfix(String a, int64_t len);
|
||||
API String GetPrefix(String a, int64_t len);
|
||||
API String GetSlice(String arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST);
|
||||
API String CutLastSlash(String *s);
|
||||
API String ChopLastSlash(String s);
|
||||
API String ChopLastPeriod(String s);
|
||||
API String SkipToLastSlash(String s);
|
||||
API String SkipToLastPeriod(String s);
|
||||
API String CutPrefix(String *string, int64_t len);
|
||||
API String CutPostfix(String *string, int64_t len);
|
||||
|
||||
API String Copy(Allocator allocator, String string);
|
||||
API String Copy(Allocator allocator, char *string);
|
||||
API void NormalizePathInPlace(String s);
|
||||
API String NormalizePath(Allocator allocator, String s);
|
||||
|
||||
API String FormatV(Allocator allocator, const char *data, va_list args1);
|
||||
API String Format(Allocator allocator, const char *data, ...);
|
||||
#define STRING_FORMAT(allocator, data, result) \
|
||||
va_list args1; \
|
||||
va_start(args1, data); \
|
||||
String result = FormatV(allocator, data, args1); \
|
||||
va_end(args1)
|
||||
|
||||
|
||||
typedef int SeekFlag;
|
||||
enum {
|
||||
SeekFlag_None = 0,
|
||||
SeekFlag_IgnoreCase = 1,
|
||||
SeekFlag_MatchFindLast = 2,
|
||||
};
|
||||
API bool Seek(String string, String find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None);
|
||||
|
||||
API Array<String> Split(Allocator allocator, String string, String delimiter = " ");
|
||||
API String Merge(Allocator allocator, Array<String> list, String separator);
|
||||
API Int GetSize(Array<String> array);
|
||||
@@ -0,0 +1,422 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
API int64_t WideLength(char16_t *string) {
|
||||
if (!string) return 0;
|
||||
int64_t len = 0;
|
||||
while (*string++ != 0)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
API char16_t ToLowerCase(char16_t a) {
|
||||
if (a >= u'A' && a <= u'Z') a += 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
API char16_t ToUpperCase(char16_t a) {
|
||||
if (a >= u'a' && a <= u'z') a -= 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
API bool IsWhitespace(char16_t w) {
|
||||
bool result = w == u'\n' || w == u' ' || w == u'\t' || w == u'\v' || w == u'\r';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsAlphabetic(char16_t a) {
|
||||
bool result = (a >= u'a' && a <= u'z') || (a >= u'A' && a <= u'Z');
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsIdent(char16_t a) {
|
||||
bool result = (a >= u'a' && a <= u'z') || (a >= u'A' && a <= u'Z') || a == u'_';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsDigit(char16_t a) {
|
||||
bool result = a >= u'0' && a <= u'9';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsAlphanumeric(char16_t a) {
|
||||
bool result = IsDigit(a) || IsAlphabetic(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsSymbol(char16_t w) {
|
||||
bool result = (w >= u'!' && w <= u'/') || (w >= u':' && w <= u'@') || (w >= u'[' && w <= u'`') || (w >= u'{' && w <= u'~');
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsNonWord(char16_t w) {
|
||||
if (w == u'_') return false;
|
||||
bool result = IsSymbol(w) || IsWhitespace(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsWord(char16_t w) {
|
||||
bool result = !IsNonWord(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsBrace(char16_t c) {
|
||||
bool result = c == u'{' || c == u'}';
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool IsParen(char16_t c) {
|
||||
bool result = c == u'(' || c == u')';
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
API String16 Chop(String16 a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String16 result = {a.data, a.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Skip(String16 a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String16 result = {a.data + len, a.len - len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 GetPostfix(String16 a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
int64_t remain_len = a.len - len;
|
||||
String16 result = {a.data + remain_len, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 GetPrefix(String16 a, int64_t len) {
|
||||
len = ClampTop(len, a.len);
|
||||
String16 result = {a.data, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 GetSlice(String16 arr, int64_t first_index, int64_t one_past_last_index) {
|
||||
// Negative indexes work in python style, they return you the index counting from end of list
|
||||
if (one_past_last_index == SLICE_LAST) one_past_last_index = arr.len;
|
||||
if (one_past_last_index < 0) one_past_last_index = arr.len + one_past_last_index;
|
||||
|
||||
if (first_index == SLICE_LAST) first_index = arr.len;
|
||||
if (first_index < 0) first_index = arr.len + first_index;
|
||||
|
||||
String16 result = {arr.data, arr.len};
|
||||
if (arr.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = ClampTop(first_index, arr.len - 1);
|
||||
one_past_last_index = ClampTop(one_past_last_index, arr.len);
|
||||
result.data += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
} else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool AreEqual(String16 a, String16 b, unsigned ignore_case) {
|
||||
if (a.len != b.len) return false;
|
||||
for (int64_t i = 0; i < a.len; i++) {
|
||||
char16_t A = a.data[i];
|
||||
char16_t B = b.data[i];
|
||||
if (ignore_case) {
|
||||
A = ToLowerCase(A);
|
||||
B = ToLowerCase(B);
|
||||
}
|
||||
if (A != B)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
API bool EndsWith(String16 a, String16 end, unsigned ignore_case) {
|
||||
String16 a_end = GetPostfix(a, end.len);
|
||||
bool result = AreEqual(end, a_end, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
API bool StartsWith(String16 a, String16 start, unsigned ignore_case) {
|
||||
String16 a_start = GetPrefix(a, start.len);
|
||||
bool result = AreEqual(start, a_start, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Trim(String16 string) {
|
||||
if (string.len == 0)
|
||||
return string;
|
||||
|
||||
int64_t whitespace_begin = 0;
|
||||
for (; whitespace_begin < string.len; whitespace_begin++) {
|
||||
if (!IsWhitespace(string.data[whitespace_begin])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != whitespace_begin; whitespace_end--) {
|
||||
if (!IsWhitespace(string.data[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (whitespace_begin == whitespace_end) {
|
||||
string.len = 0;
|
||||
} else {
|
||||
string = GetSlice(string, whitespace_begin, whitespace_end);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
API String16 TrimEnd(String16 string) {
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != 0; whitespace_end--) {
|
||||
if (!IsWhitespace(string.data[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String16 result = GetPrefix(string, whitespace_end);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Copy16(Allocator allocator, String16 string) {
|
||||
char16_t *copy = (char16_t *)AllocSize(allocator, sizeof(char16_t) * (string.len + 1));
|
||||
memcpy(copy, string.data, string.len * sizeof(char16_t));
|
||||
copy[string.len] = 0;
|
||||
String16 result = {copy, string.len};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Copy16(Allocator allocator, char16_t *string) {
|
||||
return Copy16(allocator, {string, (int64_t)WideLength(string)});
|
||||
}
|
||||
|
||||
API void NormalizePathInPlace(String16 s) {
|
||||
for (int64_t i = 0; i < s.len; i++) {
|
||||
if (s.data[i] == u'\\')
|
||||
s.data[i] = u'/';
|
||||
}
|
||||
}
|
||||
|
||||
API String16 NormalizePath(Allocator allocator, String16 s) {
|
||||
String16 copy = Copy16(allocator, s);
|
||||
NormalizePathInPlace(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
API bool Seek(String16 string, String16 find, int64_t *index_out, SeekFlag flags) {
|
||||
bool ignore_case = flags & SeekFlag_IgnoreCase ? true : false;
|
||||
bool result = false;
|
||||
if (flags & SeekFlag_MatchFindLast) {
|
||||
for (int64_t i = string.len; i != 0; i--) {
|
||||
int64_t index = i - 1;
|
||||
String16 substring = GetSlice(string, index, index + find.len);
|
||||
if (AreEqual(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = index;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int64_t i = 0; i < string.len; i++) {
|
||||
String16 substring = GetSlice(string, i, i + find.len);
|
||||
if (AreEqual(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = i;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 CutLastSlash(String16 *s) {
|
||||
String16 result = *s;
|
||||
Seek(*s, u"/", &s->len, SeekFlag_MatchFindLast);
|
||||
result = Skip(result, s->len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 ChopLastSlash(String16 s) {
|
||||
String16 result = s;
|
||||
Seek(s, u"/", &result.len, SeekFlag_MatchFindLast);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 ChopLastPeriod(String16 s) {
|
||||
String16 result = s;
|
||||
Seek(s, u".", &result.len, SeekFlag_MatchFindLast);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 SkipToLastSlash(String16 s) {
|
||||
int64_t pos;
|
||||
String16 result = s;
|
||||
if (Seek(s, u"/", &pos, SeekFlag_MatchFindLast)) {
|
||||
result = Skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 SkipToLastPeriod(String16 s) {
|
||||
int64_t pos;
|
||||
String16 result = s;
|
||||
if (Seek(s, u".", &pos, SeekFlag_MatchFindLast)) {
|
||||
result = Skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 CutPrefix(String16 *string, int64_t len) {
|
||||
String16 result = GetPrefix(*string, len);
|
||||
*string = Skip(*string, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 CutPostfix(String16 *string, int64_t len) {
|
||||
String16 result = GetPostfix(*string, len);
|
||||
*string = Chop(*string, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Format16V(Allocator allocator, const char *data, va_list args1) {
|
||||
Scratch scratch;
|
||||
va_list args2;
|
||||
va_copy(args2, args1);
|
||||
int64_t len = stbsp_vsnprintf(0, 0, data, args2);
|
||||
va_end(args2);
|
||||
|
||||
char *result = (char *)AllocSize(scratch, sizeof(char) * (len + 1));
|
||||
stbsp_vsnprintf(result, (int)(len + 1), data, args1);
|
||||
String res = {result, len};
|
||||
String16 res16 = ToString16(allocator, res);
|
||||
return res16;
|
||||
}
|
||||
|
||||
API String16 Format16(Allocator allocator, const char *data, ...) {
|
||||
Scratch scratch;
|
||||
STRING_FORMAT(scratch, data, result);
|
||||
String16 result16 = ToString16(allocator, result);
|
||||
return result16;
|
||||
}
|
||||
|
||||
API Array<String16> Split(Allocator allocator, String16 string, String16 delimiter) {
|
||||
Array<String16> result = {allocator};
|
||||
int64_t index = 0;
|
||||
while (Seek(string, delimiter, &index)) {
|
||||
String16 before_match = {string.data, index};
|
||||
Add(&result, before_match);
|
||||
string = Skip(string, index + delimiter.len);
|
||||
}
|
||||
Add(&result, string);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 Merge(Allocator allocator, Array<String16> list, String16 separator) {
|
||||
int64_t char_count = 0;
|
||||
For(list) char_count += it.len;
|
||||
if (char_count == 0) return {};
|
||||
int64_t node_count = list.len;
|
||||
|
||||
int64_t base_size = (char_count + 1);
|
||||
int64_t sep_size = (node_count - 1) * separator.len;
|
||||
int64_t size = base_size + sep_size;
|
||||
char16_t *buff = (char16_t *)AllocSize(allocator, sizeof(char16_t) * (size + 1));
|
||||
String16 string = {buff, 0};
|
||||
For(list) {
|
||||
Assert(string.len + it.len <= size);
|
||||
memcpy(string.data + string.len, it.data, it.len * sizeof(char16_t));
|
||||
string.len += it.len;
|
||||
if (!IsLast(list, it)) {
|
||||
memcpy(string.data + string.len, separator.data, separator.len * sizeof(char16_t));
|
||||
string.len += separator.len;
|
||||
}
|
||||
}
|
||||
Assert(string.len == size - 1);
|
||||
string.data[size] = 0;
|
||||
return string;
|
||||
}
|
||||
|
||||
API Int GetSize(Array<String16> array) {
|
||||
Int result = 0;
|
||||
For (array) result += it.len;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
API String16 SkipNumberEx(String16 *string) {
|
||||
String16 col = {string->data, 0};
|
||||
for (int64_t i = 0; i < string->len; i += 1) {
|
||||
if (IsDigit(string->data[i])) {
|
||||
col.len += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*string = Skip(*string, col.len);
|
||||
return col;
|
||||
}
|
||||
|
||||
API Int SkipNumber(String16 *string) {
|
||||
String16 col = SkipNumberEx(string);
|
||||
if (col.len == 0) return -1;
|
||||
Scratch scratch;
|
||||
String num_string = ToString(scratch, col);
|
||||
Int result = strtoll(num_string.data, NULL, 10);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 SkipUntil(String16 *string, String16 str) {
|
||||
String16 begin = *string;
|
||||
begin.len = 0;
|
||||
for (; string->len; begin.len += 1) {
|
||||
String16 match = GetPrefix(*string, str.len);
|
||||
if (StartsWith(match, str)) break;
|
||||
*string = Skip(*string, 1);
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
API String16 SkipWhitespace(String16 *string) {
|
||||
String16 begin = {string->data, 0};
|
||||
for (Int i = 0; i < string->len; i += 1) {
|
||||
if (!IsWhitespace(string->data[i])) break;
|
||||
*string = Skip(*string, 1);
|
||||
begin.len += 1;
|
||||
}
|
||||
return begin;
|
||||
}
|
||||
|
||||
// chop this - :324
|
||||
API String16 ChopNumberEx(String16 *string) {
|
||||
String16 col = {};
|
||||
for (int64_t i = string->len - 1; i >= 0; i -= 1) {
|
||||
if (IsDigit(string->data[i])) {
|
||||
col.data = string->data + i;
|
||||
col.len += 1;
|
||||
} else if (string->data[i] == L':') {
|
||||
break;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
*string = Chop(*string, col.len + 1);
|
||||
return col;
|
||||
}
|
||||
|
||||
API Int ChopNumber(String16 *string) {
|
||||
Scratch scratch;
|
||||
String16 col = ChopNumberEx(string);
|
||||
if (col.len == 0) return -1;
|
||||
String num_string = ToString(scratch, col);
|
||||
Int result = strtoll(num_string.data, NULL, 10) - 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
API int64_t WideLength(char16_t *string);
|
||||
|
||||
struct String16 {
|
||||
char16_t *data;
|
||||
int64_t len;
|
||||
|
||||
String16() = default;
|
||||
String16(char16_t *s) : data(s), len(WideLength(s)) {}
|
||||
String16(char16_t *s, int64_t l) : data((char16_t *)s), len(l) {}
|
||||
String16(const char16_t *s) : data((char16_t *)s), len(WideLength((char16_t *)s)) {}
|
||||
String16(const char16_t *s, int64_t l) : data((char16_t *)s), len(l) {}
|
||||
|
||||
|
||||
char16_t &operator[](int64_t index) {
|
||||
Assert(index < len);
|
||||
return data[index];
|
||||
}
|
||||
char16_t *begin() { return data; }
|
||||
char16_t *end() { return data + len; }
|
||||
|
||||
struct ReverseIter {
|
||||
char16_t *data;
|
||||
String16 *arr;
|
||||
|
||||
ReverseIter operator++(int) {
|
||||
ReverseIter ret = *this;
|
||||
data -= 1;
|
||||
return ret;
|
||||
}
|
||||
ReverseIter &operator++() {
|
||||
data -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
char16_t &operator*() { return data[0]; }
|
||||
char16_t *operator->() { return data; }
|
||||
|
||||
friend bool operator==(const ReverseIter &a, const ReverseIter &b) { return a.data == b.data; };
|
||||
friend bool operator!=(const ReverseIter &a, const ReverseIter &b) { return a.data != b.data; };
|
||||
|
||||
ReverseIter begin() { return ReverseIter{arr->end() - 1, arr}; }
|
||||
ReverseIter end() { return ReverseIter{arr->begin() - 1, arr}; }
|
||||
};
|
||||
ReverseIter reverse() { return {this->end() - 1, this}; }
|
||||
};
|
||||
|
||||
API char16_t ToLowerCase(char16_t a);
|
||||
API char16_t ToUpperCase(char16_t a);
|
||||
API bool IsWhitespace(char16_t w);
|
||||
API bool IsAlphabetic(char16_t a);
|
||||
API bool IsIdent(char16_t a);
|
||||
API bool IsDigit(char16_t a);
|
||||
API bool IsAlphanumeric(char16_t a);
|
||||
API bool IsSymbol(char16_t w);
|
||||
API bool IsNonWord(char16_t w);
|
||||
API bool IsWord(char16_t w);
|
||||
API bool IsBrace(char16_t c);
|
||||
API bool IsParen(char16_t c);
|
||||
|
||||
API bool EndsWith(String16 a, String16 end, unsigned ignore_case = false);
|
||||
API bool StartsWith(String16 a, String16 start, unsigned ignore_case = false);
|
||||
API bool AreEqual(String16 a, String16 b, unsigned ignore_case = false);
|
||||
inline bool operator==(String16 a, String16 b) { return AreEqual(a, b); }
|
||||
inline bool operator!=(String16 a, String16 b) { return !AreEqual(a, b); }
|
||||
|
||||
API String16 Trim(String16 string);
|
||||
API String16 TrimEnd(String16 string);
|
||||
API String16 Chop(String16 a, int64_t len);
|
||||
API String16 Skip(String16 a, int64_t len);
|
||||
API String16 GetPostfix(String16 a, int64_t len);
|
||||
API String16 GetPrefix(String16 a, int64_t len);
|
||||
API String16 GetSlice(String16 arr, int64_t first_index = 0, int64_t one_past_last_index = SLICE_LAST);
|
||||
API String16 CutLastSlash(String16 *s);
|
||||
API String16 ChopLastSlash(String16 s);
|
||||
API String16 ChopLastPeriod(String16 s);
|
||||
API String16 SkipToLastSlash(String16 s);
|
||||
API String16 SkipToLastPeriod(String16 s);
|
||||
API String16 CutPrefix(String16 *string, int64_t len);
|
||||
API String16 CutPostfix(String16 *string, int64_t len);
|
||||
|
||||
// @todo: think about this API, for parsing, maybe redesign or something
|
||||
API String16 SkipNumberEx(String16 *string);
|
||||
API Int SkipNumber(String16 *string);
|
||||
API String16 SkipUntil(String16 *string, String16 str);
|
||||
API String16 SkipWhitespace(String16 *string);
|
||||
API String16 ChopNumberEx(String16 *string);
|
||||
API Int ChopNumber(String16 *string);
|
||||
|
||||
API String16 Copy16(Allocator allocator, String16 string);
|
||||
API String16 Copy16(Allocator allocator, char16_t *string, int64_t len);
|
||||
API String16 Copy16(Allocator allocator, char *string);
|
||||
API void NormalizePathInPlace(String16 s);
|
||||
API String16 NormalizePath(Allocator allocator, String16 s);
|
||||
|
||||
API String16 Format16V(Allocator allocator, const char *data, va_list args1);
|
||||
API String16 Format16(Allocator allocator, const char *data, ...);
|
||||
|
||||
API bool Seek(String16 string, String16 find, int64_t *index_out = NULL, SeekFlag flags = SeekFlag_None);
|
||||
|
||||
API Array<String16> Split(Allocator allocator, String16 string, String16 delimiter = u" ");
|
||||
API String16 Merge(Allocator allocator, Array<String16> list, String16 separator);
|
||||
API Int GetSize(Array<String16> array);
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
Hash table implementation:
|
||||
Pointers to values
|
||||
Open adressing
|
||||
Linear Probing
|
||||
Power of 2
|
||||
Robin Hood hashing
|
||||
Resizes on high probe count (min max load factor)
|
||||
|
||||
Hash 0 is reserved for empty hash table entry
|
||||
*/
|
||||
template <class Value>
|
||||
struct HashTable {
|
||||
struct Entry {
|
||||
uint64_t hash;
|
||||
uint64_t key;
|
||||
size_t distance;
|
||||
Value value;
|
||||
};
|
||||
|
||||
Allocator allocator;
|
||||
size_t len, cap;
|
||||
Entry *values;
|
||||
|
||||
static const size_t max_load_factor = 80;
|
||||
static const size_t min_load_factor = 50;
|
||||
static const size_t significant_distance = 8;
|
||||
|
||||
// load factor calculation was rearranged
|
||||
// to get rid of division:
|
||||
//> 100 * len / cap = load_factor
|
||||
//> len * 100 = load_factor * cap
|
||||
inline bool reached_load_factor(size_t lfactor) {
|
||||
return (len + 1) * 100 >= lfactor * cap;
|
||||
}
|
||||
|
||||
inline bool is_empty(Entry *entry) { return entry->hash == 0; }
|
||||
inline bool is_occupied(Entry *entry) { return entry->hash != 0; }
|
||||
|
||||
void reserve(size_t size) {
|
||||
Assert(size > cap && "New size is smaller then original size");
|
||||
Assert(IsPowerOf2(size));
|
||||
if (!allocator.proc) allocator = GetSystemAllocator();
|
||||
|
||||
Entry *old_values = values;
|
||||
size_t old_cap = cap;
|
||||
|
||||
values = (Entry *)AllocSize(allocator, sizeof(Entry) * size);
|
||||
for (size_t i = 0; i < size; i += 1) values[i] = {};
|
||||
cap = size;
|
||||
|
||||
Assert(!(old_values == 0 && len != 0));
|
||||
if (len == 0) {
|
||||
if (old_values) {
|
||||
Dealloc(allocator, old_values);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
for (size_t i = 0; i < old_cap; i += 1) {
|
||||
Entry *it = old_values + i;
|
||||
if (is_occupied(it)) {
|
||||
insert(it->key, it->value);
|
||||
}
|
||||
}
|
||||
Dealloc(allocator, old_values);
|
||||
}
|
||||
|
||||
Entry *get_table_entry(uint64_t key) {
|
||||
if (len == 0) return 0;
|
||||
uint64_t hash = HashBytes(&key, sizeof(key));
|
||||
if (hash == 0) hash += 1;
|
||||
uint64_t index = WrapAroundPowerOf2(hash, cap);
|
||||
uint64_t i = index;
|
||||
uint64_t distance = 0;
|
||||
for (;;) {
|
||||
Entry *it = values + i;
|
||||
if (distance > it->distance) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (it->hash == hash && it->key == key) {
|
||||
return it;
|
||||
}
|
||||
|
||||
distance += 1;
|
||||
i = WrapAroundPowerOf2(i + 1, cap);
|
||||
if (i == index) return 0;
|
||||
}
|
||||
Assert(!"Invalid codepath");
|
||||
}
|
||||
|
||||
void insert(uint64_t key, const Value &value) {
|
||||
if (reached_load_factor(max_load_factor)) {
|
||||
if (cap == 0) cap = 16; // 32 cause cap*2
|
||||
reserve(cap * 2);
|
||||
}
|
||||
|
||||
uint64_t hash = HashBytes(&key, sizeof(key));
|
||||
if (hash == 0) hash += 1;
|
||||
uint64_t index = WrapAroundPowerOf2(hash, cap);
|
||||
uint64_t i = index;
|
||||
Entry to_insert = {hash, key, 0, value};
|
||||
for (;;) {
|
||||
Entry *it = values + i;
|
||||
if (is_empty(it)) {
|
||||
*it = to_insert;
|
||||
len += 1;
|
||||
// If we have more then 8 consecutive items we try to resize
|
||||
if (to_insert.distance > 8 && reached_load_factor(min_load_factor)) {
|
||||
reserve(cap * 2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (it->hash == hash && it->key == key) {
|
||||
*it = to_insert;
|
||||
// If we have more then 8 consecutive items we try to resize
|
||||
if (to_insert.distance > 8 && reached_load_factor(min_load_factor)) {
|
||||
reserve(cap * 2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Robin hood hashing
|
||||
if (to_insert.distance > it->distance) {
|
||||
Entry temp = to_insert;
|
||||
to_insert = *it;
|
||||
*it = temp;
|
||||
}
|
||||
|
||||
to_insert.distance += 1;
|
||||
i = WrapAroundPowerOf2(i + 1, cap);
|
||||
Assert(i != index && "Did a full 360 through a hash table, no good :( that shouldnt be possible");
|
||||
}
|
||||
Assert(!"Invalid codepath");
|
||||
}
|
||||
|
||||
void remove(uint64_t key) {
|
||||
Entry *entry = get_table_entry(key);
|
||||
entry->hash = 0;
|
||||
entry->distance = 0;
|
||||
len -= 1;
|
||||
}
|
||||
|
||||
Value *get(uint64_t key) {
|
||||
Entry *v = get_table_entry(key);
|
||||
if (!v) return 0;
|
||||
return &v->value;
|
||||
}
|
||||
|
||||
Value get(uint64_t key, Value default_value) {
|
||||
Entry *v = get_table_entry(key);
|
||||
if (!v) return default_value;
|
||||
return v->value;
|
||||
}
|
||||
|
||||
Value *get(String s) {
|
||||
uint64_t hash = HashBytes(s.data, (unsigned)s.len);
|
||||
return get(hash);
|
||||
}
|
||||
|
||||
Value get(String s, Value default_value) {
|
||||
uint64_t hash = HashBytes(s.data, (unsigned)s.len);
|
||||
return get(hash, default_value);
|
||||
}
|
||||
|
||||
void put(String s, const Value &value) {
|
||||
uint64_t hash = HashBytes(s.data, (unsigned)s.len);
|
||||
insert(hash, value);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
len = 0;
|
||||
for (size_t i = 0; i < cap; i += 1) {
|
||||
Entry *it = values + i;
|
||||
it->hash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void dealloc() {
|
||||
Dealloc(allocator, values);
|
||||
values = NULL;
|
||||
len = 0;
|
||||
cap = 0;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,237 @@
|
||||
API UTF32Result UTF16ToUTF32(uint16_t *c, int64_t max_advance) {
|
||||
UTF32Result result;
|
||||
MemoryZero(&result, sizeof(result));
|
||||
if (max_advance >= 1) {
|
||||
result.advance = 1;
|
||||
result.out_str = c[0];
|
||||
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) {
|
||||
if (max_advance >= 2) {
|
||||
result.out_str = 0x10000;
|
||||
result.out_str += (uint32_t)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF);
|
||||
result.advance = 2;
|
||||
} else
|
||||
result.error = 2;
|
||||
}
|
||||
} else {
|
||||
result.error = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
API UTF8Result UTF32ToUTF8(uint32_t codepoint) {
|
||||
UTF8Result result;
|
||||
MemoryZero(&result, sizeof(result));
|
||||
|
||||
if (codepoint <= 0x7F) {
|
||||
result.len = 1;
|
||||
result.out_str[0] = (char)codepoint;
|
||||
} else if (codepoint <= 0x7FF) {
|
||||
result.len = 2;
|
||||
result.out_str[0] = 0xc0 | (0x1f & (codepoint >> 6));
|
||||
result.out_str[1] = 0x80 | (0x3f & codepoint);
|
||||
} else if (codepoint <= 0xFFFF) { // 16 bit word
|
||||
result.len = 3;
|
||||
result.out_str[0] = 0xe0 | (0xf & (codepoint >> 12)); // 4 bits
|
||||
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
|
||||
result.out_str[2] = 0x80 | (0x3f & codepoint); // 6 bits
|
||||
} else if (codepoint <= 0x10FFFF) { // 21 bit word
|
||||
result.len = 4;
|
||||
result.out_str[0] = 0xf0 | (0x7 & (codepoint >> 18)); // 3 bits
|
||||
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 12)); // 6 bits
|
||||
result.out_str[2] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
|
||||
result.out_str[3] = 0x80 | (0x3f & codepoint); // 6 bits
|
||||
} else {
|
||||
result.error = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
API UTF32Result UTF8ToUTF32(uint8_t *c, int64_t max_advance) {
|
||||
UTF32Result result;
|
||||
MemoryZero(&result, sizeof(result));
|
||||
|
||||
if ((c[0] & 0x80) == 0) { // Check if leftmost zero of first byte is unset
|
||||
if (max_advance >= 1) {
|
||||
result.out_str = c[0];
|
||||
result.advance = 1;
|
||||
} else result.error = 1;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xe0) == 0xc0) {
|
||||
if ((c[1] & 0xc0) == 0x80) { // Continuation byte required
|
||||
if (max_advance >= 2) {
|
||||
result.out_str = (uint32_t)(c[0] & 0x1f) << 6u | (c[1] & 0x3f);
|
||||
result.advance = 2;
|
||||
} else result.error = 2;
|
||||
} else result.error = 2;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xf0) == 0xe0) {
|
||||
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80) { // Two continuation bytes required
|
||||
if (max_advance >= 3) {
|
||||
result.out_str = (uint32_t)(c[0] & 0xf) << 12u | (uint32_t)(c[1] & 0x3f) << 6u | (c[2] & 0x3f);
|
||||
result.advance = 3;
|
||||
} else result.error = 3;
|
||||
} else result.error = 3;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xf8) == 0xf0) {
|
||||
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80 && (c[3] & 0xc0) == 0x80) { // Three continuation bytes required
|
||||
if (max_advance >= 4) {
|
||||
result.out_str = (uint32_t)(c[0] & 0xf) << 18u | (uint32_t)(c[1] & 0x3f) << 12u | (uint32_t)(c[2] & 0x3f) << 6u | (uint32_t)(c[3] & 0x3f);
|
||||
result.advance = 4;
|
||||
} else result.error = 4;
|
||||
} else result.error = 4;
|
||||
} else result.error = 4;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
API UTF16Result UTF32ToUTF16(uint32_t codepoint) {
|
||||
UTF16Result result;
|
||||
MemoryZero(&result, sizeof(result));
|
||||
if (codepoint < 0x10000) {
|
||||
result.out_str[0] = (uint16_t)codepoint;
|
||||
result.out_str[1] = 0;
|
||||
result.len = 1;
|
||||
} else if (codepoint <= 0x10FFFF) {
|
||||
uint32_t code = (codepoint - 0x10000);
|
||||
result.out_str[0] = (uint16_t)(0xD800 | (code >> 10));
|
||||
result.out_str[1] = (uint16_t)(0xDC00 | (code & 0x3FF));
|
||||
result.len = 2;
|
||||
} else {
|
||||
result.error = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define UTF__HANDLE_DECODE_ERROR(question_mark, I) \
|
||||
{ \
|
||||
if (outlen < buffer_size - 1) buffer[outlen++] = (question_mark); \
|
||||
i += I; \
|
||||
}
|
||||
|
||||
API int64_t CreateCharFromWidechar(char *buffer, int64_t buffer_size, char16_t *in, int64_t inlen) {
|
||||
int64_t outlen = 0;
|
||||
for (int64_t i = 0; i < inlen && in[i];) {
|
||||
UTF32Result decode = UTF16ToUTF32((uint16_t *)(in + i), (int64_t)(inlen - i));
|
||||
if (!decode.error) {
|
||||
i += decode.advance;
|
||||
UTF8Result encode = UTF32ToUTF8(decode.out_str);
|
||||
if (!encode.error) {
|
||||
for (int64_t j = 0; j < encode.len; j++) {
|
||||
if (outlen < buffer_size - 1) {
|
||||
buffer[outlen++] = encode.out_str[j];
|
||||
}
|
||||
}
|
||||
} else UTF__HANDLE_DECODE_ERROR('?', 0);
|
||||
} else UTF__HANDLE_DECODE_ERROR('?', 1);
|
||||
}
|
||||
|
||||
buffer[outlen] = 0;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
API int64_t CreateWidecharFromChar(char16_t *buffer, int64_t buffer_size, char *in, int64_t inlen) {
|
||||
int64_t outlen = 0;
|
||||
for (int64_t i = 0; i < inlen;) {
|
||||
UTF32Result decode = UTF8ToUTF32((uint8_t *)(in + i), (int64_t)(inlen - i));
|
||||
if (!decode.error) {
|
||||
i += decode.advance;
|
||||
UTF16Result encode = UTF32ToUTF16(decode.out_str);
|
||||
if (!encode.error) {
|
||||
for (int64_t j = 0; j < encode.len; j++) {
|
||||
if (outlen < buffer_size - 1) {
|
||||
buffer[outlen++] = encode.out_str[j];
|
||||
}
|
||||
}
|
||||
} else UTF__HANDLE_DECODE_ERROR(0x003f, 0);
|
||||
} else UTF__HANDLE_DECODE_ERROR(0x003f, 1);
|
||||
}
|
||||
|
||||
buffer[outlen] = 0;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
API bool IsValid(UTF8Iter &iter) {
|
||||
return iter.item;
|
||||
}
|
||||
|
||||
API void Advance(UTF8Iter *iter) {
|
||||
iter->i += iter->utf8_codepoint_byte_size;
|
||||
UTF32Result r = UTF8ToUTF32((uint8_t *)(iter->data + iter->i), iter->len - iter->i);
|
||||
if (r.error) {
|
||||
iter->item = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
iter->utf8_codepoint_byte_size = r.advance;
|
||||
iter->item = r.out_str;
|
||||
}
|
||||
|
||||
API UTF8Iter IterateUTF8Ex(char *data, int64_t len) {
|
||||
UTF8Iter result;
|
||||
MemoryZero(&result, sizeof(result));
|
||||
result.data = data;
|
||||
result.len = len;
|
||||
if (len) Advance(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
API UTF8Iter IterateUTF8(char *data) {
|
||||
int64_t length = 0;
|
||||
while (data[length]) length += 1;
|
||||
return IterateUTF8Ex(data, length);
|
||||
}
|
||||
|
||||
API UTF8Iter IterateUTF8(String string) {
|
||||
return IterateUTF8Ex(string.data, string.len);
|
||||
}
|
||||
|
||||
API bool IsUTF8ContinuationByte(char c) {
|
||||
char result = (c & 0b11000000) == 0b10000000;
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 ToString16(Allocator allocator, String string) {
|
||||
char16_t *buffer = (char16_t *)AllocSize(allocator, sizeof(char16_t) * (string.len + 1));
|
||||
int64_t size = CreateWidecharFromChar(buffer, string.len + 1, string.data, string.len);
|
||||
String16 result = {buffer, size};
|
||||
return result;
|
||||
}
|
||||
|
||||
API String16 ToString16(Allocator allocator, char *in_string) {
|
||||
String string(in_string);
|
||||
String16 result = ToString16(allocator, string);
|
||||
return result;
|
||||
}
|
||||
|
||||
API char16_t *ToWidechar(Allocator allocator, String string) {
|
||||
String16 result = ToString16(allocator, string);
|
||||
return result.data;
|
||||
}
|
||||
|
||||
API String ToString(Allocator allocator, String16 string) {
|
||||
Assert(sizeof(char16_t) == 2);
|
||||
|
||||
int64_t buffer_size = (string.len + 1) * 2;
|
||||
char *buffer = (char *)AllocSize(allocator, buffer_size);
|
||||
int64_t size = CreateCharFromWidechar(buffer, buffer_size, string.data, string.len);
|
||||
String result = {buffer, size};
|
||||
|
||||
Assert(size < buffer_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
API String ToString(Allocator allocator, char16_t *string, int64_t len) {
|
||||
return ToString(allocator, {string, len});
|
||||
}
|
||||
|
||||
API String ToString(Allocator allocator, char16_t *wstring) {
|
||||
int64_t size = WideLength(wstring);
|
||||
String result = ToString(allocator, {wstring, size});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
struct UTF32Result {
|
||||
uint32_t out_str;
|
||||
int64_t advance;
|
||||
int64_t error;
|
||||
};
|
||||
|
||||
struct UTF8Result {
|
||||
uint8_t out_str[4];
|
||||
int64_t len;
|
||||
int64_t error;
|
||||
};
|
||||
|
||||
struct UTF16Result {
|
||||
uint16_t out_str[2];
|
||||
int64_t len;
|
||||
int64_t error;
|
||||
};
|
||||
|
||||
struct UTF8Iter {
|
||||
char *data;
|
||||
int64_t len;
|
||||
int64_t utf8_codepoint_byte_size;
|
||||
int64_t i;
|
||||
uint32_t item;
|
||||
|
||||
UTF8Iter &operator++() {
|
||||
void Advance(UTF8Iter * iter);
|
||||
Advance(this);
|
||||
return *this;
|
||||
}
|
||||
friend bool operator!=(const UTF8Iter &a, const UTF8Iter &b) { return a.item != b.item; }
|
||||
UTF8Iter &operator*() { return *this; }
|
||||
UTF8Iter begin() {
|
||||
UTF8Iter IterateUTF8Ex(char *data, int64_t len);
|
||||
return {IterateUTF8Ex(data, len)};
|
||||
}
|
||||
UTF8Iter end() { return {}; }
|
||||
};
|
||||
|
||||
API UTF32Result UTF16ToUTF32(uint16_t *c, int64_t max_advance);
|
||||
API UTF8Result UTF32ToUTF8(uint32_t codepoint);
|
||||
API UTF32Result UTF8ToUTF32(uint8_t *c, int64_t max_advance);
|
||||
API UTF16Result UTF32ToUTF16(uint32_t codepoint);
|
||||
|
||||
API int64_t CreateCharFromWidechar(char *buffer, int64_t buffer_size, char16_t *in, int64_t inlen);
|
||||
API int64_t CreateWidecharFromChar(char16_t *buffer, int64_t buffer_size, char *in, int64_t inlen);
|
||||
API char16_t *ToWidechar(Allocator allocator, String string);
|
||||
API String16 ToString16(Allocator allocator, String string);
|
||||
API String ToString(Allocator allocator, String16 string);
|
||||
API String ToString(Allocator allocator, char16_t *string, int64_t len);
|
||||
API String ToString(Allocator allocator, char16_t *wstring);
|
||||
|
||||
API bool IsValid(UTF8Iter &iter);
|
||||
API void Advance(UTF8Iter *iter);
|
||||
API UTF8Iter IterateUTF8Ex(char *data, int64_t len);
|
||||
API UTF8Iter IterateUTF8(char *data);
|
||||
API UTF8Iter IterateUTF8(String string);
|
||||
API bool IsUTF8ContinuationByte(char c);
|
||||
@@ -0,0 +1,186 @@
|
||||
Vec2 GetSize(Rect2 r) {
|
||||
Vec2 result = {r.max.x - r.min.x, r.max.y - r.min.y};
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2 GetSizeF(Rect2I r) {
|
||||
Vec2 result = {(float)(r.max.x - r.min.x), (float)(r.max.y - r.min.y)};
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2 ToVec2(Vec2I v) { return {(float)v.x, (float)v.y}; }
|
||||
Vec2I ToVec2I(Vec2 v) { return {(Int)v.x, (Int)v.y}; }
|
||||
Rect2I ToRect2I(Rect2 r) { return {ToVec2I(r.min), ToVec2I(r.max)}; }
|
||||
Rect2 ToRect2(Rect2I r) { return {ToVec2(r.min), ToVec2(r.max)}; }
|
||||
|
||||
// clang-format off
|
||||
Rect2 operator-(Rect2 r, Rect2 value) { return { {r.min.x - value.min.x, r.min.y - value.min.y}, {r.max.x - value.max.x, r.max.y - value.max.y} }; }
|
||||
Rect2 operator+(Rect2 r, Rect2 value) { return { {r.min.x + value.min.x, r.min.y + value.min.y}, {r.max.x + value.max.x, r.max.y + value.max.y} }; }
|
||||
Rect2 operator*(Rect2 r, Rect2 value) { return { {r.min.x * value.min.x, r.min.y * value.min.y}, {r.max.x * value.max.x, r.max.y * value.max.y} }; }
|
||||
Rect2 operator/(Rect2 r, Rect2 value) { return { {r.min.x / value.min.x, r.min.y / value.min.y}, {r.max.x / value.max.x, r.max.y / value.max.y} }; }
|
||||
|
||||
Rect2 operator-(Rect2 r, Vec2 value) { return { {r.min.x - value.x, r.min.y - value.y}, {r.max.x - value.x, r.max.y - value.y} }; }
|
||||
Rect2 operator+(Rect2 r, Vec2 value) { return { {r.min.x + value.x, r.min.y + value.y}, {r.max.x + value.x, r.max.y + value.y} }; }
|
||||
Rect2 operator*(Rect2 r, Vec2 value) { return { {r.min.x * value.x, r.min.y * value.y}, {r.max.x * value.x, r.max.y * value.y} }; }
|
||||
Rect2 operator/(Rect2 r, Vec2 value) { return { {r.min.x / value.x, r.min.y / value.y}, {r.max.x / value.x, r.max.y / value.y} }; }
|
||||
Rect2 operator-(Vec2 value, Rect2 r) { return { {r.min.x - value.x, r.min.y - value.y}, {r.max.x - value.x, r.max.y - value.y} }; }
|
||||
Rect2 operator+(Vec2 value, Rect2 r) { return { {r.min.x + value.x, r.min.y + value.y}, {r.max.x + value.x, r.max.y + value.y} }; }
|
||||
Rect2 operator*(Vec2 value, Rect2 r) { return { {r.min.x * value.x, r.min.y * value.y}, {r.max.x * value.x, r.max.y * value.y} }; }
|
||||
Rect2 operator/(Vec2 value, Rect2 r) { return { {r.min.x / value.x, r.min.y / value.y}, {r.max.x / value.x, r.max.y / value.y} }; }
|
||||
|
||||
Rect2 operator-(Rect2 r, float value) { return { {r.min.x - value, r.min.y - value}, {r.max.x - value, r.max.y - value} }; }
|
||||
Rect2 operator+(Rect2 r, float value) { return { {r.min.x + value, r.min.y + value}, {r.max.x + value, r.max.y + value} }; }
|
||||
Rect2 operator*(Rect2 r, float value) { return { {r.min.x * value, r.min.y * value}, {r.max.x * value, r.max.y * value} }; }
|
||||
Rect2 operator/(Rect2 r, float value) { return { {r.min.x / value, r.min.y / value}, {r.max.x / value, r.max.y / value} }; }
|
||||
Rect2 operator-(float value, Rect2 r) { return { {r.min.x - value, r.min.y - value}, {r.max.x - value, r.max.y - value} }; }
|
||||
Rect2 operator+(float value, Rect2 r) { return { {r.min.x + value, r.min.y + value}, {r.max.x + value, r.max.y + value} }; }
|
||||
Rect2 operator*(float value, Rect2 r) { return { {r.min.x * value, r.min.y * value}, {r.max.x * value, r.max.y * value} }; }
|
||||
Rect2 operator/(float value, Rect2 r) { return { {r.min.x / value, r.min.y / value}, {r.max.x / value, r.max.y / value} }; }
|
||||
|
||||
Rect2 operator-=(Rect2 &r, Rect2 value) { r = r - value; return r; }
|
||||
Rect2 operator+=(Rect2 &r, Rect2 value) { r = r + value; return r; }
|
||||
Rect2 operator*=(Rect2 &r, Rect2 value) { r = r * value; return r; }
|
||||
Rect2 operator/=(Rect2 &r, Rect2 value) { r = r / value; return r; }
|
||||
Rect2 operator-=(Rect2 &r, Vec2 value) { r = r - value; return r; }
|
||||
Rect2 operator+=(Rect2 &r, Vec2 value) { r = r + value; return r; }
|
||||
Rect2 operator*=(Rect2 &r, Vec2 value) { r = r * value; return r; }
|
||||
Rect2 operator/=(Rect2 &r, Vec2 value) { r = r / value; return r; }
|
||||
Rect2 operator-=(Rect2 &r, float value) { r = r - value; return r; }
|
||||
Rect2 operator+=(Rect2 &r, float value) { r = r + value; return r; }
|
||||
Rect2 operator*=(Rect2 &r, float value) { r = r * value; return r; }
|
||||
Rect2 operator/=(Rect2 &r, float value) { r = r / value; return r; }
|
||||
|
||||
bool operator==(Rect2 a, Rect2 b) {
|
||||
bool result = a.min.x == b.min.x && a.min.y == b.min.y && a.max.x == b.max.x && a.max.y == b.max.y;
|
||||
return result;
|
||||
}
|
||||
bool operator!=(Rect2 a, Rect2 b) {
|
||||
bool result = !(a == b);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2 operator-(Vec2 a, Vec2 b) { return {a.x - b.x, a.y - b.y}; }
|
||||
Vec2 operator+(Vec2 a, Vec2 b) { return {a.x + b.x, a.y + b.y}; }
|
||||
Vec2 operator*(Vec2 a, Vec2 b) { return {a.x * b.x, a.y * b.y}; }
|
||||
Vec2 operator/(Vec2 a, Vec2 b) { return {a.x / b.x, a.y / b.y}; }
|
||||
|
||||
Vec2 operator-(Vec2 a, float b) { return {a.x - b, a.y - b}; }
|
||||
Vec2 operator+(Vec2 a, float b) { return {a.x + b, a.y + b}; }
|
||||
Vec2 operator*(Vec2 a, float b) { return {a.x * b, a.y * b}; }
|
||||
Vec2 operator/(Vec2 a, float b) { return {a.x / b, a.y / b}; }
|
||||
Vec2 operator-(float b, Vec2 a) { return {a.x - b, a.y - b}; }
|
||||
Vec2 operator+(float b, Vec2 a) { return {a.x + b, a.y + b}; }
|
||||
Vec2 operator*(float b, Vec2 a) { return {a.x * b, a.y * b}; }
|
||||
Vec2 operator/(float b, Vec2 a) { return {a.x / b, a.y / b}; }
|
||||
|
||||
Vec2 operator-=(Vec2 &a, Vec2 b) { a = a - b; return a; }
|
||||
Vec2 operator+=(Vec2 &a, Vec2 b) { a = a + b; return a; }
|
||||
Vec2 operator*=(Vec2 &a, Vec2 b) { a = a * b; return a; }
|
||||
Vec2 operator/=(Vec2 &a, Vec2 b) { a = a / b; return a; }
|
||||
Vec2 operator-=(Vec2 &a, float b) { a = a - b; return a; }
|
||||
Vec2 operator+=(Vec2 &a, float b) { a = a + b; return a; }
|
||||
Vec2 operator*=(Vec2 &a, float b) { a = a * b; return a; }
|
||||
Vec2 operator/=(Vec2 &a, float b) { a = a / b; return a; }
|
||||
|
||||
// clang-format on
|
||||
|
||||
Rect2 Rect0Size(float x, float y) {
|
||||
Rect2 rect = {0, 0, x, y};
|
||||
return rect;
|
||||
}
|
||||
|
||||
Rect2 Rect2FromSize(Vec2 pos, Vec2 size) {
|
||||
Rect2 result = {};
|
||||
result.min = pos;
|
||||
result.max = pos + size;
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2 Rect2MidHalf(Vec2 mid, Vec2 half_size) {
|
||||
Rect2 result = {};
|
||||
result.min = mid - half_size;
|
||||
result.max = mid + half_size;
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2 Shrink(Rect2 result, float v) {
|
||||
result.min.x += v;
|
||||
result.max.x -= v;
|
||||
result.min.y += v;
|
||||
result.max.y -= v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2 ShrinkVertical(Rect2 result, float v) {
|
||||
result.min.y += v;
|
||||
result.max.y -= v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2 ShrinkHorizontal(Rect2 result, float v) {
|
||||
result.min.x += v;
|
||||
result.max.x -= v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2 GetMid(Rect2 r) {
|
||||
Vec2 size = GetSize(r);
|
||||
size.x /= 2.f;
|
||||
size.y /= 2.f;
|
||||
Vec2 result = r.min + size;
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2 CutLeft(Rect2 *r, float value) {
|
||||
float minx = r->min.x;
|
||||
r->min.x = Min(r->min.x + value, r->max.x);
|
||||
Rect2 result = {
|
||||
{ minx, r->min.y},
|
||||
{r->min.x, r->max.y}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2 CutRight(Rect2 *r, float value) {
|
||||
float maxx = r->max.x;
|
||||
r->max.x = Max(r->min.x, r->max.x - value);
|
||||
Rect2 result = {
|
||||
{r->max.x, r->min.y},
|
||||
{ maxx, r->max.y},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
// Y is up
|
||||
Rect2 CutBottom(Rect2 *r, float value) {
|
||||
float maxy = r->max.y;
|
||||
r->max.y = Max(r->min.y, r->max.y - value);
|
||||
Rect2 result = {
|
||||
{r->min.x, r->max.y},
|
||||
{r->max.x, maxy},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
// Y is up
|
||||
Rect2 CutTop(Rect2 *r, float value) {
|
||||
float miny = r->min.y;
|
||||
r->min.y = Min(r->min.y + value, r->max.y);
|
||||
Rect2 result = {
|
||||
{r->min.x, miny},
|
||||
{r->max.x, r->min.y},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
float SafeDivide(float a, float b) {
|
||||
if (b == 0.f) {
|
||||
return 0.f;
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
bool AreOverlapping(Vec2 point, Rect2 rec) {
|
||||
bool result = (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
Rect2I operator-(Rect2I r, Rect2I value) { return { {r.min.x - value.min.x, r.min.y - value.min.y}, {r.max.x - value.max.x, r.max.y - value.max.y} }; }
|
||||
Rect2I operator+(Rect2I r, Rect2I value) { return { {r.min.x + value.min.x, r.min.y + value.min.y}, {r.max.x + value.max.x, r.max.y + value.max.y} }; }
|
||||
Rect2I operator*(Rect2I r, Rect2I value) { return { {r.min.x * value.min.x, r.min.y * value.min.y}, {r.max.x * value.max.x, r.max.y * value.max.y} }; }
|
||||
Rect2I operator/(Rect2I r, Rect2I value) { return { {r.min.x / value.min.x, r.min.y / value.min.y}, {r.max.x / value.max.x, r.max.y / value.max.y} }; }
|
||||
|
||||
Rect2I operator-(Rect2I r, Vec2I value) { return { {r.min.x - value.x, r.min.y - value.y}, {r.max.x - value.x, r.max.y - value.y} }; }
|
||||
Rect2I operator+(Rect2I r, Vec2I value) { return { {r.min.x + value.x, r.min.y + value.y}, {r.max.x + value.x, r.max.y + value.y} }; }
|
||||
Rect2I operator*(Rect2I r, Vec2I value) { return { {r.min.x * value.x, r.min.y * value.y}, {r.max.x * value.x, r.max.y * value.y} }; }
|
||||
Rect2I operator/(Rect2I r, Vec2I value) { return { {r.min.x / value.x, r.min.y / value.y}, {r.max.x / value.x, r.max.y / value.y} }; }
|
||||
Rect2I operator-(Vec2I value, Rect2I r) { return { {r.min.x - value.x, r.min.y - value.y}, {r.max.x - value.x, r.max.y - value.y} }; }
|
||||
Rect2I operator+(Vec2I value, Rect2I r) { return { {r.min.x + value.x, r.min.y + value.y}, {r.max.x + value.x, r.max.y + value.y} }; }
|
||||
Rect2I operator*(Vec2I value, Rect2I r) { return { {r.min.x * value.x, r.min.y * value.y}, {r.max.x * value.x, r.max.y * value.y} }; }
|
||||
Rect2I operator/(Vec2I value, Rect2I r) { return { {r.min.x / value.x, r.min.y / value.y}, {r.max.x / value.x, r.max.y / value.y} }; }
|
||||
|
||||
Rect2I operator-(Int value, Rect2I r) { return { {r.min.x - value, r.min.y - value}, {r.max.x - value, r.max.y - value} }; }
|
||||
Rect2I operator+(Int value, Rect2I r) { return { {r.min.x + value, r.min.y + value}, {r.max.x + value, r.max.y + value} }; }
|
||||
Rect2I operator*(Int value, Rect2I r) { return { {r.min.x * value, r.min.y * value}, {r.max.x * value, r.max.y * value} }; }
|
||||
Rect2I operator/(Int value, Rect2I r) { return { {r.min.x / value, r.min.y / value}, {r.max.x / value, r.max.y / value} }; }
|
||||
Rect2I operator-(Rect2I r, Int value) { return { {r.min.x - value, r.min.y - value}, {r.max.x - value, r.max.y - value} }; }
|
||||
Rect2I operator+(Rect2I r, Int value) { return { {r.min.x + value, r.min.y + value}, {r.max.x + value, r.max.y + value} }; }
|
||||
Rect2I operator*(Rect2I r, Int value) { return { {r.min.x * value, r.min.y * value}, {r.max.x * value, r.max.y * value} }; }
|
||||
Rect2I operator/(Rect2I r, Int value) { return { {r.min.x / value, r.min.y / value}, {r.max.x / value, r.max.y / value} }; }
|
||||
|
||||
Rect2I operator-=(Rect2I &r, Rect2I value) { r = r - value; return r; }
|
||||
Rect2I operator+=(Rect2I &r, Rect2I value) { r = r + value; return r; }
|
||||
Rect2I operator*=(Rect2I &r, Rect2I value) { r = r * value; return r; }
|
||||
Rect2I operator/=(Rect2I &r, Rect2I value) { r = r / value; return r; }
|
||||
Rect2I operator-=(Rect2I &r, Vec2I value) { r = r - value; return r; }
|
||||
Rect2I operator+=(Rect2I &r, Vec2I value) { r = r + value; return r; }
|
||||
Rect2I operator*=(Rect2I &r, Vec2I value) { r = r * value; return r; }
|
||||
Rect2I operator/=(Rect2I &r, Vec2I value) { r = r / value; return r; }
|
||||
Rect2I operator-=(Rect2I &r, Int value) { r = r - value; return r; }
|
||||
Rect2I operator+=(Rect2I &r, Int value) { r = r + value; return r; }
|
||||
Rect2I operator*=(Rect2I &r, Int value) { r = r * value; return r; }
|
||||
Rect2I operator/=(Rect2I &r, Int value) { r = r / value; return r; }
|
||||
|
||||
Vec2I operator-(Vec2I a, Vec2I b) { return {a.x - b.x, a.y - b.y}; }
|
||||
Vec2I operator+(Vec2I a, Vec2I b) { return {a.x + b.x, a.y + b.y}; }
|
||||
Vec2I operator*(Vec2I a, Vec2I b) { return {a.x * b.x, a.y * b.y}; }
|
||||
Vec2I operator/(Vec2I a, Vec2I b) { return {a.x / b.x, a.y / b.y}; }
|
||||
|
||||
Vec2I operator-(Vec2I a, Int b) { return {a.x - b, a.y - b}; }
|
||||
Vec2I operator+(Vec2I a, Int b) { return {a.x + b, a.y + b}; }
|
||||
Vec2I operator*(Vec2I a, Int b) { return {a.x * b, a.y * b}; }
|
||||
Vec2I operator/(Vec2I a, Int b) { return {a.x / b, a.y / b}; }
|
||||
Vec2I operator-(Int b, Vec2I a) { return {a.x - b, a.y - b}; }
|
||||
Vec2I operator+(Int b, Vec2I a) { return {a.x + b, a.y + b}; }
|
||||
Vec2I operator*(Int b, Vec2I a) { return {a.x * b, a.y * b}; }
|
||||
Vec2I operator/(Int b, Vec2I a) { return {a.x / b, a.y / b}; }
|
||||
|
||||
Vec2I operator-=(Vec2I &a, Vec2I b) { a = a - b; return a; }
|
||||
Vec2I operator+=(Vec2I &a, Vec2I b) { a = a + b; return a; }
|
||||
Vec2I operator*=(Vec2I &a, Vec2I b) { a = a * b; return a; }
|
||||
Vec2I operator/=(Vec2I &a, Vec2I b) { a = a / b; return a; }
|
||||
Vec2I operator-=(Vec2I &a, Int b) { a = a - b; return a; }
|
||||
Vec2I operator+=(Vec2I &a, Int b) { a = a + b; return a; }
|
||||
Vec2I operator*=(Vec2I &a, Int b) { a = a * b; return a; }
|
||||
Vec2I operator/=(Vec2I &a, Int b) { a = a / b; return a; }
|
||||
|
||||
Vec2I GetSize(Rect2I r) {
|
||||
Vec2I result = {r.max.x - r.min.x, r.max.y - r.min.y};
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2I RectI0Size(Int x, Int y) {
|
||||
Rect2I rect = {0, 0, x, y};
|
||||
return rect;
|
||||
}
|
||||
|
||||
Rect2I Rect2IFromSize(Vec2I pos, Vec2I size) {
|
||||
Rect2I result = {};
|
||||
result.min = pos;
|
||||
result.max = pos + size;
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2I Shrink(Rect2I result, Int v) {
|
||||
result.min.x += v;
|
||||
result.max.x -= v;
|
||||
result.min.y += v;
|
||||
result.max.y -= v;
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2I GetMid(Rect2I r) {
|
||||
Vec2I size = GetSize(r);
|
||||
size.x /= 2;
|
||||
size.y /= 2;
|
||||
Vec2I result = r.min + size;
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2I CutLeft(Rect2I *r, Int value) {
|
||||
Int minx = r->min.x;
|
||||
r->min.x = Min(r->min.x + value, r->max.x);
|
||||
Rect2I result = {
|
||||
{ minx, r->min.y},
|
||||
{r->min.x, r->max.y}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
Rect2I CutRight(Rect2I *r, Int value) {
|
||||
Int maxx = r->max.x;
|
||||
r->max.x = Max(r->min.x, r->max.x - value);
|
||||
Rect2I result = {
|
||||
{r->max.x, r->min.y},
|
||||
{ maxx, r->max.y},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
// Y is up
|
||||
Rect2I CutBottom(Rect2I *r, Int value) {
|
||||
Int maxy = r->max.y;
|
||||
r->max.y = Max(r->min.y, r->max.y - value);
|
||||
Rect2I result = {
|
||||
{r->min.x, r->max.y},
|
||||
{r->max.x, maxy},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
// Y is up
|
||||
Rect2I CutTop(Rect2I *r, Int value) {
|
||||
Int miny = r->min.y;
|
||||
r->min.y = Min(r->min.y + value, r->max.y);
|
||||
Rect2I result = {
|
||||
{r->min.x, miny},
|
||||
{r->max.x, r->min.y},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
Int SafeDivide(Int a, Int b) {
|
||||
if (b == 0) {
|
||||
return 0;
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
bool AreOverlapping(Vec2I point, Rect2I rec) {
|
||||
bool result = (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y);
|
||||
return result;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
||||
#include "core_platform.c"
|
||||
#include "core_intrin.c"
|
||||
#include "core_unicode.c"
|
||||
#include "core_math.c"
|
||||
#include "core_arena.c"
|
||||
#include "stb_sprintf.c"
|
||||
#include "core_string.c"
|
||||
#include "core_string16.c"
|
||||
#include "core_log.c"
|
||||
#include "core_lexer.c"
|
||||
#include "core_type_info.c"
|
||||
#include "core_hash_table.c"
|
||||
#include "core_array.c"
|
||||
#include "core_math.gen.c"
|
||||
#include "core_ctx.c"
|
||||
@@ -1,14 +0,0 @@
|
||||
#include "core_basic.h"
|
||||
#include "core_unicode.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
#include "core_string16.h"
|
||||
#include "core_math.h"
|
||||
#include "core_type_info.h"
|
||||
#include "core_lexer.h"
|
||||
#include "core_log.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_hash_table.h"
|
||||
#include "core_ctx.h"
|
||||
#include "core_array.h"
|
||||
@@ -1,202 +0,0 @@
|
||||
#include "core_arena.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_ctx.h"
|
||||
|
||||
#if PLATFORM_ADDRESS_SANITIZER
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#endif
|
||||
|
||||
#if !defined(ASAN_POISON_MEMORY_REGION)
|
||||
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#else
|
||||
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ASAN_POISON_MEMORY_REGION(addr, size)
|
||||
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
|
||||
#endif
|
||||
|
||||
fn b32 is_pow2(usize x) {
|
||||
b32 result = (((x) & ((x)-1)) == 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn usize get_align_offset(usize size, usize align) {
|
||||
assert(is_pow2(align));
|
||||
if (align == 0) return 0;
|
||||
|
||||
usize mask = align - 1;
|
||||
usize val = size & mask;
|
||||
if (val) {
|
||||
val = align - val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
fn usize align_up(usize size, usize align) {
|
||||
usize result = size + get_align_offset(size, align);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn usize align_down(usize size, usize align) {
|
||||
size += 1; // Make sure when align is 8 doesn't get rounded down to 0
|
||||
usize result = size - (align - get_align_offset(size, align));
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ma_init(ma_arena_t *arena, usize reserve) {
|
||||
reserve = align_up(reserve, ma_page_size);
|
||||
arena->align = ma_default_alignment;
|
||||
arena->data = (u8 *)os_vmem_reserve(reserve);
|
||||
if (arena->data) {
|
||||
arena->reserve = reserve;
|
||||
}
|
||||
}
|
||||
|
||||
fn ma_arena_t *ma_create(usize reserve) {
|
||||
ma_arena_t *result = NULL;
|
||||
|
||||
void *data = os_vmem_reserve(reserve);
|
||||
if (!data) return result;
|
||||
|
||||
b32 success = os_vmem_commit(data, ma_page_size);
|
||||
if (!success) {
|
||||
os_vmem_release(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = (ma_arena_t *)data;
|
||||
result->data = (u8 *)data;
|
||||
result->reserve = reserve;
|
||||
result->commit = ma_page_size;
|
||||
result->len = result->base_len = sizeof(ma_arena_t);
|
||||
result->align = ma_default_alignment;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void *ma_push_size_ex(ma_arena_t *arena, usize size) {
|
||||
// base_len is used for bootstraping arenas, it denotes the
|
||||
// space occupied by the arena. If len is smaller then base_len then
|
||||
// we start to overwrite the arena itself - pure barbarism.
|
||||
assert(arena->len >= arena->base_len);
|
||||
|
||||
usize align_offset = 0;
|
||||
if (arena->align) {
|
||||
align_offset = get_align_offset((usize)arena->data + arena->len, arena->align);
|
||||
}
|
||||
usize size_with_alignment = size + align_offset;
|
||||
usize new_len = arena->len + size_with_alignment;
|
||||
if (new_len > arena->commit) {
|
||||
if (arena->reserve == 0) {
|
||||
ma_init(arena, ma_default_reserve_size);
|
||||
}
|
||||
usize new_len_aligned_to_page_size = align_up(new_len, ma_page_size);
|
||||
usize to_commit = new_len_aligned_to_page_size - arena->commit;
|
||||
usize to_commit_clamped = CLAMP_TOP(to_commit, arena->reserve);
|
||||
if (to_commit_clamped > 0) {
|
||||
b32 success = os_vmem_commit(arena->data + arena->commit, to_commit_clamped);
|
||||
if (success) {
|
||||
MA_ASAN_UNPOISON_MEMORY_REGION(arena->data + arena->commit, to_commit_clamped);
|
||||
arena->commit += to_commit_clamped;
|
||||
}
|
||||
}
|
||||
if (new_len > arena->commit) {
|
||||
invalid_codepath;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
u8 *result = arena->data + arena->len + align_offset;
|
||||
arena->len = new_len;
|
||||
MA_ASAN_UNPOISON_MEMORY_REGION(result, size);
|
||||
return (void *)result;
|
||||
}
|
||||
|
||||
fn void *ma_push_size(ma_arena_t *arena, usize size) {
|
||||
void *result = ma_push_size_ex(arena, size);
|
||||
if (result) memory_zero(result, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ma_push_arena_ex(ma_arena_t *allocator, ma_arena_t *result, usize size) {
|
||||
result->data = (u8 *)ma_push_size(allocator, size);
|
||||
result->reserve = size;
|
||||
result->commit = size;
|
||||
result->align = ma_default_alignment;
|
||||
}
|
||||
|
||||
fn ma_arena_t *ma_push_arena(ma_arena_t *allocator, usize size) {
|
||||
ma_arena_t *result = ma_push_type(allocator, ma_arena_t);
|
||||
ma_push_arena_ex(allocator, result, size);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ma_destroy(ma_arena_t *arena) {
|
||||
if (arena == NULL || arena->data == NULL) return;
|
||||
b32 zero_memory = (u8 *)arena != arena->data;
|
||||
os_vmem_release(arena->data);
|
||||
if (zero_memory) memory_zero(arena, sizeof(ma_arena_t));
|
||||
}
|
||||
|
||||
fn void ma_set_len(ma_arena_t *arena, usize pos) {
|
||||
// base_len is used for bootstraping arenas, it denotes the
|
||||
// space occupied by the arena. If len is smaller then base_len then
|
||||
// we start to overwrite the arena itself - pure barbarism.
|
||||
assert(arena->len >= arena->base_len);
|
||||
|
||||
pos = CLAMP(pos, arena->base_len, arena->len);
|
||||
usize size = arena->len - pos;
|
||||
arena->len = pos;
|
||||
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->len, size);
|
||||
}
|
||||
|
||||
fn void ma_pop(ma_arena_t *arena, usize size) { ma_set_len(arena, arena->len - size); }
|
||||
fn ma_temp_t ma_begin_temp(ma_arena_t *arena) { return (ma_temp_t){arena, arena->len}; }
|
||||
fn void ma_end_temp(ma_temp_t temp) { ma_set_len(temp.arena, temp.len); }
|
||||
fn void ma_set0(ma_arena_t *arena) { ma_set_len(arena, 0); }
|
||||
|
||||
//
|
||||
// Scratch arena
|
||||
fn ma_temp_t ma_begin_scratch_ex(ma_arena_t **conflicts, int conflict_count) {
|
||||
ma_arena_t *unoccupied = 0;
|
||||
for (int i = 0; i < lengthof(tcx->scratch); i += 1) {
|
||||
ma_arena_t *from_pool = tcx->scratch + i;
|
||||
unoccupied = from_pool;
|
||||
for (int conflict_i = 0; conflict_i < conflict_count; conflict_i += 1) {
|
||||
ma_arena_t *from_conflict = conflicts[conflict_i];
|
||||
if (from_pool == from_conflict) {
|
||||
unoccupied = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unoccupied) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(unoccupied); // failed to get free scratch memory, this is a fatal error, this shouldnt happen
|
||||
ma_temp_t result = ma_begin_temp(unoccupied);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn ma_temp_t ma_begin_scratch(void) {
|
||||
ma_temp_t result = ma_begin_temp(tcx->scratch + 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn ma_temp_t ma_begin_scratch1(ma_arena_t *conflict) {
|
||||
ma_arena_t *conflicts[] = {conflict};
|
||||
return ma_begin_scratch_ex(conflicts, 1);
|
||||
}
|
||||
|
||||
fn ma_temp_t ma_begin_scratch2(ma_arena_t *a, ma_arena_t *b) {
|
||||
ma_arena_t *conflicts[] = {a, b};
|
||||
return ma_begin_scratch_ex(conflicts, 2);
|
||||
}
|
||||
|
||||
fn void *ma_push__copy(ma_arena_t *arena, void *data, u64 size) {
|
||||
void *result = ma_push_size_ex(arena, size);
|
||||
if (result) {
|
||||
memory_copy(result, data, size);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
static const usize ma_page_size = 4096;
|
||||
static const usize ma_default_alignment = sizeof(void *);
|
||||
static const usize ma_default_reserve_size = mib(256);
|
||||
|
||||
typedef struct ma_arena_t ma_arena_t;
|
||||
struct ma_arena_t {
|
||||
u8 *data;
|
||||
usize len;
|
||||
usize base_len; // to prevent self deleting the arena
|
||||
usize reserve;
|
||||
usize commit;
|
||||
usize align;
|
||||
};
|
||||
|
||||
typedef struct ma_temp_t ma_temp_t;
|
||||
struct ma_temp_t {
|
||||
ma_arena_t *arena;
|
||||
usize len;
|
||||
};
|
||||
|
||||
//
|
||||
// constructors
|
||||
fn void ma_init(ma_arena_t *arena, usize reserve);
|
||||
fn ma_arena_t *ma_create(usize reserve);
|
||||
fn void ma_destroy(ma_arena_t *arena);
|
||||
|
||||
//
|
||||
// push
|
||||
fn void *ma_push_size(ma_arena_t *arena, usize size);
|
||||
fn void *ma_push_size_ex(ma_arena_t *arena, usize size);
|
||||
fn ma_arena_t *ma_push_arena(ma_arena_t *allocator, usize size);
|
||||
fn void ma_push_arena_ex(ma_arena_t *allocator, ma_arena_t *result, usize size);
|
||||
#define ma_push_type(arena, Type) (Type *)ma_push_size((arena), sizeof(Type))
|
||||
#define ma_push_array(arena, Type, count) (Type *)ma_push_size((arena), sizeof(Type) * (count))
|
||||
#define ma_push_type_copy(ma, data) ma_push__copy((ma), (data), sizeof(*(data)))
|
||||
#define ma_push_array_copy(ma, data, count) ma_push__copy((ma), (data), (count) * sizeof(*(data)))
|
||||
|
||||
//
|
||||
// pop
|
||||
fn void ma_set_len(ma_arena_t *arena, usize pos);
|
||||
fn void ma_pop(ma_arena_t *arena, usize size);
|
||||
fn void ma_set0(ma_arena_t *arena);
|
||||
|
||||
//
|
||||
// temp
|
||||
fn ma_temp_t ma_begin_temp(ma_arena_t *arena);
|
||||
fn void ma_end_temp(ma_temp_t temp);
|
||||
#define ma_temp_scope(name, InArena) for (ma_temp_t name = ma_begin_temp(InArena); name.arena; (ma_end_temp(name), name.arena = 0))
|
||||
|
||||
//
|
||||
// scratch
|
||||
fn ma_temp_t ma_begin_scratch_ex(ma_arena_t **conflicts, int conflict_count);
|
||||
fn ma_temp_t ma_begin_scratch(void);
|
||||
fn ma_temp_t ma_begin_scratch1(ma_arena_t *conflict);
|
||||
#define ma_end_scratch(x) ma_end_temp(x)
|
||||
#define ma_scratch_scope(x) for (ma_temp_t x = ma_begin_scratch(); x.arena; (ma_end_temp(x), x.arena = 0))
|
||||
@@ -1,122 +0,0 @@
|
||||
#include "core_array.h"
|
||||
#include "core_basic.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_ctx.h"
|
||||
#include "core_intrin.h"
|
||||
|
||||
fn void array__init(alo_t alo, array_void_t *this, size_t item_size, i64 count) {
|
||||
assert_expr(this->data == NULL);
|
||||
this->data = alloc_size(alo, item_size * count);
|
||||
this->cap = count;
|
||||
this->len = 0;
|
||||
this->alo = alo;
|
||||
}
|
||||
|
||||
fn void array__copy(alo_t alo, array_void_t *dst, array_void_t *src, size_t item_size) {
|
||||
dst->data = alloc_size(alo, item_size * src->cap);
|
||||
memory_copy(dst->data, src->data, item_size * src->len);
|
||||
dst->cap = src->cap;
|
||||
dst->len = src->len;
|
||||
dst->alo = alo;
|
||||
}
|
||||
|
||||
fn void array__grow(array_void_t *this, size_t item_size, i64 item_count) {
|
||||
if (this->len + 1 > this->cap) {
|
||||
i64 new_cap = this->cap == 0 ? 16 : (this->cap + item_count - 1) * 2;
|
||||
void *new_data = alloc_size(this->alo, new_cap * item_size);
|
||||
if (this->data) {
|
||||
memory_copy(new_data, this->data, this->len*item_size);
|
||||
dealloc(this->alo, this->data);
|
||||
}
|
||||
this->data = new_data;
|
||||
this->cap = new_cap;
|
||||
}
|
||||
}
|
||||
|
||||
fn void array__del(array_void_t *this, size_t item_size, i64 idx, i64 count) {
|
||||
if (count == 0) return;
|
||||
assert(idx >= 0 && idx < this->len);
|
||||
assert((idx + count) > 0 && (idx + count) <= this->len);
|
||||
i64 right_len = this->len - idx - count;
|
||||
u8 *data = (u8 *)this->data;
|
||||
memory_move(data + idx * item_size, data + (idx + count) * item_size, right_len * item_size);
|
||||
this->len -= count;
|
||||
}
|
||||
|
||||
fn void array__insert(array_void_t *this, size_t item_size, i64 idx) {
|
||||
array__grow(this, item_size, 1);
|
||||
assert(idx >= 0);
|
||||
assert(idx <= this->len);
|
||||
assert(this->alo.object);
|
||||
|
||||
u8 *data = (u8 *)this->data;
|
||||
i64 right_len = this->len - idx;
|
||||
memory_move(data + (idx + 1) * item_size, data + idx * item_size, item_size * right_len);
|
||||
this->len += 1;
|
||||
}
|
||||
|
||||
fn_test void test_array(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
{
|
||||
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
|
||||
for (int i = 0; i < 512; i += 1) {
|
||||
array_add(&arr, i);
|
||||
}
|
||||
for (int i = 0; i < 512; i += 1) {
|
||||
assert(arr.data[i] == i);
|
||||
}
|
||||
assert(arr.len == 512);
|
||||
assert(arr.cap == 512);
|
||||
for (int i = 511; i >= 0; i -= 1) {
|
||||
i64 a = array_pop(&arr);
|
||||
assert(a == i);
|
||||
}
|
||||
assert(arr.len == 0);
|
||||
array_dealloc(&arr);
|
||||
}
|
||||
|
||||
{
|
||||
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
|
||||
i64 *i = array_addn(&arr, 10);
|
||||
assert(arr.len == 10 && arr.cap == 16);
|
||||
i64 *j = array_addn(&arr, 2);
|
||||
assert(i == arr.data);
|
||||
assert(j == arr.data + 10);
|
||||
array_dealloc(&arr);
|
||||
}
|
||||
|
||||
{
|
||||
array_i64_t arr = (array_i64_t){.alo = malot(scratch)};
|
||||
for (int i = 0; i < 512; i += 1) {
|
||||
array_add(&arr, i);
|
||||
}
|
||||
|
||||
array_insert(&arr, 256, 111);
|
||||
assert(arr.data[256] == 111);
|
||||
assert(arr.data[255] == 255);
|
||||
assert(arr.data[257] == 256);
|
||||
assert(arr.len == 513);
|
||||
|
||||
array_insert(&arr, 4, 222);
|
||||
assert(arr.len == 514);
|
||||
assert(arr.data[4] == 222);
|
||||
assert(arr.data[3] == 3);
|
||||
assert(arr.data[5] == 4);
|
||||
|
||||
array_swapdel(&arr, 2);
|
||||
assert(arr.len == 513);
|
||||
assert(arr.data[2] == 511);
|
||||
assert(arr.data[1] == 1);
|
||||
assert(arr.data[3] == 3);
|
||||
|
||||
array_i64_t copy = {0};
|
||||
array_copy(malot(scratch), ©, &arr);
|
||||
for (i64 i = 0; i < arr.len; i += 1) {
|
||||
assert(arr.data[i] == copy.data[i]);
|
||||
}
|
||||
assert(copy.len == arr.len);
|
||||
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
#define array(type) struct { alo_t alo; type *data; i64 len; i64 cap; }
|
||||
typedef array(void) array_void_t;
|
||||
typedef array(i64) array_i64_t;
|
||||
|
||||
#define arrisz(x) sizeof((x)->data[0])
|
||||
#define arrcst(x) ((array_void_t *)(x))
|
||||
#define array_init(a, this, count) (array__init((a), arrcst(this), arrisz(this), (count)))
|
||||
#define array_add(this, ...) (array__grow(arrcst(this), arrisz(this), 1), (this)->data[(this)->len++] = __VA_ARGS__)
|
||||
#define array_pop(this) (assert_expr((this)->len > 0), (this)->data[--(this)->len])
|
||||
#define array_dealloc(this) (dealloc((this)->alo, (this)->data))
|
||||
#define array_addn(this, n) (array__grow(arrcst(this), arrisz(this), (n)), (this)->len += (n), &(this)->data[(this)->len - (n)])
|
||||
#define array_insert(this, i, item) (array__insert(arrcst(this), arrisz(this), (i)), (this)->data[(i)] = (item))
|
||||
#define array_swapdel(this, i) (assert_expr((i) < (this)->len), (this)->data[(i)] = (this)->data[--(this)->len])
|
||||
#define array_del(this, i) (array__del(arrcst(this), arrisz(this), (i), 1))
|
||||
#define array_deln(this, i, count) (array__del(arrcst(this), arrisz(this), (i), (count)))
|
||||
#define array_copy(alo, dst, src) (array__copy((alo), arrcst(dst), (array_void_t *)(src), arrisz(dst)))
|
||||
#define array_last(x) ((x)->data[(x)->len - 1])
|
||||
#define array_for(type, it, array) for (type *it = (array)->data; it < (array)->data + (array)->len; it += 1)
|
||||
|
||||
fn void array__init(alo_t alo, array_void_t *, size_t item_size, i64 count);
|
||||
fn void array__copy(alo_t alo, array_void_t *dst, array_void_t *src, size_t item_size);
|
||||
fn void array__grow(array_void_t *, size_t item_size, i64 item_count);
|
||||
fn void array__del(array_void_t *, size_t item_size, i64 idx, i64 count);
|
||||
fn void array__insert(array_void_t *, size_t item_size, i64 idx);
|
||||
@@ -1,427 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define PLATFORM_MAC_OS 1
|
||||
#define PLATFORM_POSIX 1
|
||||
#elif defined(_WIN32)
|
||||
#define PLATFORM_WINDOWS 1
|
||||
#elif defined(__linux__)
|
||||
#define PLATFORM_POSIX 1
|
||||
#define PLATFORM_LINUX 1
|
||||
#elif defined(__wasm)
|
||||
#define PLATFORM_WASM 1
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#define PLATFORM_CLANG 1
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#define PLATFORM_GCC 1
|
||||
#elif defined(_MSC_VER)
|
||||
#define PLATFORM_CL 1
|
||||
#elif defined(__TINYC__)
|
||||
#define PLATFORM_TCC 1
|
||||
#endif
|
||||
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#define PLATFORM_EMSCRIPTEN 1
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_EMSCRIPTEN
|
||||
#define PLATFORM_EMSCRIPTEN 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_WASM
|
||||
#define PLATFORM_WASM 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
#define PLATFORM_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_LINUX
|
||||
#define PLATFORM_LINUX 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_POSIX
|
||||
#define PLATFORM_POSIX 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_MAC_OS
|
||||
#define PLATFORM_MAC_OS 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_CLANG
|
||||
#define PLATFORM_CLANG 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_GCC
|
||||
#define PLATFORM_GCC 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_CL
|
||||
#define PLATFORM_CL 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_TCC
|
||||
#define PLATFORM_TCC 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_ADDRESS_SANITIZER
|
||||
#define PLATFORM_ADDRESS_SANITIZER 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_DEBUG_ASSERT
|
||||
#define PLATFORM_DEBUG_ASSERT 1
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) WINDOWS
|
||||
#elif PLATFORM_WASM
|
||||
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) WASM
|
||||
#else
|
||||
#define SWITCH_PLATFORM_WINDOWS_WASM_ELSE(WINDOWS, WASM, ELSE) ELSE
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CLANG
|
||||
#define IF_PLATFORM_CLANG_ELSE(IF, ELSE) IF
|
||||
#else
|
||||
#define IF_PLATFORM_CLANG_ELSE(IF, ELSE) ELSE
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#define IF_PLATFORM_WINDOWS(x) x
|
||||
#else
|
||||
#define IF_PLATFORM_WINDOWS(x)
|
||||
#endif
|
||||
|
||||
#if PLATFORM_LINUX && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef uintptr_t usize;
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
typedef uint8_t u8;
|
||||
|
||||
typedef intptr_t isize;
|
||||
typedef int64_t i64;
|
||||
typedef int32_t i32;
|
||||
typedef int16_t i16;
|
||||
typedef int8_t i8;
|
||||
|
||||
typedef int64_t b64;
|
||||
typedef int32_t b32;
|
||||
typedef int16_t b16;
|
||||
typedef int8_t b8;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
#define f32_max FLT_MAX
|
||||
#define f32_min FLT_MIN
|
||||
#define f64_max DBL_MAX
|
||||
#define f64_min DBL_MIN
|
||||
|
||||
#define i8_max INT8_MAX
|
||||
#define i8_min INT8_MIN
|
||||
#define i16_max INT16_MAX
|
||||
#define i16_min INT16_MIN
|
||||
#define i32_max INT32_MAX
|
||||
#define i32_min INT32_MIN
|
||||
#define i64_max INT64_MAX
|
||||
#define i64_min INT64_MIN
|
||||
|
||||
#define u8_max UINT8_MAX
|
||||
#define u8_min 0
|
||||
#define u16_max UINT16_MAX
|
||||
#define u16_min 0
|
||||
#define u32_max UINT32_MAX
|
||||
#define u32_min 0
|
||||
#define u64_max UINT64_MAX
|
||||
#define u64_min 0
|
||||
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#define fn
|
||||
#define fn_test
|
||||
#define gb
|
||||
#define locl static
|
||||
|
||||
typedef union convert_f64_u64_t convert_f64_u64_t;
|
||||
union convert_f64_u64_t { f64 f; u64 i; };
|
||||
typedef union convert_f64_i64_t convert_f64_i64_t;
|
||||
union convert_f64_i64_t { f64 f; i64 i; };
|
||||
typedef union convert_f32_u32_t convert_f32_u32_t;
|
||||
union convert_f32_u32_t { f32 f; u32 i; };
|
||||
typedef union convert_f32_i32_t convert_f32_i32_t;
|
||||
union convert_f32_i32_t { f32 f; i32 i; };
|
||||
|
||||
#define U64_TO_F64(x) (((convert_f64_u64_t) { .i = (x) }).f)
|
||||
#define U32_TO_F32(x) (((convert_f32_u32_t) { .i = (x) }).f)
|
||||
#define F64_TO_U64(x) (((convert_f64_u64_t) { .f = (x) }).i)
|
||||
#define F32_TO_U32(x) (((convert_f32_u32_t) { .f = (x) }).i)
|
||||
|
||||
#define I64_TO_F64(x) (((convert_f64_i64_t) { .i = (x) }).f)
|
||||
#define I32_TO_F32(x) (((convert_f32_i32_t) { .i = (x) }).f)
|
||||
#define F64_TO_I64(x) (((convert_f64_i64_t) { .f = (x) }).i)
|
||||
#define F32_TO_I32(x) (((convert_f32_i32_t) { .f = (x) }).i)
|
||||
|
||||
#define MIN(x,y) ((x) > (y) ? (y) : (x))
|
||||
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
#define CLAMP_TOP(A,X) MIN(A,X)
|
||||
#define CLAMP_BOT(X,B) MAX(X,B)
|
||||
#define CLAMP(x,a,b) (((x)<(a))?(a):((x)>(b))?(b):(x))
|
||||
|
||||
#define set_bit(x) (1ULL << (x))
|
||||
#define lengthof(x) ((int)(sizeof((x))/sizeof((x)[0])))
|
||||
#ifndef offsetof
|
||||
#define offsetof(st, m) ((usize)&(((st *)0)->m))
|
||||
#endif
|
||||
#define expect(x) if (!(x))
|
||||
#define unused(x) (void)(x)
|
||||
|
||||
#define kib(x) (1024ULL * (x##ULL))
|
||||
#define mib(x) (1024ULL * kib(x))
|
||||
#define gib(x) (1024ULL * mib(x))
|
||||
#define thousand(n) ((n)*1000)
|
||||
#define million(n) ((n)*1000000)
|
||||
#define billion(n) ((n)*1000000000)
|
||||
|
||||
#define zero_struct(x) memory_zero((x), sizeof(*(x)))
|
||||
|
||||
|
||||
#define defer_if(begin, cond_end) for (b32 PASTE(_i_, __LINE__) = !!begin; PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) = (cond_end, 0))
|
||||
#define defer_block(begin, end) for (i32 PASTE(_i_, __LINE__) = (begin, 0); !PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) += (end, 1))
|
||||
|
||||
#define stack_t(type, size) struct { type data[size]; i32 len; }
|
||||
#define STACK_CAP(stack) (lengthof((stack).data))
|
||||
#define STACK_EMPTY(stack) ((stack).len == 0)
|
||||
#define STACK_FULL(stack) ((stack).len == STACK_CAP(stack))
|
||||
#define STACK_PUSH(stack, ...) (assert_expr(!STACK_FULL(stack)), (stack).data[(stack).len++] = __VA_ARGS__)
|
||||
#define STACK_POP(stack) (assert_expr(!STACK_EMPTY(stack)), (stack).data[--(stack).len])
|
||||
#define STACK_TOP(stack) (assert_expr(!STACK_EMPTY(stack)), (stack).data[((stack).len-1)])
|
||||
|
||||
#define STRINGIFY_(S) #S
|
||||
#define STRINGIFY(S) STRINGIFY_(S)
|
||||
#define PASTE_(a, b) a##b
|
||||
#define PASTE(a, b) PASTE_(a, b)
|
||||
#define SWAP(t, a, b) do { t PASTE(temp__, __LINE__) = a; a = b; b = PASTE(temp__, __LINE__); } while(0)
|
||||
#define SWAP_PTR(t, a, b) do { t PASTE(temp__, __LINE__) = *a; *a = *b; *b = PASTE(temp__, __LINE__); } while(0)
|
||||
#define CODE(...) #__VA_ARGS__
|
||||
|
||||
#if PLATFORM_CL || (PLATFORM_CLANG && PLATFORM_WINDOWS)
|
||||
#pragma section(".rdata$", read)
|
||||
#define gb_read_only __declspec(allocate(".rdata$"))
|
||||
#elif PLATFORM_CLANG && PLATFORM_LINUX
|
||||
#define gb_read_only __attribute__((section(".rodata")))
|
||||
#else
|
||||
#define gb_read_only
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#define fn_inline __forceinline
|
||||
#elif PLATFORM_CLANG || PLATFORM_GCC
|
||||
#define fn_inline __attribute__((always_inline))
|
||||
#else
|
||||
#define fn_inline
|
||||
#endif
|
||||
|
||||
#ifndef FILE_AND_LINE_GCC_FORMAT
|
||||
#define FILE_AND_LINE __FILE__ "(" STRINGIFY(__LINE__) ")"
|
||||
#else
|
||||
#define FILE_AND_LINE __FILE__ ":" STRINGIFY(__LINE__)
|
||||
#endif
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
int IsDebuggerPresent(void);
|
||||
#define debug__break() (IsDebuggerPresent() && (__debugbreak(), 1))
|
||||
#elif PLATFORM_UNIX
|
||||
// https://github.com/r-lyeh/tinybits/blob/master/tinyassert.c
|
||||
#include <signal.h>
|
||||
static void os_unix_sigtrap(int signum) { signal(SIGTRAP, SIG_DFL); }
|
||||
#define debug__break() (signal(SIGTRAP, os_unix_sigtrap), raise(SIGTRAP))
|
||||
#elif PLATFORM_WASM
|
||||
void wasm_trap(void);
|
||||
#define debug__break() wasm_trap()
|
||||
#elif PLATFORM_TCC
|
||||
#define debug__break() raise(SIGTRAP)
|
||||
#else
|
||||
#define debug__break() __builtin_trap()
|
||||
#endif
|
||||
#define debug_break() (debug__break(), 1)
|
||||
|
||||
#if PLATFORM_WASM | PLATFORM_TCC
|
||||
#define gb_thread
|
||||
#elif PLATFORM_GCC | PLATFORM_CLANG
|
||||
#define gb_thread __thread
|
||||
#elif PLATFORM_CL
|
||||
#define gb_thread __declspec(thread)
|
||||
#else
|
||||
#define gb_thread _Thread_local
|
||||
#endif
|
||||
|
||||
#if PLATFORM_CL
|
||||
#pragma warning(disable: 4116)
|
||||
#endif
|
||||
|
||||
// Single linked list Queue
|
||||
#define SLLQ_APPEND_EX(f, l, n, next) \
|
||||
do { \
|
||||
assert_expr((n)->next == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
(l) = (l)->next = (n); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_APPEND(f, l, n) SLLQ_APPEND_EX(f, l, n, next)
|
||||
|
||||
#define SLLQ_PREPEND_EX(f, l, n, next) \
|
||||
do { \
|
||||
assert_expr((n)->next == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (n); \
|
||||
} else { \
|
||||
(n)->next = (f); \
|
||||
(f) = (n); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_PREPEND(f, l, n) SLLQ_PREPEND_EX(f, l, n, next)
|
||||
|
||||
#define SLLQ_REMOVE_FIRST_EX(f, l, next) \
|
||||
do { \
|
||||
if ((f) == (l)) { \
|
||||
(f) = (l) = 0; \
|
||||
} else { \
|
||||
(f) = (f)->next; \
|
||||
} \
|
||||
} while (0)
|
||||
#define SLLQ_REMOVE_FIRST(f, l) SLLQ_REMOVE_FIRST_EX(f, l, next)
|
||||
|
||||
// Singly linked list stack
|
||||
#define SLLS_PUSH_EX(stack_base, new_stack_base, next) \
|
||||
do { \
|
||||
(new_stack_base)->next = (stack_base); \
|
||||
(stack_base) = (new_stack_base); \
|
||||
} while (0)
|
||||
#define SLLS_PUSH(stack_base, new_stack_base) \
|
||||
SLLS_PUSH_EX(stack_base, new_stack_base, next)
|
||||
|
||||
#define SLLS_POP(stack_base) ((stack_base) = (stack_base)->next)
|
||||
#define SLLS_POP_AND_STORE(stack_base, out_node) \
|
||||
do { \
|
||||
if (stack_base) { \
|
||||
(out_node) = (stack_base); \
|
||||
(stack_base) = (stack_base)->next; \
|
||||
(out_node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Doubly linked list Queue
|
||||
#define DLLQ_APPEND_EX(f, l, node, next, prev) \
|
||||
do { \
|
||||
assert_expr((node)->next == NULL); \
|
||||
assert_expr((node)->prev == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
} else { \
|
||||
(l)->next = (node); \
|
||||
(node)->prev = (l); \
|
||||
(l) = (node); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_APPEND(f, l, node) DLLQ_APPEND_EX(f, l, node, next, prev)
|
||||
|
||||
#define DLLQ_PREPEND_EX(f, l, node, next, prev) \
|
||||
do { \
|
||||
assert_expr((node)->next == NULL); \
|
||||
assert_expr((node)->prev == NULL); \
|
||||
if ((f) == 0) { \
|
||||
(f) = (l) = (node); \
|
||||
} else { \
|
||||
(node)->next = (f); \
|
||||
(f)->prev = (node); \
|
||||
(f) = (node); \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_PREPEND(f, l, node) DLLQ_PREPEND_EX(f, l, node, next, prev)
|
||||
|
||||
#define DLLQ_CONTAINS(f, l, n, next, prev) for (
|
||||
|
||||
#define DLLQ_REMOVE_EX(first, last, node, next, prev) \
|
||||
do { \
|
||||
if ((first) == (last)) { \
|
||||
assert_expr((node) == (first)); \
|
||||
(first) = (last) = 0; \
|
||||
} else if ((last) == (node)) { \
|
||||
(last) = (last)->prev; \
|
||||
(last)->next = 0; \
|
||||
} else if ((first) == (node)) { \
|
||||
(first) = (first)->next; \
|
||||
(first)->prev = 0; \
|
||||
} else { \
|
||||
(node)->prev->next = (node)->next; \
|
||||
(node)->next->prev = (node)->prev; \
|
||||
} \
|
||||
if (node) { \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLQ_REMOVE(first, last, node) DLLQ_REMOVE_EX(first, last, node, next, prev)
|
||||
|
||||
// Doubly linked list Stack
|
||||
#define DLLS_PUSH_EX(first, node, next, prev) \
|
||||
do { \
|
||||
assert_expr((node)->next == NULL); \
|
||||
assert_expr((node)->prev == NULL); \
|
||||
(node)->next = (first); \
|
||||
if ((first)) \
|
||||
(first)->prev = (node); \
|
||||
(first) = (node); \
|
||||
} while (0)
|
||||
#define DLLS_PUSH(first, node) DLLS_PUSH_EX(first, node, next, prev)
|
||||
#define DLLS_REMOVE_EX(first, node, next, prev) \
|
||||
do { \
|
||||
if ((node) == (first)) { \
|
||||
(first) = (first)->next; \
|
||||
if ((first)) \
|
||||
(first)->prev = 0; \
|
||||
} else { \
|
||||
(node)->prev->next = (node)->next; \
|
||||
if ((node)->next) \
|
||||
(node)->next->prev = (node)->prev; \
|
||||
} \
|
||||
if (node) { \
|
||||
(node)->prev = 0; \
|
||||
(node)->next = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define DLLS_REMOVE(first, node) DLLS_REMOVE_EX(first, node, next, prev)
|
||||
|
||||
typedef enum {
|
||||
alokind_alloc,
|
||||
alokind_dealloc,
|
||||
} alokind_t;
|
||||
|
||||
typedef struct alo_t alo_t;
|
||||
struct alo_t {
|
||||
void *object;
|
||||
void *(*proc)(alo_t alo, alokind_t kind, void *ptr, size_t size);
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "core_ctx.h"
|
||||
#include "core_platform.h"
|
||||
|
||||
gb_thread thread_ctx_t *tcx;
|
||||
|
||||
fn void *ma_arena_alo_proc(alo_t alo, alokind_t kind, void *ptr, size_t size) {
|
||||
unused(ptr);
|
||||
if (kind == alokind_alloc) {
|
||||
return ma_push_size(alo.object, size);
|
||||
} else if (kind == alokind_dealloc) {
|
||||
return NULL;
|
||||
} else_is_invalid;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn alo_t malo(ma_arena_t *arena) {
|
||||
return (alo_t){arena, ma_arena_alo_proc};
|
||||
}
|
||||
|
||||
fn alo_t malot(ma_temp_t temp) {
|
||||
return malo(temp.arena);
|
||||
}
|
||||
|
||||
fn void dealloc(alo_t alo, void *ptr) {
|
||||
alo.proc(alo, alokind_dealloc, ptr, 0);
|
||||
}
|
||||
|
||||
fn void *alloc_size(alo_t alo, size_t size) {
|
||||
return alo.proc(alo, alokind_alloc, NULL, size);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_arena.h"
|
||||
#include "core_log.h"
|
||||
|
||||
typedef struct thread_ctx_t thread_ctx_t;
|
||||
struct thread_ctx_t {
|
||||
ma_arena_t scratch[3];
|
||||
ma_arena_t temp; // application specific arena
|
||||
|
||||
// I probably want to discourage using it implicitly like: tcx.perm, instead just pass it around
|
||||
// to functions that allocate pernament memory. temp and scratch very nicely create reusable code
|
||||
// perm is basically gb state so it would be nice to annotate which functions are reusable
|
||||
// and which functions have state
|
||||
ma_arena_t perm;
|
||||
|
||||
void *app_ctx;
|
||||
void *rn_ctx;
|
||||
void *ui_ctx;
|
||||
void *te_ctx;
|
||||
void *user_ctx;
|
||||
|
||||
logger_t log;
|
||||
int thread_index;
|
||||
};
|
||||
|
||||
#define alloc_type(alo, type) (type *)alloc_size((aloc), sizeof(type))
|
||||
#define alloc_array(alo, type, count) (type *)alloc_size((alo), sizeof(type) * (count))
|
||||
fn alo_t malo(ma_arena_t *arena);
|
||||
fn alo_t malot(ma_temp_t temp);
|
||||
fn void dealloc(alo_t alo, void *ptr);
|
||||
fn void *alloc_size(alo_t alo, size_t size);
|
||||
fn int tcx_alloc_id(void);
|
||||
|
||||
extern gb_thread thread_ctx_t *tcx;
|
||||
@@ -1,217 +0,0 @@
|
||||
#include "core_hash_table.h"
|
||||
#include "core_platform.h"
|
||||
|
||||
// xorshift64
|
||||
fn u64 get_random_u64(random_seed_t *seed) {
|
||||
u64 x = seed->a;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 7;
|
||||
x ^= x << 17;
|
||||
return seed->a = x;
|
||||
}
|
||||
|
||||
fn u64 get_random_in_range_u64(random_seed_t *seed, u64 start, u64 one_past_end) {
|
||||
u64 r = get_random_u64(seed);
|
||||
u64 diff = one_past_end - start;
|
||||
u64 rr = r % diff;
|
||||
u64 rrr = rr + start;
|
||||
return rrr;
|
||||
}
|
||||
|
||||
fn i64 get_random_in_range_i64(random_seed_t *seed, i64 start, i64 one_past_end) {
|
||||
u64 r = get_random_u64(seed);
|
||||
i64 diff = one_past_end - start;
|
||||
u64 rr = r % diff;
|
||||
i64 rrr = (i64)rr + start;
|
||||
return rrr;
|
||||
}
|
||||
|
||||
fn f64 get_random_f64(random_seed_t *seed) {
|
||||
f64 random = (f64)get_random_in_range_u64(seed, 0, UINT32_MAX);
|
||||
f64 result = random / (f64)(UINT32_MAX - 1u);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn u64 hash_data(s8_t string) {
|
||||
u8 *data = (u8 *)string.str;
|
||||
u64 hash = (u64)14695981039346656037ULL;
|
||||
for (i64 i = 0; i < string.len; i++) {
|
||||
hash = hash ^ (u64)(data[i]);
|
||||
hash = hash * (u64)1099511628211ULL;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
fn u64 hash_mix(u64 x, u64 y) {
|
||||
x ^= y;
|
||||
x *= 0xff51afd7ed558ccd;
|
||||
x ^= x >> 32;
|
||||
return x;
|
||||
}
|
||||
|
||||
fn ht_t *ht_create(ma_arena_t *arena, i32 size) {
|
||||
ht_t *result = ma_push_type(arena, ht_t);
|
||||
result->buckets = ma_push_array(arena, ht_bucket_t, size);
|
||||
result->bucket_count = size;
|
||||
result->arena = arena;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_kv(ht_t *ht, u64 hash, ht_key_value_t kv) {
|
||||
ht_node_t *result = ma_push_type(ht->arena, ht_node_t);
|
||||
result->kv = kv;
|
||||
i64 idx = hash % ht->bucket_count;
|
||||
SLLQ_APPEND(ht->buckets[idx].first, ht->buckets[idx].last, result);
|
||||
ht->item_count += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_u64(ht_t *ht, u64 key, u64 value) {
|
||||
u64 hash = hash_data(s8_struct(key));
|
||||
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_u64 = key, .value_u64 = value});
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_ptr(ht_t *ht, void *key, void *value) {
|
||||
return ht_insert_u64(ht, (u64)key, (u64)value);
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_string(ht_t *ht, s8_t key, s8_t value) {
|
||||
u64 hash = hash_data(key);
|
||||
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_string = key, .value_string = value});
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_insert_string_ptr(ht_t *ht, s8_t key, void *value) {
|
||||
u64 hash = hash_data(key);
|
||||
return ht_insert_kv(ht, hash, (ht_key_value_t){.key_string = key, .value_ptr = value});
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_search_u64_ex(ht_t *ht, u64 key) {
|
||||
u64 hash = hash_data(s8_struct(key));
|
||||
i64 idx = hash % ht->bucket_count;
|
||||
ht_bucket_t *bucket = ht->buckets + idx;
|
||||
for (ht_node_t *it = bucket->first; it; it = it->next) {
|
||||
if (it->kv.key_u64 == key) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_search_ptr_ex(ht_t *ht, void *key) {
|
||||
u64 hash = hash_data(s8_struct(key));
|
||||
i64 idx = hash % ht->bucket_count;
|
||||
ht_bucket_t *bucket = ht->buckets + idx;
|
||||
for (ht_node_t *it = bucket->first; it; it = it->next) {
|
||||
if (it->kv.key_ptr == key) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn ht_node_t *ht_search_string_ex(ht_t *ht, s8_t key) {
|
||||
u64 hash = hash_data(key);
|
||||
i64 idx = hash % ht->bucket_count;
|
||||
ht_bucket_t *bucket = ht->buckets + idx;
|
||||
for (ht_node_t *it = bucket->first; it; it = it->next) {
|
||||
if (s8_are_equal(it->kv.key_string, key)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn u64 *ht_search_u64(ht_t *ht, u64 key) {
|
||||
ht_node_t *node = ht_search_u64_ex(ht, key);
|
||||
if (node) return &node->kv.value_u64;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn void **ht_search_ptr(ht_t *ht, void *key) {
|
||||
ht_node_t *node = ht_search_ptr_ex(ht, key);
|
||||
if (node) return &node->kv.value_ptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn s8_t *ht_search_string(ht_t *ht, s8_t key) {
|
||||
ht_node_t *node = ht_search_string_ex(ht, key);
|
||||
if (node) return &node->kv.value_string;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn void **ht_search_string_ptr(ht_t *ht, s8_t key) {
|
||||
ht_node_t *node = ht_search_string_ex(ht, key);
|
||||
if (node) return &node->kv.value_ptr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// string interning
|
||||
fn s8i_t *intern_string(ht_t *ht, s8_t string) {
|
||||
s8_t *item = ht_search_string(ht, string);
|
||||
if (!item) {
|
||||
string = s8_copy(ht->arena, string);
|
||||
ht_node_t *node = ht_insert_string(ht, string, string);
|
||||
item = &node->kv.value_string;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
fn s8i_t *internf(ht_t *ht, char *str, ...) {
|
||||
S8_FMT(ht->arena, str, string);
|
||||
return intern_string(ht, string);
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// testing
|
||||
|
||||
fn_test void test_hash_table(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
{
|
||||
ht_t *ht = ht_create(scratch.arena, 16);
|
||||
|
||||
for (u64 i = 0; i < 128; i += 1) {
|
||||
ht_insert_u64(ht, i, i);
|
||||
ht_node_t *node = ht_search_u64_ex(ht, i);
|
||||
assert_expr(node->kv.value_u64 == i);
|
||||
assert(node->kv.key_u64 == i);
|
||||
}
|
||||
for (u64 i = 0; i < 128; i += 1) {
|
||||
ht_node_t *node = ht_search_u64_ex(ht, i);
|
||||
assert(node->kv.value_u64 == i);
|
||||
assert(node->kv.key_u64 == i);
|
||||
}
|
||||
|
||||
ht_node_t *node = ht_search_u64_ex(ht, 1111);
|
||||
assert(node == NULL);
|
||||
}
|
||||
{
|
||||
ht_t *ht = ht_create(scratch.arena, 16);
|
||||
|
||||
for (i32 i = 0; i < 128; i += 1) {
|
||||
s8_t s = s8_printf(scratch.arena, "%d", i);
|
||||
ht_insert_string(ht, s, s);
|
||||
ht_node_t *node = ht_search_string_ex(ht, s);
|
||||
assert(s8_are_equal(node->kv.value_string, s));
|
||||
assert(s8_are_equal(node->kv.key_string, s));
|
||||
}
|
||||
|
||||
ht_node_t *node = ht_search_string_ex(ht, s8("memes"));
|
||||
assert(node == NULL);
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
fn_test void test_intern_table(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
ht_t *ht = ht_create(scratch.arena, 4);
|
||||
assert(internf(ht, "asd") == internf(ht, "asd"));
|
||||
assert(internf(ht, "asdf") != internf(ht, "asd"));
|
||||
assert(internf(ht, "asdf") == internf(ht, "asdf"));
|
||||
assert(internf(ht, "123asdf") == internf(ht, "123asdf"));
|
||||
assert(internf(ht, "123asdf") != internf(ht, "133asdf"));
|
||||
assert(internf(ht, "") == internf(ht, ""));
|
||||
assert(internf(ht, "") != internf(ht, "a"));
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
|
||||
typedef struct ht_key_value_t ht_key_value_t;
|
||||
struct ht_key_value_t {
|
||||
union {
|
||||
s8_t key_string;
|
||||
u64 key_u64;
|
||||
void *key_ptr;
|
||||
};
|
||||
union {
|
||||
s8_t value_string;
|
||||
void *value_ptr;
|
||||
u64 value_u64;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct ht_node_t ht_node_t;
|
||||
struct ht_node_t {
|
||||
ht_node_t *next;
|
||||
ht_key_value_t kv;
|
||||
};
|
||||
|
||||
typedef struct ht_bucket_t ht_bucket_t;
|
||||
struct ht_bucket_t {
|
||||
ht_node_t *first;
|
||||
ht_node_t *last;
|
||||
};
|
||||
|
||||
typedef struct ht_t ht_t;
|
||||
struct ht_t {
|
||||
ma_arena_t *arena;
|
||||
i32 item_count;
|
||||
i32 bucket_count;
|
||||
ht_bucket_t *buckets;
|
||||
};
|
||||
|
||||
fn ht_t *ht_create (ma_arena_t *arena, i32 size);
|
||||
fn ht_node_t *ht_insert_kv (ht_t *ht, u64 hash, ht_key_value_t kv);
|
||||
fn ht_node_t *ht_insert_u64 (ht_t *ht, u64 key, u64 value);
|
||||
fn ht_node_t *ht_insert_ptr (ht_t *ht, void *key, void *value);
|
||||
fn ht_node_t *ht_insert_string (ht_t *ht, s8_t key, s8_t value);
|
||||
fn ht_node_t *ht_insert_string_ptr (ht_t *ht, s8_t key, void *value);
|
||||
fn u64 *ht_search_u64 (ht_t *ht, u64 key);
|
||||
fn void **ht_search_ptr (ht_t *ht, void *key);
|
||||
fn s8_t *ht_search_string (ht_t *ht, s8_t key);
|
||||
fn void **ht_search_string_ptr (ht_t *ht, s8_t key);
|
||||
fn ht_node_t *ht_search_u64_ex (ht_t *ht, u64 key);
|
||||
fn ht_node_t *ht_search_ptr_ex (ht_t *ht, void *key);
|
||||
fn ht_node_t *ht_search_string_ex (ht_t *ht, s8_t key);
|
||||
|
||||
///////////////////////////////
|
||||
// string interning
|
||||
#define s8i_t s8_t
|
||||
fn s8i_t *intern_string(ht_t *ht, s8_t string);
|
||||
fn s8i_t *internf(ht_t *ht, char *str, ...);
|
||||
|
||||
|
||||
///////////////////////////////
|
||||
// Hashing
|
||||
typedef struct random_seed_t random_seed_t;
|
||||
struct random_seed_t {
|
||||
u64 a;
|
||||
};
|
||||
|
||||
fn u64 get_random_u64(random_seed_t *seed);
|
||||
fn u64 get_random_in_range_u64(random_seed_t *seed, u64 start, u64 one_past_end);
|
||||
fn i64 get_random_in_range_i64(random_seed_t *seed, i64 start, i64 one_past_end);
|
||||
fn f64 get_random_f64(random_seed_t *seed);
|
||||
fn u64 hash_data(s8_t string);
|
||||
fn u64 hash_mix(u64 x, u64 y);
|
||||
@@ -1,242 +0,0 @@
|
||||
#include "core_intrin.h"
|
||||
#include "core_basic.h"
|
||||
#include "core_platform.h"
|
||||
|
||||
fn void memory_copy(void *dst, void *src, usize n) {
|
||||
IF_PLATFORM_CLANG_ELSE(__builtin_memcpy(dst, src, n), memcpy(dst, src, n));
|
||||
}
|
||||
|
||||
fn void memory_move(void *dest, const void *src, usize n) {
|
||||
IF_PLATFORM_CLANG_ELSE(__builtin_memmove(dest, src, n), memmove(dest, src, n));
|
||||
}
|
||||
|
||||
fn void memory_set(void *dst, i32 c, usize size) {
|
||||
IF_PLATFORM_CLANG_ELSE(__builtin_memset(dst, c, size), memset(dst, c, size));
|
||||
}
|
||||
|
||||
fn int bad_memory__compare(void *left, void *right, usize size) {
|
||||
u8 *l = left;
|
||||
u8 *r = right;
|
||||
for (usize i = 0; i < size; i += 1) {
|
||||
if (l[i] != r[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn b32 memory_equal(void *left, void *right, usize size) {
|
||||
int cmp = IF_PLATFORM_CLANG_ELSE(bad_memory__compare(left, right, size), memcmp(left, right, size));
|
||||
return cmp == 0;
|
||||
}
|
||||
|
||||
fn void memory_zero(void *dst, usize size) {
|
||||
memory_set(dst, 0, size);
|
||||
}
|
||||
|
||||
fn f32 f32_sqrt(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_sqrtf(x), sqrtf(x)); }
|
||||
fn f64 f64_sqrt(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_sqrt(x), sqrt(x)); }
|
||||
fn f32 f32_ceil(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_ceilf(x), ceilf(x)); }
|
||||
fn f64 f64_ceil(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_ceil(x), ceil(x)); }
|
||||
fn f32 f32_floor(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_floorf(x), floorf(x)); }
|
||||
fn f64 f64_floor(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_floor(x), floor(x)); }
|
||||
fn f32 f32_abs(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_fabsf(x), fabsf(x)); }
|
||||
fn f64 f64_abs(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_fabs(x), fabs(x)); }
|
||||
// fn f32 f32_round(f32 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_roundf(x), roundf(x)); }
|
||||
fn f64 f64_round(f64 x) { return IF_PLATFORM_CLANG_ELSE(__builtin_round(x), round(x)); }
|
||||
fn f64 f64_mod(f64 a, f64 b) { return IF_PLATFORM_CLANG_ELSE(__builtin_fmod(a, b), fmod(a, b)); }
|
||||
fn f32 f32_mod(f32 a, f32 b) { return IF_PLATFORM_CLANG_ELSE(__builtin_fmodf(a, b), fmodf(a, b)); }
|
||||
|
||||
/* https://gitlab.com/nakst/essence/-/blob/master/shared/math.cpp
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
** SOFTWARE.
|
||||
**
|
||||
*/
|
||||
|
||||
fn f64 f64_exp2(f64 x) {
|
||||
f64 a = f64_floor(x * 8);
|
||||
int64_t ai = (i64)a;
|
||||
|
||||
if (ai < -1024) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
f64 b = x - a / 8;
|
||||
|
||||
f64 y = U64_TO_F64(0x3FF0000000000000) +
|
||||
b * (U64_TO_F64(0x3FE62E42FEFA3A00) +
|
||||
b * (U64_TO_F64(0x3FCEBFBDFF829140) +
|
||||
b * (U64_TO_F64(0x3FAC6B08D73C4A40) +
|
||||
b * (U64_TO_F64(0x3F83B2AB53873280) +
|
||||
b * (U64_TO_F64(0x3F55D88F363C6C00) +
|
||||
b * (U64_TO_F64(0x3F242C003E4A2000) +
|
||||
b * U64_TO_F64(0x3EF0B291F6C00000)))))));
|
||||
|
||||
f64 m[8] = {
|
||||
U64_TO_F64(0x3FF0000000000000),
|
||||
U64_TO_F64(0x3FF172B83C7D517B),
|
||||
U64_TO_F64(0x3FF306FE0A31B715),
|
||||
U64_TO_F64(0x3FF4BFDAD5362A27),
|
||||
U64_TO_F64(0x3FF6A09E667F3BCD),
|
||||
U64_TO_F64(0x3FF8ACE5422AA0DB),
|
||||
U64_TO_F64(0x3FFAE89F995AD3AD),
|
||||
U64_TO_F64(0x3FFD5818DCFBA487),
|
||||
};
|
||||
|
||||
y *= m[ai & 7];
|
||||
|
||||
convert_f64_u64_t c;
|
||||
c.f = y;
|
||||
c.i += (ai >> 3) << 52;
|
||||
return c.f;
|
||||
}
|
||||
|
||||
fn f32 f32_exp2(f32 x) {
|
||||
f32 a = f32_floor(x);
|
||||
i32 ai = (i32)a;
|
||||
|
||||
if (ai < -128) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
f32 b = x - a;
|
||||
|
||||
f32 y = U32_TO_F32(0x3F7FFFFE) + b * (U32_TO_F32(0x3F31729A) + b * (U32_TO_F32(0x3E75E700) + b * (U32_TO_F32(0x3D64D520) + b * (U32_TO_F32(0x3C128280) + b * U32_TO_F32(0x3AF89400)))));
|
||||
|
||||
convert_f32_u32_t c;
|
||||
c.f = y;
|
||||
c.i += ai << 23;
|
||||
return c.f;
|
||||
}
|
||||
|
||||
fn f64 f64_log2(f64 x) {
|
||||
convert_f64_u64_t c;
|
||||
c.f = x;
|
||||
int64_t e = ((c.i >> 52) & 2047) - 0x3FF;
|
||||
c.i = (c.i & ~((uint64_t)0x7FF << 52)) + ((uint64_t)0x3FF << 52);
|
||||
x = c.f;
|
||||
|
||||
f64 a;
|
||||
|
||||
if (x < 1.125) {
|
||||
a = 0;
|
||||
} else if (x < 1.250) {
|
||||
x *= 1.125 / 1.250;
|
||||
a = U64_TO_F64(0xBFC374D65D9E608E);
|
||||
} else if (x < 1.375) {
|
||||
x *= 1.125 / 1.375;
|
||||
a = U64_TO_F64(0xBFD28746C334FECB);
|
||||
} else if (x < 1.500) {
|
||||
x *= 1.125 / 1.500;
|
||||
a = U64_TO_F64(0xBFDA8FF971810A5E);
|
||||
} else if (x < 1.625) {
|
||||
x *= 1.125 / 1.625;
|
||||
a = U64_TO_F64(0xBFE0F9F9FFC8932A);
|
||||
} else if (x < 1.750) {
|
||||
x *= 1.125 / 1.750;
|
||||
a = U64_TO_F64(0xBFE465D36ED11B11);
|
||||
} else if (x < 1.875) {
|
||||
x *= 1.125 / 1.875;
|
||||
a = U64_TO_F64(0xBFE79538DEA712F5);
|
||||
} else {
|
||||
x *= 1.125 / 2.000;
|
||||
a = U64_TO_F64(0xBFEA8FF971810A5E);
|
||||
}
|
||||
|
||||
f64 y = U64_TO_F64(0xC00FF8445026AD97) + x * (U64_TO_F64(0x40287A7A02D9353F) + x * (U64_TO_F64(0xC03711C58D55CEE2) + x * (U64_TO_F64(0x4040E8263C321A26) + x * (U64_TO_F64(0xC041EB22EA691BB3) + x * (U64_TO_F64(0x403B00FB376D1F10) + x * (U64_TO_F64(0xC02C416ABE857241) + x * (U64_TO_F64(0x40138BA7FAA3523A) + x * (U64_TO_F64(0xBFF019731AF80316) + x * U64_TO_F64(0x3FB7F1CD3852C200)))))))));
|
||||
|
||||
return y - a + e;
|
||||
}
|
||||
|
||||
fn f32 f32_log2(f32 x) {
|
||||
// TODO f32_log2(0.9999971379999999f) gives 0.00000143051147460938 (should be negative!!).
|
||||
|
||||
convert_f32_u32_t c;
|
||||
c.f = x;
|
||||
i32 e = ((c.i >> 23) & 255) - 0x7F;
|
||||
c.i = (c.i & ~(0xFF << 23)) + (0x7F << 23);
|
||||
x = c.f;
|
||||
|
||||
f32 y = U32_TO_F32(0xC05B5154) + x * (U32_TO_F32(0x410297C6) + x * (U32_TO_F32(0xC1205CEB) + x * (U32_TO_F32(0x4114DF63) + x * (U32_TO_F32(0xC0C0DBBB) + x * (U32_TO_F32(0x402942C6) + x * (U32_TO_F32(0xBF3FF98A) + x * (U32_TO_F32(0x3DFE1050) + x * U32_TO_F32(0xBC151480))))))));
|
||||
|
||||
return y + e;
|
||||
}
|
||||
|
||||
fn f64 f64_pow(f64 x, f64 y) {
|
||||
return f64_exp2(y * f64_log2(x));
|
||||
}
|
||||
|
||||
fn f32 f32_pow(f32 x, f32 y) {
|
||||
return f32_exp2(y * f32_log2(x));
|
||||
}
|
||||
|
||||
//
|
||||
/* https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libm/common/s_round.c;hb=master
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
**/
|
||||
fn f32 f32_round(f32 x) {
|
||||
u32 w = F32_TO_U32(x);
|
||||
/* Most significant word, least significant word. */
|
||||
int exponent_less_127;
|
||||
|
||||
/* Extract exponent field. */
|
||||
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
|
||||
|
||||
if (exponent_less_127 < 23) {
|
||||
if (exponent_less_127 < 0) {
|
||||
w &= 0x80000000;
|
||||
if (exponent_less_127 == -1)
|
||||
/* Result is +1.0 or -1.0. */
|
||||
w |= ((u32)127 << 23);
|
||||
} else {
|
||||
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
|
||||
if ((w & exponent_mask) == 0)
|
||||
/* x has an integral value. */
|
||||
return x;
|
||||
|
||||
w += 0x00400000 >> exponent_less_127;
|
||||
w &= ~exponent_mask;
|
||||
}
|
||||
} else {
|
||||
if (exponent_less_127 == 128)
|
||||
/* x is NaN or infinite. */
|
||||
return x + x;
|
||||
else
|
||||
return x;
|
||||
}
|
||||
x = U32_TO_F32(w);
|
||||
return x;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// other
|
||||
fn u32 u32_safe_cast(u64 v) {
|
||||
assert_expr(v <= u32_max);
|
||||
return (u32)v;
|
||||
}
|
||||
|
||||
fn u16 u16_safe_cast(u64 v) {
|
||||
assert(v <= u16_max);
|
||||
return (u16)v;
|
||||
}
|
||||
|
||||
fn u8 u8_safe_cast(u64 v) {
|
||||
assert(v <= u8_max);
|
||||
return (u8)v;
|
||||
}
|
||||
|
||||
fn i32 i32_safe_cast(i64 v) {
|
||||
assert(v >= i32_min && v <= i32_max);
|
||||
return (i32)v;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
fn void memory_copy(void *dst, void *src, usize n);
|
||||
fn void memory_move(void *dest, const void *src, usize n);
|
||||
fn void memory_set(void *dst, i32 c, usize size);
|
||||
fn b32 memory_equal(void *left, void *right, usize size);
|
||||
fn void memory_zero(void *dst, usize size);
|
||||
|
||||
fn f32 f32_sqrt(f32 x);
|
||||
fn f64 f64_sqrt(f64 x);
|
||||
fn f32 f32_ceil(f32 x);
|
||||
fn f64 f64_ceil(f64 x);
|
||||
fn f32 f32_floor(f32 x);
|
||||
fn f64 f64_floor(f64 x);
|
||||
fn f32 f32_abs(f32 x);
|
||||
fn f64 f64_abs(f64 x);
|
||||
fn f32 f32_round(f32 x);
|
||||
fn f64 f64_round(f64 x);
|
||||
fn f64 f64_mod(f64 a, f64 b);
|
||||
fn f32 f32_mod(f32 a, f32 b);
|
||||
fn f64 f64_exp2(f64 x);
|
||||
fn f32 f32_exp2(f32 x);
|
||||
fn f64 f64_log2(f64 x);
|
||||
fn f32 f32_log2(f32 x);
|
||||
fn f64 f64_pow(f64 x, f64 y);
|
||||
fn f32 f32_pow(f32 x, f32 y);
|
||||
fn f32 f32_round(f32 x);
|
||||
fn u32 u32_safe_cast(u64 v);
|
||||
fn u16 u16_safe_cast(u64 v);
|
||||
fn u8 u8_safe_cast(u64 v);
|
||||
fn i32 i32_safe_cast(i64 v);
|
||||
@@ -1,469 +0,0 @@
|
||||
#include "core_lexer.h"
|
||||
#include "core_log.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_ctx.h"
|
||||
|
||||
#define lex_error(TOKEN, STRING) do {\
|
||||
errorf(STRING);\
|
||||
TOKEN->kind = lex_kind_error;\
|
||||
TOKEN->string = s8(STRING);\
|
||||
} while (0)
|
||||
|
||||
fn lexer_t lex_make(s8_t stream, char *file_name) {
|
||||
lexer_t result = {.at = stream.str, .end = stream.str + stream.len, .file = file_name};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 lex_at_end(lexer_t *lex) {
|
||||
b32 result = lex->at >= lex->end;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void lex_advance(lexer_t *lex) {
|
||||
if (lex_at_end(lex)) return;
|
||||
if (lex->at[0] == '\n') { lex->column = 0; lex->line += 1; }
|
||||
lex->column += 1;
|
||||
lex->at += 1;
|
||||
}
|
||||
|
||||
fn b32 lex_match(lexer_t *lex, char c) {
|
||||
if (lex->at[0] == c) {
|
||||
lex_advance(lex);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void lex_eat_whitespace(lexer_t *lex) {
|
||||
for (;;) {
|
||||
if (char_is_whitespace(lex->at[0])) {
|
||||
if (lex->at[0] == '\n') lex->inside_macro = false;
|
||||
lex_advance(lex);
|
||||
} else if (lex->at[0] == '\\' && lex->at[1] == '\n') {
|
||||
lex_advance(lex); lex_advance(lex);
|
||||
} else if (lex->at[0] == '\\' && lex->at[1] == '\r' && lex->at[2] == '\n') {
|
||||
lex_advance(lex); lex_advance(lex); lex_advance(lex);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn void lex_eat_macro_whitespace(lexer_t *lex) {
|
||||
while (lex->at[0] == ' ' || lex->at[0] == '\t') lex_advance(lex);
|
||||
}
|
||||
|
||||
fn void lex_suffix(lexer_t *lex, lex_t *token) {
|
||||
if (lex_match(lex, 'f')) {
|
||||
token->kind = lex_kind_real;
|
||||
token->suffix = lex_suffix_f;
|
||||
} else if (lex_match(lex, 'd')) {
|
||||
token->kind = lex_kind_real;
|
||||
token->suffix = lex_suffix_d;
|
||||
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'u' && lex->at[1] == 'l' && lex->at[2] == 'l') || (lex->at[0] == 'U' && lex->at[1] == 'L' && lex->at[2] == 'L'))) {
|
||||
token->suffix = lex_suffix_ull;
|
||||
lex_advance(lex); lex_advance(lex); lex_advance(lex);
|
||||
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'u' && lex->at[1] == 'l') || (lex->at[0] == 'U' && lex->at[1] == 'L'))) {
|
||||
token->suffix = lex_suffix_ul;
|
||||
lex_advance(lex); lex_advance(lex);
|
||||
} else if (token->kind == lex_kind_integer && (lex->at[0] == 'l' || lex->at[0] == 'L')) {
|
||||
token->suffix = lex_suffix_l;
|
||||
lex_advance(lex);
|
||||
} else if (token->kind == lex_kind_integer && ((lex->at[0] == 'l' && lex->at[1] == 'l') || (lex->at[0] == 'L' && lex->at[1] == 'L'))) {
|
||||
token->suffix = lex_suffix_ll;
|
||||
lex_advance(lex); lex_advance(lex);
|
||||
}
|
||||
}
|
||||
|
||||
fn void lex_eat_number(lexer_t *lex, lex_t *token) {
|
||||
token->kind = lex_kind_integer;
|
||||
for (;;) {
|
||||
if (char_is_digit(lex->at[0])) {
|
||||
lex_advance(lex);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lex_match(lex, '.')) {
|
||||
if (token->kind == lex_kind_real) {
|
||||
lex_error(token, "multiple '.' periods in floating point number literal");
|
||||
return;
|
||||
}
|
||||
token->kind = lex_kind_real;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
lex_suffix(lex, token);
|
||||
}
|
||||
|
||||
fn void lex_eat_until(lexer_t *lex, char c) {
|
||||
while (lex->at[0] != c && !lex_at_end(lex)) lex_advance(lex);
|
||||
}
|
||||
|
||||
fn void lex_eat_string(lexer_t *lex, lex_t *token) {
|
||||
token->kind = lex_kind_string;
|
||||
for (;;) {
|
||||
if (lex->at[0] == '\\') {
|
||||
lex_advance(lex);
|
||||
} else if (lex_match(lex, token->str[0])) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (lex->at[0] == 0) {
|
||||
lex_error(token, "unclosed string");
|
||||
return;
|
||||
}
|
||||
|
||||
lex_advance(lex);
|
||||
}
|
||||
}
|
||||
|
||||
fn b32 lex_macro(lexer_t *lex, lex_t *token) {
|
||||
lex_eat_macro_whitespace(lex);
|
||||
token->str = lex->at;
|
||||
while (char_is_alphabetic(lex->at[0])) lex_advance(lex);
|
||||
token->len = (i32)(lex->at - token->str);
|
||||
|
||||
if (s8_are_equal(token->string, s8("define"))) {
|
||||
token->kind = lex_kind_preproc_define;
|
||||
} else if (s8_are_equal(token->string, s8("ifdef"))) {
|
||||
token->kind = lex_kind_preproc_ifdef;
|
||||
} else if (s8_are_equal(token->string, s8("ifndef"))) {
|
||||
token->kind = lex_kind_preproc_ifndef;
|
||||
} else if (s8_are_equal(token->string, s8("include"))) {
|
||||
token->kind = lex_kind_preproc_include;
|
||||
lex_eat_macro_whitespace(lex);
|
||||
char end = 0;
|
||||
if (lex_match(lex, '"')) {
|
||||
end = '"';
|
||||
} else if (lex_match(lex, '<')) {
|
||||
end = '>';
|
||||
token->system_include = true;
|
||||
} else {
|
||||
lex_error(token, "invalid include directive, should be followed by string or '<'");
|
||||
return false;
|
||||
}
|
||||
|
||||
token->str = lex->at;
|
||||
while (lex->at[0] != end) {
|
||||
if (lex_at_end(lex)) {
|
||||
lex_error(token, "invalid include directive, reached end of file");
|
||||
return false;
|
||||
}
|
||||
if (lex->at[0] == '\n') {
|
||||
lex_error(token, "invalid include directive, reached end of line");
|
||||
return false;
|
||||
}
|
||||
lex_advance(lex);
|
||||
}
|
||||
lex_advance(lex);
|
||||
} else if (s8_are_equal(token->string, s8("if"))) {
|
||||
token->kind = lex_kind_preproc_if;
|
||||
} else if (s8_are_equal(token->string, s8("endif"))) {
|
||||
token->kind = lex_kind_preproc_endif;
|
||||
} else if (s8_are_equal(token->string, s8("error"))) {
|
||||
token->kind = lex_kind_preproc_error;
|
||||
lex_eat_macro_whitespace(lex);
|
||||
token->str = lex->at;
|
||||
lex_eat_until(lex, '\n');
|
||||
} else if (s8_are_equal(token->string, s8("else"))) {
|
||||
token->kind = lex_kind_preproc_else;
|
||||
} else if (s8_are_equal(token->string, s8("elif"))) {
|
||||
token->kind = lex_kind_preproc_elif;
|
||||
} else if (s8_are_equal(token->string, s8("pragma"))) {
|
||||
token->kind = lex_kind_preproc_pragma;
|
||||
} else if (s8_are_equal(token->string, s8("undef"))) {
|
||||
token->kind = lex_kind_preproc_undef;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define LEX_CASE3(C1, K1, C2, K2, C3, K3) \
|
||||
case C1: { \
|
||||
token->kind = K1; \
|
||||
if (lex_match(lex, C2)) { \
|
||||
lex_advance(lex); \
|
||||
token->kind = K2; \
|
||||
} else if (lex_match(lex, C3)) { \
|
||||
lex_advance(lex); \
|
||||
token->kind = K3; \
|
||||
} \
|
||||
} break
|
||||
|
||||
fn void lex_token_ex(lexer_t *lex, lex_t *token) {
|
||||
lex_eat_whitespace(lex);
|
||||
*token = (lex_t){.str = lex->at, .file = lex->file, .line = lex->line, .column = lex->column};
|
||||
lex_advance(lex);
|
||||
|
||||
switch (token->str[0]) {
|
||||
case '\0': token->kind = lex_kind_eof; break;
|
||||
case '{': token->kind = lex_kind_open_brace; break;
|
||||
case '}': token->kind = lex_kind_close_brace; break;
|
||||
case '(': token->kind = lex_kind_open_paren; break;
|
||||
case ')': token->kind = lex_kind_close_paren; break;
|
||||
case '[': token->kind = lex_kind_open_bracket; break;
|
||||
case ']': token->kind = lex_kind_close_bracket; break;
|
||||
case '~': token->kind = lex_kind_bit_negation; break;
|
||||
case ';': token->kind = lex_kind_semicolon; break;
|
||||
case ':': token->kind = lex_kind_colon; break;
|
||||
case ',': token->kind = lex_kind_comma; break;
|
||||
case '@': token->kind = lex_kind_tag; break;
|
||||
case '?': token->kind = lex_kind_question; break;
|
||||
case '\\': token->kind = lex_kind_escape; break;
|
||||
case '"': lex_eat_string(lex, token); break;
|
||||
case '`': lex_eat_string(lex, token); break;
|
||||
case '\'': lex_eat_string(lex, token); break;
|
||||
|
||||
LEX_CASE3('^', lex_kind_bit_xor, '=', lex_kind_bit_xor_assign, /*ignored option*/'=', lex_kind_bit_xor_assign);
|
||||
LEX_CASE3('=', lex_kind_assign, '=', lex_kind_equals, /*ignored option*/'=', lex_kind_equals);
|
||||
LEX_CASE3('!', lex_kind_negation, '=', lex_kind_not_equals, /*ignored option*/'=', lex_kind_not_equals);
|
||||
LEX_CASE3('%', lex_kind_modulo, '=', lex_kind_modulo_assign, /*ignored option*/'=', lex_kind_modulo_assign);
|
||||
LEX_CASE3('*', lex_kind_multiply, '=', lex_kind_multiply_assign, /*ignored option*/'=', lex_kind_multiply_assign);
|
||||
LEX_CASE3('+', lex_kind_plus, '+', lex_kind_increment, '=', lex_kind_plus_assign);
|
||||
LEX_CASE3('-', lex_kind_minus, '-', lex_kind_decrement, '=', lex_kind_minus_assign);
|
||||
LEX_CASE3('&', lex_kind_bit_and, '&', lex_kind_and, '=', lex_kind_bit_and_assign);
|
||||
LEX_CASE3('|', lex_kind_bit_or, '|', lex_kind_or, '=', lex_kind_bit_or_assign);
|
||||
|
||||
case '.': {
|
||||
token->kind = lex_kind_dot;
|
||||
if (lex->at[0] == '.' && lex->at[1] == '.') {
|
||||
lex_advance(lex);
|
||||
lex_advance(lex);
|
||||
token->kind = lex_kind_three_dots;
|
||||
}
|
||||
} break;
|
||||
|
||||
case '/': {
|
||||
token->kind = lex_kind_divide;
|
||||
if (lex_match(lex, '/')) {
|
||||
token->kind = lex_kind_comment;
|
||||
lex_eat_until(lex, '\n');
|
||||
} else if (lex_match(lex, '*')) {
|
||||
token->kind = lex_kind_comment;
|
||||
for (;;) {
|
||||
if (lex->at[0] == '*' && lex->at[1] == '/') {
|
||||
break;
|
||||
}
|
||||
if (lex->at[0] == 0) {
|
||||
lex_error(token, "unclosed block comment");
|
||||
return;
|
||||
}
|
||||
lex_advance(lex);
|
||||
}
|
||||
lex_advance(lex);
|
||||
lex_advance(lex);
|
||||
} else if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_divide_assign;
|
||||
}
|
||||
} break;
|
||||
|
||||
case '>': {
|
||||
token->kind = lex_kind_greater;
|
||||
if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_greater_or_equal;
|
||||
} else if (lex_match(lex, '>')) {
|
||||
token->kind = lex_kind_bit_right_shift;
|
||||
if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_bit_right_shift_assign;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case '<': {
|
||||
token->kind = lex_kind_lesser;
|
||||
if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_lesser_or_equal;
|
||||
} else if (lex_match(lex, '<')) {
|
||||
token->kind = lex_kind_bit_left_shift;
|
||||
if (lex_match(lex, '=')) {
|
||||
token->kind = lex_kind_bit_left_shift_assign;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case '#': {
|
||||
if (lex_match(lex, '#')) {
|
||||
token->kind = lex_kind_preproc_concat;
|
||||
} else {
|
||||
b32 inside_macro = lex_macro(lex, token);
|
||||
if (inside_macro) {
|
||||
lex->inside_macro = true;
|
||||
} else {
|
||||
if (!lex->inside_macro) {
|
||||
lex_error(token, "invalid preprocessor directive");
|
||||
return;
|
||||
}
|
||||
token->kind = lex_kind_preproc_stringify;
|
||||
token->str = lex->at;
|
||||
// this is slighly wrong, first letter can't be number
|
||||
while (char_is_alphanumeric(lex->at[0]) || lex->at[0] == '_') lex_advance(lex);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': {
|
||||
lex_eat_number(lex, token);
|
||||
} break;
|
||||
|
||||
case 'A': case 'a': case 'B': case 'b': case 'C': case 'c':
|
||||
case 'D': case 'd': case 'E': case 'e': case 'F': case 'f':
|
||||
case 'G': case 'g': case 'H': case 'h': case 'I': case 'i':
|
||||
case 'J': case 'j': case 'K': case 'k': case 'L': case 'l':
|
||||
case 'M': case 'm': case 'N': case 'n': case 'O': case 'o':
|
||||
case 'P': case 'p': case 'Q': case 'q': case 'R': case 'r':
|
||||
case 'S': case 's': case 'T': case 't': case 'U': case 'u':
|
||||
case 'V': case 'v': case 'W': case 'w': case 'X': case 'x':
|
||||
case 'Y': case 'y': case 'Z': case 'z': case '_': {
|
||||
token->kind = lex_kind_ident;
|
||||
while (char_is_alphanumeric(lex->at[0]) || lex->at[0] == '_') lex_advance(lex);
|
||||
} break;
|
||||
|
||||
default: {
|
||||
lex_error(token, "found invalid character in the token stream");
|
||||
}
|
||||
}
|
||||
|
||||
token->len = (i32)(lex->at - token->str);
|
||||
|
||||
if (token->kind == lex_kind_integer) {
|
||||
s8_t string_to_lex = token->string;
|
||||
if (token->suffix != lex_suffix_none) {
|
||||
s8_t string_value = ti_enum_value_to_name(token->suffix, type(lex_suffix_t));
|
||||
s8_t prefix = s8("lex_suffix_");
|
||||
string_to_lex.len -= string_value.len - prefix.len;
|
||||
}
|
||||
token->integer = u64_from_s8(string_to_lex, 10);
|
||||
} else if (token->kind == lex_kind_real) {
|
||||
s8_t string_to_lex = token->string;
|
||||
if (token->suffix != lex_suffix_none) {
|
||||
s8_t string_value = ti_enum_value_to_name(token->suffix, type(lex_suffix_t));
|
||||
s8_t prefix = s8("lex_suffix_");
|
||||
string_to_lex.len -= string_value.len - prefix.len;
|
||||
}
|
||||
token->real = f64_from_s8(string_to_lex);
|
||||
} else if (token->kind == lex_kind_string) {
|
||||
token->str += 1;
|
||||
token->len -= 2;
|
||||
} else if (token->kind == lex_kind_preproc_include) {
|
||||
token->len -= 1;
|
||||
}
|
||||
if (lex->inside_macro) token->inside_macro = true;
|
||||
}
|
||||
|
||||
fn lex_t lex_token(lexer_t *lex) {
|
||||
lex_t result = {0};
|
||||
lex_token_ex(lex, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn lex_array_t lex_tokens(ma_arena_t *arena, char *file_name, s8_t stream) {
|
||||
usize align = arena->align;
|
||||
arena->align = 0;
|
||||
|
||||
lex_array_t token_array = {0};
|
||||
lexer_t l = lex_make(stream, file_name);
|
||||
for (;;) {
|
||||
lex_t *token = ma_push_type(arena, lex_t);
|
||||
if (token_array.data == NULL) {
|
||||
token_array.data = token;
|
||||
}
|
||||
token_array.len += 1;
|
||||
|
||||
do {
|
||||
lex_token_ex(&l, token);
|
||||
} while (token->kind == lex_kind_comment);
|
||||
if (token->kind == lex_kind_eof) break;
|
||||
}
|
||||
|
||||
arena->align = align;
|
||||
return token_array;
|
||||
}
|
||||
|
||||
gb_read_only s8_t lex_kind_simple_strings[] = {
|
||||
#define X(KIND, STR, SIMPLE) s8_const(SIMPLE),
|
||||
LEX_KIND_XLIST
|
||||
#undef X
|
||||
};
|
||||
|
||||
fn s8_t lex_kind_to_simple_s8(lex_kind_t kind) {
|
||||
assert_expr(kind >= 0 && kind < lex_kind_count);
|
||||
return lex_kind_simple_strings[kind];
|
||||
}
|
||||
|
||||
gb_read_only s8_t lex_kind_strings[] = {
|
||||
#define X(KIND, STR, SIMPLE) s8_const(STR),
|
||||
LEX_KIND_XLIST
|
||||
#undef X
|
||||
};
|
||||
|
||||
fn s8_t lex_kind_to_s8(lex_kind_t kind) {
|
||||
assert(kind >= 0 && kind < lex_kind_count);
|
||||
return lex_kind_strings[kind];
|
||||
}
|
||||
|
||||
fn lex_t *parser_next(parser_t *par) {
|
||||
lex_t *result = par->at;
|
||||
if (result->kind != lex_kind_eof) par->at += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn lex_t *parser_match(parser_t *par, lex_kind_t kind) {
|
||||
if (par->at->kind == kind) {
|
||||
return parser_next(par);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fn lex_t *parser_matchi(parser_t *par, s8_t str) {
|
||||
if (par->at->kind == lex_kind_ident && s8_are_equal(par->at->string, str)) {
|
||||
return parser_next(par);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fn void parser_panicf(b32 print_only_file, lex_t *token, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
b8 p = tcx->log.print_file_and_line;
|
||||
tcx->log.print_file_and_line = false;
|
||||
|
||||
S8_FMT(scratch.arena, str, str8);
|
||||
if (print_only_file) {
|
||||
fatalf("%s: error: %.*s", token->file, s8_fmtspec(str8));
|
||||
} else {
|
||||
fatalf("%s(%d): error: %.*s", token->file, token->line, s8_fmtspec(str8));
|
||||
}
|
||||
|
||||
|
||||
tcx->log.print_file_and_line = p;
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
fn lex_t *parser_expect(parser_t *par, lex_kind_t kind) {
|
||||
lex_t *token = parser_match(par, kind);
|
||||
if (!token) parser_panicf(par->print_only_file, par->at, "expected token kind: %s, got instead: %s", lex_kind_to_s8(kind).str, lex_kind_to_s8(par->at->kind).str);
|
||||
return token;
|
||||
}
|
||||
|
||||
fn lex_t *parser_expecti(parser_t *par, s8_t ident) {
|
||||
lex_t *token = parser_matchi(par, ident);
|
||||
if (!token) parser_panicf(par->print_only_file, par->at, "expected identifier: '%.*s'", s8_fmtspec(ident));
|
||||
return token;
|
||||
}
|
||||
|
||||
fn void parser_eat_until(parser_t *par, lex_kind_t kind) {
|
||||
while (par->at->kind != kind && par->at->kind != lex_kind_eof) {
|
||||
parser_next(par);
|
||||
}
|
||||
}
|
||||
|
||||
fn void parser_eat_including(parser_t *par, lex_kind_t kind) {
|
||||
parser_eat_until(par, kind);
|
||||
parser_next(par);
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_string.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_type_info.h"
|
||||
|
||||
typedef enum lex_kind_t {
|
||||
#define LEX_KIND_XLIST\
|
||||
X(lex_kind_eof , "end of file" , "---" )\
|
||||
X(lex_kind_error , "error" , "---" )\
|
||||
X(lex_kind_integer , "integer" , "---" )\
|
||||
X(lex_kind_real , "real" , "---" )\
|
||||
X(lex_kind_ident , "identifier" , "---" )\
|
||||
X(lex_kind_string , "string" , "---" )\
|
||||
X(lex_kind_comment , "comment" , "---" )\
|
||||
X(lex_kind_open_brace , "'{' open brace" , "{" )\
|
||||
X(lex_kind_close_brace , "'}' close brace" , "}" )\
|
||||
X(lex_kind_open_paren , "'(' open parenthesis" , "(" )\
|
||||
X(lex_kind_close_paren , "')' close parenthesis" , ")" )\
|
||||
X(lex_kind_open_bracket , "'[' open bracket" , "[" )\
|
||||
X(lex_kind_close_bracket , "']' close bracket" , "]" )\
|
||||
X(lex_kind_plus , "'+' plus" , "+" )\
|
||||
X(lex_kind_minus , "'-' minus" , "-" )\
|
||||
X(lex_kind_divide , "'/' division sign" , "/" )\
|
||||
X(lex_kind_multiply , "'*' multiplication sign" , "*" )\
|
||||
X(lex_kind_modulo , "'%' modulo" , "%" )\
|
||||
X(lex_kind_or , "'||' logical or" , "||" )\
|
||||
X(lex_kind_and , "'&&' logical and" , "&&" )\
|
||||
X(lex_kind_negation , "'!' logical negation" , "!" )\
|
||||
X(lex_kind_bit_negation , "'~' bit negation" , "~" )\
|
||||
X(lex_kind_bit_left_shift , "'<<' bit left shift" , "<<" )\
|
||||
X(lex_kind_bit_right_shift , "'>>' bit right shift" , ">>" )\
|
||||
X(lex_kind_bit_or , "'|' bit or" , "|" )\
|
||||
X(lex_kind_bit_and , "'&' bit and" , "&" )\
|
||||
X(lex_kind_bit_xor , "'^' bit xor" , "^" )\
|
||||
X(lex_kind_decrement , "'--' decrement" , "--" )\
|
||||
X(lex_kind_increment , "'++' increment" , "++" )\
|
||||
X(lex_kind_post_decrement , "'--' post decrement" , "--" )\
|
||||
X(lex_kind_post_increment , "'++' post increment" , "++" )\
|
||||
X(lex_kind_assign , "'=' assignment" , "=" )\
|
||||
X(lex_kind_divide_assign , "'/=' divide assignment" , "/=" )\
|
||||
X(lex_kind_multiply_assign , "'*=' multiply assignment" , "*=" )\
|
||||
X(lex_kind_plus_assign , "'+=' plus assignment" , "+=" )\
|
||||
X(lex_kind_minus_assign , "'-=' minus assignment" , "-=" )\
|
||||
X(lex_kind_modulo_assign , "'%=' modulo assignment" , "%=" )\
|
||||
X(lex_kind_bit_and_assign , "'&=' bit and assignment" , "&=" )\
|
||||
X(lex_kind_bit_or_assign , "'|=' bit or assignment" , "|=" )\
|
||||
X(lex_kind_bit_xor_assign , "'^=' bit xor assignment" , "^=" )\
|
||||
X(lex_kind_bit_left_shift_assign , "'<<=' bit left shift assignment" , "<<=" )\
|
||||
X(lex_kind_bit_right_shift_assign , "'>>=' bit right shift assignment" , ">>=" )\
|
||||
X(lex_kind_equals , "'==' equals sign" , "==" )\
|
||||
X(lex_kind_not_equals , "'!=' not equals sign" , "!=" )\
|
||||
X(lex_kind_lesser , "'<' lesser then" , "<" )\
|
||||
X(lex_kind_greater , "'>' greater then" , ">" )\
|
||||
X(lex_kind_lesser_or_equal , "'<=' lesser then or equal" , "<=" )\
|
||||
X(lex_kind_greater_or_equal , "'>=' greater then or equal" , ">=" )\
|
||||
X(lex_kind_comma , "',' comma" , "," )\
|
||||
X(lex_kind_dot , "'.' dot" , "." )\
|
||||
X(lex_kind_three_dots , "'...' three dots" , "..." )\
|
||||
X(lex_kind_semicolon , "';' semicolon" , ";" )\
|
||||
X(lex_kind_colon , "':' colon" , ":" )\
|
||||
X(lex_kind_arrow , "'->' arrow" , "->" )\
|
||||
X(lex_kind_question , "'?' question mark" , "?" )\
|
||||
X(lex_kind_tag , "'@' tag sign" , "@" )\
|
||||
X(lex_kind_escape , "'\\' escape" , "\\" )\
|
||||
X(lex_kind_preproc_null , "preproc_null" , "---" )\
|
||||
X(lex_kind_preproc_define , "preproc_define" , "---" )\
|
||||
X(lex_kind_preproc_ifdef , "preproc_ifdef" , "---" )\
|
||||
X(lex_kind_preproc_ifndef , "preproc_ifndef" , "---" )\
|
||||
X(lex_kind_preproc_include , "preproc_include" , "---" )\
|
||||
X(lex_kind_preproc_endif , "preproc_endif" , "---" )\
|
||||
X(lex_kind_preproc_if , "preproc_if" , "---" )\
|
||||
X(lex_kind_preproc_pragma , "preproc_pragma" , "---" )\
|
||||
X(lex_kind_preproc_error , "preproc_error" , "---" )\
|
||||
X(lex_kind_preproc_else , "preproc_else" , "---" )\
|
||||
X(lex_kind_preproc_elif , "preproc_elif" , "---" )\
|
||||
X(lex_kind_preproc_undef , "preproc_undef" , "---" )\
|
||||
X(lex_kind_preproc_concat , "preproc_concat" , "---" )\
|
||||
X(lex_kind_preproc_stringify , "preproc_stringify" , "---" )\
|
||||
|
||||
#define X(KIND, STR, SIMPLE) KIND,
|
||||
LEX_KIND_XLIST
|
||||
#undef X
|
||||
|
||||
lex_kind_count,
|
||||
} lex_kind_t;
|
||||
|
||||
typedef enum lex_suffix_t {
|
||||
#define LEX_SUFFIX_XLIST\
|
||||
X(lex_suffix_none) \
|
||||
X(lex_suffix_f) \
|
||||
X(lex_suffix_d) \
|
||||
X(lex_suffix_u) \
|
||||
X(lex_suffix_ul) \
|
||||
X(lex_suffix_ull) \
|
||||
X(lex_suffix_l) \
|
||||
X(lex_suffix_ll) \
|
||||
|
||||
#define X(KIND) KIND,
|
||||
LEX_SUFFIX_XLIST
|
||||
#undef X
|
||||
|
||||
lex_suffix_count,
|
||||
} lex_suffix_t;
|
||||
|
||||
typedef struct lex_t lex_t;
|
||||
struct lex_t {
|
||||
lex_kind_t kind;
|
||||
lex_suffix_t suffix;
|
||||
struct {
|
||||
b8 inside_macro: 1;
|
||||
b8 system_include: 1;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {char *str; i64 len;};
|
||||
s8_t string;
|
||||
};
|
||||
|
||||
i32 line;
|
||||
i32 column;
|
||||
char *file;
|
||||
|
||||
union {
|
||||
u64 integer;
|
||||
f64 real;
|
||||
char *error;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct lexer_t lexer_t;
|
||||
struct lexer_t {
|
||||
char *at;
|
||||
char *end;
|
||||
char *file;
|
||||
i32 line;
|
||||
i32 column;
|
||||
|
||||
b8 inside_macro;
|
||||
};
|
||||
|
||||
typedef struct lex_array_t lex_array_t;
|
||||
struct lex_array_t {
|
||||
lex_t *data;
|
||||
i32 len;
|
||||
};
|
||||
|
||||
fn lex_array_t lex_tokens(ma_arena_t *arena, char *filename, s8_t stream);
|
||||
fn s8_t lex_kind_to_simple_s8(lex_kind_t kind);
|
||||
fn s8_t lex_kind_to_s8(lex_kind_t kind);
|
||||
|
||||
typedef struct parser_t parser_t;
|
||||
struct parser_t {
|
||||
ma_arena_t *arena;
|
||||
lex_t *at;
|
||||
b8 print_only_file;
|
||||
};
|
||||
|
||||
#define parser_make(ARENA, TOKEN) &(parser_t){.arena = ARENA, .at = TOKEN}
|
||||
fn lex_t *parser_next(parser_t *par);
|
||||
fn lex_t *parser_match(parser_t *par, lex_kind_t kind);
|
||||
fn lex_t *parser_matchi(parser_t *par, s8_t str);
|
||||
fn lex_t *parser_expect(parser_t *par, lex_kind_t kind);
|
||||
fn void parser_panicf(b32 print_only_file, lex_t *token, const char *str, ...);
|
||||
fn void parser_eat_until(parser_t *par, lex_kind_t kind);
|
||||
fn void parser_eat_including(parser_t *par, lex_kind_t kind);
|
||||
|
||||
static gb_read_only lex_t lex_null;
|
||||
|
||||
static gb_read_only type_member_t members__lex_kind_t[] = {
|
||||
#define X(KIND, STR, SIMPLE) {.name = s8_const("lex_kind_" #KIND), .value = KIND},
|
||||
LEX_KIND_XLIST
|
||||
#undef X
|
||||
};
|
||||
static DEFINE_ENUM(lex_kind_t);
|
||||
|
||||
static gb_read_only type_member_t members__lex_suffix_t[] = {
|
||||
#define X(KIND) {.name = s8_const(#KIND), .value = KIND},
|
||||
LEX_SUFFIX_XLIST
|
||||
#undef X
|
||||
};
|
||||
static DEFINE_ENUM(lex_suffix_t);
|
||||
@@ -1,42 +0,0 @@
|
||||
#include "core_log.h"
|
||||
#include "core_ctx.h"
|
||||
#include "core_platform.h"
|
||||
|
||||
fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
S8_FMT(scratch.arena, str, string);
|
||||
tcx->log.log_proc(level, file_and_line, string);
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
fn void default_log_proc(log_level_t level, s8_t file_and_line, s8_t string) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
|
||||
char *colon = ": ";
|
||||
if (tcx->log.print_file_and_line == false) {
|
||||
file_and_line.len = 0;
|
||||
colon = "";
|
||||
}
|
||||
|
||||
switch(level) {
|
||||
case log_level_debug:
|
||||
case log_level_info: {
|
||||
os_console_log(s8_printf(scratch.arena, "%.*s\n", s8_fmtspec(string)).str);
|
||||
} break;
|
||||
case log_level_warning: {
|
||||
os_console_log(s8_printf(scratch.arena, "%.*s%s%.*s\n", s8_fmtspec(file_and_line), colon, s8_fmtspec(string)).str);
|
||||
if (tcx->log.break_on_warning) debug_break();
|
||||
} break;
|
||||
case log_level_error: {
|
||||
os_console_log(s8_printf(scratch.arena, "%.*s%s%.*s\n", s8_fmtspec(file_and_line), colon, s8_fmtspec(string)).str);
|
||||
if (tcx->log.break_on_error) debug_break();
|
||||
} break;
|
||||
case log_level_fatal: {
|
||||
os_error_box(s8_printf(scratch.arena, "%.*s%s%.*s\n", s8_fmtspec(file_and_line), colon, s8_fmtspec(string)).str);
|
||||
if (tcx->log.break_on_fatal) debug_break();
|
||||
} break;
|
||||
default_is_invalid;
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_string.h"
|
||||
|
||||
typedef enum {
|
||||
log_level_debug,
|
||||
log_level_info,
|
||||
log_level_warning,
|
||||
log_level_error,
|
||||
log_level_fatal,
|
||||
} log_level_t;
|
||||
|
||||
typedef struct logger_t logger_t;
|
||||
struct logger_t {
|
||||
void (*log_proc)(log_level_t level, s8_t file_and_line, s8_t string);
|
||||
void *user_data;
|
||||
b8 break_on_fatal;
|
||||
b8 break_on_error;
|
||||
b8 break_on_warning;
|
||||
b8 print_file_and_line;
|
||||
};
|
||||
|
||||
///////////////////////////////
|
||||
// main api
|
||||
#define debugf(...) log_basef(log_level_debug, S8_FILE_AND_LINE, __VA_ARGS__)
|
||||
#define errorf(...) log_basef(log_level_error, S8_FILE_AND_LINE, __VA_ARGS__)
|
||||
#define fatalf(...) (log_basef(log_level_fatal, S8_FILE_AND_LINE, __VA_ARGS__), 0)
|
||||
|
||||
fn void default_log_proc(log_level_t level, s8_t file_and_line, s8_t string);
|
||||
fn void log_basef(log_level_t level, s8_t file_and_line, const char *str, ...);
|
||||
@@ -1,555 +0,0 @@
|
||||
#include "core_math.h"
|
||||
#include "core_intrin.h"
|
||||
|
||||
/*
|
||||
* Converts an RGB color value to HSL. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* also https://gist.github.com/ciembor/1494530
|
||||
* alpha is ignored
|
||||
*/
|
||||
fn v3f32_t v3f32_rgb_to_hsl(v3f32_t color) {
|
||||
v3f32_t result;
|
||||
f32 max = MAX(MAX(color.r, color.g), color.b);
|
||||
f32 min = MIN(MIN(color.r, color.g), color.b);
|
||||
|
||||
result.h = result.s = result.l = (max + min) / 2.f;
|
||||
|
||||
if (max == min) {
|
||||
result.h = result.s = 0.f; // achromatic
|
||||
} else {
|
||||
f32 d = max - min;
|
||||
result.s = (result.l > 0.5f) ? d / (2.f - max - min) : d / (max + min);
|
||||
|
||||
if (max == color.r) {
|
||||
result.h = (color.g - color.b) / d + (color.g < color.b ? 6.f : 0.f);
|
||||
} else if (max == color.g) {
|
||||
result.h = (color.b - color.r) / d + 2.f;
|
||||
} else if (max == color.b) {
|
||||
result.h = (color.r - color.g) / d + 4.f;
|
||||
}
|
||||
|
||||
result.h /= 6.f;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts an HUE to r, g or b.
|
||||
* returns f32 in the set [0, 1].
|
||||
*/
|
||||
fn f32 f32_hue_to_rgb(f32 p, f32 q, f32 t) {
|
||||
if (t < 0.f)
|
||||
t += 1.f;
|
||||
if (t > 1.f)
|
||||
t -= 1.f;
|
||||
if (t < 1.f / 6.f)
|
||||
return p + (q - p) * 6.f * t;
|
||||
if (t < 1.f / 2.f)
|
||||
return q;
|
||||
if (t < 2.f / 3.f)
|
||||
return p + (q - p) * (2.f / 3.f - t) * 6.f;
|
||||
return p;
|
||||
}
|
||||
|
||||
fn v3f32_t v3f32_hsl_to_rgb(v3f32_t color) {
|
||||
v3f32_t result;
|
||||
|
||||
if (0 == color.s) {
|
||||
result.r = result.g = result.b = color.l; // achromatic
|
||||
} else {
|
||||
f32 q = color.l < 0.5f ? color.l * (1.f + color.s)
|
||||
: color.l + color.s - color.l * color.s;
|
||||
f32 p = 2.f * color.l - q;
|
||||
result.r = f32_hue_to_rgb(p, q, color.h + 1.f / 3.f);
|
||||
result.g = f32_hue_to_rgb(p, q, color.h);
|
||||
result.b = f32_hue_to_rgb(p, q, color.h - 1.f / 3.f);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn v4f32_t v4f32_rgba_to_hsla(v4f32_t rgba) {
|
||||
v3f32_t result = v3f32_rgb_to_hsl(rgba.xyz);
|
||||
return (v4f32_t){result.r, result.g, result.b, rgba.a};
|
||||
}
|
||||
|
||||
fn v4f32_t v4f32_hsla_to_rgba(v4f32_t color) {
|
||||
v3f32_t result = v3f32_hsl_to_rgb(color.xyz);
|
||||
return (v4f32_t){result.r, result.g, result.b, color.a};
|
||||
}
|
||||
|
||||
/*
|
||||
https://git.musl-libc.org/cgit/musl/tree/src/math
|
||||
https://gitlab.com/nakst/essence/-/blob/master/shared/math.cpp
|
||||
*/
|
||||
|
||||
|
||||
fn f64 f64_clamp01(f64 a) { return CLAMP(a, 0, 1); }
|
||||
fn f64 f64_lerp(f64 a, f64 b, f64 t) { return (1 - t) * a + t * b; }
|
||||
fn f64 f64_smooth_step(f64 t) { return t*t*(3-2*t); }
|
||||
fn f64 f64_ease_in_quint(f64 x) { return x * x * x * x * x; }
|
||||
fn f64 f64_ease_in_cubic(f64 x) { return x * x * x; }
|
||||
fn f64 f64_ping_pong(f64 x) { return 1.0 - f64_abs(1.0 - f64_mod(x,2)); }
|
||||
|
||||
fn f32 f32_clamp01(f32 a) { return CLAMP(a, 0, 1); }
|
||||
fn f32 f32_lerp(f32 a, f32 b, f32 t) { return (1 - t) * a + t * b; }
|
||||
fn f32 f32_smooth_step(f32 t) { return t*t*(3-2*t); }
|
||||
fn f32 f32_ease_in_quint(f32 x) { return x * x * x * x * x; }
|
||||
fn f32 f32_ease_in_cubic(f32 x) { return x * x * x; }
|
||||
fn f32 f32_ping_pong(f32 x) { return 1.0f - f32_abs(1.0f - f32_mod(x,2)); }
|
||||
|
||||
fn v4f32_t v4f32_lerp(v4f32_t a, v4f32_t b, f32 t) {
|
||||
return (v4f32_t){f32_lerp(a.x, b.x, t), f32_lerp(a.y, b.y, t), f32_lerp(a.z, b.z, t), f32_lerp(a.w, b.w, t)};
|
||||
}
|
||||
|
||||
fn v4f32_t v4f32_lerp_noa(v4f32_t a, v4f32_t b, f32 t) {
|
||||
return (v4f32_t){f32_lerp(a.x, b.x, t), f32_lerp(a.y, b.y, t), f32_lerp(a.z, b.z, t), a.w};
|
||||
}
|
||||
|
||||
fn f64 _Sine(f64 x) {
|
||||
// Calculates sin(x) for x in [0, pi/4].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return x * (U64_TO_F64(0x3FF0000000000000) + x2 * (U64_TO_F64(0xBFC5555555555540) + x2 * (U64_TO_F64(0x3F8111111110ED80) + x2 * (U64_TO_F64(0xBF2A01A019AE6000)
|
||||
+ x2 * (U64_TO_F64(0x3EC71DE349280000) + x2 * (U64_TO_F64(0xBE5AE5DC48000000) + x2 * U64_TO_F64(0x3DE5D68200000000)))))));
|
||||
}
|
||||
|
||||
fn f32 _SineFloat(f32 x) {
|
||||
// Calculates sin(x) for x in [0, pi/4].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return x * (U32_TO_F32(0x3F800000) + x2 * (U32_TO_F32(0xBE2AAAA0) + x2 * (U32_TO_F32(0x3C0882C0) + x2 * U32_TO_F32(0xB94C6000))));
|
||||
}
|
||||
|
||||
fn f64 _ArcSine(f64 x) {
|
||||
// Calculates arcsin(x) for x in [0, 0.5].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFE6) + x2 * (U64_TO_F64(0x3FC555555555FE00) + x2 * (U64_TO_F64(0x3FB333333292DF90) + x2 * (U64_TO_F64(0x3FA6DB6DFD3693A0)
|
||||
+ x2 * (U64_TO_F64(0x3F9F1C608DE51900) + x2 * (U64_TO_F64(0x3F96EA0659B9A080) + x2 * (U64_TO_F64(0x3F91B4ABF1029100)
|
||||
+ x2 * (U64_TO_F64(0x3F8DA8DAF31ECD00) + x2 * (U64_TO_F64(0x3F81C01FD5000C00) + x2 * (U64_TO_F64(0x3F94BDA038CF6B00)
|
||||
+ x2 * (U64_TO_F64(0xBF8E849CA75B1E00) + x2 * U64_TO_F64(0x3FA146C2D37F2C60))))))))))));
|
||||
}
|
||||
|
||||
fn f32 _ArcSineFloat(f32 x) {
|
||||
// Calculates arcsin(x) for x in [0, 0.5].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return x * (U32_TO_F32(0x3F800004) + x2 * (U32_TO_F32(0x3E2AA130) + x2 * (U32_TO_F32(0x3D9B2C28) + x2 * (U32_TO_F32(0x3D1C1800) + x2 * U32_TO_F32(0x3D5A97C0)))));
|
||||
}
|
||||
|
||||
fn f64 _ArcTangent(f64 x) {
|
||||
// Calculates arctan(x) for x in [0, 0.5].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFF8) + x2 * (U64_TO_F64(0xBFD5555555553B44) + x2 * (U64_TO_F64(0x3FC9999999803988) + x2 * (U64_TO_F64(0xBFC249248C882E80)
|
||||
+ x2 * (U64_TO_F64(0x3FBC71C5A4E4C220) + x2 * (U64_TO_F64(0xBFB745B3B75243F0) + x2 * (U64_TO_F64(0x3FB3AFAE9A2939E0)
|
||||
+ x2 * (U64_TO_F64(0xBFB1030C4A4A1B90) + x2 * (U64_TO_F64(0x3FAD6F65C35579A0) + x2 * (U64_TO_F64(0xBFA805BCFDAFEDC0)
|
||||
+ x2 * (U64_TO_F64(0x3F9FC6B5E115F2C0) + x2 * U64_TO_F64(0xBF87DCA5AB25BF80))))))))))));
|
||||
}
|
||||
|
||||
fn f32 _ArcTangentFloat(f32 x) {
|
||||
// Calculates arctan(x) for x in [0, 0.5].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return x * (U32_TO_F32(0x3F7FFFF8) + x2 * (U32_TO_F32(0xBEAAA53C) + x2 * (U32_TO_F32(0x3E4BC990) + x2 * (U32_TO_F32(0xBE084A60) + x2 * U32_TO_F32(0x3D8864B0)))));
|
||||
}
|
||||
|
||||
fn f64 _Cosine(f64 x) {
|
||||
// Calculates cos(x) for x in [0, pi/4].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return U64_TO_F64(0x3FF0000000000000) + x2 * (U64_TO_F64(0xBFDFFFFFFFFFFFA0) + x2 * (U64_TO_F64(0x3FA555555554F7C0) + x2 * (U64_TO_F64(0xBF56C16C16475C00)
|
||||
+ x2 * (U64_TO_F64(0x3EFA019F87490000) + x2 * (U64_TO_F64(0xBE927DF66B000000) + x2 * U64_TO_F64(0x3E21B949E0000000))))));
|
||||
}
|
||||
|
||||
fn f32 _CosineFloat(f32 x) {
|
||||
// Calculates cos(x) for x in [0, pi/4].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return U32_TO_F32(0x3F800000) + x2 * (U32_TO_F32(0xBEFFFFDA) + x2 * (U32_TO_F32(0x3D2A9F60) + x2 * U32_TO_F32(0xBAB22C00)));
|
||||
}
|
||||
|
||||
fn f64 _Tangent(f64 x) {
|
||||
// Calculates tan(x) for x in [0, pi/4].
|
||||
|
||||
f64 x2 = x * x;
|
||||
|
||||
return x * (U64_TO_F64(0x3FEFFFFFFFFFFFE8) + x2 * (U64_TO_F64(0x3FD5555555558000) + x2 * (U64_TO_F64(0x3FC1111110FACF90) + x2 * (U64_TO_F64(0x3FABA1BA266BFD20)
|
||||
+ x2 * (U64_TO_F64(0x3F9664F30E56E580) + x2 * (U64_TO_F64(0x3F822703B08BDC00) + x2 * (U64_TO_F64(0x3F6D698D2E4A4C00)
|
||||
+ x2 * (U64_TO_F64(0x3F57FF4F23EA4400) + x2 * (U64_TO_F64(0x3F424F3BEC845800) + x2 * (U64_TO_F64(0x3F34C78CA9F61000)
|
||||
+ x2 * (U64_TO_F64(0xBF042089F8510000) + x2 * (U64_TO_F64(0x3F29D7372D3A8000) + x2 * (U64_TO_F64(0xBF19D1C5EF6F0000)
|
||||
+ x2 * (U64_TO_F64(0x3F0980BDF11E8000)))))))))))))));
|
||||
}
|
||||
|
||||
fn f32 _TangentFloat(f32 x) {
|
||||
// Calculates tan(x) for x in [0, pi/4].
|
||||
|
||||
f32 x2 = x * x;
|
||||
|
||||
return x * (U32_TO_F32(0x3F800001) + x2 * (U32_TO_F32(0x3EAAA9AA) + x2 * (U32_TO_F32(0x3E08ABA8) + x2 * (U32_TO_F32(0x3D58EC90)
|
||||
+ x2 * (U32_TO_F32(0x3CD24840) + x2 * (U32_TO_F32(0x3AC3CA00) + x2 * U32_TO_F32(0x3C272F00)))))));
|
||||
}
|
||||
|
||||
fn f64 f64_sin(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= 2 * F64_PI * f64_floor(x / (2 * F64_PI));
|
||||
|
||||
// x in 0, 2*pi
|
||||
|
||||
if (x < F64_PI / 2) {
|
||||
} else if (x < F64_PI) {
|
||||
x = F64_PI - x;
|
||||
} else if (x < 3 * F64_PI / 2) {
|
||||
x = x - F64_PI;
|
||||
negate = !negate;
|
||||
} else {
|
||||
x = F64_PI * 2 - x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f64 y = x < F64_PI / 4 ? _Sine(x) : _Cosine(F64_PI / 2 - x);
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
|
||||
fn f32 f32_sin(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= 2 * F32_PI * f32_floor(x / (2 * F32_PI));
|
||||
|
||||
// x in 0, 2*pi
|
||||
|
||||
if (x < F32_PI / 2) {
|
||||
} else if (x < F32_PI) {
|
||||
x = F32_PI - x;
|
||||
} else if (x < 3 * F32_PI / 2) {
|
||||
x = x - F32_PI;
|
||||
negate = !negate;
|
||||
} else {
|
||||
x = F32_PI * 2 - x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f32 y = x < F32_PI / 4 ? _SineFloat(x) : _CosineFloat(F32_PI / 2 - x);
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_cos(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= 2 * F64_PI * f64_floor(x / (2 * F64_PI));
|
||||
|
||||
// x in 0, 2*pi
|
||||
|
||||
if (x < F64_PI / 2) {
|
||||
} else if (x < F64_PI) {
|
||||
x = F64_PI - x;
|
||||
negate = !negate;
|
||||
} else if (x < 3 * F64_PI / 2) {
|
||||
x = x - F64_PI;
|
||||
negate = !negate;
|
||||
} else {
|
||||
x = F64_PI * 2 - x;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f64 y = x < F64_PI / 4 ? _Cosine(x) : _Sine(F64_PI / 2 - x);
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f32 f32_cos(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= 2 * F32_PI * f32_floor(x / (2 * F32_PI));
|
||||
|
||||
// x in 0, 2*pi
|
||||
|
||||
if (x < F32_PI / 2) {
|
||||
} else if (x < F32_PI) {
|
||||
x = F32_PI - x;
|
||||
negate = !negate;
|
||||
} else if (x < 3 * F32_PI / 2) {
|
||||
x = x - F32_PI;
|
||||
negate = !negate;
|
||||
} else {
|
||||
x = F32_PI * 2 - x;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f32 y = x < F32_PI / 4 ? _CosineFloat(x) : _SineFloat(F32_PI / 2 - x);
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_tan(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= F64_PI * f64_floor(x / F64_PI);
|
||||
|
||||
// x in 0, pi
|
||||
|
||||
if (x > F64_PI / 2) {
|
||||
x = F64_PI - x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f64 y = x < F64_PI / 4 ? _Tangent(x) : (1.0 / _Tangent(F64_PI / 2 - x));
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f32 f32_tan(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
// x in -infty, infty
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, infty
|
||||
|
||||
x -= F32_PI * f32_floor(x / F32_PI);
|
||||
|
||||
// x in 0, pi
|
||||
|
||||
if (x > F32_PI / 2) {
|
||||
x = F32_PI - x;
|
||||
negate = !negate;
|
||||
}
|
||||
|
||||
// x in 0, pi/2
|
||||
|
||||
f32 y = x < F32_PI / 4 ? _TangentFloat(x) : (1.0f / _TangentFloat(F32_PI / 2 - x));
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_asin(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
f64 y;
|
||||
|
||||
if (x < 0.5) {
|
||||
y = _ArcSine(x);
|
||||
} else {
|
||||
y = F64_PI / 2 - 2 * _ArcSine(f64_sqrt(0.5 - 0.5 * x));
|
||||
}
|
||||
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f32 f32_asin(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
f32 y;
|
||||
|
||||
if (x < 0.5) {
|
||||
y = _ArcSineFloat(x);
|
||||
} else {
|
||||
y = F32_PI / 2 - 2 * _ArcSineFloat(f32_sqrt(0.5f - 0.5f * x));
|
||||
}
|
||||
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_acos(f64 x) {
|
||||
return f64_asin(-x) + F64_PI / 2;
|
||||
}
|
||||
|
||||
fn f32 f32_acos(f32 x) {
|
||||
return f32_asin(-x) + F32_PI / 2;
|
||||
}
|
||||
|
||||
fn f64 f64_atan(f64 x) {
|
||||
b32 negate = false;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
b32 reciprocalTaken = false;
|
||||
|
||||
if (x > 1) {
|
||||
x = 1 / x;
|
||||
reciprocalTaken = true;
|
||||
}
|
||||
|
||||
f64 y;
|
||||
|
||||
if (x < 0.5) {
|
||||
y = _ArcTangent(x);
|
||||
} else {
|
||||
y = 0.463647609000806116 + _ArcTangent((2 * x - 1) / (2 + x));
|
||||
}
|
||||
|
||||
if (reciprocalTaken) {
|
||||
y = F64_PI / 2 - y;
|
||||
}
|
||||
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f32 f32_atan(f32 x) {
|
||||
b32 negate = false;
|
||||
|
||||
if (x < 0) {
|
||||
x = -x;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
b32 reciprocalTaken = false;
|
||||
|
||||
if (x > 1) {
|
||||
x = 1 / x;
|
||||
reciprocalTaken = true;
|
||||
}
|
||||
|
||||
f32 y;
|
||||
|
||||
if (x < 0.5f) {
|
||||
y = _ArcTangentFloat(x);
|
||||
} else {
|
||||
y = 0.463647609000806116f + _ArcTangentFloat((2 * x - 1) / (2 + x));
|
||||
}
|
||||
|
||||
if (reciprocalTaken) {
|
||||
y = F32_PI / 2 - y;
|
||||
}
|
||||
|
||||
return negate ? -y : y;
|
||||
}
|
||||
|
||||
fn f64 f64_atan2(f64 y, f64 x) {
|
||||
if (x == 0) return y > 0 ? F64_PI / 2 : -F64_PI / 2;
|
||||
else if (x > 0) return f64_atan(y / x);
|
||||
else if (y >= 0) return F64_PI + f64_atan(y / x);
|
||||
else return -F64_PI + f64_atan(y / x);
|
||||
}
|
||||
|
||||
fn f32 f32_atan2(f32 y, f32 x) {
|
||||
if (x == 0) return y > 0 ? F32_PI / 2 : -F32_PI / 2;
|
||||
else if (x > 0) return f32_atan(y / x);
|
||||
else if (y >= 0) return F32_PI + f32_atan(y / x);
|
||||
else return -F32_PI + f32_atan(y / x);
|
||||
}
|
||||
|
||||
fn b32 f32_are_equal(f32 a, f32 b) {
|
||||
f32 diff = f32_abs(a - b);
|
||||
b32 result = diff <= 0.00001f;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 f64_are_equal(f64 a, f64 b) {
|
||||
f64 diff = f64_abs(a - b);
|
||||
b32 result = diff <= 0.00001;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn f32 f32_ease_out_bounce(f32 x) {
|
||||
f32 n1 = 7.5625f;
|
||||
f32 d1 = 2.75f;
|
||||
|
||||
if (x < 1.f / d1) {
|
||||
return n1 * x * x;
|
||||
} else if (x < 2.f / d1) {
|
||||
return n1 * (x -= 1.5f / d1) * x + 0.75f;
|
||||
} else if (x < 2.5f / d1) {
|
||||
return n1 * (x -= 2.25f / d1) * x + 0.9375f;
|
||||
} else {
|
||||
return n1 * (x -= 2.625f / d1) * x + 0.984375f;
|
||||
}
|
||||
}
|
||||
|
||||
fn f32 f32_ease_out_elastic(f32 x) {
|
||||
f32 c4 = (2 * F32_PI) / 3;
|
||||
|
||||
return x == 0.f
|
||||
? 0
|
||||
: x == 1.f
|
||||
? 1
|
||||
: f32_pow(2.f, -10.f * x) * f32_sin((x * 10.f - 0.75f) * c4) + 1.f;
|
||||
}
|
||||
|
||||
fn f32 f32_ease_out_cubic(f32 x) {
|
||||
return 1.f - f32_pow(1.f - x, 3.f);
|
||||
}
|
||||
|
||||
fn f32 f32_ease_out_n(f32 x, f32 n) {
|
||||
return 1.f - f32_pow(1.f - x, n);
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_lerp(r2f32_t a, r2f32_t b, f32 t) {
|
||||
r2f32_t result = { .min = {f32_lerp(a.min.x, b.min.x, t), f32_lerp(a.min.y, b.min.y, t)}, .max = {f32_lerp(a.max.x, b.max.x, t), f32_lerp(a.max.y, b.max.y, t)} };
|
||||
return result;
|
||||
}
|
||||
@@ -1,959 +0,0 @@
|
||||
#include "core_math.h"
|
||||
#include "core_intrin.h"
|
||||
|
||||
fn_inline v2f32_t v2f32(f32 x, f32 y) { return (v2f32_t){ x, y }; }
|
||||
gb_read_only v2f32_t v2f32_null = {0};
|
||||
fn_inline b32 v2f32_is_null(v2f32_t a) { return memory_equal(&a, &v2f32_null, sizeof(a)); }
|
||||
fn_inline b32 v2f32_are_equal(v2f32_t a, v2f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v2f32_t v2f32_add(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x + b.x, a.y + b.y }; }
|
||||
fn_inline v2f32_t v2f32_adds(v2f32_t a, f32 b) { return (v2f32_t){ a.x + b, a.y + b }; }
|
||||
fn_inline v2f32_t v2f32_sub(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x - b.x, a.y - b.y }; }
|
||||
fn_inline v2f32_t v2f32_subs(v2f32_t a, f32 b) { return (v2f32_t){ a.x - b, a.y - b }; }
|
||||
fn_inline v2f32_t v2f32_mul(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x * b.x, a.y * b.y }; }
|
||||
fn_inline v2f32_t v2f32_muls(v2f32_t a, f32 b) { return (v2f32_t){ a.x * b, a.y * b }; }
|
||||
fn_inline v2f32_t v2f32_div(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x / b.x, a.y / b.y }; }
|
||||
fn_inline v2f32_t v2f32_divs(v2f32_t a, f32 b) { return (v2f32_t){ a.x / b, a.y / b }; }
|
||||
fn_inline v3f32_t v3f32(f32 x, f32 y, f32 z) { return (v3f32_t){ x, y, z }; }
|
||||
gb_read_only v3f32_t v3f32_null = {0};
|
||||
fn_inline b32 v3f32_is_null(v3f32_t a) { return memory_equal(&a, &v3f32_null, sizeof(a)); }
|
||||
fn_inline b32 v3f32_are_equal(v3f32_t a, v3f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v3f32_t v3f32_add(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
|
||||
fn_inline v3f32_t v3f32_adds(v3f32_t a, f32 b) { return (v3f32_t){ a.x + b, a.y + b, a.z + b }; }
|
||||
fn_inline v3f32_t v3f32_sub(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
|
||||
fn_inline v3f32_t v3f32_subs(v3f32_t a, f32 b) { return (v3f32_t){ a.x - b, a.y - b, a.z - b }; }
|
||||
fn_inline v3f32_t v3f32_mul(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
|
||||
fn_inline v3f32_t v3f32_muls(v3f32_t a, f32 b) { return (v3f32_t){ a.x * b, a.y * b, a.z * b }; }
|
||||
fn_inline v3f32_t v3f32_div(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
|
||||
fn_inline v3f32_t v3f32_divs(v3f32_t a, f32 b) { return (v3f32_t){ a.x / b, a.y / b, a.z / b }; }
|
||||
fn_inline v4f32_t v4f32(f32 x, f32 y, f32 z, f32 w) { return (v4f32_t){ x, y, z, w }; }
|
||||
gb_read_only v4f32_t v4f32_null = {0};
|
||||
fn_inline b32 v4f32_is_null(v4f32_t a) { return memory_equal(&a, &v4f32_null, sizeof(a)); }
|
||||
fn_inline b32 v4f32_are_equal(v4f32_t a, v4f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v4f32_t v4f32_add(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
|
||||
fn_inline v4f32_t v4f32_adds(v4f32_t a, f32 b) { return (v4f32_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
|
||||
fn_inline v4f32_t v4f32_sub(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
|
||||
fn_inline v4f32_t v4f32_subs(v4f32_t a, f32 b) { return (v4f32_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
|
||||
fn_inline v4f32_t v4f32_mul(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
|
||||
fn_inline v4f32_t v4f32_muls(v4f32_t a, f32 b) { return (v4f32_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
|
||||
fn_inline v4f32_t v4f32_div(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
|
||||
fn_inline v4f32_t v4f32_divs(v4f32_t a, f32 b) { return (v4f32_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
|
||||
fn_inline r2f32_t r2f32(f32 x0, f32 y0, f32 x1, f32 y1) { return (r2f32_t){ x0, y0, x1, y1 }; }
|
||||
gb_read_only r2f32_t r2f32_null = {0};
|
||||
fn_inline b32 r2f32_is_null(r2f32_t a) { return memory_equal(&a, &r2f32_null, sizeof(a)); }
|
||||
fn_inline b32 r2f32_are_equal(r2f32_t a, r2f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r2f32_t r2f32_add(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
|
||||
fn_inline r2f32_t r2f32_adds(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
|
||||
fn_inline r2f32_t r2f32_sub(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
|
||||
fn_inline r2f32_t r2f32_subs(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
|
||||
fn_inline r2f32_t r2f32_mul(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
|
||||
fn_inline r2f32_t r2f32_muls(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
|
||||
fn_inline r2f32_t r2f32_div(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
|
||||
fn_inline r2f32_t r2f32_divs(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
|
||||
fn_inline r3f32_t r3f32(f32 x0, f32 y0, f32 z0, f32 x1, f32 y1, f32 z1) { return (r3f32_t){ x0, y0, z0, x1, y1, z1 }; }
|
||||
gb_read_only r3f32_t r3f32_null = {0};
|
||||
fn_inline b32 r3f32_is_null(r3f32_t a) { return memory_equal(&a, &r3f32_null, sizeof(a)); }
|
||||
fn_inline b32 r3f32_are_equal(r3f32_t a, r3f32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r3f32_t r3f32_add(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
|
||||
fn_inline r3f32_t r3f32_adds(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
|
||||
fn_inline r3f32_t r3f32_sub(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
|
||||
fn_inline r3f32_t r3f32_subs(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
|
||||
fn_inline r3f32_t r3f32_mul(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
|
||||
fn_inline r3f32_t r3f32_muls(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
|
||||
fn_inline r3f32_t r3f32_div(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
|
||||
fn_inline r3f32_t r3f32_divs(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
|
||||
fn_inline v2f64_t v2f64(f64 x, f64 y) { return (v2f64_t){ x, y }; }
|
||||
gb_read_only v2f64_t v2f64_null = {0};
|
||||
fn_inline b32 v2f64_is_null(v2f64_t a) { return memory_equal(&a, &v2f64_null, sizeof(a)); }
|
||||
fn_inline b32 v2f64_are_equal(v2f64_t a, v2f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v2f64_t v2f64_add(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x + b.x, a.y + b.y }; }
|
||||
fn_inline v2f64_t v2f64_adds(v2f64_t a, f64 b) { return (v2f64_t){ a.x + b, a.y + b }; }
|
||||
fn_inline v2f64_t v2f64_sub(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x - b.x, a.y - b.y }; }
|
||||
fn_inline v2f64_t v2f64_subs(v2f64_t a, f64 b) { return (v2f64_t){ a.x - b, a.y - b }; }
|
||||
fn_inline v2f64_t v2f64_mul(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x * b.x, a.y * b.y }; }
|
||||
fn_inline v2f64_t v2f64_muls(v2f64_t a, f64 b) { return (v2f64_t){ a.x * b, a.y * b }; }
|
||||
fn_inline v2f64_t v2f64_div(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x / b.x, a.y / b.y }; }
|
||||
fn_inline v2f64_t v2f64_divs(v2f64_t a, f64 b) { return (v2f64_t){ a.x / b, a.y / b }; }
|
||||
fn_inline v3f64_t v3f64(f64 x, f64 y, f64 z) { return (v3f64_t){ x, y, z }; }
|
||||
gb_read_only v3f64_t v3f64_null = {0};
|
||||
fn_inline b32 v3f64_is_null(v3f64_t a) { return memory_equal(&a, &v3f64_null, sizeof(a)); }
|
||||
fn_inline b32 v3f64_are_equal(v3f64_t a, v3f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v3f64_t v3f64_add(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
|
||||
fn_inline v3f64_t v3f64_adds(v3f64_t a, f64 b) { return (v3f64_t){ a.x + b, a.y + b, a.z + b }; }
|
||||
fn_inline v3f64_t v3f64_sub(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
|
||||
fn_inline v3f64_t v3f64_subs(v3f64_t a, f64 b) { return (v3f64_t){ a.x - b, a.y - b, a.z - b }; }
|
||||
fn_inline v3f64_t v3f64_mul(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
|
||||
fn_inline v3f64_t v3f64_muls(v3f64_t a, f64 b) { return (v3f64_t){ a.x * b, a.y * b, a.z * b }; }
|
||||
fn_inline v3f64_t v3f64_div(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
|
||||
fn_inline v3f64_t v3f64_divs(v3f64_t a, f64 b) { return (v3f64_t){ a.x / b, a.y / b, a.z / b }; }
|
||||
fn_inline v4f64_t v4f64(f64 x, f64 y, f64 z, f64 w) { return (v4f64_t){ x, y, z, w }; }
|
||||
gb_read_only v4f64_t v4f64_null = {0};
|
||||
fn_inline b32 v4f64_is_null(v4f64_t a) { return memory_equal(&a, &v4f64_null, sizeof(a)); }
|
||||
fn_inline b32 v4f64_are_equal(v4f64_t a, v4f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v4f64_t v4f64_add(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
|
||||
fn_inline v4f64_t v4f64_adds(v4f64_t a, f64 b) { return (v4f64_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
|
||||
fn_inline v4f64_t v4f64_sub(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
|
||||
fn_inline v4f64_t v4f64_subs(v4f64_t a, f64 b) { return (v4f64_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
|
||||
fn_inline v4f64_t v4f64_mul(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
|
||||
fn_inline v4f64_t v4f64_muls(v4f64_t a, f64 b) { return (v4f64_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
|
||||
fn_inline v4f64_t v4f64_div(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
|
||||
fn_inline v4f64_t v4f64_divs(v4f64_t a, f64 b) { return (v4f64_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
|
||||
fn_inline r2f64_t r2f64(f64 x0, f64 y0, f64 x1, f64 y1) { return (r2f64_t){ x0, y0, x1, y1 }; }
|
||||
gb_read_only r2f64_t r2f64_null = {0};
|
||||
fn_inline b32 r2f64_is_null(r2f64_t a) { return memory_equal(&a, &r2f64_null, sizeof(a)); }
|
||||
fn_inline b32 r2f64_are_equal(r2f64_t a, r2f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r2f64_t r2f64_add(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
|
||||
fn_inline r2f64_t r2f64_adds(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
|
||||
fn_inline r2f64_t r2f64_sub(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
|
||||
fn_inline r2f64_t r2f64_subs(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
|
||||
fn_inline r2f64_t r2f64_mul(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
|
||||
fn_inline r2f64_t r2f64_muls(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
|
||||
fn_inline r2f64_t r2f64_div(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
|
||||
fn_inline r2f64_t r2f64_divs(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
|
||||
fn_inline r3f64_t r3f64(f64 x0, f64 y0, f64 z0, f64 x1, f64 y1, f64 z1) { return (r3f64_t){ x0, y0, z0, x1, y1, z1 }; }
|
||||
gb_read_only r3f64_t r3f64_null = {0};
|
||||
fn_inline b32 r3f64_is_null(r3f64_t a) { return memory_equal(&a, &r3f64_null, sizeof(a)); }
|
||||
fn_inline b32 r3f64_are_equal(r3f64_t a, r3f64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r3f64_t r3f64_add(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
|
||||
fn_inline r3f64_t r3f64_adds(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
|
||||
fn_inline r3f64_t r3f64_sub(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
|
||||
fn_inline r3f64_t r3f64_subs(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
|
||||
fn_inline r3f64_t r3f64_mul(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
|
||||
fn_inline r3f64_t r3f64_muls(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
|
||||
fn_inline r3f64_t r3f64_div(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
|
||||
fn_inline r3f64_t r3f64_divs(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
|
||||
fn_inline v2i32_t v2i32(i32 x, i32 y) { return (v2i32_t){ x, y }; }
|
||||
gb_read_only v2i32_t v2i32_null = {0};
|
||||
fn_inline b32 v2i32_is_null(v2i32_t a) { return memory_equal(&a, &v2i32_null, sizeof(a)); }
|
||||
fn_inline b32 v2i32_are_equal(v2i32_t a, v2i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v2i32_t v2i32_add(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x + b.x, a.y + b.y }; }
|
||||
fn_inline v2i32_t v2i32_adds(v2i32_t a, i32 b) { return (v2i32_t){ a.x + b, a.y + b }; }
|
||||
fn_inline v2i32_t v2i32_sub(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x - b.x, a.y - b.y }; }
|
||||
fn_inline v2i32_t v2i32_subs(v2i32_t a, i32 b) { return (v2i32_t){ a.x - b, a.y - b }; }
|
||||
fn_inline v2i32_t v2i32_mul(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x * b.x, a.y * b.y }; }
|
||||
fn_inline v2i32_t v2i32_muls(v2i32_t a, i32 b) { return (v2i32_t){ a.x * b, a.y * b }; }
|
||||
fn_inline v2i32_t v2i32_div(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x / b.x, a.y / b.y }; }
|
||||
fn_inline v2i32_t v2i32_divs(v2i32_t a, i32 b) { return (v2i32_t){ a.x / b, a.y / b }; }
|
||||
fn_inline v3i32_t v3i32(i32 x, i32 y, i32 z) { return (v3i32_t){ x, y, z }; }
|
||||
gb_read_only v3i32_t v3i32_null = {0};
|
||||
fn_inline b32 v3i32_is_null(v3i32_t a) { return memory_equal(&a, &v3i32_null, sizeof(a)); }
|
||||
fn_inline b32 v3i32_are_equal(v3i32_t a, v3i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v3i32_t v3i32_add(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
|
||||
fn_inline v3i32_t v3i32_adds(v3i32_t a, i32 b) { return (v3i32_t){ a.x + b, a.y + b, a.z + b }; }
|
||||
fn_inline v3i32_t v3i32_sub(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
|
||||
fn_inline v3i32_t v3i32_subs(v3i32_t a, i32 b) { return (v3i32_t){ a.x - b, a.y - b, a.z - b }; }
|
||||
fn_inline v3i32_t v3i32_mul(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
|
||||
fn_inline v3i32_t v3i32_muls(v3i32_t a, i32 b) { return (v3i32_t){ a.x * b, a.y * b, a.z * b }; }
|
||||
fn_inline v3i32_t v3i32_div(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
|
||||
fn_inline v3i32_t v3i32_divs(v3i32_t a, i32 b) { return (v3i32_t){ a.x / b, a.y / b, a.z / b }; }
|
||||
fn_inline v4i32_t v4i32(i32 x, i32 y, i32 z, i32 w) { return (v4i32_t){ x, y, z, w }; }
|
||||
gb_read_only v4i32_t v4i32_null = {0};
|
||||
fn_inline b32 v4i32_is_null(v4i32_t a) { return memory_equal(&a, &v4i32_null, sizeof(a)); }
|
||||
fn_inline b32 v4i32_are_equal(v4i32_t a, v4i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v4i32_t v4i32_add(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
|
||||
fn_inline v4i32_t v4i32_adds(v4i32_t a, i32 b) { return (v4i32_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
|
||||
fn_inline v4i32_t v4i32_sub(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
|
||||
fn_inline v4i32_t v4i32_subs(v4i32_t a, i32 b) { return (v4i32_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
|
||||
fn_inline v4i32_t v4i32_mul(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
|
||||
fn_inline v4i32_t v4i32_muls(v4i32_t a, i32 b) { return (v4i32_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
|
||||
fn_inline v4i32_t v4i32_div(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
|
||||
fn_inline v4i32_t v4i32_divs(v4i32_t a, i32 b) { return (v4i32_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
|
||||
fn_inline r2i32_t r2i32(i32 x0, i32 y0, i32 x1, i32 y1) { return (r2i32_t){ x0, y0, x1, y1 }; }
|
||||
gb_read_only r2i32_t r2i32_null = {0};
|
||||
fn_inline b32 r2i32_is_null(r2i32_t a) { return memory_equal(&a, &r2i32_null, sizeof(a)); }
|
||||
fn_inline b32 r2i32_are_equal(r2i32_t a, r2i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r2i32_t r2i32_add(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
|
||||
fn_inline r2i32_t r2i32_adds(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
|
||||
fn_inline r2i32_t r2i32_sub(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
|
||||
fn_inline r2i32_t r2i32_subs(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
|
||||
fn_inline r2i32_t r2i32_mul(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
|
||||
fn_inline r2i32_t r2i32_muls(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
|
||||
fn_inline r2i32_t r2i32_div(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
|
||||
fn_inline r2i32_t r2i32_divs(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
|
||||
fn_inline r3i32_t r3i32(i32 x0, i32 y0, i32 z0, i32 x1, i32 y1, i32 z1) { return (r3i32_t){ x0, y0, z0, x1, y1, z1 }; }
|
||||
gb_read_only r3i32_t r3i32_null = {0};
|
||||
fn_inline b32 r3i32_is_null(r3i32_t a) { return memory_equal(&a, &r3i32_null, sizeof(a)); }
|
||||
fn_inline b32 r3i32_are_equal(r3i32_t a, r3i32_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r3i32_t r3i32_add(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
|
||||
fn_inline r3i32_t r3i32_adds(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
|
||||
fn_inline r3i32_t r3i32_sub(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
|
||||
fn_inline r3i32_t r3i32_subs(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
|
||||
fn_inline r3i32_t r3i32_mul(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
|
||||
fn_inline r3i32_t r3i32_muls(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
|
||||
fn_inline r3i32_t r3i32_div(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
|
||||
fn_inline r3i32_t r3i32_divs(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
|
||||
fn_inline v2i64_t v2i64(i64 x, i64 y) { return (v2i64_t){ x, y }; }
|
||||
gb_read_only v2i64_t v2i64_null = {0};
|
||||
fn_inline b32 v2i64_is_null(v2i64_t a) { return memory_equal(&a, &v2i64_null, sizeof(a)); }
|
||||
fn_inline b32 v2i64_are_equal(v2i64_t a, v2i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v2i64_t v2i64_add(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x + b.x, a.y + b.y }; }
|
||||
fn_inline v2i64_t v2i64_adds(v2i64_t a, i64 b) { return (v2i64_t){ a.x + b, a.y + b }; }
|
||||
fn_inline v2i64_t v2i64_sub(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x - b.x, a.y - b.y }; }
|
||||
fn_inline v2i64_t v2i64_subs(v2i64_t a, i64 b) { return (v2i64_t){ a.x - b, a.y - b }; }
|
||||
fn_inline v2i64_t v2i64_mul(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x * b.x, a.y * b.y }; }
|
||||
fn_inline v2i64_t v2i64_muls(v2i64_t a, i64 b) { return (v2i64_t){ a.x * b, a.y * b }; }
|
||||
fn_inline v2i64_t v2i64_div(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x / b.x, a.y / b.y }; }
|
||||
fn_inline v2i64_t v2i64_divs(v2i64_t a, i64 b) { return (v2i64_t){ a.x / b, a.y / b }; }
|
||||
fn_inline v3i64_t v3i64(i64 x, i64 y, i64 z) { return (v3i64_t){ x, y, z }; }
|
||||
gb_read_only v3i64_t v3i64_null = {0};
|
||||
fn_inline b32 v3i64_is_null(v3i64_t a) { return memory_equal(&a, &v3i64_null, sizeof(a)); }
|
||||
fn_inline b32 v3i64_are_equal(v3i64_t a, v3i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v3i64_t v3i64_add(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
|
||||
fn_inline v3i64_t v3i64_adds(v3i64_t a, i64 b) { return (v3i64_t){ a.x + b, a.y + b, a.z + b }; }
|
||||
fn_inline v3i64_t v3i64_sub(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
|
||||
fn_inline v3i64_t v3i64_subs(v3i64_t a, i64 b) { return (v3i64_t){ a.x - b, a.y - b, a.z - b }; }
|
||||
fn_inline v3i64_t v3i64_mul(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
|
||||
fn_inline v3i64_t v3i64_muls(v3i64_t a, i64 b) { return (v3i64_t){ a.x * b, a.y * b, a.z * b }; }
|
||||
fn_inline v3i64_t v3i64_div(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
|
||||
fn_inline v3i64_t v3i64_divs(v3i64_t a, i64 b) { return (v3i64_t){ a.x / b, a.y / b, a.z / b }; }
|
||||
fn_inline v4i64_t v4i64(i64 x, i64 y, i64 z, i64 w) { return (v4i64_t){ x, y, z, w }; }
|
||||
gb_read_only v4i64_t v4i64_null = {0};
|
||||
fn_inline b32 v4i64_is_null(v4i64_t a) { return memory_equal(&a, &v4i64_null, sizeof(a)); }
|
||||
fn_inline b32 v4i64_are_equal(v4i64_t a, v4i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline v4i64_t v4i64_add(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
|
||||
fn_inline v4i64_t v4i64_adds(v4i64_t a, i64 b) { return (v4i64_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
|
||||
fn_inline v4i64_t v4i64_sub(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
|
||||
fn_inline v4i64_t v4i64_subs(v4i64_t a, i64 b) { return (v4i64_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
|
||||
fn_inline v4i64_t v4i64_mul(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
|
||||
fn_inline v4i64_t v4i64_muls(v4i64_t a, i64 b) { return (v4i64_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
|
||||
fn_inline v4i64_t v4i64_div(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
|
||||
fn_inline v4i64_t v4i64_divs(v4i64_t a, i64 b) { return (v4i64_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
|
||||
fn_inline r2i64_t r2i64(i64 x0, i64 y0, i64 x1, i64 y1) { return (r2i64_t){ x0, y0, x1, y1 }; }
|
||||
gb_read_only r2i64_t r2i64_null = {0};
|
||||
fn_inline b32 r2i64_is_null(r2i64_t a) { return memory_equal(&a, &r2i64_null, sizeof(a)); }
|
||||
fn_inline b32 r2i64_are_equal(r2i64_t a, r2i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r2i64_t r2i64_add(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
|
||||
fn_inline r2i64_t r2i64_adds(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
|
||||
fn_inline r2i64_t r2i64_sub(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
|
||||
fn_inline r2i64_t r2i64_subs(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
|
||||
fn_inline r2i64_t r2i64_mul(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
|
||||
fn_inline r2i64_t r2i64_muls(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
|
||||
fn_inline r2i64_t r2i64_div(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
|
||||
fn_inline r2i64_t r2i64_divs(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
|
||||
fn_inline r3i64_t r3i64(i64 x0, i64 y0, i64 z0, i64 x1, i64 y1, i64 z1) { return (r3i64_t){ x0, y0, z0, x1, y1, z1 }; }
|
||||
gb_read_only r3i64_t r3i64_null = {0};
|
||||
fn_inline b32 r3i64_is_null(r3i64_t a) { return memory_equal(&a, &r3i64_null, sizeof(a)); }
|
||||
fn_inline b32 r3i64_are_equal(r3i64_t a, r3i64_t b) { return memory_equal(&a, &b, sizeof(a)); }
|
||||
fn_inline r3i64_t r3i64_add(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
|
||||
fn_inline r3i64_t r3i64_adds(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
|
||||
fn_inline r3i64_t r3i64_sub(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
|
||||
fn_inline r3i64_t r3i64_subs(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
|
||||
fn_inline r3i64_t r3i64_mul(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
|
||||
fn_inline r3i64_t r3i64_muls(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
|
||||
fn_inline r3i64_t r3i64_div(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
|
||||
fn_inline r3i64_t r3i64_divs(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
|
||||
fn_inline r2f32_t r2f32_min_dim(v2f32_t pos, v2f32_t size) { return (r2f32_t){ pos, v2f32_add(pos, size) }; }
|
||||
fn_inline r2f32_t r2f32_center_half_dim(v2f32_t center, v2f32_t halfdim) { return (r2f32_t){ v2f32_sub(center, halfdim), v2f32_add(center, halfdim) }; }
|
||||
fn_inline r3f32_t r3f32_min_dim(v3f32_t pos, v3f32_t size) { return (r3f32_t){ pos, v3f32_add(pos, size) }; }
|
||||
fn_inline r3f32_t r3f32_center_half_dim(v3f32_t center, v3f32_t halfdim) { return (r3f32_t){ v3f32_sub(center, halfdim), v3f32_add(center, halfdim) }; }
|
||||
fn_inline r2f64_t r2f64_min_dim(v2f64_t pos, v2f64_t size) { return (r2f64_t){ pos, v2f64_add(pos, size) }; }
|
||||
fn_inline r2f64_t r2f64_center_half_dim(v2f64_t center, v2f64_t halfdim) { return (r2f64_t){ v2f64_sub(center, halfdim), v2f64_add(center, halfdim) }; }
|
||||
fn_inline r3f64_t r3f64_min_dim(v3f64_t pos, v3f64_t size) { return (r3f64_t){ pos, v3f64_add(pos, size) }; }
|
||||
fn_inline r3f64_t r3f64_center_half_dim(v3f64_t center, v3f64_t halfdim) { return (r3f64_t){ v3f64_sub(center, halfdim), v3f64_add(center, halfdim) }; }
|
||||
fn_inline r2i32_t r2i32_min_dim(v2i32_t pos, v2i32_t size) { return (r2i32_t){ pos, v2i32_add(pos, size) }; }
|
||||
fn_inline r2i32_t r2i32_center_half_dim(v2i32_t center, v2i32_t halfdim) { return (r2i32_t){ v2i32_sub(center, halfdim), v2i32_add(center, halfdim) }; }
|
||||
fn_inline r3i32_t r3i32_min_dim(v3i32_t pos, v3i32_t size) { return (r3i32_t){ pos, v3i32_add(pos, size) }; }
|
||||
fn_inline r3i32_t r3i32_center_half_dim(v3i32_t center, v3i32_t halfdim) { return (r3i32_t){ v3i32_sub(center, halfdim), v3i32_add(center, halfdim) }; }
|
||||
fn_inline r2i64_t r2i64_min_dim(v2i64_t pos, v2i64_t size) { return (r2i64_t){ pos, v2i64_add(pos, size) }; }
|
||||
fn_inline r2i64_t r2i64_center_half_dim(v2i64_t center, v2i64_t halfdim) { return (r2i64_t){ v2i64_sub(center, halfdim), v2i64_add(center, halfdim) }; }
|
||||
fn_inline r3i64_t r3i64_min_dim(v3i64_t pos, v3i64_t size) { return (r3i64_t){ pos, v3i64_add(pos, size) }; }
|
||||
fn_inline r3i64_t r3i64_center_half_dim(v3i64_t center, v3i64_t halfdim) { return (r3i64_t){ v3i64_sub(center, halfdim), v3i64_add(center, halfdim) }; }
|
||||
fn r2f32_t r2f32_cut_left(r2f32_t *r, f32 value) {
|
||||
f32 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2f32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_right(r2f32_t *r, f32 value) {
|
||||
f32 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2f32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_top(r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2f32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_bottom(r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2f32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_cut_left_no_squash(r2f32_t *r, f32 value) {
|
||||
f32 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2f32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_right_no_squash(r2f32_t *r, f32 value) {
|
||||
f32 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2f32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_top_no_squash(r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2f32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_cut_bottom_no_squash(r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2f32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_add_left(r2f32_t *r, f32 value) {
|
||||
r2f32_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_add_right(r2f32_t *r, f32 value) {
|
||||
r2f32_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_add_top(r2f32_t *r, f32 value) {
|
||||
r2f32_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_add_bottom(r2f32_t *r, f32 value) {
|
||||
r2f32_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2f32_t r2f32_getp_left(const r2f32_t *rect, f32 value) {
|
||||
r2f32_t result = r2f32(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_getp_right(const r2f32_t *rect, f32 value) {
|
||||
r2f32_t result = r2f32(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_getp_bottom(const r2f32_t *rect, f32 value) {
|
||||
r2f32_t result = r2f32(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_getp_top(const r2f32_t *rect, f32 value) {
|
||||
r2f32_t result = r2f32(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_get_left(const r2f32_t *r, f32 value) {
|
||||
f32 minx = r->min.x;
|
||||
r2f32_t result = (r2f32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_get_right(const r2f32_t *r, f32 value) {
|
||||
f32 maxx = r->max.x;
|
||||
r2f32_t result = (r2f32_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_get_top(const r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 miny = r->min.y;
|
||||
r2f32_t result = (r2f32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2f32_t r2f32_get_bottom(const r2f32_t *r, f32 value) { /* Y is down */
|
||||
f32 maxy = r->max.y;
|
||||
r2f32_t result = (r2f32_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2f32_t r2f32_expand(r2f32_t rect, v2f32_t value) { return (r2f32_t){ v2f32_sub(rect.min, value), v2f32_add(rect.max, value) }; }
|
||||
fn_inline r2f32_t r2f32_shrink(r2f32_t rect, v2f32_t value) { return (r2f32_t){ v2f32_add(rect.min, value), v2f32_sub(rect.max, value) }; }
|
||||
fn_inline r2f32_t r2f32_shrinks(r2f32_t rect, f32 value) { return (r2f32_t){ v2f32_adds(rect.min, value), v2f32_subs(rect.max, value) }; }
|
||||
fn_inline v2f32_t r2f32_size(r2f32_t r) { return (v2f32_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2f32_t r2f32_get_mid(r2f32_t r) { return v2f32_add(r.min, v2f32_divs(r2f32_size(r), 2)); }
|
||||
fn_inline b32 r2f32_contains(r2f32_t rec, v2f32_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2f32_t r2f32_intersect(r2f32_t a, r2f32_t b) { return (r2f32_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2f32_t r2f32_union(r2f32_t a, r2f32_t b) { return (r2f32_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline f32 r1f32_size(r1f32_t a) { return a.max - a.min; }
|
||||
fn_inline r1f32_t r1f32(f32 min, f32 max) { return (r1f32_t){min,max}; }
|
||||
fn_inline r1f32_t r1f32_auto(f32 a, f32 b) { return (r1f32_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1f32_t r1f32s(f32 a) { return (r1f32_t){a,a}; }
|
||||
fn_inline r1f32_t r1f32_clamp(r1f32_t a, f32 min, f32 max) { return (r1f32_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1f32_contains(r1f32_t rec, f32 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1f32_are_equal(r1f32_t a, r1f32_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1f32_t r1f32_null;
|
||||
|
||||
fn b32 r1f32_overlap(r1f32_t a, r1f32_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2f32_t v2f32_clamps(v2f32_t v, f32 min, f32 max) {
|
||||
v2f32_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2f32_t v2f32_clamp(v2f32_t v, v2f32_t min, v2f32_t max) {
|
||||
v2f32_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f32_t r2f32_fix(r2f32_t n) {
|
||||
r2f32_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_left(r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_right(r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_top(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_bottom(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_cut_left_no_squash(r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_right_no_squash(r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_top_no_squash(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_bottom_no_squash(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_add_left(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_right(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_top(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_bottom(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2f64_t r2f64_getp_left(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_right(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_bottom(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_top(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_get_left(const r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_right(const r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_top(const r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_bottom(const r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2f64_t r2f64_expand(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_sub(rect.min, value), v2f64_add(rect.max, value) }; }
|
||||
fn_inline r2f64_t r2f64_shrink(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_add(rect.min, value), v2f64_sub(rect.max, value) }; }
|
||||
fn_inline r2f64_t r2f64_shrinks(r2f64_t rect, f64 value) { return (r2f64_t){ v2f64_adds(rect.min, value), v2f64_subs(rect.max, value) }; }
|
||||
fn_inline v2f64_t r2f64_size(r2f64_t r) { return (v2f64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2f64_t r2f64_get_mid(r2f64_t r) { return v2f64_add(r.min, v2f64_divs(r2f64_size(r), 2)); }
|
||||
fn_inline b32 r2f64_contains(r2f64_t rec, v2f64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2f64_t r2f64_intersect(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2f64_t r2f64_union(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline f64 r1f64_size(r1f64_t a) { return a.max - a.min; }
|
||||
fn_inline r1f64_t r1f64(f64 min, f64 max) { return (r1f64_t){min,max}; }
|
||||
fn_inline r1f64_t r1f64_auto(f64 a, f64 b) { return (r1f64_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1f64_t r1f64s(f64 a) { return (r1f64_t){a,a}; }
|
||||
fn_inline r1f64_t r1f64_clamp(r1f64_t a, f64 min, f64 max) { return (r1f64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1f64_contains(r1f64_t rec, f64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1f64_are_equal(r1f64_t a, r1f64_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1f64_t r1f64_null;
|
||||
|
||||
fn b32 r1f64_overlap(r1f64_t a, r1f64_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2f64_t v2f64_clamps(v2f64_t v, f64 min, f64 max) {
|
||||
v2f64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2f64_t v2f64_clamp(v2f64_t v, v2f64_t min, v2f64_t max) {
|
||||
v2f64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_fix(r2f64_t n) {
|
||||
r2f64_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_left(r2i32_t *r, i32 value) {
|
||||
i32 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2i32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_right(r2i32_t *r, i32 value) {
|
||||
i32 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2i32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_top(r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2i32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_bottom(r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2i32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i32_t r2i32_cut_left_no_squash(r2i32_t *r, i32 value) {
|
||||
i32 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2i32_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_right_no_squash(r2i32_t *r, i32 value) {
|
||||
i32 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2i32_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_top_no_squash(r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2i32_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_cut_bottom_no_squash(r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2i32_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i32_t r2i32_add_left(r2i32_t *r, i32 value) {
|
||||
r2i32_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_add_right(r2i32_t *r, i32 value) {
|
||||
r2i32_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_add_top(r2i32_t *r, i32 value) {
|
||||
r2i32_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_add_bottom(r2i32_t *r, i32 value) {
|
||||
r2i32_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2i32_t r2i32_getp_left(const r2i32_t *rect, i32 value) {
|
||||
r2i32_t result = r2i32(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_getp_right(const r2i32_t *rect, i32 value) {
|
||||
r2i32_t result = r2i32(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_getp_bottom(const r2i32_t *rect, i32 value) {
|
||||
r2i32_t result = r2i32(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_getp_top(const r2i32_t *rect, i32 value) {
|
||||
r2i32_t result = r2i32(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i32_t r2i32_get_left(const r2i32_t *r, i32 value) {
|
||||
i32 minx = r->min.x;
|
||||
r2i32_t result = (r2i32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_get_right(const r2i32_t *r, i32 value) {
|
||||
i32 maxx = r->max.x;
|
||||
r2i32_t result = (r2i32_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_get_top(const r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 miny = r->min.y;
|
||||
r2i32_t result = (r2i32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2i32_t r2i32_get_bottom(const r2i32_t *r, i32 value) { /* Y is down */
|
||||
i32 maxy = r->max.y;
|
||||
r2i32_t result = (r2i32_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2i32_t r2i32_expand(r2i32_t rect, v2i32_t value) { return (r2i32_t){ v2i32_sub(rect.min, value), v2i32_add(rect.max, value) }; }
|
||||
fn_inline r2i32_t r2i32_shrink(r2i32_t rect, v2i32_t value) { return (r2i32_t){ v2i32_add(rect.min, value), v2i32_sub(rect.max, value) }; }
|
||||
fn_inline r2i32_t r2i32_shrinks(r2i32_t rect, i32 value) { return (r2i32_t){ v2i32_adds(rect.min, value), v2i32_subs(rect.max, value) }; }
|
||||
fn_inline v2i32_t r2i32_size(r2i32_t r) { return (v2i32_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2i32_t r2i32_get_mid(r2i32_t r) { return v2i32_add(r.min, v2i32_divs(r2i32_size(r), 2)); }
|
||||
fn_inline b32 r2i32_contains(r2i32_t rec, v2i32_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2i32_t r2i32_intersect(r2i32_t a, r2i32_t b) { return (r2i32_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2i32_t r2i32_union(r2i32_t a, r2i32_t b) { return (r2i32_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline i32 r1i32_size(r1i32_t a) { return a.max - a.min; }
|
||||
fn_inline r1i32_t r1i32(i32 min, i32 max) { return (r1i32_t){min,max}; }
|
||||
fn_inline r1i32_t r1i32_auto(i32 a, i32 b) { return (r1i32_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1i32_t r1i32s(i32 a) { return (r1i32_t){a,a}; }
|
||||
fn_inline r1i32_t r1i32_clamp(r1i32_t a, i32 min, i32 max) { return (r1i32_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1i32_contains(r1i32_t rec, i32 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1i32_are_equal(r1i32_t a, r1i32_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1i32_t r1i32_null;
|
||||
|
||||
fn b32 r1i32_overlap(r1i32_t a, r1i32_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2i32_t v2i32_clamps(v2i32_t v, i32 min, i32 max) {
|
||||
v2i32_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2i32_t v2i32_clamp(v2i32_t v, v2i32_t min, v2i32_t max) {
|
||||
v2i32_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i32_t r2i32_fix(r2i32_t n) {
|
||||
r2i32_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_left(r2i64_t *r, i64 value) {
|
||||
i64 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2i64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_right(r2i64_t *r, i64 value) {
|
||||
i64 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2i64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_top(r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2i64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_bottom(r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2i64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i64_t r2i64_cut_left_no_squash(r2i64_t *r, i64 value) {
|
||||
i64 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2i64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_right_no_squash(r2i64_t *r, i64 value) {
|
||||
i64 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2i64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_top_no_squash(r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2i64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_cut_bottom_no_squash(r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2i64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i64_t r2i64_add_left(r2i64_t *r, i64 value) {
|
||||
r2i64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_add_right(r2i64_t *r, i64 value) {
|
||||
r2i64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_add_top(r2i64_t *r, i64 value) {
|
||||
r2i64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_add_bottom(r2i64_t *r, i64 value) {
|
||||
r2i64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2i64_t r2i64_getp_left(const r2i64_t *rect, i64 value) {
|
||||
r2i64_t result = r2i64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_getp_right(const r2i64_t *rect, i64 value) {
|
||||
r2i64_t result = r2i64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_getp_bottom(const r2i64_t *rect, i64 value) {
|
||||
r2i64_t result = r2i64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_getp_top(const r2i64_t *rect, i64 value) {
|
||||
r2i64_t result = r2i64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i64_t r2i64_get_left(const r2i64_t *r, i64 value) {
|
||||
i64 minx = r->min.x;
|
||||
r2i64_t result = (r2i64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_get_right(const r2i64_t *r, i64 value) {
|
||||
i64 maxx = r->max.x;
|
||||
r2i64_t result = (r2i64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_get_top(const r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 miny = r->min.y;
|
||||
r2i64_t result = (r2i64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2i64_t r2i64_get_bottom(const r2i64_t *r, i64 value) { /* Y is down */
|
||||
i64 maxy = r->max.y;
|
||||
r2i64_t result = (r2i64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2i64_t r2i64_expand(r2i64_t rect, v2i64_t value) { return (r2i64_t){ v2i64_sub(rect.min, value), v2i64_add(rect.max, value) }; }
|
||||
fn_inline r2i64_t r2i64_shrink(r2i64_t rect, v2i64_t value) { return (r2i64_t){ v2i64_add(rect.min, value), v2i64_sub(rect.max, value) }; }
|
||||
fn_inline r2i64_t r2i64_shrinks(r2i64_t rect, i64 value) { return (r2i64_t){ v2i64_adds(rect.min, value), v2i64_subs(rect.max, value) }; }
|
||||
fn_inline v2i64_t r2i64_size(r2i64_t r) { return (v2i64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2i64_t r2i64_get_mid(r2i64_t r) { return v2i64_add(r.min, v2i64_divs(r2i64_size(r), 2)); }
|
||||
fn_inline b32 r2i64_contains(r2i64_t rec, v2i64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2i64_t r2i64_intersect(r2i64_t a, r2i64_t b) { return (r2i64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2i64_t r2i64_union(r2i64_t a, r2i64_t b) { return (r2i64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline i64 r1i64_size(r1i64_t a) { return a.max - a.min; }
|
||||
fn_inline r1i64_t r1i64(i64 min, i64 max) { return (r1i64_t){min,max}; }
|
||||
fn_inline r1i64_t r1i64_auto(i64 a, i64 b) { return (r1i64_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1i64_t r1i64s(i64 a) { return (r1i64_t){a,a}; }
|
||||
fn_inline r1i64_t r1i64_clamp(r1i64_t a, i64 min, i64 max) { return (r1i64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1i64_contains(r1i64_t rec, i64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1i64_are_equal(r1i64_t a, r1i64_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1i64_t r1i64_null;
|
||||
|
||||
fn b32 r1i64_overlap(r1i64_t a, r1i64_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2i64_t v2i64_clamps(v2i64_t v, i64 min, i64 max) {
|
||||
v2i64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2i64_t v2i64_clamp(v2i64_t v, v2i64_t min, v2i64_t max) {
|
||||
v2i64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2i64_t r2i64_fix(r2i64_t n) {
|
||||
r2i64_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
fn_inline v2f64_t v2f32_to_v2f64(v2f32_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
|
||||
fn_inline v3f64_t v3f32_to_v3f64(v3f32_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
|
||||
fn_inline v4f64_t v4f32_to_v4f64(v4f32_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
|
||||
fn_inline r2f64_t r2f32_to_r2f64(r2f32_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
|
||||
fn_inline r3f64_t r3f32_to_r3f64(r3f32_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
|
||||
fn_inline v2i32_t v2f32_to_v2i32(v2f32_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
|
||||
fn_inline v3i32_t v3f32_to_v3i32(v3f32_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
|
||||
fn_inline v4i32_t v4f32_to_v4i32(v4f32_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
|
||||
fn_inline r2i32_t r2f32_to_r2i32(r2f32_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
|
||||
fn_inline r3i32_t r3f32_to_r3i32(r3f32_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
|
||||
fn_inline v2i64_t v2f32_to_v2i64(v2f32_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
|
||||
fn_inline v3i64_t v3f32_to_v3i64(v3f32_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
|
||||
fn_inline v4i64_t v4f32_to_v4i64(v4f32_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
|
||||
fn_inline r2i64_t r2f32_to_r2i64(r2f32_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
|
||||
fn_inline r3i64_t r3f32_to_r3i64(r3f32_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
|
||||
fn_inline v2f32_t v2f64_to_v2f32(v2f64_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
|
||||
fn_inline v3f32_t v3f64_to_v3f32(v3f64_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
|
||||
fn_inline v4f32_t v4f64_to_v4f32(v4f64_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
|
||||
fn_inline r2f32_t r2f64_to_r2f32(r2f64_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
|
||||
fn_inline r3f32_t r3f64_to_r3f32(r3f64_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
|
||||
fn_inline v2i32_t v2f64_to_v2i32(v2f64_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
|
||||
fn_inline v3i32_t v3f64_to_v3i32(v3f64_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
|
||||
fn_inline v4i32_t v4f64_to_v4i32(v4f64_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
|
||||
fn_inline r2i32_t r2f64_to_r2i32(r2f64_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
|
||||
fn_inline r3i32_t r3f64_to_r3i32(r3f64_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
|
||||
fn_inline v2i64_t v2f64_to_v2i64(v2f64_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
|
||||
fn_inline v3i64_t v3f64_to_v3i64(v3f64_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
|
||||
fn_inline v4i64_t v4f64_to_v4i64(v4f64_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
|
||||
fn_inline r2i64_t r2f64_to_r2i64(r2f64_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
|
||||
fn_inline r3i64_t r3f64_to_r3i64(r3f64_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
|
||||
fn_inline v2f32_t v2i32_to_v2f32(v2i32_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
|
||||
fn_inline v3f32_t v3i32_to_v3f32(v3i32_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
|
||||
fn_inline v4f32_t v4i32_to_v4f32(v4i32_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
|
||||
fn_inline r2f32_t r2i32_to_r2f32(r2i32_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
|
||||
fn_inline r3f32_t r3i32_to_r3f32(r3i32_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
|
||||
fn_inline v2f64_t v2i32_to_v2f64(v2i32_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
|
||||
fn_inline v3f64_t v3i32_to_v3f64(v3i32_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
|
||||
fn_inline v4f64_t v4i32_to_v4f64(v4i32_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
|
||||
fn_inline r2f64_t r2i32_to_r2f64(r2i32_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
|
||||
fn_inline r3f64_t r3i32_to_r3f64(r3i32_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
|
||||
fn_inline v2i64_t v2i32_to_v2i64(v2i32_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
|
||||
fn_inline v3i64_t v3i32_to_v3i64(v3i32_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
|
||||
fn_inline v4i64_t v4i32_to_v4i64(v4i32_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
|
||||
fn_inline r2i64_t r2i32_to_r2i64(r2i32_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
|
||||
fn_inline r3i64_t r3i32_to_r3i64(r3i32_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
|
||||
fn_inline v2f32_t v2i64_to_v2f32(v2i64_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
|
||||
fn_inline v3f32_t v3i64_to_v3f32(v3i64_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
|
||||
fn_inline v4f32_t v4i64_to_v4f32(v4i64_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
|
||||
fn_inline r2f32_t r2i64_to_r2f32(r2i64_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
|
||||
fn_inline r3f32_t r3i64_to_r3f32(r3i64_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
|
||||
fn_inline v2f64_t v2i64_to_v2f64(v2i64_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
|
||||
fn_inline v3f64_t v3i64_to_v3f64(v3i64_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
|
||||
fn_inline v4f64_t v4i64_to_v4f64(v4i64_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
|
||||
fn_inline r2f64_t r2i64_to_r2f64(r2i64_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
|
||||
fn_inline r3f64_t r3i64_to_r3f64(r3i64_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
|
||||
fn_inline v2i32_t v2i64_to_v2i32(v2i64_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
|
||||
fn_inline v3i32_t v3i64_to_v3i32(v3i64_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
|
||||
fn_inline v4i32_t v4i64_to_v4i32(v4i64_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
|
||||
fn_inline r2i32_t r2i64_to_r2i32(r2i64_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
|
||||
fn_inline r3i32_t r3i64_to_r3i32(r3i64_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
|
||||
fn_inline r2f32_t r2f32_add_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_add(a.min, b), v2f32_add(a.max, b) }; }
|
||||
fn_inline r2f32_t r2f32_sub_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_sub(a.min, b), v2f32_sub(a.max, b) }; }
|
||||
fn_inline r2f32_t r2f32_mul_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_mul(a.min, b), v2f32_mul(a.max, b) }; }
|
||||
fn_inline r2f32_t r2f32_div_v2f32(r2f32_t a, v2f32_t b) { return (r2f32_t){ v2f32_div(a.min, b), v2f32_div(a.max, b) }; }
|
||||
fn_inline r2f64_t r2f64_add_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_add(a.min, b), v2f64_add(a.max, b) }; }
|
||||
fn_inline r2f64_t r2f64_sub_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_sub(a.min, b), v2f64_sub(a.max, b) }; }
|
||||
fn_inline r2f64_t r2f64_mul_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_mul(a.min, b), v2f64_mul(a.max, b) }; }
|
||||
fn_inline r2f64_t r2f64_div_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_div(a.min, b), v2f64_div(a.max, b) }; }
|
||||
fn_inline r2i32_t r2i32_add_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_add(a.min, b), v2i32_add(a.max, b) }; }
|
||||
fn_inline r2i32_t r2i32_sub_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_sub(a.min, b), v2i32_sub(a.max, b) }; }
|
||||
fn_inline r2i32_t r2i32_mul_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_mul(a.min, b), v2i32_mul(a.max, b) }; }
|
||||
fn_inline r2i32_t r2i32_div_v2i32(r2i32_t a, v2i32_t b) { return (r2i32_t){ v2i32_div(a.min, b), v2i32_div(a.max, b) }; }
|
||||
fn_inline r2i64_t r2i64_add_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_add(a.min, b), v2i64_add(a.max, b) }; }
|
||||
fn_inline r2i64_t r2i64_sub_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_sub(a.min, b), v2i64_sub(a.max, b) }; }
|
||||
fn_inline r2i64_t r2i64_mul_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_mul(a.min, b), v2i64_mul(a.max, b) }; }
|
||||
fn_inline r2i64_t r2i64_div_v2i64(r2i64_t a, v2i64_t b) { return (r2i64_t){ v2i64_div(a.min, b), v2i64_div(a.max, b) }; }
|
||||
fn f32 f32_safe_ratio(f32 a, f32 b, f32 if0) {
|
||||
f32 result = if0;
|
||||
if (b != 0.0) {
|
||||
result = a / b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn_inline f32 f32_safe_ratio0(f32 a, f32 b) { return f32_safe_ratio(a, b, 0); }
|
||||
fn_inline f32 f32_safe_ratio1(f32 a, f32 b) { return f32_safe_ratio(a, b, 0); }
|
||||
fn f64 f64_safe_ratio(f64 a, f64 b, f64 if0) {
|
||||
f64 result = if0;
|
||||
if (b != 0.0) {
|
||||
result = a / b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn_inline f64 f64_safe_ratio0(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
|
||||
fn_inline f64 f64_safe_ratio1(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
|
||||
@@ -1,215 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
typedef union v2f32_t v2f32_t;
|
||||
union v2f32_t {
|
||||
struct { f32 x, y; };
|
||||
f32 e[2];
|
||||
};
|
||||
|
||||
typedef union v3f32_t v3f32_t;
|
||||
union v3f32_t {
|
||||
struct { f32 x, y, z; };
|
||||
struct { v2f32_t xy; };
|
||||
struct { f32 _x0; v2f32_t zw; };
|
||||
struct { f32 r, g, b; };
|
||||
struct { f32 h, s, l; };
|
||||
f32 e[3];
|
||||
};
|
||||
|
||||
typedef union v4f32_t v4f32_t;
|
||||
union v4f32_t {
|
||||
struct { f32 x, y, z, w; };
|
||||
struct { v2f32_t xy; v2f32_t zw; };
|
||||
struct { v3f32_t xyz; };
|
||||
struct { f32 _x0; f32 yzw; };
|
||||
struct { f32 r, g, b, a; };
|
||||
struct { f32 h, s, l, _a; };
|
||||
f32 e[4];
|
||||
};
|
||||
|
||||
typedef union r1f32_t r1f32_t;
|
||||
union r1f32_t {
|
||||
struct { f32 min, max; };
|
||||
struct { f32 x0, x1; };
|
||||
f32 e[2];
|
||||
};
|
||||
|
||||
typedef union r2f32_t r2f32_t;
|
||||
union r2f32_t {
|
||||
struct { v2f32_t min, max; };
|
||||
struct { f32 x0, y0, x1, y1; };
|
||||
v4f32_t e4;
|
||||
f32 e[4];
|
||||
};
|
||||
|
||||
typedef union r3f32_t r3f32_t;
|
||||
union r3f32_t {
|
||||
struct { v3f32_t min, max; };
|
||||
struct { f32 x0, y0, z0, x1, y1, z1; };
|
||||
f32 e[6];
|
||||
};
|
||||
|
||||
|
||||
typedef union v2f64_t v2f64_t;
|
||||
union v2f64_t {
|
||||
struct { f64 x, y; };
|
||||
f64 e[2];
|
||||
};
|
||||
|
||||
typedef union v3f64_t v3f64_t;
|
||||
union v3f64_t {
|
||||
struct { f64 x, y, z; };
|
||||
struct { v2f64_t xy; };
|
||||
struct { f64 _x0; v2f64_t zw; };
|
||||
struct { f64 r, g, b; };
|
||||
struct { f64 h, s, l; };
|
||||
f64 e[3];
|
||||
};
|
||||
|
||||
typedef union v4f64_t v4f64_t;
|
||||
union v4f64_t {
|
||||
struct { f64 x, y, z, w; };
|
||||
struct { v2f64_t xy; v2f64_t zw; };
|
||||
struct { v3f64_t xyz; };
|
||||
struct { f64 _x0; f64 yzw; };
|
||||
struct { f64 r, g, b, a; };
|
||||
struct { f64 h, s, l, _a; };
|
||||
f64 e[4];
|
||||
};
|
||||
|
||||
typedef union r1f64_t r1f64_t;
|
||||
union r1f64_t {
|
||||
struct { f64 min, max; };
|
||||
struct { f64 x0, x1; };
|
||||
f64 e[2];
|
||||
};
|
||||
|
||||
typedef union r2f64_t r2f64_t;
|
||||
union r2f64_t {
|
||||
struct { v2f64_t min, max; };
|
||||
struct { f64 x0, y0, x1, y1; };
|
||||
v4f64_t e4;
|
||||
f64 e[4];
|
||||
};
|
||||
|
||||
typedef union r3f64_t r3f64_t;
|
||||
union r3f64_t {
|
||||
struct { v3f64_t min, max; };
|
||||
struct { f64 x0, y0, z0, x1, y1, z1; };
|
||||
f64 e[6];
|
||||
};
|
||||
|
||||
|
||||
typedef union v2i32_t v2i32_t;
|
||||
union v2i32_t {
|
||||
struct { i32 x, y; };
|
||||
i32 e[2];
|
||||
};
|
||||
|
||||
typedef union v3i32_t v3i32_t;
|
||||
union v3i32_t {
|
||||
struct { i32 x, y, z; };
|
||||
struct { v2i32_t xy; };
|
||||
struct { i32 _x0; v2i32_t zw; };
|
||||
struct { i32 r, g, b; };
|
||||
struct { i32 h, s, l; };
|
||||
i32 e[3];
|
||||
};
|
||||
|
||||
typedef union v4i32_t v4i32_t;
|
||||
union v4i32_t {
|
||||
struct { i32 x, y, z, w; };
|
||||
struct { v2i32_t xy; v2i32_t zw; };
|
||||
struct { v3i32_t xyz; };
|
||||
struct { i32 _x0; i32 yzw; };
|
||||
struct { i32 r, g, b, a; };
|
||||
struct { i32 h, s, l, _a; };
|
||||
i32 e[4];
|
||||
};
|
||||
|
||||
typedef union r1i32_t r1i32_t;
|
||||
union r1i32_t {
|
||||
struct { i32 min, max; };
|
||||
struct { i32 x0, x1; };
|
||||
i32 e[2];
|
||||
};
|
||||
|
||||
typedef union r2i32_t r2i32_t;
|
||||
union r2i32_t {
|
||||
struct { v2i32_t min, max; };
|
||||
struct { i32 x0, y0, x1, y1; };
|
||||
v4i32_t e4;
|
||||
i32 e[4];
|
||||
};
|
||||
|
||||
typedef union r3i32_t r3i32_t;
|
||||
union r3i32_t {
|
||||
struct { v3i32_t min, max; };
|
||||
struct { i32 x0, y0, z0, x1, y1, z1; };
|
||||
i32 e[6];
|
||||
};
|
||||
|
||||
|
||||
typedef union v2i64_t v2i64_t;
|
||||
union v2i64_t {
|
||||
struct { i64 x, y; };
|
||||
i64 e[2];
|
||||
};
|
||||
|
||||
typedef union v3i64_t v3i64_t;
|
||||
union v3i64_t {
|
||||
struct { i64 x, y, z; };
|
||||
struct { v2i64_t xy; };
|
||||
struct { i64 _x0; v2i64_t zw; };
|
||||
struct { i64 r, g, b; };
|
||||
struct { i64 h, s, l; };
|
||||
i64 e[3];
|
||||
};
|
||||
|
||||
typedef union v4i64_t v4i64_t;
|
||||
union v4i64_t {
|
||||
struct { i64 x, y, z, w; };
|
||||
struct { v2i64_t xy; v2i64_t zw; };
|
||||
struct { v3i64_t xyz; };
|
||||
struct { i64 _x0; i64 yzw; };
|
||||
struct { i64 r, g, b, a; };
|
||||
struct { i64 h, s, l, _a; };
|
||||
i64 e[4];
|
||||
};
|
||||
|
||||
typedef union r1i64_t r1i64_t;
|
||||
union r1i64_t {
|
||||
struct { i64 min, max; };
|
||||
struct { i64 x0, x1; };
|
||||
i64 e[2];
|
||||
};
|
||||
|
||||
typedef union r2i64_t r2i64_t;
|
||||
union r2i64_t {
|
||||
struct { v2i64_t min, max; };
|
||||
struct { i64 x0, y0, x1, y1; };
|
||||
v4i64_t e4;
|
||||
i64 e[4];
|
||||
};
|
||||
|
||||
typedef union r3i64_t r3i64_t;
|
||||
union r3i64_t {
|
||||
struct { v3i64_t min, max; };
|
||||
struct { i64 x0, y0, z0, x1, y1, z1; };
|
||||
i64 e[6];
|
||||
};
|
||||
|
||||
#define F64_PI (3.1415926535897932384626433832795028841971693994)
|
||||
#define F64_DEG2RAD (F64_PI / 180.0); // @Usage: degree * DEG2RAD = radians;
|
||||
#define F64_RAD2DEG (180.0 / F64_PI);
|
||||
#define F32_PI ((f32)F64_PI)
|
||||
|
||||
#define v4f32_const_rgba255(r, g, b, a) { (f32)(r) / 255.0f, (f32)(g) / 255.0f, (f32)(b) / 255.0f, (f32)(a) / 255.0f }
|
||||
#define v4f32_rgba255(r, g, b, a) (v4f32_t){ (f32)(r) / 255.0f, (f32)(g) / 255.0f, (f32)(b) / 255.0f, (f32)(a) / 255.0f }
|
||||
|
||||
static gb_read_only v4f32_t white_color = v4f32_const_rgba255(255, 255, 255, 255);
|
||||
static gb_read_only v4f32_t black_color = v4f32_const_rgba255(0, 0, 0, 255);
|
||||
static gb_read_only v4f32_t magenta_color = v4f32_const_rgba255(255, 0, 255, 255);
|
||||
static gb_read_only v4f32_t red_color = v4f32_const_rgba255(255, 0, 0, 255);
|
||||
static gb_read_only v4f32_t blue_color = v4f32_const_rgba255(0, 0, 255, 255);
|
||||
@@ -1,406 +0,0 @@
|
||||
import sys
|
||||
|
||||
op_idx = 0
|
||||
opname_idx = 1
|
||||
symbols = [
|
||||
["+", "add"],
|
||||
["-", "sub"],
|
||||
["*", "mul"],
|
||||
["/", "div"],
|
||||
]
|
||||
|
||||
basic_types = [
|
||||
"f32",
|
||||
"f64",
|
||||
"i32",
|
||||
"i64",
|
||||
]
|
||||
|
||||
name_idx = 0
|
||||
member_idx = 1
|
||||
|
||||
vec_types = [
|
||||
["v2", ["x", "y"]],
|
||||
["v3", ["x", "y", "z"]],
|
||||
["v4", ["x", "y", "z", "w"]],
|
||||
]
|
||||
|
||||
rect_types = [
|
||||
["r2", ["x0", "y0", "x1", "y1"]],
|
||||
["r3", ["x0", "y0", "z0", "x1", "y1", "z1"]],
|
||||
]
|
||||
|
||||
struct_types = vec_types + rect_types
|
||||
|
||||
|
||||
# fd = open("core_math.gen.h", "w")
|
||||
# sys.stdout = fd
|
||||
|
||||
# print("// auto generated using:", __file__)
|
||||
|
||||
# for bt in basic_types:
|
||||
# s = """
|
||||
# typedef union v2f64_t v2f64_t;
|
||||
# union v2f64_t {
|
||||
# struct { f64 x, y; };
|
||||
# f64 e[2];
|
||||
# };
|
||||
|
||||
# typedef union v3f64_t v3f64_t;
|
||||
# union v3f64_t {
|
||||
# struct { f64 x, y, z; };
|
||||
# struct { v2f64_t xy; };
|
||||
# struct { f64 _x0; v2f64_t zw; };
|
||||
# struct { f64 r, g, b; };
|
||||
# struct { f64 h, s, l; };
|
||||
# f64 e[3];
|
||||
# };
|
||||
|
||||
# typedef union v4f64_t v4f64_t;
|
||||
# union v4f64_t {
|
||||
# struct { f64 x, y, z, w; };
|
||||
# struct { v2f64_t xy; v2f64_t zw; };
|
||||
# struct { v3f64_t xyz; };
|
||||
# struct { f64 _x0; f64 yzw; };
|
||||
# struct { f64 r, g, b, a; };
|
||||
# struct { f64 h, s, l, _a; };
|
||||
# f64 e[4];
|
||||
# };
|
||||
|
||||
# typedef union r1f64_t r1f64_t;
|
||||
# union r1f64_t {
|
||||
# struct { f64 min, max; };
|
||||
# struct { f64 x0, x1; };
|
||||
# f64 e[2];
|
||||
# };
|
||||
|
||||
# typedef union r2f64_t r2f64_t;
|
||||
# union r2f64_t {
|
||||
# struct { v2f64_t min, max; };
|
||||
# struct { f64 x0, y0, x1, y1; };
|
||||
# v4f64_t e4;
|
||||
# f64 e[4];
|
||||
# };
|
||||
|
||||
# typedef union r3f64_t r3f64_t;
|
||||
# union r3f64_t {
|
||||
# struct { v3f64_t min, max; };
|
||||
# struct { f64 x0, y0, z0, x1, y1, z1; };
|
||||
# f64 e[6];
|
||||
# };
|
||||
#
|
||||
#
|
||||
# type_t type__v2f64_t = { type_kind_struct, s8_const("v2f64_t"), sizeof(v2f64_t), .count = 2,
|
||||
# .members = (type_member_t[]){
|
||||
# {s8_const("x"), &type__f64, .offset = offsetof(v2f64_t, x)},
|
||||
# {s8_const("y"), &type__f64, .offset = offsetof(v2f64_t, y)},
|
||||
# }
|
||||
# };
|
||||
|
||||
# type_t type__v3f64_t = { type_kind_struct, s8_const("v3f64_t"), sizeof(v3f64_t), .count = 3,
|
||||
# .members = (type_member_t[]){
|
||||
# {s8_const("x"), &type__f64, .offset = offsetof(v3f64_t, x)},
|
||||
# {s8_const("y"), &type__f64, .offset = offsetof(v3f64_t, y)},
|
||||
# {s8_const("z"), &type__f64, .offset = offsetof(v3f64_t, z)},
|
||||
# }
|
||||
# };
|
||||
|
||||
# type_t type__v4f64_t = { type_kind_struct, s8_const("v4f64_t"), sizeof(v4f64_t), .count = 4,
|
||||
# .members = (type_member_t[]){
|
||||
# {s8_const("x"), &type__f64, .offset = offsetof(v4f64_t, x)},
|
||||
# {s8_const("y"), &type__f64, .offset = offsetof(v4f64_t, y)},
|
||||
# {s8_const("z"), &type__f64, .offset = offsetof(v4f64_t, z)},
|
||||
# {s8_const("w"), &type__f64, .offset = offsetof(v4f64_t, w)},
|
||||
# }
|
||||
# };
|
||||
|
||||
# type_t type__r3f64_t = { type_kind_struct, s8_const("r3f64_t"), sizeof(r3f64_t), .count = 6,
|
||||
# .members = (type_member_t[]){
|
||||
# {s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, x0)},
|
||||
# {s8_const("y0"), &type__f64, .offset = offsetof(r3f64_t, y0)},
|
||||
# {s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, z0)},
|
||||
# {s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, x1)},
|
||||
# {s8_const("y1"), &type__f64, .offset = offsetof(r3f64_t, y1)},
|
||||
# {s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, z1)},
|
||||
# }
|
||||
# };
|
||||
|
||||
# type_member_t members__r2f64_t[] = {
|
||||
# {s8_const("x0"), &type__f64, .offset = offsetof(r2f64_t, x0)},
|
||||
# {s8_const("y0"), &type__f64, .offset = offsetof(r2f64_t, y0)},
|
||||
# {s8_const("x1"), &type__f64, .offset = offsetof(r2f64_t, x1)},
|
||||
# {s8_const("y1"), &type__f64, .offset = offsetof(r2f64_t, y1)},
|
||||
# };
|
||||
# DEFINE_STRUCT(r2f64_t);
|
||||
|
||||
# type_member_t members__r1f64_t[] = {
|
||||
# {s8_const("x0"), &type__f64, .offset = offsetof(r1f64_t, x0)},
|
||||
# {s8_const("x1"), &type__f64, .offset = offsetof(r1f64_t, x1)},
|
||||
# };
|
||||
# DEFINE_STRUCT(r1f64_t);
|
||||
# """
|
||||
# s = s.replace("f64", bt)
|
||||
# print(s)
|
||||
|
||||
|
||||
fd = open("core_math.gen.c", "w", newline = "\n", encoding = "utf-8")
|
||||
sys.stdout = fd
|
||||
|
||||
for basic_type in basic_types:
|
||||
for st in struct_types:
|
||||
type = f"{st[name_idx]}{basic_type}"
|
||||
typedef = f"{type}_t"
|
||||
members = st[member_idx]
|
||||
|
||||
def members_as_func_params(members, basic_type):
|
||||
result = ""
|
||||
for i, m in enumerate(members):
|
||||
result += f"{basic_type} {m}"
|
||||
if i != len(members) - 1:
|
||||
result += ", "
|
||||
return result
|
||||
|
||||
print(f"""fn_inline {type}_t {type}({members_as_func_params(members, basic_type)}) {{ return ({type}_t){{ {members_as_func_params(members, "")} }}; }}""")
|
||||
print(f"""gb_read_only {type}_t {type}_null = {{0}};""")
|
||||
print(f"""fn_inline b32 {type}_is_null({type}_t a) {{ return memory_equal(&a, &{type}_null, sizeof(a)); }}""")
|
||||
print(f"""fn_inline b32 {type}_are_equal({type}_t a, {type}_t b) {{ return memory_equal(&a, &b, sizeof(a)); }}""")
|
||||
|
||||
for sym in symbols:
|
||||
op = sym[op_idx]
|
||||
opname = sym[opname_idx]
|
||||
|
||||
|
||||
def op_str(members, op, skip_right = False):
|
||||
result = ""
|
||||
for i in range(len(members)):
|
||||
mem = members[i]
|
||||
if skip_right:
|
||||
result += f"a.{mem} {op} b"
|
||||
else:
|
||||
result += f"a.{mem} {op} b.{mem}"
|
||||
|
||||
if i != len(members) - 1:
|
||||
result += ", "
|
||||
return result
|
||||
|
||||
|
||||
print(f"fn_inline {type}_t {type}_{opname}({type}_t a, {type}_t b) {{ return ({type}_t){{ {op_str(members, op)} }}; }}")
|
||||
print(f"fn_inline {type}_t {type}_{opname}s({type}_t a, {basic_type} b) {{ return ({type}_t){{ {op_str(members, op, skip_right = True)} }}; }}")
|
||||
|
||||
for basic_type in basic_types:
|
||||
for i in range(len(rect_types)):
|
||||
vec_type = vec_types[i]
|
||||
rect_type = rect_types[i]
|
||||
|
||||
vec_name = vec_type[name_idx] + basic_type
|
||||
vec_members = vec_type[member_idx]
|
||||
rect_name = rect_type[name_idx] + basic_type
|
||||
rect_members = rect_type[member_idx]
|
||||
|
||||
print(f"fn_inline {rect_name}_t {rect_name}_min_dim({vec_name}_t pos, {vec_name}_t size) {{ return ({rect_name}_t){{ pos, {vec_name}_add(pos, size) }}; }}")
|
||||
print(f"fn_inline {rect_name}_t {rect_name}_center_half_dim({vec_name}_t center, {vec_name}_t halfdim) {{ return ({rect_name}_t){{ {vec_name}_sub(center, halfdim), {vec_name}_add(center, halfdim) }}; }}")
|
||||
|
||||
for basic_type in basic_types:
|
||||
s = """
|
||||
fn r2f64_t r2f64_cut_left(r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r->min.x = MIN(r->min.x + value, r->max.x);
|
||||
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_right(r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r->max.x = MAX(r->min.x, r->max.x - value);
|
||||
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_top(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r->min.y = MIN(r->max.y, r->min.y + value);
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_bottom(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r->max.y = MAX(r->min.y, r->max.y - value);
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_cut_left_no_squash(r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r->min.x = r->min.x + value;
|
||||
r2f64_t result = { .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_right_no_squash(r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r->max.x = r->max.x - value;
|
||||
r2f64_t result = { .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_top_no_squash(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r->min.y = r->min.y + value;
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_cut_bottom_no_squash(r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r->max.y = r->max.y - value;
|
||||
r2f64_t result = { .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_add_left(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x - value, r->min.y}, .max = {r->min.x, r->max.y} };
|
||||
r->min.x -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_right(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->max.x, r->min.y}, .max = {r->max.x + value, r->max.y} };
|
||||
r->max.x += value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_top(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x, r->min.y - value}, .max = {r->max.x, r->min.y} };
|
||||
r->min.y -= value;
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_add_bottom(r2f64_t *r, f64 value) {
|
||||
r2f64_t result = { .min = {r->min.x, r->max.y}, .max = {r->max.x, r->max.y + value} };
|
||||
r->max.y += value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// get past left
|
||||
fn r2f64_t r2f64_getp_left(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_right(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_bottom(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_getp_top(const r2f64_t *rect, f64 value) {
|
||||
r2f64_t result = r2f64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_get_left(const r2f64_t *r, f64 value) {
|
||||
f64 minx = r->min.x;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_right(const r2f64_t *r, f64 value) {
|
||||
f64 maxx = r->max.x;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_top(const r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 miny = r->min.y;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
|
||||
return result;
|
||||
}
|
||||
fn r2f64_t r2f64_get_bottom(const r2f64_t *r, f64 value) { /* Y is down */
|
||||
f64 maxy = r->max.y;
|
||||
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
fn_inline r2f64_t r2f64_expand(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_sub(rect.min, value), v2f64_add(rect.max, value) }; }
|
||||
fn_inline r2f64_t r2f64_shrink(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_add(rect.min, value), v2f64_sub(rect.max, value) }; }
|
||||
fn_inline r2f64_t r2f64_shrinks(r2f64_t rect, f64 value) { return (r2f64_t){ v2f64_adds(rect.min, value), v2f64_subs(rect.max, value) }; }
|
||||
fn_inline v2f64_t r2f64_size(r2f64_t r) { return (v2f64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
|
||||
fn_inline v2f64_t r2f64_get_mid(r2f64_t r) { return v2f64_add(r.min, v2f64_divs(r2f64_size(r), 2)); }
|
||||
fn_inline b32 r2f64_contains(r2f64_t rec, v2f64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
|
||||
fn_inline r2f64_t r2f64_intersect(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MAX(a.min.x, b.min.x), .min.y = MAX(a.min.y, b.min.y), .max.x = MIN(a.max.x, b.max.x), .max.y = MIN(a.max.y, b.max.y) }; }
|
||||
fn_inline r2f64_t r2f64_union(r2f64_t a, r2f64_t b) { return (r2f64_t){ .min.x = MIN(a.min.x, b.min.x), .min.y = MIN(a.min.y, b.min.y), .max.x = MAX(a.max.x, b.max.x), .max.y = MAX(a.max.y, b.max.y) }; }
|
||||
|
||||
fn_inline f64 r1f64_size(r1f64_t a) { return a.max - a.min; }
|
||||
fn_inline r1f64_t r1f64(f64 min, f64 max) { return (r1f64_t){min,max}; }
|
||||
fn_inline r1f64_t r1f64_auto(f64 a, f64 b) { return (r1f64_t){MIN(a,b),MAX(a,b)}; }
|
||||
fn_inline r1f64_t r1f64s(f64 a) { return (r1f64_t){a,a}; }
|
||||
fn_inline r1f64_t r1f64_clamp(r1f64_t a, f64 min, f64 max) { return (r1f64_t){ .min = CLAMP(a.min, min, max), .max = CLAMP(a.max, min, max) }; }
|
||||
fn_inline b32 r1f64_contains(r1f64_t rec, f64 point) { return (point >= rec.min) && (point < rec.max) && (point >= rec.min) && (point < rec.max); }
|
||||
fn_inline b32 r1f64_are_equal(r1f64_t a, r1f64_t b) { return a.min == b.min && a.max == b.max; }
|
||||
gb_read_only r1f64_t r1f64_null;
|
||||
|
||||
fn b32 r1f64_overlap(r1f64_t a, r1f64_t b) {
|
||||
b32 r1 = (a.max >= b.min && a.max <= b.max) || (a.min >= b.min && a.min <= b.max);
|
||||
b32 r2 = (b.max >= a.min && b.max <= a.max) || (b.min >= a.min && b.min <= a.max);
|
||||
return r1 || r2;
|
||||
}
|
||||
|
||||
fn v2f64_t v2f64_clamps(v2f64_t v, f64 min, f64 max) {
|
||||
v2f64_t result = { CLAMP(v.x, min, max), CLAMP(v.y, min, max) };
|
||||
return result;
|
||||
}
|
||||
fn v2f64_t v2f64_clamp(v2f64_t v, v2f64_t min, v2f64_t max) {
|
||||
v2f64_t result = { CLAMP(v.x, min.x, max.x), CLAMP(v.y, min.y, max.y) };
|
||||
return result;
|
||||
}
|
||||
|
||||
fn r2f64_t r2f64_fix(r2f64_t n) {
|
||||
r2f64_t result = {
|
||||
.min = {MIN(n.min.x, n.max.x), MIN(n.min.y, n.max.y)},
|
||||
.max = {MAX(n.min.x, n.max.x), MAX(n.min.y, n.max.y)},
|
||||
};
|
||||
return result;
|
||||
}
|
||||
""".strip()
|
||||
s = s.replace("f64", basic_type)
|
||||
print(s)
|
||||
|
||||
for at in basic_types:
|
||||
for bt in basic_types:
|
||||
if at == bt: continue
|
||||
for st in struct_types:
|
||||
atype = f"{st[name_idx]}{at}"
|
||||
btype = f"{st[name_idx]}{bt}"
|
||||
members = st[member_idx]
|
||||
|
||||
def cast_members(members, type):
|
||||
result = ""
|
||||
for i in range(len(members)):
|
||||
result += f"({type})v.{members[i]}"
|
||||
if i != len(members) - 1:
|
||||
result += ", "
|
||||
return result
|
||||
|
||||
print(f"fn_inline {btype}_t {atype}_to_{btype}({atype}_t v) {{ return ({btype}_t){{ {cast_members(members, bt)} }}; }}")
|
||||
|
||||
|
||||
#######
|
||||
# generate r2f64_sub_v2f64 for +-*/ and types
|
||||
for bt in basic_types:
|
||||
for sym in symbols:
|
||||
word_op = sym[1]
|
||||
s = """
|
||||
fn_inline r2f64_t r2f64_sub_v2f64(r2f64_t a, v2f64_t b) { return (r2f64_t){ v2f64_sub(a.min, b), v2f64_sub(a.max, b) }; }
|
||||
""".strip()
|
||||
s = s.replace("f64", bt)
|
||||
s = s.replace("sub", word_op)
|
||||
print(s)
|
||||
|
||||
|
||||
for bt in ["f32", "f64"]:
|
||||
s = """
|
||||
fn f64 f64_safe_ratio(f64 a, f64 b, f64 if0) {
|
||||
f64 result = if0;
|
||||
if (b != 0.0) {
|
||||
result = a / b;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn_inline f64 f64_safe_ratio0(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
|
||||
fn_inline f64 f64_safe_ratio1(f64 a, f64 b) { return f64_safe_ratio(a, b, 0); }
|
||||
""".strip()
|
||||
s = s.replace("f64", bt)
|
||||
print(s)
|
||||
@@ -1,613 +0,0 @@
|
||||
#include "core_platform.h"
|
||||
#include "core_ctx.h"
|
||||
#include "stb_sprintf.h"
|
||||
|
||||
#if PLATFORM_WASM && PLATFORM_EMSCRIPTEN == 0
|
||||
#define gb_wasm_export __attribute__((visibility("default")))
|
||||
#define fn_export __attribute__((visibility("default")))
|
||||
#define fn_wasm_import
|
||||
|
||||
fn_wasm_import void wasm_alert(isize ptr, i32 len);
|
||||
fn_wasm_import f64 wasm_parse_float(isize str, i32 len);
|
||||
fn_wasm_import void wasm_write_to_console(isize str, i32 len);
|
||||
fn_wasm_import void wasm_trap(void);
|
||||
|
||||
extern char __heap_base;
|
||||
|
||||
fn void *os_vmem_reserve(usize size) {
|
||||
unused(size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_commit(void *p, usize size) {
|
||||
unused(p);
|
||||
unused(size);
|
||||
return false;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_release(void *p) {
|
||||
unused(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_decommit(void *p, usize size) {
|
||||
unused(p);
|
||||
unused(size);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void os_error_box(char *str) {
|
||||
wasm_alert((isize)str, str_len(str));
|
||||
}
|
||||
|
||||
fn void os_console_log(char *str) {
|
||||
s8_t string = s8_from_char(str);
|
||||
if (s8_ends_with(string, s8("\n"))) {
|
||||
string = s8_chop(string, 1);
|
||||
}
|
||||
wasm_write_to_console((isize)string.str, (i32)string.len);
|
||||
}
|
||||
|
||||
fn f64 os_parse_float(char *str) {
|
||||
return wasm_parse_float((isize)str, str_len((char *)str));
|
||||
}
|
||||
|
||||
fn void os_core_small_init(ma_arena_t *arena) {
|
||||
tcx = ma_push_type(arena, thread_ctx_t);
|
||||
tcx->log.break_on_error = true;
|
||||
tcx->log.break_on_fatal = true;
|
||||
tcx->log.break_on_warning = true;
|
||||
tcx->log.print_file_and_line = true;
|
||||
tcx->log.log_proc = default_log_proc;
|
||||
}
|
||||
|
||||
fn void os_core_init(void) {
|
||||
ma_arena_t perm = {0};
|
||||
isize page_size = kib(64);
|
||||
isize page_count = __builtin_wasm_memory_size(0);
|
||||
u8 *memory = (u8 *)&__heap_base;
|
||||
usize memory_size = page_count * (page_size) - (isize)memory;
|
||||
perm.data = memory;
|
||||
perm.commit = perm.reserve = memory_size;
|
||||
os_core_small_init(&perm);
|
||||
tcx->perm = perm;
|
||||
ma_push_arena_ex(&tcx->perm, &tcx->temp, mib(64));
|
||||
ma_push_arena_ex(&tcx->perm, &tcx->scratch[0], mib(2));
|
||||
ma_push_arena_ex(&tcx->perm, &tcx->scratch[1], kib(256));
|
||||
ma_push_arena_ex(&tcx->perm, &tcx->scratch[2], kib(64));
|
||||
debugf("memory size = %lld", memory_size);
|
||||
}
|
||||
#elif PLATFORM_WINDOWS
|
||||
#pragma comment(lib, "user32.lib")
|
||||
#pragma comment(lib, "DbgHelp.lib")
|
||||
#pragma comment(lib, "Shell32.lib")
|
||||
#pragma comment(lib, "Ole32.lib")
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <DbgHelp.h>
|
||||
#include <TlHelp32.h>
|
||||
#include <Shlobj.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct b_stacktrace_tag* b_stacktrace_handle;
|
||||
|
||||
/*
|
||||
Returns a stack-trace handle from the point of view of the caller which
|
||||
can be expanded to a string via b_stacktrace_to_string.
|
||||
The handle is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
fn b_stacktrace_handle b_stacktrace_get();
|
||||
|
||||
/*
|
||||
Converts a stack-trace handle to a human-readable string.
|
||||
The string is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
fn char* b_stacktrace_to_string(b_stacktrace_handle stacktrace);
|
||||
|
||||
/*
|
||||
Returns a human-readable stack-trace string from the point of view of the
|
||||
caller.
|
||||
The string is allocated with `malloc` and needs to be freed with `free`
|
||||
*/
|
||||
fn char* b_stacktrace_get_string(void);
|
||||
|
||||
/* version */
|
||||
|
||||
typedef struct print_buf {
|
||||
char* buf;
|
||||
int pos;
|
||||
int size;
|
||||
} print_buf;
|
||||
|
||||
static print_buf buf_init(void) {
|
||||
print_buf ret = {
|
||||
(char*) malloc(1024),
|
||||
0,
|
||||
1024
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void buf_printf(print_buf* b, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const int len = stbsp_vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
va_end(args);
|
||||
|
||||
const int new_end = b->pos + len;
|
||||
|
||||
if (new_end > b->size) {
|
||||
while (new_end > b->size) b->size *= 2;
|
||||
b->buf = (char*)realloc(b->buf, b->size);
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
b->pos += stbsp_vsnprintf(b->buf + b->pos, len, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
char* b_stacktrace_get_string(void) {
|
||||
b_stacktrace_handle h = b_stacktrace_get();
|
||||
char* ret = b_stacktrace_to_string(h);
|
||||
free(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define B_STACKTRACE_MAX_DEPTH 1024
|
||||
#define B_STACKTRACE_ERROR_FLAG ((DWORD64)1 << 63)
|
||||
|
||||
typedef struct b_stacktrace_entry {
|
||||
DWORD64 AddrPC_Offset;
|
||||
DWORD64 AddrReturn_Offset;
|
||||
} b_stacktrace_entry;
|
||||
|
||||
static int SymInitialize_called = 0;
|
||||
|
||||
b_stacktrace_handle b_stacktrace_get(void) {
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
CONTEXT context;
|
||||
STACKFRAME64 frame; /* in/out stackframe */
|
||||
DWORD imageType;
|
||||
b_stacktrace_entry* ret = (b_stacktrace_entry*)malloc(B_STACKTRACE_MAX_DEPTH * sizeof(b_stacktrace_entry));
|
||||
int i = 0;
|
||||
|
||||
if (!SymInitialize_called) {
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
SymInitialize_called = 1;
|
||||
}
|
||||
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
#ifdef _M_IX86
|
||||
imageType = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_X64
|
||||
imageType = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rsp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Rsp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_IA64
|
||||
imageType = IMAGE_FILE_MACHINE_IA64;
|
||||
frame.AddrPC.Offset = context.StIIP;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.IntSp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrBStore.Offset = context.RsBSP;
|
||||
frame.AddrBStore.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.IntSp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
#else
|
||||
#error "Platform not supported!"
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
b_stacktrace_entry* cur = ret + i++;
|
||||
if (i == B_STACKTRACE_MAX_DEPTH) {
|
||||
cur->AddrPC_Offset = 0;
|
||||
cur->AddrReturn_Offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!StackWalk64(imageType, process, thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
|
||||
cur->AddrPC_Offset = frame.AddrPC.Offset;
|
||||
cur->AddrReturn_Offset = B_STACKTRACE_ERROR_FLAG; /* mark error */
|
||||
cur->AddrReturn_Offset |= GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
cur->AddrPC_Offset = frame.AddrPC.Offset;
|
||||
cur->AddrReturn_Offset = frame.AddrReturn.Offset;
|
||||
|
||||
if (frame.AddrReturn.Offset == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (b_stacktrace_handle)(ret);
|
||||
}
|
||||
|
||||
char* b_stacktrace_to_string(b_stacktrace_handle h) {
|
||||
const b_stacktrace_entry* entries = (b_stacktrace_entry*)h;
|
||||
int i = 0;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
print_buf out = buf_init();
|
||||
IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + 1024);
|
||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
symbol->MaxNameLength = 1024;
|
||||
|
||||
while (1) {
|
||||
IMAGEHLP_LINE64 lineData;
|
||||
DWORD lineOffset = 0;
|
||||
DWORD64 symOffset = 0;
|
||||
const b_stacktrace_entry* cur = entries + i++;
|
||||
|
||||
if (cur->AddrReturn_Offset & B_STACKTRACE_ERROR_FLAG) {
|
||||
DWORD error = cur->AddrReturn_Offset & 0xFFFFFFFF;
|
||||
buf_printf(&out, "StackWalk64 error: %d @ %p\n", error, cur->AddrPC_Offset);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur->AddrPC_Offset == cur->AddrReturn_Offset) {
|
||||
buf_printf(&out, "Stack overflow @ %p\n", cur->AddrPC_Offset);
|
||||
break;
|
||||
}
|
||||
|
||||
SymGetLineFromAddr64(process, cur->AddrPC_Offset, &lineOffset, &lineData);
|
||||
buf_printf(&out, "%s(%d): ", lineData.FileName, lineData.LineNumber);
|
||||
|
||||
if (SymGetSymFromAddr64(process, cur->AddrPC_Offset, &symOffset, symbol)) {
|
||||
buf_printf(&out, "%s\n", symbol->Name);
|
||||
}
|
||||
else {
|
||||
buf_printf(&out, " Unkown symbol @ %p\n", cur->AddrPC_Offset);
|
||||
}
|
||||
|
||||
if (cur->AddrReturn_Offset == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(symbol);
|
||||
return out.buf;
|
||||
}
|
||||
|
||||
fn void *os_vmem_reserve(usize size) {
|
||||
void *result = VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_commit(void *p, usize size) {
|
||||
void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
return result ? true : false;
|
||||
}
|
||||
fn b32 os_vmem_release(void *p) {
|
||||
BOOL result = VirtualFree(p, 0, MEM_RELEASE);
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_decommit(void *p, usize size) {
|
||||
BOOL result = VirtualFree(p, size, MEM_DECOMMIT);
|
||||
return result ? true : false;
|
||||
}
|
||||
|
||||
fn void os_error_box(char *str) {
|
||||
OutputDebugStringA(str);
|
||||
fprintf(stderr, "%s", str);
|
||||
fflush(stderr);
|
||||
MessageBoxA(NULL, str, "fatal error", MB_OK);
|
||||
}
|
||||
|
||||
fn void os_console_log(char *str) {
|
||||
OutputDebugStringA(str);
|
||||
fputs(str, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
fn f64 os_parse_float(char *str) {
|
||||
return strtod(str, NULL);
|
||||
}
|
||||
|
||||
fn void os_win32_crash_handler(int signal) {
|
||||
printf("signal: %d\n", signal);
|
||||
puts(b_stacktrace_get_string());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fn void os_win32_register_crash_handler() {
|
||||
signal(SIGSEGV, os_win32_crash_handler);
|
||||
signal(SIGABRT, os_win32_crash_handler);
|
||||
}
|
||||
|
||||
fn void os_core_small_init(ma_arena_t *arena) {
|
||||
tcx = ma_push_type(arena, thread_ctx_t);
|
||||
tcx->log.break_on_error = true;
|
||||
tcx->log.break_on_fatal = true;
|
||||
tcx->log.break_on_warning = true;
|
||||
tcx->log.print_file_and_line = true;
|
||||
tcx->log.log_proc = default_log_proc;
|
||||
os_win32_register_crash_handler();
|
||||
}
|
||||
|
||||
fn void os_core_init(void) {
|
||||
ma_arena_t perm = {0};
|
||||
os_core_small_init(&perm);
|
||||
tcx->perm = perm;
|
||||
}
|
||||
#elif PLATFORM_POSIX
|
||||
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
|
||||
#if !PLATFORM_EMSCRIPTEN
|
||||
#include <execinfo.h>
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
fn void *os_vmem_reserve(usize size) {
|
||||
void *result = mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
return result == MAP_FAILED ? NULL : result;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_commit(void *ptr, usize size) {
|
||||
mprotect(ptr, size, PROT_READ|PROT_WRITE);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_release(void *ptr) {
|
||||
int result = munmap(ptr, 0);
|
||||
return result == 0 ? true : false;
|
||||
}
|
||||
|
||||
fn b32 os_vmem_decommit(void *ptr, usize size) {
|
||||
madvise(ptr, size, MADV_DONTNEED);
|
||||
mprotect(ptr, size, PROT_NONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void os_error_box(char *str) {
|
||||
fprintf(stderr, "%s", str);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
fn void os_console_log(char *str) {
|
||||
fputs(str, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
fn f64 os_parse_float(char *str) {
|
||||
return strtod(str, NULL);
|
||||
}
|
||||
|
||||
#if !PLATFORM_EMSCRIPTEN
|
||||
|
||||
typedef struct b_stacktrace_tag* b_stacktrace_handle;
|
||||
b_stacktrace_handle b_stacktrace_get();
|
||||
int b_stacktrace_depth(b_stacktrace_handle stacktrace);
|
||||
char* b_stacktrace_to_string(b_stacktrace_handle stacktrace);
|
||||
char* malloc_backtrace(void);
|
||||
|
||||
typedef struct print_buf {
|
||||
char* buf;
|
||||
int pos;
|
||||
int size;
|
||||
} print_buf;
|
||||
|
||||
static print_buf buf_init(void) {
|
||||
print_buf ret = {
|
||||
(char*) malloc(1024),
|
||||
0,
|
||||
1024
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void buf_printf(print_buf* b, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const int len = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||
va_end(args);
|
||||
|
||||
const int new_end = b->pos + len;
|
||||
|
||||
if (new_end > b->size) {
|
||||
while (new_end > b->size) b->size *= 2;
|
||||
b->buf = (char*)realloc(b->buf, b->size);
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
b->pos += vsnprintf(b->buf + b->pos, len, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
char* malloc_backtrace(void) {
|
||||
b_stacktrace_handle h = b_stacktrace_get();
|
||||
char* ret = b_stacktrace_to_string(h);
|
||||
free(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define B_STACKTRACE_MAX_DEPTH 1024
|
||||
|
||||
typedef struct b_stacktrace {
|
||||
void* trace[B_STACKTRACE_MAX_DEPTH];
|
||||
int trace_size;
|
||||
} b_stacktrace;
|
||||
|
||||
b_stacktrace_handle b_stacktrace_get(void) {
|
||||
b_stacktrace* ret = (b_stacktrace*)malloc(sizeof(b_stacktrace));
|
||||
ret->trace_size = backtrace(ret->trace, B_STACKTRACE_MAX_DEPTH);
|
||||
return (b_stacktrace_handle)(ret);
|
||||
}
|
||||
|
||||
int b_stacktrace_depth(b_stacktrace_handle h) {
|
||||
const b_stacktrace* stacktrace = (b_stacktrace*)h;
|
||||
return stacktrace->trace_size;
|
||||
}
|
||||
|
||||
char* b_stacktrace_to_string(b_stacktrace_handle h) {
|
||||
const b_stacktrace* stacktrace = (b_stacktrace*)h;
|
||||
char** messages = backtrace_symbols(stacktrace->trace, stacktrace->trace_size);
|
||||
print_buf out = buf_init();
|
||||
int i;
|
||||
|
||||
int skip_count = 5;
|
||||
for (i = 0; i < stacktrace->trace_size; ++i) {
|
||||
void* tracei = stacktrace->trace[i];
|
||||
char* msg = messages[i];
|
||||
|
||||
if (i < skip_count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* calculate load offset */
|
||||
Dl_info info;
|
||||
dladdr(tracei, &info);
|
||||
if (info.dli_fbase == (void*)0x400000) {
|
||||
/* address from executable, so don't offset */
|
||||
info.dli_fbase = NULL;
|
||||
}
|
||||
|
||||
while (*msg && *msg != '(') ++msg;
|
||||
*msg = 0;
|
||||
|
||||
{
|
||||
char cmd[1024];
|
||||
char line[2048];
|
||||
|
||||
FILE* fp;
|
||||
snprintf(cmd, 1024, "addr2line -e %s -f -C -p %p 2>/dev/null", messages[i], (void*)((char*)tracei - (char*)info.dli_fbase));
|
||||
|
||||
fp = popen(cmd, "r");
|
||||
if (!fp) {
|
||||
buf_printf(&out, "Failed to generate trace further...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
buf_printf(&out, " ");
|
||||
if (strstr(line, "?? ")) {
|
||||
/* just output address if nothing can be found */
|
||||
buf_printf(&out, "%p\n", tracei);
|
||||
}
|
||||
else {
|
||||
int len = strlen(line);
|
||||
char *at = strstr(line, " at ");
|
||||
if (at) {
|
||||
char *function = line;
|
||||
int function_len = at - line;
|
||||
char *file = at + 4;
|
||||
int file_len = strlen(file) - 1;
|
||||
buf_printf(&out, " %.*s %.*s (%s)\n", file_len, file, function_len, function, messages[i]);
|
||||
} else {
|
||||
buf_printf(&out, " %.*s (%s)\n", len - 1, line, messages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
free(messages);
|
||||
return out.buf;
|
||||
}
|
||||
|
||||
void print_backtrace(void) {
|
||||
char *backtrace = malloc_backtrace();
|
||||
puts(backtrace);
|
||||
free(backtrace);
|
||||
}
|
||||
|
||||
const char *signal_to_string(int signal) {
|
||||
switch (signal) {
|
||||
case SIGINT: return "SIGINT";
|
||||
case SIGILL: return "SIGILL";
|
||||
case SIGABRT: return "SIGABRT";
|
||||
case SIGFPE: return "SIGFPE";
|
||||
case SIGSEGV: return "SIGSEGV";
|
||||
case SIGTERM: return "SIGTERM";
|
||||
case SIGHUP: return "SIGALRM";
|
||||
case SIGQUIT: return "SIGQUIT";
|
||||
case SIGTRAP: return "SIGTRAP";
|
||||
case SIGKILL: return "SIGKILL";
|
||||
case SIGPIPE: return "SIGPIPE";
|
||||
case SIGALRM: return "SIGHUP";
|
||||
case SIGPOLL: return "SIGPOLL";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
void backtrace_handle_signal(int signal, siginfo_t* info, void* context) {
|
||||
(void)context; // unused
|
||||
printf("Stack trace (%s/%d):", signal_to_string(signal), signal);
|
||||
if (signal == SIGSEGV) {
|
||||
printf(" at addr: %p", info->si_addr);
|
||||
}
|
||||
puts("");
|
||||
print_backtrace();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void setup_backtrace() {
|
||||
struct sigaction sa;
|
||||
sa.sa_sigaction = backtrace_handle_signal;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
sigaction(SIGABRT, &sa, NULL);
|
||||
sigaction(SIGFPE, &sa, NULL);
|
||||
sigaction(SIGBUS, &sa, NULL);
|
||||
sigaction(SIGILL, &sa, NULL);
|
||||
sigaction(SIGTRAP, &sa, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
fn void os_core_small_init(ma_arena_t *arena) {
|
||||
tcx = ma_push_type(arena, thread_ctx_t);
|
||||
tcx->log.break_on_error = true;
|
||||
tcx->log.break_on_fatal = true;
|
||||
tcx->log.break_on_warning = true;
|
||||
tcx->log.print_file_and_line = true;
|
||||
tcx->log.log_proc = default_log_proc;
|
||||
#if !PLATFORM_EMSCRIPTEN
|
||||
setup_backtrace();
|
||||
#endif
|
||||
}
|
||||
|
||||
fn void os_core_init(void) {
|
||||
ma_arena_t perm = {0};
|
||||
os_core_small_init(&perm);
|
||||
tcx->perm = perm;
|
||||
}
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
|
||||
fn void os_error_box(char *str);
|
||||
fn void os_console_log(char *str);
|
||||
|
||||
fn void *os_vmem_reserve(usize size);
|
||||
fn b32 os_vmem_commit(void *p, usize size);
|
||||
fn b32 os_vmem_release(void *p);
|
||||
fn b32 os_vmem_decommit(void *p, usize size);
|
||||
|
||||
fn void os_core_init(void);
|
||||
fn void os_core_small_init(ma_arena_t *arena);
|
||||
fn f64 os_parse_float(char *str);
|
||||
|
||||
|
||||
#if PLATFORM_DEBUG_ASSERT
|
||||
#define assert_expr(x) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x "\n"), debug_break()))
|
||||
#define assert(x) do { assert_expr(x); } while(0)
|
||||
#define assert_ex(x, msg) (!(x) && (os_error_box(FILE_AND_LINE ": assertion failed: " #x " :: " #msg "\n"), debug_break()))
|
||||
#else
|
||||
#define assert_expr(x) (void)(x)
|
||||
#define assert(x) do { (void)(x); } while(0)
|
||||
#define assert_ex(x, msg) do { (void)(x); } while(0)
|
||||
#endif
|
||||
#define not_implemented assert(!"not implemented!")
|
||||
#define invalid_codepath assert(!"invalid code path!")
|
||||
#define default_is_invalid default: assert(!"invalid default case")
|
||||
#define else_is_invalid else { assert(!"else was not expected to be executed!"); }
|
||||
@@ -1,557 +0,0 @@
|
||||
#include "core_string.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_platform.h"
|
||||
#include "stb_sprintf.h"
|
||||
|
||||
fn i32 str_len(char *str) {
|
||||
i32 i = 0;
|
||||
while (str[i]) i += 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
fn b32 str_eq(char *a, char *b) {
|
||||
return s8_are_equal(s8_from_char(a), s8_from_char(b));
|
||||
}
|
||||
|
||||
fn char char_to_lower_case(char a) {
|
||||
if (a >= 'A' && a <= 'Z') a += 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
fn char char_to_upper_case(char a) {
|
||||
if (a >= 'a' && a <= 'z') a -= 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
fn b32 char_is_whitespace(char w) {
|
||||
b32 result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_alphabetic(char a) {
|
||||
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_ident(char a) {
|
||||
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_digit(char a) {
|
||||
b32 result = a >= '0' && a <= '9';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_alphanumeric(char a) {
|
||||
b32 result = char_is_digit(a) || char_is_alphabetic(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_symbol(char w) {
|
||||
b32 result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_non_word(char w) {
|
||||
b32 result = w != '_' && (char_is_symbol(w) || char_is_whitespace(w));
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char_is_word(char w) {
|
||||
b32 result = !char_is_non_word(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_from_range(char *begin, char *end) {
|
||||
assert(end >= begin);
|
||||
intptr_t size = (intptr_t)end - (intptr_t)begin;
|
||||
s8_t result = {begin, size};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_from_char(char *string) {
|
||||
s8_t result;
|
||||
result.str = (char *)string;
|
||||
result.len = str_len(string);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_copy(ma_arena_t *ma, s8_t string) {
|
||||
char *copy = (char *)ma_push_size(ma, sizeof(char) * (string.len + 1));
|
||||
memory_copy(copy, string.str, string.len);
|
||||
copy[string.len] = 0;
|
||||
s8_t result = s8_make(copy, string.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_copy_char(ma_arena_t *ma, char *s) {
|
||||
int64_t len = str_len(s);
|
||||
char *copy = (char *)ma_push_size(ma, sizeof(char) * (len + 1));
|
||||
memory_copy(copy, s, len);
|
||||
copy[len] = 0;
|
||||
s8_t result = s8_make(copy, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_are_equal_ex(s8_t a, s8_t b, b32 ignore_case) {
|
||||
if (a.len != b.len) return false;
|
||||
for (int64_t i = 0; i < a.len; i++) {
|
||||
char A = a.str[i];
|
||||
char B = b.str[i];
|
||||
if (ignore_case) {
|
||||
A = char_to_lower_case(A);
|
||||
B = char_to_lower_case(B);
|
||||
}
|
||||
if (A != B)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn b32 s8_are_equal(s8_t a, s8_t b) {
|
||||
return s8_are_equal_ex(a, b, false);
|
||||
}
|
||||
|
||||
fn s8_t s8_get_postfix(s8_t string, int64_t len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
int64_t remain_len = string.len - len;
|
||||
s8_t result = s8_make(string.str + remain_len, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_get_prefix(s8_t string, int64_t len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
s8_t result = s8_make(string.str, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_chop(s8_t string, int64_t len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
s8_t result = s8_make(string.str, string.len - len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_skip(s8_t string, int64_t len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
int64_t remain = string.len - len;
|
||||
s8_t result = s8_make(string.str + len, remain);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_ends_with_ex(s8_t a, s8_t end, b32 ignore_case) {
|
||||
s8_t a_end = s8_get_postfix(a, end.len);
|
||||
b32 result = s8_are_equal_ex(end, a_end, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_starts_with_ex(s8_t a, s8_t start, b32 ignore_case) {
|
||||
s8_t a_start = s8_get_prefix(a, start.len);
|
||||
b32 result = s8_are_equal_ex(start, a_start, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_ends_with(s8_t a, s8_t end) {
|
||||
return s8_ends_with_ex(a, end, false);
|
||||
}
|
||||
|
||||
fn b32 s8_starts_with(s8_t a, s8_t start) {
|
||||
return s8_starts_with_ex(a, start, false);
|
||||
}
|
||||
|
||||
fn void s8_normalize_path_unsafe(s8_t s) {
|
||||
for (int64_t i = 0; i < s.len; i++) {
|
||||
if (s.str[i] == '\\')
|
||||
s.str[i] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
fn b32 s8_is_pointer_inside(s8_t string, char *p) {
|
||||
uintptr_t pointer = (uintptr_t)p;
|
||||
uintptr_t start = (uintptr_t)string.str;
|
||||
uintptr_t stop = start + (uintptr_t)string.len;
|
||||
b32 result = pointer >= start && pointer < stop;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_cut_start(s8_t *in, i64 size) {
|
||||
s8_t result = s8_get_prefix(*in, size);
|
||||
*in = s8_skip(*in, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_cut_end(s8_t *in, i64 size) {
|
||||
s8_t result = s8_get_postfix(*in, size);
|
||||
*in = s8_chop(*in, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
s8_t s8_skip_to_p(s8_t string, char *p) {
|
||||
if (s8_is_pointer_inside(string, p)) {
|
||||
s8_t result = s8_make(p, p - string.str);
|
||||
return result;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
s8_t s8_skip_past(s8_t string, s8_t a) {
|
||||
if (s8_is_pointer_inside(string, a.str)) {
|
||||
s8_t on_p = s8_make(a.str, a.str - string.str);
|
||||
s8_t result = s8_skip(on_p, a.len);
|
||||
return result;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
#endif
|
||||
|
||||
fn s8_t s8_slice(s8_t string, int64_t first_index, int64_t one_past_last_index) {
|
||||
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
|
||||
if (first_index < 0) first_index = string.len + first_index;
|
||||
assert(first_index < one_past_last_index);
|
||||
assert(string.len > 0);
|
||||
s8_t result = string;
|
||||
if (string.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = CLAMP_TOP(first_index, string.len - 1);
|
||||
one_past_last_index = CLAMP_TOP(one_past_last_index, string.len);
|
||||
result.str += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
}
|
||||
else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_trim(s8_t string) {
|
||||
if (string.len == 0)
|
||||
return string;
|
||||
|
||||
int64_t whitespace_begin = 0;
|
||||
for (; whitespace_begin < string.len; whitespace_begin++) {
|
||||
if (!char_is_whitespace(string.str[whitespace_begin])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != whitespace_begin; whitespace_end--) {
|
||||
if (!char_is_whitespace(string.str[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (whitespace_begin == whitespace_end) {
|
||||
string.len = 0;
|
||||
}
|
||||
else {
|
||||
string = s8_slice(string, whitespace_begin, whitespace_end);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
fn s8_t s8_trim_end(s8_t string) {
|
||||
int64_t whitespace_end = string.len;
|
||||
for (; whitespace_end != 0; whitespace_end--) {
|
||||
if (!char_is_whitespace(string.str[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s8_t result = s8_get_prefix(string, whitespace_end);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s8_seek(s8_t string, s8_t find, s8_seek_t flags, int64_t *index_out) {
|
||||
b32 ignore_case = flags & s8_seek_ignore_case ? true : false;
|
||||
b32 result = false;
|
||||
if (flags & s8_seek_match_find_last) {
|
||||
for (int64_t i = string.len; i != 0; i--) {
|
||||
int64_t index = i - 1;
|
||||
s8_t substring = s8_slice(string, index, index + find.len);
|
||||
if (s8_are_equal_ex(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = index;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int64_t i = 0; i < string.len; i++) {
|
||||
s8_t substring = s8_slice(string, i, i + find.len);
|
||||
if (s8_are_equal_ex(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = i;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn int64_t s8_find(s8_t string, s8_t find, s8_seek_t flag) {
|
||||
int64_t result = -1;
|
||||
s8_seek(string, find, flag, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_chop_last_char(s8_t s, s8_t ch) {
|
||||
s8_t result = s;
|
||||
s8_seek(s, ch, s8_seek_match_find_last, &result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_chop_last_slash(s8_t s) {
|
||||
return s8_chop_last_char(s, s8("/"));
|
||||
}
|
||||
|
||||
fn s8_t s8_chop_last_period(s8_t s) {
|
||||
return s8_chop_last_char(s, s8("."));
|
||||
}
|
||||
|
||||
fn s8_t s8_skip_to_last_char(s8_t s, s8_t ch) {
|
||||
int64_t pos;
|
||||
s8_t result = s;
|
||||
if (s8_seek(s, ch, s8_seek_match_find_last, &pos)) {
|
||||
result = s8_skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t s8_skip_to_last_slash(s8_t s) {
|
||||
return s8_skip_to_last_char(s, s8("/"));
|
||||
}
|
||||
|
||||
fn s8_t s8_skip_to_last_period(s8_t s) {
|
||||
return s8_skip_to_last_char(s, s8("."));
|
||||
}
|
||||
|
||||
fn s8_t s8_get_name_no_ext(s8_t s) {
|
||||
return s8_skip_to_last_slash(s8_chop_last_period(s));
|
||||
}
|
||||
|
||||
fn s8_t s8_normalize_path(ma_arena_t *ma, s8_t s) {
|
||||
s8_t copy = s8_copy(ma, s);
|
||||
s8_normalize_path_unsafe(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s8_t s8_to_lower_case(ma_arena_t *ma, s8_t s) {
|
||||
s8_t copy = s8_copy(ma, s);
|
||||
for (int64_t i = 0; i < copy.len; i++) {
|
||||
copy.str[i] = char_to_lower_case(copy.str[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s8_t s8_to_upper_case(ma_arena_t *ma, s8_t s) {
|
||||
s8_t copy = s8_copy(ma, s);
|
||||
for (int64_t i = 0; i < copy.len; i++) {
|
||||
copy.str[i] = char_to_upper_case(copy.str[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s8_t s8_vfmt(ma_arena_t *ma, const char *str, va_list args1) {
|
||||
va_list args2;
|
||||
va_copy(args2, args1);
|
||||
int64_t len = s8_vsnprintf(0, 0, str, args2);
|
||||
va_end(args2);
|
||||
|
||||
char *result = (char *)ma_push_size(ma, sizeof(char) * (len + 1));
|
||||
s8_vsnprintf(result, (i32)(len + 1), str, args1);
|
||||
s8_t res = s8_make(result, len);
|
||||
return res;
|
||||
}
|
||||
|
||||
fn s8_t s8_printf(ma_arena_t *ma, const char *str, ...) {
|
||||
S8_FMT(ma, str, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn sb8_node_t *sb8_create_node(ma_arena_t *ma, s8_t str) {
|
||||
sb8_node_t *node = ma_push_type(ma, sb8_node_t);
|
||||
node->string = str;
|
||||
return node;
|
||||
}
|
||||
|
||||
fn sb8_node_t *sb8_append(sb8_t *list, s8_t string) {
|
||||
assert(list->arena != NULL);
|
||||
sb8_node_t *node = sb8_create_node(list->arena, string);
|
||||
SLLQ_APPEND(list->first, list->last, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
fn s8_t sb8_printf(sb8_t *sb, const char *str, ...) {
|
||||
S8_FMT(sb->arena, str, result);
|
||||
sb8_append(sb, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void sb8_indent(sb8_t *sb) {
|
||||
sb8_printf(sb, "\n%.*s", sb->indent*4, " ");
|
||||
}
|
||||
|
||||
fn s8_t sb8_stmtf(sb8_t *sb, const char *str, ...) {
|
||||
S8_FMT(sb->arena, str, result);
|
||||
sb8_indent(sb);
|
||||
sb8_append(sb, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn int64_t sb8_char_size(sb8_t *sb) {
|
||||
int64_t result = 0;
|
||||
for (sb8_node_t *it = sb->first; it; it = it->next) {
|
||||
result += it->len;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t sb8_merge(ma_arena_t *arena, sb8_t *sb) {
|
||||
int64_t size = sb8_char_size(sb) + 1;
|
||||
char *str = ma_push_size(arena, size);
|
||||
s8_t result = {str, 0};
|
||||
for (sb8_node_t *it = sb->first; it; it = it->next) {
|
||||
memory_copy(result.str + result.len, it->str, it->len);
|
||||
result.len += it->len;
|
||||
}
|
||||
result.str[result.len] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags) {
|
||||
sb8_t result = (sb8_t){ma};
|
||||
int64_t index = 0;
|
||||
|
||||
s8_seek_t find_flag = flags & s8_split_ignore_case ? s8_seek_ignore_case : s8_seek_none;
|
||||
while (s8_seek(string, find, find_flag, &index)) {
|
||||
s8_t before_match = s8_make(string.str, index);
|
||||
if (flags & s8_split_cleanup) {
|
||||
before_match = s8_trim(before_match);
|
||||
if (before_match.len) {
|
||||
sb8_append(&result, before_match);
|
||||
}
|
||||
} else {
|
||||
sb8_append(&result, before_match);
|
||||
}
|
||||
if (flags & s8_split_inclusive) {
|
||||
s8_t match = s8_make(string.str + index, find.len);
|
||||
sb8_append(&result, match);
|
||||
}
|
||||
string = s8_skip(string, index + find.len);
|
||||
}
|
||||
if (string.len) sb8_append(&result, string);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn u64 u64_from_hexchar(char c) {
|
||||
switch (c) {
|
||||
case '0': return 0; break;
|
||||
case '1': return 1; break;
|
||||
case '2': return 2; break;
|
||||
case '3': return 3; break;
|
||||
case '4': return 4; break;
|
||||
case '5': return 5; break;
|
||||
case '6': return 6; break;
|
||||
case '7': return 7; break;
|
||||
case '8': return 8; break;
|
||||
case '9': return 9; break;
|
||||
case 'a':
|
||||
case 'A': return 10; break;
|
||||
case 'b':
|
||||
case 'B': return 11; break;
|
||||
case 'c':
|
||||
case 'C': return 12; break;
|
||||
case 'd':
|
||||
case 'D': return 13; break;
|
||||
case 'e':
|
||||
case 'E': return 14; break;
|
||||
case 'f':
|
||||
case 'F': return 15; break;
|
||||
default: return 255;
|
||||
}
|
||||
}
|
||||
|
||||
fn u64 u64_from_s8(s8_t s, u64 base) {
|
||||
assert(base >= 2 && base <= 16);
|
||||
u64 acc = 0;
|
||||
for (i64 i = 0; i < s.len; i++) {
|
||||
u64 num = u64_from_hexchar(s.str[i]);
|
||||
assert(num < base);
|
||||
acc *= base;
|
||||
acc += num;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
fn u64 u64_from_s8_loose(s8_t s, u64 base) {
|
||||
assert(base >= 2 && base <= 16);
|
||||
u64 acc = 0;
|
||||
for (i64 i = 0; i < s.len; i++) {
|
||||
u64 num = u64_from_hexchar(s.str[i]);
|
||||
if (num >= base) {
|
||||
break;
|
||||
}
|
||||
acc *= base;
|
||||
acc += num;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
fn f64 f64_from_s8(s8_t string) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s8_t num_string = s8_copy(scratch.arena, string);
|
||||
f64 result = os_parse_float(num_string.str);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_read_only i64 s8_fuzzy_closer_word_begin = 5;
|
||||
gb_read_only i64 s8_fuzzy_consecutive_multiplier = 3;
|
||||
fn i64 s8_fuzzy_rate_string(s8_t string, s8_t with) {
|
||||
if (with.len == 0) return 0;
|
||||
|
||||
i64 points = 0;
|
||||
i64 consecutive = 0;
|
||||
i64 with_i = 0;
|
||||
for (i64 i = 0; i < string.len; i++) {
|
||||
if (string.str[i] == with.str[with_i]) {
|
||||
i64 closer_begin = CLAMP_BOT((i64)0, s8_fuzzy_closer_word_begin - i);
|
||||
points += closer_begin;
|
||||
consecutive++;
|
||||
with_i += 1;
|
||||
} else {
|
||||
points += consecutive * s8_fuzzy_consecutive_multiplier;
|
||||
consecutive = 0;
|
||||
with_i = 0;
|
||||
}
|
||||
|
||||
if (with_i >= with.len) with_i = 0;
|
||||
}
|
||||
points += consecutive * s8_fuzzy_consecutive_multiplier;
|
||||
return points;
|
||||
}
|
||||
|
||||
fn fuzzy_pair_t *s8_fuzzy_rate_array(ma_arena_t *arena, s8_t needle, s8_t *array, i32 len) {
|
||||
fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len);
|
||||
for (i32 i = 0; i < len; i += 1) {
|
||||
pairs[i].rating = s8_fuzzy_rate_string(array[i], needle);
|
||||
pairs[i].index = i;
|
||||
}
|
||||
|
||||
for (i32 i = 0; i < len - 1; i++) {
|
||||
for (i32 j = 0; j < len - 1; j++) {
|
||||
if (pairs[j].rating < pairs[j + 1].rating) {
|
||||
SWAP(fuzzy_pair_t, pairs[j], pairs[j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
|
||||
typedef struct s8_t s8_t;
|
||||
struct s8_t {
|
||||
char *str;
|
||||
int64_t len;
|
||||
};
|
||||
|
||||
typedef struct sb8_node_t sb8_node_t;
|
||||
struct sb8_node_t {
|
||||
sb8_node_t *next;
|
||||
union {
|
||||
struct { char *str; int64_t len; };
|
||||
s8_t string;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct sb8_t sb8_t;
|
||||
struct sb8_t {
|
||||
ma_arena_t *arena;
|
||||
sb8_node_t *first;
|
||||
sb8_node_t *last;
|
||||
|
||||
// WARNING: remember to update typeinfo after editing this
|
||||
i32 indent;
|
||||
};
|
||||
|
||||
typedef i32 s8_seek_t;
|
||||
enum {
|
||||
s8_seek_none = 0,
|
||||
s8_seek_ignore_case = 1,
|
||||
s8_seek_match_find_last = 2,
|
||||
};
|
||||
|
||||
typedef i32 s8_split_t;
|
||||
enum {
|
||||
s8_split_none = 0,
|
||||
s8_split_ignore_case = 1,
|
||||
s8_split_inclusive = 2,
|
||||
s8_split_cleanup = 4,
|
||||
};
|
||||
|
||||
enum { s8_ignore_case = 1 };
|
||||
|
||||
//
|
||||
// char and char string operations
|
||||
fn i32 str_len(char *str);
|
||||
fn b32 str_eq(char *a, char *b);
|
||||
fn char char_to_lower_case(char a);
|
||||
fn char char_to_upper_case(char a);
|
||||
fn b32 char_is_whitespace(char w);
|
||||
fn b32 char_is_alphabetic(char a);
|
||||
fn b32 char_is_ident(char a);
|
||||
fn b32 char_is_digit(char a);
|
||||
fn b32 char_is_alphanumeric(char a);
|
||||
|
||||
fn u64 u64_from_hexchar(char c);
|
||||
fn u64 u64_from_s8(s8_t s, u64 base);
|
||||
fn f64 f64_from_s8(s8_t string);
|
||||
|
||||
//
|
||||
// string8 constructors
|
||||
#define s8_make(str,len) (s8_t){str, len}
|
||||
#define s8_null (s8_t){0}
|
||||
#define s8_invalid s8("<INVALID>")
|
||||
#define s8(string) (s8_t){(char *)string, sizeof(string) - 1}
|
||||
#define s8_const(string) { string, sizeof(string) - 1 }
|
||||
#define s8_struct(DATA) (s8_t){.str = (char *)&(DATA), .len = sizeof(DATA)}
|
||||
#define s8_array(DATA) (s8_t){.str = (char *)(DATA), .len = lengthof(DATA)}
|
||||
#define s8_array_lit(DATA) {.str = (char *)(DATA), .len = lengthof(DATA)}
|
||||
fn s8_t s8_from_range(char *begin, char *end);
|
||||
fn s8_t s8_from_char(char *string);
|
||||
fn s8_t s8_copy(ma_arena_t *ma, s8_t string);
|
||||
|
||||
//
|
||||
// conditional
|
||||
fn b32 s8_are_equal_ex(s8_t a, s8_t b, b32 ignore_case);
|
||||
fn b32 s8_are_equal(s8_t a, s8_t b);
|
||||
fn b32 s8_ends_with_ex(s8_t a, s8_t end, b32 ignore_case);
|
||||
fn b32 s8_starts_with_ex(s8_t a, s8_t start, b32 ignore_case);
|
||||
fn b32 s8_ends_with(s8_t a, s8_t end);
|
||||
fn b32 s8_starts_with(s8_t a, s8_t start);
|
||||
fn b32 s8_is_pointer_inside(s8_t string, char *p);// @todo: maybe more general?
|
||||
|
||||
//
|
||||
// search
|
||||
fn b32 s8_seek(s8_t string, s8_t find, s8_seek_t flags, int64_t *index_out);
|
||||
fn int64_t s8_find(s8_t string, s8_t find, s8_seek_t flag);
|
||||
fn sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags);
|
||||
|
||||
//
|
||||
// string view transforms
|
||||
fn s8_t s8_slice(s8_t string, int64_t first_index, int64_t one_past_last_index);
|
||||
fn s8_t s8_get_postfix(s8_t string, int64_t len);
|
||||
fn s8_t s8_get_prefix(s8_t string, int64_t len);
|
||||
fn s8_t s8_chop(s8_t string, int64_t len);
|
||||
fn s8_t s8_skip(s8_t string, int64_t len);
|
||||
fn s8_t s8_chop_last_slash(s8_t s);
|
||||
fn s8_t s8_chop_last_period(s8_t s);
|
||||
fn s8_t s8_skip_to_last_slash(s8_t s);
|
||||
fn s8_t s8_skip_to_last_period(s8_t s);
|
||||
fn s8_t s8_get_name_no_ext(s8_t s);
|
||||
fn s8_t s8_trim(s8_t string);
|
||||
fn s8_t s8_trim_end(s8_t string);
|
||||
fn s8_t s8_cut_start(s8_t *in, i64 size);
|
||||
fn s8_t s8_cut_end(s8_t *in, i64 size);
|
||||
//
|
||||
// formatting
|
||||
fn void s8_normalize_path_unsafe(s8_t s);
|
||||
fn s8_t s8_normalize_path(ma_arena_t *ma, s8_t s);
|
||||
fn s8_t s8_to_lower_case(ma_arena_t *ma, s8_t s);
|
||||
fn s8_t s8_to_upper_case(ma_arena_t *ma, s8_t s);
|
||||
fn s8_t s8_vfmt(ma_arena_t *ma, const char *str, va_list args1);
|
||||
fn s8_t s8_printf(ma_arena_t *ma, const char *str, ...);
|
||||
|
||||
//
|
||||
// string builder
|
||||
#define sb8(ARENA) &(sb8_t){.arena = arena}
|
||||
#define sb8_serial_begin(ARENA) &(sb8_t){.arena = ARENA}
|
||||
#define sb8_serial_end(ARENA, SB) sb8_merge(ARENA, SB)
|
||||
|
||||
fn s8_t sb8_printf(sb8_t *sb, const char *str, ...);
|
||||
fn sb8_node_t *sb8_append(sb8_t *list, s8_t string);
|
||||
fn sb8_node_t *sb8_create_node(ma_arena_t *ma, s8_t str);
|
||||
|
||||
fn s8_t sb8_merge(ma_arena_t *arena, sb8_t *sb);
|
||||
fn void sb8_indent(sb8_t *sb);
|
||||
fn s8_t sb8_stmtf(sb8_t *sb, const char *str, ...);
|
||||
fn int64_t sb8_char_size(sb8_t *sb);
|
||||
|
||||
#if 0
|
||||
sb8_t *sbin_write_begin(ma_arena_t *arena);
|
||||
s8_t sbin_write_end(sb8_t *sb);
|
||||
|
||||
void *sbin_write_data(sb8_t *sb, void *p, i64 size);
|
||||
void *sbin_write_size(sb8_t *sb, i64 size);
|
||||
void *sbin_write_u64(sb8_t *sb, u64 value);
|
||||
void *sbin_write_u32(sb8_t *sb, u32 value);
|
||||
void *sbin_write_u16(sb8_t *sb, u16 value);
|
||||
void *sbin_write_u8(sb8_t *sb, u8 value);
|
||||
s8_t *sbin_write_s8(sb8_t *sb, s8_t string);
|
||||
char *sbin_write_str(sb8_t *sb, char *string);
|
||||
|
||||
stream_t sbin_read_begin(void *p, i64 size);
|
||||
void sbin_read_end(stream_t *stream);
|
||||
void *sbin_read_data(stream_t *stream, i64 size);
|
||||
#endif
|
||||
|
||||
//
|
||||
// other
|
||||
#define s8_fmtspec(string) (int)(string).len, (string).str
|
||||
#define S8_CODE(...) s8(#__VA_ARGS__)
|
||||
#define S8_FILE s8(__FILE__)
|
||||
#define S8_FILE_AND_LINE s8(FILE_AND_LINE)
|
||||
|
||||
#define S8_FMT(ma, str, result) \
|
||||
va_list args1; \
|
||||
va_start(args1, str); \
|
||||
s8_t result = s8_vfmt(ma, str, args1); \
|
||||
va_end(args1)
|
||||
|
||||
#if PLATFORM_TCC
|
||||
#define s8_vsnprintf vsnprintf
|
||||
#else
|
||||
#define s8_vsnprintf stbsp_vsnprintf
|
||||
#endif
|
||||
|
||||
#define STR_FMT(buff, str) \
|
||||
va_list args1; \
|
||||
va_start(args1, str); \
|
||||
i32 len = s8_vsnprintf(buff, sizeof(buff), str, args1); \
|
||||
va_end(args1)
|
||||
|
||||
typedef struct fuzzy_pair_t fuzzy_pair_t;
|
||||
struct fuzzy_pair_t {
|
||||
i64 index;
|
||||
i64 rating;
|
||||
};
|
||||
@@ -1,622 +0,0 @@
|
||||
#include "core_string16.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_intrin.h"
|
||||
#include "core_unicode.h"
|
||||
#include "core_ctx.h"
|
||||
|
||||
fn i64 str16_len(u16 *string) {
|
||||
i64 len = 0;
|
||||
while (*string++ != 0)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
fn u16 char16_to_lower_case(u16 a) {
|
||||
if (a >= 'A' && a <= 'Z') a += 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
fn u16 char16_to_upper_case(u16 a) {
|
||||
if (a >= 'a' && a <= 'z') a -= 32;
|
||||
return a;
|
||||
}
|
||||
|
||||
fn b32 char16_is_whitespace(u16 w) {
|
||||
b32 result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_alphabetic(u16 a) {
|
||||
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_ident(u16 a) {
|
||||
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_digit(u16 a) {
|
||||
b32 result = a >= '0' && a <= '9';
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_symbol(u16 w) {
|
||||
b32 result = (w >= '!' && w <= '/') || (w >= ':' && w <= '@') || (w >= '[' && w <= '`') || (w >= '{' && w <= '~');
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_non_word(u16 w) {
|
||||
b32 result = w != '_' && (char16_is_symbol(w) || char16_is_whitespace(w));
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_word(u16 w) {
|
||||
b32 result = !char16_is_non_word(w);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 char16_is_alphanumeric(u16 a) {
|
||||
b32 result = char16_is_digit(a) || char16_is_alphabetic(a);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_from_range(u16 *begin, u16 *end) {
|
||||
assert_expr(end >= begin);
|
||||
intptr_t size = (intptr_t)end - (intptr_t)begin;
|
||||
s16_t result = {begin, size / 2};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_from_str16(u16 *string) {
|
||||
s16_t result;
|
||||
result.str = string;
|
||||
result.len = str16_len(string);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_copy(ma_arena_t *ma, s16_t string) {
|
||||
i64 byte_size = sizeof(u16) * string.len;
|
||||
u16 *copy = (u16 *)ma_push_size(ma, byte_size + sizeof(u16));
|
||||
memory_copy(copy, string.str, byte_size);
|
||||
copy[string.len] = 0;
|
||||
s16_t result = s16_make(copy, string.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_copy_str16(ma_arena_t *ma, u16 *s) {
|
||||
return s16_copy(ma, s16_make(s, str16_len(s)));
|
||||
}
|
||||
|
||||
fn b32 s16_are_equal_ex(s16_t a, s16_t b, b32 ignore_case) {
|
||||
if (a.len != b.len) return false;
|
||||
for (i64 i = 0; i < a.len; i++) {
|
||||
u16 A = a.str[i];
|
||||
u16 B = b.str[i];
|
||||
if (ignore_case) {
|
||||
A = char16_to_lower_case(A);
|
||||
B = char16_to_lower_case(B);
|
||||
}
|
||||
if (A != B)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn b32 s16_are_equal(s16_t a, s16_t b) {
|
||||
return s16_are_equal_ex(a, b, false);
|
||||
}
|
||||
|
||||
fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string) {
|
||||
u16 *buffer = ma_push_array(ma, u16, string.len + 1);
|
||||
i64 len = wstr_from_str(buffer, string.len + 1, string.str, string.len);
|
||||
assert(len <= string.len); // @todo: verify
|
||||
return (s16_t){buffer, len};
|
||||
}
|
||||
|
||||
fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string) {
|
||||
i64 buffer_size = (string.len + 1) * 2;
|
||||
char *buffer = ma_push_array(ma, char, buffer_size);
|
||||
i64 len = str_from_wstr(buffer, buffer_size, string.str, string.len);
|
||||
assert(len < buffer_size);
|
||||
return (s8_t){buffer, len};
|
||||
}
|
||||
|
||||
fn s16_t s16_get_postfix(s16_t string, i64 len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
i64 remain_len = string.len - len;
|
||||
s16_t result = s16_make(string.str + remain_len, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_get_prefix(s16_t string, i64 len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
s16_t result = s16_make(string.str, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_chop(s16_t string, i64 len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
s16_t result = s16_make(string.str, string.len - len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_skip(s16_t string, i64 len) {
|
||||
len = CLAMP_TOP(len, string.len);
|
||||
i64 remain = string.len - len;
|
||||
s16_t result = s16_make(string.str + len, remain);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s16_ends_with_ex(s16_t a, s16_t end, b32 ignore_case) {
|
||||
s16_t a_end = s16_get_postfix(a, end.len);
|
||||
b32 result = s16_are_equal_ex(end, a_end, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s16_starts_with_ex(s16_t a, s16_t start, b32 ignore_case) {
|
||||
s16_t a_start = s16_get_prefix(a, start.len);
|
||||
b32 result = s16_are_equal_ex(start, a_start, ignore_case);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s16_ends_with(s16_t a, s16_t end) {
|
||||
return s16_ends_with_ex(a, end, false);
|
||||
}
|
||||
|
||||
fn b32 s16_starts_with(s16_t a, s16_t start) {
|
||||
return s16_ends_with_ex(a, start, false);
|
||||
}
|
||||
|
||||
fn void s16_normalize_path_unsafe(s16_t s) {
|
||||
for (i64 i = 0; i < s.len; i++) {
|
||||
if (s.str[i] == '\\')
|
||||
s.str[i] = '/';
|
||||
}
|
||||
}
|
||||
|
||||
fn s16_t s16_normalize_path(ma_arena_t *ma, s16_t s) {
|
||||
s16_t copy = s16_copy(ma, s);
|
||||
s16_normalize_path_unsafe(copy);
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn b32 s16_is_pointer_inside(s16_t string, u16 *p) {
|
||||
uintptr_t pointer = (uintptr_t)p;
|
||||
uintptr_t start = (uintptr_t)string.str;
|
||||
uintptr_t stop = start + (uintptr_t)string.len * sizeof(u16);
|
||||
b32 result = pointer >= start && pointer < stop;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_cut_start(s16_t *in, i64 size) {
|
||||
s16_t result = s16_get_prefix(*in, size);
|
||||
*in = s16_skip(*in, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_cut_end(s16_t *in, i64 size) {
|
||||
s16_t result = s16_get_postfix(*in, size);
|
||||
*in = s16_chop(*in, result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_slice(s16_t string, i64 first_index, i64 one_past_last_index) {
|
||||
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
|
||||
if (first_index < 0) first_index = string.len + first_index;
|
||||
assert(first_index < one_past_last_index);
|
||||
assert(string.len > 0);
|
||||
s16_t result = string;
|
||||
if (string.len > 0) {
|
||||
if (one_past_last_index > first_index) {
|
||||
first_index = CLAMP_TOP(first_index, string.len - 1);
|
||||
one_past_last_index = CLAMP_TOP(one_past_last_index, string.len);
|
||||
result.str += first_index;
|
||||
result.len = one_past_last_index - first_index;
|
||||
}
|
||||
else {
|
||||
result.len = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_trim(s16_t string) {
|
||||
if (string.len == 0)
|
||||
return string;
|
||||
|
||||
i64 whitespace_begin = 0;
|
||||
for (; whitespace_begin < string.len; whitespace_begin++) {
|
||||
if (!char16_is_whitespace(string.str[whitespace_begin])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i64 whitespace_end = string.len;
|
||||
for (; whitespace_end != whitespace_begin; whitespace_end--) {
|
||||
if (!char16_is_whitespace(string.str[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (whitespace_begin == whitespace_end) {
|
||||
string.len = 0;
|
||||
}
|
||||
else {
|
||||
string = s16_slice(string, whitespace_begin, whitespace_end);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
fn s16_t s16_trim_end(s16_t string) {
|
||||
i64 whitespace_end = string.len;
|
||||
for (; whitespace_end != 0; whitespace_end--) {
|
||||
if (!char16_is_whitespace(string.str[whitespace_end - 1])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s16_t result = s16_get_prefix(string, whitespace_end);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 s16_seek(s16_t string, s16_t find, s16_seek_t flags, int64_t *index_out) {
|
||||
b32 ignore_case = flags & s16_seek_ignore_case ? true : false;
|
||||
b32 result = false;
|
||||
if (flags & s16_seek_match_find_last) {
|
||||
for (int64_t i = string.len; i != 0; i--) {
|
||||
int64_t index = i - 1;
|
||||
s16_t substring = s16_slice(string, index, index + find.len);
|
||||
if (s16_are_equal_ex(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = index;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int64_t i = 0; i < string.len; i++) {
|
||||
s16_t substring = s16_slice(string, i, i + find.len);
|
||||
if (s16_are_equal_ex(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = i;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn int64_t s16_find(s16_t string, s16_t find, s16_seek_t flag) {
|
||||
int64_t result = -1;
|
||||
s16_seek(string, find, flag, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_chop_last_char(s16_t s, s16_t ch) {
|
||||
s16_t result = s;
|
||||
s16_seek(s, ch, s16_seek_match_find_last, &result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
// fn s16_t s16_chop_last_slash(s16_t s) {
|
||||
// return s16_chop_last_char(s, s16("/"));
|
||||
// }
|
||||
|
||||
// fn s16_t s16_chop_last_period(s16_t s) {
|
||||
// return s16_chop_last_char(s, s16("."));
|
||||
// }
|
||||
|
||||
fn s16_t s16_skip_to_last_char(s16_t s, s16_t ch) {
|
||||
int64_t pos;
|
||||
s16_t result = s;
|
||||
if (s16_seek(s, ch, s16_seek_match_find_last, &pos)) {
|
||||
result = s16_skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// fn s16_t s16_skip_to_last_slash(s16_t s) {
|
||||
// return s16_skip_to_last_char(s, s16("/"));
|
||||
// }
|
||||
|
||||
// fn s16_t s16_skip_to_last_period(s16_t s) {
|
||||
// return s16_skip_to_last_char(s, s16("."));
|
||||
// }
|
||||
|
||||
// fn s16_t s16_get_name_no_ext(s16_t s) {
|
||||
// return s16_skip_to_last_slash(s16_chop_last_period(s));
|
||||
// }
|
||||
|
||||
fn s16_t s16_to_lower_case(ma_arena_t *ma, s16_t s) {
|
||||
s16_t copy = s16_copy(ma, s);
|
||||
for (int64_t i = 0; i < copy.len; i++) {
|
||||
copy.str[i] = char16_to_lower_case(copy.str[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s16_t s16_to_upper_case(ma_arena_t *ma, s16_t s) {
|
||||
s16_t copy = s16_copy(ma, s);
|
||||
for (int64_t i = 0; i < copy.len; i++) {
|
||||
copy.str[i] = char16_to_upper_case(copy.str[i]);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn s16_t s16_printf(ma_arena_t *ma, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(ma);
|
||||
S8_FMT(scratch.arena, str, result);
|
||||
s16_t result16 = s16_from_s8(ma, result);
|
||||
ma_end_scratch(scratch);
|
||||
return result16;
|
||||
}
|
||||
|
||||
fn u64 u64_from_s16(s16_t s, u64 base) {
|
||||
assert(base >= 2 && base <= 16);
|
||||
u64 acc = 0;
|
||||
for (i64 i = 0; i < s.len; i++) {
|
||||
u64 num = u64_from_hexchar((char)s.str[i]);
|
||||
assert(num < base);
|
||||
acc *= base;
|
||||
acc += num;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
fn f64 f64_from_s16(s16_t string) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
s8_t num_string = s8_from_s16(scratch.arena, string);
|
||||
f64 result = os_parse_float(num_string.str);
|
||||
ma_end_scratch(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_read_only i64 s16_fuzzy_closer_word_begin = 5;
|
||||
gb_read_only i64 s16_fuzzy_consecutive_multiplier = 3;
|
||||
fn i64 s16_fuzzy_rate(s16_t string, s16_t with) {
|
||||
if (with.len == 0) return 0;
|
||||
|
||||
i64 points = 0;
|
||||
i64 consecutive = 0;
|
||||
i64 with_i = 0;
|
||||
for (i64 i = 0; i < string.len; i++) {
|
||||
if (string.str[i] == with.str[with_i]) {
|
||||
i64 closer_begin = CLAMP_BOT((i64)0, s16_fuzzy_closer_word_begin - i);
|
||||
points += closer_begin;
|
||||
consecutive++;
|
||||
with_i += 1;
|
||||
} else {
|
||||
points += consecutive * s16_fuzzy_consecutive_multiplier;
|
||||
consecutive = 0;
|
||||
with_i = 0;
|
||||
}
|
||||
|
||||
if (with_i >= with.len) with_i = 0;
|
||||
}
|
||||
points += consecutive * s16_fuzzy_consecutive_multiplier;
|
||||
return points;
|
||||
}
|
||||
|
||||
fn fuzzy_pair_t *s16_fuzzy_rate_array(ma_arena_t *arena, s16_t needle, s16_t *array, i32 len) {
|
||||
fuzzy_pair_t *pairs = ma_push_array(arena, fuzzy_pair_t, len);
|
||||
for (i32 i = 0; i < len; i += 1) {
|
||||
pairs[i].rating = s16_fuzzy_rate(array[i], needle);
|
||||
pairs[i].index = i;
|
||||
}
|
||||
|
||||
for (i32 i = 0; i < len - 1; i++) {
|
||||
for (i32 j = 0; j < len - 1; j++) {
|
||||
if (pairs[j].rating < pairs[j + 1].rating) {
|
||||
SWAP(fuzzy_pair_t, pairs[j], pairs[j + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
fn sb16_node_t *sb16_create_node(ma_arena_t *ma, s16_t str) {
|
||||
sb16_node_t *node = ma_push_type(ma, sb16_node_t);
|
||||
node->string = str;
|
||||
return node;
|
||||
}
|
||||
|
||||
fn sb16_node_t *sb16_append(sb16_t *list, s16_t string) {
|
||||
assert(list->arena != NULL);
|
||||
sb16_node_t *node = sb16_create_node(list->arena, string);
|
||||
SLLQ_APPEND(list->first, list->last, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
fn s16_t sb16_printf(sb16_t *sb, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(sb->arena);
|
||||
S8_FMT(scratch.arena, str, result);
|
||||
s16_t result16 = s16_from_s8(sb->arena, result);
|
||||
sb16_append(sb, result16);
|
||||
ma_end_scratch(scratch);
|
||||
return result16;
|
||||
}
|
||||
|
||||
fn void sb16_indent(sb16_t *sb) {
|
||||
sb16_printf(sb, "\n%.*s", sb->indent*4, " ");
|
||||
}
|
||||
|
||||
fn s16_t sb16_stmtf(sb16_t *sb, const char *str, ...) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(sb->arena);
|
||||
S8_FMT(scratch.arena, str, result);
|
||||
s16_t result16 = s16_from_s8(sb->arena, result);
|
||||
sb16_indent(sb);
|
||||
sb16_append(sb, result16);
|
||||
ma_end_scratch(scratch);
|
||||
return result16;
|
||||
}
|
||||
|
||||
fn int64_t sb16_char_size(sb16_t *sb) {
|
||||
int64_t result = 0;
|
||||
for (sb16_node_t *it = sb->first; it; it = it->next) {
|
||||
result += it->len;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t sb16_merge(ma_arena_t *arena, sb16_t *sb) {
|
||||
int64_t size = sb16_char_size(sb) + 1;
|
||||
i64 byte_size = size * sizeof(u16);
|
||||
u16 *str = ma_push_size(arena, byte_size);
|
||||
s16_t result = {str, 0};
|
||||
for (sb16_node_t *it = sb->first; it; it = it->next) {
|
||||
memory_copy(result.str + result.len, it->str, it->len * sizeof(u16));
|
||||
result.len += it->len;
|
||||
}
|
||||
result.str[result.len] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags) {
|
||||
sb16_t result = (sb16_t){ma};
|
||||
int64_t index = 0;
|
||||
|
||||
s16_seek_t find_flag = flags & s16_split_ignore_case ? s16_seek_ignore_case : s16_seek_none;
|
||||
while (s16_seek(string, find, find_flag, &index)) {
|
||||
s16_t before_match = s16_make(string.str, index);
|
||||
sb16_append(&result, before_match);
|
||||
if (flags & s16_split_inclusive) {
|
||||
s16_t match = s16_make(string.str + index, find.len);
|
||||
sb16_append(&result, match);
|
||||
}
|
||||
string = s16_skip(string, index + find.len);
|
||||
}
|
||||
if (string.len) sb16_append(&result, string);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s16_t s16_copy_ex(alo_t ma, s16_t string) {
|
||||
i64 byte_size = sizeof(u16) * string.len;
|
||||
u16 *copy = (u16 *)alloc_size(ma, byte_size + sizeof(u16));
|
||||
memory_copy(copy, string.str, byte_size);
|
||||
copy[string.len] = 0;
|
||||
s16_t result = s16_make(copy, string.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
fn_test void test_string16(void) {
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
|
||||
// string16 lit basic tests
|
||||
{
|
||||
s16_t a = s16("memes");
|
||||
assert(a.len == 5);
|
||||
assert(a.str[0] == char16('m'));
|
||||
assert(a.str[4] == char16('s'));
|
||||
s16_t b = s16("not memes");
|
||||
s16_t c = s16("MEMES");
|
||||
assert(s16_are_equal(a, b) == false);
|
||||
assert(s16_are_equal(a, a) == true);
|
||||
assert(s16_are_equal_ex(a, c, true) == true);
|
||||
}
|
||||
|
||||
{
|
||||
assert(char16_to_upper_case('a') == char16('A'));
|
||||
assert(char16_to_upper_case('a') == 'A');
|
||||
assert(char16_to_upper_case(char16('a')) == 'A');
|
||||
assert(char16_is_digit('3'));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16_from_str16(str16("memes"));
|
||||
assert(a.len == 5);
|
||||
assert(s16_are_equal(a, s16("memes")) == true);
|
||||
|
||||
s16_t b = s16_copy(scratch.arena, a);
|
||||
assert(a.str != b.str);
|
||||
assert(b.len == a.len);
|
||||
assert(s16_are_equal(a, b));
|
||||
|
||||
s16_t c = s16_from_range(a.str, a.str + a.len);
|
||||
assert(s16_are_equal(a, c));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16("thing itself");
|
||||
assert(s16_starts_with_ex(a, s16("thing"), false));
|
||||
assert(!s16_starts_with_ex(a, s16("thing itself and"), false));
|
||||
assert(!s16_starts_with_ex(a, s16("thing itself "), false));
|
||||
assert(s16_starts_with_ex(a, s16("THING"), true));
|
||||
assert(!s16_starts_with_ex(a, s16("a"), false));
|
||||
|
||||
assert(s16_ends_with_ex(a, s16("itself"), false));
|
||||
assert(s16_ends_with_ex(a, s16("thing itself"), false));
|
||||
assert(!s16_ends_with_ex(a, s16("thing itselfa"), false));
|
||||
|
||||
s16_t b = s16("memes");
|
||||
assert(s16_is_pointer_inside(b, b.str));
|
||||
assert(s16_is_pointer_inside(b, b.str + 4));
|
||||
assert(!s16_is_pointer_inside(b, b.str + 5));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16("C:\\Program Files\\Memes");
|
||||
u16 memes[256] = {0};
|
||||
memory_copy(memes, a.str, a.len * 2 + 2);
|
||||
s16_t b = s16_make(memes, a.len);
|
||||
|
||||
s16_normalize_path_unsafe(b);
|
||||
assert(b.str[2] == '/');
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16(" thing ");
|
||||
s16_t b = s16_trim(a);
|
||||
assert(s16_are_equal(b, s16("thing")));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16_printf(scratch.arena, "%d", 432);
|
||||
assert(s16_are_equal(a, s16("432")));
|
||||
assert(f64_from_s16(s16("432.0")) == 432.0);
|
||||
assert(u64_from_s16(s16("432"), 10) == 432);
|
||||
}
|
||||
|
||||
{
|
||||
sb16_t *list = sb16_serial_begin(scratch.arena);
|
||||
sb16_printf(list, "%d ", 987);
|
||||
sb16_printf(list, "ter ");
|
||||
sb16_printf(list, "|");
|
||||
s16_t string = sb16_serial_end(scratch.arena, list);
|
||||
assert(s16_are_equal(string, s16("987 ter |")));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16("A|B|dek|mek|vek|");
|
||||
sb16_t b = s16_split(scratch.arena, a, s16("|"), s16_split_none);
|
||||
assert(s16_are_equal(b.first->string, s16("A")));
|
||||
assert(s16_are_equal(b.first->next->string, s16("B")));
|
||||
assert(s16_are_equal(b.first->next->next->string, s16("dek")));
|
||||
assert(s16_are_equal(b.first->next->next->next->string, s16("mek")));
|
||||
assert(s16_are_equal(b.first->next->next->next->next->string, s16("vek")));
|
||||
assert(b.first->next->next->next->next->next == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16_to_upper_case(scratch.arena, s16("thing Meme"));
|
||||
assert(s16_are_equal(a, s16("THING MEME")));
|
||||
|
||||
a = s16_to_lower_case(scratch.arena, s16("THING Meme"));
|
||||
assert(s16_are_equal(a, s16("thing meme")));
|
||||
}
|
||||
|
||||
{
|
||||
s16_t a = s16("C:/thing/itself");
|
||||
assert(s16_are_equal(s16_chop_last_slash(a), s16("C:/thing")));
|
||||
}
|
||||
|
||||
ma_end_scratch(scratch);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,128 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
|
||||
typedef struct s16_t s16_t;
|
||||
struct s16_t {
|
||||
u16 *str;
|
||||
i64 len;
|
||||
};
|
||||
|
||||
typedef struct sb16_node_t sb16_node_t;
|
||||
struct sb16_node_t {
|
||||
sb16_node_t *next;
|
||||
union {
|
||||
struct { u16 *str; int64_t len; };
|
||||
s16_t string;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct sb16_t sb16_t;
|
||||
struct sb16_t {
|
||||
ma_arena_t *arena;
|
||||
sb16_node_t *first;
|
||||
sb16_node_t *last;
|
||||
|
||||
// WARNING: remember to update typeinfo after editing this
|
||||
i32 indent;
|
||||
};
|
||||
|
||||
typedef i32 s16_seek_t;
|
||||
enum {
|
||||
s16_seek_none = 0,
|
||||
s16_seek_ignore_case = 1,
|
||||
s16_seek_match_find_last = 2,
|
||||
};
|
||||
|
||||
typedef i32 s16_split_t;
|
||||
enum {
|
||||
s16_split_none = 0,
|
||||
s16_split_ignore_case = 1,
|
||||
s16_split_inclusive = 2,
|
||||
};
|
||||
|
||||
enum { s16_ignore_case = 1 };
|
||||
|
||||
|
||||
typedef struct s32_t s32_t;
|
||||
struct s32_t {
|
||||
u32 *str;
|
||||
i64 len;
|
||||
};
|
||||
|
||||
#define s16_make(str,len) (s16_t){str, len}
|
||||
|
||||
#define s16(str) (s16_t){(u16 *)u##str, lengthof(str) - 1}
|
||||
#define s16_const(string) { (u16 *)u##string, lengthof(string) - 1 }
|
||||
#define s16_invalid s16_lit("<INVALID>")
|
||||
#define s16_null (s16_t){0}
|
||||
|
||||
#define str16(str) ((u16 *)u##str)
|
||||
#define char16(str) ((u16)u##str)
|
||||
|
||||
#define sb16(ARENA) &(sb16_t){.arena = arena}
|
||||
#define sb16_serial_begin(ARENA) &(sb16_t){.arena = ARENA}
|
||||
#define sb16_serial_end(ARENA, SB) sb16_merge(ARENA, SB)
|
||||
|
||||
fn i64 str16_len(u16 *string);
|
||||
fn u16 char16_to_lower_case(u16 a);
|
||||
fn u16 char16_to_upper_case(u16 a);
|
||||
fn b32 char16_is_whitespace(u16 w);
|
||||
fn b32 char16_is_alphabetic(u16 a);
|
||||
fn b32 char16_is_ident(u16 a);
|
||||
fn b32 char16_is_digit(u16 a);
|
||||
fn b32 char16_is_symbol(u16 w);
|
||||
fn b32 char16_is_non_word(u16 w);
|
||||
fn b32 char16_is_word(u16 w);
|
||||
fn b32 char16_is_alphanumeric(u16 a);
|
||||
fn s16_t s16_from_range(u16 *begin, u16 *end);
|
||||
fn s16_t s16_from_str16(u16 *string);
|
||||
fn s16_t s16_copy(ma_arena_t *ma, s16_t string);
|
||||
fn s16_t s16_copy_str16(ma_arena_t *ma, u16 *s);
|
||||
fn b32 s16_are_equal_ex(s16_t a, s16_t b, b32 ignore_case);
|
||||
fn b32 s16_are_equal(s16_t a, s16_t b);
|
||||
fn s16_t s16_from_s8(ma_arena_t *ma, s8_t string);
|
||||
fn s8_t s8_from_s16(ma_arena_t *ma, s16_t string);
|
||||
fn s16_t s16_get_postfix(s16_t string, i64 len);
|
||||
fn s16_t s16_get_prefix(s16_t string, i64 len);
|
||||
fn s16_t s16_chop(s16_t string, i64 len);
|
||||
fn s16_t s16_skip(s16_t string, i64 len);
|
||||
fn b32 s16_ends_with_ex(s16_t a, s16_t end, b32 ignore_case);
|
||||
fn b32 s16_starts_with_ex(s16_t a, s16_t start, b32 ignore_case);
|
||||
fn b32 s16_ends_with(s16_t a, s16_t end);
|
||||
fn b32 s16_starts_with(s16_t a, s16_t start);
|
||||
fn void s16_normalize_path_unsafe(s16_t s);
|
||||
fn s16_t s16_normalize_path(ma_arena_t *ma, s16_t s);
|
||||
fn b32 s16_is_pointer_inside(s16_t string, u16 *p);
|
||||
fn s16_t s16_cut_start(s16_t *in, i64 size);
|
||||
fn s16_t s16_cut_end(s16_t *in, i64 size);
|
||||
fn s16_t s16_slice(s16_t string, i64 first_index, i64 one_past_last_index);
|
||||
fn s16_t s16_trim(s16_t string);
|
||||
fn s16_t s16_trim_end(s16_t string);
|
||||
fn b32 s16_seek(s16_t string, s16_t find, s16_seek_t flags, int64_t *index_out);
|
||||
fn int64_t s16_find(s16_t string, s16_t find, s16_seek_t flag);
|
||||
fn s16_t s16_chop_last_char(s16_t s, s16_t ch);
|
||||
fn s16_t s16_chop_last_slash(s16_t s);
|
||||
fn s16_t s16_chop_last_period(s16_t s);
|
||||
fn s16_t s16_skip_to_last_char(s16_t s, s16_t ch);
|
||||
fn s16_t s16_skip_to_last_slash(s16_t s);
|
||||
fn s16_t s16_skip_to_last_period(s16_t s);
|
||||
fn s16_t s16_get_name_no_ext(s16_t s);
|
||||
fn s16_t s16_to_lower_case(ma_arena_t *ma, s16_t s);
|
||||
fn s16_t s16_to_upper_case(ma_arena_t *ma, s16_t s);
|
||||
fn s16_t s16_printf(ma_arena_t *ma, const char *str, ...);
|
||||
fn u64 u64_from_s16(s16_t s, u64 base);
|
||||
fn f64 f64_from_s16(s16_t string);
|
||||
fn i64 s16_fuzzy_rate(s16_t string, s16_t with);
|
||||
fn fuzzy_pair_t *s16_fuzzy_rate_array(ma_arena_t *arena, s16_t needle, s16_t *array, i32 len);
|
||||
fn sb16_node_t *sb16_create_node(ma_arena_t *ma, s16_t str);
|
||||
fn sb16_node_t *sb16_append(sb16_t *list, s16_t string);
|
||||
fn s16_t sb16_printf(sb16_t *sb, const char *str, ...);
|
||||
fn void sb16_indent(sb16_t *sb);
|
||||
fn s16_t sb16_stmtf(sb16_t *sb, const char *str, ...);
|
||||
fn int64_t sb16_char_size(sb16_t *sb);
|
||||
fn s16_t sb16_merge(ma_arena_t *arena, sb16_t *sb);
|
||||
fn sb16_t s16_split(ma_arena_t *ma, s16_t string, s16_t find, s16_split_t flags);
|
||||
fn s16_t s16_copy_ex(alo_t ma, s16_t string);
|
||||
fn_test void test_string16(void);
|
||||
@@ -1,466 +0,0 @@
|
||||
#include "core_type_info.h"
|
||||
#include "core_platform.h"
|
||||
#include "core_log.h"
|
||||
#include "core_lexer.h"
|
||||
|
||||
fn s8_t ti_enum_value_to_name(i64 value, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *it = type->members + i;
|
||||
if (value == it->value) {
|
||||
return it->name;
|
||||
}
|
||||
}
|
||||
return s8("invalid");
|
||||
}
|
||||
|
||||
fn i64 ti_enum_name_to_value(s8_t name, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *it = type->members + i;
|
||||
if (s8_are_equal(it->name, name)) {
|
||||
return it->value;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
fn i64 ti_enum_read_value(void *p, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
i64 value = 0;
|
||||
if (type->size == 1) {
|
||||
value = *(i8 *)p;
|
||||
} else if (type->size == 2) {
|
||||
value = *(i16 *)p;
|
||||
} else if (type->size == 4) {
|
||||
value = *(i32 *)p;
|
||||
} else if (type->size == 8) {
|
||||
value = *(i64 *)p;
|
||||
} else {
|
||||
fatalf("invalid size of enum: %d", type->size);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
fn void ti_enum_write_value(void *p, i64 value, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
if (type->size == 1) {
|
||||
*(i8 *)p = (i8)value;
|
||||
} else if (type->size == 2) {
|
||||
*(i16 *)p = (i16)value;
|
||||
} else if (type->size == 4) {
|
||||
*(i32 *)p = (i32)value;
|
||||
} else if (type->size == 8) {
|
||||
*(i64 *)p = (i64)value;
|
||||
} else {
|
||||
fatalf("invalid size of enum: %d", type->size);
|
||||
}
|
||||
}
|
||||
|
||||
fn i64 ti_enum_next_value(i64 value, type_t *type) {
|
||||
assert(type->kind == type_kind_enum);
|
||||
i32 next_i = 0;
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *it = type->members + i;
|
||||
if (value == it->value) {
|
||||
if (i + 1 < type->count) {
|
||||
next_i = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type_member_t *tm = type->members + next_i;
|
||||
return tm->value;
|
||||
}
|
||||
|
||||
fn type_member_t *ti_get_member(s8_t name, type_t *type) {
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *it = type->members + i;
|
||||
if (s8_are_equal(it->name, name)) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn void *ti_extract_member(void *p, type_member_t *tm) {
|
||||
u8 *p8 = (u8 *)p;
|
||||
u8 *result = p8 + tm->offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void *ti_extract_array_idx(void *p, type_t *type, i32 idx) {
|
||||
assert(idx < type->count);
|
||||
|
||||
u8 *p8 = (u8 *)p;
|
||||
u8 *result = p8 + type->base->size * idx;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ti__serial_data_ex(sb8_t *sb, void *p, type_t *type) {
|
||||
assert(type->kind != type_kind_invalid);
|
||||
|
||||
switch(type->kind) {
|
||||
case type_kind_i8: {
|
||||
i8 n = *(i8 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i16: {
|
||||
i16 n = *(i16 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i32: {
|
||||
i32 n = *(i32 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i64: {
|
||||
i64 n = *(i64 *)p;
|
||||
sb8_printf(sb, "%lld", (long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u8: {
|
||||
u8 n = *(u8 *)p;
|
||||
sb8_printf(sb, "%u", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u16: {
|
||||
u16 n = *(u16 *)p;
|
||||
sb8_printf(sb, "%u", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u32: {
|
||||
u32 n = *(u32 *)p;
|
||||
sb8_printf(sb, "%u", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u64: {
|
||||
u64 n = *(u64 *)p;
|
||||
sb8_printf(sb, "%llu", (unsigned long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b8: {
|
||||
b8 n = *(b8 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b16: {
|
||||
b16 n = *(b16 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b32: {
|
||||
b32 n = *(b32 *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b64: {
|
||||
b64 n = *(b64 *)p;
|
||||
sb8_printf(sb, "%lld", (long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_f32: {
|
||||
f32 n = *(f32 *)p;
|
||||
sb8_printf(sb, "%f", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_f64: {
|
||||
f64 n = *(f64 *)p;
|
||||
sb8_printf(sb, "%f", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_isize: {
|
||||
isize n = *(isize *)p;
|
||||
sb8_printf(sb, "%lld", (long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_usize: {
|
||||
usize n = *(usize *)p;
|
||||
sb8_printf(sb, "%llu", (unsigned long long)n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_int: {
|
||||
int n = *(int *)p;
|
||||
sb8_printf(sb, "%d", n);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_char: {
|
||||
char n = *(char *)p;
|
||||
sb8_printf(sb, "%c", n);
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (type == &type__s8_t) {
|
||||
s8_t n = *(s8_t *)p;
|
||||
sb8_printf(sb, "\"%.*s\"", s8_fmtspec(n));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (type->kind == type_kind_pointer) {
|
||||
sb8_printf(sb, "0x%x", p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_enum) {
|
||||
i64 value = ti_enum_read_value(p, type);
|
||||
s8_t s = ti_enum_value_to_name(value, type);
|
||||
sb8_append(sb, s);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_array) {
|
||||
sb8_printf(sb, "{");
|
||||
sb->indent += 1;
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
void *mem_p = ti_extract_array_idx(p, type, i);
|
||||
sb8_indent(sb);
|
||||
ti__serial_data_ex(sb, mem_p, type->base);
|
||||
sb8_printf(sb, ",");
|
||||
}
|
||||
sb->indent -= 1;
|
||||
sb8_stmtf(sb, "}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_struct) {
|
||||
sb8_printf(sb, "{");
|
||||
sb->indent += 1;
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *mem = type->members + i;
|
||||
void *mem_p = ti_extract_member(p, mem);
|
||||
sb8_indent(sb);
|
||||
sb8_printf(sb, "%.*s: ", s8_fmtspec(mem->name));
|
||||
ti__serial_data_ex(sb, mem_p, mem->type);
|
||||
sb8_printf(sb, ",");
|
||||
}
|
||||
sb->indent -= 1;
|
||||
sb8_stmtf(sb, "}");
|
||||
return;
|
||||
}
|
||||
|
||||
fatalf("can't serialize: unhandled type");
|
||||
}
|
||||
|
||||
fn s8_t ti__serial_data(ma_arena_t *arena, void *p, type_t *type) {
|
||||
ma_temp_t scratch = ma_begin_scratch1(arena);
|
||||
sb8_t *sb = sb8_serial_begin(scratch.arena);
|
||||
ti__serial_data_ex(sb, p, type);
|
||||
s8_t string = sb8_serial_end(arena, sb);
|
||||
ma_end_scratch(scratch);
|
||||
return string;
|
||||
}
|
||||
|
||||
fn i64 ti__parser_match_i64(parser_t *par) {
|
||||
i64 minus = 1;
|
||||
if (parser_match(par, lex_kind_minus)) {
|
||||
minus = -1;
|
||||
}
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
i64 result = (i64)token->integer * minus;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn void ti__deserial_data_ex(ma_arena_t *arena, parser_t *par, void *p, type_t *type) {
|
||||
switch(type->kind) {
|
||||
case type_kind_i8: {
|
||||
i8 *n = (i8 *)p;
|
||||
n[0] = (i8)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i16: {
|
||||
i16 *n = (i16 *)p;
|
||||
n[0] = (i16)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i32: {
|
||||
i32 *n = (i32 *)p;
|
||||
n[0] = (i32)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_i64: {
|
||||
i64 *n = (i64 *)p;
|
||||
n[0] = (i64)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b8: {
|
||||
b8 *n = (b8 *)p;
|
||||
n[0] = (b8)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b16: {
|
||||
b16 *n = (b16 *)p;
|
||||
n[0] = (b16)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b32: {
|
||||
b32 *n = (b32 *)p;
|
||||
n[0] = (b32)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_b64: {
|
||||
b64 *n = (b64 *)p;
|
||||
n[0] = (b64)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u8: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
u8 *n = (u8 *)p;
|
||||
n[0] = (u8)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u16: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
u16 *n = (u16 *)p;
|
||||
n[0] = (u16)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u32: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
u32 *n = (u32 *)p;
|
||||
n[0] = (u32)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_u64: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
u64 *n = (u64 *)p;
|
||||
n[0] = (u64)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_f32: {
|
||||
lex_t *token = parser_expect(par, lex_kind_real);
|
||||
f32 *n = (f32 *)p;
|
||||
n[0] = (f32)token->real;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_f64: {
|
||||
lex_t *token = parser_expect(par, lex_kind_real);
|
||||
f64 *n = (f64 *)p;
|
||||
n[0] = token->real;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_isize: {
|
||||
isize *n = (isize *)p;
|
||||
n[0] = (isize)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_usize: {
|
||||
lex_t *token = parser_expect(par, lex_kind_integer);
|
||||
usize *n = (usize *)p;
|
||||
n[0] = (usize)token->integer;
|
||||
return;
|
||||
} break;
|
||||
case type_kind_int: {
|
||||
int *n = (int *)p;
|
||||
n[0] = (int)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
case type_kind_char: {
|
||||
char *n = (char *)p;
|
||||
n[0] = (char)ti__parser_match_i64(par);
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (type == &type__s8_t) {
|
||||
lex_t *token = parser_expect(par, lex_kind_string);
|
||||
s8_t *n = (s8_t *)p;
|
||||
n[0] = s8_copy(arena, token->string);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_enum) {
|
||||
lex_t *token = parser_expect(par, lex_kind_ident);
|
||||
i64 value = ti_enum_name_to_value(token->string, type);
|
||||
if (value == -1) {
|
||||
fatalf("invalid enum value: %.*s", s8_fmtspec(token->string));
|
||||
}
|
||||
|
||||
ti_enum_write_value(p, value, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_struct) {
|
||||
#if 0
|
||||
parser_expect(par, lex_kind_open_brace);
|
||||
while (!parser_match(par, lex_kind_close_brace)) {
|
||||
lex_t *ident = parser_expect(par, lex_kind_ident);
|
||||
parser_expect(par, lex_kind_colon);
|
||||
|
||||
type_member_t *mem = ti_get_member(type, ident->string);
|
||||
if (mem) {
|
||||
u8 *mem_p = p8 + mem->offset;
|
||||
ti__deserial_data_ex(arena, par, mem_p, mem->type);
|
||||
} else {
|
||||
debugf("deserial - skipping field: %.*s", s8_fmtspec(ident->string));
|
||||
parser_eat_until(par, lex_kind_comma);
|
||||
}
|
||||
|
||||
parser_expect(par, lex_kind_comma);
|
||||
}
|
||||
|
||||
#else // strict
|
||||
parser_expect(par, lex_kind_open_brace);
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
type_member_t *mem = type->members + i;
|
||||
void *memp = ti_extract_member(p, mem);
|
||||
|
||||
lex_t *ident = parser_expect(par, lex_kind_ident);
|
||||
parser_expect(par, lex_kind_colon);
|
||||
|
||||
expect (s8_are_equal(ident->string, mem->name)) fatalf("expected identifier: %.*s, got instead %.*s", s8_fmtspec(mem->name), s8_fmtspec(ident->string));
|
||||
|
||||
ti__deserial_data_ex(arena, par, memp, mem->type);
|
||||
parser_expect(par, lex_kind_comma);
|
||||
}
|
||||
parser_expect(par, lex_kind_close_brace);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (type->kind == type_kind_array) {
|
||||
parser_expect(par, lex_kind_open_brace);
|
||||
for (i32 i = 0; i < type->count; i += 1) {
|
||||
void *memp = ti_extract_array_idx(p, type, i);
|
||||
ti__deserial_data_ex(arena, par, memp, type->base);
|
||||
parser_expect(par, lex_kind_comma);
|
||||
}
|
||||
parser_expect(par, lex_kind_close_brace);
|
||||
}
|
||||
}
|
||||
|
||||
fn void *ti__deserial_data(ma_arena_t *arena, s8_t data, type_t *type) {
|
||||
void *p = ma_push_size(arena, type->size);
|
||||
ma_temp_t scratch = ma_begin_scratch();
|
||||
lex_array_t tokens = lex_tokens(scratch.arena, "data serializing", data);
|
||||
parser_t *par = parser_make(scratch.arena, tokens.data);
|
||||
ti__deserial_data_ex(arena, par, p, type);
|
||||
ma_end_scratch(scratch);
|
||||
return p;
|
||||
}
|
||||
|
||||
fn b32 ti_is_basic(type_t *type) {
|
||||
b32 result = type->kind >= type_kind_first_basic && type->kind <= type_kind_last_basic;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn b32 ti_has_type_name(type_t *type) {
|
||||
b32 result = ti_is_basic(type) || type->kind == type_kind_struct || type->kind == type_kind_enum || type->kind == type_kind_union;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn s8_t ti_serial_type(ma_arena_t *arena, type_t *type) {
|
||||
if (ti_has_type_name(type)) {
|
||||
return type->name;
|
||||
} else if (type->kind == type_kind_pointer) {
|
||||
s8_t name = ti_serial_type(arena, type->base);
|
||||
return s8_printf(arena, "%.*s*", s8_fmtspec(name));
|
||||
} else if (type->kind == type_kind_array) {
|
||||
s8_t name = ti_serial_type(arena, type->base);
|
||||
return s8_printf(arena, "%.*s[%d]", s8_fmtspec(name), type->count);
|
||||
} else_is_invalid;
|
||||
return s8_invalid;
|
||||
}
|
||||
@@ -1,364 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
#include "core_arena.h"
|
||||
#include "core_string.h"
|
||||
#include "core_string16.h"
|
||||
#include "core_math.h"
|
||||
|
||||
typedef int type_kind_t;
|
||||
enum {
|
||||
type_kind_invalid,
|
||||
|
||||
type_kind_i8,
|
||||
type_kind_i16,
|
||||
type_kind_i32,
|
||||
type_kind_i64,
|
||||
type_kind_b8,
|
||||
type_kind_b16,
|
||||
type_kind_b32,
|
||||
type_kind_b64,
|
||||
type_kind_u8,
|
||||
type_kind_u16,
|
||||
type_kind_u32,
|
||||
type_kind_u64,
|
||||
type_kind_f32,
|
||||
type_kind_f64,
|
||||
type_kind_isize,
|
||||
type_kind_usize,
|
||||
type_kind_int,
|
||||
type_kind_char,
|
||||
type_kind_void,
|
||||
|
||||
type_kind_pointer,
|
||||
type_kind_array,
|
||||
type_kind_struct,
|
||||
type_kind_union,
|
||||
type_kind_enum,
|
||||
|
||||
type_kind_first_basic = type_kind_i8,
|
||||
type_kind_last_basic = type_kind_void,
|
||||
};
|
||||
|
||||
typedef struct type_t type_t;
|
||||
struct type_t {
|
||||
type_kind_t kind;
|
||||
s8_t name;
|
||||
i32 size;
|
||||
i32 count;
|
||||
struct type_member_t *members;
|
||||
type_t *base;
|
||||
};
|
||||
|
||||
typedef struct type_member_t type_member_t;
|
||||
struct type_member_t {
|
||||
s8_t name;
|
||||
type_t *type;
|
||||
i64 value;
|
||||
u64 offset;
|
||||
b8 dont_serialize;
|
||||
};
|
||||
|
||||
typedef struct mt_tweak_t mt_tweak_t;
|
||||
struct mt_tweak_t {
|
||||
type_t *type;
|
||||
s8_t name;
|
||||
void *ptr;
|
||||
f32 min, max;
|
||||
};
|
||||
#define mt_embed_file(name, path)
|
||||
#define mt_tweak_f32(name, default, min, max)
|
||||
#define mt_tweak_color(name, ...)
|
||||
#define mt_tweak_b32(name, default)
|
||||
|
||||
//
|
||||
// serialization to string
|
||||
#define ti_deserial_data(ARENA, DATA, TYPE) (TYPE *)ti__deserial_data(ARENA, DATA, type(TYPE))
|
||||
#define ti_serial_data(ARENA, DATA, TYPE) ti__serial_data(ARENA, DATA, type(TYPE))
|
||||
|
||||
fn void *ti__deserial_data(ma_arena_t *arena, s8_t data, type_t *type);
|
||||
fn s8_t ti__serial_data(ma_arena_t *arena, void *p, type_t *type);
|
||||
|
||||
//
|
||||
// utilities
|
||||
fn s8_t ti_enum_value_to_name(i64 value, type_t *type);
|
||||
fn i64 ti_enum_name_to_value(s8_t name, type_t *type);
|
||||
fn type_member_t *ti_get_member(s8_t name, type_t *type);
|
||||
|
||||
//
|
||||
// core type info data
|
||||
#define type(X) (&type__##X)
|
||||
#define DEFINE_ENUM(x) type_t type__##x = {type_kind_enum, s8_const(#x), sizeof(x), .members = members__##x, .count = lengthof(members__##x)}
|
||||
#define DEFINE_STRUCT(x) type_t type__##x = {type_kind_struct, s8_const(#x), sizeof(x), .members = members__##x, .count = lengthof(members__##x)}
|
||||
#define POINTER(x) (type_t){type_kind_pointer, s8_const(#x "*"), sizeof(void *), .base = &type__##x}
|
||||
|
||||
static gb_read_only type_t type__i8 = {type_kind_i8, s8_const("i8"), sizeof(i8)};
|
||||
static gb_read_only type_t type__i16 = {type_kind_i16, s8_const("i16"), sizeof(i16)};
|
||||
static gb_read_only type_t type__i32 = {type_kind_i32, s8_const("i32"), sizeof(i32)};
|
||||
static gb_read_only type_t type__i64 = {type_kind_i64, s8_const("i64"), sizeof(i64)};
|
||||
static gb_read_only type_t type__u8 = {type_kind_u8, s8_const("u8"), sizeof(u8)};
|
||||
static gb_read_only type_t type__u16 = {type_kind_u16, s8_const("u16"), sizeof(u16)};
|
||||
static gb_read_only type_t type__u32 = {type_kind_u32, s8_const("u32"), sizeof(u32)};
|
||||
static gb_read_only type_t type__u64 = {type_kind_u64, s8_const("u64"), sizeof(u64)};
|
||||
static gb_read_only type_t type__b8 = {type_kind_b8, s8_const("b8"), sizeof(b8)};
|
||||
static gb_read_only type_t type__b16 = {type_kind_b16, s8_const("b16"), sizeof(b16)};
|
||||
static gb_read_only type_t type__b32 = {type_kind_b32, s8_const("b32"), sizeof(b32)};
|
||||
static gb_read_only type_t type__b64 = {type_kind_b64, s8_const("b64"), sizeof(b64)};
|
||||
static gb_read_only type_t type__f32 = {type_kind_f32, s8_const("f32"), sizeof(f32)};
|
||||
static gb_read_only type_t type__f64 = {type_kind_f64, s8_const("f64"), sizeof(f64)};
|
||||
static gb_read_only type_t type__isize = {type_kind_isize, s8_const("isize"), sizeof(isize)};
|
||||
static gb_read_only type_t type__usize = {type_kind_usize, s8_const("usize"), sizeof(usize)};
|
||||
static gb_read_only type_t type__int = {type_kind_int, s8_const("int"), sizeof(int)};
|
||||
static gb_read_only type_t type__char = {type_kind_char, s8_const("char"), sizeof(char)};
|
||||
static gb_read_only type_t type__void = {type_kind_void, s8_const("void")};
|
||||
|
||||
static gb_read_only type_t type__s8_t = { type_kind_struct, s8_const("s8_t"), sizeof(s8_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("str"), &POINTER(char), .offset = offsetof(s8_t, str)},
|
||||
{s8_const("len"), &type__i64, .offset = offsetof(s8_t, len)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__s16_t = { type_kind_struct, s8_const("s16_t"), sizeof(s16_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("str"), &POINTER(u16), .offset = offsetof(s16_t, str)},
|
||||
{s8_const("len"), &type__i64, .offset = offsetof(s16_t, len)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__s32_t = { type_kind_struct, s8_const("s32_t"), sizeof(s32_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("str"), &POINTER(u32), .offset = offsetof(s32_t, str)},
|
||||
{s8_const("len"), &type__i64, .offset = offsetof(s32_t, len)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__ma_arena_t = { type_kind_struct, s8_const("ma_arena_t"), sizeof(ma_arena_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("data"), &POINTER(u8), .offset = offsetof(ma_arena_t, data)},
|
||||
{s8_const("len"), &type__usize, .offset = offsetof(ma_arena_t, len)},
|
||||
{s8_const("base_len"), &type__usize, .offset = offsetof(ma_arena_t, base_len)},
|
||||
{s8_const("reserve"), &type__usize, .offset = offsetof(ma_arena_t, reserve)},
|
||||
{s8_const("commit"), &type__usize, .offset = offsetof(ma_arena_t, commit)},
|
||||
{s8_const("align"), &type__usize, .offset = offsetof(ma_arena_t, align)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__sb8_node_t = {type_kind_struct, s8_const("sb8_node_t"), sizeof(sb8_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("next"), &POINTER(sb8_node_t), .offset = offsetof(sb8_node_t, next)},
|
||||
{s8_const("string"), &type__s8_t, .offset = offsetof(sb8_node_t, string)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__sb8_t = { type_kind_struct, s8_const("sb8_t"), sizeof(sb8_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("arena"), &POINTER(ma_arena_t), .offset = offsetof(sb8_t, arena)},
|
||||
{s8_const("first"), &POINTER(sb8_node_t), .offset = offsetof(sb8_t, first)},
|
||||
{s8_const("last"), &POINTER(sb8_node_t), .offset = offsetof(sb8_t, last)},
|
||||
{s8_const("indent"), &type__i32, .offset = offsetof(sb8_t, indent)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__ma_temp_t = { type_kind_struct, s8_const("ma_temp_t"), sizeof(ma_temp_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("arena"), &POINTER(ma_arena_t), .offset = offsetof(ma_temp_t, arena)},
|
||||
{s8_const("len"), &type__usize, .offset = offsetof(ma_temp_t, len)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v2f32_t = { type_kind_struct, s8_const("v2f32_t"), sizeof(v2f32_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f32, .offset = offsetof(v2f32_t, x)},
|
||||
{s8_const("y"), &type__f32, .offset = offsetof(v2f32_t, y)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v3f32_t = { type_kind_struct, s8_const("v3f32_t"), sizeof(v3f32_t), .count = 3,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f32, .offset = offsetof(v3f32_t, x)},
|
||||
{s8_const("y"), &type__f32, .offset = offsetof(v3f32_t, y)},
|
||||
{s8_const("z"), &type__f32, .offset = offsetof(v3f32_t, z)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v4f32_t = { type_kind_struct, s8_const("v4f32_t"), sizeof(v4f32_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f32, .offset = offsetof(v4f32_t, x)},
|
||||
{s8_const("y"), &type__f32, .offset = offsetof(v4f32_t, y)},
|
||||
{s8_const("z"), &type__f32, .offset = offsetof(v4f32_t, z)},
|
||||
{s8_const("w"), &type__f32, .offset = offsetof(v4f32_t, w)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__r3f32_t = { type_kind_struct, s8_const("r3f32_t"), sizeof(r3f32_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x0"), &type__f32, .offset = offsetof(r3f32_t, x0)},
|
||||
{s8_const("y0"), &type__f32, .offset = offsetof(r3f32_t, y0)},
|
||||
{s8_const("x0"), &type__f32, .offset = offsetof(r3f32_t, z0)},
|
||||
{s8_const("x1"), &type__f32, .offset = offsetof(r3f32_t, x1)},
|
||||
{s8_const("y1"), &type__f32, .offset = offsetof(r3f32_t, y1)},
|
||||
{s8_const("x1"), &type__f32, .offset = offsetof(r3f32_t, z1)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_member_t members__r2f32_t[] = {
|
||||
{s8_const("x0"), &type__f32, .offset = offsetof(r2f32_t, x0)},
|
||||
{s8_const("y0"), &type__f32, .offset = offsetof(r2f32_t, y0)},
|
||||
{s8_const("x1"), &type__f32, .offset = offsetof(r2f32_t, x1)},
|
||||
{s8_const("y1"), &type__f32, .offset = offsetof(r2f32_t, y1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r2f32_t);
|
||||
|
||||
static gb_read_only type_member_t members__r1f32_t[] = {
|
||||
{s8_const("x0"), &type__f32, .offset = offsetof(r1f32_t, x0)},
|
||||
{s8_const("x1"), &type__f32, .offset = offsetof(r1f32_t, x1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r1f32_t);
|
||||
|
||||
static gb_read_only type_t type__v2f64_t = { type_kind_struct, s8_const("v2f64_t"), sizeof(v2f64_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f64, .offset = offsetof(v2f64_t, x)},
|
||||
{s8_const("y"), &type__f64, .offset = offsetof(v2f64_t, y)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v3f64_t = { type_kind_struct, s8_const("v3f64_t"), sizeof(v3f64_t), .count = 3,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f64, .offset = offsetof(v3f64_t, x)},
|
||||
{s8_const("y"), &type__f64, .offset = offsetof(v3f64_t, y)},
|
||||
{s8_const("z"), &type__f64, .offset = offsetof(v3f64_t, z)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v4f64_t = { type_kind_struct, s8_const("v4f64_t"), sizeof(v4f64_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__f64, .offset = offsetof(v4f64_t, x)},
|
||||
{s8_const("y"), &type__f64, .offset = offsetof(v4f64_t, y)},
|
||||
{s8_const("z"), &type__f64, .offset = offsetof(v4f64_t, z)},
|
||||
{s8_const("w"), &type__f64, .offset = offsetof(v4f64_t, w)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__r3f64_t = { type_kind_struct, s8_const("r3f64_t"), sizeof(r3f64_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, x0)},
|
||||
{s8_const("y0"), &type__f64, .offset = offsetof(r3f64_t, y0)},
|
||||
{s8_const("x0"), &type__f64, .offset = offsetof(r3f64_t, z0)},
|
||||
{s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, x1)},
|
||||
{s8_const("y1"), &type__f64, .offset = offsetof(r3f64_t, y1)},
|
||||
{s8_const("x1"), &type__f64, .offset = offsetof(r3f64_t, z1)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_member_t members__r2f64_t[] = {
|
||||
{s8_const("x0"), &type__f64, .offset = offsetof(r2f64_t, x0)},
|
||||
{s8_const("y0"), &type__f64, .offset = offsetof(r2f64_t, y0)},
|
||||
{s8_const("x1"), &type__f64, .offset = offsetof(r2f64_t, x1)},
|
||||
{s8_const("y1"), &type__f64, .offset = offsetof(r2f64_t, y1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r2f64_t);
|
||||
|
||||
static gb_read_only type_member_t members__r1f64_t[] = {
|
||||
{s8_const("x0"), &type__f64, .offset = offsetof(r1f64_t, x0)},
|
||||
{s8_const("x1"), &type__f64, .offset = offsetof(r1f64_t, x1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r1f64_t);
|
||||
|
||||
static gb_read_only type_t type__v2i32_t = { type_kind_struct, s8_const("v2i32_t"), sizeof(v2i32_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i32, .offset = offsetof(v2i32_t, x)},
|
||||
{s8_const("y"), &type__i32, .offset = offsetof(v2i32_t, y)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v3i32_t = { type_kind_struct, s8_const("v3i32_t"), sizeof(v3i32_t), .count = 3,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i32, .offset = offsetof(v3i32_t, x)},
|
||||
{s8_const("y"), &type__i32, .offset = offsetof(v3i32_t, y)},
|
||||
{s8_const("z"), &type__i32, .offset = offsetof(v3i32_t, z)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v4i32_t = { type_kind_struct, s8_const("v4i32_t"), sizeof(v4i32_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i32, .offset = offsetof(v4i32_t, x)},
|
||||
{s8_const("y"), &type__i32, .offset = offsetof(v4i32_t, y)},
|
||||
{s8_const("z"), &type__i32, .offset = offsetof(v4i32_t, z)},
|
||||
{s8_const("w"), &type__i32, .offset = offsetof(v4i32_t, w)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__r3i32_t = { type_kind_struct, s8_const("r3i32_t"), sizeof(r3i32_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x0"), &type__i32, .offset = offsetof(r3i32_t, x0)},
|
||||
{s8_const("y0"), &type__i32, .offset = offsetof(r3i32_t, y0)},
|
||||
{s8_const("x0"), &type__i32, .offset = offsetof(r3i32_t, z0)},
|
||||
{s8_const("x1"), &type__i32, .offset = offsetof(r3i32_t, x1)},
|
||||
{s8_const("y1"), &type__i32, .offset = offsetof(r3i32_t, y1)},
|
||||
{s8_const("x1"), &type__i32, .offset = offsetof(r3i32_t, z1)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_member_t members__r2i32_t[] = {
|
||||
{s8_const("x0"), &type__i32, .offset = offsetof(r2i32_t, x0)},
|
||||
{s8_const("y0"), &type__i32, .offset = offsetof(r2i32_t, y0)},
|
||||
{s8_const("x1"), &type__i32, .offset = offsetof(r2i32_t, x1)},
|
||||
{s8_const("y1"), &type__i32, .offset = offsetof(r2i32_t, y1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r2i32_t);
|
||||
|
||||
static gb_read_only type_member_t members__r1i32_t[] = {
|
||||
{s8_const("x0"), &type__i32, .offset = offsetof(r1i32_t, x0)},
|
||||
{s8_const("x1"), &type__i32, .offset = offsetof(r1i32_t, x1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r1i32_t);
|
||||
|
||||
|
||||
static gb_read_only type_t type__v2i64_t = { type_kind_struct, s8_const("v2i64_t"), sizeof(v2i64_t), .count = 2,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i64, .offset = offsetof(v2i64_t, x)},
|
||||
{s8_const("y"), &type__i64, .offset = offsetof(v2i64_t, y)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v3i64_t = { type_kind_struct, s8_const("v3i64_t"), sizeof(v3i64_t), .count = 3,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i64, .offset = offsetof(v3i64_t, x)},
|
||||
{s8_const("y"), &type__i64, .offset = offsetof(v3i64_t, y)},
|
||||
{s8_const("z"), &type__i64, .offset = offsetof(v3i64_t, z)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__v4i64_t = { type_kind_struct, s8_const("v4i64_t"), sizeof(v4i64_t), .count = 4,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x"), &type__i64, .offset = offsetof(v4i64_t, x)},
|
||||
{s8_const("y"), &type__i64, .offset = offsetof(v4i64_t, y)},
|
||||
{s8_const("z"), &type__i64, .offset = offsetof(v4i64_t, z)},
|
||||
{s8_const("w"), &type__i64, .offset = offsetof(v4i64_t, w)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_t type__r3i64_t = { type_kind_struct, s8_const("r3i64_t"), sizeof(r3i64_t), .count = 6,
|
||||
.members = (type_member_t[]){
|
||||
{s8_const("x0"), &type__i64, .offset = offsetof(r3i64_t, x0)},
|
||||
{s8_const("y0"), &type__i64, .offset = offsetof(r3i64_t, y0)},
|
||||
{s8_const("x0"), &type__i64, .offset = offsetof(r3i64_t, z0)},
|
||||
{s8_const("x1"), &type__i64, .offset = offsetof(r3i64_t, x1)},
|
||||
{s8_const("y1"), &type__i64, .offset = offsetof(r3i64_t, y1)},
|
||||
{s8_const("x1"), &type__i64, .offset = offsetof(r3i64_t, z1)},
|
||||
}
|
||||
};
|
||||
|
||||
static gb_read_only type_member_t members__r2i64_t[] = {
|
||||
{s8_const("x0"), &type__i64, .offset = offsetof(r2i64_t, x0)},
|
||||
{s8_const("y0"), &type__i64, .offset = offsetof(r2i64_t, y0)},
|
||||
{s8_const("x1"), &type__i64, .offset = offsetof(r2i64_t, x1)},
|
||||
{s8_const("y1"), &type__i64, .offset = offsetof(r2i64_t, y1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r2i64_t);
|
||||
|
||||
static gb_read_only type_member_t members__r1i64_t[] = {
|
||||
{s8_const("x0"), &type__i64, .offset = offsetof(r1i64_t, x0)},
|
||||
{s8_const("x1"), &type__i64, .offset = offsetof(r1i64_t, x1)},
|
||||
};
|
||||
static gb_read_only DEFINE_STRUCT(r1i64_t);
|
||||
@@ -1,199 +0,0 @@
|
||||
#include "core_unicode.h"
|
||||
|
||||
fn utf32_result_t utf16_to_utf32(uint16_t *c, int max_advance) {
|
||||
utf32_result_t result = {0};
|
||||
if (max_advance >= 1) {
|
||||
result.advance = 1;
|
||||
result.out_str = c[0];
|
||||
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) {
|
||||
if (max_advance >= 2) {
|
||||
result.out_str = 0x10000;
|
||||
result.out_str += (uint32_t)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF);
|
||||
result.advance = 2;
|
||||
} else {
|
||||
result.error = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.error = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn utf8_result_t utf32_to_utf8(uint32_t codepoint) {
|
||||
utf8_result_t result = {0};
|
||||
|
||||
if (codepoint <= 0x7F) {
|
||||
result.len = 1;
|
||||
result.out_str[0] = (char)codepoint;
|
||||
}
|
||||
else if (codepoint <= 0x7FF) {
|
||||
result.len = 2;
|
||||
result.out_str[0] = 0xc0 | (0x1f & (codepoint >> 6));
|
||||
result.out_str[1] = 0x80 | (0x3f & codepoint);
|
||||
}
|
||||
else if (codepoint <= 0xFFFF) { // 16 bit word
|
||||
result.len = 3;
|
||||
result.out_str[0] = 0xe0 | (0xf & (codepoint >> 12)); // 4 bits
|
||||
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
|
||||
result.out_str[2] = 0x80 | (0x3f & codepoint); // 6 bits
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF) { // 21 bit word
|
||||
result.len = 4;
|
||||
result.out_str[0] = 0xf0 | (0x7 & (codepoint >> 18)); // 3 bits
|
||||
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 12)); // 6 bits
|
||||
result.out_str[2] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
|
||||
result.out_str[3] = 0x80 | (0x3f & codepoint); // 6 bits
|
||||
}
|
||||
else {
|
||||
result.error = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn utf32_result_t utf8_to_utf32(char *c, int max_advance) {
|
||||
utf32_result_t result = {0};
|
||||
|
||||
if ((c[0] & 0x80) == 0) { // Check if leftmost zero of first byte is unset
|
||||
if (max_advance >= 1) {
|
||||
result.out_str = c[0];
|
||||
result.advance = 1;
|
||||
}
|
||||
else result.error = 1;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xe0) == 0xc0) {
|
||||
if ((c[1] & 0xc0) == 0x80) { // Continuation byte required
|
||||
if (max_advance >= 2) {
|
||||
result.out_str = (uint32_t)(c[0] & 0x1f) << 6u | (c[1] & 0x3f);
|
||||
result.advance = 2;
|
||||
}
|
||||
else result.error = 2;
|
||||
}
|
||||
else result.error = 2;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xf0) == 0xe0) {
|
||||
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80) { // Two continuation bytes required
|
||||
if (max_advance >= 3) {
|
||||
result.out_str = (uint32_t)(c[0] & 0xf) << 12u | (uint32_t)(c[1] & 0x3f) << 6u | (c[2] & 0x3f);
|
||||
result.advance = 3;
|
||||
}
|
||||
else result.error = 3;
|
||||
}
|
||||
else result.error = 3;
|
||||
}
|
||||
|
||||
else if ((c[0] & 0xf8) == 0xf0) {
|
||||
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80 && (c[3] & 0xc0) == 0x80) { // Three continuation bytes required
|
||||
if (max_advance >= 4) {
|
||||
result.out_str = (uint32_t)(c[0] & 0xf) << 18u | (uint32_t)(c[1] & 0x3f) << 12u | (uint32_t)(c[2] & 0x3f) << 6u | (uint32_t)(c[3] & 0x3f);
|
||||
result.advance = 4;
|
||||
}
|
||||
else result.error = 4;
|
||||
}
|
||||
else result.error = 4;
|
||||
}
|
||||
else result.error = 4;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
fn utf16_result_t utf32_to_utf16(uint32_t codepoint) {
|
||||
utf16_result_t result = {0};
|
||||
if (codepoint < 0x10000) {
|
||||
result.out_str[0] = (uint16_t)codepoint;
|
||||
result.out_str[1] = 0;
|
||||
result.len = 1;
|
||||
}
|
||||
else if (codepoint <= 0x10FFFF) {
|
||||
uint32_t code = (codepoint - 0x10000);
|
||||
result.out_str[0] = (uint16_t)(0xD800 | (code >> 10));
|
||||
result.out_str[1] = (uint16_t)(0xDC00 | (code & 0x3FF));
|
||||
result.len = 2;
|
||||
}
|
||||
else {
|
||||
result.error = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define UTF__HANDLE_DECODE_ERROR(question_mark) \
|
||||
{ \
|
||||
if (outlen < buffer_size - 1) buffer[outlen++] = (question_mark); \
|
||||
break; \
|
||||
}
|
||||
|
||||
fn int64_t str_from_wstr(char *buffer, int64_t buffer_size, uint16_t *in, int64_t inlen) {
|
||||
int64_t outlen = 0;
|
||||
for (int64_t i = 0; i < inlen && in[i];) {
|
||||
utf32_result_t decode = utf16_to_utf32((uint16_t *)(in + i), (int)(inlen - i));
|
||||
if (!decode.error) {
|
||||
i += decode.advance;
|
||||
utf8_result_t encode = utf32_to_utf8(decode.out_str);
|
||||
if (!encode.error) {
|
||||
for (int64_t j = 0; j < encode.len; j++) {
|
||||
if (outlen < buffer_size - 1) {
|
||||
buffer[outlen++] = encode.out_str[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else UTF__HANDLE_DECODE_ERROR('?');
|
||||
}
|
||||
else UTF__HANDLE_DECODE_ERROR('?');
|
||||
}
|
||||
|
||||
buffer[outlen] = 0;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
fn int64_t wstr_from_str(uint16_t *buffer, int64_t buffer_size, char *in, int64_t inlen) {
|
||||
int64_t outlen = 0;
|
||||
for (int64_t i = 0; i < inlen;) {
|
||||
utf32_result_t decode = utf8_to_utf32(in + i, (int)(inlen - i));
|
||||
if (!decode.error) {
|
||||
i += decode.advance;
|
||||
utf16_result_t encode = utf32_to_utf16(decode.out_str);
|
||||
if (!encode.error) {
|
||||
for (int64_t j = 0; j < encode.len; j++) {
|
||||
if (outlen < buffer_size - 1) {
|
||||
buffer[outlen++] = encode.out_str[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else UTF__HANDLE_DECODE_ERROR(0x003f);
|
||||
}
|
||||
else UTF__HANDLE_DECODE_ERROR(0x003f);
|
||||
}
|
||||
|
||||
buffer[outlen] = 0;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
fn void utf8_advance(utf8_iter_t *iter) {
|
||||
iter->i += iter->utf8_codepoint_byte_size;
|
||||
utf32_result_t r = utf8_to_utf32(iter->str + iter->i, iter->len - iter->i);
|
||||
if (r.error) {
|
||||
iter->item = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
iter->utf8_codepoint_byte_size = r.advance;
|
||||
iter->item = r.out_str;
|
||||
}
|
||||
|
||||
// @todo: s8_t, change name
|
||||
fn utf8_iter_t utf8_iterate_ex(char *str, int len) {
|
||||
utf8_iter_t result = {str, len};
|
||||
if (len) utf8_advance(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn utf8_iter_t utf8_iterate(char *str) {
|
||||
int length = 0;
|
||||
while (str[length]) length += 1;
|
||||
return utf8_iterate_ex(str, length);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
#include "core_basic.h"
|
||||
|
||||
typedef struct utf32_result_t utf32_result_t;
|
||||
struct utf32_result_t {
|
||||
uint32_t out_str;
|
||||
int advance;
|
||||
int error;
|
||||
};
|
||||
|
||||
typedef struct utf16_result_t utf16_result_t;
|
||||
struct utf16_result_t {
|
||||
uint16_t out_str[2];
|
||||
int len;
|
||||
int error;
|
||||
};
|
||||
|
||||
typedef struct utf8_result_t utf8_result_t;
|
||||
struct utf8_result_t {
|
||||
uint8_t out_str[4];
|
||||
int len;
|
||||
int error;
|
||||
};
|
||||
|
||||
typedef struct utf8_iter_t utf8_iter_t;
|
||||
struct utf8_iter_t {
|
||||
char *str;
|
||||
int len;
|
||||
int utf8_codepoint_byte_size;
|
||||
int i;
|
||||
uint32_t item;
|
||||
};
|
||||
|
||||
//
|
||||
// codepoint conversions
|
||||
fn utf32_result_t utf16_to_utf32(uint16_t *c, int max_advance);
|
||||
fn utf8_result_t utf32_to_utf8(uint32_t codepoint);
|
||||
fn utf32_result_t utf8_to_utf32(char *c, int max_advance);
|
||||
fn utf16_result_t utf32_to_utf16(uint32_t codepoint);
|
||||
|
||||
//
|
||||
// widestring / string conversions
|
||||
fn int64_t str_from_wstr(char *buffer, int64_t buffer_size, uint16_t *in, int64_t inlen);
|
||||
fn int64_t wstr_from_str(uint16_t *buffer, int64_t buffer_size, char *in, int64_t inlen);
|
||||
|
||||
//
|
||||
// codepoint iterator
|
||||
fn utf8_iter_t utf8_iterate(char *str);
|
||||
fn utf8_iter_t utf8_iterate_ex(char *str, int len);
|
||||
fn void utf8_advance(utf8_iter_t *iter);
|
||||
/* example:
|
||||
for (utf8_iter_t iter = utf8_iterate(string); iter.item; utf8_advance(&iter)) {
|
||||
u32 codepoint = iter.item;
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -1,3 +0,0 @@
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "stb_sprintf.h"
|
||||
#undef STB_SPRINTF_IMPLEMENTATION
|
||||
File diff suppressed because it is too large
Load Diff
Vendored
+1819
File diff suppressed because it is too large
Load Diff
Vendored
+3655
File diff suppressed because it is too large
Load Diff
Vendored
+311
@@ -0,0 +1,311 @@
|
||||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||
# define KHRONOS_STATIC 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(KHRONOS_STATIC)
|
||||
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||
* header compatible with static linking. */
|
||||
# define KHRONOS_APICALL
|
||||
#elif defined(_WIN32)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
/*
|
||||
* To support platform where unsigned long cannot be used interchangeably with
|
||||
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
||||
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
||||
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
||||
* unsigned long long or similar (this results in different C++ name mangling).
|
||||
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
||||
* platforms where the size of a pointer is larger than the size of long.
|
||||
*/
|
||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
||||
#define KHRONOS_USE_INTPTR_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef KHRONOS_USE_INTPTR_T
|
||||
typedef intptr_t khronos_intptr_t;
|
||||
typedef uintptr_t khronos_uintptr_t;
|
||||
#elif defined(_WIN64)
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
||||
Vendored
+106
@@ -0,0 +1,106 @@
|
||||
# Makefile for installing Lua
|
||||
# See doc/readme.html for installation and customization instructions.
|
||||
|
||||
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
|
||||
|
||||
# Your platform. See PLATS for possible values.
|
||||
PLAT= guess
|
||||
|
||||
# Where to install. The installation starts in the src and doc directories,
|
||||
# so take care if INSTALL_TOP is not an absolute path. See the local target.
|
||||
# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with
|
||||
# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.
|
||||
INSTALL_TOP= /usr/local
|
||||
INSTALL_BIN= $(INSTALL_TOP)/bin
|
||||
INSTALL_INC= $(INSTALL_TOP)/include
|
||||
INSTALL_LIB= $(INSTALL_TOP)/lib
|
||||
INSTALL_MAN= $(INSTALL_TOP)/man/man1
|
||||
INSTALL_LMOD= $(INSTALL_TOP)/share/lua/$V
|
||||
INSTALL_CMOD= $(INSTALL_TOP)/lib/lua/$V
|
||||
|
||||
# How to install. If your install program does not support "-p", then
|
||||
# you may have to run ranlib on the installed liblua.a.
|
||||
INSTALL= install -p
|
||||
INSTALL_EXEC= $(INSTALL) -m 0755
|
||||
INSTALL_DATA= $(INSTALL) -m 0644
|
||||
#
|
||||
# If you don't have "install" you can use "cp" instead.
|
||||
# INSTALL= cp -p
|
||||
# INSTALL_EXEC= $(INSTALL)
|
||||
# INSTALL_DATA= $(INSTALL)
|
||||
|
||||
# Other utilities.
|
||||
MKDIR= mkdir -p
|
||||
RM= rm -f
|
||||
|
||||
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
|
||||
|
||||
# Convenience platforms targets.
|
||||
PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
|
||||
|
||||
# What to install.
|
||||
TO_BIN= lua luac
|
||||
TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp
|
||||
TO_LIB= liblua.a
|
||||
TO_MAN= lua.1 luac.1
|
||||
|
||||
# Lua version and release.
|
||||
V= 5.4
|
||||
R= $V.7
|
||||
|
||||
# Targets start here.
|
||||
all: $(PLAT)
|
||||
|
||||
$(PLATS) help test clean:
|
||||
@cd src && $(MAKE) $@
|
||||
|
||||
install: dummy
|
||||
cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
|
||||
cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
|
||||
cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
|
||||
cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
|
||||
cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN)
|
||||
|
||||
uninstall:
|
||||
cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN)
|
||||
cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC)
|
||||
cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB)
|
||||
cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN)
|
||||
|
||||
local:
|
||||
$(MAKE) install INSTALL_TOP=../install
|
||||
|
||||
# make may get confused with install/ if it does not support .PHONY.
|
||||
dummy:
|
||||
|
||||
# Echo config parameters.
|
||||
echo:
|
||||
@cd src && $(MAKE) -s echo
|
||||
@echo "PLAT= $(PLAT)"
|
||||
@echo "V= $V"
|
||||
@echo "R= $R"
|
||||
@echo "TO_BIN= $(TO_BIN)"
|
||||
@echo "TO_INC= $(TO_INC)"
|
||||
@echo "TO_LIB= $(TO_LIB)"
|
||||
@echo "TO_MAN= $(TO_MAN)"
|
||||
@echo "INSTALL_TOP= $(INSTALL_TOP)"
|
||||
@echo "INSTALL_BIN= $(INSTALL_BIN)"
|
||||
@echo "INSTALL_INC= $(INSTALL_INC)"
|
||||
@echo "INSTALL_LIB= $(INSTALL_LIB)"
|
||||
@echo "INSTALL_MAN= $(INSTALL_MAN)"
|
||||
@echo "INSTALL_LMOD= $(INSTALL_LMOD)"
|
||||
@echo "INSTALL_CMOD= $(INSTALL_CMOD)"
|
||||
@echo "INSTALL_EXEC= $(INSTALL_EXEC)"
|
||||
@echo "INSTALL_DATA= $(INSTALL_DATA)"
|
||||
|
||||
# Echo pkg-config data.
|
||||
pc:
|
||||
@echo "version=$R"
|
||||
@echo "prefix=$(INSTALL_TOP)"
|
||||
@echo "libdir=$(INSTALL_LIB)"
|
||||
@echo "includedir=$(INSTALL_INC)"
|
||||
|
||||
# Targets that do not create files (not all makes understand .PHONY).
|
||||
.PHONY: all $(PLATS) help test clean install uninstall local dummy echo pc
|
||||
|
||||
# (end of Makefile)
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
|
||||
This is Lua 5.4.7, released on 13 Jun 2024.
|
||||
|
||||
For installation instructions, license details, and
|
||||
further information about Lua, see doc/readme.html.
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Vendored
+678
@@ -0,0 +1,678 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Lua 5.4 Reference Manual - contents</TITLE>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="index.css">
|
||||
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
|
||||
<H1>
|
||||
<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
|
||||
Lua 5.4 Reference Manual
|
||||
</H1>
|
||||
|
||||
<P>
|
||||
The reference manual is the official definition of the Lua language.
|
||||
<BR>
|
||||
For a complete introduction to Lua programming, see the book
|
||||
<A HREF="https://www.lua.org/pil/">Programming in Lua</A>.
|
||||
|
||||
<DIV CLASS="menubar">
|
||||
<A HREF="manual.html">start</A>
|
||||
·
|
||||
<A HREF="#contents">contents</A>
|
||||
·
|
||||
<A HREF="#index">index</A>
|
||||
·
|
||||
<A HREF="https://www.lua.org/manual/">other versions</A>
|
||||
</DIV>
|
||||
|
||||
<P>
|
||||
<SMALL>
|
||||
Copyright © 2020–2024 Lua.org, PUC-Rio.
|
||||
Freely available under the terms of the
|
||||
<A HREF="https://www.lua.org/license.html">Lua license</A>.
|
||||
</SMALL>
|
||||
|
||||
<H2><A NAME="contents">Contents</A></H2>
|
||||
<UL CLASS="contents menubar">
|
||||
<LI><A HREF="manual.html">1 – Introduction</A>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#2">2 – Basic Concepts</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.1">2.1 – Values and Types</A>
|
||||
<LI><A HREF="manual.html#2.2">2.2 – Environments and the Global Environment</A>
|
||||
<LI><A HREF="manual.html#2.3">2.3 – Error Handling</A>
|
||||
<LI><A HREF="manual.html#2.4">2.4 – Metatables and Metamethods</A>
|
||||
<LI><A HREF="manual.html#2.5">2.5 – Garbage Collection</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#2.5.1">2.5.1 – Incremental Garbage Collection</A>
|
||||
<LI><A HREF="manual.html#2.5.2">2.5.2 – Generational Garbage Collection</A>
|
||||
<LI><A HREF="manual.html#2.5.3">2.5.3 – Garbage-Collection Metamethods</A>
|
||||
<LI><A HREF="manual.html#2.5.4">2.5.4 – Weak Tables</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#2.6">2.6 – Coroutines</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#3">3 – The Language</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#3.1">3.1 – Lexical Conventions</A>
|
||||
<LI><A HREF="manual.html#3.2">3.2 – Variables</A>
|
||||
<LI><A HREF="manual.html#3.3">3.3 – Statements</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#3.3.1">3.3.1 – Blocks</A>
|
||||
<LI><A HREF="manual.html#3.3.2">3.3.2 – Chunks</A>
|
||||
<LI><A HREF="manual.html#3.3.3">3.3.3 – Assignment</A>
|
||||
<LI><A HREF="manual.html#3.3.4">3.3.4 – Control Structures</A>
|
||||
<LI><A HREF="manual.html#3.3.5">3.3.5 – For Statement</A>
|
||||
<LI><A HREF="manual.html#3.3.6">3.3.6 – Function Calls as Statements</A>
|
||||
<LI><A HREF="manual.html#3.3.7">3.3.7 – Local Declarations</A>
|
||||
<LI><A HREF="manual.html#3.3.8">3.3.8 – To-be-closed Variables</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#3.4">3.4 – Expressions</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#3.4.1">3.4.1 – Arithmetic Operators</A>
|
||||
<LI><A HREF="manual.html#3.4.2">3.4.2 – Bitwise Operators</A>
|
||||
<LI><A HREF="manual.html#3.4.3">3.4.3 – Coercions and Conversions</A>
|
||||
<LI><A HREF="manual.html#3.4.4">3.4.4 – Relational Operators</A>
|
||||
<LI><A HREF="manual.html#3.4.5">3.4.5 – Logical Operators</A>
|
||||
<LI><A HREF="manual.html#3.4.6">3.4.6 – Concatenation</A>
|
||||
<LI><A HREF="manual.html#3.4.7">3.4.7 – The Length Operator</A>
|
||||
<LI><A HREF="manual.html#3.4.8">3.4.8 – Precedence</A>
|
||||
<LI><A HREF="manual.html#3.4.9">3.4.9 – Table Constructors</A>
|
||||
<LI><A HREF="manual.html#3.4.10">3.4.10 – Function Calls</A>
|
||||
<LI><A HREF="manual.html#3.4.11">3.4.11 – Function Definitions</A>
|
||||
<LI><A HREF="manual.html#3.4.12">3.4.12 – Lists of expressions, multiple results, and adjustment<A>
|
||||
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#3.5">3.5 – Visibility Rules</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#4">4 – The Application Program Interface</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#4.1">4.1 – The Stack</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#4.1.1">4.1.1 – Stack Size</A>
|
||||
<LI><A HREF="manual.html#4.1.2">4.1.2 – Valid and Acceptable Indices</A>
|
||||
<LI><A HREF="manual.html#4.1.3">4.1.3 – Pointers to strings</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#4.2">4.2 – C Closures</A>
|
||||
<LI><A HREF="manual.html#4.3">4.3 – Registry</A>
|
||||
<LI><A HREF="manual.html#4.4">4.4 – Error Handling in C</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#4.4.1">4.4.1 – Status Codes</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#4.5">4.5 – Handling Yields in C</A>
|
||||
<LI><A HREF="manual.html#4.6">4.6 – Functions and Types</A>
|
||||
<LI><A HREF="manual.html#4.7">4.7 – The Debug Interface</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#5">5 – The Auxiliary Library</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#5.1">5.1 – Functions and Types</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#6">6 – The Standard Libraries</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#6.1">6.1 – Basic Functions</A>
|
||||
<LI><A HREF="manual.html#6.2">6.2 – Coroutine Manipulation</A>
|
||||
<LI><A HREF="manual.html#6.3">6.3 – Modules</A>
|
||||
<LI><A HREF="manual.html#6.4">6.4 – String Manipulation</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#6.4.1">6.4.1 – Patterns</A>
|
||||
<LI><A HREF="manual.html#6.4.2">6.4.2 – Format Strings for Pack and Unpack</A>
|
||||
</UL>
|
||||
<LI><A HREF="manual.html#6.5">6.5 – UTF-8 Support</A>
|
||||
<LI><A HREF="manual.html#6.6">6.6 – Table Manipulation</A>
|
||||
<LI><A HREF="manual.html#6.7">6.7 – Mathematical Functions</A>
|
||||
<LI><A HREF="manual.html#6.8">6.8 – Input and Output Facilities</A>
|
||||
<LI><A HREF="manual.html#6.9">6.9 – Operating System Facilities</A>
|
||||
<LI><A HREF="manual.html#6.10">6.10 – The Debug Library</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#7">7 – Lua Standalone</A>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#8">8 – Incompatibilities with the Previous Version</A>
|
||||
<UL>
|
||||
<LI><A HREF="manual.html#8.1">8.1 – Incompatibilities in the Language</A>
|
||||
<LI><A HREF="manual.html#8.2">8.2 – Incompatibilities in the Libraries</A>
|
||||
<LI><A HREF="manual.html#8.3">8.3 – Incompatibilities in the API</A>
|
||||
</UL>
|
||||
<P>
|
||||
<LI><A HREF="manual.html#9">9 – The Complete Syntax of Lua</A>
|
||||
</UL>
|
||||
|
||||
<H2><A NAME="index">Index</A></H2>
|
||||
<TABLE CLASS="menubar" WIDTH="100%">
|
||||
<TR>
|
||||
<TD>
|
||||
<H3><A NAME="functions">Lua functions</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#6.1">basic</A><BR>
|
||||
<A HREF="manual.html#pdf-_G">_G</A><BR>
|
||||
<A HREF="manual.html#pdf-_VERSION">_VERSION</A><BR>
|
||||
<A HREF="manual.html#pdf-assert">assert</A><BR>
|
||||
<A HREF="manual.html#pdf-collectgarbage">collectgarbage</A><BR>
|
||||
<A HREF="manual.html#pdf-dofile">dofile</A><BR>
|
||||
<A HREF="manual.html#pdf-error">error</A><BR>
|
||||
<A HREF="manual.html#pdf-getmetatable">getmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-ipairs">ipairs</A><BR>
|
||||
<A HREF="manual.html#pdf-load">load</A><BR>
|
||||
<A HREF="manual.html#pdf-loadfile">loadfile</A><BR>
|
||||
<A HREF="manual.html#pdf-next">next</A><BR>
|
||||
<A HREF="manual.html#pdf-pairs">pairs</A><BR>
|
||||
<A HREF="manual.html#pdf-pcall">pcall</A><BR>
|
||||
<A HREF="manual.html#pdf-print">print</A><BR>
|
||||
<A HREF="manual.html#pdf-rawequal">rawequal</A><BR>
|
||||
<A HREF="manual.html#pdf-rawget">rawget</A><BR>
|
||||
<A HREF="manual.html#pdf-rawlen">rawlen</A><BR>
|
||||
<A HREF="manual.html#pdf-rawset">rawset</A><BR>
|
||||
<A HREF="manual.html#pdf-require">require</A><BR>
|
||||
<A HREF="manual.html#pdf-select">select</A><BR>
|
||||
<A HREF="manual.html#pdf-setmetatable">setmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-tonumber">tonumber</A><BR>
|
||||
<A HREF="manual.html#pdf-tostring">tostring</A><BR>
|
||||
<A HREF="manual.html#pdf-type">type</A><BR>
|
||||
<A HREF="manual.html#pdf-warn">warn</A><BR>
|
||||
<A HREF="manual.html#pdf-xpcall">xpcall</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.2">coroutine</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.close">coroutine.close</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.create">coroutine.create</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.isyieldable">coroutine.isyieldable</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.resume">coroutine.resume</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.running">coroutine.running</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.status">coroutine.status</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.wrap">coroutine.wrap</A><BR>
|
||||
<A HREF="manual.html#pdf-coroutine.yield">coroutine.yield</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.10">debug</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.debug">debug.debug</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.gethook">debug.gethook</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getinfo">debug.getinfo</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getlocal">debug.getlocal</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getmetatable">debug.getmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getregistry">debug.getregistry</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getupvalue">debug.getupvalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.getuservalue">debug.getuservalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.sethook">debug.sethook</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setlocal">debug.setlocal</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setmetatable">debug.setmetatable</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setupvalue">debug.setupvalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.setuservalue">debug.setuservalue</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.traceback">debug.traceback</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.upvalueid">debug.upvalueid</A><BR>
|
||||
<A HREF="manual.html#pdf-debug.upvaluejoin">debug.upvaluejoin</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.8">io</A><BR>
|
||||
<A HREF="manual.html#pdf-io.close">io.close</A><BR>
|
||||
<A HREF="manual.html#pdf-io.flush">io.flush</A><BR>
|
||||
<A HREF="manual.html#pdf-io.input">io.input</A><BR>
|
||||
<A HREF="manual.html#pdf-io.lines">io.lines</A><BR>
|
||||
<A HREF="manual.html#pdf-io.open">io.open</A><BR>
|
||||
<A HREF="manual.html#pdf-io.output">io.output</A><BR>
|
||||
<A HREF="manual.html#pdf-io.popen">io.popen</A><BR>
|
||||
<A HREF="manual.html#pdf-io.read">io.read</A><BR>
|
||||
<A HREF="manual.html#pdf-io.stderr">io.stderr</A><BR>
|
||||
<A HREF="manual.html#pdf-io.stdin">io.stdin</A><BR>
|
||||
<A HREF="manual.html#pdf-io.stdout">io.stdout</A><BR>
|
||||
<A HREF="manual.html#pdf-io.tmpfile">io.tmpfile</A><BR>
|
||||
<A HREF="manual.html#pdf-io.type">io.type</A><BR>
|
||||
<A HREF="manual.html#pdf-io.write">io.write</A><BR>
|
||||
|
||||
<A HREF="manual.html#pdf-file:close">file:close</A><BR>
|
||||
<A HREF="manual.html#pdf-file:flush">file:flush</A><BR>
|
||||
<A HREF="manual.html#pdf-file:lines">file:lines</A><BR>
|
||||
<A HREF="manual.html#pdf-file:read">file:read</A><BR>
|
||||
<A HREF="manual.html#pdf-file:seek">file:seek</A><BR>
|
||||
<A HREF="manual.html#pdf-file:setvbuf">file:setvbuf</A><BR>
|
||||
<A HREF="manual.html#pdf-file:write">file:write</A><BR>
|
||||
|
||||
</TD>
|
||||
<TD>
|
||||
<H3> </H3>
|
||||
<P>
|
||||
<A HREF="manual.html#6.7">math</A><BR>
|
||||
<A HREF="manual.html#pdf-math.abs">math.abs</A><BR>
|
||||
<A HREF="manual.html#pdf-math.acos">math.acos</A><BR>
|
||||
<A HREF="manual.html#pdf-math.asin">math.asin</A><BR>
|
||||
<A HREF="manual.html#pdf-math.atan">math.atan</A><BR>
|
||||
<A HREF="manual.html#pdf-math.ceil">math.ceil</A><BR>
|
||||
<A HREF="manual.html#pdf-math.cos">math.cos</A><BR>
|
||||
<A HREF="manual.html#pdf-math.deg">math.deg</A><BR>
|
||||
<A HREF="manual.html#pdf-math.exp">math.exp</A><BR>
|
||||
<A HREF="manual.html#pdf-math.floor">math.floor</A><BR>
|
||||
<A HREF="manual.html#pdf-math.fmod">math.fmod</A><BR>
|
||||
<A HREF="manual.html#pdf-math.huge">math.huge</A><BR>
|
||||
<A HREF="manual.html#pdf-math.log">math.log</A><BR>
|
||||
<A HREF="manual.html#pdf-math.max">math.max</A><BR>
|
||||
<A HREF="manual.html#pdf-math.maxinteger">math.maxinteger</A><BR>
|
||||
<A HREF="manual.html#pdf-math.min">math.min</A><BR>
|
||||
<A HREF="manual.html#pdf-math.mininteger">math.mininteger</A><BR>
|
||||
<A HREF="manual.html#pdf-math.modf">math.modf</A><BR>
|
||||
<A HREF="manual.html#pdf-math.pi">math.pi</A><BR>
|
||||
<A HREF="manual.html#pdf-math.rad">math.rad</A><BR>
|
||||
<A HREF="manual.html#pdf-math.random">math.random</A><BR>
|
||||
<A HREF="manual.html#pdf-math.randomseed">math.randomseed</A><BR>
|
||||
<A HREF="manual.html#pdf-math.sin">math.sin</A><BR>
|
||||
<A HREF="manual.html#pdf-math.sqrt">math.sqrt</A><BR>
|
||||
<A HREF="manual.html#pdf-math.tan">math.tan</A><BR>
|
||||
<A HREF="manual.html#pdf-math.tointeger">math.tointeger</A><BR>
|
||||
<A HREF="manual.html#pdf-math.type">math.type</A><BR>
|
||||
<A HREF="manual.html#pdf-math.ult">math.ult</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.9">os</A><BR>
|
||||
<A HREF="manual.html#pdf-os.clock">os.clock</A><BR>
|
||||
<A HREF="manual.html#pdf-os.date">os.date</A><BR>
|
||||
<A HREF="manual.html#pdf-os.difftime">os.difftime</A><BR>
|
||||
<A HREF="manual.html#pdf-os.execute">os.execute</A><BR>
|
||||
<A HREF="manual.html#pdf-os.exit">os.exit</A><BR>
|
||||
<A HREF="manual.html#pdf-os.getenv">os.getenv</A><BR>
|
||||
<A HREF="manual.html#pdf-os.remove">os.remove</A><BR>
|
||||
<A HREF="manual.html#pdf-os.rename">os.rename</A><BR>
|
||||
<A HREF="manual.html#pdf-os.setlocale">os.setlocale</A><BR>
|
||||
<A HREF="manual.html#pdf-os.time">os.time</A><BR>
|
||||
<A HREF="manual.html#pdf-os.tmpname">os.tmpname</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.3">package</A><BR>
|
||||
<A HREF="manual.html#pdf-package.config">package.config</A><BR>
|
||||
<A HREF="manual.html#pdf-package.cpath">package.cpath</A><BR>
|
||||
<A HREF="manual.html#pdf-package.loaded">package.loaded</A><BR>
|
||||
<A HREF="manual.html#pdf-package.loadlib">package.loadlib</A><BR>
|
||||
<A HREF="manual.html#pdf-package.path">package.path</A><BR>
|
||||
<A HREF="manual.html#pdf-package.preload">package.preload</A><BR>
|
||||
<A HREF="manual.html#pdf-package.searchers">package.searchers</A><BR>
|
||||
<A HREF="manual.html#pdf-package.searchpath">package.searchpath</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.4">string</A><BR>
|
||||
<A HREF="manual.html#pdf-string.byte">string.byte</A><BR>
|
||||
<A HREF="manual.html#pdf-string.char">string.char</A><BR>
|
||||
<A HREF="manual.html#pdf-string.dump">string.dump</A><BR>
|
||||
<A HREF="manual.html#pdf-string.find">string.find</A><BR>
|
||||
<A HREF="manual.html#pdf-string.format">string.format</A><BR>
|
||||
<A HREF="manual.html#pdf-string.gmatch">string.gmatch</A><BR>
|
||||
<A HREF="manual.html#pdf-string.gsub">string.gsub</A><BR>
|
||||
<A HREF="manual.html#pdf-string.len">string.len</A><BR>
|
||||
<A HREF="manual.html#pdf-string.lower">string.lower</A><BR>
|
||||
<A HREF="manual.html#pdf-string.match">string.match</A><BR>
|
||||
<A HREF="manual.html#pdf-string.pack">string.pack</A><BR>
|
||||
<A HREF="manual.html#pdf-string.packsize">string.packsize</A><BR>
|
||||
<A HREF="manual.html#pdf-string.rep">string.rep</A><BR>
|
||||
<A HREF="manual.html#pdf-string.reverse">string.reverse</A><BR>
|
||||
<A HREF="manual.html#pdf-string.sub">string.sub</A><BR>
|
||||
<A HREF="manual.html#pdf-string.unpack">string.unpack</A><BR>
|
||||
<A HREF="manual.html#pdf-string.upper">string.upper</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.6">table</A><BR>
|
||||
<A HREF="manual.html#pdf-table.concat">table.concat</A><BR>
|
||||
<A HREF="manual.html#pdf-table.insert">table.insert</A><BR>
|
||||
<A HREF="manual.html#pdf-table.move">table.move</A><BR>
|
||||
<A HREF="manual.html#pdf-table.pack">table.pack</A><BR>
|
||||
<A HREF="manual.html#pdf-table.remove">table.remove</A><BR>
|
||||
<A HREF="manual.html#pdf-table.sort">table.sort</A><BR>
|
||||
<A HREF="manual.html#pdf-table.unpack">table.unpack</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#6.5">utf8</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.char">utf8.char</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.charpattern">utf8.charpattern</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.codepoint">utf8.codepoint</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.codes">utf8.codes</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.len">utf8.len</A><BR>
|
||||
<A HREF="manual.html#pdf-utf8.offset">utf8.offset</A><BR>
|
||||
|
||||
<H3><A NAME="metamethods">metamethods</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#2.4">__add</A><BR>
|
||||
<A HREF="manual.html#2.4">__band</A><BR>
|
||||
<A HREF="manual.html#2.4">__bnot</A><BR>
|
||||
<A HREF="manual.html#2.4">__bor</A><BR>
|
||||
<A HREF="manual.html#2.4">__bxor</A><BR>
|
||||
<A HREF="manual.html#2.4">__call</A><BR>
|
||||
<A HREF="manual.html#3.3.8">__close</A><BR>
|
||||
<A HREF="manual.html#2.4">__concat</A><BR>
|
||||
<A HREF="manual.html#2.4">__div</A><BR>
|
||||
<A HREF="manual.html#2.4">__eq</A><BR>
|
||||
<A HREF="manual.html#2.5.3">__gc</A><BR>
|
||||
<A HREF="manual.html#2.4">__idiv</A><BR>
|
||||
<A HREF="manual.html#2.4">__index</A><BR>
|
||||
<A HREF="manual.html#2.4">__le</A><BR>
|
||||
<A HREF="manual.html#2.4">__len</A><BR>
|
||||
<A HREF="manual.html#2.4">__lt</A><BR>
|
||||
<A HREF="manual.html#pdf-getmetatable">__metatable</A><BR>
|
||||
<A HREF="manual.html#2.4">__mod</A><BR>
|
||||
<A HREF="manual.html#2.5.4">__mode</A><BR>
|
||||
<A HREF="manual.html#2.4">__mul</A><BR>
|
||||
<A HREF="manual.html#luaL_newmetatable">__name</A><BR>
|
||||
<A HREF="manual.html#2.4">__newindex</A><BR>
|
||||
<A HREF="manual.html#pdf-pairs">__pairs</A><BR>
|
||||
<A HREF="manual.html#2.4">__pow</A><BR>
|
||||
<A HREF="manual.html#2.4">__shl</A><BR>
|
||||
<A HREF="manual.html#2.4">__shr</A><BR>
|
||||
<A HREF="manual.html#2.4">__sub</A><BR>
|
||||
<A HREF="manual.html#pdf-tostring">__tostring</A><BR>
|
||||
<A HREF="manual.html#2.4">__unm</A><BR>
|
||||
|
||||
<H3><A NAME="env">environment<BR>variables</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#pdf-LUA_CPATH">LUA_CPATH</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_CPATH_5_4">LUA_CPATH_5_4</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_INIT">LUA_INIT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_INIT_5_4">LUA_INIT_5_4</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_PATH">LUA_PATH</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_PATH_5_4">LUA_PATH_5_4</A><BR>
|
||||
|
||||
</TD>
|
||||
<TD>
|
||||
<H3><A NAME="api">C API</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#lua_Alloc">lua_Alloc</A><BR>
|
||||
<A HREF="manual.html#lua_CFunction">lua_CFunction</A><BR>
|
||||
<A HREF="manual.html#lua_Debug">lua_Debug</A><BR>
|
||||
<A HREF="manual.html#lua_Hook">lua_Hook</A><BR>
|
||||
<A HREF="manual.html#lua_Integer">lua_Integer</A><BR>
|
||||
<A HREF="manual.html#lua_KContext">lua_KContext</A><BR>
|
||||
<A HREF="manual.html#lua_KFunction">lua_KFunction</A><BR>
|
||||
<A HREF="manual.html#lua_Number">lua_Number</A><BR>
|
||||
<A HREF="manual.html#lua_Reader">lua_Reader</A><BR>
|
||||
<A HREF="manual.html#lua_State">lua_State</A><BR>
|
||||
<A HREF="manual.html#lua_Unsigned">lua_Unsigned</A><BR>
|
||||
<A HREF="manual.html#lua_WarnFunction">lua_WarnFunction</A><BR>
|
||||
<A HREF="manual.html#lua_Writer">lua_Writer</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#lua_absindex">lua_absindex</A><BR>
|
||||
<A HREF="manual.html#lua_arith">lua_arith</A><BR>
|
||||
<A HREF="manual.html#lua_atpanic">lua_atpanic</A><BR>
|
||||
<A HREF="manual.html#lua_call">lua_call</A><BR>
|
||||
<A HREF="manual.html#lua_callk">lua_callk</A><BR>
|
||||
<A HREF="manual.html#lua_checkstack">lua_checkstack</A><BR>
|
||||
<A HREF="manual.html#lua_close">lua_close</A><BR>
|
||||
<A HREF="manual.html#lua_closeslot">lua_closeslot</A><BR>
|
||||
<A HREF="manual.html#lua_compare">lua_compare</A><BR>
|
||||
<A HREF="manual.html#lua_concat">lua_concat</A><BR>
|
||||
<A HREF="manual.html#lua_copy">lua_copy</A><BR>
|
||||
<A HREF="manual.html#lua_createtable">lua_createtable</A><BR>
|
||||
<A HREF="manual.html#lua_dump">lua_dump</A><BR>
|
||||
<A HREF="manual.html#lua_error">lua_error</A><BR>
|
||||
<A HREF="manual.html#lua_gc">lua_gc</A><BR>
|
||||
<A HREF="manual.html#lua_getallocf">lua_getallocf</A><BR>
|
||||
<A HREF="manual.html#lua_getextraspace">lua_getextraspace</A><BR>
|
||||
<A HREF="manual.html#lua_getfield">lua_getfield</A><BR>
|
||||
<A HREF="manual.html#lua_getglobal">lua_getglobal</A><BR>
|
||||
<A HREF="manual.html#lua_gethook">lua_gethook</A><BR>
|
||||
<A HREF="manual.html#lua_gethookcount">lua_gethookcount</A><BR>
|
||||
<A HREF="manual.html#lua_gethookmask">lua_gethookmask</A><BR>
|
||||
<A HREF="manual.html#lua_geti">lua_geti</A><BR>
|
||||
<A HREF="manual.html#lua_getinfo">lua_getinfo</A><BR>
|
||||
<A HREF="manual.html#lua_getiuservalue">lua_getiuservalue</A><BR>
|
||||
<A HREF="manual.html#lua_getlocal">lua_getlocal</A><BR>
|
||||
<A HREF="manual.html#lua_getmetatable">lua_getmetatable</A><BR>
|
||||
<A HREF="manual.html#lua_getstack">lua_getstack</A><BR>
|
||||
<A HREF="manual.html#lua_gettable">lua_gettable</A><BR>
|
||||
<A HREF="manual.html#lua_gettop">lua_gettop</A><BR>
|
||||
<A HREF="manual.html#lua_getupvalue">lua_getupvalue</A><BR>
|
||||
<A HREF="manual.html#lua_insert">lua_insert</A><BR>
|
||||
<A HREF="manual.html#lua_isboolean">lua_isboolean</A><BR>
|
||||
<A HREF="manual.html#lua_iscfunction">lua_iscfunction</A><BR>
|
||||
<A HREF="manual.html#lua_isfunction">lua_isfunction</A><BR>
|
||||
<A HREF="manual.html#lua_isinteger">lua_isinteger</A><BR>
|
||||
<A HREF="manual.html#lua_islightuserdata">lua_islightuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_isnil">lua_isnil</A><BR>
|
||||
<A HREF="manual.html#lua_isnone">lua_isnone</A><BR>
|
||||
<A HREF="manual.html#lua_isnoneornil">lua_isnoneornil</A><BR>
|
||||
<A HREF="manual.html#lua_isnumber">lua_isnumber</A><BR>
|
||||
<A HREF="manual.html#lua_isstring">lua_isstring</A><BR>
|
||||
<A HREF="manual.html#lua_istable">lua_istable</A><BR>
|
||||
<A HREF="manual.html#lua_isthread">lua_isthread</A><BR>
|
||||
<A HREF="manual.html#lua_isuserdata">lua_isuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_isyieldable">lua_isyieldable</A><BR>
|
||||
<A HREF="manual.html#lua_len">lua_len</A><BR>
|
||||
<A HREF="manual.html#lua_load">lua_load</A><BR>
|
||||
<A HREF="manual.html#lua_newstate">lua_newstate</A><BR>
|
||||
<A HREF="manual.html#lua_newtable">lua_newtable</A><BR>
|
||||
<A HREF="manual.html#lua_newthread">lua_newthread</A><BR>
|
||||
<A HREF="manual.html#lua_newuserdatauv">lua_newuserdatauv</A><BR>
|
||||
<A HREF="manual.html#lua_next">lua_next</A><BR>
|
||||
<A HREF="manual.html#lua_numbertointeger">lua_numbertointeger</A><BR>
|
||||
<A HREF="manual.html#lua_pcall">lua_pcall</A><BR>
|
||||
<A HREF="manual.html#lua_pcallk">lua_pcallk</A><BR>
|
||||
<A HREF="manual.html#lua_pop">lua_pop</A><BR>
|
||||
<A HREF="manual.html#lua_pushboolean">lua_pushboolean</A><BR>
|
||||
<A HREF="manual.html#lua_pushcclosure">lua_pushcclosure</A><BR>
|
||||
<A HREF="manual.html#lua_pushcfunction">lua_pushcfunction</A><BR>
|
||||
<A HREF="manual.html#lua_pushfstring">lua_pushfstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushglobaltable">lua_pushglobaltable</A><BR>
|
||||
<A HREF="manual.html#lua_pushinteger">lua_pushinteger</A><BR>
|
||||
<A HREF="manual.html#lua_pushlightuserdata">lua_pushlightuserdata</A><BR>
|
||||
<A HREF="manual.html#lua_pushliteral">lua_pushliteral</A><BR>
|
||||
<A HREF="manual.html#lua_pushlstring">lua_pushlstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushnil">lua_pushnil</A><BR>
|
||||
<A HREF="manual.html#lua_pushnumber">lua_pushnumber</A><BR>
|
||||
<A HREF="manual.html#lua_pushstring">lua_pushstring</A><BR>
|
||||
<A HREF="manual.html#lua_pushthread">lua_pushthread</A><BR>
|
||||
<A HREF="manual.html#lua_pushvalue">lua_pushvalue</A><BR>
|
||||
<A HREF="manual.html#lua_pushvfstring">lua_pushvfstring</A><BR>
|
||||
<A HREF="manual.html#lua_rawequal">lua_rawequal</A><BR>
|
||||
<A HREF="manual.html#lua_rawget">lua_rawget</A><BR>
|
||||
<A HREF="manual.html#lua_rawgeti">lua_rawgeti</A><BR>
|
||||
<A HREF="manual.html#lua_rawgetp">lua_rawgetp</A><BR>
|
||||
<A HREF="manual.html#lua_rawlen">lua_rawlen</A><BR>
|
||||
<A HREF="manual.html#lua_rawset">lua_rawset</A><BR>
|
||||
<A HREF="manual.html#lua_rawseti">lua_rawseti</A><BR>
|
||||
<A HREF="manual.html#lua_rawsetp">lua_rawsetp</A><BR>
|
||||
<A HREF="manual.html#lua_register">lua_register</A><BR>
|
||||
<A HREF="manual.html#lua_remove">lua_remove</A><BR>
|
||||
<A HREF="manual.html#lua_replace">lua_replace</A><BR>
|
||||
<A HREF="manual.html#lua_resetthread">lua_resetthread</A><BR>
|
||||
<A HREF="manual.html#lua_resume">lua_resume</A><BR>
|
||||
<A HREF="manual.html#lua_rotate">lua_rotate</A><BR>
|
||||
<A HREF="manual.html#lua_setallocf">lua_setallocf</A><BR>
|
||||
<A HREF="manual.html#lua_setfield">lua_setfield</A><BR>
|
||||
<A HREF="manual.html#lua_setglobal">lua_setglobal</A><BR>
|
||||
<A HREF="manual.html#lua_sethook">lua_sethook</A><BR>
|
||||
<A HREF="manual.html#lua_seti">lua_seti</A><BR>
|
||||
<A HREF="manual.html#lua_setiuservalue">lua_setiuservalue</A><BR>
|
||||
<A HREF="manual.html#lua_setlocal">lua_setlocal</A><BR>
|
||||
<A HREF="manual.html#lua_setmetatable">lua_setmetatable</A><BR>
|
||||
<A HREF="manual.html#lua_settable">lua_settable</A><BR>
|
||||
<A HREF="manual.html#lua_settop">lua_settop</A><BR>
|
||||
<A HREF="manual.html#lua_setupvalue">lua_setupvalue</A><BR>
|
||||
<A HREF="manual.html#lua_setwarnf">lua_setwarnf</A><BR>
|
||||
<A HREF="manual.html#lua_status">lua_status</A><BR>
|
||||
<A HREF="manual.html#lua_stringtonumber">lua_stringtonumber</A><BR>
|
||||
<A HREF="manual.html#lua_toboolean">lua_toboolean</A><BR>
|
||||
<A HREF="manual.html#lua_tocfunction">lua_tocfunction</A><BR>
|
||||
<A HREF="manual.html#lua_toclose">lua_toclose</A><BR>
|
||||
<A HREF="manual.html#lua_tointeger">lua_tointeger</A><BR>
|
||||
<A HREF="manual.html#lua_tointegerx">lua_tointegerx</A><BR>
|
||||
<A HREF="manual.html#lua_tolstring">lua_tolstring</A><BR>
|
||||
<A HREF="manual.html#lua_tonumber">lua_tonumber</A><BR>
|
||||
<A HREF="manual.html#lua_tonumberx">lua_tonumberx</A><BR>
|
||||
<A HREF="manual.html#lua_topointer">lua_topointer</A><BR>
|
||||
<A HREF="manual.html#lua_tostring">lua_tostring</A><BR>
|
||||
<A HREF="manual.html#lua_tothread">lua_tothread</A><BR>
|
||||
<A HREF="manual.html#lua_touserdata">lua_touserdata</A><BR>
|
||||
<A HREF="manual.html#lua_type">lua_type</A><BR>
|
||||
<A HREF="manual.html#lua_typename">lua_typename</A><BR>
|
||||
<A HREF="manual.html#lua_upvalueid">lua_upvalueid</A><BR>
|
||||
<A HREF="manual.html#lua_upvalueindex">lua_upvalueindex</A><BR>
|
||||
<A HREF="manual.html#lua_upvaluejoin">lua_upvaluejoin</A><BR>
|
||||
<A HREF="manual.html#lua_version">lua_version</A><BR>
|
||||
<A HREF="manual.html#lua_warning">lua_warning</A><BR>
|
||||
<A HREF="manual.html#lua_xmove">lua_xmove</A><BR>
|
||||
<A HREF="manual.html#lua_yield">lua_yield</A><BR>
|
||||
<A HREF="manual.html#lua_yieldk">lua_yieldk</A><BR>
|
||||
|
||||
</TD>
|
||||
<TD>
|
||||
<H3><A NAME="auxlib">auxiliary library</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#luaL_Buffer">luaL_Buffer</A><BR>
|
||||
<A HREF="manual.html#luaL_Reg">luaL_Reg</A><BR>
|
||||
<A HREF="manual.html#luaL_Stream">luaL_Stream</A><BR>
|
||||
|
||||
<P>
|
||||
<A HREF="manual.html#luaL_addchar">luaL_addchar</A><BR>
|
||||
<A HREF="manual.html#luaL_addgsub">luaL_addgsub</A><BR>
|
||||
<A HREF="manual.html#luaL_addlstring">luaL_addlstring</A><BR>
|
||||
<A HREF="manual.html#luaL_addsize">luaL_addsize</A><BR>
|
||||
<A HREF="manual.html#luaL_addstring">luaL_addstring</A><BR>
|
||||
<A HREF="manual.html#luaL_addvalue">luaL_addvalue</A><BR>
|
||||
<A HREF="manual.html#luaL_argcheck">luaL_argcheck</A><BR>
|
||||
<A HREF="manual.html#luaL_argerror">luaL_argerror</A><BR>
|
||||
<A HREF="manual.html#luaL_argexpected">luaL_argexpected</A><BR>
|
||||
<A HREF="manual.html#luaL_buffaddr">luaL_buffaddr</A><BR>
|
||||
<A HREF="manual.html#luaL_buffinit">luaL_buffinit</A><BR>
|
||||
<A HREF="manual.html#luaL_buffinitsize">luaL_buffinitsize</A><BR>
|
||||
<A HREF="manual.html#luaL_bufflen">luaL_bufflen</A><BR>
|
||||
<A HREF="manual.html#luaL_buffsub">luaL_buffsub</A><BR>
|
||||
<A HREF="manual.html#luaL_callmeta">luaL_callmeta</A><BR>
|
||||
<A HREF="manual.html#luaL_checkany">luaL_checkany</A><BR>
|
||||
<A HREF="manual.html#luaL_checkinteger">luaL_checkinteger</A><BR>
|
||||
<A HREF="manual.html#luaL_checklstring">luaL_checklstring</A><BR>
|
||||
<A HREF="manual.html#luaL_checknumber">luaL_checknumber</A><BR>
|
||||
<A HREF="manual.html#luaL_checkoption">luaL_checkoption</A><BR>
|
||||
<A HREF="manual.html#luaL_checkstack">luaL_checkstack</A><BR>
|
||||
<A HREF="manual.html#luaL_checkstring">luaL_checkstring</A><BR>
|
||||
<A HREF="manual.html#luaL_checktype">luaL_checktype</A><BR>
|
||||
<A HREF="manual.html#luaL_checkudata">luaL_checkudata</A><BR>
|
||||
<A HREF="manual.html#luaL_checkversion">luaL_checkversion</A><BR>
|
||||
<A HREF="manual.html#luaL_dofile">luaL_dofile</A><BR>
|
||||
<A HREF="manual.html#luaL_dostring">luaL_dostring</A><BR>
|
||||
<A HREF="manual.html#luaL_error">luaL_error</A><BR>
|
||||
<A HREF="manual.html#luaL_execresult">luaL_execresult</A><BR>
|
||||
<A HREF="manual.html#luaL_fileresult">luaL_fileresult</A><BR>
|
||||
<A HREF="manual.html#luaL_getmetafield">luaL_getmetafield</A><BR>
|
||||
<A HREF="manual.html#luaL_getmetatable">luaL_getmetatable</A><BR>
|
||||
<A HREF="manual.html#luaL_getsubtable">luaL_getsubtable</A><BR>
|
||||
<A HREF="manual.html#luaL_gsub">luaL_gsub</A><BR>
|
||||
<A HREF="manual.html#luaL_len">luaL_len</A><BR>
|
||||
<A HREF="manual.html#luaL_loadbuffer">luaL_loadbuffer</A><BR>
|
||||
<A HREF="manual.html#luaL_loadbufferx">luaL_loadbufferx</A><BR>
|
||||
<A HREF="manual.html#luaL_loadfile">luaL_loadfile</A><BR>
|
||||
<A HREF="manual.html#luaL_loadfilex">luaL_loadfilex</A><BR>
|
||||
<A HREF="manual.html#luaL_loadstring">luaL_loadstring</A><BR>
|
||||
<A HREF="manual.html#luaL_newlib">luaL_newlib</A><BR>
|
||||
<A HREF="manual.html#luaL_newlibtable">luaL_newlibtable</A><BR>
|
||||
<A HREF="manual.html#luaL_newmetatable">luaL_newmetatable</A><BR>
|
||||
<A HREF="manual.html#luaL_newstate">luaL_newstate</A><BR>
|
||||
<A HREF="manual.html#luaL_openlibs">luaL_openlibs</A><BR>
|
||||
<A HREF="manual.html#luaL_opt">luaL_opt</A><BR>
|
||||
<A HREF="manual.html#luaL_optinteger">luaL_optinteger</A><BR>
|
||||
<A HREF="manual.html#luaL_optlstring">luaL_optlstring</A><BR>
|
||||
<A HREF="manual.html#luaL_optnumber">luaL_optnumber</A><BR>
|
||||
<A HREF="manual.html#luaL_optstring">luaL_optstring</A><BR>
|
||||
<A HREF="manual.html#luaL_prepbuffer">luaL_prepbuffer</A><BR>
|
||||
<A HREF="manual.html#luaL_prepbuffsize">luaL_prepbuffsize</A><BR>
|
||||
<A HREF="manual.html#luaL_pushfail">luaL_pushfail</A><BR>
|
||||
<A HREF="manual.html#luaL_pushresult">luaL_pushresult</A><BR>
|
||||
<A HREF="manual.html#luaL_pushresultsize">luaL_pushresultsize</A><BR>
|
||||
<A HREF="manual.html#luaL_ref">luaL_ref</A><BR>
|
||||
<A HREF="manual.html#luaL_requiref">luaL_requiref</A><BR>
|
||||
<A HREF="manual.html#luaL_setfuncs">luaL_setfuncs</A><BR>
|
||||
<A HREF="manual.html#luaL_setmetatable">luaL_setmetatable</A><BR>
|
||||
<A HREF="manual.html#luaL_testudata">luaL_testudata</A><BR>
|
||||
<A HREF="manual.html#luaL_tolstring">luaL_tolstring</A><BR>
|
||||
<A HREF="manual.html#luaL_traceback">luaL_traceback</A><BR>
|
||||
<A HREF="manual.html#luaL_typeerror">luaL_typeerror</A><BR>
|
||||
<A HREF="manual.html#luaL_typename">luaL_typename</A><BR>
|
||||
<A HREF="manual.html#luaL_unref">luaL_unref</A><BR>
|
||||
<A HREF="manual.html#luaL_where">luaL_where</A><BR>
|
||||
|
||||
<H3><A NAME="library">standard library</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#pdf-luaopen_base">luaopen_base</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_coroutine">luaopen_coroutine</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_debug">luaopen_debug</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_io">luaopen_io</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_math">luaopen_math</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_os">luaopen_os</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_package">luaopen_package</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_string">luaopen_string</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_table">luaopen_table</A><BR>
|
||||
<A HREF="manual.html#pdf-luaopen_utf8">luaopen_utf8</A><BR>
|
||||
|
||||
<H3><A NAME="constants">constants</A></H3>
|
||||
<P>
|
||||
<A HREF="manual.html#pdf-LUA_ERRERR">LUA_ERRERR</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRFILE">LUA_ERRFILE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRMEM">LUA_ERRMEM</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRRUN">LUA_ERRRUN</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_ERRSYNTAX">LUA_ERRSYNTAX</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKCALL">LUA_HOOKCALL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKCOUNT">LUA_HOOKCOUNT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_LOADED_TABLE">LUA_LOADED_TABLE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MASKRET">LUA_MASKRET</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MAXINTEGER">LUA_MAXINTEGER</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MININTEGER">LUA_MININTEGER</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MINSTACK">LUA_MINSTACK</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_MULTRET">LUA_MULTRET</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_NOREF">LUA_NOREF</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OK">LUA_OK</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPADD">LUA_OPADD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPBAND">LUA_OPBAND</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPBNOT">LUA_OPBNOT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPBOR">LUA_OPBOR</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPBXOR">LUA_OPBXOR</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPDIV">LUA_OPDIV</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPEQ">LUA_OPEQ</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPIDIV">LUA_OPIDIV</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPLE">LUA_OPLE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPLT">LUA_OPLT</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPMOD">LUA_OPMOD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPMUL">LUA_OPMUL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPPOW">LUA_OPPOW</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPSHL">LUA_OPSHL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_PRELOAD_TABLE">LUA_PRELOAD_TABLE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_RIDX_MAINTHREAD">LUA_RIDX_MAINTHREAD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TBOOLEAN">LUA_TBOOLEAN</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TFUNCTION">LUA_TFUNCTION</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TLIGHTUSERDATA">LUA_TLIGHTUSERDATA</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TNIL">LUA_TNIL</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TNONE">LUA_TNONE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TNUMBER">LUA_TNUMBER</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TSTRING">LUA_TSTRING</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TTABLE">LUA_TTABLE</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TTHREAD">LUA_TTHREAD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR>
|
||||
<A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR>
|
||||
<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
|
||||
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
|
||||
<P CLASS="footer">
|
||||
Last update:
|
||||
Thu May 9 14:47:09 UTC 2024
|
||||
</P>
|
||||
<!--
|
||||
Last change: revised for Lua 5.4.7
|
||||
-->
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
ul {
|
||||
list-style-type: none ;
|
||||
}
|
||||
|
||||
ul.contents {
|
||||
padding: 0 ;
|
||||
}
|
||||
|
||||
table {
|
||||
border: none ;
|
||||
border-spacing: 0 ;
|
||||
border-collapse: collapse ;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top ;
|
||||
padding: 0 ;
|
||||
text-align: left ;
|
||||
line-height: 1.25 ;
|
||||
width: 15% ;
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
Vendored
+155
@@ -0,0 +1,155 @@
|
||||
.\" $Id: lua.man,v 1.14 2024/05/08 18:48:27 lhf Exp $
|
||||
.TH LUA 1 "$Date: 2024/05/08 18:48:27 $"
|
||||
.SH NAME
|
||||
lua \- Lua interpreter
|
||||
.SH SYNOPSIS
|
||||
.B lua
|
||||
[
|
||||
.I options
|
||||
]
|
||||
[
|
||||
.I script
|
||||
[
|
||||
.I args
|
||||
]
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B lua
|
||||
is the standalone Lua interpreter.
|
||||
It loads and executes Lua programs,
|
||||
either in textual source form or
|
||||
in precompiled binary form.
|
||||
(Precompiled binaries are output by
|
||||
.BR luac ,
|
||||
the Lua compiler.)
|
||||
.B lua
|
||||
can be used as a batch interpreter and also interactively.
|
||||
.LP
|
||||
After handling the
|
||||
.IR options ,
|
||||
the Lua program in file
|
||||
.I script
|
||||
is loaded and executed.
|
||||
The
|
||||
.I args
|
||||
are available to
|
||||
.I script
|
||||
as strings in a global table named
|
||||
.B arg
|
||||
and also as arguments to its main function.
|
||||
When called without arguments,
|
||||
.B lua
|
||||
behaves as
|
||||
.B "lua \-v \-i"
|
||||
if the standard input is a terminal,
|
||||
and as
|
||||
.B "lua \-"
|
||||
otherwise.
|
||||
.LP
|
||||
In interactive mode,
|
||||
.B lua
|
||||
prompts the user,
|
||||
reads lines from the standard input,
|
||||
and executes them as they are read.
|
||||
If the line contains an expression,
|
||||
then the line is evaluated and the result is printed.
|
||||
If a line does not contain a complete statement,
|
||||
then a secondary prompt is displayed and
|
||||
lines are read until a complete statement is formed or
|
||||
a syntax error is found.
|
||||
.LP
|
||||
Before handling command line options and scripts,
|
||||
.B lua
|
||||
checks the contents of the environment variables
|
||||
.B LUA_INIT_5_4
|
||||
and
|
||||
.BR LUA_INIT ,
|
||||
in that order.
|
||||
If the contents are of the form
|
||||
.RI '@ filename ',
|
||||
then
|
||||
.I filename
|
||||
is executed.
|
||||
Otherwise, the contents are assumed to be a Lua statement and is executed.
|
||||
When
|
||||
.B LUA_INIT_5_4
|
||||
is defined,
|
||||
.B LUA_INIT
|
||||
is ignored.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-e " stat"
|
||||
execute statement
|
||||
.IR stat .
|
||||
.TP
|
||||
.B \-i
|
||||
enter interactive mode after executing
|
||||
.IR script .
|
||||
.TP
|
||||
.BI \-l " mod"
|
||||
require library
|
||||
.I mod
|
||||
into global
|
||||
.IR mod .
|
||||
.TP
|
||||
.BI \-l " g=mod"
|
||||
require library
|
||||
.I mod
|
||||
into global
|
||||
.IR g .
|
||||
.TP
|
||||
.B \-v
|
||||
show version information.
|
||||
.TP
|
||||
.B \-E
|
||||
ignore environment variables.
|
||||
.TP
|
||||
.B \-W
|
||||
turn warnings on.
|
||||
.TP
|
||||
.B \-\-
|
||||
stop handling options.
|
||||
.TP
|
||||
.B \-
|
||||
stop handling options and execute the standard input as a file.
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
The following environment variables affect the execution of
|
||||
.BR lua .
|
||||
When defined,
|
||||
the version-specific variants take priority
|
||||
and the version-neutral variants are ignored.
|
||||
.TP
|
||||
.B LUA_INIT, LUA_INIT_5_4
|
||||
Code to be executed before command line options and scripts.
|
||||
.TP
|
||||
.B LUA_PATH, LUA_PATH_5_4
|
||||
Initial value of package.path,
|
||||
the path used by require to search for Lua loaders.
|
||||
.TP
|
||||
.B LUA_CPATH, LUA_CPATH_5_4
|
||||
Initial value of package.cpath,
|
||||
the path used by require to search for C loaders.
|
||||
.SH EXIT STATUS
|
||||
If a script calls os.exit,
|
||||
then
|
||||
.B lua
|
||||
exits with the given exit status.
|
||||
Otherwise,
|
||||
.B lua
|
||||
exits
|
||||
with EXIT_SUCCESS (0 on POSIX systems) if there were no errors
|
||||
and
|
||||
with EXIT_FAILURE (1 on POSIX systems) if there were errors.
|
||||
Errors raised in interactive mode do not cause exits.
|
||||
.SH DIAGNOSTICS
|
||||
Error messages should be self explanatory.
|
||||
.SH "SEE ALSO"
|
||||
.BR luac (1)
|
||||
.br
|
||||
The documentation at lua.org,
|
||||
especially section 7 of the reference manual.
|
||||
.SH AUTHORS
|
||||
R. Ierusalimschy,
|
||||
L. H. de Figueiredo,
|
||||
W. Celes
|
||||
.\" EOF
|
||||
Vendored
+162
@@ -0,0 +1,162 @@
|
||||
html {
|
||||
background-color: #F8F8F8 ;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #FFFFFF ;
|
||||
color: #000000 ;
|
||||
font-family: Helvetica, Arial, sans-serif ;
|
||||
text-align: justify ;
|
||||
line-height: 1.25 ;
|
||||
margin: 16px auto ;
|
||||
padding: 32px ;
|
||||
border: solid #ccc 1px ;
|
||||
border-radius: 20px ;
|
||||
max-width: 70em ;
|
||||
width: 90% ;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
color: #000080 ;
|
||||
font-family: Verdana, Geneva, sans-serif ;
|
||||
font-weight: normal ;
|
||||
font-style: normal ;
|
||||
text-align: left ;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 28pt ;
|
||||
}
|
||||
|
||||
h1 img {
|
||||
vertical-align: text-bottom ;
|
||||
}
|
||||
|
||||
h2:before {
|
||||
content: "\2756" ;
|
||||
padding-right: 0.5em ;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none ;
|
||||
}
|
||||
|
||||
a:link {
|
||||
color: #000080 ;
|
||||
}
|
||||
|
||||
a:link:hover, a:visited:hover {
|
||||
background-color: #D0D0FF ;
|
||||
color: #000080 ;
|
||||
border-radius: 4px ;
|
||||
}
|
||||
|
||||
a:link:active, a:visited:active {
|
||||
color: #FF0000 ;
|
||||
}
|
||||
|
||||
div.menubar {
|
||||
padding-bottom: 0.5em ;
|
||||
}
|
||||
|
||||
p.menubar {
|
||||
margin-left: 2.5em ;
|
||||
}
|
||||
|
||||
.menubar a:hover {
|
||||
margin: -3px -3px -3px -3px ;
|
||||
padding: 3px 3px 3px 3px ;
|
||||
border-radius: 4px ;
|
||||
}
|
||||
|
||||
:target {
|
||||
background-color: #F0F0F0 ;
|
||||
margin: -8px ;
|
||||
padding: 8px ;
|
||||
border-radius: 8px ;
|
||||
outline: none ;
|
||||
}
|
||||
|
||||
hr {
|
||||
display: none ;
|
||||
}
|
||||
|
||||
table hr {
|
||||
background-color: #a0a0a0 ;
|
||||
color: #a0a0a0 ;
|
||||
border: 0 ;
|
||||
height: 1px ;
|
||||
display: block ;
|
||||
}
|
||||
|
||||
.footer {
|
||||
color: gray ;
|
||||
font-size: x-small ;
|
||||
text-transform: lowercase ;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
border: solid #a0a0a0 2px ;
|
||||
border-radius: 2em ;
|
||||
background-image: url('images/search.png') ;
|
||||
background-repeat: no-repeat ;
|
||||
background-position: 4px center ;
|
||||
padding-left: 20px ;
|
||||
height: 2em ;
|
||||
}
|
||||
|
||||
pre.session {
|
||||
background-color: #F8F8F8 ;
|
||||
padding: 1em ;
|
||||
border-radius: 8px ;
|
||||
}
|
||||
|
||||
table {
|
||||
border: none ;
|
||||
border-spacing: 0 ;
|
||||
border-collapse: collapse ;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0 ;
|
||||
margin: 0 ;
|
||||
}
|
||||
|
||||
td.gutter {
|
||||
width: 4% ;
|
||||
}
|
||||
|
||||
table.columns td {
|
||||
vertical-align: top ;
|
||||
padding-bottom: 1em ;
|
||||
text-align: justify ;
|
||||
line-height: 1.25 ;
|
||||
}
|
||||
|
||||
table.book td {
|
||||
vertical-align: top ;
|
||||
}
|
||||
|
||||
table.book td.cover {
|
||||
padding-right: 1em ;
|
||||
}
|
||||
|
||||
table.book img {
|
||||
border: solid #000080 1px ;
|
||||
border-radius: 2px ;
|
||||
}
|
||||
|
||||
table.book span {
|
||||
font-size: small ;
|
||||
text-align: left ;
|
||||
display: block ;
|
||||
margin-top: 0.25em ;
|
||||
}
|
||||
|
||||
p.logos a:link:hover, p.logos a:visited:hover {
|
||||
background-color: inherit ;
|
||||
}
|
||||
|
||||
img {
|
||||
background-color: white ;
|
||||
}
|
||||
Vendored
+118
@@ -0,0 +1,118 @@
|
||||
.\" $Id: luac.man,v 1.29 2011/11/16 13:53:40 lhf Exp $
|
||||
.TH LUAC 1 "$Date: 2011/11/16 13:53:40 $"
|
||||
.SH NAME
|
||||
luac \- Lua compiler
|
||||
.SH SYNOPSIS
|
||||
.B luac
|
||||
[
|
||||
.I options
|
||||
] [
|
||||
.I filenames
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B luac
|
||||
is the Lua compiler.
|
||||
It translates programs written in the Lua programming language
|
||||
into binary files containing precompiled chunks
|
||||
that can be later loaded and executed.
|
||||
.LP
|
||||
The main advantages of precompiling chunks are:
|
||||
faster loading,
|
||||
protecting source code from accidental user changes,
|
||||
and
|
||||
off-line syntax checking.
|
||||
Precompiling does not imply faster execution
|
||||
because in Lua chunks are always compiled into bytecodes before being executed.
|
||||
.B luac
|
||||
simply allows those bytecodes to be saved in a file for later execution.
|
||||
Precompiled chunks are not necessarily smaller than the corresponding source.
|
||||
The main goal in precompiling is faster loading.
|
||||
.LP
|
||||
In the command line,
|
||||
you can mix
|
||||
text files containing Lua source and
|
||||
binary files containing precompiled chunks.
|
||||
.B luac
|
||||
produces a single output file containing the combined bytecodes
|
||||
for all files given.
|
||||
Executing the combined file is equivalent to executing the given files.
|
||||
By default,
|
||||
the output file is named
|
||||
.BR luac.out ,
|
||||
but you can change this with the
|
||||
.B \-o
|
||||
option.
|
||||
.LP
|
||||
Precompiled chunks are
|
||||
.I not
|
||||
portable across different architectures.
|
||||
Moreover,
|
||||
the internal format of precompiled chunks
|
||||
is likely to change when a new version of Lua is released.
|
||||
Make sure you save the source files of all Lua programs that you precompile.
|
||||
.LP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-l
|
||||
produce a listing of the compiled bytecode for Lua's virtual machine.
|
||||
Listing bytecodes is useful to learn about Lua's virtual machine.
|
||||
If no files are given, then
|
||||
.B luac
|
||||
loads
|
||||
.B luac.out
|
||||
and lists its contents.
|
||||
Use
|
||||
.B \-l \-l
|
||||
for a full listing.
|
||||
.TP
|
||||
.BI \-o " file"
|
||||
output to
|
||||
.IR file ,
|
||||
instead of the default
|
||||
.BR luac.out .
|
||||
(You can use
|
||||
.B "'\-'"
|
||||
for standard output,
|
||||
but not on platforms that open standard output in text mode.)
|
||||
The output file may be one of the given files because
|
||||
all files are loaded before the output file is written.
|
||||
Be careful not to overwrite precious files.
|
||||
.TP
|
||||
.B \-p
|
||||
load files but do not generate any output file.
|
||||
Used mainly for syntax checking and for testing precompiled chunks:
|
||||
corrupted files will probably generate errors when loaded.
|
||||
If no files are given, then
|
||||
.B luac
|
||||
loads
|
||||
.B luac.out
|
||||
and tests its contents.
|
||||
No messages are displayed if the file loads without errors.
|
||||
.TP
|
||||
.B \-s
|
||||
strip debug information before writing the output file.
|
||||
This saves some space in very large chunks,
|
||||
but if errors occur when running a stripped chunk,
|
||||
then the error messages may not contain the full information they usually do.
|
||||
In particular,
|
||||
line numbers and names of local variables are lost.
|
||||
.TP
|
||||
.B \-v
|
||||
show version information.
|
||||
.TP
|
||||
.B \-\-
|
||||
stop handling options.
|
||||
.TP
|
||||
.B \-
|
||||
stop handling options and process standard input.
|
||||
.SH "SEE ALSO"
|
||||
.BR lua (1)
|
||||
.br
|
||||
The documentation at lua.org.
|
||||
.SH DIAGNOSTICS
|
||||
Error messages should be self explanatory.
|
||||
.SH AUTHORS
|
||||
R. Ierusalimschy,
|
||||
L. H. de Figueiredo,
|
||||
W. Celes
|
||||
.\" EOF
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
h3 code {
|
||||
font-family: inherit ;
|
||||
font-size: inherit ;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-size: 12pt ;
|
||||
}
|
||||
|
||||
span.apii {
|
||||
color: gray ;
|
||||
float: right ;
|
||||
font-family: inherit ;
|
||||
font-style: normal ;
|
||||
font-size: small ;
|
||||
}
|
||||
|
||||
h2:before {
|
||||
content: "" ;
|
||||
padding-right: 0em ;
|
||||
}
|
||||
Vendored
+12060
File diff suppressed because it is too large
Load Diff
Vendored
+339
@@ -0,0 +1,339 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Lua 5.4 readme</TITLE>
|
||||
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
|
||||
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<STYLE TYPE="text/css">
|
||||
blockquote, .display {
|
||||
border: solid #a0a0a0 2px ;
|
||||
border-radius: 8px ;
|
||||
padding: 1em ;
|
||||
margin: 0px ;
|
||||
}
|
||||
|
||||
.display {
|
||||
word-spacing: 0.25em ;
|
||||
}
|
||||
|
||||
dl.display dd {
|
||||
padding-bottom: 0.2em ;
|
||||
}
|
||||
|
||||
tt, kbd, code {
|
||||
font-size: 12pt ;
|
||||
}
|
||||
</STYLE>
|
||||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
|
||||
<H1>
|
||||
<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A>
|
||||
Welcome to Lua 5.4
|
||||
</H1>
|
||||
|
||||
<DIV CLASS="menubar">
|
||||
<A HREF="#about">about</A>
|
||||
·
|
||||
<A HREF="#install">installation</A>
|
||||
·
|
||||
<A HREF="#changes">changes</A>
|
||||
·
|
||||
<A HREF="#license">license</A>
|
||||
·
|
||||
<A HREF="contents.html">reference manual</A>
|
||||
</DIV>
|
||||
|
||||
<H2><A NAME="about">About Lua</A></H2>
|
||||
<P>
|
||||
Lua is a powerful, efficient, lightweight, embeddable scripting language
|
||||
developed by a
|
||||
<A HREF="https://www.lua.org/authors.html">team</A>
|
||||
at
|
||||
<A HREF="https://www.puc-rio.br/">PUC-Rio</A>,
|
||||
the Pontifical Catholic University of Rio de Janeiro in Brazil.
|
||||
Lua is
|
||||
<A HREF="#license">free software</A>
|
||||
used in
|
||||
<A HREF="https://www.lua.org/uses.html">many products and projects</A>
|
||||
around the world.
|
||||
|
||||
<P>
|
||||
Lua's
|
||||
<A HREF="https://www.lua.org/">official website</A>
|
||||
provides complete information
|
||||
about Lua,
|
||||
including
|
||||
an
|
||||
<A HREF="https://www.lua.org/about.html">executive summary</A>,
|
||||
tips on
|
||||
<A HREF="https://www.lua.org/start.html">getting started</A>,
|
||||
and
|
||||
updated
|
||||
<A HREF="https://www.lua.org/docs.html">documentation</A>,
|
||||
especially the
|
||||
<A HREF="https://www.lua.org/manual/5.4/">reference manual</A>,
|
||||
which may differ slightly from the
|
||||
<A HREF="contents.html">local copy</A>
|
||||
distributed in this package.
|
||||
|
||||
<H2><A NAME="install">Installing Lua</A></H2>
|
||||
<P>
|
||||
Lua is distributed in
|
||||
<A HREF="https://www.lua.org/ftp/">source</A>
|
||||
form.
|
||||
You need to build it before using it.
|
||||
Building Lua should be straightforward
|
||||
because
|
||||
Lua is implemented in pure ANSI C and compiles unmodified in all known
|
||||
platforms that have an ANSI C compiler.
|
||||
Lua also compiles unmodified as C++.
|
||||
The instructions given below for building Lua are for Unix-like platforms,
|
||||
such as Linux and macOS.
|
||||
See also
|
||||
<A HREF="#other">instructions for other systems</A>
|
||||
and
|
||||
<A HREF="#customization">customization options</A>.
|
||||
|
||||
<P>
|
||||
If you don't have the time or the inclination to compile Lua yourself,
|
||||
get a binary from
|
||||
<A HREF="https://luabinaries.sourceforge.net">LuaBinaries</A>.
|
||||
|
||||
<H3>Building Lua</H3>
|
||||
<P>
|
||||
In most common Unix-like platforms, simply do "<KBD>make</KBD>".
|
||||
Here are the details.
|
||||
|
||||
<OL>
|
||||
<LI>
|
||||
Open a terminal window and move to
|
||||
the top-level directory, which is named <TT>lua-5.4.7</TT>.
|
||||
The <TT>Makefile</TT> there controls both the build process and the installation process.
|
||||
<P>
|
||||
<LI>
|
||||
Do "<KBD>make</KBD>". The <TT>Makefile</TT> will guess your platform and build Lua for it.
|
||||
<P>
|
||||
<LI>
|
||||
If the guess failed, do "<KBD>make help</KBD>" and see if your platform is listed.
|
||||
The platforms currently supported are:
|
||||
<P>
|
||||
<P CLASS="display">
|
||||
guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
|
||||
</P>
|
||||
<P>
|
||||
If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
|
||||
is your platform name.
|
||||
<P>
|
||||
If your platform is not listed, try the closest one or posix, generic,
|
||||
c89, in this order.
|
||||
<P>
|
||||
<LI>
|
||||
The compilation takes only a few moments
|
||||
and produces three files in the <TT>src</TT> directory:
|
||||
lua (the interpreter),
|
||||
luac (the compiler),
|
||||
and liblua.a (the library).
|
||||
<P>
|
||||
<LI>
|
||||
To check that Lua has been built correctly, do "<KBD>make test</KBD>"
|
||||
after building Lua. This will run the interpreter and print its version.
|
||||
</OL>
|
||||
<P>
|
||||
If you're running Linux, try "<KBD>make linux-readline</KBD>" to build the interactive Lua interpreter with handy line-editing and history capabilities.
|
||||
If you get compilation errors,
|
||||
make sure you have installed the <TT>readline</TT> development package
|
||||
(which is probably named <TT>libreadline-dev</TT> or <TT>readline-devel</TT>).
|
||||
If you get link errors after that,
|
||||
then try "<KBD>make linux-readline MYLIBS=-ltermcap</KBD>".
|
||||
|
||||
<H3>Installing Lua</H3>
|
||||
<P>
|
||||
Once you have built Lua, you may want to install it in an official
|
||||
place in your system. In this case, do "<KBD>make install</KBD>". The official
|
||||
place and the way to install files are defined in the <TT>Makefile</TT>. You'll
|
||||
probably need the right permissions to install files, and so may need to do "<KBD>sudo make install</KBD>".
|
||||
|
||||
<P>
|
||||
To build and install Lua in one step, do "<KBD>make all install</KBD>",
|
||||
or "<KBD>make xxx install</KBD>",
|
||||
where xxx is your platform name.
|
||||
|
||||
<P>
|
||||
To install Lua locally after building it, do "<KBD>make local</KBD>".
|
||||
This will create a directory <TT>install</TT> with subdirectories
|
||||
<TT>bin</TT>, <TT>include</TT>, <TT>lib</TT>, <TT>man</TT>, <TT>share</TT>,
|
||||
and install Lua as listed below.
|
||||
|
||||
To install Lua locally, but in some other directory, do
|
||||
"<KBD>make install INSTALL_TOP=xxx</KBD>", where xxx is your chosen directory.
|
||||
The installation starts in the <TT>src</TT> and <TT>doc</TT> directories,
|
||||
so take care if <TT>INSTALL_TOP</TT> is not an absolute path.
|
||||
|
||||
<DL CLASS="display">
|
||||
<DT>
|
||||
bin:
|
||||
<DD>
|
||||
lua luac
|
||||
<DT>
|
||||
include:
|
||||
<DD>
|
||||
lua.h luaconf.h lualib.h lauxlib.h lua.hpp
|
||||
<DT>
|
||||
lib:
|
||||
<DD>
|
||||
liblua.a
|
||||
<DT>
|
||||
man/man1:
|
||||
<DD>
|
||||
lua.1 luac.1
|
||||
</DL>
|
||||
|
||||
<P>
|
||||
These are the only directories you need for development.
|
||||
If you only want to run Lua programs,
|
||||
you only need the files in <TT>bin</TT> and <TT>man</TT>.
|
||||
The files in <TT>include</TT> and <TT>lib</TT> are needed for
|
||||
embedding Lua in C or C++ programs.
|
||||
|
||||
<H3><A NAME="customization">Customization</A></H3>
|
||||
<P>
|
||||
Three kinds of things can be customized by editing a file:
|
||||
<UL>
|
||||
<LI> Where and how to install Lua — edit <TT>Makefile</TT>.
|
||||
<LI> How to build Lua — edit <TT>src/Makefile</TT>.
|
||||
<LI> Lua features — edit <TT>src/luaconf.h</TT>.
|
||||
</UL>
|
||||
|
||||
<P>
|
||||
You don't actually need to edit the Makefiles because you may set the
|
||||
relevant variables in the command line when invoking make.
|
||||
Nevertheless, it's probably best to edit and save the Makefiles to
|
||||
record the changes you've made.
|
||||
|
||||
<P>
|
||||
On the other hand, if you need to customize some Lua features,
|
||||
edit <TT>src/luaconf.h</TT> before building and installing Lua.
|
||||
The edited file will be the one installed, and
|
||||
it will be used by any Lua clients that you build, to ensure consistency.
|
||||
Further customization is available to experts by editing the Lua sources.
|
||||
|
||||
<H3><A NAME="other">Building Lua on other systems</A></H3>
|
||||
<P>
|
||||
If you're not using the usual Unix tools, then the instructions for
|
||||
building Lua depend on the compiler you use. You'll need to create
|
||||
projects (or whatever your compiler uses) for building the library,
|
||||
the interpreter, and the compiler, as follows:
|
||||
|
||||
<DL CLASS="display">
|
||||
<DT>
|
||||
library:
|
||||
<DD>
|
||||
lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c ltm.c lundump.c lvm.c lzio.c
|
||||
lauxlib.c lbaselib.c lcorolib.c ldblib.c liolib.c lmathlib.c loadlib.c loslib.c lstrlib.c ltablib.c lutf8lib.c linit.c
|
||||
<DT>
|
||||
interpreter:
|
||||
<DD>
|
||||
library, lua.c
|
||||
<DT>
|
||||
compiler:
|
||||
<DD>
|
||||
library, luac.c
|
||||
</DL>
|
||||
|
||||
<P>
|
||||
To use Lua as a library in your own programs, you need to know how to
|
||||
create and use libraries with your compiler. Moreover, to dynamically load
|
||||
C libraries for Lua, you'll need to know how to create dynamic libraries
|
||||
and you'll need to make sure that the Lua API functions are accessible to
|
||||
those dynamic libraries — but <EM>don't</EM> link the Lua library
|
||||
into each dynamic library. For Unix, we recommend that the Lua library
|
||||
be linked statically into the host program and its symbols exported for
|
||||
dynamic linking; <TT>src/Makefile</TT> does this for the Lua interpreter.
|
||||
For Windows, we recommend that the Lua library be a DLL.
|
||||
In all cases, the compiler luac should be linked statically.
|
||||
|
||||
<P>
|
||||
As mentioned above, you may edit <TT>src/luaconf.h</TT> to customize
|
||||
some features before building Lua.
|
||||
|
||||
<H2><A NAME="changes">Changes since Lua 5.3</A></H2>
|
||||
<P>
|
||||
Here are the main changes introduced in Lua 5.4.
|
||||
The
|
||||
<A HREF="contents.html">reference manual</A>
|
||||
lists the
|
||||
<A HREF="manual.html#8">incompatibilities</A> that had to be introduced.
|
||||
|
||||
<H3>Main changes</H3>
|
||||
<UL>
|
||||
<LI> new generational mode for garbage collection
|
||||
<LI> to-be-closed variables
|
||||
<LI> const variables
|
||||
<LI> userdata can have multiple user values
|
||||
<LI> new implementation for math.random
|
||||
<LI> warning system
|
||||
<LI> debug information about function arguments and returns
|
||||
<LI> new semantics for the integer 'for' loop
|
||||
<LI> optional 'init' argument to 'string.gmatch'
|
||||
<LI> new functions 'lua_resetthread' and 'coroutine.close'
|
||||
<LI> string-to-number coercions moved to the string library
|
||||
<LI> allocation function allowed to fail when shrinking a memory block
|
||||
<LI> new format '%p' in 'string.format'
|
||||
<LI> utf8 library accepts codepoints up to 2^31
|
||||
</UL>
|
||||
|
||||
<H2><A NAME="license">License</A></H2>
|
||||
<P>
|
||||
<A HREF="https://opensource.org/osd">
|
||||
<IMG SRC="OSIApproved_100X125.png" ALIGN="right" ALT="[Open Source Initiative Approved License]" STYLE="padding-left: 1em" WIDTH=50>
|
||||
</A>
|
||||
Lua is free software distributed under the terms of the
|
||||
<A HREF="https://opensource.org/license/mit">MIT license</A>
|
||||
reproduced below;
|
||||
it may be used for any purpose, including commercial purposes,
|
||||
at absolutely no cost without having to ask us.
|
||||
|
||||
The only requirement is that if you do use Lua,
|
||||
then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation.
|
||||
|
||||
For details, see the
|
||||
<A HREF="https://www.lua.org/license.html">license page</A>.
|
||||
|
||||
<BLOCKQUOTE STYLE="padding-bottom: 0em">
|
||||
Copyright © 1994–2024 Lua.org, PUC-Rio.
|
||||
|
||||
<P>
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
<P>
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
<P>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
</BLOCKQUOTE>
|
||||
<P>
|
||||
|
||||
<P CLASS="footer">
|
||||
Last update:
|
||||
Wed May 8 21:56:16 UTC 2024
|
||||
</P>
|
||||
<!--
|
||||
Last change: revised for Lua 5.4.7
|
||||
-->
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
Vendored
+225
@@ -0,0 +1,225 @@
|
||||
# Makefile for building Lua
|
||||
# See ../doc/readme.html for installation and customization instructions.
|
||||
|
||||
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
|
||||
|
||||
# Your platform. See PLATS for possible values.
|
||||
PLAT= guess
|
||||
|
||||
CC= gcc -std=gnu99
|
||||
CFLAGS= -O2 -Wall -Wextra -DLUA_COMPAT_5_3 $(SYSCFLAGS) $(MYCFLAGS)
|
||||
LDFLAGS= $(SYSLDFLAGS) $(MYLDFLAGS)
|
||||
LIBS= -lm $(SYSLIBS) $(MYLIBS)
|
||||
|
||||
AR= ar rcu
|
||||
RANLIB= ranlib
|
||||
RM= rm -f
|
||||
UNAME= uname
|
||||
|
||||
SYSCFLAGS=
|
||||
SYSLDFLAGS=
|
||||
SYSLIBS=
|
||||
|
||||
MYCFLAGS=
|
||||
MYLDFLAGS=
|
||||
MYLIBS=
|
||||
MYOBJS=
|
||||
|
||||
# Special flags for compiler modules; -Os reduces code size.
|
||||
CMCFLAGS=
|
||||
|
||||
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
|
||||
|
||||
PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
|
||||
|
||||
LUA_A= liblua.a
|
||||
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
|
||||
LIB_O= lauxlib.o lbaselib.o lcorolib.o ldblib.o liolib.o lmathlib.o loadlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o linit.o
|
||||
BASE_O= $(CORE_O) $(LIB_O) $(MYOBJS)
|
||||
|
||||
LUA_T= lua
|
||||
LUA_O= lua.o
|
||||
|
||||
LUAC_T= luac
|
||||
LUAC_O= luac.o
|
||||
|
||||
ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)
|
||||
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
|
||||
ALL_A= $(LUA_A)
|
||||
|
||||
# Targets start here.
|
||||
default: $(PLAT)
|
||||
|
||||
all: $(ALL_T)
|
||||
|
||||
o: $(ALL_O)
|
||||
|
||||
a: $(ALL_A)
|
||||
|
||||
$(LUA_A): $(BASE_O)
|
||||
$(AR) $@ $(BASE_O)
|
||||
$(RANLIB) $@
|
||||
|
||||
$(LUA_T): $(LUA_O) $(LUA_A)
|
||||
$(CC) -o $@ $(LDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
|
||||
|
||||
$(LUAC_T): $(LUAC_O) $(LUA_A)
|
||||
$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
|
||||
|
||||
test:
|
||||
./$(LUA_T) -v
|
||||
|
||||
clean:
|
||||
$(RM) $(ALL_T) $(ALL_O)
|
||||
|
||||
depend:
|
||||
@$(CC) $(CFLAGS) -MM l*.c
|
||||
|
||||
echo:
|
||||
@echo "PLAT= $(PLAT)"
|
||||
@echo "CC= $(CC)"
|
||||
@echo "CFLAGS= $(CFLAGS)"
|
||||
@echo "LDFLAGS= $(LDFLAGS)"
|
||||
@echo "LIBS= $(LIBS)"
|
||||
@echo "AR= $(AR)"
|
||||
@echo "RANLIB= $(RANLIB)"
|
||||
@echo "RM= $(RM)"
|
||||
@echo "UNAME= $(UNAME)"
|
||||
|
||||
# Convenience targets for popular platforms.
|
||||
ALL= all
|
||||
|
||||
help:
|
||||
@echo "Do 'make PLATFORM' where PLATFORM is one of these:"
|
||||
@echo " $(PLATS)"
|
||||
@echo "See doc/readme.html for complete instructions."
|
||||
|
||||
guess:
|
||||
@echo Guessing `$(UNAME)`
|
||||
@$(MAKE) `$(UNAME)`
|
||||
|
||||
AIX aix:
|
||||
$(MAKE) $(ALL) CC="xlc" CFLAGS="-O2 -DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-ldl" SYSLDFLAGS="-brtl -bexpall"
|
||||
|
||||
bsd:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN" SYSLIBS="-Wl,-E"
|
||||
|
||||
c89:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
|
||||
@echo ''
|
||||
@echo '*** C89 does not guarantee 64-bit integers for Lua.'
|
||||
@echo '*** Make sure to compile all external Lua libraries'
|
||||
@echo '*** with LUA_USE_C89 to ensure consistency'
|
||||
@echo ''
|
||||
|
||||
FreeBSD NetBSD OpenBSD freebsd:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE -I/usr/include/edit" SYSLIBS="-Wl,-E -ledit" CC="cc"
|
||||
|
||||
generic: $(ALL)
|
||||
|
||||
ios:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_IOS"
|
||||
|
||||
Linux linux: linux-noreadline
|
||||
|
||||
linux-noreadline:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl"
|
||||
|
||||
linux-readline:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE" SYSLIBS="-Wl,-E -ldl -lreadline"
|
||||
|
||||
Darwin macos macosx:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX -DLUA_USE_READLINE" SYSLIBS="-lreadline"
|
||||
|
||||
mingw:
|
||||
$(MAKE) "LUA_A=lua54.dll" "LUA_T=lua.exe" \
|
||||
"AR=$(CC) -shared -o" "RANLIB=strip --strip-unneeded" \
|
||||
"SYSCFLAGS=-DLUA_BUILD_AS_DLL" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe
|
||||
$(MAKE) "LUAC_T=luac.exe" luac.exe
|
||||
|
||||
posix:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX"
|
||||
|
||||
SunOS solaris:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_POSIX -DLUA_USE_DLOPEN -D_REENTRANT" SYSLIBS="-ldl"
|
||||
|
||||
# Targets that do not create files (not all makes understand .PHONY).
|
||||
.PHONY: all $(PLATS) help test clean default o a depend echo
|
||||
|
||||
# Compiler modules may use special flags.
|
||||
llex.o:
|
||||
$(CC) $(CFLAGS) $(CMCFLAGS) -c llex.c
|
||||
|
||||
lparser.o:
|
||||
$(CC) $(CFLAGS) $(CMCFLAGS) -c lparser.c
|
||||
|
||||
lcode.o:
|
||||
$(CC) $(CFLAGS) $(CMCFLAGS) -c lcode.c
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
|
||||
ltable.h lundump.h lvm.h
|
||||
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h
|
||||
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
|
||||
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
|
||||
ldo.h lgc.h lstring.h ltable.h lvm.h
|
||||
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
|
||||
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||
lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
|
||||
ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
|
||||
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
|
||||
lparser.h lstring.h ltable.h lundump.h lvm.h
|
||||
ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \
|
||||
ltm.h lzio.h lmem.h lundump.h
|
||||
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h
|
||||
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
|
||||
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h
|
||||
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
|
||||
lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
|
||||
lstring.h ltable.h
|
||||
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
|
||||
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
|
||||
ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
|
||||
lvm.h
|
||||
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
|
||||
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
|
||||
llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
|
||||
ldo.h lfunc.h lstring.h lgc.h ltable.h
|
||||
lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
|
||||
lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
|
||||
lstring.h ltable.h
|
||||
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
|
||||
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
|
||||
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
|
||||
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
|
||||
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h ldebug.h lstate.h \
|
||||
lobject.h llimits.h ltm.h lzio.h lmem.h lopcodes.h lopnames.h lundump.h
|
||||
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
|
||||
lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
|
||||
lundump.h
|
||||
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
|
||||
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
|
||||
llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
|
||||
ltable.h lvm.h ljumptab.h
|
||||
lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
|
||||
lobject.h ltm.h lzio.h
|
||||
|
||||
# (end of Makefile)
|
||||
Vendored
+1463
File diff suppressed because it is too large
Load Diff
Vendored
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
** $Id: lapi.h $
|
||||
** Auxiliary functions from Lua API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lapi_h
|
||||
#define lapi_h
|
||||
|
||||
|
||||
#include "llimits.h"
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
/* Increments 'L->top.p', checking for stack overflows */
|
||||
#define api_incr_top(L) {L->top.p++; \
|
||||
api_check(L, L->top.p <= L->ci->top.p, \
|
||||
"stack overflow");}
|
||||
|
||||
|
||||
/*
|
||||
** If a call returns too many multiple returns, the callee may not have
|
||||
** stack space to accommodate all results. In this case, this macro
|
||||
** increases its stack space ('L->ci->top.p').
|
||||
*/
|
||||
#define adjustresults(L,nres) \
|
||||
{ if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
|
||||
L->ci->top.p = L->top.p; }
|
||||
|
||||
|
||||
/* Ensure the stack has at least 'n' elements */
|
||||
#define api_checknelems(L,n) \
|
||||
api_check(L, (n) < (L->top.p - L->ci->func.p), \
|
||||
"not enough elements in the stack")
|
||||
|
||||
|
||||
/*
|
||||
** To reduce the overhead of returning from C functions, the presence of
|
||||
** to-be-closed variables in these functions is coded in the CallInfo's
|
||||
** field 'nresults', in a way that functions with no to-be-closed variables
|
||||
** with zero, one, or "all" wanted results have no overhead. Functions
|
||||
** with other number of wanted results, as well as functions with
|
||||
** variables to be closed, have an extra check.
|
||||
*/
|
||||
|
||||
#define hastocloseCfunc(n) ((n) < LUA_MULTRET)
|
||||
|
||||
/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
|
||||
#define codeNresults(n) (-(n) - 3)
|
||||
#define decodeNresults(n) (-(n) - 3)
|
||||
|
||||
#endif
|
||||
Vendored
+1126
File diff suppressed because it is too large
Load Diff
Vendored
+301
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
** $Id: lauxlib.h $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lauxlib_h
|
||||
#define lauxlib_h
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "luaconf.h"
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
/* global table */
|
||||
#define LUA_GNAME "_G"
|
||||
|
||||
|
||||
typedef struct luaL_Buffer luaL_Buffer;
|
||||
|
||||
|
||||
/* extra error code for 'luaL_loadfilex' */
|
||||
#define LUA_ERRFILE (LUA_ERRERR+1)
|
||||
|
||||
|
||||
/* key, in the registry, for table of loaded modules */
|
||||
#define LUA_LOADED_TABLE "_LOADED"
|
||||
|
||||
|
||||
/* key, in the registry, for table of preloaded loaders */
|
||||
#define LUA_PRELOAD_TABLE "_PRELOAD"
|
||||
|
||||
|
||||
typedef struct luaL_Reg {
|
||||
const char *name;
|
||||
lua_CFunction func;
|
||||
} luaL_Reg;
|
||||
|
||||
|
||||
#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
|
||||
|
||||
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
|
||||
#define luaL_checkversion(L) \
|
||||
luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
|
||||
|
||||
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
|
||||
LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
|
||||
LUALIB_API int (luaL_typeerror) (lua_State *L, int arg, const char *tname);
|
||||
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
|
||||
size_t *l);
|
||||
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
|
||||
const char *def, size_t *l);
|
||||
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
|
||||
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
|
||||
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
|
||||
lua_Integer def);
|
||||
|
||||
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
|
||||
LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
|
||||
LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
|
||||
|
||||
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
|
||||
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
|
||||
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
|
||||
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
|
||||
|
||||
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
|
||||
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
|
||||
|
||||
LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
|
||||
const char *const lst[]);
|
||||
|
||||
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
|
||||
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
||||
|
||||
|
||||
/* predefined references */
|
||||
#define LUA_NOREF (-2)
|
||||
#define LUA_REFNIL (-1)
|
||||
|
||||
LUALIB_API int (luaL_ref) (lua_State *L, int t);
|
||||
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
|
||||
|
||||
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
|
||||
const char *mode);
|
||||
|
||||
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
|
||||
|
||||
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
|
||||
const char *name, const char *mode);
|
||||
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
||||
|
||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
||||
|
||||
LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
|
||||
const char *p, const char *r);
|
||||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
|
||||
const char *p, const char *r);
|
||||
|
||||
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
|
||||
|
||||
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
|
||||
|
||||
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
|
||||
const char *msg, int level);
|
||||
|
||||
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
|
||||
lua_CFunction openf, int glb);
|
||||
|
||||
/*
|
||||
** ===============================================================
|
||||
** some useful macros
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
|
||||
#define luaL_newlibtable(L,l) \
|
||||
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
|
||||
|
||||
#define luaL_newlib(L,l) \
|
||||
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
|
||||
|
||||
#define luaL_argcheck(L, cond,arg,extramsg) \
|
||||
((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg))))
|
||||
|
||||
#define luaL_argexpected(L,cond,arg,tname) \
|
||||
((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname))))
|
||||
|
||||
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
||||
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
|
||||
|
||||
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
|
||||
|
||||
#define luaL_dofile(L, fn) \
|
||||
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||
|
||||
#define luaL_dostring(L, s) \
|
||||
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||
|
||||
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
|
||||
|
||||
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
|
||||
|
||||
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
|
||||
|
||||
|
||||
/*
|
||||
** Perform arithmetic operations on lua_Integer values with wrap-around
|
||||
** semantics, as the Lua core does.
|
||||
*/
|
||||
#define luaL_intop(op,v1,v2) \
|
||||
((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2)))
|
||||
|
||||
|
||||
/* push the value used to represent failure/error */
|
||||
#define luaL_pushfail(L) lua_pushnil(L)
|
||||
|
||||
|
||||
/*
|
||||
** Internal assertions for in-house debugging
|
||||
*/
|
||||
#if !defined(lua_assert)
|
||||
|
||||
#if defined LUAI_ASSERT
|
||||
#include <assert.h>
|
||||
#define lua_assert(c) assert(c)
|
||||
#else
|
||||
#define lua_assert(c) ((void)0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Buffer manipulation
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
struct luaL_Buffer {
|
||||
char *b; /* buffer address */
|
||||
size_t size; /* buffer size */
|
||||
size_t n; /* number of characters in buffer */
|
||||
lua_State *L;
|
||||
union {
|
||||
LUAI_MAXALIGN; /* ensure maximum alignment for buffer */
|
||||
char b[LUAL_BUFFERSIZE]; /* initial buffer */
|
||||
} init;
|
||||
};
|
||||
|
||||
|
||||
#define luaL_bufflen(bf) ((bf)->n)
|
||||
#define luaL_buffaddr(bf) ((bf)->b)
|
||||
|
||||
|
||||
#define luaL_addchar(B,c) \
|
||||
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
|
||||
((B)->b[(B)->n++] = (c)))
|
||||
|
||||
#define luaL_addsize(B,s) ((B)->n += (s))
|
||||
|
||||
#define luaL_buffsub(B,s) ((B)->n -= (s))
|
||||
|
||||
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
|
||||
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
|
||||
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
|
||||
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
|
||||
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
|
||||
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
|
||||
|
||||
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** File handles for IO library
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
|
||||
** initial structure 'luaL_Stream' (it may contain other fields
|
||||
** after that initial structure).
|
||||
*/
|
||||
|
||||
#define LUA_FILEHANDLE "FILE*"
|
||||
|
||||
|
||||
typedef struct luaL_Stream {
|
||||
FILE *f; /* stream (NULL for incompletely created streams) */
|
||||
lua_CFunction closef; /* to close stream (NULL for closed streams) */
|
||||
} luaL_Stream;
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** "Abstraction Layer" for basic report of messages and errors
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/* print a string */
|
||||
#if !defined(lua_writestring)
|
||||
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
|
||||
#endif
|
||||
|
||||
/* print a newline and flush the output */
|
||||
#if !defined(lua_writeline)
|
||||
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
|
||||
#endif
|
||||
|
||||
/* print an error message */
|
||||
#if !defined(lua_writestringerror)
|
||||
#define lua_writestringerror(s,p) \
|
||||
(fprintf(stderr, (s), (p)), fflush(stderr))
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {============================================================
|
||||
** Compatibility with deprecated conversions
|
||||
** =============================================================
|
||||
*/
|
||||
#if defined(LUA_COMPAT_APIINTCASTS)
|
||||
|
||||
#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
|
||||
#define luaL_optunsigned(L,a,d) \
|
||||
((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
|
||||
|
||||
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#endif
|
||||
/* }============================================================ */
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Vendored
+549
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
** $Id: lbaselib.c $
|
||||
** Basic library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lbaselib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
static int luaB_print (lua_State *L) {
|
||||
int n = lua_gettop(L); /* number of arguments */
|
||||
int i;
|
||||
for (i = 1; i <= n; i++) { /* for each argument */
|
||||
size_t l;
|
||||
const char *s = luaL_tolstring(L, i, &l); /* convert it to string */
|
||||
if (i > 1) /* not the first element? */
|
||||
lua_writestring("\t", 1); /* add a tab before it */
|
||||
lua_writestring(s, l); /* print it */
|
||||
lua_pop(L, 1); /* pop result */
|
||||
}
|
||||
lua_writeline();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Creates a warning with all given arguments.
|
||||
** Check first for errors; otherwise an error may interrupt
|
||||
** the composition of a warning, leaving it unfinished.
|
||||
*/
|
||||
static int luaB_warn (lua_State *L) {
|
||||
int n = lua_gettop(L); /* number of arguments */
|
||||
int i;
|
||||
luaL_checkstring(L, 1); /* at least one argument */
|
||||
for (i = 2; i <= n; i++)
|
||||
luaL_checkstring(L, i); /* make sure all arguments are strings */
|
||||
for (i = 1; i < n; i++) /* compose warning */
|
||||
lua_warning(L, lua_tostring(L, i), 1);
|
||||
lua_warning(L, lua_tostring(L, n), 0); /* close warning */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define SPACECHARS " \f\n\r\t\v"
|
||||
|
||||
static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
|
||||
lua_Unsigned n = 0;
|
||||
int neg = 0;
|
||||
s += strspn(s, SPACECHARS); /* skip initial spaces */
|
||||
if (*s == '-') { s++; neg = 1; } /* handle sign */
|
||||
else if (*s == '+') s++;
|
||||
if (!isalnum((unsigned char)*s)) /* no digit? */
|
||||
return NULL;
|
||||
do {
|
||||
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
|
||||
: (toupper((unsigned char)*s) - 'A') + 10;
|
||||
if (digit >= base) return NULL; /* invalid numeral */
|
||||
n = n * base + digit;
|
||||
s++;
|
||||
} while (isalnum((unsigned char)*s));
|
||||
s += strspn(s, SPACECHARS); /* skip trailing spaces */
|
||||
*pn = (lua_Integer)((neg) ? (0u - n) : n);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_tonumber (lua_State *L) {
|
||||
if (lua_isnoneornil(L, 2)) { /* standard conversion? */
|
||||
if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */
|
||||
lua_settop(L, 1); /* yes; return it */
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
size_t l;
|
||||
const char *s = lua_tolstring(L, 1, &l);
|
||||
if (s != NULL && lua_stringtonumber(L, s) == l + 1)
|
||||
return 1; /* successful conversion to number */
|
||||
/* else not a number */
|
||||
luaL_checkany(L, 1); /* (but there must be some parameter) */
|
||||
}
|
||||
}
|
||||
else {
|
||||
size_t l;
|
||||
const char *s;
|
||||
lua_Integer n = 0; /* to avoid warnings */
|
||||
lua_Integer base = luaL_checkinteger(L, 2);
|
||||
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
|
||||
s = lua_tolstring(L, 1, &l);
|
||||
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
|
||||
if (b_str2int(s, (int)base, &n) == s + l) {
|
||||
lua_pushinteger(L, n);
|
||||
return 1;
|
||||
} /* else not a number */
|
||||
} /* else not a number */
|
||||
luaL_pushfail(L); /* not a number */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_error (lua_State *L) {
|
||||
int level = (int)luaL_optinteger(L, 2, 1);
|
||||
lua_settop(L, 1);
|
||||
if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
|
||||
luaL_where(L, level); /* add extra information */
|
||||
lua_pushvalue(L, 1);
|
||||
lua_concat(L, 2);
|
||||
}
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_getmetatable (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (!lua_getmetatable(L, 1)) {
|
||||
lua_pushnil(L);
|
||||
return 1; /* no metatable */
|
||||
}
|
||||
luaL_getmetafield(L, 1, "__metatable");
|
||||
return 1; /* returns either __metatable field (if present) or metatable */
|
||||
}
|
||||
|
||||
|
||||
static int luaB_setmetatable (lua_State *L) {
|
||||
int t = lua_type(L, 2);
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
|
||||
if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL))
|
||||
return luaL_error(L, "cannot change a protected metatable");
|
||||
lua_settop(L, 2);
|
||||
lua_setmetatable(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_rawequal (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
luaL_checkany(L, 2);
|
||||
lua_pushboolean(L, lua_rawequal(L, 1, 2));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_rawlen (lua_State *L) {
|
||||
int t = lua_type(L, 1);
|
||||
luaL_argexpected(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
|
||||
"table or string");
|
||||
lua_pushinteger(L, lua_rawlen(L, 1));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_rawget (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_checkany(L, 2);
|
||||
lua_settop(L, 2);
|
||||
lua_rawget(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int luaB_rawset (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
luaL_checkany(L, 2);
|
||||
luaL_checkany(L, 3);
|
||||
lua_settop(L, 3);
|
||||
lua_rawset(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int pushmode (lua_State *L, int oldmode) {
|
||||
if (oldmode == -1)
|
||||
luaL_pushfail(L); /* invalid call to 'lua_gc' */
|
||||
else
|
||||
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
|
||||
: "generational");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** check whether call to 'lua_gc' was valid (not inside a finalizer)
|
||||
*/
|
||||
#define checkvalres(res) { if (res == -1) break; }
|
||||
|
||||
static int luaB_collectgarbage (lua_State *L) {
|
||||
static const char *const opts[] = {"stop", "restart", "collect",
|
||||
"count", "step", "setpause", "setstepmul",
|
||||
"isrunning", "generational", "incremental", NULL};
|
||||
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
|
||||
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
|
||||
LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
|
||||
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
|
||||
switch (o) {
|
||||
case LUA_GCCOUNT: {
|
||||
int k = lua_gc(L, o);
|
||||
int b = lua_gc(L, LUA_GCCOUNTB);
|
||||
checkvalres(k);
|
||||
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
|
||||
return 1;
|
||||
}
|
||||
case LUA_GCSTEP: {
|
||||
int step = (int)luaL_optinteger(L, 2, 0);
|
||||
int res = lua_gc(L, o, step);
|
||||
checkvalres(res);
|
||||
lua_pushboolean(L, res);
|
||||
return 1;
|
||||
}
|
||||
case LUA_GCSETPAUSE:
|
||||
case LUA_GCSETSTEPMUL: {
|
||||
int p = (int)luaL_optinteger(L, 2, 0);
|
||||
int previous = lua_gc(L, o, p);
|
||||
checkvalres(previous);
|
||||
lua_pushinteger(L, previous);
|
||||
return 1;
|
||||
}
|
||||
case LUA_GCISRUNNING: {
|
||||
int res = lua_gc(L, o);
|
||||
checkvalres(res);
|
||||
lua_pushboolean(L, res);
|
||||
return 1;
|
||||
}
|
||||
case LUA_GCGEN: {
|
||||
int minormul = (int)luaL_optinteger(L, 2, 0);
|
||||
int majormul = (int)luaL_optinteger(L, 3, 0);
|
||||
return pushmode(L, lua_gc(L, o, minormul, majormul));
|
||||
}
|
||||
case LUA_GCINC: {
|
||||
int pause = (int)luaL_optinteger(L, 2, 0);
|
||||
int stepmul = (int)luaL_optinteger(L, 3, 0);
|
||||
int stepsize = (int)luaL_optinteger(L, 4, 0);
|
||||
return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize));
|
||||
}
|
||||
default: {
|
||||
int res = lua_gc(L, o);
|
||||
checkvalres(res);
|
||||
lua_pushinteger(L, res);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
luaL_pushfail(L); /* invalid call (inside a finalizer) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_type (lua_State *L) {
|
||||
int t = lua_type(L, 1);
|
||||
luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
|
||||
lua_pushstring(L, lua_typename(L, t));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_next (lua_State *L) {
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
lua_settop(L, 2); /* create a 2nd argument if there isn't one */
|
||||
if (lua_next(L, 1))
|
||||
return 2;
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int pairscont (lua_State *L, int status, lua_KContext k) {
|
||||
(void)L; (void)status; (void)k; /* unused */
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int luaB_pairs (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
|
||||
lua_pushcfunction(L, luaB_next); /* will return generator, */
|
||||
lua_pushvalue(L, 1); /* state, */
|
||||
lua_pushnil(L); /* and initial value */
|
||||
}
|
||||
else {
|
||||
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
||||
lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traversal function for 'ipairs'
|
||||
*/
|
||||
static int ipairsaux (lua_State *L) {
|
||||
lua_Integer i = luaL_checkinteger(L, 2);
|
||||
i = luaL_intop(+, i, 1);
|
||||
lua_pushinteger(L, i);
|
||||
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
|
||||
** (The given "table" may not be a table.)
|
||||
*/
|
||||
static int luaB_ipairs (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
lua_pushcfunction(L, ipairsaux); /* iteration function */
|
||||
lua_pushvalue(L, 1); /* state */
|
||||
lua_pushinteger(L, 0); /* initial value */
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
static int load_aux (lua_State *L, int status, int envidx) {
|
||||
if (l_likely(status == LUA_OK)) {
|
||||
if (envidx != 0) { /* 'env' parameter? */
|
||||
lua_pushvalue(L, envidx); /* environment for loaded function */
|
||||
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
|
||||
lua_pop(L, 1); /* remove 'env' if not used by previous call */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else { /* error (message is on top of the stack) */
|
||||
luaL_pushfail(L);
|
||||
lua_insert(L, -2); /* put before error message */
|
||||
return 2; /* return fail plus error message */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_loadfile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
const char *mode = luaL_optstring(L, 2, NULL);
|
||||
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
|
||||
int status = luaL_loadfilex(L, fname, mode);
|
||||
return load_aux(L, status, env);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Read function
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** reserved slot, above all arguments, to hold a copy of the returned
|
||||
** string to avoid it being collected while parsed. 'load' has four
|
||||
** optional arguments (chunk, source name, mode, and environment).
|
||||
*/
|
||||
#define RESERVEDSLOT 5
|
||||
|
||||
|
||||
/*
|
||||
** Reader for generic 'load' function: 'lua_load' uses the
|
||||
** stack for internal stuff, so the reader cannot change the
|
||||
** stack top. Instead, it keeps its resulting string in a
|
||||
** reserved slot inside the stack.
|
||||
*/
|
||||
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
|
||||
(void)(ud); /* not used */
|
||||
luaL_checkstack(L, 2, "too many nested functions");
|
||||
lua_pushvalue(L, 1); /* get function */
|
||||
lua_call(L, 0, 1); /* call it */
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1); /* pop result */
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
else if (l_unlikely(!lua_isstring(L, -1)))
|
||||
luaL_error(L, "reader function must return a string");
|
||||
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
|
||||
return lua_tolstring(L, RESERVEDSLOT, size);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_load (lua_State *L) {
|
||||
int status;
|
||||
size_t l;
|
||||
const char *s = lua_tolstring(L, 1, &l);
|
||||
const char *mode = luaL_optstring(L, 3, "bt");
|
||||
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
|
||||
if (s != NULL) { /* loading a string? */
|
||||
const char *chunkname = luaL_optstring(L, 2, s);
|
||||
status = luaL_loadbufferx(L, s, l, chunkname, mode);
|
||||
}
|
||||
else { /* loading from a reader function */
|
||||
const char *chunkname = luaL_optstring(L, 2, "=(load)");
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
|
||||
status = lua_load(L, generic_reader, NULL, chunkname, mode);
|
||||
}
|
||||
return load_aux(L, status, env);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
|
||||
(void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */
|
||||
return lua_gettop(L) - 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_dofile (lua_State *L) {
|
||||
const char *fname = luaL_optstring(L, 1, NULL);
|
||||
lua_settop(L, 1);
|
||||
if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
|
||||
return lua_error(L);
|
||||
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
|
||||
return dofilecont(L, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_assert (lua_State *L) {
|
||||
if (l_likely(lua_toboolean(L, 1))) /* condition is true? */
|
||||
return lua_gettop(L); /* return all arguments */
|
||||
else { /* error */
|
||||
luaL_checkany(L, 1); /* there must be a condition */
|
||||
lua_remove(L, 1); /* remove it */
|
||||
lua_pushliteral(L, "assertion failed!"); /* default message */
|
||||
lua_settop(L, 1); /* leave only message (default if no other one) */
|
||||
return luaB_error(L); /* call 'error' */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_select (lua_State *L) {
|
||||
int n = lua_gettop(L);
|
||||
if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
|
||||
lua_pushinteger(L, n-1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_Integer i = luaL_checkinteger(L, 1);
|
||||
if (i < 0) i = n + i;
|
||||
else if (i > n) i = n;
|
||||
luaL_argcheck(L, 1 <= i, 1, "index out of range");
|
||||
return n - (int)i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Continuation function for 'pcall' and 'xpcall'. Both functions
|
||||
** already pushed a 'true' before doing the call, so in case of success
|
||||
** 'finishpcall' only has to return everything in the stack minus
|
||||
** 'extra' values (where 'extra' is exactly the number of items to be
|
||||
** ignored).
|
||||
*/
|
||||
static int finishpcall (lua_State *L, int status, lua_KContext extra) {
|
||||
if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */
|
||||
lua_pushboolean(L, 0); /* first result (false) */
|
||||
lua_pushvalue(L, -2); /* error message */
|
||||
return 2; /* return false, msg */
|
||||
}
|
||||
else
|
||||
return lua_gettop(L) - (int)extra; /* return all results */
|
||||
}
|
||||
|
||||
|
||||
static int luaB_pcall (lua_State *L) {
|
||||
int status;
|
||||
luaL_checkany(L, 1);
|
||||
lua_pushboolean(L, 1); /* first result if no errors */
|
||||
lua_insert(L, 1); /* put it in place */
|
||||
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall);
|
||||
return finishpcall(L, status, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Do a protected call with error handling. After 'lua_rotate', the
|
||||
** stack will have <f, err, true, f, [args...]>; so, the function passes
|
||||
** 2 to 'finishpcall' to skip the 2 first values when returning results.
|
||||
*/
|
||||
static int luaB_xpcall (lua_State *L) {
|
||||
int status;
|
||||
int n = lua_gettop(L);
|
||||
luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */
|
||||
lua_pushboolean(L, 1); /* first result */
|
||||
lua_pushvalue(L, 1); /* function */
|
||||
lua_rotate(L, 3, 2); /* move them below function's arguments */
|
||||
status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall);
|
||||
return finishpcall(L, status, 2);
|
||||
}
|
||||
|
||||
|
||||
static int luaB_tostring (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
luaL_tolstring(L, 1, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg base_funcs[] = {
|
||||
{"assert", luaB_assert},
|
||||
{"collectgarbage", luaB_collectgarbage},
|
||||
{"dofile", luaB_dofile},
|
||||
{"error", luaB_error},
|
||||
{"getmetatable", luaB_getmetatable},
|
||||
{"ipairs", luaB_ipairs},
|
||||
{"loadfile", luaB_loadfile},
|
||||
{"load", luaB_load},
|
||||
{"next", luaB_next},
|
||||
{"pairs", luaB_pairs},
|
||||
{"pcall", luaB_pcall},
|
||||
{"print", luaB_print},
|
||||
{"warn", luaB_warn},
|
||||
{"rawequal", luaB_rawequal},
|
||||
{"rawlen", luaB_rawlen},
|
||||
{"rawget", luaB_rawget},
|
||||
{"rawset", luaB_rawset},
|
||||
{"select", luaB_select},
|
||||
{"setmetatable", luaB_setmetatable},
|
||||
{"tonumber", luaB_tonumber},
|
||||
{"tostring", luaB_tostring},
|
||||
{"type", luaB_type},
|
||||
{"xpcall", luaB_xpcall},
|
||||
/* placeholders */
|
||||
{LUA_GNAME, NULL},
|
||||
{"_VERSION", NULL},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_base (lua_State *L) {
|
||||
/* open lib into global table */
|
||||
lua_pushglobaltable(L);
|
||||
luaL_setfuncs(L, base_funcs, 0);
|
||||
/* set global _G */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setfield(L, -2, LUA_GNAME);
|
||||
/* set global _VERSION */
|
||||
lua_pushliteral(L, LUA_VERSION);
|
||||
lua_setfield(L, -2, "_VERSION");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Vendored
+1874
File diff suppressed because it is too large
Load Diff
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
** $Id: lcode.h $
|
||||
** Code generator for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lcode_h
|
||||
#define lcode_h
|
||||
|
||||
#include "llex.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lparser.h"
|
||||
|
||||
|
||||
/*
|
||||
** Marks the end of a patch list. It is an invalid value both as an absolute
|
||||
** address, and as a list link (would link an element to itself).
|
||||
*/
|
||||
#define NO_JUMP (-1)
|
||||
|
||||
|
||||
/*
|
||||
** grep "ORDER OPR" if you change these enums (ORDER OP)
|
||||
*/
|
||||
typedef enum BinOpr {
|
||||
/* arithmetic operators */
|
||||
OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW,
|
||||
OPR_DIV, OPR_IDIV,
|
||||
/* bitwise operators */
|
||||
OPR_BAND, OPR_BOR, OPR_BXOR,
|
||||
OPR_SHL, OPR_SHR,
|
||||
/* string operator */
|
||||
OPR_CONCAT,
|
||||
/* comparison operators */
|
||||
OPR_EQ, OPR_LT, OPR_LE,
|
||||
OPR_NE, OPR_GT, OPR_GE,
|
||||
/* logical operators */
|
||||
OPR_AND, OPR_OR,
|
||||
OPR_NOBINOPR
|
||||
} BinOpr;
|
||||
|
||||
|
||||
/* true if operation is foldable (that is, it is arithmetic or bitwise) */
|
||||
#define foldbinop(op) ((op) <= OPR_SHR)
|
||||
|
||||
|
||||
#define luaK_codeABC(fs,o,a,b,c) luaK_codeABCk(fs,o,a,b,c,0)
|
||||
|
||||
|
||||
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
|
||||
|
||||
|
||||
/* get (pointer to) instruction of given 'expdesc' */
|
||||
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
|
||||
|
||||
|
||||
#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
|
||||
|
||||
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
|
||||
|
||||
LUAI_FUNC int luaK_code (FuncState *fs, Instruction i);
|
||||
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
|
||||
LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
|
||||
int B, int C, int k);
|
||||
LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
|
||||
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
|
||||
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
|
||||
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
|
||||
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
|
||||
LUAI_FUNC void luaK_int (FuncState *fs, int reg, lua_Integer n);
|
||||
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
||||
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
||||
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
||||
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
|
||||
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
|
||||
LUAI_FUNC int luaK_jump (FuncState *fs);
|
||||
LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
|
||||
LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
|
||||
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
|
||||
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
|
||||
LUAI_FUNC int luaK_getlabel (FuncState *fs);
|
||||
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
|
||||
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
|
||||
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
|
||||
expdesc *v2, int line);
|
||||
LUAI_FUNC void luaK_settablesize (FuncState *fs, int pc,
|
||||
int ra, int asize, int hsize);
|
||||
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
|
||||
LUAI_FUNC void luaK_finish (FuncState *fs);
|
||||
LUAI_FUNC l_noret luaK_semerror (LexState *ls, const char *msg);
|
||||
|
||||
|
||||
#endif
|
||||
Vendored
+210
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
** $Id: lcorolib.c $
|
||||
** Coroutine Library
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lcorolib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
static lua_State *getco (lua_State *L) {
|
||||
lua_State *co = lua_tothread(L, 1);
|
||||
luaL_argexpected(L, co, 1, "thread");
|
||||
return co;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Resumes a coroutine. Returns the number of results for non-error
|
||||
** cases or -1 for errors.
|
||||
*/
|
||||
static int auxresume (lua_State *L, lua_State *co, int narg) {
|
||||
int status, nres;
|
||||
if (l_unlikely(!lua_checkstack(co, narg))) {
|
||||
lua_pushliteral(L, "too many arguments to resume");
|
||||
return -1; /* error flag */
|
||||
}
|
||||
lua_xmove(L, co, narg);
|
||||
status = lua_resume(co, L, narg, &nres);
|
||||
if (l_likely(status == LUA_OK || status == LUA_YIELD)) {
|
||||
if (l_unlikely(!lua_checkstack(L, nres + 1))) {
|
||||
lua_pop(co, nres); /* remove results anyway */
|
||||
lua_pushliteral(L, "too many results to resume");
|
||||
return -1; /* error flag */
|
||||
}
|
||||
lua_xmove(co, L, nres); /* move yielded values */
|
||||
return nres;
|
||||
}
|
||||
else {
|
||||
lua_xmove(co, L, 1); /* move error message */
|
||||
return -1; /* error flag */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_coresume (lua_State *L) {
|
||||
lua_State *co = getco(L);
|
||||
int r;
|
||||
r = auxresume(L, co, lua_gettop(L) - 1);
|
||||
if (l_unlikely(r < 0)) {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_insert(L, -2);
|
||||
return 2; /* return false + error message */
|
||||
}
|
||||
else {
|
||||
lua_pushboolean(L, 1);
|
||||
lua_insert(L, -(r + 1));
|
||||
return r + 1; /* return true + 'resume' returns */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_auxwrap (lua_State *L) {
|
||||
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
|
||||
int r = auxresume(L, co, lua_gettop(L));
|
||||
if (l_unlikely(r < 0)) { /* error? */
|
||||
int stat = lua_status(co);
|
||||
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
||||
stat = lua_closethread(co, L); /* close its tbc variables */
|
||||
lua_assert(stat != LUA_OK);
|
||||
lua_xmove(co, L, 1); /* move error message to the caller */
|
||||
}
|
||||
if (stat != LUA_ERRMEM && /* not a memory error and ... */
|
||||
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
|
||||
luaL_where(L, 1); /* add extra info, if available */
|
||||
lua_insert(L, -2);
|
||||
lua_concat(L, 2);
|
||||
}
|
||||
return lua_error(L); /* propagate error */
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_cocreate (lua_State *L) {
|
||||
lua_State *NL;
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
NL = lua_newthread(L);
|
||||
lua_pushvalue(L, 1); /* move function to top */
|
||||
lua_xmove(L, NL, 1); /* move function from L to NL */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_cowrap (lua_State *L) {
|
||||
luaB_cocreate(L);
|
||||
lua_pushcclosure(L, luaB_auxwrap, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_yield (lua_State *L) {
|
||||
return lua_yield(L, lua_gettop(L));
|
||||
}
|
||||
|
||||
|
||||
#define COS_RUN 0
|
||||
#define COS_DEAD 1
|
||||
#define COS_YIELD 2
|
||||
#define COS_NORM 3
|
||||
|
||||
|
||||
static const char *const statname[] =
|
||||
{"running", "dead", "suspended", "normal"};
|
||||
|
||||
|
||||
static int auxstatus (lua_State *L, lua_State *co) {
|
||||
if (L == co) return COS_RUN;
|
||||
else {
|
||||
switch (lua_status(co)) {
|
||||
case LUA_YIELD:
|
||||
return COS_YIELD;
|
||||
case LUA_OK: {
|
||||
lua_Debug ar;
|
||||
if (lua_getstack(co, 0, &ar)) /* does it have frames? */
|
||||
return COS_NORM; /* it is running */
|
||||
else if (lua_gettop(co) == 0)
|
||||
return COS_DEAD;
|
||||
else
|
||||
return COS_YIELD; /* initial state */
|
||||
}
|
||||
default: /* some error occurred */
|
||||
return COS_DEAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int luaB_costatus (lua_State *L) {
|
||||
lua_State *co = getco(L);
|
||||
lua_pushstring(L, statname[auxstatus(L, co)]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_yieldable (lua_State *L) {
|
||||
lua_State *co = lua_isnone(L, 1) ? L : getco(L);
|
||||
lua_pushboolean(L, lua_isyieldable(co));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_corunning (lua_State *L) {
|
||||
int ismain = lua_pushthread(L);
|
||||
lua_pushboolean(L, ismain);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
static int luaB_close (lua_State *L) {
|
||||
lua_State *co = getco(L);
|
||||
int status = auxstatus(L, co);
|
||||
switch (status) {
|
||||
case COS_DEAD: case COS_YIELD: {
|
||||
status = lua_closethread(co, L);
|
||||
if (status == LUA_OK) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_xmove(co, L, 1); /* move error message */
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
default: /* normal or running coroutine */
|
||||
return luaL_error(L, "cannot close a %s coroutine", statname[status]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg co_funcs[] = {
|
||||
{"create", luaB_cocreate},
|
||||
{"resume", luaB_coresume},
|
||||
{"running", luaB_corunning},
|
||||
{"status", luaB_costatus},
|
||||
{"wrap", luaB_cowrap},
|
||||
{"yield", luaB_yield},
|
||||
{"isyieldable", luaB_yieldable},
|
||||
{"close", luaB_close},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_coroutine (lua_State *L) {
|
||||
luaL_newlib(L, co_funcs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
** $Id: lctype.c $
|
||||
** 'ctype' functions for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define lctype_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include "lctype.h"
|
||||
|
||||
#if !LUA_USE_CTYPE /* { */
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
#if defined (LUA_UCID) /* accept UniCode IDentifiers? */
|
||||
/* consider all non-ascii codepoints to be alphabetic */
|
||||
#define NONA 0x01
|
||||
#else
|
||||
#define NONA 0x00 /* default */
|
||||
#endif
|
||||
|
||||
|
||||
LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
|
||||
0x00, /* EOZ */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */
|
||||
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */
|
||||
0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */
|
||||
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05,
|
||||
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */
|
||||
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00,
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 8. */
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* 9. */
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* a. */
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* b. */
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
|
||||
0x00, 0x00, NONA, NONA, NONA, NONA, NONA, NONA, /* c. */
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* d. */
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA, /* e. */
|
||||
NONA, NONA, NONA, NONA, NONA, NONA, NONA, NONA,
|
||||
NONA, NONA, NONA, NONA, NONA, 0x00, 0x00, 0x00, /* f. */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
#endif /* } */
|
||||
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
** $Id: lctype.h $
|
||||
** 'ctype' functions for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef lctype_h
|
||||
#define lctype_h
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
/*
|
||||
** WARNING: the functions defined here do not necessarily correspond
|
||||
** to the similar functions in the standard C ctype.h. They are
|
||||
** optimized for the specific needs of Lua.
|
||||
*/
|
||||
|
||||
#if !defined(LUA_USE_CTYPE)
|
||||
|
||||
#if 'A' == 65 && '0' == 48
|
||||
/* ASCII case: can use its own tables; faster and fixed */
|
||||
#define LUA_USE_CTYPE 0
|
||||
#else
|
||||
/* must use standard C ctype */
|
||||
#define LUA_USE_CTYPE 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !LUA_USE_CTYPE /* { */
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "llimits.h"
|
||||
|
||||
|
||||
#define ALPHABIT 0
|
||||
#define DIGITBIT 1
|
||||
#define PRINTBIT 2
|
||||
#define SPACEBIT 3
|
||||
#define XDIGITBIT 4
|
||||
|
||||
|
||||
#define MASK(B) (1 << (B))
|
||||
|
||||
|
||||
/*
|
||||
** add 1 to char to allow index -1 (EOZ)
|
||||
*/
|
||||
#define testprop(c,p) (luai_ctype_[(c)+1] & (p))
|
||||
|
||||
/*
|
||||
** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_'
|
||||
*/
|
||||
#define lislalpha(c) testprop(c, MASK(ALPHABIT))
|
||||
#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT)))
|
||||
#define lisdigit(c) testprop(c, MASK(DIGITBIT))
|
||||
#define lisspace(c) testprop(c, MASK(SPACEBIT))
|
||||
#define lisprint(c) testprop(c, MASK(PRINTBIT))
|
||||
#define lisxdigit(c) testprop(c, MASK(XDIGITBIT))
|
||||
|
||||
|
||||
/*
|
||||
** In ASCII, this 'ltolower' is correct for alphabetic characters and
|
||||
** for '.'. That is enough for Lua needs. ('check_exp' ensures that
|
||||
** the character either is an upper-case letter or is unchanged by
|
||||
** the transformation, which holds for lower-case letters and '.'.)
|
||||
*/
|
||||
#define ltolower(c) \
|
||||
check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \
|
||||
(c) | ('A' ^ 'a'))
|
||||
|
||||
|
||||
/* one entry for each character and for -1 (EOZ) */
|
||||
LUAI_DDEC(const lu_byte luai_ctype_[UCHAR_MAX + 2];)
|
||||
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
/*
|
||||
** use standard C ctypes
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#define lislalpha(c) (isalpha(c) || (c) == '_')
|
||||
#define lislalnum(c) (isalnum(c) || (c) == '_')
|
||||
#define lisdigit(c) (isdigit(c))
|
||||
#define lisspace(c) (isspace(c))
|
||||
#define lisprint(c) (isprint(c))
|
||||
#define lisxdigit(c) (isxdigit(c))
|
||||
|
||||
#define ltolower(c) (tolower(c))
|
||||
|
||||
#endif /* } */
|
||||
|
||||
#endif
|
||||
|
||||
Vendored
+483
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
** $Id: ldblib.c $
|
||||
** Interface from Lua to its debug API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define ldblib_c
|
||||
#define LUA_LIB
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
|
||||
/*
|
||||
** The hook table at registry[HOOKKEY] maps threads to their current
|
||||
** hook function.
|
||||
*/
|
||||
static const char *const HOOKKEY = "_HOOKKEY";
|
||||
|
||||
|
||||
/*
|
||||
** If L1 != L, L1 can be in any state, and therefore there are no
|
||||
** guarantees about its stack space; any push in L1 must be
|
||||
** checked.
|
||||
*/
|
||||
static void checkstack (lua_State *L, lua_State *L1, int n) {
|
||||
if (l_unlikely(L != L1 && !lua_checkstack(L1, n)))
|
||||
luaL_error(L, "stack overflow");
|
||||
}
|
||||
|
||||
|
||||
static int db_getregistry (lua_State *L) {
|
||||
lua_pushvalue(L, LUA_REGISTRYINDEX);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_getmetatable (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (!lua_getmetatable(L, 1)) {
|
||||
lua_pushnil(L); /* no metatable */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_setmetatable (lua_State *L) {
|
||||
int t = lua_type(L, 2);
|
||||
luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
|
||||
lua_settop(L, 2);
|
||||
lua_setmetatable(L, 1);
|
||||
return 1; /* return 1st argument */
|
||||
}
|
||||
|
||||
|
||||
static int db_getuservalue (lua_State *L) {
|
||||
int n = (int)luaL_optinteger(L, 2, 1);
|
||||
if (lua_type(L, 1) != LUA_TUSERDATA)
|
||||
luaL_pushfail(L);
|
||||
else if (lua_getiuservalue(L, 1, n) != LUA_TNONE) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_setuservalue (lua_State *L) {
|
||||
int n = (int)luaL_optinteger(L, 3, 1);
|
||||
luaL_checktype(L, 1, LUA_TUSERDATA);
|
||||
luaL_checkany(L, 2);
|
||||
lua_settop(L, 2);
|
||||
if (!lua_setiuservalue(L, 1, n))
|
||||
luaL_pushfail(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Auxiliary function used by several library functions: check for
|
||||
** an optional thread as function's first argument and set 'arg' with
|
||||
** 1 if this argument is present (so that functions can skip it to
|
||||
** access their other arguments)
|
||||
*/
|
||||
static lua_State *getthread (lua_State *L, int *arg) {
|
||||
if (lua_isthread(L, 1)) {
|
||||
*arg = 1;
|
||||
return lua_tothread(L, 1);
|
||||
}
|
||||
else {
|
||||
*arg = 0;
|
||||
return L; /* function will operate over current thread */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Variations of 'lua_settable', used by 'db_getinfo' to put results
|
||||
** from 'lua_getinfo' into result table. Key is always a string;
|
||||
** value can be a string, an int, or a boolean.
|
||||
*/
|
||||
static void settabss (lua_State *L, const char *k, const char *v) {
|
||||
lua_pushstring(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
}
|
||||
|
||||
static void settabsi (lua_State *L, const char *k, int v) {
|
||||
lua_pushinteger(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
}
|
||||
|
||||
static void settabsb (lua_State *L, const char *k, int v) {
|
||||
lua_pushboolean(L, v);
|
||||
lua_setfield(L, -2, k);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** In function 'db_getinfo', the call to 'lua_getinfo' may push
|
||||
** results on the stack; later it creates the result table to put
|
||||
** these objects. Function 'treatstackoption' puts the result from
|
||||
** 'lua_getinfo' on top of the result table so that it can call
|
||||
** 'lua_setfield'.
|
||||
*/
|
||||
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
|
||||
if (L == L1)
|
||||
lua_rotate(L, -2, 1); /* exchange object and table */
|
||||
else
|
||||
lua_xmove(L1, L, 1); /* move object to the "main" stack */
|
||||
lua_setfield(L, -2, fname); /* put object into table */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Calls 'lua_getinfo' and collects all results in a new table.
|
||||
** L1 needs stack space for an optional input (function) plus
|
||||
** two optional outputs (function and line table) from function
|
||||
** 'lua_getinfo'.
|
||||
*/
|
||||
static int db_getinfo (lua_State *L) {
|
||||
lua_Debug ar;
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *options = luaL_optstring(L, arg+2, "flnSrtu");
|
||||
checkstack(L, L1, 3);
|
||||
luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'");
|
||||
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
|
||||
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
|
||||
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
|
||||
lua_xmove(L, L1, 1);
|
||||
}
|
||||
else { /* stack level */
|
||||
if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
|
||||
luaL_pushfail(L); /* level out of range */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (!lua_getinfo(L1, options, &ar))
|
||||
return luaL_argerror(L, arg+2, "invalid option");
|
||||
lua_newtable(L); /* table to collect results */
|
||||
if (strchr(options, 'S')) {
|
||||
lua_pushlstring(L, ar.source, ar.srclen);
|
||||
lua_setfield(L, -2, "source");
|
||||
settabss(L, "short_src", ar.short_src);
|
||||
settabsi(L, "linedefined", ar.linedefined);
|
||||
settabsi(L, "lastlinedefined", ar.lastlinedefined);
|
||||
settabss(L, "what", ar.what);
|
||||
}
|
||||
if (strchr(options, 'l'))
|
||||
settabsi(L, "currentline", ar.currentline);
|
||||
if (strchr(options, 'u')) {
|
||||
settabsi(L, "nups", ar.nups);
|
||||
settabsi(L, "nparams", ar.nparams);
|
||||
settabsb(L, "isvararg", ar.isvararg);
|
||||
}
|
||||
if (strchr(options, 'n')) {
|
||||
settabss(L, "name", ar.name);
|
||||
settabss(L, "namewhat", ar.namewhat);
|
||||
}
|
||||
if (strchr(options, 'r')) {
|
||||
settabsi(L, "ftransfer", ar.ftransfer);
|
||||
settabsi(L, "ntransfer", ar.ntransfer);
|
||||
}
|
||||
if (strchr(options, 't'))
|
||||
settabsb(L, "istailcall", ar.istailcall);
|
||||
if (strchr(options, 'L'))
|
||||
treatstackoption(L, L1, "activelines");
|
||||
if (strchr(options, 'f'))
|
||||
treatstackoption(L, L1, "func");
|
||||
return 1; /* return table */
|
||||
}
|
||||
|
||||
|
||||
static int db_getlocal (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */
|
||||
if (lua_isfunction(L, arg + 1)) { /* function argument? */
|
||||
lua_pushvalue(L, arg + 1); /* push function */
|
||||
lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
|
||||
return 1; /* return only name (there is no value) */
|
||||
}
|
||||
else { /* stack-level argument */
|
||||
lua_Debug ar;
|
||||
const char *name;
|
||||
int level = (int)luaL_checkinteger(L, arg + 1);
|
||||
if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
|
||||
return luaL_argerror(L, arg+1, "level out of range");
|
||||
checkstack(L, L1, 1);
|
||||
name = lua_getlocal(L1, &ar, nvar);
|
||||
if (name) {
|
||||
lua_xmove(L1, L, 1); /* move local value */
|
||||
lua_pushstring(L, name); /* push name */
|
||||
lua_rotate(L, -2, 1); /* re-order */
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
luaL_pushfail(L); /* no name (nor value) */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int db_setlocal (lua_State *L) {
|
||||
int arg;
|
||||
const char *name;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
lua_Debug ar;
|
||||
int level = (int)luaL_checkinteger(L, arg + 1);
|
||||
int nvar = (int)luaL_checkinteger(L, arg + 2);
|
||||
if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
|
||||
return luaL_argerror(L, arg+1, "level out of range");
|
||||
luaL_checkany(L, arg+3);
|
||||
lua_settop(L, arg+3);
|
||||
checkstack(L, L1, 1);
|
||||
lua_xmove(L, L1, 1);
|
||||
name = lua_setlocal(L1, &ar, nvar);
|
||||
if (name == NULL)
|
||||
lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */
|
||||
lua_pushstring(L, name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** get (if 'get' is true) or set an upvalue from a closure
|
||||
*/
|
||||
static int auxupvalue (lua_State *L, int get) {
|
||||
const char *name;
|
||||
int n = (int)luaL_checkinteger(L, 2); /* upvalue index */
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */
|
||||
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
|
||||
if (name == NULL) return 0;
|
||||
lua_pushstring(L, name);
|
||||
lua_insert(L, -(get+1)); /* no-op if get is false */
|
||||
return get + 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_getupvalue (lua_State *L) {
|
||||
return auxupvalue(L, 1);
|
||||
}
|
||||
|
||||
|
||||
static int db_setupvalue (lua_State *L) {
|
||||
luaL_checkany(L, 3);
|
||||
return auxupvalue(L, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether a given upvalue from a given closure exists and
|
||||
** returns its index
|
||||
*/
|
||||
static void *checkupval (lua_State *L, int argf, int argnup, int *pnup) {
|
||||
void *id;
|
||||
int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */
|
||||
luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */
|
||||
id = lua_upvalueid(L, argf, nup);
|
||||
if (pnup) {
|
||||
luaL_argcheck(L, id != NULL, argnup, "invalid upvalue index");
|
||||
*pnup = nup;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
static int db_upvalueid (lua_State *L) {
|
||||
void *id = checkupval(L, 1, 2, NULL);
|
||||
if (id != NULL)
|
||||
lua_pushlightuserdata(L, id);
|
||||
else
|
||||
luaL_pushfail(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_upvaluejoin (lua_State *L) {
|
||||
int n1, n2;
|
||||
checkupval(L, 1, 2, &n1);
|
||||
checkupval(L, 3, 4, &n2);
|
||||
luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
|
||||
luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
|
||||
lua_upvaluejoin(L, 1, n1, 3, n2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Call hook function registered at hook table for the current
|
||||
** thread (if there is one)
|
||||
*/
|
||||
static void hookf (lua_State *L, lua_Debug *ar) {
|
||||
static const char *const hooknames[] =
|
||||
{"call", "return", "line", "count", "tail call"};
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY);
|
||||
lua_pushthread(L);
|
||||
if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */
|
||||
lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */
|
||||
if (ar->currentline >= 0)
|
||||
lua_pushinteger(L, ar->currentline); /* push current line */
|
||||
else lua_pushnil(L);
|
||||
lua_assert(lua_getinfo(L, "lS", ar));
|
||||
lua_call(L, 2, 0); /* call hook function */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Convert a string mask (for 'sethook') into a bit mask
|
||||
*/
|
||||
static int makemask (const char *smask, int count) {
|
||||
int mask = 0;
|
||||
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
|
||||
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
|
||||
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
|
||||
if (count > 0) mask |= LUA_MASKCOUNT;
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Convert a bit mask (for 'gethook') into a string mask
|
||||
*/
|
||||
static char *unmakemask (int mask, char *smask) {
|
||||
int i = 0;
|
||||
if (mask & LUA_MASKCALL) smask[i++] = 'c';
|
||||
if (mask & LUA_MASKRET) smask[i++] = 'r';
|
||||
if (mask & LUA_MASKLINE) smask[i++] = 'l';
|
||||
smask[i] = '\0';
|
||||
return smask;
|
||||
}
|
||||
|
||||
|
||||
static int db_sethook (lua_State *L) {
|
||||
int arg, mask, count;
|
||||
lua_Hook func;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
if (lua_isnoneornil(L, arg+1)) { /* no hook? */
|
||||
lua_settop(L, arg+1);
|
||||
func = NULL; mask = 0; count = 0; /* turn off hooks */
|
||||
}
|
||||
else {
|
||||
const char *smask = luaL_checkstring(L, arg+2);
|
||||
luaL_checktype(L, arg+1, LUA_TFUNCTION);
|
||||
count = (int)luaL_optinteger(L, arg + 3, 0);
|
||||
func = hookf; mask = makemask(smask, count);
|
||||
}
|
||||
if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) {
|
||||
/* table just created; initialize it */
|
||||
lua_pushliteral(L, "k");
|
||||
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
|
||||
lua_pushvalue(L, -1);
|
||||
lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */
|
||||
}
|
||||
checkstack(L, L1, 1);
|
||||
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
|
||||
lua_pushvalue(L, arg + 1); /* value (hook function) */
|
||||
lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
|
||||
lua_sethook(L1, func, mask, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int db_gethook (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
char buff[5];
|
||||
int mask = lua_gethookmask(L1);
|
||||
lua_Hook hook = lua_gethook(L1);
|
||||
if (hook == NULL) { /* no hook? */
|
||||
luaL_pushfail(L);
|
||||
return 1;
|
||||
}
|
||||
else if (hook != hookf) /* external hook? */
|
||||
lua_pushliteral(L, "external hook");
|
||||
else { /* hook table must exist */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, HOOKKEY);
|
||||
checkstack(L, L1, 1);
|
||||
lua_pushthread(L1); lua_xmove(L1, L, 1);
|
||||
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
|
||||
lua_remove(L, -2); /* remove hook table */
|
||||
}
|
||||
lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */
|
||||
lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
||||
static int db_debug (lua_State *L) {
|
||||
for (;;) {
|
||||
char buffer[250];
|
||||
lua_writestringerror("%s", "lua_debug> ");
|
||||
if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
|
||||
strcmp(buffer, "cont\n") == 0)
|
||||
return 0;
|
||||
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
|
||||
lua_pcall(L, 0, 0, 0))
|
||||
lua_writestringerror("%s\n", luaL_tolstring(L, -1, NULL));
|
||||
lua_settop(L, 0); /* remove eventual returns */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int db_traceback (lua_State *L) {
|
||||
int arg;
|
||||
lua_State *L1 = getthread(L, &arg);
|
||||
const char *msg = lua_tostring(L, arg + 1);
|
||||
if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
|
||||
lua_pushvalue(L, arg + 1); /* return it untouched */
|
||||
else {
|
||||
int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
|
||||
luaL_traceback(L, L1, msg, level);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int db_setcstacklimit (lua_State *L) {
|
||||
int limit = (int)luaL_checkinteger(L, 1);
|
||||
int res = lua_setcstacklimit(L, limit);
|
||||
lua_pushinteger(L, res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const luaL_Reg dblib[] = {
|
||||
{"debug", db_debug},
|
||||
{"getuservalue", db_getuservalue},
|
||||
{"gethook", db_gethook},
|
||||
{"getinfo", db_getinfo},
|
||||
{"getlocal", db_getlocal},
|
||||
{"getregistry", db_getregistry},
|
||||
{"getmetatable", db_getmetatable},
|
||||
{"getupvalue", db_getupvalue},
|
||||
{"upvaluejoin", db_upvaluejoin},
|
||||
{"upvalueid", db_upvalueid},
|
||||
{"setuservalue", db_setuservalue},
|
||||
{"sethook", db_sethook},
|
||||
{"setlocal", db_setlocal},
|
||||
{"setmetatable", db_setmetatable},
|
||||
{"setupvalue", db_setupvalue},
|
||||
{"traceback", db_traceback},
|
||||
{"setcstacklimit", db_setcstacklimit},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
LUAMOD_API int luaopen_debug (lua_State *L) {
|
||||
luaL_newlib(L, dblib);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Vendored
+962
@@ -0,0 +1,962 @@
|
||||
/*
|
||||
** $Id: ldebug.c $
|
||||
** Debug Interface
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define ldebug_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
#include "lapi.h"
|
||||
#include "lcode.h"
|
||||
#include "ldebug.h"
|
||||
#include "ldo.h"
|
||||
#include "lfunc.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lstate.h"
|
||||
#include "lstring.h"
|
||||
#include "ltable.h"
|
||||
#include "ltm.h"
|
||||
#include "lvm.h"
|
||||
|
||||
|
||||
|
||||
#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
|
||||
|
||||
|
||||
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
||||
const char **name);
|
||||
|
||||
|
||||
static int currentpc (CallInfo *ci) {
|
||||
lua_assert(isLua(ci));
|
||||
return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Get a "base line" to find the line corresponding to an instruction.
|
||||
** Base lines are regularly placed at MAXIWTHABS intervals, so usually
|
||||
** an integer division gets the right place. When the source file has
|
||||
** large sequences of empty/comment lines, it may need extra entries,
|
||||
** so the original estimate needs a correction.
|
||||
** If the original estimate is -1, the initial 'if' ensures that the
|
||||
** 'while' will run at least once.
|
||||
** The assertion that the estimate is a lower bound for the correct base
|
||||
** is valid as long as the debug info has been generated with the same
|
||||
** value for MAXIWTHABS or smaller. (Previous releases use a little
|
||||
** smaller value.)
|
||||
*/
|
||||
static int getbaseline (const Proto *f, int pc, int *basepc) {
|
||||
if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) {
|
||||
*basepc = -1; /* start from the beginning */
|
||||
return f->linedefined;
|
||||
}
|
||||
else {
|
||||
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
|
||||
/* estimate must be a lower bound of the correct base */
|
||||
lua_assert(i < 0 ||
|
||||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
|
||||
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
|
||||
i++; /* low estimate; adjust it */
|
||||
*basepc = f->abslineinfo[i].pc;
|
||||
return f->abslineinfo[i].line;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Get the line corresponding to instruction 'pc' in function 'f';
|
||||
** first gets a base line and from there does the increments until
|
||||
** the desired instruction.
|
||||
*/
|
||||
int luaG_getfuncline (const Proto *f, int pc) {
|
||||
if (f->lineinfo == NULL) /* no debug information? */
|
||||
return -1;
|
||||
else {
|
||||
int basepc;
|
||||
int baseline = getbaseline(f, pc, &basepc);
|
||||
while (basepc++ < pc) { /* walk until given instruction */
|
||||
lua_assert(f->lineinfo[basepc] != ABSLINEINFO);
|
||||
baseline += f->lineinfo[basepc]; /* correct line */
|
||||
}
|
||||
return baseline;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int getcurrentline (CallInfo *ci) {
|
||||
return luaG_getfuncline(ci_func(ci)->p, currentpc(ci));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Set 'trap' for all active Lua frames.
|
||||
** This function can be called during a signal, under "reasonable"
|
||||
** assumptions. A new 'ci' is completely linked in the list before it
|
||||
** becomes part of the "active" list, and we assume that pointers are
|
||||
** atomic; see comment in next function.
|
||||
** (A compiler doing interprocedural optimizations could, theoretically,
|
||||
** reorder memory writes in such a way that the list could be
|
||||
** temporarily broken while inserting a new element. We simply assume it
|
||||
** has no good reasons to do that.)
|
||||
*/
|
||||
static void settraps (CallInfo *ci) {
|
||||
for (; ci != NULL; ci = ci->previous)
|
||||
if (isLua(ci))
|
||||
ci->u.l.trap = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function can be called during a signal, under "reasonable"
|
||||
** assumptions.
|
||||
** Fields 'basehookcount' and 'hookcount' (set by 'resethookcount')
|
||||
** are for debug only, and it is no problem if they get arbitrary
|
||||
** values (causes at most one wrong hook call). 'hookmask' is an atomic
|
||||
** value. We assume that pointers are atomic too (e.g., gcc ensures that
|
||||
** for all platforms where it runs). Moreover, 'hook' is always checked
|
||||
** before being called (see 'luaD_hook').
|
||||
*/
|
||||
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
|
||||
if (func == NULL || mask == 0) { /* turn off hooks? */
|
||||
mask = 0;
|
||||
func = NULL;
|
||||
}
|
||||
L->hook = func;
|
||||
L->basehookcount = count;
|
||||
resethookcount(L);
|
||||
L->hookmask = cast_byte(mask);
|
||||
if (mask)
|
||||
settraps(L->ci); /* to trace inside 'luaV_execute' */
|
||||
}
|
||||
|
||||
|
||||
LUA_API lua_Hook lua_gethook (lua_State *L) {
|
||||
return L->hook;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_gethookmask (lua_State *L) {
|
||||
return L->hookmask;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_gethookcount (lua_State *L) {
|
||||
return L->basehookcount;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
|
||||
int status;
|
||||
CallInfo *ci;
|
||||
if (level < 0) return 0; /* invalid (negative) level */
|
||||
lua_lock(L);
|
||||
for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
|
||||
level--;
|
||||
if (level == 0 && ci != &L->base_ci) { /* level found? */
|
||||
status = 1;
|
||||
ar->i_ci = ci;
|
||||
}
|
||||
else status = 0; /* no such level */
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static const char *upvalname (const Proto *p, int uv) {
|
||||
TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
|
||||
if (s == NULL) return "?";
|
||||
else return getstr(s);
|
||||
}
|
||||
|
||||
|
||||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||
if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
|
||||
int nextra = ci->u.l.nextraargs;
|
||||
if (n >= -nextra) { /* 'n' is negative */
|
||||
*pos = ci->func.p - nextra - (n + 1);
|
||||
return "(vararg)"; /* generic name for any vararg */
|
||||
}
|
||||
}
|
||||
return NULL; /* no such vararg */
|
||||
}
|
||||
|
||||
|
||||
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
||||
StkId base = ci->func.p + 1;
|
||||
const char *name = NULL;
|
||||
if (isLua(ci)) {
|
||||
if (n < 0) /* access to vararg values? */
|
||||
return findvararg(ci, n, pos);
|
||||
else
|
||||
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
|
||||
}
|
||||
if (name == NULL) { /* no 'standard' name? */
|
||||
StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
|
||||
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
|
||||
/* generic name for any valid slot */
|
||||
name = isLua(ci) ? "(temporary)" : "(C temporary)";
|
||||
}
|
||||
else
|
||||
return NULL; /* no name */
|
||||
}
|
||||
if (pos)
|
||||
*pos = base + (n - 1);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
const char *name;
|
||||
lua_lock(L);
|
||||
if (ar == NULL) { /* information about non-active function? */
|
||||
if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
|
||||
name = NULL;
|
||||
else /* consider live variables at function start (parameters) */
|
||||
name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
|
||||
}
|
||||
else { /* active function; get information through 'ar' */
|
||||
StkId pos = NULL; /* to avoid warnings */
|
||||
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
||||
if (name) {
|
||||
setobjs2s(L, L->top.p, pos);
|
||||
api_incr_top(L);
|
||||
}
|
||||
}
|
||||
lua_unlock(L);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
StkId pos = NULL; /* to avoid warnings */
|
||||
const char *name;
|
||||
lua_lock(L);
|
||||
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
||||
if (name) {
|
||||
setobjs2s(L, pos, L->top.p - 1);
|
||||
L->top.p--; /* pop value */
|
||||
}
|
||||
lua_unlock(L);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
static void funcinfo (lua_Debug *ar, Closure *cl) {
|
||||
if (!LuaClosure(cl)) {
|
||||
ar->source = "=[C]";
|
||||
ar->srclen = LL("=[C]");
|
||||
ar->linedefined = -1;
|
||||
ar->lastlinedefined = -1;
|
||||
ar->what = "C";
|
||||
}
|
||||
else {
|
||||
const Proto *p = cl->l.p;
|
||||
if (p->source) {
|
||||
ar->source = getstr(p->source);
|
||||
ar->srclen = tsslen(p->source);
|
||||
}
|
||||
else {
|
||||
ar->source = "=?";
|
||||
ar->srclen = LL("=?");
|
||||
}
|
||||
ar->linedefined = p->linedefined;
|
||||
ar->lastlinedefined = p->lastlinedefined;
|
||||
ar->what = (ar->linedefined == 0) ? "main" : "Lua";
|
||||
}
|
||||
luaO_chunkid(ar->short_src, ar->source, ar->srclen);
|
||||
}
|
||||
|
||||
|
||||
static int nextline (const Proto *p, int currentline, int pc) {
|
||||
if (p->lineinfo[pc] != ABSLINEINFO)
|
||||
return currentline + p->lineinfo[pc];
|
||||
else
|
||||
return luaG_getfuncline(p, pc);
|
||||
}
|
||||
|
||||
|
||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
if (!LuaClosure(f)) {
|
||||
setnilvalue(s2v(L->top.p));
|
||||
api_incr_top(L);
|
||||
}
|
||||
else {
|
||||
const Proto *p = f->l.p;
|
||||
int currentline = p->linedefined;
|
||||
Table *t = luaH_new(L); /* new table to store active lines */
|
||||
sethvalue2s(L, L->top.p, t); /* push it on stack */
|
||||
api_incr_top(L);
|
||||
if (p->lineinfo != NULL) { /* proto with debug information? */
|
||||
int i;
|
||||
TValue v;
|
||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||
if (!p->is_vararg) /* regular function? */
|
||||
i = 0; /* consider all instructions */
|
||||
else { /* vararg function */
|
||||
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
||||
currentline = nextline(p, currentline, 0);
|
||||
i = 1; /* skip first instruction (OP_VARARGPREP) */
|
||||
}
|
||||
for (; i < p->sizelineinfo; i++) { /* for each instruction */
|
||||
currentline = nextline(p, currentline, i); /* get its line */
|
||||
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
||||
/* calling function is a known function? */
|
||||
if (ci != NULL && !(ci->callstatus & CIST_TAIL))
|
||||
return funcnamefromcall(L, ci->previous, name);
|
||||
else return NULL; /* no way to find a name */
|
||||
}
|
||||
|
||||
|
||||
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
|
||||
Closure *f, CallInfo *ci) {
|
||||
int status = 1;
|
||||
for (; *what; what++) {
|
||||
switch (*what) {
|
||||
case 'S': {
|
||||
funcinfo(ar, f);
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
ar->currentline = (ci && isLua(ci)) ? getcurrentline(ci) : -1;
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
|
||||
if (!LuaClosure(f)) {
|
||||
ar->isvararg = 1;
|
||||
ar->nparams = 0;
|
||||
}
|
||||
else {
|
||||
ar->isvararg = f->l.p->is_vararg;
|
||||
ar->nparams = f->l.p->numparams;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 't': {
|
||||
ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
ar->namewhat = getfuncname(L, ci, &ar->name);
|
||||
if (ar->namewhat == NULL) {
|
||||
ar->namewhat = ""; /* not found */
|
||||
ar->name = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'r': {
|
||||
if (ci == NULL || !(ci->callstatus & CIST_TRAN))
|
||||
ar->ftransfer = ar->ntransfer = 0;
|
||||
else {
|
||||
ar->ftransfer = ci->u2.transferinfo.ftransfer;
|
||||
ar->ntransfer = ci->u2.transferinfo.ntransfer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'L':
|
||||
case 'f': /* handled by lua_getinfo */
|
||||
break;
|
||||
default: status = 0; /* invalid option */
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
||||
int status;
|
||||
Closure *cl;
|
||||
CallInfo *ci;
|
||||
TValue *func;
|
||||
lua_lock(L);
|
||||
if (*what == '>') {
|
||||
ci = NULL;
|
||||
func = s2v(L->top.p - 1);
|
||||
api_check(L, ttisfunction(func), "function expected");
|
||||
what++; /* skip the '>' */
|
||||
L->top.p--; /* pop function */
|
||||
}
|
||||
else {
|
||||
ci = ar->i_ci;
|
||||
func = s2v(ci->func.p);
|
||||
lua_assert(ttisfunction(func));
|
||||
}
|
||||
cl = ttisclosure(func) ? clvalue(func) : NULL;
|
||||
status = auxgetinfo(L, what, ar, cl, ci);
|
||||
if (strchr(what, 'f')) {
|
||||
setobj2s(L, L->top.p, func);
|
||||
api_incr_top(L);
|
||||
}
|
||||
if (strchr(what, 'L'))
|
||||
collectvalidlines(L, cl);
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Symbolic Execution
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
|
||||
static int filterpc (int pc, int jmptarget) {
|
||||
if (pc < jmptarget) /* is code conditional (inside a jump)? */
|
||||
return -1; /* cannot know who sets that register */
|
||||
else return pc; /* current position sets that register */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to find last instruction before 'lastpc' that modified register 'reg'.
|
||||
*/
|
||||
static int findsetreg (const Proto *p, int lastpc, int reg) {
|
||||
int pc;
|
||||
int setreg = -1; /* keep last instruction that changed 'reg' */
|
||||
int jmptarget = 0; /* any code before this address is conditional */
|
||||
if (testMMMode(GET_OPCODE(p->code[lastpc])))
|
||||
lastpc--; /* previous instruction was not actually executed */
|
||||
for (pc = 0; pc < lastpc; pc++) {
|
||||
Instruction i = p->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
int a = GETARG_A(i);
|
||||
int change; /* true if current instruction changed 'reg' */
|
||||
switch (op) {
|
||||
case OP_LOADNIL: { /* set registers from 'a' to 'a+b' */
|
||||
int b = GETARG_B(i);
|
||||
change = (a <= reg && reg <= a + b);
|
||||
break;
|
||||
}
|
||||
case OP_TFORCALL: { /* affect all regs above its base */
|
||||
change = (reg >= a + 2);
|
||||
break;
|
||||
}
|
||||
case OP_CALL:
|
||||
case OP_TAILCALL: { /* affect all registers above base */
|
||||
change = (reg >= a);
|
||||
break;
|
||||
}
|
||||
case OP_JMP: { /* doesn't change registers, but changes 'jmptarget' */
|
||||
int b = GETARG_sJ(i);
|
||||
int dest = pc + 1 + b;
|
||||
/* jump does not skip 'lastpc' and is larger than current one? */
|
||||
if (dest <= lastpc && dest > jmptarget)
|
||||
jmptarget = dest; /* update 'jmptarget' */
|
||||
change = 0;
|
||||
break;
|
||||
}
|
||||
default: /* any instruction that sets A */
|
||||
change = (testAMode(op) && reg == a);
|
||||
break;
|
||||
}
|
||||
if (change)
|
||||
setreg = filterpc(pc, jmptarget);
|
||||
}
|
||||
return setreg;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find a "name" for the constant 'c'.
|
||||
*/
|
||||
static const char *kname (const Proto *p, int index, const char **name) {
|
||||
TValue *kvalue = &p->k[index];
|
||||
if (ttisstring(kvalue)) {
|
||||
*name = getstr(tsvalue(kvalue));
|
||||
return "constant";
|
||||
}
|
||||
else {
|
||||
*name = "?";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char *basicgetobjname (const Proto *p, int *ppc, int reg,
|
||||
const char **name) {
|
||||
int pc = *ppc;
|
||||
*name = luaF_getlocalname(p, reg + 1, pc);
|
||||
if (*name) /* is a local? */
|
||||
return "local";
|
||||
/* else try symbolic execution */
|
||||
*ppc = pc = findsetreg(p, pc, reg);
|
||||
if (pc != -1) { /* could find instruction? */
|
||||
Instruction i = p->code[pc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
switch (op) {
|
||||
case OP_MOVE: {
|
||||
int b = GETARG_B(i); /* move from 'b' to 'a' */
|
||||
if (b < GETARG_A(i))
|
||||
return basicgetobjname(p, ppc, b, name); /* get name for 'b' */
|
||||
break;
|
||||
}
|
||||
case OP_GETUPVAL: {
|
||||
*name = upvalname(p, GETARG_B(i));
|
||||
return "upvalue";
|
||||
}
|
||||
case OP_LOADK: return kname(p, GETARG_Bx(i), name);
|
||||
case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
return NULL; /* could not find reasonable name */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find a "name" for the register 'c'.
|
||||
*/
|
||||
static void rname (const Proto *p, int pc, int c, const char **name) {
|
||||
const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */
|
||||
if (!(what && *what == 'c')) /* did not find a constant name? */
|
||||
*name = "?";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find a "name" for a 'C' value in an RK instruction.
|
||||
*/
|
||||
static void rkname (const Proto *p, int pc, Instruction i, const char **name) {
|
||||
int c = GETARG_C(i); /* key index */
|
||||
if (GETARG_k(i)) /* is 'c' a constant? */
|
||||
kname(p, c, name);
|
||||
else /* 'c' is a register */
|
||||
rname(p, pc, c, name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether table being indexed by instruction 'i' is the
|
||||
** environment '_ENV'
|
||||
*/
|
||||
static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) {
|
||||
int t = GETARG_B(i); /* table index */
|
||||
const char *name; /* name of indexed variable */
|
||||
if (isup) /* is 't' an upvalue? */
|
||||
name = upvalname(p, t);
|
||||
else /* 't' is a register */
|
||||
basicgetobjname(p, &pc, t, &name);
|
||||
return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Extend 'basicgetobjname' to handle table accesses
|
||||
*/
|
||||
static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||
const char **name) {
|
||||
const char *kind = basicgetobjname(p, &lastpc, reg, name);
|
||||
if (kind != NULL)
|
||||
return kind;
|
||||
else if (lastpc != -1) { /* could find instruction? */
|
||||
Instruction i = p->code[lastpc];
|
||||
OpCode op = GET_OPCODE(i);
|
||||
switch (op) {
|
||||
case OP_GETTABUP: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
kname(p, k, name);
|
||||
return isEnv(p, lastpc, i, 1);
|
||||
}
|
||||
case OP_GETTABLE: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
rname(p, lastpc, k, name);
|
||||
return isEnv(p, lastpc, i, 0);
|
||||
}
|
||||
case OP_GETI: {
|
||||
*name = "integer index";
|
||||
return "field";
|
||||
}
|
||||
case OP_GETFIELD: {
|
||||
int k = GETARG_C(i); /* key index */
|
||||
kname(p, k, name);
|
||||
return isEnv(p, lastpc, i, 0);
|
||||
}
|
||||
case OP_SELF: {
|
||||
rkname(p, lastpc, i, name);
|
||||
return "method";
|
||||
}
|
||||
default: break; /* go through to return NULL */
|
||||
}
|
||||
}
|
||||
return NULL; /* could not find reasonable name */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to find a name for a function based on the code that called it.
|
||||
** (Only works when function was called by a Lua function.)
|
||||
** Returns what the name is (e.g., "for iterator", "method",
|
||||
** "metamethod") and sets '*name' to point to the name.
|
||||
*/
|
||||
static const char *funcnamefromcode (lua_State *L, const Proto *p,
|
||||
int pc, const char **name) {
|
||||
TMS tm = (TMS)0; /* (initial value avoids warnings) */
|
||||
Instruction i = p->code[pc]; /* calling instruction */
|
||||
switch (GET_OPCODE(i)) {
|
||||
case OP_CALL:
|
||||
case OP_TAILCALL:
|
||||
return getobjname(p, pc, GETARG_A(i), name); /* get function name */
|
||||
case OP_TFORCALL: { /* for iterator */
|
||||
*name = "for iterator";
|
||||
return "for iterator";
|
||||
}
|
||||
/* other instructions can do calls through metamethods */
|
||||
case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
|
||||
case OP_GETI: case OP_GETFIELD:
|
||||
tm = TM_INDEX;
|
||||
break;
|
||||
case OP_SETTABUP: case OP_SETTABLE: case OP_SETI: case OP_SETFIELD:
|
||||
tm = TM_NEWINDEX;
|
||||
break;
|
||||
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
|
||||
tm = cast(TMS, GETARG_C(i));
|
||||
break;
|
||||
}
|
||||
case OP_UNM: tm = TM_UNM; break;
|
||||
case OP_BNOT: tm = TM_BNOT; break;
|
||||
case OP_LEN: tm = TM_LEN; break;
|
||||
case OP_CONCAT: tm = TM_CONCAT; break;
|
||||
case OP_EQ: tm = TM_EQ; break;
|
||||
/* no cases for OP_EQI and OP_EQK, as they don't call metamethods */
|
||||
case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break;
|
||||
case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break;
|
||||
case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break;
|
||||
default:
|
||||
return NULL; /* cannot find a reasonable name */
|
||||
}
|
||||
*name = getshrstr(G(L)->tmname[tm]) + 2;
|
||||
return "metamethod";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to find a name for a function based on how it was called.
|
||||
*/
|
||||
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
||||
const char **name) {
|
||||
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
|
||||
*name = "?";
|
||||
return "hook";
|
||||
}
|
||||
else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */
|
||||
*name = "__gc";
|
||||
return "metamethod"; /* report it as such */
|
||||
}
|
||||
else if (isLua(ci))
|
||||
return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Check whether pointer 'o' points to some value in the stack frame of
|
||||
** the current function and, if so, returns its index. Because 'o' may
|
||||
** not point to a value in this stack, we cannot compare it with the
|
||||
** region boundaries (undefined behavior in ISO C).
|
||||
*/
|
||||
static int instack (CallInfo *ci, const TValue *o) {
|
||||
int pos;
|
||||
StkId base = ci->func.p + 1;
|
||||
for (pos = 0; base + pos < ci->top.p; pos++) {
|
||||
if (o == s2v(base + pos))
|
||||
return pos;
|
||||
}
|
||||
return -1; /* not found */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Checks whether value 'o' came from an upvalue. (That can only happen
|
||||
** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on
|
||||
** upvalues.)
|
||||
*/
|
||||
static const char *getupvalname (CallInfo *ci, const TValue *o,
|
||||
const char **name) {
|
||||
LClosure *c = ci_func(ci);
|
||||
int i;
|
||||
for (i = 0; i < c->nupvalues; i++) {
|
||||
if (c->upvals[i]->v.p == o) {
|
||||
*name = upvalname(c->p, i);
|
||||
return "upvalue";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char *formatvarinfo (lua_State *L, const char *kind,
|
||||
const char *name) {
|
||||
if (kind == NULL)
|
||||
return ""; /* no information */
|
||||
else
|
||||
return luaO_pushfstring(L, " (%s '%s')", kind, name);
|
||||
}
|
||||
|
||||
/*
|
||||
** Build a string with a "description" for the value 'o', such as
|
||||
** "variable 'x'" or "upvalue 'y'".
|
||||
*/
|
||||
static const char *varinfo (lua_State *L, const TValue *o) {
|
||||
CallInfo *ci = L->ci;
|
||||
const char *name = NULL; /* to avoid warnings */
|
||||
const char *kind = NULL;
|
||||
if (isLua(ci)) {
|
||||
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
||||
if (!kind) { /* not an upvalue? */
|
||||
int reg = instack(ci, o); /* try a register */
|
||||
if (reg >= 0) /* is 'o' a register? */
|
||||
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
|
||||
}
|
||||
}
|
||||
return formatvarinfo(L, kind, name);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Raise a type error
|
||||
*/
|
||||
static l_noret typeerror (lua_State *L, const TValue *o, const char *op,
|
||||
const char *extra) {
|
||||
const char *t = luaT_objtypename(L, o);
|
||||
luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Raise a type error with "standard" information about the faulty
|
||||
** object 'o' (using 'varinfo').
|
||||
*/
|
||||
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
||||
typeerror(L, o, op, varinfo(L, o));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Raise an error for calling a non-callable object. Try to find a name
|
||||
** for the object based on how it was called ('funcnamefromcall'); if it
|
||||
** cannot get a name there, try 'varinfo'.
|
||||
*/
|
||||
l_noret luaG_callerror (lua_State *L, const TValue *o) {
|
||||
CallInfo *ci = L->ci;
|
||||
const char *name = NULL; /* to avoid warnings */
|
||||
const char *kind = funcnamefromcall(L, ci, &name);
|
||||
const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
|
||||
typeerror(L, o, "call", extra);
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) {
|
||||
luaG_runerror(L, "bad 'for' %s (number expected, got %s)",
|
||||
what, luaT_objtypename(L, o));
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
if (ttisstring(p1) || cvt2str(p1)) p1 = p2;
|
||||
luaG_typeerror(L, p1, "concatenate");
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_opinterror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2, const char *msg) {
|
||||
if (!ttisnumber(p1)) /* first operand is wrong? */
|
||||
p2 = p1; /* now second is wrong */
|
||||
luaG_typeerror(L, p2, msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Error when both values are convertible to numbers, but not to integers
|
||||
*/
|
||||
l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
lua_Integer temp;
|
||||
if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I))
|
||||
p2 = p1;
|
||||
luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
|
||||
const char *t1 = luaT_objtypename(L, p1);
|
||||
const char *t2 = luaT_objtypename(L, p2);
|
||||
if (strcmp(t1, t2) == 0)
|
||||
luaG_runerror(L, "attempt to compare two %s values", t1);
|
||||
else
|
||||
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
|
||||
}
|
||||
|
||||
|
||||
/* add src:line information to 'msg' */
|
||||
const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
|
||||
int line) {
|
||||
char buff[LUA_IDSIZE];
|
||||
if (src)
|
||||
luaO_chunkid(buff, getstr(src), tsslen(src));
|
||||
else { /* no source available; use "?" instead */
|
||||
buff[0] = '?'; buff[1] = '\0';
|
||||
}
|
||||
return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_errormsg (lua_State *L) {
|
||||
if (L->errfunc != 0) { /* is there an error handling function? */
|
||||
StkId errfunc = restorestack(L, L->errfunc);
|
||||
lua_assert(ttisfunction(s2v(errfunc)));
|
||||
setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
|
||||
setobjs2s(L, L->top.p - 1, errfunc); /* push function */
|
||||
L->top.p++; /* assume EXTRA_STACK */
|
||||
luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
|
||||
}
|
||||
luaD_throw(L, LUA_ERRRUN);
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
||||
CallInfo *ci = L->ci;
|
||||
const char *msg;
|
||||
va_list argp;
|
||||
luaC_checkGC(L); /* error message uses memory */
|
||||
va_start(argp, fmt);
|
||||
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
|
||||
va_end(argp);
|
||||
if (isLua(ci)) { /* if Lua function, add source:line information */
|
||||
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
|
||||
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
|
||||
L->top.p--;
|
||||
}
|
||||
luaG_errormsg(L);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether new instruction 'newpc' is in a different line from
|
||||
** previous instruction 'oldpc'. More often than not, 'newpc' is only
|
||||
** one or a few instructions after 'oldpc' (it must be after, see
|
||||
** caller), so try to avoid calling 'luaG_getfuncline'. If they are
|
||||
** too far apart, there is a good chance of a ABSLINEINFO in the way,
|
||||
** so it goes directly to 'luaG_getfuncline'.
|
||||
*/
|
||||
static int changedline (const Proto *p, int oldpc, int newpc) {
|
||||
if (p->lineinfo == NULL) /* no debug information? */
|
||||
return 0;
|
||||
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
|
||||
int delta = 0; /* line difference */
|
||||
int pc = oldpc;
|
||||
for (;;) {
|
||||
int lineinfo = p->lineinfo[++pc];
|
||||
if (lineinfo == ABSLINEINFO)
|
||||
break; /* cannot compute delta; fall through */
|
||||
delta += lineinfo;
|
||||
if (pc == newpc)
|
||||
return (delta != 0); /* delta computed successfully */
|
||||
}
|
||||
}
|
||||
/* either instructions are too far apart or there is an absolute line
|
||||
info in the way; compute line difference explicitly */
|
||||
return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traces Lua calls. If code is running the first instruction of a function,
|
||||
** and function is not vararg, and it is not coming from an yield,
|
||||
** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall'
|
||||
** after adjusting its variable arguments; otherwise, they could call
|
||||
** a line/count hook before the call hook. Functions coming from
|
||||
** an yield already called 'luaD_hookcall' before yielding.)
|
||||
*/
|
||||
int luaG_tracecall (lua_State *L) {
|
||||
CallInfo *ci = L->ci;
|
||||
Proto *p = ci_func(ci)->p;
|
||||
ci->u.l.trap = 1; /* ensure hooks will be checked */
|
||||
if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */
|
||||
if (p->is_vararg)
|
||||
return 0; /* hooks will start at VARARGPREP instruction */
|
||||
else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */
|
||||
luaD_hookcall(L, ci); /* check 'call' hook */
|
||||
}
|
||||
return 1; /* keep 'trap' on */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Traces the execution of a Lua function. Called before the execution
|
||||
** of each opcode, when debug is on. 'L->oldpc' stores the last
|
||||
** instruction traced, to detect line changes. When entering a new
|
||||
** function, 'npci' will be zero and will test as a new line whatever
|
||||
** the value of 'oldpc'. Some exceptional conditions may return to
|
||||
** a function without setting 'oldpc'. In that case, 'oldpc' may be
|
||||
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
|
||||
** at most causes an extra call to a line hook.)
|
||||
** This function is not "Protected" when called, so it should correct
|
||||
** 'L->top.p' before calling anything that can run the GC.
|
||||
*/
|
||||
int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
||||
CallInfo *ci = L->ci;
|
||||
lu_byte mask = L->hookmask;
|
||||
const Proto *p = ci_func(ci)->p;
|
||||
int counthook;
|
||||
if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */
|
||||
ci->u.l.trap = 0; /* don't need to stop again */
|
||||
return 0; /* turn off 'trap' */
|
||||
}
|
||||
pc++; /* reference is always next instruction */
|
||||
ci->u.l.savedpc = pc; /* save 'pc' */
|
||||
counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
|
||||
if (counthook)
|
||||
resethookcount(L); /* reset count */
|
||||
else if (!(mask & LUA_MASKLINE))
|
||||
return 1; /* no line hook and count != 0; nothing to be done now */
|
||||
if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
|
||||
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
|
||||
return 1; /* do not call hook again (VM yielded, so it did not move) */
|
||||
}
|
||||
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
|
||||
L->top.p = ci->top.p; /* correct top */
|
||||
if (counthook)
|
||||
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
|
||||
if (mask & LUA_MASKLINE) {
|
||||
/* 'L->oldpc' may be invalid; use zero in this case */
|
||||
int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0;
|
||||
int npci = pcRel(pc, p);
|
||||
if (npci <= oldpc || /* call hook when jump back (loop), */
|
||||
changedline(p, oldpc, npci)) { /* or when enter new line */
|
||||
int newline = luaG_getfuncline(p, npci);
|
||||
luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */
|
||||
}
|
||||
L->oldpc = npci; /* 'pc' of last call to line hook */
|
||||
}
|
||||
if (L->status == LUA_YIELD) { /* did hook yield? */
|
||||
if (counthook)
|
||||
L->hookcount = 1; /* undo decrement to zero */
|
||||
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
|
||||
luaD_throw(L, LUA_YIELD);
|
||||
}
|
||||
return 1; /* keep 'trap' on */
|
||||
}
|
||||
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
** $Id: ldebug.h $
|
||||
** Auxiliary functions from Debug Interface module
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef ldebug_h
|
||||
#define ldebug_h
|
||||
|
||||
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
#define pcRel(pc, p) (cast_int((pc) - (p)->code) - 1)
|
||||
|
||||
|
||||
/* Active Lua function (given call info) */
|
||||
#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
|
||||
|
||||
|
||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||
|
||||
/*
|
||||
** mark for entries in 'lineinfo' array that has absolute information in
|
||||
** 'abslineinfo' array
|
||||
*/
|
||||
#define ABSLINEINFO (-0x80)
|
||||
|
||||
|
||||
/*
|
||||
** MAXimum number of successive Instructions WiTHout ABSolute line
|
||||
** information. (A power of two allows fast divisions.)
|
||||
*/
|
||||
#if !defined(MAXIWTHABS)
|
||||
#define MAXIWTHABS 128
|
||||
#endif
|
||||
|
||||
|
||||
LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc);
|
||||
LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n,
|
||||
StkId *pos);
|
||||
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
|
||||
const char *opname);
|
||||
LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o);
|
||||
LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o,
|
||||
const char *what);
|
||||
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2);
|
||||
LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2,
|
||||
const char *msg);
|
||||
LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2);
|
||||
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
|
||||
const TValue *p2);
|
||||
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
|
||||
LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
|
||||
TString *src, int line);
|
||||
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
|
||||
LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
|
||||
LUAI_FUNC int luaG_tracecall (lua_State *L);
|
||||
|
||||
|
||||
#endif
|
||||
Vendored
+1028
File diff suppressed because it is too large
Load Diff
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
** $Id: ldo.h $
|
||||
** Stack and Call structure of Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef ldo_h
|
||||
#define ldo_h
|
||||
|
||||
|
||||
#include "llimits.h"
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lzio.h"
|
||||
|
||||
|
||||
/*
|
||||
** Macro to check stack size and grow stack if needed. Parameters
|
||||
** 'pre'/'pos' allow the macro to preserve a pointer into the
|
||||
** stack across reallocations, doing the work only when needed.
|
||||
** It also allows the running of one GC step when the stack is
|
||||
** reallocated.
|
||||
** 'condmovestack' is used in heavy tests to force a stack reallocation
|
||||
** at every check.
|
||||
*/
|
||||
#define luaD_checkstackaux(L,n,pre,pos) \
|
||||
if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
|
||||
{ pre; luaD_growstack(L, n, 1); pos; } \
|
||||
else { condmovestack(L,pre,pos); }
|
||||
|
||||
/* In general, 'pre'/'pos' are empty (nothing to save) */
|
||||
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
|
||||
|
||||
|
||||
|
||||
#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
|
||||
#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
|
||||
|
||||
|
||||
/* macro to check stack size, preserving 'p' */
|
||||
#define checkstackp(L,n,p) \
|
||||
luaD_checkstackaux(L, n, \
|
||||
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
|
||||
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
|
||||
|
||||
|
||||
/* macro to check stack size and GC, preserving 'p' */
|
||||
#define checkstackGCp(L,n,p) \
|
||||
luaD_checkstackaux(L, n, \
|
||||
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
|
||||
luaC_checkGC(L), /* stack grow uses memory */ \
|
||||
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
|
||||
|
||||
|
||||
/* macro to check stack size and GC */
|
||||
#define checkstackGC(L,fsize) \
|
||||
luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
|
||||
|
||||
|
||||
/* type of protected functions, to be ran by 'runprotected' */
|
||||
typedef void (*Pfunc) (lua_State *L, void *ud);
|
||||
|
||||
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
|
||||
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
|
||||
const char *mode);
|
||||
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
|
||||
int fTransfer, int nTransfer);
|
||||
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
|
||||
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
|
||||
int narg1, int delta);
|
||||
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
|
||||
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||
ptrdiff_t oldtop, ptrdiff_t ef);
|
||||
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);
|
||||
LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror);
|
||||
LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror);
|
||||
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
|
||||
LUAI_FUNC void luaD_inctop (lua_State *L);
|
||||
|
||||
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
|
||||
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user