Compare commits
328
Commits
v0.7-Alpha
...
16bc66c80e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16bc66c80e | ||
|
|
f8c42a53c6 | ||
|
|
eca538c6af | ||
|
|
ce2be411d7 | ||
|
|
16fc3fa379 | ||
|
|
62b36ec8bb | ||
|
|
b6b246fb38 | ||
|
|
d91d3c6b6f | ||
|
|
3ab2673fd3 | ||
|
|
ca7ff99a79 | ||
|
|
177820cd6e | ||
|
|
d254d3aec4 | ||
|
|
299f1b1ef7 | ||
|
|
9c968967e2 | ||
|
|
04ae75c698 | ||
|
|
6d551e95b9 | ||
|
|
a7cb7b0411 | ||
|
|
46e816d7ce | ||
|
|
28aa2c4dec | ||
|
|
d410590a86 | ||
|
|
e271fa39e4 | ||
|
|
08dcc3152f | ||
|
|
0829603262 | ||
|
|
3133977b0f | ||
|
|
e4088185af | ||
|
|
c55151886f | ||
|
|
6689235691 | ||
|
|
6533a3be29 | ||
|
|
adbcb2a83b | ||
|
|
15847f10b9 | ||
|
|
8952cf5f1b | ||
|
|
2bdd49fd19 | ||
|
|
0f95c916dd | ||
|
|
527fb3b132 | ||
|
|
abffa74ad8 | ||
|
|
772d0de5c1 | ||
|
|
cb50f93af5 | ||
|
|
e4f564b165 | ||
|
|
0b78b74fbc | ||
|
|
5d8883ec45 | ||
|
|
c90c210e04 | ||
|
|
980d1d7134 | ||
|
|
b027778328 | ||
|
|
a6143e12b4 | ||
|
|
868b93cdd0 | ||
|
|
0b03b3cd92 | ||
|
|
572e957c17 | ||
|
|
63bc3bebed | ||
|
|
70872c29d1 | ||
|
|
e9752cb906 | ||
|
|
7946954017 | ||
|
|
4fe1a4da65 | ||
|
|
956ab73130 | ||
|
|
f93250da07 | ||
|
|
1b4f9a2e77 | ||
|
|
c8cf55403b | ||
|
|
76257123da | ||
|
|
3c249d2fae | ||
|
|
683f13deab | ||
|
|
a7da5f2060 | ||
|
|
db88979b75 | ||
|
|
e04f72ddca | ||
|
|
e8bb381520 | ||
|
|
a33b3644d9 | ||
|
|
96ffca3094 | ||
|
|
967a044637 | ||
|
|
b5cf633e98 | ||
|
|
16d0e0834f | ||
|
|
76ac3a0f93 | ||
|
|
78bcc21130 | ||
|
|
a125653448 | ||
|
|
aa2170ba80 | ||
|
|
5705196710 | ||
|
|
cf0d787196 | ||
|
|
8d436fe546 | ||
|
|
e15ac22132 | ||
|
|
bac57a5872 | ||
|
|
012fcb6bd5 | ||
|
|
6ffdca8595 | ||
|
|
e3172057d3 | ||
|
|
8d48da0b9e | ||
|
|
30dea2e9fd | ||
|
|
633879d35f | ||
|
|
831b52129d | ||
|
|
55427822a0 | ||
|
|
71b7320e1c | ||
|
|
2a025cb073 | ||
|
|
0e782cdf99 | ||
|
|
a390e7f895 | ||
|
|
65427bd0f1 | ||
|
|
cb898595b0 | ||
|
|
9b86d84dd6 | ||
|
|
4dfb9031d7 | ||
|
|
401f85f673 | ||
|
|
caec5d8dfc | ||
|
|
44d0a9cf9d | ||
|
|
c0aa4fee95 | ||
|
|
913d9bf26b | ||
|
|
c8d6c27f07 | ||
|
|
aecc2c59dd | ||
|
|
0e32838da1 | ||
|
|
ef78772278 | ||
|
|
8891657eb1 | ||
|
|
a18b5b97aa | ||
|
|
0ea88a263d | ||
|
|
eea4ebf5c4 | ||
|
|
7351ba6175 | ||
|
|
8e3e66b3c1 | ||
|
|
2c51a2f9c8 | ||
|
|
e3b3882443 | ||
|
|
0046c4a223 | ||
|
|
5aaef0f1a2 | ||
|
|
abdad1a436 | ||
|
|
a4143b537d | ||
|
|
0ccffe3f80 | ||
|
|
cd7548c3d4 | ||
|
|
79a1951861 | ||
|
|
e786d7c3b6 | ||
|
|
e6f30c7e1d | ||
|
|
6147912783 | ||
|
|
ed9f719a07 | ||
|
|
500f216da2 | ||
|
|
12e31276eb | ||
|
|
65c3fabc52 | ||
|
|
c016e245eb | ||
|
|
99dbc499fa | ||
|
|
1c133bfc8d | ||
|
|
451b71884c | ||
|
|
4d638a7255 | ||
|
|
ceea184d5a | ||
|
|
92e0d3ab8b | ||
|
|
9b059dca47 | ||
|
|
46562d54e7 | ||
|
|
ec07c70dcf | ||
|
|
63dd77237a | ||
|
|
cf3908c6f0 | ||
|
|
266163557f | ||
|
|
8bb2bc7b1b | ||
|
|
a3407c14d5 | ||
|
|
47b9c37e94 | ||
|
|
1c3134218e | ||
|
|
a3e7ec4c72 | ||
|
|
cae1555b11 | ||
|
|
f7709bb64e | ||
|
|
3a55af9ce4 | ||
|
|
6081834687 | ||
|
|
a3548a5bd3 | ||
|
|
d686831a7c | ||
|
|
ba1dd1894a | ||
|
|
e00b2f8afb | ||
|
|
72d088c566 | ||
|
|
c6fba23173 | ||
|
|
d45908fb32 | ||
|
|
a7c9dad9fd | ||
|
|
63ebd0d094 | ||
|
|
f28ae57f16 | ||
|
|
2fe708e4be | ||
|
|
69a9abcd59 | ||
|
|
defe42c15c | ||
|
|
05e65aa464 | ||
|
|
8f47f3b30f | ||
|
|
0bad61fda6 | ||
|
|
ea18792373 | ||
|
|
16b8a3a164 | ||
|
|
5b0079fb0c | ||
|
|
9321a04ebc | ||
|
|
9b68791e38 | ||
|
|
2dcc968c39 | ||
|
|
c38b077c37 | ||
|
|
f9b5029e64 | ||
|
|
2b24511f7d | ||
|
|
5cd69e1742 | ||
|
|
007bfa0cb0 | ||
|
|
37c33ffb3e | ||
|
|
937235b776 | ||
|
|
f9c21ebc04 | ||
|
|
fec709cc76 | ||
|
|
80cb3f4eca | ||
|
|
9e88cb8724 | ||
|
|
f61c1c560d | ||
|
|
8ef982003a | ||
|
|
31691b1466 | ||
|
|
ed0c0422ad | ||
|
|
e5acac1d18 | ||
|
|
c7b072266f | ||
|
|
a96d03eaed | ||
|
|
0b4ccac8f9 | ||
|
|
31a3609b28 | ||
|
|
fbdb870986 | ||
|
|
6d04165b96 | ||
|
|
cc245cc263 | ||
|
|
06deb1e836 | ||
|
|
5527a27f7b | ||
|
|
a67fdef20a | ||
|
|
056a5863b8 | ||
|
|
79eb5f1f76 | ||
|
|
c6cb583518 | ||
|
|
34eec66f35 | ||
|
|
4137ebfbd8 | ||
|
|
5958dd2055 | ||
|
|
163ad0a511 | ||
|
|
e3c2a577ba | ||
|
|
81a0376c99 | ||
|
|
1417a68757 | ||
|
|
1e4d5ce630 | ||
|
|
0f2763a115 | ||
|
|
420f452d35 | ||
|
|
908c385de5 | ||
|
|
c1878265c8 | ||
|
|
23742868c4 | ||
|
|
2e5e31ed3b | ||
|
|
00df336610 | ||
|
|
d89c9a6072 | ||
|
|
6aa99ac1d5 | ||
|
|
3989f5fa83 | ||
|
|
f90c0a59b6 | ||
|
|
33f992ef56 | ||
|
|
0542204b35 | ||
|
|
e5616c5879 | ||
|
|
40a256f6c3 | ||
|
|
b8e1aa6eb7 | ||
|
|
e1592ba410 | ||
|
|
4a2a93d41b | ||
|
|
36260f6edb | ||
|
|
83d691c65c | ||
|
|
626ab703a7 | ||
|
|
6b10cd2b3e | ||
|
|
91a3250d4c | ||
|
|
a667eb4afe | ||
|
|
f67f9547df | ||
|
|
772db608be | ||
|
|
be023325a9 | ||
|
|
a0ee683f82 | ||
|
|
6ad0ae97bc | ||
|
|
3319bfcaa9 | ||
|
|
9d27c7d37e | ||
|
|
5c73fbee83 | ||
|
|
36ebbfe29b | ||
|
|
053daaf877 | ||
|
|
040ec00606 | ||
|
|
919166efa1 | ||
|
|
9bd6dac783 | ||
|
|
212d907d73 | ||
|
|
c1ab233686 | ||
|
|
b42b224c0d | ||
|
|
041671762b | ||
|
|
d0f3b6187e | ||
|
|
b22f589203 | ||
|
|
4af85f8612 | ||
|
|
e9c151f85d | ||
|
|
a900e86b65 | ||
|
|
d5a4b77033 | ||
|
|
eaba60f80b | ||
|
|
912cc6b538 | ||
|
|
3dd5482a46 | ||
|
|
632fa10027 | ||
|
|
6498b13658 | ||
|
|
7f562cd77f | ||
|
|
3a0e971ebf | ||
|
|
4997cb5878 | ||
|
|
729c891cbd | ||
|
|
754bcfb31e | ||
|
|
a8708abf8b | ||
|
|
4b48b96a79 | ||
|
|
9495fc2985 | ||
|
|
378de73a7d | ||
|
|
35ac0c1048 | ||
|
|
2c893d5e35 | ||
|
|
6ea40094ee | ||
|
|
0a8d3bfc6a | ||
|
|
212b4e6d16 | ||
|
|
d606c790ca | ||
|
|
2bfbef1d0c | ||
|
|
f1fb75cc1c | ||
|
|
2200bcde9a | ||
|
|
3e249d9bc5 | ||
|
|
3868e1e811 | ||
|
|
543427dfe5 | ||
|
|
f2d4ec96f0 | ||
|
|
1076818250 | ||
|
|
c4c308c8ba | ||
|
|
a4d9a63d71 | ||
|
|
0197afd543 | ||
|
|
7249a7317d | ||
|
|
abf51e4aa9 | ||
|
|
9b6dc3cbd8 | ||
|
|
9edcbad907 | ||
|
|
a6766cf0b1 | ||
|
|
8635b0fd1b | ||
|
|
30eec99628 | ||
|
|
f9117a2353 | ||
|
|
c81f4b34ee | ||
|
|
c97762ac16 | ||
|
|
5e79e8ba65 | ||
|
|
49a2cd7b2c | ||
|
|
a6c6574390 | ||
|
|
c4846dad26 | ||
|
|
a61a28b778 | ||
|
|
d0c995893d | ||
|
|
a42e241afb | ||
|
|
6d85dd8fe8 | ||
|
|
db6e8b33eb | ||
|
|
7be3617083 | ||
|
|
5c47777972 | ||
|
|
4a2ed6de4e | ||
|
|
9f64760b7a | ||
|
|
68f34e6fab | ||
|
|
1f9bbddbb7 | ||
|
|
050b00f28a | ||
|
|
1241f44fd4 | ||
|
|
7d1c499e7b | ||
|
|
b3f0c2734f | ||
|
|
eaeb8acee4 | ||
|
|
12bf878cb3 | ||
|
|
52ae431ad6 | ||
|
|
05fa62eced | ||
|
|
2f7836b191 | ||
|
|
f574a9ba9a | ||
|
|
a6bf60a51e | ||
|
|
37d9782cf2 | ||
|
|
11679ba8b4 | ||
|
|
8985f0a4d9 | ||
|
|
32a910515e | ||
|
|
aa928ff446 | ||
|
|
5aff89262b | ||
|
|
b5fa864318 | ||
|
|
bb35444be9 | ||
|
|
67d02c1f62 |
No files matched your search
+29
-16
@@ -1,6 +1,7 @@
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
build/*
|
||||
**/build/*
|
||||
.vs
|
||||
|
||||
**/*.gen.*
|
||||
@@ -16,18 +17,30 @@ build/*
|
||||
gencpp.hpp
|
||||
gencpp.cpp
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
**/*.lib
|
||||
**/*.pdb
|
||||
**/*.exe
|
||||
**/*.dll
|
||||
|
||||
release/**
|
||||
|
||||
# Unreal
|
||||
**/Unreal/*.h
|
||||
**/Unreal/*.cpp
|
||||
! **/Unreal/validate.unreal.cpp
|
||||
project/auxiliary/vis_ast/dependencies/temp
|
||||
test/gen/original
|
||||
singleheader/gen/scratch.hpp
|
||||
test/gen/scratch.cpp
|
||||
gen_c_library/gen
|
||||
|
||||
**/*.sln
|
||||
**/*.sln.DotSettings.user
|
||||
**/*.10x
|
||||
**/*.vcxproj
|
||||
**/*.vcxproj.filters
|
||||
**/*.vcxproj.user
|
||||
test/c_library/gen
|
||||
test/cpp_library/gen
|
||||
|
||||
!scripts/helpers/refactor.exe
|
||||
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE",
|
||||
"GEN_TIME"
|
||||
],
|
||||
"windowsSdkVersion": "10.0.19041.0",
|
||||
"compilerPath": "C:/Users/Ed/scoop/apps/llvm/current/bin/clang++.exe",
|
||||
"intelliSenseMode": "windows-clang-x64",
|
||||
"compileCommands": "${workspaceFolder}/project/build/compile_commands.json"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
-45
@@ -1,45 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug gentime lldb",
|
||||
"program": "${workspaceFolder}/test/gen/build/gencpp.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/test/gen/",
|
||||
"postRunCommands": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"name": "Debug gentime vsdbg",
|
||||
"program": "${workspaceFolder}/test/gen/build/gencpp.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/test/gen/",
|
||||
"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis"
|
||||
},
|
||||
{
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"name": "Debug bootstrap vsdbg",
|
||||
"program": "${workspaceFolder}/project/build/gencpp_bootstrap.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/project/",
|
||||
"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis"
|
||||
},
|
||||
{
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"name": "Debug singleheader vsdbg",
|
||||
"program": "${workspaceFolder}/singleheader/build/gencpp_singleheader.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/singleheader/",
|
||||
"visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
-34
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.rmd": "markdown",
|
||||
"array": "cpp",
|
||||
"compare": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xutility": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"table.h": "c",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"exception": "cpp",
|
||||
"optional": "cpp",
|
||||
"tuple": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"limits": "cpp",
|
||||
"concepts": "cpp",
|
||||
"*.rh": "cpp"
|
||||
},
|
||||
"C_Cpp.intelliSenseEngineFallback": "disabled",
|
||||
"mesonbuild.configureOnOpen": true,
|
||||
"C_Cpp.errorSquiggles": "disabled", // This doesn't work well with how the headers are included.
|
||||
"godot_tools.scene_file_config": "",
|
||||
"C_Cpp.default.compilerPath": "cl.exe",
|
||||
"C_Cpp.exclusionPolicy": "checkFilesAndFolders",
|
||||
"C_Cpp.files.exclude": {
|
||||
"**/.vscode": true,
|
||||
"**/.vs": true,
|
||||
"**/sanity.gen.hpp": true
|
||||
}
|
||||
}
|
||||
@@ -26,3 +26,19 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Source URL: https://github.com/Ed94/gencpp
|
||||
|
||||
Acknowledgements
|
||||
|
||||
* The dependencies for gencpp source are derived from the zpl library: https://github.com/zpl-c/zpl
|
||||
|
||||
Special thanks to:
|
||||
|
||||
* The Handmade Community.
|
||||
|
||||
* Casey Muratori, Ginger Bill (Bill Hall), Mr. 4th (Allen Webster), Ryan Fluery: Influnced conceptually how to handle staged metaprograming.
|
||||
|
||||
* Jonathan Blow: Jai's metaprogramming influenced the design of this library.
|
||||
|
||||
* My friends for putting up with discord spam on this library.
|
||||
@@ -1,30 +1,46 @@
|
||||
# gencpp
|
||||
|
||||
An attempt at simple staged metaprogramming for c/c++.
|
||||
An attempt at simple staged metaprogramming for C/C++. Reflect and generate code for your codebase at runtime!
|
||||
|
||||
The library API is a composition of code element constructors.
|
||||
These build up a code AST to then serialize with a file builder.
|
||||

|
||||

|
||||
|
||||
This code base attempts follow the [handmade philosophy](https://handmade.network/manifesto),
|
||||
its not meant to be a black box metaprogramming utility, it should be easy to intergrate into a user's their project domain.
|
||||
The library API is a composition of code element constructors, and a non-standards-compliant single-pass C/C++ parser.
|
||||
These build up a code AST to then serialize with a file builder, or can be traversed for staged-reflection of C/C++ code.
|
||||
|
||||
This code base attempts follow the [handmade philosophy](https://handmade.network/manifesto).
|
||||
Its not meant to be a black box metaprogramming utility, it should be easy to integrate into a user's project domain.
|
||||
|
||||
## Documentation
|
||||
|
||||
* [docs - General](./docs/Readme.md): Overview and additional docs
|
||||
* [AST_Design](./docs/AST_Design.md): Overview of ASTs
|
||||
* [AST Types](./docs/AST_Types.md): Listing of all AST types along with their Code type interface.
|
||||
* [Parsing](./docs/Parsing.md): Overview of the parsing interface.
|
||||
* [Parser Algo](./docs/Parser_Algo.md): In-depth breakdown of the parser's implementation.
|
||||
* [base](./base/Readme.md): Essential (base) library.
|
||||
* [gen_c_library](./gen_c_library/): C11 library variant generation (single header and segmented).
|
||||
* [gen_segmented](./gen_segmented/): Segmented C++ (`gen.<hpp/cpp>`, `gen.dep.<hpp/cpp>`) generation
|
||||
* [gen_singleheader](./gen_singleheader/): Singlehader C++ generation `gen.hpp`
|
||||
* [gen_unreal_engine](./gen_unreal_engine/): Unreal Engine thirdparty code generation.
|
||||
|
||||
## Notes
|
||||
|
||||
The project has reached an *alpha* state, all the current functionality works for the test cases but it will most likely break in many other cases.
|
||||
This project is still in development (very much an alpha state), so expect bugs and missing features.
|
||||
See [issues](https://github.com/Ed94/gencpp/issues) for a list of known bugs or todos.
|
||||
|
||||
A `natvis` and `natstepfilter` are provided in the scripts directory.
|
||||
The library can already be used to generate code just fine, but the parser is where the most work is needed. If your C++ isn't "down to earth" expect issues.
|
||||
|
||||
***The editor and scanner have not been implemented yet. The scanner will come first, then the editor.***
|
||||
|
||||
A C variant is hosted [here](https://github.com/Ed94/genc); I will complete it when this library is feature complete, it should be easier to make than this...
|
||||
A `natvis` and `natstepfilter` are provided in the scripts directory (its outdated, I'll update this readme when its not).
|
||||
*Minor update: I've been using [RAD Debugger](https://github.com/EpicGamesExt/raddebugger) with this and the code structures should be easy to debug even without natvis.*
|
||||
|
||||
## Usage
|
||||
|
||||
A metaprogram is built to generate files before the main program is built. We'll term runtime for this program as `GEN_TIME`. The metaprogram's core implementation are within `gen.hpp` and `gen.cpp` in the project directory.
|
||||
|
||||
`gen.cpp` \`s `main()` is defined as `gen_main()` which the user will have to define once for their program. There they will dictate everything that should be generated.
|
||||
`gen.cpp` \`s `main()` is defined as `gen_main()` which the user will have to define once for their program. There they may reflect and/or generate code.
|
||||
|
||||
In order to keep the locality of this code within the same files the following pattern may be used (although this pattern isn't required at all):
|
||||
In order to keep the locality of this code within the same files the following pattern may be used (although this pattern isn't the best to use):
|
||||
|
||||
Within `program.cpp` :
|
||||
|
||||
@@ -36,7 +52,11 @@ Within `program.cpp` :
|
||||
|
||||
u32 gen_main()
|
||||
{
|
||||
gen::Context ctx;
|
||||
gen::init(& ctx);
|
||||
...
|
||||
gen::deinit(& ctx);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -47,7 +67,6 @@ u32 gen_main()
|
||||
|
||||
// Regular runtime dependent on the generated code here.
|
||||
#endif
|
||||
|
||||
```
|
||||
|
||||
The design uses a constructive builder API for the code to generate.
|
||||
@@ -60,18 +79,18 @@ Example using each construction interface:
|
||||
Validation and construction through a functional interface.
|
||||
|
||||
```cpp
|
||||
Code t_uw = def_type( name(uw) );
|
||||
Code t_allocator = def_type( name(allocator) );
|
||||
Code t_string_const = def_type( name(char), def_specifiers( args( ESpecifier::Const, ESpecifier::Ptr ) ));
|
||||
CodeTypename t_uw = def_type( name(usize) );
|
||||
CodeTypename t_allocator = def_type( name(allocator) );
|
||||
CodeTypename t_string_const = def_type( name(char), def_specifiers( args( ESpecifier::Const, ESpecifier::Ptr ) ));
|
||||
|
||||
Code header;
|
||||
CodeStruct header;
|
||||
{
|
||||
Code num = def_variable( t_uw, name(Num) );
|
||||
Code cap = def_variable( t_uw, name(Capacity) );
|
||||
Code mem_alloc = def_variable( t_allocator, name(Allocator) );
|
||||
Code body = def_struct_body( args( num, cap, mem_alloc ) );
|
||||
CodeVar num = def_variable( t_uw, name(Num) );
|
||||
CodeVar cap = def_variable( t_uw, name(Capacity) );
|
||||
CodeVar mem_alloc = def_variable( t_allocator, name(Allocator) );
|
||||
CodeBody body = def_struct_body( args( num, cap, mem_alloc ) );
|
||||
|
||||
header = def_struct( name(ArrayHeader), __, __, body );
|
||||
header = def_struct( name(ArrayHeader), { body });
|
||||
}
|
||||
```
|
||||
|
||||
@@ -80,11 +99,11 @@ Code header;
|
||||
Validation through ast construction.
|
||||
|
||||
```cpp
|
||||
Code header = parse_struct( code(
|
||||
CodeStruct header = parse_struct( code(
|
||||
struct ArrayHeader
|
||||
{
|
||||
uw Num;
|
||||
uw Capacity;
|
||||
usize Num;
|
||||
usize Capacity;
|
||||
allocator Allocator;
|
||||
};
|
||||
));
|
||||
@@ -99,8 +118,8 @@ No validation, just glorified text injection.
|
||||
Code header = code_str(
|
||||
struct ArrayHeader
|
||||
{
|
||||
uw Num;
|
||||
uw Capacity;
|
||||
usize Num;
|
||||
usize Capacity;
|
||||
allocator Allocator;
|
||||
};
|
||||
);
|
||||
@@ -109,22 +128,32 @@ Code header = code_str(
|
||||
`name` is a helper macro for providing a string literal with its size, intended for the name parameter of functions.
|
||||
`code` is a helper macro for providing a string literal with its size, but intended for code string parameters.
|
||||
`args` is a helper macro for providing the number of arguments to varadic constructors.
|
||||
`code_str` is a helper macro for writting `untyped_str( code( <content> ))`
|
||||
`code_str` is a helper macro for writing `untyped_str( code( <content> ))`
|
||||
|
||||
All three constrcuton interfaces will generate the following C code:
|
||||
All three construction interfaces will generate the following C code:
|
||||
|
||||
```cpp
|
||||
struct ArrayHeader
|
||||
{
|
||||
uw Num;
|
||||
uw Capacity;
|
||||
usize Num;
|
||||
usize Capacity;
|
||||
allocator Allocator;
|
||||
};
|
||||
```
|
||||
|
||||
**Note: The formatting shown here is not how it will look. For your desired formatting its recommended to run a pass through the files with an auto-formatter.**
|
||||
*(The library currently uses clang-format for formatting, beaware its pretty slow...)*
|
||||
*(The library currently uses clang-format for formatting, beware its pretty slow...)*
|
||||
|
||||
## Building
|
||||
|
||||
See the [scripts directory](scripts/).
|
||||
|
||||
## Gallery
|
||||
|
||||
### Listing definitions in the Cuik Compiler
|
||||
|
||||
https://github.com/user-attachments/assets/2302240c-01f1-4e1b-a4b5-292eb3186648
|
||||
|
||||
### Unreal: Generating a UAttributeSet from a UDataTable
|
||||
|
||||
https://github.com/user-attachments/assets/2a07b743-825d-4f9f-beaf-3559e8748a4d
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
## Navigation
|
||||
|
||||
# base
|
||||
|
||||
[Top](../Readme.md)
|
||||
|
||||
* [docs](../docs/Readme.md)
|
||||
|
||||
The library is fragmented into a series of headers and source files meant to be scanned in and then generated to a standard target format, or a user's desires.
|
||||
|
||||
If using the library's provided build scripts:
|
||||
|
||||
```ps1
|
||||
.\build.ps1 <compiler> <debug or omit> base
|
||||
```
|
||||
|
||||
## Content Overview
|
||||
|
||||
* **base**: Files are in granular pieces separated into four directories:
|
||||
* **dependencies**: Originally from the c-zpl library and modified thereafter.
|
||||
* **components**: The essential definitions of the library.
|
||||
* **helpers**: Contains helper functionality used by base and the variant library generators.
|
||||
* `base_codegen.hpp`: Helps with self-hosted code generation of enums, and operator overload inlines of the code types.
|
||||
* `<push/pop>.<name>.inline.<hpp>`: macros that are meant to be injected at specific locations of the library file/s.
|
||||
* `misc.hpp`: Misc functionality used by the library generation metaprograms.
|
||||
* `undef.macros.h`: Undefines all macros from library.
|
||||
* **auxiliary**: Non-essential tooling:
|
||||
* `Builder`: Similar conceptually to Jai programming language's *builder*, just opens a file and prepares a string buffer to serialize code into (`builder_print`, `builder_print_fmt`). Then write & close the file when completed (`builder_write`).
|
||||
* **`Scanner`**: Interface to load up `Code` from files two basic functions are currently provided.
|
||||
* `scan_file`: Used mainly by the library format generators to directly scan files into untyped `Code` (raw string content, pre-formatted no AST parsed).
|
||||
* `parse_file`: Used to read file and then parsed to populate a `CodeBody` AST.
|
||||
* CSV parsing via one or two columns simplified.
|
||||
* **gen_segemetned**: Dependencies go into gen.dep.{hpp/cpp} and components into gen.{hpp/cpp}
|
||||
* **gen_singleheader**: Everything into a single file: gen.hpp
|
||||
* **gen_unreal_engine**: Like gen_segmented but the library is modified slightly to compile as a thirdparty library within an Unreal Engine plugin or module.
|
||||
* **gen_c_library**: The library is heavily modifed into C11 compliant code. A segmented and single-header set of variants are generated.
|
||||
|
||||
Code not making up the core library is located in `auxiliary/<auxiliary_name>.<hpp/cpp>`. These are optional extensions or tools for the library.
|
||||
|
||||
## Dependencies
|
||||
|
||||
The project has no external dependencies beyond:
|
||||
|
||||
* `errno.h`
|
||||
* `stat.h`
|
||||
* `stdarg.h`
|
||||
* `stddef.h`
|
||||
* `stdio.h`
|
||||
* `copyfile.h` (Mac)
|
||||
* `types.h` (Linux)
|
||||
* `sys/man.h` (Linux)
|
||||
* `fcntl.h` (POSXIX Filesystem)
|
||||
* `unistd.h` (Linux/Mac)
|
||||
* `intrin.h` (Windows)
|
||||
* `io.h` (Windows with gcc)
|
||||
* `windows.h` (Windows)
|
||||
|
||||
Dependencies for the project are wrapped within `GENCPP_ROLL_OWN_DEPENDENCIES` (Defining it will disable them).
|
||||
The majority of the dependency's implementation was derived from the [c-zpl library](https://github.com/zpl-c/zpl).
|
||||
|
||||
See the following files for any updates:
|
||||
|
||||
* [`platform.hpp`](./dependencies/platform.hpp)
|
||||
* [`src_start.cpp`](./dependencies/src_start.cpp)
|
||||
* [`filesystem.cpp`](./dependencies/filesystem.cpp)
|
||||
* [`memory.cpp`](./dependencies/memory.cpp)
|
||||
|
||||
## Conventions
|
||||
|
||||
This library was written in a subset of C++ where the following are not used at all:
|
||||
|
||||
* RAII (Constructors/Destructors), lifetimes are managed using named static or regular functions.
|
||||
* Language provide dynamic dispatch, RTTI
|
||||
* Object-Oriented Inheritance
|
||||
* Exceptions
|
||||
|
||||
Polymorphic & Member-functions are used as an ergonomic choice, along with a conserative use of operator overloads.
|
||||
The base library itself does not use anything but C-like features to allow for generating a derviative compatiable with C.
|
||||
|
||||
Member function support or free-functions with reference object passing are wrapped in `! GEN_C_LIKE CPP` preprocess conditionals.
|
||||
|
||||
## C++ template usage
|
||||
|
||||
There are only 4 template definitions in the entire library (C++ versions). (`Array<Type>`, `Hashtable<Type>`, `swap<Type>`, and `tmpl_cast<CodeT>(CodeT code)`)
|
||||
|
||||
Two generic templated containers are used throughout the library:
|
||||
|
||||
* `template< class Type> struct Array`
|
||||
* `template< class Type> struct HashTable`
|
||||
|
||||
`tmpl_cast<CodeT>(CodeT code)` is just an alternative way to explicitly cast to code. Its usage is wrapped in a macro called `cast` for the base library (needed for interoperability with C).
|
||||
|
||||
`template< class Type> swap( Type& a, Type& b)` is used over a macro.
|
||||
|
||||
Otherwise the library is free of any templates.
|
||||
|
||||
## Macro usage
|
||||
|
||||
Since this is a meta-programming library, it was desired to keep both templates and macros (especially macros) usage very limited.
|
||||
|
||||
Most macros are defined within [macros.hpp](./dependencies/macros.hpp).
|
||||
|
||||
The most advanced macro usage is `num_args` which is a helper for counting the number of arguments of another macro.
|
||||
|
||||
Any large macros used implementing the gen interface or parser are going to be phased out in favor of just forcinlined functions.
|
||||
*(Unless there is a hot-path that requires them)*
|
||||
|
||||
The vast majority of macros should be single-line subsitutions that either add:
|
||||
|
||||
* Improvements to searching
|
||||
* Intentionality of keyword usage
|
||||
* A feature that only the preprocessor has (ex: function name reflection or stringifying)
|
||||
* Compatibility of statements or expressions bewteen C & C++ that cannot be parsed by gencpp itself.
|
||||
* Masking highly verbose syntax (the latter is getting phased out).
|
||||
|
||||
[gen_c_library](../gen_c_library/) has the most advanced set of macros for c11's generic selection.
|
||||
|
||||
* A significant amount of explicit code geneeration is utilized to keep abuse of the preprocessor to the absolute minimum.
|
||||
* There is a heavy set of documentation inlined wth them; their naming is also highly verbose and explicit.
|
||||
* See its documentation for more information.
|
||||
|
||||
## On base code generation
|
||||
|
||||
There are ***five*** header files which are automatically generated using [base_codegen.hpp](./helpers/base_codegen.hpp) by [base.cpp](./base.cpp). They are all located in [components/gen](./components/gen/).
|
||||
|
||||
* [ecodetypes.hpp](./components/gen/ecode.hpp): `CodeType` enum definition and related implementation. Generation is based off of [ECodeType.csv](./enums/ECodeTypes.csv).
|
||||
* [especifier.hpp](./components/gen/especifier.hpp): `Specifier` enum definition, etc. Generated using [ESpecifier.csv](./enums/ESpecifier.csv).
|
||||
* [eoperator.hpp](./components/gen/eoperator.hpp): `Operator` enum definition, etc. Generated using [EOperator.hpp](./enums/EOperator.csv).
|
||||
* [etoktype.cpp](./components/gen/etoktype.cpp): `TokType` enum defininition, etc. Used by the lexer and parser backend. Uses two csvs:
|
||||
* [ETokType.csv](./enums/ETokType.csv): Provides the enum entries and their strinng ids.
|
||||
* [AttributeTokens.csv](./enums/AttributeTokens.csv): Provides tokens entries that should be considered as attributes by the lexer and parser. Sspecfiically macro attributes such as those use for exporting symbols.
|
||||
* [ast_inlines.hpp](./components/gen/ast_inlines.hpp): Member trivial `operator` definitions for C++ code types. Does not use a csv.
|
||||
|
||||
[misc.hpp](./helpers/misc.hpp): Has shared functions used by the library generation meta-programs throughout this codebase.
|
||||
|
||||
If using the library's provided build scripts:
|
||||
|
||||
```ps1
|
||||
.\build.ps1 <compiler> <debug or omit> base
|
||||
```
|
||||
|
||||
Will refresh those files.
|
||||
|
||||
## On multi-threading
|
||||
|
||||
Currently unsupported. I want the library to be *stable* and *correct*, with the addition of exhausting all basic single-threaded optimizations before I consider multi-threading.
|
||||
|
||||
## Extending the library
|
||||
|
||||
This library is relatively very small (for parsing C++), and can be extended without much hassle.
|
||||
|
||||
The convention you'll see used throughout the upfront interface of the library is as follows:
|
||||
|
||||
1. Check name or parameters to make sure they are valid for the construction requested
|
||||
2. Create a code object using `make_code`.
|
||||
3. Populate immediate fields (Name, Type, ModuleFlags, etc)
|
||||
4. Populate sub-entires using `add_entry`. If using the default serialization function `to_strbuilder`, follow the order at which entires are expected to appear (there is a strong ordering expected).
|
||||
|
||||
Names or Content fields are interned strings and thus showed be cached using `cache_str` if its desired to preserve that behavior.
|
||||
|
||||
`def_operator` is the most sophisticated upfront constructor as it has multiple permutations of definitions that could be created that are not trivial to determine if valid.
|
||||
|
||||
The parser is documented under [`docs/Parsing.md`](../docs/Parsing.md) and [`docs/Parser_Algo.md`](../docs/Parser_Algo.md). Read that and the entire library if you want to extend it.
|
||||
|
||||
### Attributes
|
||||
|
||||
To add additional macro attributes, all that has to be done is modifying [`AttributeTokens.csv`](./enums/AttributeTokens.csv).
|
||||
|
||||
### Specifiers
|
||||
|
||||
To add additional macro specifiers, the following needs to be done:
|
||||
|
||||
1. Adjust [especifier.hpp](./components/gen/especifier.hpp)
|
||||
2. Adjust [etoktype.cpp](./components/gen/etoktype.cpp)
|
||||
3. Adjust [parser_case_macros.cpp](./components/parser_case_macros.cpp)
|
||||
|
||||
If the specifier is a new trailing specifier on function definitions:
|
||||
|
||||
Head into [base_codegen.hpp](./helpers/base_codegen.hpp): `gen_especifier`. There will be an `is_trailing` function that needs to be adjusted with an additional case for the user's new trailing specifier.
|
||||
|
||||
### Code Types
|
||||
|
||||
These require the following to be handled to the equivalent extent as the other types:
|
||||
|
||||
1. Adjust [ECodeTypes.csv](./enums/ECodeTypes.csv) with the new types
|
||||
2. Define a new `AST_<Name>` and `Code<Name>`. See
|
||||
* [ast.hpp](./components/ast.hpp): Initial forwards and user defined conversion for Code.
|
||||
* [ast_types.hpp](./components/ast_types.hpp): Define the `AST_<Name>` struct.
|
||||
* [code_types.hpp](./components/code_types.hpp): Defne the `CodeType` struct. If its needs an iterator see: `struct CodeBody` & `struct CodeParams`.
|
||||
3. [ast_case_macros.cpp](./components/ast_case_macros.cpp): Review cases here if the new code type needs to be considered.
|
||||
4. [ast.cpp](./components/ast.cpp): Need to review
|
||||
* `code_debug_str`
|
||||
* `code_is_equal`
|
||||
* `code_to_strbuilder_ptr`
|
||||
* `code_validate_body`
|
||||
5. [code_serialization.cpp](./components/code_serialization.cpp): Define serialization here.
|
||||
6. [inlines.hpp](./components/inlines.hpp): Any inline definitions for the `struct Code<Name>` are defined here.
|
||||
7. [interface.cpp](./components/interface.hpp): Define the `Code<Name>` upfront and parsing interface.
|
||||
8. [interface.upfront.cpp](./components/interface.upfront.cpp): Define the upfront constructor implementation.
|
||||
9. [interface.parsing.cpp](./components/interface.parsing.cpp): Define the parsing interface implementation.
|
||||
10. [lexer.cpp](./components/lexer.cpp): Adjust the lexer as needed.
|
||||
11. [parser.cpp](./components/parser.cpp): Adjust the parser as needed.
|
||||
|
||||
## A note on compilation and runtime generation speed
|
||||
|
||||
The library is designed to be fast to compile and generate code at runtime as fast as possible on a debug build.
|
||||
Its recommended that your metaprogam be compiled using a single translation unit (unity build).
|
||||
|
||||
## Whats with the expression / executions support #ifd and enums?
|
||||
|
||||
The library is a *work in progress* and those are unfinished hypotheticals for adding the ability to manage or parse the AST of expresions or execution scope code.
|
||||
They are entirely untested and not meant to be used yet, futher there is no parsing support or an upfront interface for what CodeTypes are defined so far.
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# include "builder.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Builder
|
||||
|
||||
Builder builder_open( char const* path )
|
||||
{
|
||||
Builder result;
|
||||
|
||||
FileError error = file_open_mode( & result.File, EFileMode_WRITE, path );
|
||||
if ( error != EFileError_NONE )
|
||||
{
|
||||
log_failure( "gen::File::open - Could not open file: %s", path);
|
||||
return result;
|
||||
}
|
||||
|
||||
Context* ctx = get_context();
|
||||
GEN_ASSERT_NOT_NULL(ctx);
|
||||
result.Buffer = strbuilder_make_reserve( ctx->Allocator_Temp, ctx->InitSize_BuilderBuffer );
|
||||
|
||||
// log_fmt("$Builder - Opened file: %s\n", result.File.filename );
|
||||
return result;
|
||||
}
|
||||
|
||||
void builder_pad_lines( Builder* builder, s32 num )
|
||||
{
|
||||
strbuilder_append_str( & builder->Buffer, txt("\n") );
|
||||
}
|
||||
|
||||
void builder_print( Builder* builder, Code code )
|
||||
{
|
||||
StrBuilder str = code_to_strbuilder(code);
|
||||
// const ssize len = str.length();
|
||||
// log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data );
|
||||
strbuilder_append_string( & builder->Buffer, str );
|
||||
}
|
||||
|
||||
void builder_print_fmt_va( Builder* builder, char const* fmt, va_list va )
|
||||
{
|
||||
ssize res;
|
||||
char buf[ GEN_PRINTF_MAXLEN ] = { 0 };
|
||||
|
||||
res = c_str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1;
|
||||
|
||||
strbuilder_append_c_str_len( (StrBuilder*) & (builder->Buffer), (char const*)buf, res);
|
||||
}
|
||||
|
||||
void builder_write(Builder* builder)
|
||||
{
|
||||
b32 result = file_write( & builder->File, builder->Buffer, strbuilder_length(builder->Buffer) );
|
||||
|
||||
if ( result == false )
|
||||
log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & builder->File ) );
|
||||
|
||||
log_fmt( "Generated: %s\n", builder->File.filename );
|
||||
file_close( & builder->File );
|
||||
strbuilder_free(& builder->Buffer);
|
||||
}
|
||||
|
||||
#pragma endregion Builder
|
||||
@@ -0,0 +1,71 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "helpers/push_ignores.inline.hpp"
|
||||
# include "components/header_start.hpp"
|
||||
# include "components/types.hpp"
|
||||
# include "components/gen/ecode.hpp"
|
||||
# include "components/gen/eoperator.hpp"
|
||||
# include "components/gen/especifier.hpp"
|
||||
# include "components/ast.hpp"
|
||||
# include "components/code_types.hpp"
|
||||
# include "components/ast_types.hpp"
|
||||
# include "components/interface.hpp"
|
||||
# include "components/inlines.hpp"
|
||||
# include "components/gen/ast_inlines.hpp"
|
||||
# include "components/header_end.hpp"
|
||||
using namespace gen;
|
||||
#endif
|
||||
|
||||
#pragma region Builder
|
||||
|
||||
struct Builder;
|
||||
typedef struct Builder Builder;
|
||||
|
||||
GEN_API Builder builder_open ( char const* path );
|
||||
GEN_API void builder_pad_lines ( Builder* builder, s32 num );
|
||||
GEN_API void builder_print ( Builder* builder, Code code );
|
||||
GEN_API void builder_print_fmt_va( Builder* builder, char const* fmt, va_list va );
|
||||
GEN_API void builder_write ( Builder* builder );
|
||||
|
||||
forceinline void builder_print_fmt ( Builder* builder, char const* fmt, ... ) {
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
builder_print_fmt_va( builder, fmt, va );
|
||||
va_end( va );
|
||||
}
|
||||
|
||||
struct Builder
|
||||
{
|
||||
FileInfo File;
|
||||
StrBuilder Buffer;
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline static Builder open( char const* path ) { return builder_open(path); }
|
||||
|
||||
forceinline void pad_lines( s32 num ) { return builder_pad_lines(this, num); }
|
||||
|
||||
forceinline void print( Code code ) { return builder_print(this, code); }
|
||||
forceinline void print_fmt( char const* fmt, ... ) {
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
builder_print_fmt_va( this, fmt, va );
|
||||
va_end( va );
|
||||
}
|
||||
|
||||
forceinline void write() { return builder_write(this); }
|
||||
#endif
|
||||
};
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline void builder_pad_lines( Builder& builder, s32 num ) { return builder_pad_lines(& builder, num); }
|
||||
forceinline void builder_print ( Builder& builder, Code code ) { return builder_print(& builder, code); }
|
||||
forceinline void builder_write ( Builder& builder ) { return builder_write(& builder ); }
|
||||
forceinline void builder_print_fmt( Builder& builder, char const* fmt, ...) {
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
builder_print_fmt_va( & builder, fmt, va );
|
||||
va_end( va );
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma endregion Builder
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "helpers/push_ignores.inline.hpp"
|
||||
# include "components/header_start.hpp"
|
||||
# include "components/types.hpp"
|
||||
# include "components/gen/ecode.hpp"
|
||||
# include "components/gen/eoperator.hpp"
|
||||
# include "components/gen/especifier.hpp"
|
||||
# include "components/ast.hpp"
|
||||
# include "components/code_types.hpp"
|
||||
# include "components/ast_types.hpp"
|
||||
# include "components/interface.hpp"
|
||||
# include "components/inlines.hpp"
|
||||
# include "components/gen/ast_inlines.hpp"
|
||||
# include "components/header_end.hpp"
|
||||
#endif
|
||||
|
||||
/*
|
||||
Explicitly generates a resolved definition of a cpp template definition.
|
||||
|
||||
TODO(Ed): Needs implementing for the C-library variant.
|
||||
TODO(Ed): We need a non <token> syntax subst implemtnation for Strings for this to work. It must subst keywords directly based on template parameter names.
|
||||
|
||||
This is only meant to be used on relatively trivial templates, where the type or numeric is mostly a 'duck' type.
|
||||
It cannot parse complex template parameters.
|
||||
|
||||
The varadic args should correspond 1:1 with the type of objects the generator expects from the template's parameters.alignas.
|
||||
*/
|
||||
|
||||
CodeOperator gen_operator_template( CodeTemplate template, ... );
|
||||
CodeFn gen_func_template( CodeTemplate template, ... );
|
||||
Code gen_class_struct_template( CodeTemplate template, ... );
|
||||
|
||||
Code gen_template( CodeTemplate template, ... );
|
||||
Code gen_template( Str template, Str instantiation );
|
||||
@@ -0,0 +1,148 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# include "scanner.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Scanner
|
||||
|
||||
Code scan_file( char const* path )
|
||||
{
|
||||
FileInfo file;
|
||||
|
||||
FileError error = file_open_mode( & file, EFileMode_READ, path );
|
||||
if ( error != EFileError_NONE )
|
||||
{
|
||||
GEN_FATAL( "scan_file: Could not open: %s", path );
|
||||
}
|
||||
|
||||
ssize fsize = file_size( & file );
|
||||
if ( fsize <= 0 )
|
||||
{
|
||||
GEN_FATAL("scan_file: %s is empty", path );
|
||||
}
|
||||
|
||||
StrBuilder str = strbuilder_make_reserve( get_context()->Allocator_Temp, fsize );
|
||||
file_read( & file, str, fsize );
|
||||
strbuilder_get_header(str)->Length = fsize;
|
||||
|
||||
// Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks
|
||||
// Its designed so that the directive should be the first thing in the file.
|
||||
// Anything that comes before it will also be omitted.
|
||||
{
|
||||
#define current (*scanner)
|
||||
#define matched 0
|
||||
#define move_fwd() do { ++ scanner; -- left; } while (0)
|
||||
const Str directive_start = txt( "ifdef" );
|
||||
const Str directive_end = txt( "endif" );
|
||||
const Str def_intellisense = txt("GEN_INTELLISENSE_DIRECTIVES" );
|
||||
|
||||
bool found_directive = false;
|
||||
char const* scanner = (char const*)str;
|
||||
s32 left = fsize;
|
||||
while ( left )
|
||||
{
|
||||
// Processing directive.
|
||||
if ( current == '#' )
|
||||
{
|
||||
move_fwd();
|
||||
while ( left && char_is_space( current ) )
|
||||
move_fwd();
|
||||
|
||||
if ( ! found_directive )
|
||||
{
|
||||
if ( left && c_str_compare_len( scanner, directive_start.Ptr, directive_start.Len ) == matched )
|
||||
{
|
||||
scanner += directive_start.Len;
|
||||
left -= directive_start.Len;
|
||||
|
||||
while ( left && char_is_space( current ) )
|
||||
move_fwd();
|
||||
|
||||
if ( left && c_str_compare_len( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched )
|
||||
{
|
||||
scanner += def_intellisense.Len;
|
||||
left -= def_intellisense.Len;
|
||||
|
||||
found_directive = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip to end of line
|
||||
while ( left && current != '\r' && current != '\n' )
|
||||
move_fwd();
|
||||
move_fwd();
|
||||
|
||||
if ( left && current == '\n' )
|
||||
move_fwd();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( left && c_str_compare_len( scanner, directive_end.Ptr, directive_end.Len ) == matched )
|
||||
{
|
||||
scanner += directive_end.Len;
|
||||
left -= directive_end.Len;
|
||||
|
||||
// Skip to end of line
|
||||
while ( left && current != '\r' && current != '\n' )
|
||||
move_fwd();
|
||||
move_fwd();
|
||||
|
||||
if ( left && current == '\n' )
|
||||
move_fwd();
|
||||
|
||||
// sptr skip_size = fsize - left;
|
||||
if ( (scanner + 2) >= ( (char const*) str + fsize ) )
|
||||
{
|
||||
mem_move( str, scanner, left );
|
||||
strbuilder_get_header(str)->Length = left;
|
||||
break;
|
||||
}
|
||||
|
||||
mem_move( str, scanner, left );
|
||||
strbuilder_get_header(str)->Length = left;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
move_fwd();
|
||||
}
|
||||
#undef move_fwd
|
||||
#undef matched
|
||||
#undef current
|
||||
}
|
||||
|
||||
file_close( & file );
|
||||
return untyped_str( strbuilder_to_str(str) );
|
||||
}
|
||||
|
||||
CodeBody parse_file( const char* path ) {
|
||||
FileContents file = file_read_contents( get_context()->Allocator_Temp, true, path );
|
||||
Str content = { (char const*)file.data, file.size };
|
||||
CodeBody code = parse_global_body( content );
|
||||
log_fmt("\nParsed: %s\n", path);
|
||||
return code;
|
||||
}
|
||||
|
||||
CSV_Column parse_csv_one_column(AllocatorInfo allocator, char const* path) {
|
||||
FileContents content = file_read_contents( allocator, file_zero_terminate, path );
|
||||
Arena csv_arena = arena_init_from_memory(content.data, content.size);
|
||||
|
||||
CSV_Column result;
|
||||
csv_parse( & result.ADT, rcast(char*, content.data), allocator, false );
|
||||
result.Content = result.ADT.nodes[0].nodes;
|
||||
return result;
|
||||
}
|
||||
|
||||
CSV_Columns2 parse_csv_two_columns(AllocatorInfo allocator, char const* path) {
|
||||
FileContents content = file_read_contents( allocator, file_zero_terminate, path );
|
||||
Arena csv_arena = arena_init_from_memory(content.data, content.size);
|
||||
|
||||
CSV_Columns2 result;
|
||||
csv_parse( & result.ADT, rcast(char*, content.data), allocator, false );
|
||||
result.Col_1 = result.ADT.nodes[0].nodes;
|
||||
result.Col_2 = result.ADT.nodes[1].nodes;
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma endregion Scanner
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "helpers/push_ignores.inline.hpp"
|
||||
# include "components/header_start.hpp"
|
||||
# include "components/types.hpp"
|
||||
# include "components/gen/ecode.hpp"
|
||||
# include "components/gen/eoperator.hpp"
|
||||
# include "components/gen/especifier.hpp"
|
||||
# include "components/ast.hpp"
|
||||
# include "components/code_types.hpp"
|
||||
# include "components/ast_types.hpp"
|
||||
# include "components/interface.hpp"
|
||||
# include "components/inlines.hpp"
|
||||
# include "components/gen/ast_inlines.hpp"
|
||||
# include "components/header_end.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Scanner
|
||||
|
||||
// This is a simple file reader that reads the entire file into memory.
|
||||
// It has an extra option to skip the first few lines for undesired includes.
|
||||
// This is done so that includes can be kept in dependency and component files so that intellisense works.
|
||||
GEN_API Code scan_file( char const* path );
|
||||
|
||||
GEN_API CodeBody parse_file( const char* path );
|
||||
|
||||
// The follow is basic support for light csv parsing (use it as an example)
|
||||
// Make something robust if its more serious.
|
||||
|
||||
typedef struct CSV_Column CSV_Column;
|
||||
struct CSV_Column {
|
||||
CSV_Object ADT;
|
||||
Array(ADT_Node) Content;
|
||||
};
|
||||
|
||||
typedef struct CSV_Columns2 CSV_Columns2;
|
||||
struct CSV_Columns2 {
|
||||
CSV_Object ADT;
|
||||
Array(ADT_Node) Col_1;
|
||||
Array(ADT_Node) Col_2;
|
||||
};
|
||||
|
||||
GEN_API CSV_Column parse_csv_one_column (AllocatorInfo allocator, char const* path);
|
||||
GEN_API CSV_Columns2 parse_csv_two_columns(AllocatorInfo allocator, char const* path);
|
||||
|
||||
#pragma endregion Scanner
|
||||
@@ -0,0 +1,74 @@
|
||||
#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
#define GEN_ENFORCE_STRONG_CODE_TYPES
|
||||
#define GEN_C_LIKE_CPP 1
|
||||
#include "gen.cpp"
|
||||
#include "helpers/push_ignores.inline.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
GEN_NS_BEGIN
|
||||
#include "helpers/base_codegen.hpp"
|
||||
#include "helpers/misc.hpp"
|
||||
GEN_NS_END
|
||||
|
||||
using namespace gen;
|
||||
|
||||
constexpr char const* path_format_style = "../scripts/.clang-format";
|
||||
constexpr char const* scratch_file = "build/scratch.hpp";
|
||||
|
||||
Code format( Code code ) {
|
||||
return code_refactor_and_format(code, scratch_file, nullptr, path_format_style );
|
||||
}
|
||||
|
||||
constexpr char const* generation_notice =
|
||||
"// This file was generated automatially by gencpp's bootstrap.cpp "
|
||||
"(See: https://github.com/Ed94/gencpp)\n\n";
|
||||
|
||||
int gen_main()
|
||||
{
|
||||
gen::Context ctx {};
|
||||
gen::init( & ctx);
|
||||
|
||||
CodeBody gen_component_header = def_global_body( args(
|
||||
def_preprocess_cond( PreprocessCond_IfDef, txt("GEN_INTELLISENSE_DIRECTIVES") ),
|
||||
pragma_once,
|
||||
def_include(txt("components/types.hpp")),
|
||||
preprocess_endif,
|
||||
fmt_newline,
|
||||
untyped_str( to_str_from_c_str(generation_notice) )
|
||||
));
|
||||
|
||||
CodeBody ecode = gen_ecode ( "enums/ECodeTypes.csv" );
|
||||
CodeBody eoperator = gen_eoperator ( "enums/EOperator.csv" );
|
||||
CodeBody especifier = gen_especifier( "enums/ESpecifier.csv" );
|
||||
CodeBody etoktype = gen_etoktype ( "enums/ETokType.csv", "enums/AttributeTokens.csv" );
|
||||
CodeBody ast_inlines = gen_ast_inlines();
|
||||
|
||||
Builder header_ecode = builder_open( "components/gen/ecodetypes.hpp" );
|
||||
builder_print( & header_ecode, gen_component_header );
|
||||
builder_print( & header_ecode, format(ecode) );
|
||||
builder_write( & header_ecode);
|
||||
|
||||
Builder header_eoperator = builder_open( "components/gen/eoperator.hpp" );
|
||||
builder_print( & header_eoperator, gen_component_header );
|
||||
builder_print( & header_eoperator, format(eoperator) );
|
||||
builder_write( & header_eoperator );
|
||||
|
||||
Builder header_especifier = builder_open( "components/gen/especifier.hpp" );
|
||||
builder_print( & header_especifier, gen_component_header );
|
||||
builder_print( & header_especifier, format(especifier) );
|
||||
builder_write( & header_especifier);
|
||||
|
||||
Builder header_etoktype = builder_open( "components/gen/etoktype.hpp" );
|
||||
builder_print( & header_etoktype, gen_component_header );
|
||||
builder_print( & header_etoktype, format(etoktype) );
|
||||
builder_write( & header_etoktype);
|
||||
|
||||
Builder header_ast_inlines = builder_open( "components/gen/ast_inlines.hpp" );
|
||||
builder_print( & header_ast_inlines, gen_component_header );
|
||||
builder_print( & header_ast_inlines, format(ast_inlines) );
|
||||
builder_write( & header_ast_inlines);
|
||||
|
||||
gen::deinit(& ctx);
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,457 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "types.hpp"
|
||||
#include "gen/ecode.hpp"
|
||||
#include "gen/eoperator.hpp"
|
||||
#include "gen/especifier.hpp"
|
||||
#endif
|
||||
|
||||
/*
|
||||
______ ______ ________ __ __ ______ __
|
||||
/ \ / \| \ | \ | \ / \ | \
|
||||
| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ | ▓▓\ | ▓▓ | ▓▓▓▓▓▓\ ______ ____| ▓▓ ______
|
||||
| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓▓\| ▓▓ | ▓▓ \▓▓/ \ / ▓▓/ \
|
||||
| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\
|
||||
| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓
|
||||
| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓ | ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓
|
||||
| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓▓ \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \
|
||||
\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
|
||||
*/
|
||||
|
||||
struct AST;
|
||||
struct AST_Body;
|
||||
struct AST_Attributes;
|
||||
struct AST_Comment;
|
||||
struct AST_Constructor;
|
||||
// struct AST_BaseClass;
|
||||
struct AST_Class;
|
||||
struct AST_Define;
|
||||
struct AST_DefineParams;
|
||||
struct AST_Destructor;
|
||||
struct AST_Enum;
|
||||
struct AST_Exec;
|
||||
struct AST_Extern;
|
||||
struct AST_Include;
|
||||
struct AST_Friend;
|
||||
struct AST_Fn;
|
||||
struct AST_Module;
|
||||
struct AST_NS;
|
||||
struct AST_Operator;
|
||||
struct AST_OpCast;
|
||||
struct AST_Params;
|
||||
struct AST_Pragma;
|
||||
struct AST_PreprocessCond;
|
||||
struct AST_Specifiers;
|
||||
|
||||
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
|
||||
struct AST_Expr;
|
||||
struct AST_Expr_Assign;
|
||||
struct AST_Expr_Alignof;
|
||||
struct AST_Expr_Binary;
|
||||
struct AST_Expr_CStyleCast;
|
||||
struct AST_Expr_FunctionalCast;
|
||||
struct AST_Expr_CppCast;
|
||||
struct AST_Expr_ProcCall;
|
||||
struct AST_Expr_Decltype;
|
||||
struct AST_Expr_Comma; // TODO(Ed) : This is a binary op not sure if it needs its own AST...
|
||||
struct AST_Expr_AMS; // Access Member Symbol
|
||||
struct AST_Expr_Sizeof;
|
||||
struct AST_Expr_Subscript;
|
||||
struct AST_Expr_Ternary;
|
||||
struct AST_Expr_UnaryPrefix;
|
||||
struct AST_Expr_UnaryPostfix;
|
||||
struct AST_Expr_Element;
|
||||
|
||||
struct AST_Stmt;
|
||||
struct AST_Stmt_Break;
|
||||
struct AST_Stmt_Case;
|
||||
struct AST_Stmt_Continue;
|
||||
struct AST_Stmt_Decl;
|
||||
struct AST_Stmt_Do;
|
||||
struct AST_Stmt_Expr; // TODO(Ed) : Is this distinction needed? (Should it be a flag instead?)
|
||||
struct AST_Stmt_Else;
|
||||
struct AST_Stmt_If;
|
||||
struct AST_Stmt_For;
|
||||
struct AST_Stmt_Goto;
|
||||
struct AST_Stmt_Label;
|
||||
struct AST_Stmt_Switch;
|
||||
struct AST_Stmt_While;
|
||||
#endif
|
||||
|
||||
struct AST_Struct;
|
||||
struct AST_Template;
|
||||
struct AST_Typename;
|
||||
struct AST_Typedef;
|
||||
struct AST_Union;
|
||||
struct AST_Using;
|
||||
struct AST_Var;
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST* Code;
|
||||
#else
|
||||
struct Code;
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST_Body* CodeBody;
|
||||
typedef AST_Attributes* CodeAttributes;
|
||||
typedef AST_Comment* CodeComment;
|
||||
typedef AST_Class* CodeClass;
|
||||
typedef AST_Constructor* CodeConstructor;
|
||||
typedef AST_Define* CodeDefine;
|
||||
typedef AST_DefineParams* CodeDefineParams;
|
||||
typedef AST_Destructor* CodeDestructor;
|
||||
typedef AST_Enum* CodeEnum;
|
||||
typedef AST_Exec* CodeExec;
|
||||
typedef AST_Extern* CodeExtern;
|
||||
typedef AST_Include* CodeInclude;
|
||||
typedef AST_Friend* CodeFriend;
|
||||
typedef AST_Fn* CodeFn;
|
||||
typedef AST_Module* CodeModule;
|
||||
typedef AST_NS* CodeNS;
|
||||
typedef AST_Operator* CodeOperator;
|
||||
typedef AST_OpCast* CodeOpCast;
|
||||
typedef AST_Params* CodeParams;
|
||||
typedef AST_PreprocessCond* CodePreprocessCond;
|
||||
typedef AST_Pragma* CodePragma;
|
||||
typedef AST_Specifiers* CodeSpecifiers;
|
||||
#else
|
||||
struct CodeBody;
|
||||
struct CodeAttributes;
|
||||
struct CodeComment;
|
||||
struct CodeClass;
|
||||
struct CodeConstructor;
|
||||
struct CodeDefine;
|
||||
struct CodeDefineParams;
|
||||
struct CodeDestructor;
|
||||
struct CodeEnum;
|
||||
struct CodeExec;
|
||||
struct CodeExtern;
|
||||
struct CodeInclude;
|
||||
struct CodeFriend;
|
||||
struct CodeFn;
|
||||
struct CodeModule;
|
||||
struct CodeNS;
|
||||
struct CodeOperator;
|
||||
struct CodeOpCast;
|
||||
struct CodeParams;
|
||||
struct CodePreprocessCond;
|
||||
struct CodePragma;
|
||||
struct CodeSpecifiers;
|
||||
#endif
|
||||
|
||||
#ifdef GEN_EXECUTION_EXPRESSION_SUPPORT
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST_Expr* CodeExpr;
|
||||
typedef AST_Expr_Assign* CodeExpr_Assign;
|
||||
typedef AST_Expr_Alignof* CodeExpr_Alignof;
|
||||
typedef AST_Expr_Binary* CodeExpr_Binary;
|
||||
typedef AST_Expr_CStyleCast* CodeExpr_CStyleCast;
|
||||
typedef AST_Expr_FunctionalCast* CodeExpr_FunctionalCast;
|
||||
typedef AST_Expr_CppCast* CodeExpr_CppCast;
|
||||
typedef AST_Expr_Element* CodeExpr_Element;
|
||||
typedef AST_Expr_ProcCall* CodeExpr_ProcCall;
|
||||
typedef AST_Expr_Decltype* CodeExpr_Decltype;
|
||||
typedef AST_Expr_Comma* CodeExpr_Comma;
|
||||
typedef AST_Expr_AMS* CodeExpr_AMS; // Access Member Symbol
|
||||
typedef AST_Expr_Sizeof* CodeExpr_Sizeof;
|
||||
typedef AST_Expr_Subscript* CodeExpr_Subscript;
|
||||
typedef AST_Expr_Ternary* CodeExpr_Ternary;
|
||||
typedef AST_Expr_UnaryPrefix* CodeExpr_UnaryPrefix;
|
||||
typedef AST_Expr_UnaryPostfix* CodeExpr_UnaryPostfix;
|
||||
#else
|
||||
struct CodeExpr;
|
||||
struct CodeExpr_Assign;
|
||||
struct CodeExpr_Alignof;
|
||||
struct CodeExpr_Binary;
|
||||
struct CodeExpr_CStyleCast;
|
||||
struct CodeExpr_FunctionalCast;
|
||||
struct CodeExpr_CppCast;
|
||||
struct CodeExpr_Element;
|
||||
struct CodeExpr_ProcCall;
|
||||
struct CodeExpr_Decltype;
|
||||
struct CodeExpr_Comma;
|
||||
struct CodeExpr_AMS; // Access Member Symbol
|
||||
struct CodeExpr_Sizeof;
|
||||
struct CodeExpr_Subscript;
|
||||
struct CodeExpr_Ternary;
|
||||
struct CodeExpr_UnaryPrefix;
|
||||
struct CodeExpr_UnaryPostfix;
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST_Stmt* CodeStmt;
|
||||
typedef AST_Stmt_Break* CodeStmt_Break;
|
||||
typedef AST_Stmt_Case* CodeStmt_Case;
|
||||
typedef AST_Stmt_Continue* CodeStmt_Continue;
|
||||
typedef AST_Stmt_Decl* CodeStmt_Decl;
|
||||
typedef AST_Stmt_Do* CodeStmt_Do;
|
||||
typedef AST_Stmt_Expr* CodeStmt_Expr;
|
||||
typedef AST_Stmt_Else* CodeStmt_Else;
|
||||
typedef AST_Stmt_If* CodeStmt_If;
|
||||
typedef AST_Stmt_For* CodeStmt_For;
|
||||
typedef AST_Stmt_Goto* CodeStmt_Goto;
|
||||
typedef AST_Stmt_Label* CodeStmt_Label;
|
||||
typedef AST_Stmt_Switch* CodeStmt_Switch;
|
||||
typedef AST_Stmt_While* CodeStmt_While;
|
||||
#else
|
||||
struct CodeStmt;
|
||||
struct CodeStmt_Break;
|
||||
struct CodeStmt_Case;
|
||||
struct CodeStmt_Continue;
|
||||
struct CodeStmt_Decl;
|
||||
struct CodeStmt_Do;
|
||||
struct CodeStmt_Expr;
|
||||
struct CodeStmt_Else;
|
||||
struct CodeStmt_If;
|
||||
struct CodeStmt_For;
|
||||
struct CodeStmt_Goto;
|
||||
struct CodeStmt_Label;
|
||||
struct CodeStmt_Switch;
|
||||
struct CodeStmt_While;
|
||||
#endif
|
||||
|
||||
// GEN_EXECUTION_EXPRESSION_SUPPORT
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef AST_Struct* CodeStruct;
|
||||
typedef AST_Template* CodeTemplate;
|
||||
typedef AST_Typename* CodeTypename;
|
||||
typedef AST_Typedef* CodeTypedef;
|
||||
typedef AST_Union* CodeUnion;
|
||||
typedef AST_Using* CodeUsing;
|
||||
typedef AST_Var* CodeVar;
|
||||
#else
|
||||
struct CodeStruct;
|
||||
struct CodeTemplate;
|
||||
struct CodeTypename;
|
||||
struct CodeTypedef;
|
||||
struct CodeUnion;
|
||||
struct CodeUsing;
|
||||
struct CodeVar;
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); }
|
||||
#endif
|
||||
|
||||
#pragma region Code C-Interface
|
||||
|
||||
GEN_API void code_append (Code code, Code other );
|
||||
GEN_API Str code_debug_str (Code code);
|
||||
GEN_API Code code_duplicate (Code code);
|
||||
GEN_API Code* code_entry (Code code, u32 idx );
|
||||
GEN_API bool code_has_entries (Code code);
|
||||
GEN_API bool code_is_body (Code code);
|
||||
GEN_API bool code_is_equal (Code code, Code other);
|
||||
GEN_API bool code_is_valid (Code code);
|
||||
GEN_API void code_set_global (Code code);
|
||||
GEN_API StrBuilder code_to_strbuilder (Code self );
|
||||
GEN_API void code_to_strbuilder_ptr(Code self, StrBuilder* result );
|
||||
GEN_API Str code_type_str (Code self );
|
||||
GEN_API bool code_validate_body (Code self );
|
||||
|
||||
#pragma endregion Code C-Interface
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
/*
|
||||
AST* wrapper
|
||||
- Not constantly have to append the '*' as this is written often..
|
||||
- Allows for implicit conversion to any of the ASTs (raw or filtered).
|
||||
*/
|
||||
struct Code
|
||||
{
|
||||
AST* ast;
|
||||
|
||||
# define Using_Code( Typename ) \
|
||||
forceinline Str debug_str() { return code_debug_str(* this); } \
|
||||
forceinline Code duplicate() { return code_duplicate(* this); } \
|
||||
forceinline bool is_equal( Code other ) { return code_is_equal(* this, other); } \
|
||||
forceinline bool is_body() { return code_is_body(* this); } \
|
||||
forceinline bool is_valid() { return code_is_valid(* this); } \
|
||||
forceinline void set_global() { return code_set_global(* this); }
|
||||
|
||||
# define Using_CodeOps( Typename ) \
|
||||
forceinline Typename& operator = ( Code other ); \
|
||||
forceinline bool operator ==( Code other ) { return (AST*)ast == other.ast; } \
|
||||
forceinline bool operator !=( Code other ) { return (AST*)ast != other.ast; } \
|
||||
forceinline bool operator ==(std::nullptr_t) const { return ast == nullptr; } \
|
||||
forceinline bool operator !=(std::nullptr_t) const { return ast != nullptr; } \
|
||||
operator bool();
|
||||
|
||||
#if ! GEN_C_LIKE_CPP
|
||||
Using_Code( Code );
|
||||
forceinline void append(Code other) { return code_append(* this, other); }
|
||||
forceinline Code* entry(u32 idx) { return code_entry(* this, idx); }
|
||||
forceinline bool has_entries() { return code_has_entries(* this); }
|
||||
forceinline StrBuilder to_strbuilder() { return code_to_strbuilder(* this); }
|
||||
forceinline void to_strbuilder(StrBuilder& result) { return code_to_strbuilder_ptr(* this, & result); }
|
||||
forceinline Str type_str() { return code_type_str(* this); }
|
||||
forceinline bool validate_body() { return code_validate_body(*this); }
|
||||
#endif
|
||||
|
||||
Using_CodeOps( Code );
|
||||
forceinline Code operator *() { return * this; } // Required to support for-range iteration.
|
||||
forceinline AST* operator ->() { return ast; }
|
||||
|
||||
Code& operator ++();
|
||||
|
||||
#ifdef GEN_ENFORCE_STRONG_CODE_TYPES
|
||||
# define operator explicit operator
|
||||
#endif
|
||||
operator CodeBody() const;
|
||||
operator CodeAttributes() const;
|
||||
// operator CodeBaseClass() const;
|
||||
operator CodeComment() const;
|
||||
operator CodeClass() const;
|
||||
operator CodeConstructor() const;
|
||||
operator CodeDefine() const;
|
||||
operator CodeDefineParams() const;
|
||||
operator CodeDestructor() const;
|
||||
operator CodeExec() const;
|
||||
operator CodeEnum() const;
|
||||
operator CodeExtern() const;
|
||||
operator CodeInclude() const;
|
||||
operator CodeFriend() const;
|
||||
operator CodeFn() const;
|
||||
operator CodeModule() const;
|
||||
operator CodeNS() const;
|
||||
operator CodeOperator() const;
|
||||
operator CodeOpCast() const;
|
||||
operator CodeParams() const;
|
||||
operator CodePragma() const;
|
||||
operator CodePreprocessCond() const;
|
||||
operator CodeSpecifiers() const;
|
||||
operator CodeStruct() const;
|
||||
operator CodeTemplate() const;
|
||||
operator CodeTypename() const;
|
||||
operator CodeTypedef() const;
|
||||
operator CodeUnion() const;
|
||||
operator CodeUsing() const;
|
||||
operator CodeVar() const;
|
||||
#undef operator
|
||||
};
|
||||
#endif
|
||||
|
||||
#pragma region Statics
|
||||
// Used to identify ASTs that should always be duplicated. (Global constant ASTs)
|
||||
GEN_API extern Code Code_Global;
|
||||
|
||||
// Used to identify invalid generated code.
|
||||
GEN_API extern Code Code_Invalid;
|
||||
#pragma endregion Statics
|
||||
|
||||
struct Code_POD
|
||||
{
|
||||
AST* ast;
|
||||
};
|
||||
static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" );
|
||||
|
||||
// Desired width of the AST data structure.
|
||||
constexpr int const AST_POD_Size = 128;
|
||||
|
||||
constexpr static
|
||||
int AST_ArrSpecs_Cap =
|
||||
(
|
||||
AST_POD_Size
|
||||
- sizeof(Code)
|
||||
- sizeof(StrCached)
|
||||
- sizeof(Code) * 2
|
||||
- sizeof(Token*)
|
||||
- sizeof(Code)
|
||||
- sizeof(CodeType)
|
||||
- sizeof(ModuleFlag)
|
||||
- sizeof(u32)
|
||||
)
|
||||
/ sizeof(Specifier) - 1;
|
||||
|
||||
/*
|
||||
Simple AST POD with functionality to seralize into C++ syntax.
|
||||
TODO(Ed): Eventually haven't a transparent AST like this will longer be viable once statements & expressions are in (most likely....)
|
||||
*/
|
||||
struct AST
|
||||
{
|
||||
union {
|
||||
struct
|
||||
{
|
||||
Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable
|
||||
Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable // TODO(Ed): Parameters can have attributes
|
||||
Code Specs; // Class, Destructor, Function, Operator, Struct, Typename, Variable
|
||||
union {
|
||||
Code InitializerList; // Constructor
|
||||
Code ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces.
|
||||
Code ReturnType; // Function, Operator, Typename
|
||||
Code UnderlyingType; // Enum, Typedef
|
||||
Code ValueType; // Parameter, Variable
|
||||
};
|
||||
union {
|
||||
Code Macro; // Parameter
|
||||
Code BitfieldSize; // Variable (Class/Struct Data Member)
|
||||
Code Params; // Constructor, Define, Function, Operator, Template, Typename
|
||||
Code UnderlyingTypeMacro; // Enum
|
||||
};
|
||||
union {
|
||||
Code ArrExpr; // Typename
|
||||
Code Body; // Class, Constructor, Define, Destructor, Enum, Friend, Function, Namespace, Struct, Union
|
||||
Code Declaration; // Friend, Template
|
||||
Code Value; // Parameter, Variable
|
||||
};
|
||||
union {
|
||||
Code NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value )
|
||||
Code SuffixSpecs; // Typename, Function (Thanks Unreal)
|
||||
Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal)
|
||||
};
|
||||
};
|
||||
StrCached Content; // Attributes, Comment, Execution, Include
|
||||
struct {
|
||||
Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers
|
||||
Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used.
|
||||
};
|
||||
};
|
||||
StrCached Name;
|
||||
union {
|
||||
Code Prev;
|
||||
Code Front;
|
||||
Code Last;
|
||||
};
|
||||
union {
|
||||
Code Next;
|
||||
Code Back;
|
||||
};
|
||||
Token* Token; // Reference to starting token, only available if it was derived from parsing.
|
||||
Code Parent;
|
||||
CodeType Type;
|
||||
// CodeFlag CodeFlags;
|
||||
ModuleFlag ModuleFlags;
|
||||
union {
|
||||
b32 IsFunction; // Used by typedef to not serialize the name field.
|
||||
struct {
|
||||
b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack.
|
||||
ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union)
|
||||
};
|
||||
Operator Op;
|
||||
AccessSpec ParentAccess;
|
||||
s32 NumEntries;
|
||||
s32 VarParenthesizedInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression.
|
||||
};
|
||||
};
|
||||
static_assert( sizeof(AST) == AST_POD_Size, "ERROR: AST is not size of AST_POD_Size" );
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
// Uses an implicitly overloaded cast from the AST to the desired code type.
|
||||
// Necessary if the user wants GEN_ENFORCE_STRONG_CODE_TYPES
|
||||
struct InvalidCode_ImplictCaster;
|
||||
#define InvalidCode (InvalidCode_ImplictCaster{})
|
||||
#else
|
||||
#define InvalidCode (void*){ (void*)Code_Invalid }
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
struct NullCode_ImplicitCaster;
|
||||
// Used when the its desired when omission is allowed in a definition.
|
||||
#define NullCode (NullCode_ImplicitCaster{})
|
||||
#else
|
||||
#define NullCode nullptr
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
// These macros are used in the swtich cases within ast.cpp, inteface.upfront.cpp, parser.cpp
|
||||
|
||||
# define GEN_AST_BODY_CLASS_UNALLOWED_TYPES_CASES \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Extern_Linkage: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Function_Fwd: \
|
||||
case CT_Global_Body: \
|
||||
case CT_Namespace: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator: \
|
||||
case CT_Operator_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename
|
||||
# define GEN_AST_BODY_STRUCT_UNALLOWED_TYPES_CASES GEN_AST_BODY_CLASS_UNALLOWED_TYPES_CASES
|
||||
|
||||
# define GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES_CASES \
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Extern_Linkage: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Function_Fwd: \
|
||||
case CT_Global_Body: \
|
||||
case CT_Namespace: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator: \
|
||||
case CT_Operator_Fwd: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename
|
||||
|
||||
# define GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES_CASES \
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Execution: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename
|
||||
# define GEN_AST_BODY_EXPORT_UNALLOWED_TYPES_CASES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES_CASES
|
||||
# define GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES_CASES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES_CASES
|
||||
|
||||
# define GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES_CASES \
|
||||
case CT_Access_Public: \
|
||||
case CT_Access_Protected: \
|
||||
case CT_Access_Private: \
|
||||
case CT_PlatformAttributes: \
|
||||
case CT_Class_Body: \
|
||||
case CT_Enum_Body: \
|
||||
case CT_Execution: \
|
||||
case CT_Friend: \
|
||||
case CT_Function_Body: \
|
||||
case CT_Namespace_Body: \
|
||||
case CT_Operator_Member: \
|
||||
case CT_Operator_Member_Fwd: \
|
||||
case CT_Parameters: \
|
||||
case CT_Specifiers: \
|
||||
case CT_Struct_Body: \
|
||||
case CT_Typename
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,986 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "components/types.hpp"
|
||||
#endif
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
#pragma region generated code inline implementation
|
||||
|
||||
inline Code& Code::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Code::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeBody& CodeBody::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeBody::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeAttributes& CodeAttributes::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeAttributes::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeAttributes::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Attributes* CodeAttributes::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeComment& CodeComment::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeComment::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeComment::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Comment* CodeComment::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeConstructor& CodeConstructor::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeConstructor::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeConstructor::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Constructor* CodeConstructor::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeClass& CodeClass::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeClass::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeDefine& CodeDefine::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeDefine::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeDefine::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Define* CodeDefine::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeDefineParams& CodeDefineParams::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeDefineParams::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeDestructor& CodeDestructor::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeDestructor::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeDestructor::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Destructor* CodeDestructor::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeEnum& CodeEnum::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeEnum::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeEnum::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Enum* CodeEnum::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeExec& CodeExec::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeExec::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeExec::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Exec* CodeExec::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeExtern& CodeExtern::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeExtern::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeExtern::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Extern* CodeExtern::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeFriend& CodeFriend::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeFriend::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeFriend::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Friend* CodeFriend::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeFn& CodeFn::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeFn::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeFn::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Fn* CodeFn::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeInclude& CodeInclude::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeInclude::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeInclude::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Include* CodeInclude::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeModule& CodeModule::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeModule::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeModule::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Module* CodeModule::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeNS& CodeNS::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeNS::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeNS::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_NS* CodeNS::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeOperator& CodeOperator::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeOperator::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeOperator::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Operator* CodeOperator::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeOpCast& CodeOpCast::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeOpCast::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeOpCast::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_OpCast* CodeOpCast::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeParams& CodeParams::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeParams::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodePragma& CodePragma::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodePragma::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodePragma::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Pragma* CodePragma::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodePreprocessCond& CodePreprocessCond::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodePreprocessCond::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodePreprocessCond::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_PreprocessCond* CodePreprocessCond::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeSpecifiers& CodeSpecifiers::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeSpecifiers::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeStruct& CodeStruct::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeStruct::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeTemplate& CodeTemplate::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeTemplate::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeTemplate::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Template* CodeTemplate::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeTypename& CodeTypename::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeTypename::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeTypename::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Typename* CodeTypename::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeTypedef& CodeTypedef::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeTypedef::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeTypedef::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Typedef* CodeTypedef::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeUnion& CodeUnion::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeUnion::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeUnion::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Union* CodeUnion::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeUsing& CodeUsing::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeUsing::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeUsing::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Using* CodeUsing::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
inline CodeVar& CodeVar::operator=(Code other)
|
||||
{
|
||||
if (other.ast != nullptr && other->Parent != nullptr)
|
||||
{
|
||||
ast = rcast(decltype(ast), code_duplicate(other).ast);
|
||||
ast->Parent = { nullptr };
|
||||
}
|
||||
ast = rcast(decltype(ast), other.ast);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CodeVar::operator bool()
|
||||
{
|
||||
return ast != nullptr;
|
||||
}
|
||||
|
||||
inline CodeVar::operator Code()
|
||||
{
|
||||
return *rcast(Code*, this);
|
||||
}
|
||||
|
||||
inline AST_Var* CodeVar::operator->()
|
||||
{
|
||||
if (ast == nullptr)
|
||||
{
|
||||
log_failure("Attempt to dereference a nullptr!\n");
|
||||
return nullptr;
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
#pragma endregion generated code inline implementation
|
||||
|
||||
#pragma region generated AST/Code cast implementation
|
||||
GEN_OPTIMIZE_MAPPINGS_BEGIN
|
||||
|
||||
forceinline Code::operator CodeBody() const
|
||||
{
|
||||
return { (AST_Body*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeAttributes() const
|
||||
{
|
||||
return { (AST_Attributes*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeComment() const
|
||||
{
|
||||
return { (AST_Comment*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeConstructor() const
|
||||
{
|
||||
return { (AST_Constructor*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeClass() const
|
||||
{
|
||||
return { (AST_Class*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeDefine() const
|
||||
{
|
||||
return { (AST_Define*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeDefineParams() const
|
||||
{
|
||||
return { (AST_DefineParams*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeDestructor() const
|
||||
{
|
||||
return { (AST_Destructor*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeEnum() const
|
||||
{
|
||||
return { (AST_Enum*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeExec() const
|
||||
{
|
||||
return { (AST_Exec*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeExtern() const
|
||||
{
|
||||
return { (AST_Extern*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeFriend() const
|
||||
{
|
||||
return { (AST_Friend*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeFn() const
|
||||
{
|
||||
return { (AST_Fn*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeInclude() const
|
||||
{
|
||||
return { (AST_Include*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeModule() const
|
||||
{
|
||||
return { (AST_Module*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeNS() const
|
||||
{
|
||||
return { (AST_NS*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeOperator() const
|
||||
{
|
||||
return { (AST_Operator*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeOpCast() const
|
||||
{
|
||||
return { (AST_OpCast*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeParams() const
|
||||
{
|
||||
return { (AST_Params*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodePragma() const
|
||||
{
|
||||
return { (AST_Pragma*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodePreprocessCond() const
|
||||
{
|
||||
return { (AST_PreprocessCond*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeSpecifiers() const
|
||||
{
|
||||
return { (AST_Specifiers*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeStruct() const
|
||||
{
|
||||
return { (AST_Struct*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeTemplate() const
|
||||
{
|
||||
return { (AST_Template*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeTypename() const
|
||||
{
|
||||
return { (AST_Typename*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeTypedef() const
|
||||
{
|
||||
return { (AST_Typedef*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeUnion() const
|
||||
{
|
||||
return { (AST_Union*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeUsing() const
|
||||
{
|
||||
return { (AST_Using*)ast };
|
||||
}
|
||||
|
||||
forceinline Code::operator CodeVar() const
|
||||
{
|
||||
return { (AST_Var*)ast };
|
||||
}
|
||||
|
||||
GEN_OPITMIZE_MAPPINGS_END
|
||||
#pragma endregion generated AST / Code cast implementation
|
||||
@@ -0,0 +1,222 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "components/types.hpp"
|
||||
#endif
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
enum CodeType : u32
|
||||
{
|
||||
CT_Invalid,
|
||||
CT_Untyped,
|
||||
CT_NewLine,
|
||||
CT_Comment,
|
||||
CT_Access_Private,
|
||||
CT_Access_Protected,
|
||||
CT_Access_Public,
|
||||
CT_PlatformAttributes,
|
||||
CT_Class,
|
||||
CT_Class_Fwd,
|
||||
CT_Class_Body,
|
||||
CT_Constructor,
|
||||
CT_Constructor_Fwd,
|
||||
CT_Destructor,
|
||||
CT_Destructor_Fwd,
|
||||
CT_Enum,
|
||||
CT_Enum_Fwd,
|
||||
CT_Enum_Body,
|
||||
CT_Enum_Class,
|
||||
CT_Enum_Class_Fwd,
|
||||
CT_Execution,
|
||||
CT_Export_Body,
|
||||
CT_Extern_Linkage,
|
||||
CT_Extern_Linkage_Body,
|
||||
CT_Friend,
|
||||
CT_Function,
|
||||
CT_Function_Fwd,
|
||||
CT_Function_Body,
|
||||
CT_Global_Body,
|
||||
CT_Module,
|
||||
CT_Namespace,
|
||||
CT_Namespace_Body,
|
||||
CT_Operator,
|
||||
CT_Operator_Fwd,
|
||||
CT_Operator_Member,
|
||||
CT_Operator_Member_Fwd,
|
||||
CT_Operator_Cast,
|
||||
CT_Operator_Cast_Fwd,
|
||||
CT_Parameters,
|
||||
CT_Parameters_Define,
|
||||
CT_Preprocess_Define,
|
||||
CT_Preprocess_Include,
|
||||
CT_Preprocess_If,
|
||||
CT_Preprocess_IfDef,
|
||||
CT_Preprocess_IfNotDef,
|
||||
CT_Preprocess_ElIf,
|
||||
CT_Preprocess_Else,
|
||||
CT_Preprocess_EndIf,
|
||||
CT_Preprocess_Pragma,
|
||||
CT_Specifiers,
|
||||
CT_Struct,
|
||||
CT_Struct_Fwd,
|
||||
CT_Struct_Body,
|
||||
CT_Template,
|
||||
CT_Typedef,
|
||||
CT_Typename,
|
||||
CT_Union,
|
||||
CT_Union_Fwd,
|
||||
CT_Union_Body,
|
||||
CT_Using,
|
||||
CT_Using_Namespace,
|
||||
CT_Variable,
|
||||
CT_NumTypes,
|
||||
CT_UnderlyingType = GEN_U32_MAX
|
||||
};
|
||||
|
||||
inline Str codetype_to_str(CodeType type)
|
||||
{
|
||||
local_persist Str lookup[] = {
|
||||
{ "Invalid", sizeof("Invalid") - 1 },
|
||||
{ "Untyped", sizeof("Untyped") - 1 },
|
||||
{ "NewLine", sizeof("NewLine") - 1 },
|
||||
{ "Comment", sizeof("Comment") - 1 },
|
||||
{ "Access_Private", sizeof("Access_Private") - 1 },
|
||||
{ "Access_Protected", sizeof("Access_Protected") - 1 },
|
||||
{ "Access_Public", sizeof("Access_Public") - 1 },
|
||||
{ "PlatformAttributes", sizeof("PlatformAttributes") - 1 },
|
||||
{ "Class", sizeof("Class") - 1 },
|
||||
{ "Class_Fwd", sizeof("Class_Fwd") - 1 },
|
||||
{ "Class_Body", sizeof("Class_Body") - 1 },
|
||||
{ "Constructor", sizeof("Constructor") - 1 },
|
||||
{ "Constructor_Fwd", sizeof("Constructor_Fwd") - 1 },
|
||||
{ "Destructor", sizeof("Destructor") - 1 },
|
||||
{ "Destructor_Fwd", sizeof("Destructor_Fwd") - 1 },
|
||||
{ "Enum", sizeof("Enum") - 1 },
|
||||
{ "Enum_Fwd", sizeof("Enum_Fwd") - 1 },
|
||||
{ "Enum_Body", sizeof("Enum_Body") - 1 },
|
||||
{ "Enum_Class", sizeof("Enum_Class") - 1 },
|
||||
{ "Enum_Class_Fwd", sizeof("Enum_Class_Fwd") - 1 },
|
||||
{ "Execution", sizeof("Execution") - 1 },
|
||||
{ "Export_Body", sizeof("Export_Body") - 1 },
|
||||
{ "Extern_Linkage", sizeof("Extern_Linkage") - 1 },
|
||||
{ "Extern_Linkage_Body", sizeof("Extern_Linkage_Body") - 1 },
|
||||
{ "Friend", sizeof("Friend") - 1 },
|
||||
{ "Function", sizeof("Function") - 1 },
|
||||
{ "Function_Fwd", sizeof("Function_Fwd") - 1 },
|
||||
{ "Function_Body", sizeof("Function_Body") - 1 },
|
||||
{ "Global_Body", sizeof("Global_Body") - 1 },
|
||||
{ "Module", sizeof("Module") - 1 },
|
||||
{ "Namespace", sizeof("Namespace") - 1 },
|
||||
{ "Namespace_Body", sizeof("Namespace_Body") - 1 },
|
||||
{ "Operator", sizeof("Operator") - 1 },
|
||||
{ "Operator_Fwd", sizeof("Operator_Fwd") - 1 },
|
||||
{ "Operator_Member", sizeof("Operator_Member") - 1 },
|
||||
{ "Operator_Member_Fwd", sizeof("Operator_Member_Fwd") - 1 },
|
||||
{ "Operator_Cast", sizeof("Operator_Cast") - 1 },
|
||||
{ "Operator_Cast_Fwd", sizeof("Operator_Cast_Fwd") - 1 },
|
||||
{ "Parameters", sizeof("Parameters") - 1 },
|
||||
{ "Parameters_Define", sizeof("Parameters_Define") - 1 },
|
||||
{ "Preprocess_Define", sizeof("Preprocess_Define") - 1 },
|
||||
{ "Preprocess_Include", sizeof("Preprocess_Include") - 1 },
|
||||
{ "Preprocess_If", sizeof("Preprocess_If") - 1 },
|
||||
{ "Preprocess_IfDef", sizeof("Preprocess_IfDef") - 1 },
|
||||
{ "Preprocess_IfNotDef", sizeof("Preprocess_IfNotDef") - 1 },
|
||||
{ "Preprocess_ElIf", sizeof("Preprocess_ElIf") - 1 },
|
||||
{ "Preprocess_Else", sizeof("Preprocess_Else") - 1 },
|
||||
{ "Preprocess_EndIf", sizeof("Preprocess_EndIf") - 1 },
|
||||
{ "Preprocess_Pragma", sizeof("Preprocess_Pragma") - 1 },
|
||||
{ "Specifiers", sizeof("Specifiers") - 1 },
|
||||
{ "Struct", sizeof("Struct") - 1 },
|
||||
{ "Struct_Fwd", sizeof("Struct_Fwd") - 1 },
|
||||
{ "Struct_Body", sizeof("Struct_Body") - 1 },
|
||||
{ "Template", sizeof("Template") - 1 },
|
||||
{ "Typedef", sizeof("Typedef") - 1 },
|
||||
{ "Typename", sizeof("Typename") - 1 },
|
||||
{ "Union", sizeof("Union") - 1 },
|
||||
{ "Union_Fwd", sizeof("Union_Fwd") - 1 },
|
||||
{ "Union_Body", sizeof("Union_Body") - 1 },
|
||||
{ "Using", sizeof("Using") - 1 },
|
||||
{ "Using_Namespace", sizeof("Using_Namespace") - 1 },
|
||||
{ "Variable", sizeof("Variable") - 1 },
|
||||
};
|
||||
return lookup[type];
|
||||
}
|
||||
|
||||
inline Str codetype_to_keyword_str(CodeType type)
|
||||
{
|
||||
local_persist Str lookup[] = {
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "//", sizeof("//") - 1 },
|
||||
{ "private", sizeof("private") - 1 },
|
||||
{ "protected", sizeof("protected") - 1 },
|
||||
{ "public", sizeof("public") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "class", sizeof("class") - 1 },
|
||||
{ "clsss", sizeof("clsss") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "enum", sizeof("enum") - 1 },
|
||||
{ "enum", sizeof("enum") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "enum class", sizeof("enum class") - 1 },
|
||||
{ "enum class", sizeof("enum class") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "extern", sizeof("extern") - 1 },
|
||||
{ "extern", sizeof("extern") - 1 },
|
||||
{ "friend", sizeof("friend") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "module", sizeof("module") - 1 },
|
||||
{ "namespace", sizeof("namespace") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "operator", sizeof("operator") - 1 },
|
||||
{ "operator", sizeof("operator") - 1 },
|
||||
{ "operator", sizeof("operator") - 1 },
|
||||
{ "operator", sizeof("operator") - 1 },
|
||||
{ "operator", sizeof("operator") - 1 },
|
||||
{ "operator", sizeof("operator") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "define", sizeof("define") - 1 },
|
||||
{ "include", sizeof("include") - 1 },
|
||||
{ "if", sizeof("if") - 1 },
|
||||
{ "ifdef", sizeof("ifdef") - 1 },
|
||||
{ "ifndef", sizeof("ifndef") - 1 },
|
||||
{ "elif", sizeof("elif") - 1 },
|
||||
{ "else", sizeof("else") - 1 },
|
||||
{ "endif", sizeof("endif") - 1 },
|
||||
{ "pragma", sizeof("pragma") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "struct", sizeof("struct") - 1 },
|
||||
{ "struct", sizeof("struct") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "template", sizeof("template") - 1 },
|
||||
{ "typedef", sizeof("typedef") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "union", sizeof("union") - 1 },
|
||||
{ "union", sizeof("union") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
{ "using", sizeof("using") - 1 },
|
||||
{ "using namespace", sizeof("using namespace") - 1 },
|
||||
{ "__NA__", sizeof("__NA__") - 1 },
|
||||
};
|
||||
return lookup[type];
|
||||
}
|
||||
|
||||
forceinline Str to_str(CodeType type)
|
||||
{
|
||||
return codetype_to_str(type);
|
||||
}
|
||||
|
||||
forceinline Str to_keyword_str(CodeType type)
|
||||
{
|
||||
return codetype_to_keyword_str(type);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "components/types.hpp"
|
||||
#endif
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
enum Operator : u32
|
||||
{
|
||||
Op_Invalid,
|
||||
Op_Assign,
|
||||
Op_Assign_Add,
|
||||
Op_Assign_Subtract,
|
||||
Op_Assign_Multiply,
|
||||
Op_Assign_Divide,
|
||||
Op_Assign_Modulo,
|
||||
Op_Assign_BAnd,
|
||||
Op_Assign_BOr,
|
||||
Op_Assign_BXOr,
|
||||
Op_Assign_LShift,
|
||||
Op_Assign_RShift,
|
||||
Op_Increment,
|
||||
Op_Decrement,
|
||||
Op_Unary_Plus,
|
||||
Op_Unary_Minus,
|
||||
Op_UnaryNot,
|
||||
Op_Add,
|
||||
Op_Subtract,
|
||||
Op_Multiply,
|
||||
Op_Divide,
|
||||
Op_Modulo,
|
||||
Op_BNot,
|
||||
Op_BAnd,
|
||||
Op_BOr,
|
||||
Op_BXOr,
|
||||
Op_LShift,
|
||||
Op_RShift,
|
||||
Op_LAnd,
|
||||
Op_LOr,
|
||||
Op_LEqual,
|
||||
Op_LNot,
|
||||
Op_Lesser,
|
||||
Op_Greater,
|
||||
Op_LesserEqual,
|
||||
Op_GreaterEqual,
|
||||
Op_Subscript,
|
||||
Op_Indirection,
|
||||
Op_AddressOf,
|
||||
Op_MemberOfPointer,
|
||||
Op_PtrToMemOfPtr,
|
||||
Op_FunctionCall,
|
||||
Op_Comma,
|
||||
Op_New,
|
||||
Op_NewArray,
|
||||
Op_Delete,
|
||||
Op_DeleteArray,
|
||||
Op_NumOps,
|
||||
Op_UnderlyingType = 0xffffffffu
|
||||
};
|
||||
|
||||
inline Str operator_to_str(Operator op)
|
||||
{
|
||||
local_persist Str lookup[] = {
|
||||
{ "INVALID", sizeof("INVALID") - 1 },
|
||||
{ "=", sizeof("=") - 1 },
|
||||
{ "+=", sizeof("+=") - 1 },
|
||||
{ "-=", sizeof("-=") - 1 },
|
||||
{ "*=", sizeof("*=") - 1 },
|
||||
{ "/=", sizeof("/=") - 1 },
|
||||
{ "%=", sizeof("%=") - 1 },
|
||||
{ "&=", sizeof("&=") - 1 },
|
||||
{ "|=", sizeof("|=") - 1 },
|
||||
{ "^=", sizeof("^=") - 1 },
|
||||
{ "<<=", sizeof("<<=") - 1 },
|
||||
{ ">>=", sizeof(">>=") - 1 },
|
||||
{ "++", sizeof("++") - 1 },
|
||||
{ "--", sizeof("--") - 1 },
|
||||
{ "+", sizeof("+") - 1 },
|
||||
{ "-", sizeof("-") - 1 },
|
||||
{ "!", sizeof("!") - 1 },
|
||||
{ "+", sizeof("+") - 1 },
|
||||
{ "-", sizeof("-") - 1 },
|
||||
{ "*", sizeof("*") - 1 },
|
||||
{ "/", sizeof("/") - 1 },
|
||||
{ "%", sizeof("%") - 1 },
|
||||
{ "~", sizeof("~") - 1 },
|
||||
{ "&", sizeof("&") - 1 },
|
||||
{ "|", sizeof("|") - 1 },
|
||||
{ "^", sizeof("^") - 1 },
|
||||
{ "<<", sizeof("<<") - 1 },
|
||||
{ ">>", sizeof(">>") - 1 },
|
||||
{ "&&", sizeof("&&") - 1 },
|
||||
{ "||", sizeof("||") - 1 },
|
||||
{ "==", sizeof("==") - 1 },
|
||||
{ "!=", sizeof("!=") - 1 },
|
||||
{ "<", sizeof("<") - 1 },
|
||||
{ ">", sizeof(">") - 1 },
|
||||
{ "<=", sizeof("<=") - 1 },
|
||||
{ ">=", sizeof(">=") - 1 },
|
||||
{ "[]", sizeof("[]") - 1 },
|
||||
{ "*", sizeof("*") - 1 },
|
||||
{ "&", sizeof("&") - 1 },
|
||||
{ "->", sizeof("->") - 1 },
|
||||
{ "->*", sizeof("->*") - 1 },
|
||||
{ "()", sizeof("()") - 1 },
|
||||
{ ",", sizeof(",") - 1 },
|
||||
{ "new", sizeof("new") - 1 },
|
||||
{ "new[]", sizeof("new[]") - 1 },
|
||||
{ "delete", sizeof("delete") - 1 },
|
||||
{ "delete[]", sizeof("delete[]") - 1 },
|
||||
};
|
||||
return lookup[op];
|
||||
}
|
||||
|
||||
forceinline Str to_str(Operator op)
|
||||
{
|
||||
return operator_to_str(op);
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "components/types.hpp"
|
||||
#endif
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
enum Specifier : u32
|
||||
{
|
||||
Spec_Invalid,
|
||||
Spec_Consteval,
|
||||
Spec_Constexpr,
|
||||
Spec_Constinit,
|
||||
Spec_Explicit,
|
||||
Spec_External_Linkage,
|
||||
Spec_ForceInline,
|
||||
Spec_Global,
|
||||
Spec_Inline,
|
||||
Spec_Internal_Linkage,
|
||||
Spec_Local_Persist,
|
||||
Spec_Mutable,
|
||||
Spec_NeverInline,
|
||||
Spec_Ptr,
|
||||
Spec_Ref,
|
||||
Spec_Register,
|
||||
Spec_Restrict,
|
||||
Spec_RValue,
|
||||
Spec_Static,
|
||||
Spec_Thread_Local,
|
||||
Spec_Virtual,
|
||||
Spec_Const,
|
||||
Spec_Final,
|
||||
Spec_NoExceptions,
|
||||
Spec_Override,
|
||||
Spec_Pure,
|
||||
Spec_Delete,
|
||||
Spec_Volatile,
|
||||
Spec_NumSpecifiers,
|
||||
Spec_UnderlyingType = 0xffffffffu
|
||||
};
|
||||
|
||||
inline Str spec_to_str(Specifier type)
|
||||
{
|
||||
local_persist Str lookup[] = {
|
||||
{ "INVALID", sizeof("INVALID") - 1 },
|
||||
{ "consteval", sizeof("consteval") - 1 },
|
||||
{ "constexpr", sizeof("constexpr") - 1 },
|
||||
{ "constinit", sizeof("constinit") - 1 },
|
||||
{ "explicit", sizeof("explicit") - 1 },
|
||||
{ "extern", sizeof("extern") - 1 },
|
||||
{ "forceinline", sizeof("forceinline") - 1 },
|
||||
{ "global", sizeof("global") - 1 },
|
||||
{ "inline", sizeof("inline") - 1 },
|
||||
{ "internal", sizeof("internal") - 1 },
|
||||
{ "local_persist", sizeof("local_persist") - 1 },
|
||||
{ "mutable", sizeof("mutable") - 1 },
|
||||
{ "neverinline", sizeof("neverinline") - 1 },
|
||||
{ "*", sizeof("*") - 1 },
|
||||
{ "&", sizeof("&") - 1 },
|
||||
{ "register", sizeof("register") - 1 },
|
||||
{ "restrict", sizeof("restrict") - 1 },
|
||||
{ "&&", sizeof("&&") - 1 },
|
||||
{ "static", sizeof("static") - 1 },
|
||||
{ "thread_local", sizeof("thread_local") - 1 },
|
||||
{ "virtual", sizeof("virtual") - 1 },
|
||||
{ "const", sizeof("const") - 1 },
|
||||
{ "final", sizeof("final") - 1 },
|
||||
{ "noexcept", sizeof("noexcept") - 1 },
|
||||
{ "override", sizeof("override") - 1 },
|
||||
{ "= 0", sizeof("= 0") - 1 },
|
||||
{ "= delete", sizeof("= delete") - 1 },
|
||||
{ "volatile", sizeof("volatile") - 1 },
|
||||
};
|
||||
return lookup[type];
|
||||
}
|
||||
|
||||
inline bool spec_is_trailing(Specifier specifier)
|
||||
{
|
||||
switch (specifier)
|
||||
{
|
||||
case Spec_Const:
|
||||
case Spec_Final:
|
||||
case Spec_NoExceptions:
|
||||
case Spec_Override:
|
||||
case Spec_Pure:
|
||||
case Spec_Delete:
|
||||
case Spec_Volatile:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline Specifier str_to_specifier(Str str)
|
||||
{
|
||||
local_persist u32 keymap[Spec_NumSpecifiers];
|
||||
do_once_start for (u32 index = 0; index < Spec_NumSpecifiers; index++)
|
||||
{
|
||||
Str enum_str = spec_to_str((Specifier)index);
|
||||
keymap[index] = crc32(enum_str.Ptr, enum_str.Len);
|
||||
}
|
||||
do_once_end u32 hash = crc32(str.Ptr, str.Len);
|
||||
for (u32 index = 0; index < Spec_NumSpecifiers; index++)
|
||||
{
|
||||
if (keymap[index] == hash)
|
||||
return (Specifier)index;
|
||||
}
|
||||
return Spec_Invalid;
|
||||
}
|
||||
|
||||
forceinline Str to_str(Specifier spec)
|
||||
{
|
||||
return spec_to_str(spec);
|
||||
}
|
||||
|
||||
forceinline Specifier to_type(Str str)
|
||||
{
|
||||
return str_to_specifier(str);
|
||||
}
|
||||
|
||||
forceinline bool is_trailing(Specifier specifier)
|
||||
{
|
||||
return spec_is_trailing(specifier);
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "components/types.hpp"
|
||||
#endif
|
||||
|
||||
// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp)
|
||||
|
||||
#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry(Tok_Attribute_GEN_API, "GEN_API")
|
||||
|
||||
enum TokType : u32
|
||||
{
|
||||
Tok_Invalid,
|
||||
Tok_Access_Private,
|
||||
Tok_Access_Protected,
|
||||
Tok_Access_Public,
|
||||
Tok_Access_MemberSymbol,
|
||||
Tok_Access_StaticSymbol,
|
||||
Tok_Ampersand,
|
||||
Tok_Ampersand_DBL,
|
||||
Tok_Assign_Classifer,
|
||||
Tok_Attribute_Open,
|
||||
Tok_Attribute_Close,
|
||||
Tok_BraceCurly_Open,
|
||||
Tok_BraceCurly_Close,
|
||||
Tok_BraceSquare_Open,
|
||||
Tok_BraceSquare_Close,
|
||||
Tok_Paren_Open,
|
||||
Tok_Paren_Close,
|
||||
Tok_Comment,
|
||||
Tok_Comment_End,
|
||||
Tok_Comment_Start,
|
||||
Tok_Char,
|
||||
Tok_Comma,
|
||||
Tok_Decl_Class,
|
||||
Tok_Decl_GNU_Attribute,
|
||||
Tok_Decl_MSVC_Attribute,
|
||||
Tok_Decl_Enum,
|
||||
Tok_Decl_Extern_Linkage,
|
||||
Tok_Decl_Friend,
|
||||
Tok_Decl_Module,
|
||||
Tok_Decl_Namespace,
|
||||
Tok_Decl_Operator,
|
||||
Tok_Decl_Struct,
|
||||
Tok_Decl_Template,
|
||||
Tok_Decl_Typedef,
|
||||
Tok_Decl_Using,
|
||||
Tok_Decl_Union,
|
||||
Tok_Identifier,
|
||||
Tok_Module_Import,
|
||||
Tok_Module_Export,
|
||||
Tok_NewLine,
|
||||
Tok_Number,
|
||||
Tok_Operator,
|
||||
Tok_Preprocess_Hash,
|
||||
Tok_Preprocess_Define,
|
||||
Tok_Preprocess_Define_Param,
|
||||
Tok_Preprocess_If,
|
||||
Tok_Preprocess_IfDef,
|
||||
Tok_Preprocess_IfNotDef,
|
||||
Tok_Preprocess_ElIf,
|
||||
Tok_Preprocess_Else,
|
||||
Tok_Preprocess_EndIf,
|
||||
Tok_Preprocess_Include,
|
||||
Tok_Preprocess_Pragma,
|
||||
Tok_Preprocess_Content,
|
||||
Tok_Preprocess_Macro_Expr,
|
||||
Tok_Preprocess_Macro_Stmt,
|
||||
Tok_Preprocess_Macro_Typename,
|
||||
Tok_Preprocess_Unsupported,
|
||||
Tok_Spec_Alignas,
|
||||
Tok_Spec_Const,
|
||||
Tok_Spec_Consteval,
|
||||
Tok_Spec_Constexpr,
|
||||
Tok_Spec_Constinit,
|
||||
Tok_Spec_Explicit,
|
||||
Tok_Spec_Extern,
|
||||
Tok_Spec_Final,
|
||||
Tok_Spec_ForceInline,
|
||||
Tok_Spec_Global,
|
||||
Tok_Spec_Inline,
|
||||
Tok_Spec_Internal_Linkage,
|
||||
Tok_Spec_LocalPersist,
|
||||
Tok_Spec_Mutable,
|
||||
Tok_Spec_NeverInline,
|
||||
Tok_Spec_Override,
|
||||
Tok_Spec_Restrict,
|
||||
Tok_Spec_Static,
|
||||
Tok_Spec_ThreadLocal,
|
||||
Tok_Spec_Volatile,
|
||||
Tok_Spec_Virtual,
|
||||
Tok_Star,
|
||||
Tok_Statement_End,
|
||||
Tok_StaticAssert,
|
||||
Tok_String,
|
||||
Tok_Type_Typename,
|
||||
Tok_Type_Unsigned,
|
||||
Tok_Type_Signed,
|
||||
Tok_Type_Short,
|
||||
Tok_Type_Long,
|
||||
Tok_Type_bool,
|
||||
Tok_Type_char,
|
||||
Tok_Type_int,
|
||||
Tok_Type_double,
|
||||
Tok_Type_MS_int8,
|
||||
Tok_Type_MS_int16,
|
||||
Tok_Type_MS_int32,
|
||||
Tok_Type_MS_int64,
|
||||
Tok_Type_MS_W64,
|
||||
Tok_Varadic_Argument,
|
||||
Tok___Attributes_Start,
|
||||
Tok_Attribute_GEN_API,
|
||||
Tok_NumTokens
|
||||
};
|
||||
|
||||
inline Str toktype_to_str(TokType type)
|
||||
{
|
||||
local_persist Str lookup[] = {
|
||||
{ "__invalid__", sizeof("__invalid__") - 1 },
|
||||
{ "private", sizeof("private") - 1 },
|
||||
{ "protected", sizeof("protected") - 1 },
|
||||
{ "public", sizeof("public") - 1 },
|
||||
{ ".", sizeof(".") - 1 },
|
||||
{ "::", sizeof("::") - 1 },
|
||||
{ "&", sizeof("&") - 1 },
|
||||
{ "&&", sizeof("&&") - 1 },
|
||||
{ ":", sizeof(":") - 1 },
|
||||
{ "[[", sizeof("[[") - 1 },
|
||||
{ "]]", sizeof("]]") - 1 },
|
||||
{ "{", sizeof("{") - 1 },
|
||||
{ "}", sizeof("}") - 1 },
|
||||
{ "[", sizeof("[") - 1 },
|
||||
{ "]", sizeof("]") - 1 },
|
||||
{ "(", sizeof("(") - 1 },
|
||||
{ ")", sizeof(")") - 1 },
|
||||
{ "__comment__", sizeof("__comment__") - 1 },
|
||||
{ "__comment_end__", sizeof("__comment_end__") - 1 },
|
||||
{ "__comment_start__", sizeof("__comment_start__") - 1 },
|
||||
{ "__character__", sizeof("__character__") - 1 },
|
||||
{ ",", sizeof(",") - 1 },
|
||||
{ "class", sizeof("class") - 1 },
|
||||
{ "__attribute__", sizeof("__attribute__") - 1 },
|
||||
{ "__declspec", sizeof("__declspec") - 1 },
|
||||
{ "enum", sizeof("enum") - 1 },
|
||||
{ "extern", sizeof("extern") - 1 },
|
||||
{ "friend", sizeof("friend") - 1 },
|
||||
{ "module", sizeof("module") - 1 },
|
||||
{ "namespace", sizeof("namespace") - 1 },
|
||||
{ "operator", sizeof("operator") - 1 },
|
||||
{ "struct", sizeof("struct") - 1 },
|
||||
{ "template", sizeof("template") - 1 },
|
||||
{ "typedef", sizeof("typedef") - 1 },
|
||||
{ "using", sizeof("using") - 1 },
|
||||
{ "union", sizeof("union") - 1 },
|
||||
{ "__identifier__", sizeof("__identifier__") - 1 },
|
||||
{ "import", sizeof("import") - 1 },
|
||||
{ "export", sizeof("export") - 1 },
|
||||
{ "__new_line__", sizeof("__new_line__") - 1 },
|
||||
{ "__number__", sizeof("__number__") - 1 },
|
||||
{ "__operator__", sizeof("__operator__") - 1 },
|
||||
{ "#", sizeof("#") - 1 },
|
||||
{ "define", sizeof("define") - 1 },
|
||||
{ "__define_param__", sizeof("__define_param__") - 1 },
|
||||
{ "if", sizeof("if") - 1 },
|
||||
{ "ifdef", sizeof("ifdef") - 1 },
|
||||
{ "ifndef", sizeof("ifndef") - 1 },
|
||||
{ "elif", sizeof("elif") - 1 },
|
||||
{ "else", sizeof("else") - 1 },
|
||||
{ "endif", sizeof("endif") - 1 },
|
||||
{ "include", sizeof("include") - 1 },
|
||||
{ "pragma", sizeof("pragma") - 1 },
|
||||
{ "__macro_content__", sizeof("__macro_content__") - 1 },
|
||||
{ "__macro_expression__", sizeof("__macro_expression__") - 1 },
|
||||
{ "__macro_statment__", sizeof("__macro_statment__") - 1 },
|
||||
{ "__macro_typename__", sizeof("__macro_typename__") - 1 },
|
||||
{ "__unsupported__", sizeof("__unsupported__") - 1 },
|
||||
{ "alignas", sizeof("alignas") - 1 },
|
||||
{ "const", sizeof("const") - 1 },
|
||||
{ "consteval", sizeof("consteval") - 1 },
|
||||
{ "constexpr", sizeof("constexpr") - 1 },
|
||||
{ "constinit", sizeof("constinit") - 1 },
|
||||
{ "explicit", sizeof("explicit") - 1 },
|
||||
{ "extern", sizeof("extern") - 1 },
|
||||
{ "final", sizeof("final") - 1 },
|
||||
{ "forceinline", sizeof("forceinline") - 1 },
|
||||
{ "global", sizeof("global") - 1 },
|
||||
{ "inline", sizeof("inline") - 1 },
|
||||
{ "internal", sizeof("internal") - 1 },
|
||||
{ "local_persist", sizeof("local_persist") - 1 },
|
||||
{ "mutable", sizeof("mutable") - 1 },
|
||||
{ "neverinline", sizeof("neverinline") - 1 },
|
||||
{ "override", sizeof("override") - 1 },
|
||||
{ "restrict", sizeof("restrict") - 1 },
|
||||
{ "static", sizeof("static") - 1 },
|
||||
{ "thread_local", sizeof("thread_local") - 1 },
|
||||
{ "volatile", sizeof("volatile") - 1 },
|
||||
{ "virtual", sizeof("virtual") - 1 },
|
||||
{ "*", sizeof("*") - 1 },
|
||||
{ ";", sizeof(";") - 1 },
|
||||
{ "static_assert", sizeof("static_assert") - 1 },
|
||||
{ "__string__", sizeof("__string__") - 1 },
|
||||
{ "typename", sizeof("typename") - 1 },
|
||||
{ "unsigned", sizeof("unsigned") - 1 },
|
||||
{ "signed", sizeof("signed") - 1 },
|
||||
{ "short", sizeof("short") - 1 },
|
||||
{ "long", sizeof("long") - 1 },
|
||||
{ "bool", sizeof("bool") - 1 },
|
||||
{ "char", sizeof("char") - 1 },
|
||||
{ "int", sizeof("int") - 1 },
|
||||
{ "double", sizeof("double") - 1 },
|
||||
{ "__int8", sizeof("__int8") - 1 },
|
||||
{ "__int16", sizeof("__int16") - 1 },
|
||||
{ "__int32", sizeof("__int32") - 1 },
|
||||
{ "__int64", sizeof("__int64") - 1 },
|
||||
{ "_W64", sizeof("_W64") - 1 },
|
||||
{ "...", sizeof("...") - 1 },
|
||||
{ "__attrib_start__", sizeof("__attrib_start__") - 1 },
|
||||
{ "GEN_API", sizeof("GEN_API") - 1 },
|
||||
};
|
||||
return lookup[type];
|
||||
}
|
||||
|
||||
inline TokType str_to_toktype(Str str)
|
||||
{
|
||||
local_persist u32 keymap[Tok_NumTokens];
|
||||
do_once_start for (u32 index = 0; index < Tok_NumTokens; index++)
|
||||
{
|
||||
Str enum_str = toktype_to_str((TokType)index);
|
||||
keymap[index] = crc32(enum_str.Ptr, enum_str.Len);
|
||||
}
|
||||
do_once_end u32 hash = crc32(str.Ptr, str.Len);
|
||||
for (u32 index = 0; index < Tok_NumTokens; index++)
|
||||
{
|
||||
if (keymap[index] == hash)
|
||||
return (TokType)index;
|
||||
}
|
||||
return Tok_Invalid;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "inlines.hpp"
|
||||
#include "gen/ast_inlines.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Constants
|
||||
|
||||
GEN_API extern Macro enum_underlying_macro;
|
||||
|
||||
GEN_API extern Code access_public;
|
||||
GEN_API extern Code access_protected;
|
||||
GEN_API extern Code access_private;
|
||||
|
||||
GEN_API extern CodeAttributes attrib_api_export;
|
||||
GEN_API extern CodeAttributes attrib_api_import;
|
||||
|
||||
GEN_API extern Code module_global_fragment;
|
||||
GEN_API extern Code module_private_fragment;
|
||||
|
||||
GEN_API extern Code fmt_newline;
|
||||
|
||||
GEN_API extern CodePragma pragma_once;
|
||||
|
||||
GEN_API extern CodeParams param_varadic;
|
||||
|
||||
GEN_API extern CodePreprocessCond preprocess_else;
|
||||
GEN_API extern CodePreprocessCond preprocess_endif;
|
||||
|
||||
GEN_API extern CodeSpecifiers spec_const;
|
||||
GEN_API extern CodeSpecifiers spec_consteval;
|
||||
GEN_API extern CodeSpecifiers spec_constexpr;
|
||||
GEN_API extern CodeSpecifiers spec_constinit;
|
||||
GEN_API extern CodeSpecifiers spec_extern_linkage;
|
||||
GEN_API extern CodeSpecifiers spec_final;
|
||||
GEN_API extern CodeSpecifiers spec_forceinline;
|
||||
GEN_API extern CodeSpecifiers spec_global;
|
||||
GEN_API extern CodeSpecifiers spec_inline;
|
||||
GEN_API extern CodeSpecifiers spec_internal_linkage;
|
||||
GEN_API extern CodeSpecifiers spec_local_persist;
|
||||
GEN_API extern CodeSpecifiers spec_mutable;
|
||||
GEN_API extern CodeSpecifiers spec_neverinline;
|
||||
GEN_API extern CodeSpecifiers spec_noexcept;
|
||||
GEN_API extern CodeSpecifiers spec_override;
|
||||
GEN_API extern CodeSpecifiers spec_ptr;
|
||||
GEN_API extern CodeSpecifiers spec_pure;
|
||||
GEN_API extern CodeSpecifiers spec_ref;
|
||||
GEN_API extern CodeSpecifiers spec_register;
|
||||
GEN_API extern CodeSpecifiers spec_rvalue;
|
||||
GEN_API extern CodeSpecifiers spec_static_member;
|
||||
GEN_API extern CodeSpecifiers spec_thread_local;
|
||||
GEN_API extern CodeSpecifiers spec_virtual;
|
||||
GEN_API extern CodeSpecifiers spec_volatile;
|
||||
|
||||
GEN_API extern CodeTypename t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance)
|
||||
GEN_API extern CodeTypename t_auto;
|
||||
GEN_API extern CodeTypename t_void;
|
||||
GEN_API extern CodeTypename t_int;
|
||||
GEN_API extern CodeTypename t_bool;
|
||||
GEN_API extern CodeTypename t_char;
|
||||
GEN_API extern CodeTypename t_wchar_t;
|
||||
GEN_API extern CodeTypename t_class;
|
||||
GEN_API extern CodeTypename t_typename;
|
||||
|
||||
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
// Predefined typename codes. Are set to readonly and are setup during gen::init()
|
||||
GEN_API extern Context* _ctx;
|
||||
|
||||
GEN_API extern CodeTypename t_b32;
|
||||
|
||||
GEN_API extern CodeTypename t_s8;
|
||||
GEN_API extern CodeTypename t_s16;
|
||||
GEN_API extern CodeTypename t_s32;
|
||||
GEN_API extern CodeTypename t_s64;
|
||||
|
||||
GEN_API extern CodeTypename t_u8;
|
||||
GEN_API extern CodeTypename t_u16;
|
||||
GEN_API extern CodeTypename t_u32;
|
||||
GEN_API extern CodeTypename t_u64;
|
||||
|
||||
GEN_API extern CodeTypename t_ssize;
|
||||
GEN_API extern CodeTypename t_usize;
|
||||
|
||||
GEN_API extern CodeTypename t_f32;
|
||||
GEN_API extern CodeTypename t_f64;
|
||||
#endif
|
||||
|
||||
#pragma endregion Constants
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
gencpp: An attempt at "simple" staged metaprogramming for c/c++.
|
||||
|
||||
See Readme.md for more information from the project repository.
|
||||
|
||||
Public Address:
|
||||
https://github.com/Ed94/gencpp --------------------------------------------------------------.
|
||||
| _____ _____ _ _ |
|
||||
| / ____) / ____} | | | |
|
||||
| | / ___ ___ _ __ ___ _ __ _ __ | {___ | |__ _ _, __ _, ___ __| | |
|
||||
| | |{_ |/ _ \ '_ \ / __} '_ l| '_ l `\___ \| __/ _` |/ _` |/ _ \/ _` | |
|
||||
| | l__j | ___/ | | | {__; |+l } |+l | ____) | l| (_| | {_| | ___/ (_| | |
|
||||
| \_____|\___}_l |_|\___} ,__/| ,__/ (_____/ \__\__/_|\__, |\___}\__,_l |
|
||||
| | | | | __} | |
|
||||
| l_l l_l {___/ |
|
||||
! ----------------------------------------------------------------------- VERSION: v0.23-Alpha |
|
||||
! ============================================================================================ |
|
||||
! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION |
|
||||
! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL |
|
||||
! ============================================================================================ /
|
||||
*/
|
||||
#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME)
|
||||
# error Gen.hpp : GEN_TIME not defined
|
||||
#endif
|
||||
|
||||
//! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file.
|
||||
// Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl
|
||||
#ifndef GEN_ROLL_OWN_DEPENDENCIES
|
||||
# include "gen.dep.hpp"
|
||||
#endif
|
||||
@@ -0,0 +1,433 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "interface.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Code
|
||||
inline
|
||||
void code_append( Code self, Code other )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(other);
|
||||
GEN_ASSERT_MSG(self != other, "Attempted to recursively append Code AST to itself.");
|
||||
|
||||
if ( other->Parent != nullptr )
|
||||
other = code_duplicate(other);
|
||||
|
||||
other->Parent = self;
|
||||
|
||||
if ( self->Front == nullptr )
|
||||
{
|
||||
self->Front = other;
|
||||
self->Back = other;
|
||||
|
||||
self->NumEntries++;
|
||||
return;
|
||||
}
|
||||
|
||||
Code
|
||||
Current = self->Back;
|
||||
Current->Next = other;
|
||||
other->Prev = Current;
|
||||
self->Back = other;
|
||||
self->NumEntries++;
|
||||
}
|
||||
inline
|
||||
bool code_is_body(Code self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
switch (self->Type)
|
||||
{
|
||||
case CT_Enum_Body:
|
||||
case CT_Class_Body:
|
||||
case CT_Union_Body:
|
||||
case CT_Export_Body:
|
||||
case CT_Global_Body:
|
||||
case CT_Struct_Body:
|
||||
case CT_Function_Body:
|
||||
case CT_Namespace_Body:
|
||||
case CT_Extern_Linkage_Body:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
inline
|
||||
Code* code_entry( Code self, u32 idx )
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
Code* current = & self->Front;
|
||||
while ( idx >= 0 && current != nullptr )
|
||||
{
|
||||
if ( idx == 0 )
|
||||
return rcast( Code*, current);
|
||||
|
||||
current = & ( * current )->Next;
|
||||
idx--;
|
||||
}
|
||||
|
||||
return rcast( Code*, current);
|
||||
}
|
||||
forceinline
|
||||
bool code_is_valid(Code self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
return self != nullptr && self->Type != CT_Invalid;
|
||||
}
|
||||
forceinline
|
||||
bool code_has_entries(AST* self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
return self->NumEntries > 0;
|
||||
}
|
||||
forceinline
|
||||
void code_set_global(Code self)
|
||||
{
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("Code::set_global: Cannot set code as global, AST is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
self->Parent = Code_Global;
|
||||
}
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline
|
||||
Code& Code::operator ++()
|
||||
{
|
||||
if ( ast )
|
||||
ast = ast->Next.ast;
|
||||
|
||||
return * this;
|
||||
}
|
||||
#endif
|
||||
forceinline
|
||||
Str code_type_str(Code self)
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
return codetype_to_str( self->Type );
|
||||
}
|
||||
#pragma endregion Code
|
||||
|
||||
#pragma region CodeBody
|
||||
inline
|
||||
void body_append( CodeBody self, Code other )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(other);
|
||||
|
||||
if (code_is_body(other)) {
|
||||
body_append_body( self, cast(CodeBody, other) );
|
||||
return;
|
||||
}
|
||||
|
||||
code_append( cast(Code, self), other );
|
||||
}
|
||||
inline
|
||||
void body_append_body( CodeBody self, CodeBody body )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(body);
|
||||
GEN_ASSERT_MSG(self != body, "Attempted to append body to itself.");
|
||||
|
||||
for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); entry = next_CodeBody(body, entry) ) {
|
||||
body_append( self, entry );
|
||||
}
|
||||
}
|
||||
inline
|
||||
Code begin_CodeBody( CodeBody body) {
|
||||
GEN_ASSERT(body);
|
||||
if ( body != nullptr )
|
||||
return body->Front;
|
||||
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
Code end_CodeBody(CodeBody body ){
|
||||
GEN_ASSERT(body);
|
||||
return body->Back->Next;
|
||||
}
|
||||
inline
|
||||
Code next_CodeBody(CodeBody body, Code entry) {
|
||||
GEN_ASSERT(body);
|
||||
GEN_ASSERT(entry);
|
||||
return entry->Next;
|
||||
}
|
||||
#pragma endregion CodeBody
|
||||
|
||||
#pragma region CodeClass
|
||||
inline
|
||||
void class_add_interface( CodeClass self, CodeTypename type )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
GEN_ASSERT(type);
|
||||
CodeTypename possible_slot = self->ParentType;
|
||||
if ( possible_slot != nullptr )
|
||||
{
|
||||
// Were adding an interface to parent type, so we need to make sure the parent type is public.
|
||||
self->ParentAccess = AccessSpec_Public;
|
||||
// If your planning on adding a proper parent,
|
||||
// then you'll need to move this over to ParentType->next and update ParentAccess accordingly.
|
||||
}
|
||||
|
||||
while ( possible_slot != nullptr )
|
||||
{
|
||||
possible_slot = cast(CodeTypename, possible_slot->Next);
|
||||
}
|
||||
|
||||
possible_slot = type;
|
||||
}
|
||||
#pragma endregion CodeClass
|
||||
|
||||
#pragma region CodeParams
|
||||
inline
|
||||
void params_append( CodeParams appendee, CodeParams other )
|
||||
{
|
||||
GEN_ASSERT(appendee);
|
||||
GEN_ASSERT(other);
|
||||
GEN_ASSERT_MSG(appendee != other, "Attempted to append parameter to itself.");
|
||||
Code self = cast(Code, appendee);
|
||||
Code entry = cast(Code, other);
|
||||
|
||||
if ( entry->Parent != nullptr )
|
||||
entry = code_duplicate( entry );
|
||||
|
||||
entry->Parent = self;
|
||||
|
||||
if ( self->Last == nullptr )
|
||||
{
|
||||
self->Last = entry;
|
||||
self->Next = entry;
|
||||
self->NumEntries++;
|
||||
return;
|
||||
}
|
||||
|
||||
self->Last->Next = entry;
|
||||
self->Last = entry;
|
||||
self->NumEntries++;
|
||||
}
|
||||
inline
|
||||
CodeParams params_get(CodeParams self, s32 idx )
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
CodeParams param = self;
|
||||
do
|
||||
{
|
||||
if ( ++ param != nullptr )
|
||||
return NullCode;
|
||||
|
||||
param = cast(CodeParams, cast(Code, param)->Next);
|
||||
}
|
||||
while ( --idx );
|
||||
|
||||
return param;
|
||||
}
|
||||
forceinline
|
||||
bool params_has_entries(CodeParams self)
|
||||
{
|
||||
GEN_ASSERT(self);
|
||||
return self->NumEntries > 0;
|
||||
}
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline
|
||||
CodeParams& CodeParams::operator ++()
|
||||
{
|
||||
* this = ast->Next;
|
||||
return * this;
|
||||
}
|
||||
#endif
|
||||
forceinline
|
||||
CodeParams begin_CodeParams(CodeParams params)
|
||||
{
|
||||
if ( params != nullptr )
|
||||
return params;
|
||||
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
CodeParams end_CodeParams(CodeParams params)
|
||||
{
|
||||
// return { (AST_Params*) rcast( AST*, ast)->Last };
|
||||
return NullCode;
|
||||
}
|
||||
forceinline
|
||||
CodeParams next_CodeParams(CodeParams params, CodeParams param_iter)
|
||||
{
|
||||
GEN_ASSERT(param_iter);
|
||||
return param_iter->Next;
|
||||
}
|
||||
#pragma endregion CodeParams
|
||||
|
||||
#pragma region CodeDefineParams
|
||||
forceinline void define_params_append (CodeDefineParams appendee, CodeDefineParams other ) { params_append( cast(CodeParams, appendee), cast(CodeParams, other) ); }
|
||||
forceinline CodeDefineParams define_params_get (CodeDefineParams self, s32 idx ) { return (CodeDefineParams) (Code) params_get( cast(CodeParams, self), idx); }
|
||||
forceinline bool define_params_has_entries(CodeDefineParams self) { return params_has_entries( cast(CodeParams, self)); }
|
||||
|
||||
forceinline CodeDefineParams begin_CodeDefineParams(CodeDefineParams params) { return (CodeDefineParams) (Code) begin_CodeParams( cast(CodeParams, (Code)params)); }
|
||||
forceinline CodeDefineParams end_CodeDefineParams (CodeDefineParams params) { return (CodeDefineParams) (Code) end_CodeParams ( cast(CodeParams, (Code)params)); }
|
||||
forceinline CodeDefineParams next_CodeDefineParams (CodeDefineParams params, CodeDefineParams entry_iter) { return (CodeDefineParams) (Code) next_CodeParams ( cast(CodeParams, (Code)params), cast(CodeParams, (Code)entry_iter)); }
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline
|
||||
CodeDefineParams& CodeDefineParams::operator ++()
|
||||
{
|
||||
* this = ast->Next;
|
||||
return * this;
|
||||
}
|
||||
#endif
|
||||
#pragma endregion CodeDefineParams
|
||||
|
||||
#pragma region CodeSpecifiers
|
||||
inline
|
||||
bool specifiers_append(CodeSpecifiers self, Specifier spec )
|
||||
{
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!");
|
||||
return false;
|
||||
}
|
||||
if ( self->NumEntries == AST_ArrSpecs_Cap )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap );
|
||||
return false;
|
||||
}
|
||||
|
||||
self->ArrSpecs[ self->NumEntries ] = spec;
|
||||
self->NumEntries++;
|
||||
return true;
|
||||
}
|
||||
inline
|
||||
s32 specifiers_has(CodeSpecifiers self, Specifier spec)
|
||||
{
|
||||
GEN_ASSERT(self != nullptr);
|
||||
for ( s32 idx = 0; idx < self->NumEntries; idx++ ) {
|
||||
if ( self->ArrSpecs[ idx ] == spec )
|
||||
return idx;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
inline
|
||||
s32 specifiers_remove( CodeSpecifiers self, Specifier to_remove )
|
||||
{
|
||||
if ( self == nullptr )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!");
|
||||
return -1;
|
||||
}
|
||||
if ( self->NumEntries == AST_ArrSpecs_Cap )
|
||||
{
|
||||
log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap );
|
||||
return -1;
|
||||
}
|
||||
|
||||
s32 result = -1;
|
||||
|
||||
s32 curr = 0;
|
||||
s32 next = 0;
|
||||
for(; next < self->NumEntries; ++ curr, ++ next)
|
||||
{
|
||||
Specifier spec = self->ArrSpecs[next];
|
||||
if (spec == to_remove)
|
||||
{
|
||||
result = next;
|
||||
|
||||
next ++;
|
||||
if (next >= self->NumEntries)
|
||||
break;
|
||||
|
||||
spec = self->ArrSpecs[next];
|
||||
}
|
||||
|
||||
self->ArrSpecs[ curr ] = spec;
|
||||
}
|
||||
|
||||
if (result > -1) {
|
||||
self->NumEntries --;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
forceinline
|
||||
Specifier* begin_CodeSpecifiers(CodeSpecifiers self)
|
||||
{
|
||||
if ( self != nullptr )
|
||||
return & self->ArrSpecs[0];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
forceinline
|
||||
Specifier* end_CodeSpecifiers(CodeSpecifiers self)
|
||||
{
|
||||
return self->ArrSpecs + self->NumEntries;
|
||||
}
|
||||
forceinline
|
||||
Specifier* next_CodeSpecifiers(CodeSpecifiers self, Specifier* spec_iter)
|
||||
{
|
||||
return spec_iter + 1;
|
||||
}
|
||||
#pragma endregion CodeSpecifiers
|
||||
|
||||
#pragma region CodeStruct
|
||||
inline
|
||||
void struct_add_interface(CodeStruct self, CodeTypename type )
|
||||
{
|
||||
CodeTypename possible_slot = self->ParentType;
|
||||
if ( possible_slot != nullptr )
|
||||
{
|
||||
// Were adding an interface to parent type, so we need to make sure the parent type is public.
|
||||
self->ParentAccess = AccessSpec_Public;
|
||||
// If your planning on adding a proper parent,
|
||||
// then you'll need to move this over to ParentType->next and update ParentAccess accordingly.
|
||||
}
|
||||
|
||||
while ( possible_slot != nullptr )
|
||||
{
|
||||
possible_slot = cast(CodeTypename, possible_slot->Next);
|
||||
}
|
||||
|
||||
possible_slot = type;
|
||||
}
|
||||
#pragma endregion Code
|
||||
|
||||
#pragma region Interface
|
||||
inline
|
||||
CodeBody def_body( CodeType type )
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
case CT_Class_Body:
|
||||
case CT_Enum_Body:
|
||||
case CT_Export_Body:
|
||||
case CT_Extern_Linkage:
|
||||
case CT_Function_Body:
|
||||
case CT_Global_Body:
|
||||
case CT_Namespace_Body:
|
||||
case CT_Struct_Body:
|
||||
case CT_Union_Body:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_failure( "def_body: Invalid type %s", codetype_to_str(type).Ptr );
|
||||
return (CodeBody)Code_Invalid;
|
||||
}
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Type = type;
|
||||
return (CodeBody)result;
|
||||
}
|
||||
|
||||
inline
|
||||
Str token_fmt_impl( ssize num, ... )
|
||||
{
|
||||
local_persist thread_local
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
mem_set( buf, 0, GEN_PRINTF_MAXLEN );
|
||||
|
||||
va_list va;
|
||||
va_start(va, num );
|
||||
ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va);
|
||||
va_end(va);
|
||||
|
||||
Str str = { buf, result };
|
||||
return str;
|
||||
}
|
||||
#pragma endregion Interface
|
||||
@@ -0,0 +1,521 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "code_serialization.cpp"
|
||||
#endif
|
||||
|
||||
internal void parser_init();
|
||||
internal void parser_deinit();
|
||||
|
||||
internal
|
||||
void* fallback_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
{
|
||||
GEN_ASSERT(_ctx);
|
||||
GEN_ASSERT(_ctx->Fallback_AllocatorBuckets);
|
||||
Arena* last = array_back(_ctx->Fallback_AllocatorBuckets);
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case EAllocation_ALLOC:
|
||||
{
|
||||
if ( ( last->TotalUsed + size ) > last->TotalSize )
|
||||
{
|
||||
Arena bucket = arena_init_from_allocator( heap(), _ctx->InitSize_Fallback_Allocator_Bucket_Size );
|
||||
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create bucket for Fallback_AllocatorBuckets");
|
||||
|
||||
if ( ! array_append( _ctx->Fallback_AllocatorBuckets, bucket ) )
|
||||
GEN_FATAL( "Failed to append bucket to Fallback_AllocatorBuckets");
|
||||
|
||||
last = array_back(_ctx->Fallback_AllocatorBuckets);
|
||||
}
|
||||
|
||||
return alloc_align( arena_allocator_info(last), size, alignment );
|
||||
}
|
||||
case EAllocation_FREE:
|
||||
{
|
||||
// Doesn't recycle.
|
||||
}
|
||||
break;
|
||||
case EAllocation_FREE_ALL:
|
||||
{
|
||||
// Memory::cleanup instead.
|
||||
}
|
||||
break;
|
||||
case EAllocation_RESIZE:
|
||||
{
|
||||
if ( last->TotalUsed + size > last->TotalSize )
|
||||
{
|
||||
Arena bucket = arena_init_from_allocator( heap(), _ctx->InitSize_Fallback_Allocator_Bucket_Size );
|
||||
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create bucket for Fallback_AllocatorBuckets");
|
||||
|
||||
if ( ! array_append( _ctx->Fallback_AllocatorBuckets, bucket ) )
|
||||
GEN_FATAL( "Failed to append bucket to Fallback_AllocatorBuckets");
|
||||
|
||||
last = array_back( _ctx->Fallback_AllocatorBuckets);
|
||||
}
|
||||
|
||||
void* result = alloc_align( last->Backing, size, alignment );
|
||||
|
||||
if ( result != nullptr && old_memory != nullptr )
|
||||
{
|
||||
mem_copy( result, old_memory, old_size );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
internal
|
||||
void define_constants()
|
||||
{
|
||||
// We only initalize these if there is no base context.
|
||||
if ( context_counter > 0 )
|
||||
return;
|
||||
|
||||
Code_Global = make_code();
|
||||
Code_Global->Name = cache_str( txt("Global Code") );
|
||||
Code_Global->Content = Code_Global->Name;
|
||||
|
||||
Code_Invalid = make_code();
|
||||
code_set_global(Code_Invalid);
|
||||
|
||||
t_empty = (CodeTypename) make_code();
|
||||
t_empty->Type = CT_Typename;
|
||||
t_empty->Name = cache_str( txt("") );
|
||||
code_set_global(cast(Code, t_empty));
|
||||
|
||||
access_private = make_code();
|
||||
access_private->Type = CT_Access_Private;
|
||||
access_private->Name = cache_str( txt("private:\n") );
|
||||
code_set_global(cast(Code, access_private));
|
||||
|
||||
access_protected = make_code();
|
||||
access_protected->Type = CT_Access_Protected;
|
||||
access_protected->Name = cache_str( txt("protected:\n") );
|
||||
code_set_global(access_protected);
|
||||
|
||||
access_public = make_code();
|
||||
access_public->Type = CT_Access_Public;
|
||||
access_public->Name = cache_str( txt("public:\n") );
|
||||
code_set_global(access_public);
|
||||
|
||||
Str api_export_str = code(GEN_API_Export_Code);
|
||||
attrib_api_export = def_attributes( api_export_str );
|
||||
code_set_global(cast(Code, attrib_api_export));
|
||||
|
||||
Str api_import_str = code(GEN_API_Import_Code);
|
||||
attrib_api_import = def_attributes( api_import_str );
|
||||
code_set_global(cast(Code, attrib_api_import));
|
||||
|
||||
module_global_fragment = make_code();
|
||||
module_global_fragment->Type = CT_Untyped;
|
||||
module_global_fragment->Name = cache_str( txt("module;") );
|
||||
module_global_fragment->Content = module_global_fragment->Name;
|
||||
code_set_global(cast(Code, module_global_fragment));
|
||||
|
||||
module_private_fragment = make_code();
|
||||
module_private_fragment->Type = CT_Untyped;
|
||||
module_private_fragment->Name = cache_str( txt("module : private;") );
|
||||
module_private_fragment->Content = module_private_fragment->Name;
|
||||
code_set_global(cast(Code, module_private_fragment));
|
||||
|
||||
fmt_newline = make_code();
|
||||
fmt_newline->Type = CT_NewLine;
|
||||
code_set_global((Code)fmt_newline);
|
||||
|
||||
pragma_once = (CodePragma) make_code();
|
||||
pragma_once->Type = CT_Preprocess_Pragma;
|
||||
pragma_once->Name = cache_str( txt("once") );
|
||||
pragma_once->Content = pragma_once->Name;
|
||||
code_set_global((Code)pragma_once);
|
||||
|
||||
param_varadic = (CodeParams) make_code();
|
||||
param_varadic->Type = CT_Parameters;
|
||||
param_varadic->Name = cache_str( txt("...") );
|
||||
param_varadic->ValueType = t_empty;
|
||||
code_set_global((Code)param_varadic);
|
||||
|
||||
preprocess_else = (CodePreprocessCond) make_code();
|
||||
preprocess_else->Type = CT_Preprocess_Else;
|
||||
code_set_global((Code)preprocess_else);
|
||||
|
||||
preprocess_endif = (CodePreprocessCond) make_code();
|
||||
preprocess_endif->Type = CT_Preprocess_EndIf;
|
||||
code_set_global((Code)preprocess_endif);
|
||||
|
||||
Str auto_str = txt("auto"); t_auto = def_type( auto_str ); code_set_global( t_auto );
|
||||
Str void_str = txt("void"); t_void = def_type( void_str ); code_set_global( t_void );
|
||||
Str int_str = txt("int"); t_int = def_type( int_str ); code_set_global( t_int );
|
||||
Str bool_str = txt("bool"); t_bool = def_type( bool_str ); code_set_global( t_bool );
|
||||
Str char_str = txt("char"); t_char = def_type( char_str ); code_set_global( t_char );
|
||||
Str wchar_str = txt("wchar_t"); t_wchar_t = def_type( wchar_str ); code_set_global( t_wchar_t );
|
||||
Str class_str = txt("class"); t_class = def_type( class_str ); code_set_global( t_class );
|
||||
Str typename_str = txt("typename"); t_typename = def_type( typename_str ); code_set_global( t_typename );
|
||||
|
||||
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
t_b32 = def_type( name(b32) ); code_set_global( t_b32 );
|
||||
|
||||
Str s8_str = txt("s8"); t_s8 = def_type( s8_str ); code_set_global( t_s8 );
|
||||
Str s16_str = txt("s16"); t_s16 = def_type( s16_str ); code_set_global( t_s16 );
|
||||
Str s32_str = txt("s32"); t_s32 = def_type( s32_str ); code_set_global( t_s32 );
|
||||
Str s64_str = txt("s64"); t_s64 = def_type( s64_str ); code_set_global( t_s64 );
|
||||
|
||||
Str u8_str = txt("u8"); t_u8 = def_type( u8_str ); code_set_global( t_u8 );
|
||||
Str u16_str = txt("u16"); t_u16 = def_type( u16_str ); code_set_global( t_u16 );
|
||||
Str u32_str = txt("u32"); t_u32 = def_type( u32_str ); code_set_global( t_u32 );
|
||||
Str u64_str = txt("u64"); t_u64 = def_type( u64_str ); code_set_global( t_u64 );
|
||||
|
||||
Str ssize_str = txt("ssize"); t_ssize = def_type( ssize_str ); code_set_global( t_ssize );
|
||||
Str usize_str = txt("usize"); t_usize = def_type( usize_str ); code_set_global( t_usize );
|
||||
|
||||
Str f32_str = txt("f32"); t_f32 = def_type( f32_str ); code_set_global( t_f32 );
|
||||
Str f64_str = txt("f64"); t_f64 = def_type( f64_str ); code_set_global( t_f64 );
|
||||
#endif
|
||||
|
||||
spec_const = def_specifier( Spec_Const); code_set_global( cast(Code, spec_const ));
|
||||
spec_consteval = def_specifier( Spec_Consteval); code_set_global( cast(Code, spec_consteval ));
|
||||
spec_constexpr = def_specifier( Spec_Constexpr); code_set_global( cast(Code, spec_constexpr ));
|
||||
spec_constinit = def_specifier( Spec_Constinit); code_set_global( cast(Code, spec_constinit ));
|
||||
spec_extern_linkage = def_specifier( Spec_External_Linkage); code_set_global( cast(Code, spec_extern_linkage ));
|
||||
spec_final = def_specifier( Spec_Final); code_set_global( cast(Code, spec_final ));
|
||||
spec_forceinline = def_specifier( Spec_ForceInline); code_set_global( cast(Code, spec_forceinline ));
|
||||
spec_global = def_specifier( Spec_Global); code_set_global( cast(Code, spec_global ));
|
||||
spec_inline = def_specifier( Spec_Inline); code_set_global( cast(Code, spec_inline ));
|
||||
spec_internal_linkage = def_specifier( Spec_Internal_Linkage); code_set_global( cast(Code, spec_internal_linkage ));
|
||||
spec_local_persist = def_specifier( Spec_Local_Persist); code_set_global( cast(Code, spec_local_persist ));
|
||||
spec_mutable = def_specifier( Spec_Mutable); code_set_global( cast(Code, spec_mutable ));
|
||||
spec_neverinline = def_specifier( Spec_NeverInline); code_set_global( cast(Code, spec_neverinline ));
|
||||
spec_noexcept = def_specifier( Spec_NoExceptions); code_set_global( cast(Code, spec_noexcept ));
|
||||
spec_override = def_specifier( Spec_Override); code_set_global( cast(Code, spec_override ));
|
||||
spec_ptr = def_specifier( Spec_Ptr); code_set_global( cast(Code, spec_ptr ));
|
||||
spec_pure = def_specifier( Spec_Pure); code_set_global( cast(Code, spec_pure ));
|
||||
spec_ref = def_specifier( Spec_Ref); code_set_global( cast(Code, spec_ref ));
|
||||
spec_register = def_specifier( Spec_Register); code_set_global( cast(Code, spec_register ));
|
||||
spec_rvalue = def_specifier( Spec_RValue); code_set_global( cast(Code, spec_rvalue ));
|
||||
spec_static_member = def_specifier( Spec_Static); code_set_global( cast(Code, spec_static_member ));
|
||||
spec_thread_local = def_specifier( Spec_Thread_Local); code_set_global( cast(Code, spec_thread_local ));
|
||||
spec_virtual = def_specifier( Spec_Virtual); code_set_global( cast(Code, spec_virtual ));
|
||||
spec_volatile = def_specifier( Spec_Volatile); code_set_global( cast(Code, spec_volatile ));
|
||||
|
||||
spec_local_persist = def_specifiers( 1, Spec_Local_Persist );
|
||||
code_set_global(cast(Code, spec_local_persist));
|
||||
|
||||
if (enum_underlying_macro.Name.Len == 0) {
|
||||
enum_underlying_macro.Name = txt("enum_underlying");
|
||||
enum_underlying_macro.Type = MT_Expression;
|
||||
enum_underlying_macro.Flags = MF_Functional;
|
||||
}
|
||||
register_macro(enum_underlying_macro);
|
||||
}
|
||||
|
||||
void init(Context* ctx)
|
||||
{
|
||||
do_once() {
|
||||
context_counter = 0;
|
||||
}
|
||||
AllocatorInfo fallback_allocator = { & fallback_allocator_proc, nullptr };
|
||||
|
||||
b32 using_fallback_allocator = false;
|
||||
if (ctx->Allocator_DyanmicContainers.Proc == nullptr) {
|
||||
ctx->Allocator_DyanmicContainers = fallback_allocator;
|
||||
using_fallback_allocator = true;
|
||||
}
|
||||
if (ctx->Allocator_Pool.Proc == nullptr ) {
|
||||
ctx->Allocator_Pool = fallback_allocator;
|
||||
using_fallback_allocator = true;
|
||||
}
|
||||
if (ctx->Allocator_StrCache.Proc == nullptr) {
|
||||
ctx->Allocator_StrCache = fallback_allocator;
|
||||
using_fallback_allocator = true;
|
||||
}
|
||||
if (ctx->Allocator_Temp.Proc == nullptr) {
|
||||
ctx->Allocator_Temp = fallback_allocator;
|
||||
using_fallback_allocator = true;
|
||||
}
|
||||
// Setup fallback allocator
|
||||
if (using_fallback_allocator)
|
||||
{
|
||||
ctx->Fallback_AllocatorBuckets = array_init_reserve(Arena, heap(), 128 );
|
||||
if ( ctx->Fallback_AllocatorBuckets == nullptr )
|
||||
GEN_FATAL( "Failed to reserve memory for Fallback_AllocatorBuckets");
|
||||
|
||||
Arena bucket = arena_init_from_allocator( heap(), ctx->InitSize_Fallback_Allocator_Bucket_Size );
|
||||
if ( bucket.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "Failed to create first bucket for Fallback_AllocatorBuckets");
|
||||
|
||||
array_append( ctx->Fallback_AllocatorBuckets, bucket );
|
||||
}
|
||||
|
||||
if (ctx->Max_CommentLineLength == 0) {
|
||||
ctx->Max_CommentLineLength = 1024;
|
||||
}
|
||||
if (ctx->Max_StrCacheLength == 0) {
|
||||
ctx->Max_StrCacheLength = kilobytes(512);
|
||||
}
|
||||
|
||||
if (ctx->InitSize_BuilderBuffer == 0) {
|
||||
ctx->InitSize_BuilderBuffer = megabytes(2);
|
||||
}
|
||||
if (ctx->InitSize_CodePoolsArray == 0) {
|
||||
ctx->InitSize_CodePoolsArray = 16;
|
||||
}
|
||||
if (ctx->InitSize_StringArenasArray == 0) {
|
||||
ctx->InitSize_StringArenasArray = 16;
|
||||
}
|
||||
if (ctx->CodePool_NumBlocks == 0) {
|
||||
ctx->CodePool_NumBlocks = kilobytes(16);
|
||||
}
|
||||
|
||||
if (ctx->InitSize_LexerTokens == 0 ) {
|
||||
ctx->InitSize_LexerTokens = kilobytes(64);
|
||||
}
|
||||
if (ctx->SizePer_StringArena == 0) {
|
||||
ctx->SizePer_StringArena = megabytes(1);
|
||||
}
|
||||
|
||||
if (ctx->InitSize_Fallback_Allocator_Bucket_Size == 0) {
|
||||
ctx->InitSize_Fallback_Allocator_Bucket_Size = megabytes(8);
|
||||
}
|
||||
|
||||
// Override the current context (user has to put it back if unwanted).
|
||||
_ctx = ctx;
|
||||
|
||||
// Setup the arrays
|
||||
{
|
||||
ctx->CodePools = array_init_reserve(Pool, ctx->Allocator_DyanmicContainers, ctx->InitSize_CodePoolsArray );
|
||||
if ( ctx->CodePools == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the CodePools array" );
|
||||
|
||||
ctx->StringArenas = array_init_reserve(Arena, ctx->Allocator_DyanmicContainers, ctx->InitSize_StringArenasArray );
|
||||
if ( ctx->StringArenas == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" );
|
||||
}
|
||||
// Setup the code pool and code entries arena.
|
||||
{
|
||||
Pool code_pool = pool_init( ctx->Allocator_Pool, ctx->CodePool_NumBlocks, sizeof(AST) );
|
||||
if ( code_pool.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the code pool" );
|
||||
array_append( ctx->CodePools, code_pool );
|
||||
|
||||
// TODO(Ed): Eventually the string arenas needs to be phased out for a dedicated string slab allocator
|
||||
Arena strbuilder_arena = arena_init_from_allocator( ctx->Allocator_StrCache, ctx->SizePer_StringArena );
|
||||
if ( strbuilder_arena.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the string arena" );
|
||||
array_append( ctx->StringArenas, strbuilder_arena );
|
||||
}
|
||||
// Setup the hash tables
|
||||
{
|
||||
ctx->StrCache = hashtable_init(StrCached, ctx->Allocator_DyanmicContainers);
|
||||
if ( ctx->StrCache.Entries == nullptr )
|
||||
GEN_FATAL( "gen::init: Failed to initialize the StringCache");
|
||||
|
||||
ctx->Macros = hashtable_init(Macro, ctx->Allocator_DyanmicContainers);
|
||||
if (ctx->Macros.Hashes == nullptr || ctx->Macros.Entries == nullptr) {
|
||||
GEN_FATAL( "gen::init: Failed to initialize the PreprocessMacros table" );
|
||||
}
|
||||
}
|
||||
|
||||
define_constants();
|
||||
parser_init();
|
||||
|
||||
++ context_counter;
|
||||
}
|
||||
|
||||
void deinit(Context* ctx)
|
||||
{
|
||||
GEN_ASSERT(context_counter);
|
||||
GEN_ASSERT_MSG(context_counter > 0, "Attempted to deinit a context that for some reason wan't accounted for!");
|
||||
usize index = 0;
|
||||
usize left = array_num(ctx->CodePools);
|
||||
do
|
||||
{
|
||||
Pool* code_pool = & ctx->CodePools[index];
|
||||
pool_free(code_pool);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
index = 0;
|
||||
left = array_num(ctx->StringArenas);
|
||||
do
|
||||
{
|
||||
Arena* strbuilder_arena = & ctx->StringArenas[index];
|
||||
arena_free(strbuilder_arena);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
hashtable_destroy(ctx->StrCache);
|
||||
|
||||
array_free( ctx->CodePools);
|
||||
array_free( ctx->StringArenas);
|
||||
|
||||
hashtable_destroy(ctx->Macros);
|
||||
|
||||
left = array_num( ctx->Fallback_AllocatorBuckets);
|
||||
if (left)
|
||||
{
|
||||
index = 0;
|
||||
do
|
||||
{
|
||||
Arena* bucket = & ctx->Fallback_AllocatorBuckets[ index ];
|
||||
arena_free(bucket);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
array_free( ctx->Fallback_AllocatorBuckets);
|
||||
}
|
||||
parser_deinit();
|
||||
|
||||
if (_ctx == ctx)
|
||||
_ctx = nullptr;
|
||||
-- context_counter;
|
||||
|
||||
Context wipe = {};
|
||||
* ctx = wipe;
|
||||
}
|
||||
|
||||
Context* get_context() {
|
||||
return _ctx;
|
||||
}
|
||||
|
||||
void reset(Context* ctx)
|
||||
{
|
||||
s32 index = 0;
|
||||
s32 left = array_num(ctx->CodePools);
|
||||
do
|
||||
{
|
||||
Pool* code_pool = & ctx->CodePools[index];
|
||||
pool_clear(code_pool);
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
index = 0;
|
||||
left = array_num(ctx->StringArenas);
|
||||
do
|
||||
{
|
||||
Arena* strbuilder_arena = & ctx->StringArenas[index];
|
||||
strbuilder_arena->TotalUsed = 0;;
|
||||
index++;
|
||||
}
|
||||
while ( left--, left );
|
||||
|
||||
hashtable_clear(ctx->StrCache);
|
||||
hashtable_clear(ctx->Macros);
|
||||
define_constants();
|
||||
}
|
||||
|
||||
void set_context(Context* new_ctx) {
|
||||
GEN_ASSERT(new_ctx);
|
||||
_ctx = new_ctx;
|
||||
}
|
||||
|
||||
AllocatorInfo get_cached_str_allocator( s32 str_length )
|
||||
{
|
||||
Arena* last = array_back(_ctx->StringArenas);
|
||||
usize size_req = str_length + sizeof(StrBuilderHeader) + sizeof(char*);
|
||||
if ( last->TotalUsed + scast(ssize, size_req) > last->TotalSize )
|
||||
{
|
||||
Arena new_arena = arena_init_from_allocator( _ctx->Allocator_StrCache, _ctx->SizePer_StringArena );
|
||||
if ( ! array_append( _ctx->StringArenas, new_arena ) )
|
||||
GEN_FATAL( "gen::get_cached_str_allocator: Failed to allocate a new string arena" );
|
||||
|
||||
last = array_back( _ctx->StringArenas);
|
||||
}
|
||||
return arena_allocator_info(last);
|
||||
}
|
||||
|
||||
// Will either make or retrive a code string.
|
||||
StrCached cache_str( Str str )
|
||||
{
|
||||
if (str.Len > _ctx->Max_StrCacheLength) {
|
||||
// Do not cache the string, just shove into the arena and and return it.
|
||||
Str result = strbuilder_to_str( strbuilder_make_str( get_cached_str_allocator( str.Len ), str ));
|
||||
return result;
|
||||
}
|
||||
u64 key = crc32( str.Ptr, str.Len ); {
|
||||
StrCached* result = hashtable_get( _ctx->StrCache, key );
|
||||
if ( result )
|
||||
return * result;
|
||||
}
|
||||
Str result = strbuilder_to_str( strbuilder_make_str( get_cached_str_allocator( str.Len ), str ));
|
||||
hashtable_set( _ctx->StrCache, key, result );
|
||||
return result;
|
||||
}
|
||||
|
||||
// Used internally to retireve a Code object form the CodePool.
|
||||
Code make_code()
|
||||
{
|
||||
Pool* allocator = array_back( _ctx->CodePools);
|
||||
if ( allocator->FreeList == nullptr )
|
||||
{
|
||||
Pool code_pool = pool_init( _ctx->Allocator_Pool, _ctx->CodePool_NumBlocks, sizeof(AST) );
|
||||
|
||||
if ( code_pool.PhysicalStart == nullptr )
|
||||
GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." );
|
||||
|
||||
if ( ! array_append( _ctx->CodePools, code_pool ) )
|
||||
GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." );
|
||||
|
||||
allocator = array_back( _ctx->CodePools);
|
||||
}
|
||||
Code result = { rcast( AST*, alloc( pool_allocator_info(allocator), sizeof(AST) )) };
|
||||
mem_set( rcast(void*, cast(AST*, result)), 0, sizeof(AST) );
|
||||
return result;
|
||||
}
|
||||
|
||||
Macro* lookup_macro( Str name ) {
|
||||
u32 key = crc32( name.Ptr, name.Len );
|
||||
return hashtable_get( _ctx->Macros, key );
|
||||
}
|
||||
|
||||
void register_macro( Macro macro ) {
|
||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||
GEN_ASSERT(macro.Name.Len > 0);
|
||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||
macro.Name = cache_str(macro.Name);
|
||||
hashtable_set( _ctx->Macros, key, macro );
|
||||
}
|
||||
|
||||
void register_macros( s32 num, ... )
|
||||
{
|
||||
GEN_ASSERT(num > 0);
|
||||
va_list va;
|
||||
va_start(va, num);
|
||||
do
|
||||
{
|
||||
Macro macro = va_arg(va, Macro);
|
||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||
GEN_ASSERT(macro.Name.Len > 0);
|
||||
macro.Name = cache_str(macro.Name);
|
||||
|
||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||
hashtable_set( _ctx->Macros, key, macro );
|
||||
}
|
||||
while (num--, num > 0);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void register_macros_arr( s32 num, Macro* macros )
|
||||
{
|
||||
GEN_ASSERT(num > 0);
|
||||
do
|
||||
{
|
||||
Macro macro = * macros;
|
||||
GEN_ASSERT_NOT_NULL(macro.Name.Ptr);
|
||||
GEN_ASSERT(macro.Name.Len > 0);
|
||||
macro.Name = cache_str(macro.Name);
|
||||
|
||||
u32 key = crc32( macro.Name.Ptr, macro.Name.Len );
|
||||
hashtable_set( _ctx->Macros, key, macro );
|
||||
++ macros;
|
||||
}
|
||||
while (num--, num > 0);
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "ast_types.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Gen Interface
|
||||
/*
|
||||
/ \ | \ | \ / \
|
||||
| ▓▓▓▓▓▓\ ______ _______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______
|
||||
| ▓▓ __\▓▓/ \| \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \
|
||||
| ▓▓| \ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\
|
||||
| ▓▓ \▓▓▓▓ ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓
|
||||
| ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓
|
||||
\▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \
|
||||
\▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓
|
||||
*/
|
||||
|
||||
#if 0
|
||||
enum LogLevel : u32
|
||||
{
|
||||
Info,
|
||||
Warning,
|
||||
Panic,
|
||||
};
|
||||
|
||||
struct LogEntry
|
||||
{
|
||||
Str msg;
|
||||
u32 line_num;
|
||||
void* data;
|
||||
};
|
||||
|
||||
typedef void LoggerCallback(LogEntry entry);
|
||||
#endif
|
||||
|
||||
// Note(Ed): This is subject to heavily change
|
||||
// with upcoming changes to the library's fallback (default) allocations strategy;
|
||||
// and major changes to lexer/parser context usage.
|
||||
struct Context
|
||||
{
|
||||
// User Configuration
|
||||
|
||||
// Persistent Data Allocation
|
||||
AllocatorInfo Allocator_DyanmicContainers; // By default will use a genral slab allocator (TODO(Ed): Currently does not)
|
||||
AllocatorInfo Allocator_Pool; // By default will use the growing vmem reserve (TODO(Ed): Currently does not)
|
||||
AllocatorInfo Allocator_StrCache; // By default will use a dedicated slab allocator (TODO(Ed): Currently does not)
|
||||
|
||||
// Temporary Allocation
|
||||
AllocatorInfo Allocator_Temp;
|
||||
|
||||
// LoggerCallaback* log_callback; // TODO(Ed): Impl user logger callback as an option.
|
||||
|
||||
// Initalization config
|
||||
u32 Max_CommentLineLength; // Used by def_comment
|
||||
u32 Max_StrCacheLength; // Any cached string longer than this is always allocated again.
|
||||
|
||||
u32 InitSize_BuilderBuffer;
|
||||
u32 InitSize_CodePoolsArray;
|
||||
u32 InitSize_StringArenasArray;
|
||||
|
||||
u32 CodePool_NumBlocks;
|
||||
|
||||
// TODO(Ed): Review these... (No longer needed if using the proper allocation strategy)
|
||||
u32 InitSize_LexerTokens;
|
||||
u32 SizePer_StringArena;
|
||||
|
||||
// TODO(Ed): Symbol Table
|
||||
// Keep track of all resolved symbols (naemspaced identifiers)
|
||||
|
||||
// Parser
|
||||
|
||||
// Used by the lexer to persistently treat all these identifiers as preprocessor defines.
|
||||
// Populate with strings via gen::cache_str.
|
||||
// Functional defines must have format: id( ;at minimum to indicate that the define is only valid with arguments.
|
||||
MacroTable Macros;
|
||||
|
||||
// Backend
|
||||
|
||||
// The fallback allocator is utilized if any fo the three above allocators is not specified by the user.
|
||||
u32 InitSize_Fallback_Allocator_Bucket_Size;
|
||||
Array(Arena) Fallback_AllocatorBuckets;
|
||||
|
||||
StringTable token_fmt_map;
|
||||
|
||||
// Array(Token) LexerTokens;
|
||||
|
||||
Array(Pool) CodePools;
|
||||
Array(Arena) StringArenas;
|
||||
|
||||
StringTable StrCache;
|
||||
|
||||
// TODO(Ed): This needs to be just handled by a parser context
|
||||
Array(Token) Lexer_Tokens;
|
||||
|
||||
// TODO(Ed): Active parse context vs a parse result need to be separated conceptually
|
||||
ParseContext parser;
|
||||
|
||||
// TODO(Ed): Formatting - This will eventually be in a separate struct when in the process of serialization of the builder.
|
||||
s32 temp_serialize_indent;
|
||||
};
|
||||
|
||||
// Initialize the library. There first ctx initialized must exist for lifetime of other contextes that come after as its the one that
|
||||
GEN_API void init(Context* ctx);
|
||||
|
||||
// Currently manually free's the arenas, code for checking for leaks.
|
||||
// However on Windows at least, it doesn't need to occur as the OS will clean up after the process.
|
||||
GEN_API void deinit(Context* ctx);
|
||||
|
||||
// Retrieves the active context (not usually needed, but here in case...)
|
||||
GEN_API Context* get_context();
|
||||
|
||||
// Clears the allocations, but doesn't free the memoery, then calls init() again.
|
||||
// Ease of use.
|
||||
GEN_API void reset(Context* ctx);
|
||||
|
||||
GEN_API void set_context(Context* ctx);
|
||||
|
||||
// Mostly intended for the parser
|
||||
GEN_API Macro* lookup_macro( Str Name );
|
||||
|
||||
// Alternative way to add a preprocess define entry for the lexer & parser to utilize
|
||||
// if the user doesn't want to use def_define
|
||||
// Macros are tracked by name so if the name already exists the entry will be overwritten.
|
||||
GEN_API void register_macro( Macro macro );
|
||||
|
||||
// Ease of use batch registration
|
||||
GEN_API void register_macros( s32 num, ... );
|
||||
GEN_API void register_macros_arr( s32 num, Macro* macros );
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline void register_macros( s32 num, Macro* macros ) { return register_macros_arr(num, macros); }
|
||||
#endif
|
||||
|
||||
// Used internally to retrive or make string allocations.
|
||||
// Strings are stored in a series of string arenas of fixed size (SizePer_StringArena)
|
||||
GEN_API StrCached cache_str( Str str );
|
||||
|
||||
/*
|
||||
This provides a fresh Code AST.
|
||||
The gen interface use this as their method from getting a new AST object from the CodePool.
|
||||
Use this if you want to make your own API for formatting the supported Code Types.
|
||||
*/
|
||||
GEN_API Code make_code();
|
||||
|
||||
// Set these before calling gen's init() procedure.
|
||||
|
||||
#pragma region Upfront
|
||||
|
||||
GEN_API CodeAttributes def_attributes( Str content );
|
||||
GEN_API CodeComment def_comment ( Str content );
|
||||
|
||||
struct Opts_def_struct {
|
||||
CodeBody body;
|
||||
CodeTypename parent;
|
||||
AccessSpec parent_access;
|
||||
CodeAttributes attributes;
|
||||
CodeTypename* interfaces;
|
||||
s32 num_interfaces;
|
||||
CodeSpecifiers specifiers; // Only used for final specifier for now.
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeClass def_class( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_constructor {
|
||||
CodeParams params;
|
||||
Code initializer_list;
|
||||
Code body;
|
||||
};
|
||||
GEN_API CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_define {
|
||||
CodeDefineParams params;
|
||||
Str content;
|
||||
MacroFlags flags;
|
||||
b32 dont_register_to_preprocess_macros;
|
||||
};
|
||||
GEN_API CodeDefine def_define( Str name, MacroType type, Opts_def_define opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_destructor {
|
||||
Code body;
|
||||
CodeSpecifiers specifiers;
|
||||
};
|
||||
GEN_API CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_enum {
|
||||
CodeBody body;
|
||||
CodeTypename type;
|
||||
EnumT specifier;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
Code type_macro;
|
||||
};
|
||||
GEN_API CodeEnum def_enum( Str name, Opts_def_enum opts GEN_PARAM_DEFAULT );
|
||||
|
||||
GEN_API CodeExec def_execution ( Str content );
|
||||
GEN_API CodeExtern def_extern_link( Str name, CodeBody body );
|
||||
GEN_API CodeFriend def_friend ( Code symbol );
|
||||
|
||||
struct Opts_def_function {
|
||||
CodeParams params;
|
||||
CodeTypename ret_type;
|
||||
CodeBody body;
|
||||
CodeSpecifiers specs;
|
||||
CodeAttributes attrs;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeFn def_function( Str name, Opts_def_function opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_include { b32 foreign; };
|
||||
struct Opts_def_module { ModuleFlag mflags; };
|
||||
struct Opts_def_namespace { ModuleFlag mflags; };
|
||||
GEN_API CodeInclude def_include ( Str content, Opts_def_include opts GEN_PARAM_DEFAULT );
|
||||
GEN_API CodeModule def_module ( Str name, Opts_def_module opts GEN_PARAM_DEFAULT );
|
||||
GEN_API CodeNS def_namespace( Str name, CodeBody body, Opts_def_namespace opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_operator {
|
||||
CodeParams params;
|
||||
CodeTypename ret_type;
|
||||
CodeBody body;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeOperator def_operator( Operator op, Str nspace, Opts_def_operator opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_operator_cast {
|
||||
CodeBody body;
|
||||
CodeSpecifiers specs;
|
||||
};
|
||||
GEN_API CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_param { Code value; };
|
||||
GEN_API CodeParams def_param ( CodeTypename type, Str name, Opts_def_param opts GEN_PARAM_DEFAULT );
|
||||
GEN_API CodePragma def_pragma( Str directive );
|
||||
|
||||
GEN_API CodePreprocessCond def_preprocess_cond( EPreprocessCond type, Str content );
|
||||
|
||||
GEN_API CodeSpecifiers def_specifier( Specifier specifier );
|
||||
|
||||
GEN_API CodeStruct def_struct( Str name, Opts_def_struct opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_template { ModuleFlag mflags; };
|
||||
GEN_API CodeTemplate def_template( CodeParams params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_type {
|
||||
ETypenameTag type_tag;
|
||||
Code arrayexpr;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
};
|
||||
GEN_API CodeTypename def_type( Str name, Opts_def_type opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_typedef {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeTypedef def_typedef( Str name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_union {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeUnion def_union( Str name, CodeBody body, Opts_def_union opts GEN_PARAM_DEFAULT );
|
||||
|
||||
struct Opts_def_using {
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeUsing def_using( Str name, CodeTypename type, Opts_def_using opts GEN_PARAM_DEFAULT );
|
||||
|
||||
GEN_API CodeUsing def_using_namespace( Str name );
|
||||
|
||||
struct Opts_def_variable
|
||||
{
|
||||
Code value;
|
||||
CodeSpecifiers specifiers;
|
||||
CodeAttributes attributes;
|
||||
ModuleFlag mflags;
|
||||
};
|
||||
GEN_API CodeVar def_variable( CodeTypename type, Str name, Opts_def_variable opts GEN_PARAM_DEFAULT );
|
||||
|
||||
// Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries.
|
||||
GEN_API CodeBody def_body( CodeType type );
|
||||
|
||||
// There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num,
|
||||
/// or provide as an array of Code objects.
|
||||
|
||||
GEN_API CodeBody def_class_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_class_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeDefineParams def_define_params ( s32 num, ... );
|
||||
GEN_API CodeDefineParams def_define_params_arr ( s32 num, CodeDefineParams* codes );
|
||||
GEN_API CodeBody def_enum_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_enum_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_export_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_export_body_arr ( s32 num, Code* codes);
|
||||
GEN_API CodeBody def_extern_link_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_extern_link_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_function_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_function_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_global_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_global_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_namespace_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_namespace_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeParams def_params ( s32 num, ... );
|
||||
GEN_API CodeParams def_params_arr ( s32 num, CodeParams* params );
|
||||
GEN_API CodeSpecifiers def_specifiers ( s32 num, ... );
|
||||
GEN_API CodeSpecifiers def_specifiers_arr ( s32 num, Specifier* specs );
|
||||
GEN_API CodeBody def_struct_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_struct_body_arr ( s32 num, Code* codes );
|
||||
GEN_API CodeBody def_union_body ( s32 num, ... );
|
||||
GEN_API CodeBody def_union_body_arr ( s32 num, Code* codes );
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline CodeBody def_class_body ( s32 num, Code* codes ) { return def_class_body_arr(num, codes); }
|
||||
forceinline CodeDefineParams def_define_params ( s32 num, CodeDefineParams* codes ) { return def_define_params_arr(num, codes); }
|
||||
forceinline CodeBody def_enum_body ( s32 num, Code* codes ) { return def_enum_body_arr(num, codes); }
|
||||
forceinline CodeBody def_export_body ( s32 num, Code* codes) { return def_export_body_arr(num, codes); }
|
||||
forceinline CodeBody def_extern_link_body( s32 num, Code* codes ) { return def_extern_link_body_arr(num, codes); }
|
||||
forceinline CodeBody def_function_body ( s32 num, Code* codes ) { return def_function_body_arr(num, codes); }
|
||||
forceinline CodeBody def_global_body ( s32 num, Code* codes ) { return def_global_body_arr(num, codes); }
|
||||
forceinline CodeBody def_namespace_body ( s32 num, Code* codes ) { return def_namespace_body_arr(num, codes); }
|
||||
forceinline CodeParams def_params ( s32 num, CodeParams* params ) { return def_params_arr(num, params); }
|
||||
forceinline CodeSpecifiers def_specifiers ( s32 num, Specifier* specs ) { return def_specifiers_arr(num, specs); }
|
||||
forceinline CodeBody def_struct_body ( s32 num, Code* codes ) { return def_struct_body_arr(num, codes); }
|
||||
forceinline CodeBody def_union_body ( s32 num, Code* codes ) { return def_union_body_arr(num, codes); }
|
||||
#endif
|
||||
|
||||
#pragma endregion Upfront
|
||||
|
||||
#pragma region Parsing
|
||||
|
||||
#if 0
|
||||
struct StackNode
|
||||
{
|
||||
StackNode* Prev;
|
||||
|
||||
Token Start;
|
||||
Token Name; // The name of the AST node (if parsed)
|
||||
Str FailedProc; // The name of the procedure that failed
|
||||
};
|
||||
// Stack nodes are allocated the error's allocator
|
||||
|
||||
struct Error
|
||||
{
|
||||
StrBuilder message;
|
||||
StackNode* context_stack;
|
||||
};
|
||||
|
||||
struct ParseInfo
|
||||
{
|
||||
Arena FileMem;
|
||||
Arena TokMem;
|
||||
Arena CodeMem;
|
||||
|
||||
FileContents FileContent;
|
||||
Array<Token> Tokens;
|
||||
Array<Error> Errors;
|
||||
// Errors are allocated to a dedicated general arena.
|
||||
};
|
||||
|
||||
CodeBody parse_file( Str path );
|
||||
#endif
|
||||
|
||||
GEN_API CodeClass parse_class ( Str class_def );
|
||||
GEN_API CodeConstructor parse_constructor ( Str constructor_def );
|
||||
GEN_API CodeDefine parse_define ( Str define_def );
|
||||
GEN_API CodeDestructor parse_destructor ( Str destructor_def );
|
||||
GEN_API CodeEnum parse_enum ( Str enum_def );
|
||||
GEN_API CodeBody parse_export_body ( Str export_def );
|
||||
GEN_API CodeExtern parse_extern_link ( Str exten_link_def );
|
||||
GEN_API CodeFriend parse_friend ( Str friend_def );
|
||||
GEN_API CodeFn parse_function ( Str fn_def );
|
||||
GEN_API CodeBody parse_global_body ( Str body_def );
|
||||
GEN_API CodeNS parse_namespace ( Str namespace_def );
|
||||
GEN_API CodeOperator parse_operator ( Str operator_def );
|
||||
GEN_API CodeOpCast parse_operator_cast( Str operator_def );
|
||||
GEN_API CodeStruct parse_struct ( Str struct_def );
|
||||
GEN_API CodeTemplate parse_template ( Str template_def );
|
||||
GEN_API CodeTypename parse_type ( Str type_def );
|
||||
GEN_API CodeTypedef parse_typedef ( Str typedef_def );
|
||||
GEN_API CodeUnion parse_union ( Str union_def );
|
||||
GEN_API CodeUsing parse_using ( Str using_def );
|
||||
GEN_API CodeVar parse_variable ( Str var_def );
|
||||
|
||||
#pragma endregion Parsing
|
||||
|
||||
#pragma region Untyped text
|
||||
|
||||
GEN_API ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va );
|
||||
//! Do not use directly. Use the token_fmt macro instead.
|
||||
GEN_API Str token_fmt_impl( ssize, ... );
|
||||
|
||||
GEN_API Code untyped_str( Str content);
|
||||
GEN_API Code untyped_fmt ( char const* fmt, ... );
|
||||
GEN_API Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... );
|
||||
|
||||
#pragma endregion Untyped text
|
||||
|
||||
#pragma region Macros
|
||||
|
||||
#ifndef gen_main
|
||||
#define gen_main main
|
||||
#endif
|
||||
|
||||
#ifndef name
|
||||
// Convienence for defining any name used with the gen api.
|
||||
// Lets you provide the length and string literal to the functions without the need for the DSL.
|
||||
# if GEN_COMPILER_C
|
||||
# define name( Id_ ) (Str){ stringize(Id_), sizeof(stringize( Id_ )) - 1 }
|
||||
# else
|
||||
# define name( Id_ ) Str { stringize(Id_), sizeof(stringize( Id_ )) - 1 }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef code
|
||||
// Same as name just used to indicate intention of literal for code instead of names.
|
||||
# if GEN_COMPILER_C
|
||||
# define code( ... ) (Str){ stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 }
|
||||
# else
|
||||
# define code( ... ) Str { stringize( __VA_ARGS__ ), sizeof(stringize(__VA_ARGS__)) - 1 }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef args
|
||||
// Provides the number of arguments while passing args inplace.
|
||||
#define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#ifndef code_str
|
||||
// Just wrappers over common untyped code definition constructions.
|
||||
#define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#ifndef code_fmt
|
||||
#define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#ifndef parse_fmt
|
||||
#define parse_fmt( type, ... ) GEN_NS parse_##type( token_fmt( __VA_ARGS__ ) )
|
||||
#endif
|
||||
|
||||
#ifndef token_fmt
|
||||
/*
|
||||
Takes a format string (char const*) and a list of tokens (Str) and returns a Str of the formatted string.
|
||||
Tokens are provided in '<'identifier'>' format where '<' '>' are just angle brackets (you can change it in token_fmt_va)
|
||||
---------------------------------------------------------
|
||||
Example - A string with:
|
||||
typedef <type> <name> <name>;
|
||||
Will have a token_fmt arguments populated with:
|
||||
"type", str_for_type,
|
||||
"name", str_for_name,
|
||||
and:
|
||||
stringize( typedef <type> <name> <name>; )
|
||||
-----------------------------------------------------------
|
||||
So the full call for this example would be:
|
||||
token_fmt(
|
||||
"type", str_for_type
|
||||
, "name", str_for_name
|
||||
, stringize(
|
||||
typedef <type> <name> <name>
|
||||
));
|
||||
!----------------------------------------------------------
|
||||
! Note: token_fmt_va is whitespace sensitive for the tokens.
|
||||
! This can be alleviated by skipping whitespace between brackets but it was choosen to not have that implementation by default.
|
||||
*/
|
||||
#define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#pragma endregion Macros
|
||||
|
||||
#pragma endregion Gen Interface
|
||||
@@ -0,0 +1,341 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "gen/etoktype.cpp"
|
||||
#include "interface.upfront.cpp"
|
||||
#include "lexer.cpp"
|
||||
#include "parser.cpp"
|
||||
#endif
|
||||
|
||||
// Publically Exposed Interface
|
||||
|
||||
CodeClass parse_class( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
push_scope();
|
||||
CodeClass result = (CodeClass) parse_class_struct( Tok_Decl_Class, parser_not_inplace_def );
|
||||
parser_pop(& _ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeConstructor parse_constructor( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
// TODO(Ed): Constructors can have prefix attributes
|
||||
|
||||
CodeSpecifiers specifiers = NullCode;
|
||||
Specifier specs_found[ 16 ] = { Spec_NumSpecifiers };
|
||||
s32 NumSpecifiers = 0;
|
||||
|
||||
while ( left && tok_is_specifier(currtok) )
|
||||
{
|
||||
Specifier spec = str_to_specifier( currtok.Text );
|
||||
|
||||
b32 ignore_spec = false;
|
||||
|
||||
switch ( spec )
|
||||
{
|
||||
case Spec_Constexpr :
|
||||
case Spec_Explicit:
|
||||
case Spec_Inline :
|
||||
case Spec_ForceInline :
|
||||
case Spec_NeverInline :
|
||||
break;
|
||||
|
||||
case Spec_Const :
|
||||
ignore_spec = true;
|
||||
break;
|
||||
|
||||
default :
|
||||
log_failure( "Invalid specifier %s for variable\n%S", spec_to_str( spec ), parser_to_strbuilder(_ctx->parser) );
|
||||
parser_pop(& _ctx->parser);
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
// Every specifier after would be considered part of the type type signature
|
||||
if (ignore_spec)
|
||||
break;
|
||||
|
||||
specs_found[ NumSpecifiers ] = spec;
|
||||
NumSpecifiers++;
|
||||
eat( currtok.Type );
|
||||
}
|
||||
|
||||
if ( NumSpecifiers )
|
||||
{
|
||||
specifiers = def_specifiers_arr( NumSpecifiers, specs_found );
|
||||
// <specifiers> ...
|
||||
}
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
CodeConstructor result = parser_parse_constructor( specifiers );
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeDefine parse_define( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
push_scope();
|
||||
CodeDefine result = parser_parse_define();
|
||||
parser_pop(& _ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeDestructor parse_destructor( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
// TODO(Ed): Destructors can have prefix attributes
|
||||
// TODO(Ed): Destructors can have virtual
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
CodeDestructor result = parser_parse_destructor(NullCode);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeEnum parse_enum( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
{
|
||||
parser_pop(& _ctx->parser);
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_enum( parser_not_inplace_def);
|
||||
}
|
||||
|
||||
CodeBody parse_export_body( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_export_body();
|
||||
}
|
||||
|
||||
CodeExtern parse_extern_link( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_extern_link();
|
||||
}
|
||||
|
||||
CodeFriend parse_friend( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_friend();
|
||||
}
|
||||
|
||||
CodeFn parse_function( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return (CodeFn) parser_parse_function();
|
||||
}
|
||||
|
||||
CodeBody parse_global_body( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
push_scope();
|
||||
CodeBody result = parse_global_nspace( CT_Global_Body );
|
||||
parser_pop(& _ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeNS parse_namespace( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_namespace();
|
||||
}
|
||||
|
||||
CodeOperator parse_operator( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return (CodeOperator) parser_parse_operator();
|
||||
}
|
||||
|
||||
CodeOpCast parse_operator_cast( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_operator_cast(NullCode);
|
||||
}
|
||||
|
||||
CodeStruct parse_struct( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
push_scope();
|
||||
CodeStruct result = (CodeStruct) parse_class_struct( Tok_Decl_Struct, parser_not_inplace_def );
|
||||
parser_pop(& _ctx->parser);
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeTemplate parse_template( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_template();
|
||||
}
|
||||
|
||||
CodeTypename parse_type( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_type( parser_not_from_template, nullptr);
|
||||
}
|
||||
|
||||
CodeTypedef parse_typedef( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_typedef();
|
||||
}
|
||||
|
||||
CodeUnion parse_union( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_union( parser_not_inplace_def);
|
||||
}
|
||||
|
||||
CodeUsing parse_using( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_using();
|
||||
}
|
||||
|
||||
CodeVar parse_variable( Str def )
|
||||
{
|
||||
check_parse_args( def );
|
||||
|
||||
TokArray toks = lex( def );
|
||||
if ( toks.Arr == nullptr )
|
||||
return InvalidCode;
|
||||
|
||||
_ctx->parser.Tokens = toks;
|
||||
return parser_parse_variable();
|
||||
}
|
||||
|
||||
// Undef helper macros
|
||||
#undef check_parse_args
|
||||
#undef currtok_noskip
|
||||
#undef currtok
|
||||
#undef peektok
|
||||
#undef prevtok
|
||||
#undef nexttok
|
||||
#undef nexttok_noskip
|
||||
#undef eat
|
||||
#undef left
|
||||
#undef check
|
||||
#undef push_scope
|
||||
#undef def_assign
|
||||
|
||||
// Here for C Variant
|
||||
#undef lex_dont_skip_formatting
|
||||
#undef lex_skip_formatting
|
||||
|
||||
#undef parser_inplace_def
|
||||
#undef parser_not_inplace_def
|
||||
#undef parser_dont_consume_braces
|
||||
#undef parser_consume_braces
|
||||
#undef parser_not_from_template
|
||||
#undef parser_use_parenthesis
|
||||
#undef parser_strip_formatting_dont_preserve_newlines
|
||||
@@ -1,29 +1,27 @@
|
||||
sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va )
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "interface.parsing.cpp"
|
||||
#endif
|
||||
|
||||
ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va )
|
||||
{
|
||||
char const* buf_begin = buf;
|
||||
sw remaining = buf_size;
|
||||
ssize remaining = buf_size;
|
||||
|
||||
local_persist
|
||||
Arena tok_map_arena;
|
||||
|
||||
HashTable<StrC> tok_map;
|
||||
if (_ctx->token_fmt_map.Hashes == nullptr) {
|
||||
_ctx->token_fmt_map = hashtable_init(Str, _ctx->Allocator_DyanmicContainers );
|
||||
}
|
||||
// Populate token pairs
|
||||
{
|
||||
local_persist
|
||||
char tok_map_mem[ TokenFmt_TokenMap_MemSize ];
|
||||
|
||||
tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) );
|
||||
tok_map = HashTable<StrC>::init( tok_map_arena );
|
||||
|
||||
s32 left = num_tokens - 1;
|
||||
|
||||
while ( left-- )
|
||||
{
|
||||
char const* token = va_arg( va, char const* );
|
||||
StrC value = va_arg( va, StrC );
|
||||
Str value = va_arg( va, Str );
|
||||
|
||||
u32 key = crc32( token, str_len(token) );
|
||||
|
||||
tok_map.set( key, value );
|
||||
u32 key = crc32( token, c_str_len(token) );
|
||||
hashtable_set( _ctx->token_fmt_map, key, value );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +30,7 @@ sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va )
|
||||
|
||||
while ( current )
|
||||
{
|
||||
sw len = 0;
|
||||
ssize len = 0;
|
||||
|
||||
while ( current && current != '<' && remaining )
|
||||
{
|
||||
@@ -59,11 +57,11 @@ sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va )
|
||||
char const* token = fmt + 1;
|
||||
|
||||
u32 key = crc32( token, tok_len );
|
||||
StrC* value = tok_map.get( key );
|
||||
Str* value = hashtable_get(_ctx->token_fmt_map, key );
|
||||
|
||||
if ( value )
|
||||
{
|
||||
sw left = value->Len;
|
||||
ssize left = value->Len;
|
||||
char const* str = value->Ptr;
|
||||
|
||||
while ( left-- )
|
||||
@@ -88,33 +86,29 @@ sw token_fmt_va( char* buf, uw buf_size, s32 num_tokens, va_list va )
|
||||
current = * fmt;
|
||||
}
|
||||
}
|
||||
|
||||
tok_map.clear();
|
||||
tok_map_arena.free();
|
||||
|
||||
sw result = buf_size - remaining;
|
||||
|
||||
hashtable_clear(_ctx->token_fmt_map);
|
||||
ssize result = buf_size - remaining;
|
||||
return result;
|
||||
}
|
||||
|
||||
Code untyped_str( StrC content )
|
||||
Code untyped_str( Str content )
|
||||
{
|
||||
if ( content.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_str: empty string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = get_cached_string( content );
|
||||
result->Type = ECode::Untyped;
|
||||
result->Name = cache_str( content );
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = result->Name;
|
||||
|
||||
if ( result->Name == nullptr )
|
||||
if ( result->Name.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_str: could not cache string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -125,7 +119,7 @@ Code untyped_fmt( char const* fmt, ...)
|
||||
if ( fmt == nullptr )
|
||||
{
|
||||
log_failure( "untyped_fmt: null format string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
local_persist thread_local
|
||||
@@ -133,52 +127,52 @@ Code untyped_fmt( char const* fmt, ...)
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
sw length = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va);
|
||||
ssize length = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va);
|
||||
va_end(va);
|
||||
Str content = { buf, length };
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = get_cached_string( { str_len(fmt, MaxNameLength), fmt } );
|
||||
result->Type = ECode::Untyped;
|
||||
result->Content = get_cached_string( { length, buf } );
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = cache_str( content );
|
||||
|
||||
if ( result->Name == nullptr )
|
||||
if ( result->Name.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_fmt: could not cache string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Code untyped_token_fmt( s32 num_tokens, ... )
|
||||
Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... )
|
||||
{
|
||||
if ( num_tokens == 0 )
|
||||
{
|
||||
log_failure( "untyped_token_fmt: zero tokens" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
local_persist thread_local
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, num_tokens);
|
||||
sw length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va);
|
||||
va_start(va, fmt);
|
||||
ssize length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va);
|
||||
va_end(va);
|
||||
|
||||
Str buf_str = { buf, length };
|
||||
|
||||
Code
|
||||
result = make_code();
|
||||
result->Name = get_cached_string( { length, buf } );
|
||||
result->Type = ECode::Untyped;
|
||||
result->Content = result->Name;
|
||||
result->Type = CT_Untyped;
|
||||
result->Content = cache_str( buf_str );
|
||||
|
||||
if ( result->Name == nullptr )
|
||||
if ( result->Name.Len == 0 )
|
||||
{
|
||||
log_failure( "untyped_fmt: could not cache string" );
|
||||
return CodeInvalid;
|
||||
return InvalidCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,112 @@
|
||||
// These macros are used in the swtich cases within parser.cpp
|
||||
|
||||
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_TOK_SPECIFIER_CASES \
|
||||
case Tok_Spec_Consteval: \
|
||||
case Tok_Spec_Constexpr: \
|
||||
case Tok_Spec_Constinit: \
|
||||
case Tok_Spec_Explicit: \
|
||||
case Tok_Spec_ForceInline: \
|
||||
case Tok_Spec_Inline: \
|
||||
case Tok_Spec_Mutable: \
|
||||
case Tok_Spec_NeverInline: \
|
||||
case Tok_Spec_Static: \
|
||||
case Tok_Spec_Volatile: \
|
||||
case Tok_Spec_Virtual
|
||||
|
||||
#define GEN_PARSER_CLASS_STRUCT_BODY_ALLOWED_MEMBER_SPECIFIER_CASES \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_Constinit: \
|
||||
case Spec_Explicit: \
|
||||
case Spec_Inline: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Mutable: \
|
||||
case Spec_NeverInline: \
|
||||
case Spec_Static: \
|
||||
case Spec_Volatile: \
|
||||
case Spec_Virtual
|
||||
|
||||
#define GEN_PARSER_CLASS_GLOBAL_NSPACE_ALLOWED_MEMBER_TOK_SPECIFIER_CASES \
|
||||
case Tok_Spec_Consteval: \
|
||||
case Tok_Spec_Constexpr: \
|
||||
case Tok_Spec_Constinit: \
|
||||
case Tok_Spec_Extern: \
|
||||
case Tok_Spec_ForceInline: \
|
||||
case Tok_Spec_Global: \
|
||||
case Tok_Spec_Inline: \
|
||||
case Tok_Spec_Internal_Linkage: \
|
||||
case Tok_Spec_NeverInline: \
|
||||
case Tok_Spec_Static
|
||||
|
||||
#define GEN_PARSER_CLASS_GLOBAL_NSPACE_ALLOWED_MEMBER_SPECIFIER_CASES \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_Constinit: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Global: \
|
||||
case Spec_External_Linkage: \
|
||||
case Spec_Internal_Linkage: \
|
||||
case Spec_Inline: \
|
||||
case Spec_Mutable: \
|
||||
case Spec_NeverInline: \
|
||||
case Spec_Static: \
|
||||
case Spec_Volatile
|
||||
|
||||
#define GEN_PARSER_FRIEND_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Inline: \
|
||||
case Spec_ForceInline
|
||||
|
||||
#define GEN_PARSER_FUNCTION_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Consteval: \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_External_Linkage: \
|
||||
case Spec_Internal_Linkage: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Inline: \
|
||||
case Spec_NeverInline: \
|
||||
case Spec_Static
|
||||
|
||||
#define GEN_PARSER_OPERATOR_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Inline: \
|
||||
case Spec_NeverInline: \
|
||||
case Spec_Static
|
||||
|
||||
#define GEN_PARSER_TEMPLATE_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_Constinit: \
|
||||
case Spec_External_Linkage: \
|
||||
case Spec_Global: \
|
||||
case Spec_Inline: \
|
||||
case Spec_ForceInline: \
|
||||
case Spec_Local_Persist: \
|
||||
case Spec_Mutable: \
|
||||
case Spec_Static: \
|
||||
case Spec_Thread_Local: \
|
||||
case Spec_Volatile
|
||||
|
||||
#define GEN_PARSER_VARIABLE_ALLOWED_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Constexpr: \
|
||||
case Spec_Constinit: \
|
||||
case Spec_External_Linkage: \
|
||||
case Spec_Global: \
|
||||
case Spec_Inline: \
|
||||
case Spec_Local_Persist: \
|
||||
case Spec_Mutable: \
|
||||
case Spec_Restrict: \
|
||||
case Spec_Static: \
|
||||
case Spec_Thread_Local: \
|
||||
case Spec_Volatile
|
||||
|
||||
#define GEN_PARSER_TYPENAME_ALLOWED_SUFFIX_SPECIFIER_CASES \
|
||||
case Spec_Const: \
|
||||
case Spec_Ptr: \
|
||||
case Spec_Restrict: \
|
||||
case Spec_Ref: \
|
||||
case Spec_RValue
|
||||
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "types.hpp"
|
||||
#include "gen/ecode.hpp"
|
||||
#include "gen/eoperator.hpp"
|
||||
#include "gen/especifier.hpp"
|
||||
#include "gen/etoktype.hpp"
|
||||
#endif
|
||||
|
||||
enum TokFlags : u32
|
||||
{
|
||||
TF_Operator = bit(0),
|
||||
TF_Assign = bit(1),
|
||||
TF_Preprocess = bit(2),
|
||||
TF_Preprocess_Cond = bit(3),
|
||||
TF_Attribute = bit(6),
|
||||
TF_AccessOperator = bit(7),
|
||||
TF_AccessSpecifier = bit(8),
|
||||
TF_Specifier = bit(9),
|
||||
TF_EndDefinition = bit(10), // Either ; or }
|
||||
TF_Formatting = bit(11),
|
||||
TF_Literal = bit(12),
|
||||
TF_Macro_Functional = bit(13),
|
||||
TF_Macro_Expects_Body = bit(14),
|
||||
|
||||
TF_Null = 0,
|
||||
TF_UnderlyingType = GEN_U32_MAX,
|
||||
};
|
||||
|
||||
struct Token
|
||||
{
|
||||
Str Text;
|
||||
TokType Type;
|
||||
s32 Line;
|
||||
s32 Column;
|
||||
u32 Flags;
|
||||
};
|
||||
|
||||
constexpr Token NullToken { {}, Tok_Invalid, 0, 0, TF_Null };
|
||||
|
||||
forceinline
|
||||
AccessSpec tok_to_access_specifier(Token tok) {
|
||||
return scast(AccessSpec, tok.Type);
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_valid( Token tok ) {
|
||||
return tok.Text.Ptr && tok.Text.Len && tok.Type != Tok_Invalid;
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_access_operator(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_AccessOperator );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_access_specifier(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_AccessSpecifier );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_attribute(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Attribute );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_operator(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Operator );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_preprocessor(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Preprocess );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_preprocess_cond(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Preprocess_Cond );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_specifier(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_Specifier );
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool tok_is_end_definition(Token tok) {
|
||||
return bitfield_is_set( u32, tok.Flags, TF_EndDefinition );
|
||||
}
|
||||
|
||||
StrBuilder tok_to_strbuilder(Token tok);
|
||||
|
||||
struct TokArray
|
||||
{
|
||||
Array(Token) Arr;
|
||||
s32 Idx;
|
||||
};
|
||||
|
||||
struct LexContext
|
||||
{
|
||||
Str content;
|
||||
s32 left;
|
||||
char const* scanner;
|
||||
s32 line;
|
||||
s32 column;
|
||||
// StringTable defines;
|
||||
Token token;
|
||||
};
|
||||
|
||||
struct StackNode
|
||||
{
|
||||
StackNode* Prev;
|
||||
|
||||
Token* Start;
|
||||
Str Name; // The name of the AST node (if parsed)
|
||||
Str ProcName; // The name of the procedure
|
||||
};
|
||||
|
||||
struct ParseContext
|
||||
{
|
||||
TokArray Tokens;
|
||||
StackNode* Scope;
|
||||
};
|
||||
|
||||
enum MacroType : u16
|
||||
{
|
||||
MT_Expression, // A macro is assumed to be a expression if not resolved.
|
||||
MT_Statement,
|
||||
MT_Typename,
|
||||
MT_Block_Start, // Not Supported yet
|
||||
MT_Block_End, // Not Supported yet
|
||||
MT_Case_Statement, // Not Supported yet
|
||||
|
||||
MT_UnderlyingType = GEN_U16_MAX,
|
||||
};
|
||||
|
||||
forceinline
|
||||
TokType macrotype_to_toktype( MacroType type ) {
|
||||
switch ( type ) {
|
||||
case MT_Statement : return Tok_Preprocess_Macro_Stmt;
|
||||
case MT_Expression : return Tok_Preprocess_Macro_Expr;
|
||||
case MT_Typename : return Tok_Preprocess_Macro_Typename;
|
||||
}
|
||||
// All others unsupported for now.
|
||||
return Tok_Invalid;
|
||||
}
|
||||
|
||||
inline
|
||||
Str macrotype_to_str( MacroType type )
|
||||
{
|
||||
local_persist
|
||||
Str lookup[] = {
|
||||
{ "Statement", sizeof("Statement") - 1 },
|
||||
{ "Expression", sizeof("Expression") - 1 },
|
||||
{ "Typename", sizeof("Typename") - 1 },
|
||||
{ "Block_Start", sizeof("Block_Start") - 1 },
|
||||
{ "Block_End", sizeof("Block_End") - 1 },
|
||||
{ "Case_Statement", sizeof("Case_Statement") - 1 },
|
||||
};
|
||||
local_persist
|
||||
Str invalid = { "Invalid", sizeof("Invalid") };
|
||||
if ( type > MT_Case_Statement )
|
||||
return invalid;
|
||||
|
||||
return lookup[ type ];
|
||||
}
|
||||
|
||||
enum EMacroFlags : u16
|
||||
{
|
||||
MF_Functional = bit(0), // Macro has parameters (args expected to be passed)
|
||||
MF_Expects_Body = bit(1), // Expects to assign a braced scope to its body.
|
||||
|
||||
// lex__eat wil treat this macro as an identifier if the parser attempts to consume it as one.
|
||||
// ^^^ This is a kludge because we don't support push/pop macro pragmas rn.
|
||||
MF_Allow_As_Identifier = bit(2),
|
||||
|
||||
// lex__eat wil treat this macro as an attribute if the parser attempts to consume it as one.
|
||||
// ^^^ This a kludge because unreal has a macro that behaves as both a 'statement' and an attribute (UE_DEPRECATED, PRAGMA_ENABLE_DEPRECATION_WARNINGS, etc)
|
||||
// TODO(Ed): We can keep the MF_Allow_As_Attribute flag for macros, however, we need to add the ability of AST_Attributes to chain themselves.
|
||||
// Its thats already a thing in the standard language anyway
|
||||
// & it would allow UE_DEPRECATED, (UE_PROPERTY / UE_FUNCTION) to chain themselves as attributes of a resolved member function/variable definition
|
||||
MF_Allow_As_Attribute = bit(3),
|
||||
|
||||
// When a macro is encountered after attributes and specifiers while parsing a function, or variable:
|
||||
// It will consume the macro and treat it as resolving the definition. (Yes this is for Unreal Engine)
|
||||
// (MUST BE OF MT_Statement TYPE)
|
||||
MF_Allow_As_Definition = bit(4),
|
||||
|
||||
MF_Allow_As_Specifier = bit(5), // Created for Unreal's PURE_VIRTUAL
|
||||
|
||||
MF_Null = 0,
|
||||
MF_UnderlyingType = GEN_U16_MAX,
|
||||
};
|
||||
typedef u16 MacroFlags;
|
||||
|
||||
struct Macro
|
||||
{
|
||||
StrCached Name;
|
||||
MacroType Type;
|
||||
MacroFlags Flags;
|
||||
};
|
||||
|
||||
forceinline
|
||||
b32 macro_is_functional( Macro macro ) {
|
||||
return bitfield_is_set( b16, macro.Flags, MF_Functional );
|
||||
}
|
||||
|
||||
forceinline
|
||||
b32 macro_expects_body( Macro macro ) {
|
||||
return bitfield_is_set( b16, macro.Flags, MF_Expects_Body );
|
||||
}
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline b32 is_functional( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Functional ); }
|
||||
forceinline b32 expects_body ( Macro macro ) { return bitfield_is_set( b16, macro.Flags, MF_Expects_Body ); }
|
||||
#endif
|
||||
|
||||
typedef HashTable(Macro) MacroTable;
|
||||
@@ -9,4 +9,3 @@
|
||||
#ifndef GEN_ROLL_OWN_DEPENDENCIES
|
||||
# include "gen.dep.cpp"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "../gen.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region StaticData
|
||||
GEN_API global Context* _ctx;
|
||||
GEN_API global u32 context_counter;
|
||||
|
||||
#pragma region Constants
|
||||
GEN_API global Macro enum_underlying_macro;
|
||||
|
||||
GEN_API global Code Code_Global;
|
||||
GEN_API global Code Code_Invalid;
|
||||
|
||||
GEN_API global Code access_public;
|
||||
GEN_API global Code access_protected;
|
||||
GEN_API global Code access_private;
|
||||
|
||||
GEN_API global CodeAttributes attrib_api_export;
|
||||
GEN_API global CodeAttributes attrib_api_import;
|
||||
|
||||
GEN_API global Code module_global_fragment;
|
||||
GEN_API global Code module_private_fragment;
|
||||
|
||||
GEN_API global Code fmt_newline;
|
||||
|
||||
GEN_API global CodeParams param_varadic;
|
||||
|
||||
GEN_API global CodePragma pragma_once;
|
||||
|
||||
GEN_API global CodePreprocessCond preprocess_else;
|
||||
GEN_API global CodePreprocessCond preprocess_endif;
|
||||
|
||||
GEN_API global CodeSpecifiers spec_const;
|
||||
GEN_API global CodeSpecifiers spec_consteval;
|
||||
GEN_API global CodeSpecifiers spec_constexpr;
|
||||
GEN_API global CodeSpecifiers spec_constinit;
|
||||
GEN_API global CodeSpecifiers spec_extern_linkage;
|
||||
GEN_API global CodeSpecifiers spec_final;
|
||||
GEN_API global CodeSpecifiers spec_forceinline;
|
||||
GEN_API global CodeSpecifiers spec_global;
|
||||
GEN_API global CodeSpecifiers spec_inline;
|
||||
GEN_API global CodeSpecifiers spec_internal_linkage;
|
||||
GEN_API global CodeSpecifiers spec_local_persist;
|
||||
GEN_API global CodeSpecifiers spec_mutable;
|
||||
GEN_API global CodeSpecifiers spec_noexcept;
|
||||
GEN_API global CodeSpecifiers spec_neverinline;
|
||||
GEN_API global CodeSpecifiers spec_override;
|
||||
GEN_API global CodeSpecifiers spec_ptr;
|
||||
GEN_API global CodeSpecifiers spec_pure;
|
||||
GEN_API global CodeSpecifiers spec_ref;
|
||||
GEN_API global CodeSpecifiers spec_register;
|
||||
GEN_API global CodeSpecifiers spec_rvalue;
|
||||
GEN_API global CodeSpecifiers spec_static_member;
|
||||
GEN_API global CodeSpecifiers spec_thread_local;
|
||||
GEN_API global CodeSpecifiers spec_virtual;
|
||||
GEN_API global CodeSpecifiers spec_volatile;
|
||||
|
||||
GEN_API global CodeTypename t_empty;
|
||||
GEN_API global CodeTypename t_auto;
|
||||
GEN_API global CodeTypename t_void;
|
||||
GEN_API global CodeTypename t_int;
|
||||
GEN_API global CodeTypename t_bool;
|
||||
GEN_API global CodeTypename t_char;
|
||||
GEN_API global CodeTypename t_wchar_t;
|
||||
GEN_API global CodeTypename t_class;
|
||||
GEN_API global CodeTypename t_typename;
|
||||
|
||||
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
|
||||
GEN_API global CodeTypename t_b32;
|
||||
|
||||
GEN_API global CodeTypename t_s8;
|
||||
GEN_API global CodeTypename t_s16;
|
||||
GEN_API global CodeTypename t_s32;
|
||||
GEN_API global CodeTypename t_s64;
|
||||
|
||||
GEN_API global CodeTypename t_u8;
|
||||
GEN_API global CodeTypename t_u16;
|
||||
GEN_API global CodeTypename t_u32;
|
||||
GEN_API global CodeTypename t_u64;
|
||||
|
||||
GEN_API global CodeTypename t_ssize;
|
||||
GEN_API global CodeTypename t_usize;
|
||||
|
||||
GEN_API global CodeTypename t_f32;
|
||||
GEN_API global CodeTypename t_f64;
|
||||
#endif
|
||||
|
||||
#pragma endregion Constants
|
||||
|
||||
#pragma endregion StaticData
|
||||
@@ -0,0 +1,138 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "header_start.hpp"
|
||||
#endif
|
||||
|
||||
/*
|
||||
________ __ __ ________
|
||||
| \ | \ | \ | \
|
||||
| ▓▓▓▓▓▓▓▓_______ __ __ ______ ____ _______ | ▓▓\ | ▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______
|
||||
| ▓▓__ | \| \ | \ \ \ / \ | ▓▓▓\| ▓▓ | ▓▓ | \ | \/ \ / \ / \
|
||||
| ▓▓ \ | ▓▓▓▓▓▓▓\ ▓▓ | ▓▓ ▓▓▓▓▓▓\▓▓▓▓\ ▓▓▓▓▓▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓
|
||||
| ▓▓▓▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ | ▓▓ | ▓▓\▓▓ \ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \
|
||||
| ▓▓_____| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓ | ▓▓ | ▓▓_\▓▓▓▓▓▓\ | ▓▓ \▓▓▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\
|
||||
| ▓▓ \ ▓▓ | ▓▓\▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ \▓▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓
|
||||
\▓▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓\▓▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓
|
||||
| \__| ▓▓ ▓▓
|
||||
\▓▓ ▓▓ ▓▓
|
||||
\▓▓▓▓▓▓ \▓▓
|
||||
|
||||
*/
|
||||
|
||||
using LogFailType = ssize(*)(char const*, ...);
|
||||
|
||||
// By default this library will either crash or exit if an error is detected while generating codes.
|
||||
// Even if set to not use GEN_FATAL, GEN_FATAL will still be used for memory failures as the library is unusable when they occur.
|
||||
#ifdef GEN_DONT_USE_FATAL
|
||||
#define log_failure log_fmt
|
||||
#else
|
||||
#define log_failure GEN_FATAL
|
||||
#endif
|
||||
|
||||
enum AccessSpec : u32
|
||||
{
|
||||
AccessSpec_Default,
|
||||
AccessSpec_Private,
|
||||
AccessSpec_Protected,
|
||||
AccessSpec_Public,
|
||||
|
||||
AccessSpec_Num_AccessSpec,
|
||||
AccessSpec_Invalid,
|
||||
|
||||
AccessSpec_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(AccessSpec) == size_of(u32), "AccessSpec not u32 size" );
|
||||
|
||||
inline
|
||||
Str access_spec_to_str( AccessSpec type )
|
||||
{
|
||||
local_persist
|
||||
Str lookup[ (u32)AccessSpec_Num_AccessSpec ] = {
|
||||
{ "", sizeof( "" ) - 1 },
|
||||
{ "private", sizeof("prviate") - 1 },
|
||||
{ "private", sizeof("protected") - 1 },
|
||||
{ "public", sizeof("public") - 1 },
|
||||
};
|
||||
|
||||
Str invalid = { "Invalid", sizeof("Invalid") - 1 };
|
||||
if ( type > AccessSpec_Public )
|
||||
return invalid;
|
||||
|
||||
return lookup[ (u32)type ];
|
||||
}
|
||||
|
||||
enum CodeFlag : u32
|
||||
{
|
||||
CodeFlag_None = 0,
|
||||
CodeFlag_FunctionType = bit(0),
|
||||
CodeFlag_ParamPack = bit(1),
|
||||
CodeFlag_Module_Export = bit(2),
|
||||
CodeFlag_Module_Import = bit(3),
|
||||
|
||||
CodeFlag_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(CodeFlag) == size_of(u32), "CodeFlag not u32 size" );
|
||||
|
||||
// Used to indicate if enum definitoin is an enum class or regular enum.
|
||||
enum EnumDecl : u8
|
||||
{
|
||||
EnumDecl_Regular,
|
||||
EnumDecl_Class,
|
||||
|
||||
EnumT_SizeDef = GEN_U8_MAX,
|
||||
};
|
||||
typedef u8 EnumT;
|
||||
|
||||
enum ModuleFlag : u32
|
||||
{
|
||||
ModuleFlag_None = 0,
|
||||
ModuleFlag_Export = bit(0),
|
||||
ModuleFlag_Import = bit(1),
|
||||
|
||||
Num_ModuleFlags,
|
||||
ModuleFlag_Invalid,
|
||||
|
||||
ModuleFlag_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(ModuleFlag) == size_of(u32), "ModuleFlag not u32 size" );
|
||||
|
||||
inline
|
||||
Str module_flag_to_str( ModuleFlag flag )
|
||||
{
|
||||
local_persist
|
||||
Str lookup[ (u32)Num_ModuleFlags ] = {
|
||||
{ "__none__", sizeof("__none__") - 1 },
|
||||
{ "export", sizeof("export") - 1 },
|
||||
{ "import", sizeof("import") - 1 },
|
||||
};
|
||||
|
||||
local_persist
|
||||
Str invalid_flag = { "invalid", sizeof("invalid") };
|
||||
if ( flag > ModuleFlag_Import )
|
||||
return invalid_flag;
|
||||
|
||||
return lookup[ (u32)flag ];
|
||||
}
|
||||
|
||||
enum EPreprocessCond : u32
|
||||
{
|
||||
PreprocessCond_If,
|
||||
PreprocessCond_IfDef,
|
||||
PreprocessCond_IfNotDef,
|
||||
PreprocessCond_ElIf,
|
||||
|
||||
EPreprocessCond_SizeDef = GEN_U32_MAX,
|
||||
};
|
||||
static_assert( size_of(EPreprocessCond) == size_of(u32), "EPreprocessCond not u32 size" );
|
||||
|
||||
enum ETypenameTag : u16
|
||||
{
|
||||
Tag_None,
|
||||
Tag_Class,
|
||||
Tag_Enum,
|
||||
Tag_Struct,
|
||||
Tag_Union,
|
||||
|
||||
Tag_UnderlyingType = GEN_U16_MAX,
|
||||
};
|
||||
static_assert( size_of(ETypenameTag) == size_of(u16), "ETypenameTag is not u16 size");
|
||||
@@ -1,3 +1,8 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "macros.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Basic Types
|
||||
|
||||
#define GEN_U8_MIN 0u
|
||||
@@ -80,10 +85,10 @@ static_assert( sizeof( u16 ) == 2, "sizeof(u16) != 2" );
|
||||
static_assert( sizeof( u32 ) == 4, "sizeof(u32) != 4" );
|
||||
static_assert( sizeof( u64 ) == 8, "sizeof(u64) != 8" );
|
||||
|
||||
typedef size_t uw;
|
||||
typedef ptrdiff_t sw;
|
||||
typedef size_t usize;
|
||||
typedef ptrdiff_t ssize;
|
||||
|
||||
static_assert( sizeof( uw ) == sizeof( sw ), "sizeof(uw) != sizeof(sw)" );
|
||||
static_assert( sizeof( usize ) == sizeof( ssize ), "sizeof(usize) != sizeof(ssize)" );
|
||||
|
||||
// NOTE: (u)zpl_intptr is only here for semantic reasons really as this library will only support 32/64 bit OSes.
|
||||
#if defined( _WIN64 )
|
||||
@@ -117,5 +122,21 @@ typedef s8 b8;
|
||||
typedef s16 b16;
|
||||
typedef s32 b32;
|
||||
|
||||
#pragma endregion Basic Types
|
||||
typedef void* mem_ptr;
|
||||
typedef void const* mem_ptr_const ;
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
template<typename Type> uptr to_uptr( Type* ptr ) { return (uptr)ptr; }
|
||||
template<typename Type> sptr to_sptr( Type* ptr ) { return (sptr)ptr; }
|
||||
|
||||
template<typename Type> mem_ptr to_mem_ptr ( Type ptr ) { return (mem_ptr) ptr; }
|
||||
template<typename Type> mem_ptr_const to_mem_ptr_const( Type ptr ) { return (mem_ptr_const)ptr; }
|
||||
#else
|
||||
#define to_uptr( ptr ) ((uptr)(ptr))
|
||||
#define to_sptr( ptr ) ((sptr)(ptr))
|
||||
|
||||
#define to_mem_ptr( ptr) ((mem_ptr)ptr)
|
||||
#define to_mem_ptr_const( ptr) ((mem_ptr)ptr)
|
||||
#endif
|
||||
|
||||
#pragma endregion Basic Types
|
||||
@@ -0,0 +1,795 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "printing.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Containers
|
||||
|
||||
template<class TType> struct RemoveConst { typedef TType Type; };
|
||||
template<class TType> struct RemoveConst<const TType> { typedef TType Type; };
|
||||
template<class TType> struct RemoveConst<const TType[]> { typedef TType Type[]; };
|
||||
template<class TType, usize Size> struct RemoveConst<const TType[Size]> { typedef TType Type[Size]; };
|
||||
|
||||
template<class TType> using TRemoveConst = typename RemoveConst<TType>::Type;
|
||||
|
||||
template <class TType> struct RemovePtr { typedef TType Type; };
|
||||
template <class TType> struct RemovePtr<TType*> { typedef TType Type; };
|
||||
|
||||
template <class TType> using TRemovePtr = typename RemovePtr<TType>::Type;
|
||||
|
||||
|
||||
#pragma region Array
|
||||
#define Array(Type) Array<Type>
|
||||
|
||||
// #define array_init(Type, ...) array_init <Type>(__VA_ARGS__)
|
||||
// #define array_init_reserve(Type, ...) array_init_reserve<Type>(__VA_ARGS__)
|
||||
|
||||
struct ArrayHeader;
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
template<class Type> struct Array;
|
||||
# define get_array_underlying_type(array) typename TRemovePtr<typeof(array)>:: DataType
|
||||
#endif
|
||||
|
||||
usize array_grow_formula(ssize value);
|
||||
|
||||
template<class Type> Array<Type> array_init (AllocatorInfo allocator);
|
||||
template<class Type> Array<Type> array_init_reserve (AllocatorInfo allocator, ssize capacity);
|
||||
template<class Type> bool array_append_array (Array<Type>* array, Array<Type> other);
|
||||
template<class Type> bool array_append (Array<Type>* array, Type value);
|
||||
template<class Type> bool array_append_items (Array<Type>* array, Type* items, usize item_num);
|
||||
template<class Type> bool array_append_at (Array<Type>* array, Type item, usize idx);
|
||||
template<class Type> bool array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx);
|
||||
template<class Type> Type* array_back (Array<Type> array);
|
||||
template<class Type> void array_clear (Array<Type> array);
|
||||
template<class Type> bool array_fill (Array<Type> array, usize begin, usize end, Type value);
|
||||
template<class Type> void array_free (Array<Type>* array);
|
||||
template<class Type> bool arary_grow (Array<Type>* array, usize min_capacity);
|
||||
template<class Type> usize array_num (Array<Type> array);
|
||||
template<class Type> void arary_pop (Array<Type> array);
|
||||
template<class Type> void arary_remove_at (Array<Type> array, usize idx);
|
||||
template<class Type> bool arary_reserve (Array<Type>* array, usize new_capacity);
|
||||
template<class Type> bool arary_resize (Array<Type>* array, usize num);
|
||||
template<class Type> bool arary_set_capacity (Array<Type>* array, usize new_capacity);
|
||||
template<class Type> ArrayHeader* arary_get_header (Array<Type> array);
|
||||
|
||||
struct ArrayHeader {
|
||||
AllocatorInfo Allocator;
|
||||
usize Capacity;
|
||||
usize Num;
|
||||
};
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
template<class Type>
|
||||
struct Array
|
||||
{
|
||||
Type* Data;
|
||||
|
||||
#pragma region Member Mapping
|
||||
forceinline static Array init(AllocatorInfo allocator) { return array_init<Type>(allocator); }
|
||||
forceinline static Array init_reserve(AllocatorInfo allocator, ssize capacity) { return array_init_reserve<Type>(allocator, capacity); }
|
||||
forceinline static usize grow_formula(ssize value) { return array_grow_formula<Type>(value); }
|
||||
|
||||
forceinline bool append(Array other) { return array_append_array<Type>(this, other); }
|
||||
forceinline bool append(Type value) { return array_append<Type>(this, value); }
|
||||
forceinline bool append(Type* items, usize item_num) { return array_append_items<Type>(this, items, item_num); }
|
||||
forceinline bool append_at(Type item, usize idx) { return array_append_at<Type>(this, item, idx); }
|
||||
forceinline bool append_at(Type* items, usize item_num, usize idx) { return array_append_items_at<Type>(this, items, item_num, idx); }
|
||||
forceinline Type* back() { return array_back<Type>(* this); }
|
||||
forceinline void clear() { array_clear<Type>(* this); }
|
||||
forceinline bool fill(usize begin, usize end, Type value) { return array_fill<Type>(* this, begin, end, value); }
|
||||
forceinline void free() { array_free<Type>(this); }
|
||||
forceinline ArrayHeader* get_header() { return array_get_header<Type>(* this); }
|
||||
forceinline bool grow(usize min_capacity) { return array_grow<Type>(this, min_capacity); }
|
||||
forceinline usize num() { return array_num<Type>(*this); }
|
||||
forceinline void pop() { array_pop<Type>(* this); }
|
||||
forceinline void remove_at(usize idx) { array_remove_at<Type>(* this, idx); }
|
||||
forceinline bool reserve(usize new_capacity) { return array_reserve<Type>(this, new_capacity); }
|
||||
forceinline bool resize(usize num) { return array_resize<Type>(this, num); }
|
||||
forceinline bool set_capacity(usize new_capacity) { return array_set_capacity<Type>(this, new_capacity); }
|
||||
#pragma endregion Member Mapping
|
||||
|
||||
forceinline operator Type*() { return Data; }
|
||||
forceinline operator Type const*() const { return Data; }
|
||||
forceinline Type* begin() { return Data; }
|
||||
forceinline Type* end() { return Data + get_header()->Num; }
|
||||
|
||||
forceinline Type& operator[](ssize index) { return Data[index]; }
|
||||
forceinline Type const& operator[](ssize index) const { return Data[index]; }
|
||||
|
||||
using DataType = Type;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP && 0
|
||||
template<class Type> bool append(Array<Type>& array, Array<Type> other) { return append( & array, other ); }
|
||||
template<class Type> bool append(Array<Type>& array, Type value) { return append( & array, value ); }
|
||||
template<class Type> bool append(Array<Type>& array, Type* items, usize item_num) { return append( & array, items, item_num ); }
|
||||
template<class Type> bool append_at(Array<Type>& array, Type item, usize idx) { return append_at( & array, item, idx ); }
|
||||
template<class Type> bool append_at(Array<Type>& array, Type* items, usize item_num, usize idx) { return append_at( & array, items, item_num, idx ); }
|
||||
template<class Type> void free(Array<Type>& array) { return free( & array ); }
|
||||
template<class Type> bool grow(Array<Type>& array, usize min_capacity) { return grow( & array, min_capacity); }
|
||||
template<class Type> bool reserve(Array<Type>& array, usize new_capacity) { return reserve( & array, new_capacity); }
|
||||
template<class Type> bool resize(Array<Type>& array, usize num) { return resize( & array, num); }
|
||||
template<class Type> bool set_capacity(Array<Type>& array, usize new_capacity) { return set_capacity( & array, new_capacity); }
|
||||
|
||||
template<class Type> forceinline Type* begin(Array<Type>& array) { return array; }
|
||||
template<class Type> forceinline Type* end(Array<Type>& array) { return array + array_get_header(array)->Num; }
|
||||
template<class Type> forceinline Type* next(Array<Type>& array, Type* entry) { return entry + 1; }
|
||||
#endif
|
||||
|
||||
template<class Type> forceinline Type* array_begin(Array<Type> array) { return array; }
|
||||
template<class Type> forceinline Type* array_end(Array<Type> array) { return array + array_get_header(array)->Num; }
|
||||
template<class Type> forceinline Type* array_next(Array<Type> array, Type* entry) { return ++ entry; }
|
||||
|
||||
template<class Type> inline
|
||||
Array<Type> array_init(AllocatorInfo allocator) {
|
||||
return array_init_reserve<Type>(allocator, array_grow_formula(0));
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
Array<Type> array_init_reserve(AllocatorInfo allocator, ssize capacity)
|
||||
{
|
||||
GEN_ASSERT(capacity > 0);
|
||||
ArrayHeader* header = rcast(ArrayHeader*, alloc(allocator, sizeof(ArrayHeader) + sizeof(Type) * capacity));
|
||||
|
||||
if (header == nullptr)
|
||||
return {nullptr};
|
||||
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = capacity;
|
||||
header->Num = 0;
|
||||
|
||||
return {rcast(Type*, header + 1)};
|
||||
}
|
||||
|
||||
forceinline
|
||||
usize array_grow_formula(ssize value) {
|
||||
return 2 * value + 8;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_append_array(Array<Type>* array, Array<Type> other) {
|
||||
return array_append_items(array, (Type*)other, array_num(other));
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_append(Array<Type>* array, Type value)
|
||||
{
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
ArrayHeader* header = array_get_header(* array);
|
||||
|
||||
if (header->Num == header->Capacity)
|
||||
{
|
||||
if ( ! array_grow(array, header->Capacity))
|
||||
return false;
|
||||
header = array_get_header(* array);
|
||||
}
|
||||
|
||||
(*array)[ header->Num] = value;
|
||||
header->Num++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_append_items(Array<Type>* array, Type* items, usize item_num)
|
||||
{
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
GEN_ASSERT(items != nullptr);
|
||||
GEN_ASSERT(item_num > 0);
|
||||
ArrayHeader* header = array_get_header(* array);
|
||||
|
||||
if (header->Num + item_num > header->Capacity)
|
||||
{
|
||||
if ( ! array_grow(array, header->Capacity + item_num))
|
||||
return false;
|
||||
header = array_get_header(* array);
|
||||
}
|
||||
|
||||
mem_copy((Type*)array + header->Num, items, item_num * sizeof(Type));
|
||||
header->Num += item_num;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_append_at(Array<Type>* array, Type item, usize idx)
|
||||
{
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
ArrayHeader* header = array_get_header(* array);
|
||||
|
||||
ssize slot = idx;
|
||||
if (slot >= (ssize)(header->Num))
|
||||
slot = header->Num - 1;
|
||||
|
||||
if (slot < 0)
|
||||
slot = 0;
|
||||
|
||||
if (header->Capacity < header->Num + 1)
|
||||
{
|
||||
if ( ! array_grow(array, header->Capacity + 1))
|
||||
return false;
|
||||
|
||||
header = array_get_header(* array);
|
||||
}
|
||||
|
||||
Type* target = &(*array)[slot];
|
||||
|
||||
mem_move(target + 1, target, (header->Num - slot) * sizeof(Type));
|
||||
header->Num++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_append_items_at(Array<Type>* array, Type* items, usize item_num, usize idx)
|
||||
{
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
ArrayHeader* header = get_header(array);
|
||||
|
||||
if (idx >= header->Num)
|
||||
{
|
||||
return array_append_items(array, items, item_num);
|
||||
}
|
||||
|
||||
if (item_num > header->Capacity)
|
||||
{
|
||||
if (! grow(array, header->Capacity + item_num))
|
||||
return false;
|
||||
|
||||
header = get_header(array);
|
||||
}
|
||||
|
||||
Type* target = array.Data + idx + item_num;
|
||||
Type* src = array.Data + idx;
|
||||
|
||||
mem_move(target, src, (header->Num - idx) * sizeof(Type));
|
||||
mem_copy(src, items, item_num * sizeof(Type));
|
||||
header->Num += item_num;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
Type* array_back(Array<Type> array)
|
||||
{
|
||||
GEN_ASSERT(array != nullptr);
|
||||
|
||||
ArrayHeader* header = array_get_header(array);
|
||||
if (header->Num <= 0)
|
||||
return nullptr;
|
||||
|
||||
return & (array)[header->Num - 1];
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
void array_clear(Array<Type> array) {
|
||||
GEN_ASSERT(array != nullptr);
|
||||
ArrayHeader* header = array_get_header(array);
|
||||
header->Num = 0;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_fill(Array<Type> array, usize begin, usize end, Type value)
|
||||
{
|
||||
GEN_ASSERT(array != nullptr);
|
||||
GEN_ASSERT(begin <= end);
|
||||
ArrayHeader* header = array_get_header(array);
|
||||
|
||||
if (begin < 0 || end > header->Num)
|
||||
return false;
|
||||
|
||||
for (ssize idx = ssize(begin); idx < ssize(end); idx++) {
|
||||
array[idx] = value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Type> forceinline
|
||||
void array_free(Array<Type>* array) {
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
ArrayHeader* header = array_get_header(* array);
|
||||
allocator_free(header->Allocator, header);
|
||||
Type** Data = (Type**)array;
|
||||
*Data = nullptr;
|
||||
}
|
||||
|
||||
template<class Type> forceinline
|
||||
ArrayHeader* array_get_header(Array<Type> array) {
|
||||
GEN_ASSERT(array != nullptr);
|
||||
Type* Data = array;
|
||||
|
||||
using NonConstType = TRemoveConst<Type>;
|
||||
return rcast(ArrayHeader*, const_cast<NonConstType*>(Data)) - 1;
|
||||
}
|
||||
|
||||
template<class Type> forceinline
|
||||
bool array_grow(Array<Type>* array, usize min_capacity)
|
||||
{
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
GEN_ASSERT( min_capacity > 0 );
|
||||
ArrayHeader* header = array_get_header(* array);
|
||||
usize new_capacity = array_grow_formula(header->Capacity);
|
||||
|
||||
if (new_capacity < min_capacity)
|
||||
new_capacity = min_capacity;
|
||||
|
||||
return array_set_capacity(array, new_capacity);
|
||||
}
|
||||
|
||||
template<class Type> forceinline
|
||||
usize array_num(Array<Type> array) {
|
||||
GEN_ASSERT(array != nullptr);
|
||||
return array_get_header(array)->Num;
|
||||
}
|
||||
|
||||
template<class Type> forceinline
|
||||
void array_pop(Array<Type> array) {
|
||||
GEN_ASSERT(array != nullptr);
|
||||
ArrayHeader* header = array_get_header(array);
|
||||
GEN_ASSERT(header->Num > 0);
|
||||
header->Num--;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
void array_remove_at(Array<Type> array, usize idx)
|
||||
{
|
||||
GEN_ASSERT(array != nullptr);
|
||||
ArrayHeader* header = array_get_header(array);
|
||||
GEN_ASSERT(idx < header->Num);
|
||||
|
||||
mem_move(array + idx, array + idx + 1, sizeof(Type) * (header->Num - idx - 1));
|
||||
header->Num--;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_reserve(Array<Type>* array, usize new_capacity)
|
||||
{
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
ArrayHeader* header = array_get_header(array);
|
||||
|
||||
if (header->Capacity < new_capacity)
|
||||
return set_capacity(array, new_capacity);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_resize(Array<Type>* array, usize num)
|
||||
{
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
ArrayHeader* header = array_get_header(* array);
|
||||
|
||||
if (header->Capacity < num) {
|
||||
if (! array_grow( array, num))
|
||||
return false;
|
||||
header = array_get_header(* array);
|
||||
}
|
||||
|
||||
header->Num = num;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Type> inline
|
||||
bool array_set_capacity(Array<Type>* array, usize new_capacity)
|
||||
{
|
||||
GEN_ASSERT( array != nullptr);
|
||||
GEN_ASSERT(* array != nullptr);
|
||||
ArrayHeader* header = array_get_header(* array);
|
||||
|
||||
if (new_capacity == header->Capacity)
|
||||
return true;
|
||||
|
||||
if (new_capacity < header->Num)
|
||||
{
|
||||
header->Num = new_capacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize size = sizeof(ArrayHeader) + sizeof(Type) * new_capacity;
|
||||
ArrayHeader* new_header = rcast(ArrayHeader*, alloc(header->Allocator, size));
|
||||
|
||||
if (new_header == nullptr)
|
||||
return false;
|
||||
|
||||
mem_move(new_header, header, sizeof(ArrayHeader) + sizeof(Type) * header->Num);
|
||||
|
||||
new_header->Capacity = new_capacity;
|
||||
|
||||
allocator_free(header->Allocator, header);
|
||||
|
||||
Type** Data = (Type**)array;
|
||||
* Data = rcast(Type*, new_header + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// These are intended for use in the base library of gencpp and the C-variant of the library
|
||||
// It provides a interoperability between the C++ and C implementation of arrays. (not letting these do any crazy substiution though)
|
||||
// They are undefined in gen.hpp and gen.cpp at the end of the files.
|
||||
// We cpp library expects the user to use the regular calls as they can resolve the type fine.
|
||||
|
||||
#define array_init(type, allocator) array_init <type> (allocator )
|
||||
#define array_init_reserve(type, allocator, cap) array_init_reserve <type> (allocator, cap)
|
||||
#define array_append_array(array, other) array_append_array < get_array_underlying_type(array) > (& array, other )
|
||||
#define array_append(array, value) array_append < get_array_underlying_type(array) > (& array, value )
|
||||
#define array_append_items(array, items, item_num) array_append_items < get_array_underlying_type(array) > (& array, items, item_num )
|
||||
#define array_append_at(array, item, idx ) array_append_at < get_array_underlying_type(array) > (& array, item, idx )
|
||||
#define array_append_at_items(array, items, item_num, idx) array_append_at_items< get_array_underlying_type(array) > (& items, item_num, idx )
|
||||
#define array_back(array) array_back < get_array_underlying_type(array) > (array )
|
||||
#define array_clear(array) array_clear < get_array_underlying_type(array) > (array )
|
||||
#define array_fill(array, begin, end, value) array_fill < get_array_underlying_type(array) > (array, begin, end, value )
|
||||
#define array_free(array) array_free < get_array_underlying_type(array) > (& array )
|
||||
#define arary_grow(array, min_capacity) arary_grow < get_array_underlying_type(array) > (& array, min_capacity)
|
||||
#define array_num(array) array_num < get_array_underlying_type(array) > (array )
|
||||
#define arary_pop(array) arary_pop < get_array_underlying_type(array) > (array )
|
||||
#define arary_remove_at(array, idx) arary_remove_at < get_array_underlying_type(array) > (idx)
|
||||
#define arary_reserve(array, new_capacity) arary_reserve < get_array_underlying_type(array) > (& array, new_capacity )
|
||||
#define arary_resize(array, num) arary_resize < get_array_underlying_type(array) > (& array, num)
|
||||
#define arary_set_capacity(new_capacity) arary_set_capacity < get_array_underlying_type(array) > (& array, new_capacity )
|
||||
#define arary_get_header(array) arary_get_header < get_array_underlying_type(array) > (array )
|
||||
|
||||
#pragma endregion Array
|
||||
|
||||
#pragma region HashTable
|
||||
#define HashTable(Type) HashTable<Type>
|
||||
|
||||
template<class Type> struct HashTable;
|
||||
|
||||
#ifndef get_hashtable_underlying_type
|
||||
#define get_hashtable_underlying_type(table) typename TRemovePtr<typeof(table)>:: DataType
|
||||
#endif
|
||||
|
||||
struct HashTableFindResult {
|
||||
ssize HashIndex;
|
||||
ssize PrevIndex;
|
||||
ssize EntryIndex;
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
struct HashTableEntry {
|
||||
u64 Key;
|
||||
ssize Next;
|
||||
Type Value;
|
||||
};
|
||||
|
||||
#define HashTableEntry(Type) HashTableEntry<Type>
|
||||
|
||||
template<class Type> HashTable<Type> hashtable_init (AllocatorInfo allocator);
|
||||
template<class Type> HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num);
|
||||
template<class Type> void hashtable_clear (HashTable<Type> table);
|
||||
template<class Type> void hashtable_destroy (HashTable<Type>* table);
|
||||
template<class Type> Type* hashtable_get (HashTable<Type> table, u64 key);
|
||||
template<class Type> void hashtable_grow (HashTable<Type>* table);
|
||||
template<class Type> void hashtable_rehash (HashTable<Type>* table, ssize new_num);
|
||||
template<class Type> void hashtable_rehash_fast (HashTable<Type> table);
|
||||
template<class Type> void hashtable_remove (HashTable<Type> table, u64 key);
|
||||
template<class Type> void hashtable_remove_entry(HashTable<Type> table, ssize idx);
|
||||
template<class Type> void hashtable_set (HashTable<Type>* table, u64 key, Type value);
|
||||
template<class Type> ssize hashtable_slot (HashTable<Type> table, u64 key);
|
||||
template<class Type> void hashtable_map (HashTable<Type> table, void (*map_proc)(u64 key, Type value));
|
||||
template<class Type> void hashtable_map_mut (HashTable<Type> table, void (*map_proc)(u64 key, Type* value));
|
||||
|
||||
template<class Type> ssize hashtable__add_entry (HashTable<Type>* table, u64 key);
|
||||
template<class Type> HashTableFindResult hashtable__find (HashTable<Type> table, u64 key);
|
||||
template<class Type> bool hashtable__full (HashTable<Type> table);
|
||||
|
||||
static constexpr f32 HashTable_CriticalLoadScale = 0.7f;
|
||||
|
||||
template<typename Type>
|
||||
struct HashTable
|
||||
{
|
||||
Array<ssize> Hashes;
|
||||
Array<HashTableEntry<Type>> Entries;
|
||||
|
||||
#if ! GEN_C_LIKE_CPP
|
||||
#pragma region Member Mapping
|
||||
forceinline static HashTable init(AllocatorInfo allocator) { return hashtable_init<Type>(allocator); }
|
||||
forceinline static HashTable init_reserve(AllocatorInfo allocator, usize num) { return hashtable_init_reserve<Type>(allocator, num); }
|
||||
|
||||
forceinline void clear() { clear<Type>(*this); }
|
||||
forceinline void destroy() { destroy<Type>(*this); }
|
||||
forceinline Type* get(u64 key) { return get<Type>(*this, key); }
|
||||
forceinline void grow() { grow<Type>(*this); }
|
||||
forceinline void rehash(ssize new_num) { rehash<Type>(*this, new_num); }
|
||||
forceinline void rehash_fast() { rehash_fast<Type>(*this); }
|
||||
forceinline void remove(u64 key) { remove<Type>(*this, key); }
|
||||
forceinline void remove_entry(ssize idx) { remove_entry<Type>(*this, idx); }
|
||||
forceinline void set(u64 key, Type value) { set<Type>(*this, key, value); }
|
||||
forceinline ssize slot(u64 key) { return slot<Type>(*this, key); }
|
||||
forceinline void map(void (*proc)(u64, Type)) { map<Type>(*this, proc); }
|
||||
forceinline void map_mut(void (*proc)(u64, Type*)) { map_mut<Type>(*this, proc); }
|
||||
#pragma endregion Member Mapping
|
||||
#endif
|
||||
|
||||
using DataType = Type;
|
||||
};
|
||||
|
||||
#if GEN_SUPPORT_CPP_REFERENCES
|
||||
template<class Type> void destroy (HashTable<Type>& table) { destroy(& table); }
|
||||
template<class Type> void grow (HashTable<Type>& table) { grow(& table); }
|
||||
template<class Type> void rehash (HashTable<Type>& table, ssize new_num) { rehash(& table, new_num); }
|
||||
template<class Type> void set (HashTable<Type>& table, u64 key, Type value) { set(& table, key, value); }
|
||||
template<class Type> ssize add_entry(HashTable<Type>& table, u64 key) { add_entry(& table, key); }
|
||||
#endif
|
||||
|
||||
template<typename Type> inline
|
||||
HashTable<Type> hashtable_init(AllocatorInfo allocator) {
|
||||
HashTable<Type> result = hashtable_init_reserve<Type>(allocator, 8);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Type> inline
|
||||
HashTable<Type> hashtable_init_reserve(AllocatorInfo allocator, usize num)
|
||||
{
|
||||
HashTable<Type> result = { { nullptr }, { nullptr } };
|
||||
|
||||
result.Hashes = array_init_reserve<ssize>(allocator, num);
|
||||
array_get_header(result.Hashes)->Num = num;
|
||||
array_resize(& result.Hashes, num);
|
||||
array_fill(result.Hashes, 0, num, (ssize)-1);
|
||||
|
||||
result.Entries = array_init_reserve<HashTableEntry<Type>>(allocator, num);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
void hashtable_clear(HashTable<Type> table) {
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
array_clear(table.Entries);
|
||||
array_fill(table.Hashes, 0, array_num(table.Hashes), (ssize)-1);
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
void hashtable_destroy(HashTable<Type>* table) {
|
||||
GEN_ASSERT_NOT_NULL(table->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table->Entries);
|
||||
if (table->Hashes && array_get_header(table->Hashes)->Capacity) {
|
||||
array_free(table->Hashes);
|
||||
array_free(table->Entries);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
Type* hashtable_get(HashTable<Type> table, u64 key) {
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
ssize idx = hashtable__find(table, key).EntryIndex;
|
||||
if (idx >= 0)
|
||||
return & table.Entries[idx].Value;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
void hashtable_map(HashTable<Type> table, void (*map_proc)(u64 key, Type value)) {
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
GEN_ASSERT_NOT_NULL(map_proc);
|
||||
|
||||
for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) {
|
||||
map_proc(table.Entries[idx].Key, table.Entries[idx].Value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
void hashtable_map_mut(HashTable<Type> table, void (*map_proc)(u64 key, Type* value)) {
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
GEN_ASSERT_NOT_NULL(map_proc);
|
||||
|
||||
for (ssize idx = 0; idx < ssize(num(table.Entries)); ++idx) {
|
||||
map_proc(table.Entries[idx].Key, & table.Entries[idx].Value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
void hashtable_grow(HashTable<Type>* table) {
|
||||
GEN_ASSERT_NOT_NULL(table);
|
||||
GEN_ASSERT_NOT_NULL(table->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table->Entries);
|
||||
ssize new_num = array_grow_formula( array_num(table->Entries));
|
||||
hashtable_rehash(table, new_num);
|
||||
}
|
||||
|
||||
template<typename Type> inline
|
||||
void hashtable_rehash(HashTable<Type>* table, ssize new_num)
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(table);
|
||||
GEN_ASSERT_NOT_NULL(table->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table->Entries);
|
||||
ssize last_added_index;
|
||||
HashTable<Type> new_ht = hashtable_init_reserve<Type>( array_get_header(table->Hashes)->Allocator, new_num);
|
||||
|
||||
for (ssize idx = 0; idx < ssize( array_num(table->Entries)); ++idx)
|
||||
{
|
||||
HashTableFindResult find_result;
|
||||
HashTableEntry<Type>& entry = table->Entries[idx];
|
||||
|
||||
find_result = hashtable__find(new_ht, entry.Key);
|
||||
last_added_index = hashtable__add_entry(& new_ht, entry.Key);
|
||||
|
||||
if (find_result.PrevIndex < 0)
|
||||
new_ht.Hashes[find_result.HashIndex] = last_added_index;
|
||||
else
|
||||
new_ht.Entries[find_result.PrevIndex].Next = last_added_index;
|
||||
|
||||
new_ht.Entries[last_added_index].Next = find_result.EntryIndex;
|
||||
new_ht.Entries[last_added_index].Value = entry.Value;
|
||||
}
|
||||
|
||||
hashtable_destroy(table);
|
||||
* table = new_ht;
|
||||
}
|
||||
|
||||
template<typename Type> inline
|
||||
void hashtable_rehash_fast(HashTable<Type> table)
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
ssize idx;
|
||||
|
||||
for (idx = 0; idx < ssize(num(table.Entries)); idx++)
|
||||
table.Entries[idx].Next = -1;
|
||||
|
||||
for (idx = 0; idx < ssize(num(table.Hashes)); idx++)
|
||||
table.Hashes[idx] = -1;
|
||||
|
||||
for (idx = 0; idx < ssize(num(table.Entries)); idx++)
|
||||
{
|
||||
HashTableEntry<Type>* entry;
|
||||
HashTableFindResult find_result;
|
||||
|
||||
entry = &table.Entries[idx];
|
||||
find_result = find(table, entry->Key);
|
||||
|
||||
if (find_result.PrevIndex < 0)
|
||||
table.Hashes[find_result.HashIndex] = idx;
|
||||
else
|
||||
table.Entries[find_result.PrevIndex].Next = idx;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
void hashtable_remove(HashTable<Type> table, u64 key) {
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
HashTableFindResult find_result = find(table, key);
|
||||
|
||||
if (find_result.EntryIndex >= 0) {
|
||||
remove_at(table.Entries, find_result.EntryIndex);
|
||||
rehash_fast(table);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
void hashtable_remove_entry(HashTable<Type> table, ssize idx) {
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
remove_at(table.Entries, idx);
|
||||
}
|
||||
|
||||
template<typename Type> inline
|
||||
void hashtable_set(HashTable<Type>* table, u64 key, Type value)
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(table);
|
||||
GEN_ASSERT_NOT_NULL(table->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table->Entries);
|
||||
ssize idx;
|
||||
HashTableFindResult find_result;
|
||||
|
||||
if (hashtable_full(* table))
|
||||
hashtable_grow(table);
|
||||
|
||||
find_result = hashtable__find(* table, key);
|
||||
if (find_result.EntryIndex >= 0) {
|
||||
idx = find_result.EntryIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = hashtable__add_entry(table, key);
|
||||
|
||||
if (find_result.PrevIndex >= 0) {
|
||||
table->Entries[find_result.PrevIndex].Next = idx;
|
||||
}
|
||||
else {
|
||||
table->Hashes[find_result.HashIndex] = idx;
|
||||
}
|
||||
}
|
||||
|
||||
table->Entries[idx].Value = value;
|
||||
|
||||
if (hashtable_full(* table))
|
||||
hashtable_grow(table);
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
ssize hashtable_slot(HashTable<Type> table, u64 key) {
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
for (ssize idx = 0; idx < ssize(num(table.Hashes)); ++idx)
|
||||
if (table.Hashes[idx] == key)
|
||||
return idx;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
ssize hashtable__add_entry(HashTable<Type>* table, u64 key) {
|
||||
GEN_ASSERT_NOT_NULL(table);
|
||||
GEN_ASSERT_NOT_NULL(table->Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table->Entries);
|
||||
ssize idx;
|
||||
HashTableEntry<Type> entry = { key, -1 };
|
||||
|
||||
idx = array_num(table->Entries);
|
||||
array_append( table->Entries, entry);
|
||||
return idx;
|
||||
}
|
||||
|
||||
template<typename Type> inline
|
||||
HashTableFindResult hashtable__find(HashTable<Type> table, u64 key)
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
HashTableFindResult result = { -1, -1, -1 };
|
||||
|
||||
if (array_num(table.Hashes) > 0)
|
||||
{
|
||||
result.HashIndex = key % array_num(table.Hashes);
|
||||
result.EntryIndex = table.Hashes[result.HashIndex];
|
||||
|
||||
while (result.EntryIndex >= 0)
|
||||
{
|
||||
if (table.Entries[result.EntryIndex].Key == key)
|
||||
break;
|
||||
|
||||
result.PrevIndex = result.EntryIndex;
|
||||
result.EntryIndex = table.Entries[result.EntryIndex].Next;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Type> forceinline
|
||||
b32 hashtable_full(HashTable<Type> table) {
|
||||
GEN_ASSERT_NOT_NULL(table.Hashes);
|
||||
GEN_ASSERT_NOT_NULL(table.Entries);
|
||||
usize critical_load = usize(HashTable_CriticalLoadScale * f32(array_num(table.Hashes)));
|
||||
b32 result = array_num(table.Entries) > critical_load;
|
||||
return result;
|
||||
}
|
||||
|
||||
#define hashtable_init(type, allocator) hashtable_init <type >(allocator)
|
||||
#define hashtable_init_reserve(type, allocator, num) hashtable_init_reserve<type >(allocator, num)
|
||||
#define hashtable_clear(table) hashtable_clear < get_hashtable_underlying_type(table) >(table)
|
||||
#define hashtable_destroy(table) hashtable_destroy < get_hashtable_underlying_type(table) >(& table)
|
||||
#define hashtable_get(table, key) hashtable_get < get_hashtable_underlying_type(table) >(table, key)
|
||||
#define hashtable_grow(table) hashtable_grow < get_hashtable_underlying_type(table) >(& table)
|
||||
#define hashtable_rehash(table, new_num) hashtable_rehash < get_hashtable_underlying_type(table) >(& table, new_num)
|
||||
#define hashtable_rehash_fast(table) hashtable_rehash_fast < get_hashtable_underlying_type(table) >(table)
|
||||
#define hashtable_remove(table, key) hashtable_remove < get_hashtable_underlying_type(table) >(table, key)
|
||||
#define hashtable_remove_entry(table, idx) hashtable_remove_entry< get_hashtable_underlying_type(table) >(table, idx)
|
||||
#define hashtable_set(table, key, value) hashtable_set < get_hashtable_underlying_type(table) >(& table, key, value)
|
||||
#define hashtable_slot(table, key) hashtable_slot < get_hashtable_underlying_type(table) >(table, key)
|
||||
#define hashtable_map(table, map_proc) hashtable_map < get_hashtable_underlying_type(table) >(table, map_proc)
|
||||
#define hashtable_map_mut(table, map_proc) hashtable_map_mut < get_hashtable_underlying_type(table) >(table, map_proc)
|
||||
|
||||
//#define hashtable_add_entry(table, key) hashtable_add_entry < get_hashtable_underlying_type(table) >(& table, key)
|
||||
//#define hashtable_find(table, key) hashtable_find < get_hashtable_underlying_type(table) >(table, key)
|
||||
//#define hashtable_full(table) hashtable_full < get_hashtable_underlying_type(table) >(table)
|
||||
|
||||
#pragma endregion HashTable
|
||||
|
||||
#pragma endregion Containers
|
||||
@@ -1,8 +1,13 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "src_start.cpp"
|
||||
#endif
|
||||
|
||||
#pragma region Debug
|
||||
|
||||
void assert_handler( char const* condition, char const* file, s32 line, char const* msg, ... )
|
||||
void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... )
|
||||
{
|
||||
_printf_err( "%s:(%d): Assert Failure: ", file, line );
|
||||
_printf_err( "%s - %s:(%d): Assert Failure: ", file, function, line );
|
||||
|
||||
if ( condition )
|
||||
_printf_err( "`%s` \n", condition );
|
||||
@@ -39,4 +44,3 @@ s32 assert_crash( char const* condition )
|
||||
#endif
|
||||
|
||||
#pragma endregion Debug
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "dependencies/platform.hpp"
|
||||
# include "dependencies/macros.hpp"
|
||||
# include "basic_types.hpp"
|
||||
# include "macros.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Debug
|
||||
|
||||
#if GEN_BUILD_DEBUG
|
||||
# if defined( GEN_COMPILER_MSVC )
|
||||
# if _MSC_VER < 1300
|
||||
// #pragma message("GEN_BUILD_DEBUG: __asm int 3")
|
||||
# define GEN_DEBUG_TRAP() __asm int 3 /* Trap to debugger! */
|
||||
# else
|
||||
// #pragma message("GEN_BUILD_DEBUG: __debugbreak()")
|
||||
# define GEN_DEBUG_TRAP() __debugbreak()
|
||||
# endif
|
||||
# elif defined( GEN_COMPILER_TINYC )
|
||||
# define GEN_DEBUG_TRAP() process_exit( 1 )
|
||||
# else
|
||||
# define GEN_DEBUG_TRAP() __builtin_trap()
|
||||
# endif
|
||||
#else
|
||||
// #pragma message("GEN_BUILD_DEBUG: omitted")
|
||||
# define GEN_DEBUG_TRAP()
|
||||
#endif
|
||||
|
||||
#define GEN_ASSERT( cond ) GEN_ASSERT_MSG( cond, NULL )
|
||||
|
||||
#define GEN_ASSERT_MSG( cond, msg, ... ) \
|
||||
do \
|
||||
{ \
|
||||
if ( ! ( cond ) ) \
|
||||
{ \
|
||||
assert_handler( #cond, __FILE__, __func__, scast( s64, __LINE__ ), msg, ##__VA_ARGS__ ); \
|
||||
GEN_DEBUG_TRAP(); \
|
||||
} \
|
||||
} while ( 0 )
|
||||
|
||||
#define GEN_ASSERT_NOT_NULL( ptr ) GEN_ASSERT_MSG( ( ptr ) != NULL, #ptr " must not be NULL" )
|
||||
|
||||
// NOTE: Things that shouldn't happen with a message!
|
||||
#define GEN_PANIC( msg, ... ) GEN_ASSERT_MSG( 0, msg, ##__VA_ARGS__ )
|
||||
|
||||
#if GEN_BUILD_DEBUG
|
||||
#define GEN_FATAL( ... ) \
|
||||
do \
|
||||
{ \
|
||||
local_persist thread_local \
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 }; \
|
||||
\
|
||||
c_str_fmt(buf, GEN_PRINTF_MAXLEN, __VA_ARGS__); \
|
||||
GEN_PANIC(buf); \
|
||||
} \
|
||||
while (0)
|
||||
#else
|
||||
|
||||
# define GEN_FATAL( ... ) \
|
||||
do \
|
||||
{ \
|
||||
c_str_fmt_out_err( __VA_ARGS__ ); \
|
||||
GEN_DEBUG_TRAP(); \
|
||||
process_exit(1); \
|
||||
} \
|
||||
while (0)
|
||||
#endif
|
||||
|
||||
GEN_API void assert_handler( char const* condition, char const* file, char const* function, s32 line, char const* msg, ... );
|
||||
GEN_API s32 assert_crash( char const* condition );
|
||||
GEN_API void process_exit( u32 code );
|
||||
|
||||
#pragma endregion Debug
|
||||
@@ -1,25 +1,31 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "strings.cpp"
|
||||
#endif
|
||||
|
||||
#pragma region File Handling
|
||||
|
||||
#if defined( GEN_SYSTEM_WINDOWS ) || defined( GEN_SYSTEM_CYGWIN )
|
||||
|
||||
internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_len_ )
|
||||
internal
|
||||
wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, ssize* w_len_ )
|
||||
{
|
||||
wchar_t* w_text = NULL;
|
||||
sw len = 0, w_len = 0, w_len1 = 0;
|
||||
ssize len = 0, w_len = 0, w_len1 = 0;
|
||||
if ( text == NULL )
|
||||
{
|
||||
if ( w_len_ )
|
||||
*w_len_ = w_len;
|
||||
return NULL;
|
||||
}
|
||||
len = str_len( text );
|
||||
len = c_str_len( text );
|
||||
if ( len == 0 )
|
||||
{
|
||||
if ( w_len_ )
|
||||
*w_len_ = w_len;
|
||||
return NULL;
|
||||
}
|
||||
w_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, zpl_cast( int ) len, NULL, 0 );
|
||||
w_len = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), NULL, 0 );
|
||||
if ( w_len == 0 )
|
||||
{
|
||||
if ( w_len_ )
|
||||
@@ -27,10 +33,10 @@ internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_
|
||||
return NULL;
|
||||
}
|
||||
w_text = alloc_array( a, wchar_t, w_len + 1 );
|
||||
w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, zpl_cast( int ) len, w_text, zpl_cast( int ) w_len );
|
||||
w_len1 = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, text, scast( int, len), w_text, scast( int, w_len) );
|
||||
if ( w_len1 == 0 )
|
||||
{
|
||||
free( a, w_text );
|
||||
allocator_free( a, w_text );
|
||||
if ( w_len_ )
|
||||
*w_len_ = 0;
|
||||
return NULL;
|
||||
@@ -41,7 +47,8 @@ internal wchar_t* _alloc_utf8_to_ucs2( AllocatorInfo a, char const* text, sw* w_
|
||||
return w_text;
|
||||
}
|
||||
|
||||
internal GEN_FILE_SEEK_PROC( _win32_file_seek )
|
||||
internal
|
||||
GEN_FILE_SEEK_PROC( _win32_file_seek )
|
||||
{
|
||||
LARGE_INTEGER li_offset;
|
||||
li_offset.QuadPart = offset;
|
||||
@@ -55,12 +62,13 @@ internal GEN_FILE_SEEK_PROC( _win32_file_seek )
|
||||
return true;
|
||||
}
|
||||
|
||||
internal GEN_FILE_READ_AT_PROC( _win32_file_read )
|
||||
internal
|
||||
GEN_FILE_READ_AT_PROC( _win32_file_read )
|
||||
{
|
||||
// unused( stop_at_newline );
|
||||
b32 result = false;
|
||||
_win32_file_seek( fd, offset, ESeekWhence_BEGIN, NULL );
|
||||
DWORD size_ = zpl_cast( DWORD )( size > GEN_I32_MAX ? GEN_I32_MAX : size );
|
||||
DWORD size_ = scast( DWORD, ( size > GEN_I32_MAX ? GEN_I32_MAX : size ));
|
||||
DWORD bytes_read_;
|
||||
if ( ReadFile( fd.p, buffer, size_, &bytes_read_, NULL ) )
|
||||
{
|
||||
@@ -72,9 +80,10 @@ internal GEN_FILE_READ_AT_PROC( _win32_file_read )
|
||||
return result;
|
||||
}
|
||||
|
||||
internal GEN_FILE_WRITE_AT_PROC( _win32_file_write )
|
||||
internal
|
||||
GEN_FILE_WRITE_AT_PROC( _win32_file_write )
|
||||
{
|
||||
DWORD size_ = zpl_cast( DWORD )( size > GEN_I32_MAX ? GEN_I32_MAX : size );
|
||||
DWORD size_ = scast( DWORD, ( size > GEN_I32_MAX ? GEN_I32_MAX : size ));
|
||||
DWORD bytes_written_;
|
||||
_win32_file_seek( fd, offset, ESeekWhence_BEGIN, NULL );
|
||||
if ( WriteFile( fd.p, buffer, size_, &bytes_written_, NULL ) )
|
||||
@@ -86,14 +95,16 @@ internal GEN_FILE_WRITE_AT_PROC( _win32_file_write )
|
||||
return false;
|
||||
}
|
||||
|
||||
internal GEN_FILE_CLOSE_PROC( _win32_file_close )
|
||||
internal
|
||||
GEN_FILE_CLOSE_PROC( _win32_file_close )
|
||||
{
|
||||
CloseHandle( fd.p );
|
||||
}
|
||||
|
||||
FileOperations const default_file_operations = { _win32_file_read, _win32_file_write, _win32_file_seek, _win32_file_close };
|
||||
|
||||
neverinline GEN_FILE_OPEN_PROC( _win32_file_open )
|
||||
neverinline
|
||||
GEN_FILE_OPEN_PROC( _win32_file_open )
|
||||
{
|
||||
DWORD desired_access;
|
||||
DWORD creation_disposition;
|
||||
@@ -134,7 +145,7 @@ neverinline GEN_FILE_OPEN_PROC( _win32_file_open )
|
||||
w_text = _alloc_utf8_to_ucs2( heap(), filename, NULL );
|
||||
handle = CreateFileW( w_text, desired_access, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL );
|
||||
|
||||
free( heap(), w_text );
|
||||
allocator_free( heap(), w_text );
|
||||
|
||||
if ( handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
@@ -171,7 +182,8 @@ neverinline GEN_FILE_OPEN_PROC( _win32_file_open )
|
||||
#else // POSIX
|
||||
# include <fcntl.h>
|
||||
|
||||
internal GEN_FILE_SEEK_PROC( _posix_file_seek )
|
||||
internal
|
||||
GEN_FILE_SEEK_PROC( _posix_file_seek )
|
||||
{
|
||||
# if defined( GEN_SYSTEM_OSX )
|
||||
s64 res = lseek( fd.i, offset, whence );
|
||||
@@ -185,10 +197,11 @@ internal GEN_FILE_SEEK_PROC( _posix_file_seek )
|
||||
return true;
|
||||
}
|
||||
|
||||
internal GEN_FILE_READ_AT_PROC( _posix_file_read )
|
||||
internal
|
||||
GEN_FILE_READ_AT_PROC( _posix_file_read )
|
||||
{
|
||||
unused( stop_at_newline );
|
||||
sw res = pread( fd.i, buffer, size, offset );
|
||||
ssize res = pread( fd.i, buffer, size, offset );
|
||||
if ( res < 0 )
|
||||
return false;
|
||||
if ( bytes_read )
|
||||
@@ -196,19 +209,20 @@ internal GEN_FILE_READ_AT_PROC( _posix_file_read )
|
||||
return true;
|
||||
}
|
||||
|
||||
internal GEN_FILE_WRITE_AT_PROC( _posix_file_write )
|
||||
internal
|
||||
GEN_FILE_WRITE_AT_PROC( _posix_file_write )
|
||||
{
|
||||
sw res;
|
||||
ssize res;
|
||||
s64 curr_offset = 0;
|
||||
_posix_file_seek( fd, 0, ESeekWhence_CURRENT, &curr_offset );
|
||||
if ( curr_offset == offset )
|
||||
{
|
||||
// NOTE: Writing to stdout et al. doesn't like pwrite for numerous reasons
|
||||
res = write( zpl_cast( int ) fd.i, buffer, size );
|
||||
res = write( scast( int, fd.i), buffer, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
res = pwrite( zpl_cast( int ) fd.i, buffer, size, offset );
|
||||
res = pwrite( scast( int, fd.i), buffer, size, offset );
|
||||
}
|
||||
if ( res < 0 )
|
||||
return false;
|
||||
@@ -217,14 +231,16 @@ internal GEN_FILE_WRITE_AT_PROC( _posix_file_write )
|
||||
return true;
|
||||
}
|
||||
|
||||
internal GEN_FILE_CLOSE_PROC( _posix_file_close )
|
||||
internal
|
||||
GEN_FILE_CLOSE_PROC( _posix_file_close )
|
||||
{
|
||||
close( fd.i );
|
||||
}
|
||||
|
||||
FileOperations const default_file_operations = { _posix_file_read, _posix_file_write, _posix_file_seek, _posix_file_close };
|
||||
|
||||
neverinline GEN_FILE_OPEN_PROC( _posix_file_open )
|
||||
neverinline
|
||||
GEN_FILE_OPEN_PROC( _posix_file_open )
|
||||
{
|
||||
s32 os_mode;
|
||||
switch ( mode & GEN_FILE_MODES )
|
||||
@@ -268,7 +284,7 @@ neverinline GEN_FILE_OPEN_PROC( _posix_file_open )
|
||||
|
||||
internal void _dirinfo_free_entry( DirEntry* entry );
|
||||
|
||||
// TODO : Is this a bad idea?
|
||||
// TODO(zpl) : Is this a bad idea?
|
||||
global b32 _std_file_set = false;
|
||||
global FileInfo _std_files[ EFileStandard_COUNT ] = {
|
||||
{
|
||||
@@ -324,7 +340,7 @@ FileError file_close( FileInfo* f )
|
||||
return EFileError_INVALID;
|
||||
|
||||
if ( f->filename )
|
||||
free( heap(), zpl_cast( char* ) f->filename );
|
||||
allocator_free( heap(), ccast( char*, f->filename ));
|
||||
|
||||
#if defined( GEN_SYSTEM_WINDOWS )
|
||||
if ( f->fd.p == INVALID_HANDLE_VALUE )
|
||||
@@ -359,14 +375,14 @@ FileError file_close( FileInfo* f )
|
||||
FileError file_new( FileInfo* f, FileDescriptor fd, FileOperations ops, char const* filename )
|
||||
{
|
||||
FileError err = EFileError_NONE;
|
||||
sw len = str_len( filename );
|
||||
ssize len = c_str_len( filename );
|
||||
|
||||
f->ops = ops;
|
||||
f->fd = fd;
|
||||
f->dir = nullptr;
|
||||
f->last_write_time = 0;
|
||||
f->filename = alloc_array( heap(), char, len + 1 );
|
||||
mem_copy( zpl_cast( char* ) f->filename, zpl_cast( char* ) filename, len + 1 );
|
||||
mem_copy( ccast( char*, f->filename), ccast( char*, filename), len + 1 );
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -425,7 +441,7 @@ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const
|
||||
|
||||
if ( file_open( &file, filepath ) == EFileError_NONE )
|
||||
{
|
||||
sw fsize = zpl_cast( sw ) file_size( &file );
|
||||
ssize fsize = scast( ssize , file_size( &file ));
|
||||
if ( fsize > 0 )
|
||||
{
|
||||
result.data = alloc( a, zero_terminate ? fsize + 1 : fsize );
|
||||
@@ -433,7 +449,7 @@ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const
|
||||
file_read_at( &file, result.data, result.size, 0 );
|
||||
if ( zero_terminate )
|
||||
{
|
||||
u8* str = zpl_cast( u8* ) result.data;
|
||||
u8* str = rcast( u8*, result.data);
|
||||
str[ fsize ] = '\0';
|
||||
}
|
||||
}
|
||||
@@ -443,30 +459,33 @@ FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct _memory_fd _memory_fd;
|
||||
struct _memory_fd
|
||||
{
|
||||
u8 magic;
|
||||
u8* buf; //< zpl_array OR plain buffer if we can't write
|
||||
sw cursor;
|
||||
ssize cursor;
|
||||
AllocatorInfo allocator;
|
||||
|
||||
FileStreamFlags flags;
|
||||
sw cap;
|
||||
ssize cap;
|
||||
};
|
||||
|
||||
#define GEN__FILE_STREAM_FD_MAGIC 37
|
||||
|
||||
GEN_DEF_INLINE FileDescriptor _file_stream_fd_make( _memory_fd* d );
|
||||
GEN_DEF_INLINE _memory_fd* _file_stream_from_fd( FileDescriptor fd );
|
||||
FileDescriptor _file_stream_fd_make( _memory_fd* d );
|
||||
_memory_fd* _file_stream_from_fd( FileDescriptor fd );
|
||||
|
||||
GEN_IMPL_INLINE FileDescriptor _file_stream_fd_make( _memory_fd* d )
|
||||
inline
|
||||
FileDescriptor _file_stream_fd_make( _memory_fd* d )
|
||||
{
|
||||
FileDescriptor fd = { 0 };
|
||||
fd.p = ( void* )d;
|
||||
return fd;
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE _memory_fd* _file_stream_from_fd( FileDescriptor fd )
|
||||
inline
|
||||
_memory_fd* _file_stream_from_fd( FileDescriptor fd )
|
||||
{
|
||||
_memory_fd* d = ( _memory_fd* )fd.p;
|
||||
GEN_ASSERT( d->magic == GEN__FILE_STREAM_FD_MAGIC );
|
||||
@@ -487,7 +506,7 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator )
|
||||
d->allocator = allocator;
|
||||
d->flags = EFileStream_CLONE_WRITABLE;
|
||||
d->cap = 0;
|
||||
d->buf = Array<u8>::init( allocator );
|
||||
d->buf = array_init( u8, allocator );
|
||||
|
||||
if ( ! d->buf )
|
||||
return false;
|
||||
@@ -501,7 +520,7 @@ b8 file_stream_new( FileInfo* file, AllocatorInfo allocator )
|
||||
return true;
|
||||
}
|
||||
|
||||
b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw size, FileStreamFlags flags )
|
||||
b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize size, FileStreamFlags flags )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL( file );
|
||||
_memory_fd* d = ( _memory_fd* )alloc( allocator, size_of( _memory_fd ) );
|
||||
@@ -513,7 +532,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw siz
|
||||
d->flags = flags;
|
||||
if ( d->flags & EFileStream_CLONE_WRITABLE )
|
||||
{
|
||||
Array<u8> arr = Array<u8>::init_reserve( allocator, size );
|
||||
Array(u8) arr = array_init_reserve(u8, allocator, size );
|
||||
d->buf = arr;
|
||||
|
||||
if ( ! d->buf )
|
||||
@@ -522,7 +541,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw siz
|
||||
mem_copy( d->buf, buffer, size );
|
||||
d->cap = size;
|
||||
|
||||
arr.get_header()->Num = size;
|
||||
array_get_header(arr)->Num = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -538,7 +557,7 @@ b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw siz
|
||||
return true;
|
||||
}
|
||||
|
||||
u8* file_stream_buf( FileInfo* file, sw* size )
|
||||
u8* file_stream_buf( FileInfo* file, ssize* size )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL( file );
|
||||
_memory_fd* d = _file_stream_from_fd( file->fd );
|
||||
@@ -547,10 +566,11 @@ u8* file_stream_buf( FileInfo* file, sw* size )
|
||||
return d->buf;
|
||||
}
|
||||
|
||||
internal GEN_FILE_SEEK_PROC( _memory_file_seek )
|
||||
internal
|
||||
GEN_FILE_SEEK_PROC( _memory_file_seek )
|
||||
{
|
||||
_memory_fd* d = _file_stream_from_fd( fd );
|
||||
sw buflen = d->cap;
|
||||
ssize buflen = d->cap;
|
||||
|
||||
if ( whence == ESeekWhence_BEGIN )
|
||||
d->cursor = 0;
|
||||
@@ -563,7 +583,8 @@ internal GEN_FILE_SEEK_PROC( _memory_file_seek )
|
||||
return true;
|
||||
}
|
||||
|
||||
internal GEN_FILE_READ_AT_PROC( _memory_file_read )
|
||||
internal
|
||||
GEN_FILE_READ_AT_PROC( _memory_file_read )
|
||||
{
|
||||
// unused( stop_at_newline );
|
||||
_memory_fd* d = _file_stream_from_fd( fd );
|
||||
@@ -573,25 +594,26 @@ internal GEN_FILE_READ_AT_PROC( _memory_file_read )
|
||||
return true;
|
||||
}
|
||||
|
||||
internal GEN_FILE_WRITE_AT_PROC( _memory_file_write )
|
||||
internal
|
||||
GEN_FILE_WRITE_AT_PROC( _memory_file_write )
|
||||
{
|
||||
_memory_fd* d = _file_stream_from_fd( fd );
|
||||
|
||||
if ( ! ( d->flags & ( EFileStream_CLONE_WRITABLE | EFileStream_WRITABLE ) ) )
|
||||
return false;
|
||||
|
||||
sw buflen = d->cap;
|
||||
sw extralen = max( 0, size - ( buflen - offset ) );
|
||||
sw rwlen = size - extralen;
|
||||
sw new_cap = buflen + extralen;
|
||||
ssize buflen = d->cap;
|
||||
ssize extralen = max( 0, size - ( buflen - offset ) );
|
||||
ssize rwlen = size - extralen;
|
||||
ssize new_cap = buflen + extralen;
|
||||
|
||||
if ( d->flags & EFileStream_CLONE_WRITABLE )
|
||||
{
|
||||
Array<u8> arr = { d->buf };
|
||||
Array(u8) arr = { d->buf };
|
||||
|
||||
if ( arr.get_header()->Capacity < new_cap )
|
||||
if ( array_get_header(arr)->Capacity < scast(usize, new_cap) )
|
||||
{
|
||||
if ( ! arr.grow( ( s64 )( new_cap ) ) )
|
||||
if ( ! array_grow( & arr, ( s64 )( new_cap ) ) )
|
||||
return false;
|
||||
d->buf = arr;
|
||||
}
|
||||
@@ -601,11 +623,11 @@ internal GEN_FILE_WRITE_AT_PROC( _memory_file_write )
|
||||
|
||||
if ( ( d->flags & EFileStream_CLONE_WRITABLE ) && extralen > 0 )
|
||||
{
|
||||
Array<u8> arr = { d->buf };
|
||||
Array(u8) arr = { d->buf };
|
||||
|
||||
mem_copy( d->buf + offset + rwlen, pointer_add_const( buffer, rwlen ), extralen );
|
||||
d->cap = new_cap;
|
||||
arr.get_header()->Capacity = new_cap;
|
||||
array_get_header(arr)->Capacity = new_cap;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -617,21 +639,21 @@ internal GEN_FILE_WRITE_AT_PROC( _memory_file_write )
|
||||
return true;
|
||||
}
|
||||
|
||||
internal GEN_FILE_CLOSE_PROC( _memory_file_close )
|
||||
internal
|
||||
GEN_FILE_CLOSE_PROC( _memory_file_close )
|
||||
{
|
||||
_memory_fd* d = _file_stream_from_fd( fd );
|
||||
AllocatorInfo allocator = d->allocator;
|
||||
|
||||
if ( d->flags & EFileStream_CLONE_WRITABLE )
|
||||
{
|
||||
Array<u8> arr = { d->buf };
|
||||
arr.free();
|
||||
Array(u8) arr = { d->buf };
|
||||
array_free(arr);
|
||||
}
|
||||
|
||||
free( allocator, d );
|
||||
allocator_free( allocator, d );
|
||||
}
|
||||
|
||||
FileOperations const memory_file_operations = { _memory_file_read, _memory_file_write, _memory_file_seek, _memory_file_close };
|
||||
|
||||
#pragma endregion File Handling
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#pragma region File Handling
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "strings.hpp"
|
||||
#endif
|
||||
|
||||
typedef u32 FileMode;
|
||||
#pragma region File Handling
|
||||
|
||||
enum FileModeFlag
|
||||
{
|
||||
@@ -40,11 +43,12 @@ union FileDescriptor
|
||||
uptr u;
|
||||
};
|
||||
|
||||
typedef u32 FileMode;
|
||||
typedef struct FileOperations FileOperations;
|
||||
|
||||
#define GEN_FILE_OPEN_PROC( name ) FileError name( FileDescriptor* fd, FileOperations* ops, FileMode mode, char const* filename )
|
||||
#define GEN_FILE_READ_AT_PROC( name ) b32 name( FileDescriptor fd, void* buffer, sw size, s64 offset, sw* bytes_read, b32 stop_at_newline )
|
||||
#define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, void const* buffer, sw size, s64 offset, sw* bytes_written )
|
||||
#define GEN_FILE_READ_AT_PROC( name ) b32 name( FileDescriptor fd, void* buffer, ssize size, s64 offset, ssize* bytes_read, b32 stop_at_newline )
|
||||
#define GEN_FILE_WRITE_AT_PROC( name ) b32 name( FileDescriptor fd, mem_ptr_const buffer, ssize size, s64 offset, ssize* bytes_written )
|
||||
#define GEN_FILE_SEEK_PROC( name ) b32 name( FileDescriptor fd, s64 offset, SeekWhenceType whence, s64* new_offset )
|
||||
#define GEN_FILE_CLOSE_PROC( name ) void name( FileDescriptor fd )
|
||||
|
||||
@@ -78,7 +82,7 @@ struct DirInfo;
|
||||
struct DirEntry
|
||||
{
|
||||
char const* filename;
|
||||
struct DirInfo* dir_info;
|
||||
DirInfo* dir_info;
|
||||
u8 type;
|
||||
};
|
||||
|
||||
@@ -89,7 +93,7 @@ struct DirInfo
|
||||
|
||||
// Internals
|
||||
char** filenames; // zpl_array
|
||||
String buf;
|
||||
StrBuilder buf;
|
||||
};
|
||||
|
||||
struct FileInfo
|
||||
@@ -117,20 +121,20 @@ enum FileStandardType
|
||||
* @param std Check zpl_file_standard_type
|
||||
* @return File handle to standard I/O
|
||||
*/
|
||||
FileInfo* file_get_standard( FileStandardType std );
|
||||
GEN_API FileInfo* file_get_standard( FileStandardType std );
|
||||
|
||||
/**
|
||||
* Closes the file
|
||||
* @param file
|
||||
*/
|
||||
FileError file_close( FileInfo* file );
|
||||
GEN_API FileError file_close( FileInfo* file );
|
||||
|
||||
/**
|
||||
* Returns the currently opened file's name
|
||||
* @param file
|
||||
*/
|
||||
inline
|
||||
char const* file_name( FileInfo* file )
|
||||
char const* file_name( FileInfo* file )
|
||||
{
|
||||
return file->filename ? file->filename : "";
|
||||
}
|
||||
@@ -140,7 +144,7 @@ inline
|
||||
* @param file
|
||||
* @param filename
|
||||
*/
|
||||
FileError file_open( FileInfo* file, char const* filename );
|
||||
GEN_API FileError file_open( FileInfo* file, char const* filename );
|
||||
|
||||
/**
|
||||
* Opens a file using a specified mode
|
||||
@@ -148,7 +152,7 @@ FileError file_open( FileInfo* file, char const* filename );
|
||||
* @param mode Access mode to use
|
||||
* @param filename
|
||||
*/
|
||||
FileError file_open_mode( FileInfo* file, FileMode mode, char const* filename );
|
||||
GEN_API FileError file_open_mode( FileInfo* file, FileMode mode, char const* filename );
|
||||
|
||||
/**
|
||||
* Reads from a file
|
||||
@@ -156,7 +160,7 @@ FileError file_open_mode( FileInfo* file, FileMode mode, char const* filename );
|
||||
* @param buffer Buffer to read to
|
||||
* @param size Size to read
|
||||
*/
|
||||
GEN_DEF_INLINE b32 file_read( FileInfo* file, void* buffer, sw size );
|
||||
b32 file_read( FileInfo* file, void* buffer, ssize size );
|
||||
|
||||
/**
|
||||
* Reads file at a specific offset
|
||||
@@ -166,7 +170,7 @@ GEN_DEF_INLINE b32 file_read( FileInfo* file, void* buffer, sw size );
|
||||
* @param offset Offset to read from
|
||||
* @param bytes_read How much data we've actually read
|
||||
*/
|
||||
GEN_DEF_INLINE b32 file_read_at( FileInfo* file, void* buffer, sw size, s64 offset );
|
||||
b32 file_read_at( FileInfo* file, void* buffer, ssize size, s64 offset );
|
||||
|
||||
/**
|
||||
* Reads file safely
|
||||
@@ -176,17 +180,18 @@ GEN_DEF_INLINE b32 file_read_at( FileInfo* file, void* buffer, sw size, s64 offs
|
||||
* @param offset Offset to read from
|
||||
* @param bytes_read How much data we've actually read
|
||||
*/
|
||||
GEN_DEF_INLINE b32 file_read_at_check( FileInfo* file, void* buffer, sw size, s64 offset, sw* bytes_read );
|
||||
b32 file_read_at_check( FileInfo* file, void* buffer, ssize size, s64 offset, ssize* bytes_read );
|
||||
|
||||
typedef struct FileContents FileContents;
|
||||
struct FileContents
|
||||
{
|
||||
AllocatorInfo allocator;
|
||||
void* data;
|
||||
sw size;
|
||||
ssize size;
|
||||
};
|
||||
|
||||
constexpr b32 zero_terminate = true;
|
||||
constexpr b32 no_zero_terminate = false;
|
||||
constexpr b32 file_zero_terminate = true;
|
||||
constexpr b32 file_no_zero_terminate = false;
|
||||
|
||||
/**
|
||||
* Reads the whole file contents
|
||||
@@ -195,34 +200,34 @@ constexpr b32 no_zero_terminate = false;
|
||||
* @param filepath Path to the file
|
||||
* @return File contents data
|
||||
*/
|
||||
FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath );
|
||||
GEN_API FileContents file_read_contents( AllocatorInfo a, b32 zero_terminate, char const* filepath );
|
||||
|
||||
/**
|
||||
* Returns a size of the file
|
||||
* @param file
|
||||
* @return File size
|
||||
*/
|
||||
s64 file_size( FileInfo* file );
|
||||
GEN_API s64 file_size( FileInfo* file );
|
||||
|
||||
/**
|
||||
* Seeks the file cursor from the beginning of file to a specific position
|
||||
* @param file
|
||||
* @param offset Offset to seek to
|
||||
*/
|
||||
GEN_DEF_INLINE s64 file_seek( FileInfo* file, s64 offset );
|
||||
s64 file_seek( FileInfo* file, s64 offset );
|
||||
|
||||
/**
|
||||
* Seeks the file cursor to the end of the file
|
||||
* @param file
|
||||
*/
|
||||
GEN_DEF_INLINE s64 file_seek_to_end( FileInfo* file );
|
||||
s64 file_seek_to_end( FileInfo* file );
|
||||
|
||||
/**
|
||||
* Returns the length from the beginning of the file we've read so far
|
||||
* @param file
|
||||
* @return Our current position in file
|
||||
*/
|
||||
GEN_DEF_INLINE s64 file_tell( FileInfo* file );
|
||||
s64 file_tell( FileInfo* file );
|
||||
|
||||
/**
|
||||
* Writes to a file
|
||||
@@ -230,7 +235,7 @@ GEN_DEF_INLINE s64 file_tell( FileInfo* file );
|
||||
* @param buffer Buffer to read from
|
||||
* @param size Size to read
|
||||
*/
|
||||
GEN_DEF_INLINE b32 file_write( FileInfo* file, void const* buffer, sw size );
|
||||
b32 file_write( FileInfo* file, void const* buffer, ssize size );
|
||||
|
||||
/**
|
||||
* Writes to file at a specific offset
|
||||
@@ -240,7 +245,7 @@ GEN_DEF_INLINE b32 file_write( FileInfo* file, void const* buffer, sw size );
|
||||
* @param offset Offset to write to
|
||||
* @param bytes_written How much data we've actually written
|
||||
*/
|
||||
GEN_DEF_INLINE b32 file_write_at( FileInfo* file, void const* buffer, sw size, s64 offset );
|
||||
b32 file_write_at( FileInfo* file, void const* buffer, ssize size, s64 offset );
|
||||
|
||||
/**
|
||||
* Writes to file safely
|
||||
@@ -250,9 +255,48 @@ GEN_DEF_INLINE b32 file_write_at( FileInfo* file, void const* buffer, sw size, s
|
||||
* @param offset Offset to write to
|
||||
* @param bytes_written How much data we've actually written
|
||||
*/
|
||||
GEN_DEF_INLINE b32 file_write_at_check( FileInfo* file, void const* buffer, sw size, s64 offset, sw* bytes_written );
|
||||
b32 file_write_at_check( FileInfo* file, void const* buffer, ssize size, s64 offset, ssize* bytes_written );
|
||||
|
||||
GEN_IMPL_INLINE s64 file_seek( FileInfo* f, s64 offset )
|
||||
enum FileStreamFlags : u32
|
||||
{
|
||||
/* Allows us to write to the buffer directly. Beware: you can not append a new data! */
|
||||
EFileStream_WRITABLE = bit( 0 ),
|
||||
|
||||
/* Clones the input buffer so you can write (zpl_file_write*) data into it. */
|
||||
/* Since we work with a clone, the buffer size can dynamically grow as well. */
|
||||
EFileStream_CLONE_WRITABLE = bit( 1 ),
|
||||
|
||||
EFileStream_UNDERLYING = GEN_U32_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens a new memory stream
|
||||
* @param file
|
||||
* @param allocator
|
||||
*/
|
||||
GEN_API b8 file_stream_new( FileInfo* file, AllocatorInfo allocator );
|
||||
|
||||
/**
|
||||
* Opens a memory stream over an existing buffer
|
||||
* @param file
|
||||
* @param allocator
|
||||
* @param buffer Memory to create stream from
|
||||
* @param size Buffer's size
|
||||
* @param flags
|
||||
*/
|
||||
GEN_API b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, ssize size, FileStreamFlags flags );
|
||||
|
||||
/**
|
||||
* Retrieves the stream's underlying buffer and buffer size.
|
||||
* @param file memory stream
|
||||
* @param size (Optional) buffer size
|
||||
*/
|
||||
GEN_API u8* file_stream_buf( FileInfo* file, ssize* size );
|
||||
|
||||
extern FileOperations const memory_file_operations;
|
||||
|
||||
inline
|
||||
s64 file_seek( FileInfo* f, s64 offset )
|
||||
{
|
||||
s64 new_offset = 0;
|
||||
|
||||
@@ -264,7 +308,8 @@ GEN_IMPL_INLINE s64 file_seek( FileInfo* f, s64 offset )
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE s64 file_seek_to_end( FileInfo* f )
|
||||
inline
|
||||
s64 file_seek_to_end( FileInfo* f )
|
||||
{
|
||||
s64 new_offset = 0;
|
||||
|
||||
@@ -276,7 +321,8 @@ GEN_IMPL_INLINE s64 file_seek_to_end( FileInfo* f )
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE s64 file_tell( FileInfo* f )
|
||||
inline
|
||||
s64 file_tell( FileInfo* f )
|
||||
{
|
||||
s64 new_offset = 0;
|
||||
|
||||
@@ -288,7 +334,8 @@ GEN_IMPL_INLINE s64 file_tell( FileInfo* f )
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE b32 file_read( FileInfo* f, void* buffer, sw size )
|
||||
inline
|
||||
b32 file_read( FileInfo* f, void* buffer, ssize size )
|
||||
{
|
||||
s64 cur_offset = file_tell( f );
|
||||
b32 result = file_read_at( f, buffer, size, file_tell( f ) );
|
||||
@@ -296,19 +343,22 @@ GEN_IMPL_INLINE b32 file_read( FileInfo* f, void* buffer, sw size )
|
||||
return result;
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE b32 file_read_at( FileInfo* f, void* buffer, sw size, s64 offset )
|
||||
inline
|
||||
b32 file_read_at( FileInfo* f, void* buffer, ssize size, s64 offset )
|
||||
{
|
||||
return file_read_at_check( f, buffer, size, offset, NULL );
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE b32 file_read_at_check( FileInfo* f, void* buffer, sw size, s64 offset, sw* bytes_read )
|
||||
inline
|
||||
b32 file_read_at_check( FileInfo* f, void* buffer, ssize size, s64 offset, ssize* bytes_read )
|
||||
{
|
||||
if ( ! f->ops.read_at )
|
||||
f->ops = default_file_operations;
|
||||
return f->ops.read_at( f->fd, buffer, size, offset, bytes_read, false );
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE b32 file_write( FileInfo* f, void const* buffer, sw size )
|
||||
inline
|
||||
b32 file_write( FileInfo* f, void const* buffer, ssize size )
|
||||
{
|
||||
s64 cur_offset = file_tell( f );
|
||||
b32 result = file_write_at( f, buffer, size, file_tell( f ) );
|
||||
@@ -318,12 +368,14 @@ GEN_IMPL_INLINE b32 file_write( FileInfo* f, void const* buffer, sw size )
|
||||
return result;
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE b32 file_write_at( FileInfo* f, void const* buffer, sw size, s64 offset )
|
||||
inline
|
||||
b32 file_write_at( FileInfo* f, void const* buffer, ssize size, s64 offset )
|
||||
{
|
||||
return file_write_at_check( f, buffer, size, offset, NULL );
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE b32 file_write_at_check( FileInfo* f, void const* buffer, sw size, s64 offset, sw* bytes_written )
|
||||
inline
|
||||
b32 file_write_at_check( FileInfo* f, void const* buffer, ssize size, s64 offset, ssize* bytes_written )
|
||||
{
|
||||
if ( ! f->ops.read_at )
|
||||
f->ops = default_file_operations;
|
||||
@@ -331,43 +383,4 @@ GEN_IMPL_INLINE b32 file_write_at_check( FileInfo* f, void const* buffer, sw siz
|
||||
return f->ops.write_at( f->fd, buffer, size, offset, bytes_written );
|
||||
}
|
||||
|
||||
|
||||
|
||||
enum FileStreamFlags : u32
|
||||
{
|
||||
/* Allows us to write to the buffer directly. Beware: you can not append a new data! */
|
||||
EFileStream_WRITABLE = bit( 0 ),
|
||||
|
||||
/* Clones the input buffer so you can write (zpl_file_write*) data into it. */
|
||||
/* Since we work with a clone, the buffer size can dynamically grow as well. */
|
||||
EFileStream_CLONE_WRITABLE = bit( 1 ),
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens a new memory stream
|
||||
* @param file
|
||||
* @param allocator
|
||||
*/
|
||||
b8 file_stream_new( FileInfo* file, AllocatorInfo allocator );
|
||||
|
||||
/**
|
||||
* Opens a memory stream over an existing buffer
|
||||
* @param file
|
||||
* @param allocator
|
||||
* @param buffer Memory to create stream from
|
||||
* @param size Buffer's size
|
||||
* @param flags
|
||||
*/
|
||||
b8 file_stream_open( FileInfo* file, AllocatorInfo allocator, u8* buffer, sw size, FileStreamFlags flags );
|
||||
|
||||
/**
|
||||
* Retrieves the stream's underlying buffer and buffer size.
|
||||
* @param file memory stream
|
||||
* @param size (Optional) buffer size
|
||||
*/
|
||||
u8* file_stream_buf( FileInfo* file, sw* size );
|
||||
|
||||
extern FileOperations const memory_file_operations;
|
||||
|
||||
#pragma endregion File Handling
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "memory.cpp"
|
||||
#endif
|
||||
|
||||
#pragma region Hashing
|
||||
|
||||
global u32 const _crc32_table[ 256 ] = {
|
||||
@@ -22,11 +27,11 @@ global u32 const _crc32_table[ 256 ] = {
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
|
||||
};
|
||||
|
||||
u32 crc32( void const* data, sw len )
|
||||
u32 crc32( void const* data, ssize len )
|
||||
{
|
||||
sw remaining;
|
||||
u32 result = ~( zpl_cast( u32 ) 0 );
|
||||
u8 const* c = zpl_cast( u8 const* ) data;
|
||||
ssize remaining;
|
||||
u32 result = ~( scast( u32, 0) );
|
||||
u8 const* c = rcast( u8 const*, data);
|
||||
for ( remaining = len; remaining--; c++ )
|
||||
result = ( result >> 8 ) ^ ( _crc32_table[ ( result ^ *c ) & 0xff ] );
|
||||
return ~result;
|
||||
@@ -72,15 +77,14 @@ global u64 const _crc64_table[ 256 ] = {
|
||||
0xa6df411fbfb21ca3ull, 0xdc0731d78f8795daull, 0x536fa08fdfd90e51ull, 0x29b7d047efec8728ull,
|
||||
};
|
||||
|
||||
u64 crc64( void const* data, sw len )
|
||||
u64 crc64( void const* data, ssize len )
|
||||
{
|
||||
sw remaining;
|
||||
u64 result = ( zpl_cast( u64 ) 0 );
|
||||
u8 const* c = zpl_cast( u8 const* ) data;
|
||||
ssize remaining;
|
||||
u64 result = ( scast( u64, 0) );
|
||||
u8 const* c = rcast( u8 const*, data);
|
||||
for ( remaining = len; remaining--; c++ )
|
||||
result = ( result >> 8 ) ^ ( _crc64_table[ ( result ^ *c ) & 0xff ] );
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma endregion Hashing
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
#pragma once
|
||||
#include "containers.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Hashing
|
||||
|
||||
GEN_API u32 crc32( void const* data, ssize len );
|
||||
GEN_API u64 crc64( void const* data, ssize len );
|
||||
|
||||
#pragma endregion Hashing
|
||||
@@ -0,0 +1,318 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "platform.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Macros
|
||||
|
||||
#ifndef GEN_API
|
||||
#if GEN_COMPILER_MSVC
|
||||
#ifdef GEN_DYN_LINK
|
||||
#ifdef GEN_DYN_EXPORT
|
||||
#define GEN_API __declspec(dllexport)
|
||||
#else
|
||||
#define GEN_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define GEN_API // Empty for static builds
|
||||
#endif
|
||||
#else
|
||||
#ifdef GEN_DYN_LINK
|
||||
#define GEN_API __attribute__((visibility("default")))
|
||||
#else
|
||||
#define GEN_API // Empty for static builds
|
||||
#endif
|
||||
#endif
|
||||
#endif // GEN_API
|
||||
|
||||
#ifndef global
|
||||
#define global static // Global variables
|
||||
#endif
|
||||
#ifndef internal
|
||||
#define internal static // Internal linkage
|
||||
#endif
|
||||
#ifndef local_persist
|
||||
#define local_persist static // Local Persisting variables
|
||||
#endif
|
||||
|
||||
#ifndef bit
|
||||
#define bit( Value ) ( 1 << Value )
|
||||
#endif
|
||||
|
||||
#ifndef bitfield_is_set
|
||||
#define bitfield_is_set( Type, Field, Mask ) ( (scast(Type, Mask) & scast(Type, Field)) == scast(Type, Mask) )
|
||||
#endif
|
||||
|
||||
// Mainly intended for forcing the base library to utilize only C-valid constructs or type coercion
|
||||
#ifndef GEN_C_LIKE_CPP
|
||||
#define GEN_C_LIKE_CPP 0
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
# ifndef cast
|
||||
# define cast( type, value ) (tmpl_cast<type>( value ))
|
||||
# endif
|
||||
#else
|
||||
# ifndef cast
|
||||
# define cast( type, value ) ( (type)(value) )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
# ifndef ccast
|
||||
# define ccast( type, value ) ( const_cast< type >( (value) ) )
|
||||
# endif
|
||||
# ifndef pcast
|
||||
# define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) )
|
||||
# endif
|
||||
# ifndef rcast
|
||||
# define rcast( type, value ) reinterpret_cast< type >( value )
|
||||
# endif
|
||||
# ifndef scast
|
||||
# define scast( type, value ) static_cast< type >( value )
|
||||
# endif
|
||||
#else
|
||||
# ifndef ccast
|
||||
# define ccast( type, value ) ( (type)(value) )
|
||||
# endif
|
||||
# ifndef pcast
|
||||
# define pcast( type, value ) ( * (type*)(& value) )
|
||||
# endif
|
||||
# ifndef rcast
|
||||
# define rcast( type, value ) ( (type)(value) )
|
||||
# endif
|
||||
# ifndef scast
|
||||
# define scast( type, value ) ( (type)(value) )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef stringize
|
||||
#define stringize_va( ... ) #__VA_ARGS__
|
||||
#define stringize( ... ) stringize_va( __VA_ARGS__ )
|
||||
#endif
|
||||
|
||||
#define src_line_str stringize(__LINE__)
|
||||
|
||||
#ifndef do_once
|
||||
#define do_once() \
|
||||
local_persist int __do_once_counter_##src_line_str = 0; \
|
||||
for(; __do_once_counter_##src_line_str != 1; __do_once_counter_##src_line_str = 1 ) \
|
||||
|
||||
#define do_once_defer( expression ) \
|
||||
local_persist int __do_once_counter_##src_line_str = 0; \
|
||||
for(;__do_once_counter_##src_line_str != 1; __do_once_counter_##src_line_str = 1, (expression)) \
|
||||
|
||||
#define do_once_start \
|
||||
do \
|
||||
{ \
|
||||
local_persist \
|
||||
bool done = false; \
|
||||
if ( done ) \
|
||||
break; \
|
||||
done = true;
|
||||
|
||||
#define do_once_end \
|
||||
} \
|
||||
while(0);
|
||||
#endif
|
||||
|
||||
#ifndef labeled_scope_start
|
||||
#define labeled_scope_start if ( false ) {
|
||||
#define labeled_scope_end }
|
||||
#endif
|
||||
|
||||
#ifndef compiler_decorated_func_name
|
||||
# ifdef COMPILER_CLANG
|
||||
# define compiler_decorated_func_name __PRETTY_NAME__
|
||||
# elif defined(COMPILER_MSVC)
|
||||
# define compiler_decorated_func_name __FUNCDNAME__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef num_args_impl
|
||||
|
||||
// This is essentially an arg couneter version of GEN_SELECT_ARG macros
|
||||
// See section : _Generic function overloading for that usage (explains this heavier case)
|
||||
|
||||
#define num_args_impl( _0, \
|
||||
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
|
||||
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
|
||||
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
|
||||
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
|
||||
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
|
||||
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
|
||||
_61, _62, _63, _64, _65, _66, _67, _68, _69, _70, \
|
||||
_71, _72, _73, _74, _75, _76, _77, _78, _79, _80, \
|
||||
_81, _82, _83, _84, _85, _86, _87, _88, _89, _90, \
|
||||
_91, _92, _93, _94, _95, _96, _97, _98, _99, _100, \
|
||||
N, ... \
|
||||
) N
|
||||
|
||||
// ## deletes preceding comma if _VA_ARGS__ is empty (GCC, Clang)
|
||||
#define num_args(...) \
|
||||
num_args_impl(_, ## __VA_ARGS__, \
|
||||
100, 99, 98, 97, 96, 95, 94, 93, 92, 91, \
|
||||
90, 89, 88, 87, 86, 85, 84, 83, 82, 81, \
|
||||
80, 79, 78, 77, 76, 75, 74, 73, 72, 71, \
|
||||
70, 69, 68, 67, 66, 65, 64, 63, 62, 61, \
|
||||
60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \
|
||||
50, 49, 48, 47, 46, 45, 44, 43, 42, 41, \
|
||||
40, 39, 38, 37, 36, 35, 34, 33, 32, 31, \
|
||||
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, \
|
||||
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, \
|
||||
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, \
|
||||
0 \
|
||||
)
|
||||
#endif
|
||||
|
||||
#ifndef clamp
|
||||
#define clamp( x, lower, upper ) min( max( ( x ), ( lower ) ), ( upper ) )
|
||||
#endif
|
||||
#ifndef count_of
|
||||
#define count_of( x ) ( ( size_of( x ) / size_of( 0 [ x ] ) ) / ( ( ssize )( ! ( size_of( x ) % size_of( 0 [ x ] ) ) ) ) )
|
||||
#endif
|
||||
#ifndef is_between
|
||||
#define is_between( x, lower, upper ) ( ( ( lower ) <= ( x ) ) && ( ( x ) <= ( upper ) ) )
|
||||
#endif
|
||||
#ifndef size_of
|
||||
#define size_of( x ) ( ssize )( sizeof( x ) )
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
#define max( a, b ) ( (a > b) ? (a) : (b) )
|
||||
#endif
|
||||
#ifndef min
|
||||
#define min( a, b ) ( (a < b) ? (a) : (b) )
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_MSVC || GEN_COMPILER_TINYC
|
||||
# define offset_of( Type, element ) ( ( GEN_NS( ssize ) ) & ( ( ( Type* )0 )->element ) )
|
||||
#else
|
||||
# define offset_of( Type, element ) __builtin_offsetof( Type, element )
|
||||
#endif
|
||||
|
||||
#ifndef forceinline
|
||||
# if GEN_COMPILER_MSVC
|
||||
# define forceinline __forceinline
|
||||
# define neverinline __declspec( noinline )
|
||||
# elif GEN_COMPILER_GCC
|
||||
# define forceinline inline __attribute__((__always_inline__))
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
# elif GEN_COMPILER_CLANG
|
||||
# if __has_attribute(__always_inline__)
|
||||
# define forceinline inline __attribute__((__always_inline__))
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
# else
|
||||
# define forceinline
|
||||
# define neverinline
|
||||
# endif
|
||||
# else
|
||||
# define forceinline
|
||||
# define neverinline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef neverinline
|
||||
# if GEN_COMPILER_MSVC
|
||||
# define neverinline __declspec( noinline )
|
||||
# elif GEN_COMPILER_GCC
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
# elif GEN_COMPILER_CLANG
|
||||
# if __has_attribute(__always_inline__)
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
# else
|
||||
# define neverinline
|
||||
# endif
|
||||
# else
|
||||
# define neverinline
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
#ifndef static_assert
|
||||
#undef static_assert
|
||||
#if GEN_COMPILER_C && __STDC_VERSION__ >= 201112L
|
||||
#define static_assert(condition, message) _Static_assert(condition, message)
|
||||
#else
|
||||
#define static_assert(condition, message) typedef char static_assertion_##__LINE__[(condition)?1:-1]
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
// Already Defined
|
||||
#elif GEN_COMPILER_C && __STDC_VERSION__ >= 201112L
|
||||
# define thread_local _Thread_local
|
||||
#elif GEN_COMPILER_MSVC
|
||||
# define thread_local __declspec(thread)
|
||||
#elif GEN_COMPILER_CLANG
|
||||
# define thread_local __thread
|
||||
#else
|
||||
# error "No thread local support"
|
||||
#endif
|
||||
|
||||
#if ! defined(typeof) && (!GEN_COMPILER_C || __STDC_VERSION__ < 202311L)
|
||||
# if ! GEN_COMPILER_C
|
||||
# define typeof decltype
|
||||
# elif defined(_MSC_VER)
|
||||
# define typeof __typeof__
|
||||
# elif defined(__GNUC__) || defined(__clang__)
|
||||
# define typeof __typeof__
|
||||
# else
|
||||
# error "Compiler not supported"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef GEN_API_C_BEGIN
|
||||
# if GEN_COMPILER_C
|
||||
# define GEN_API_C_BEGIN
|
||||
# define GEN_API_C_END
|
||||
# else
|
||||
# define GEN_API_C_BEGIN extern "C" {
|
||||
# define GEN_API_C_END }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
# if __STDC_VERSION__ >= 202311L
|
||||
# define enum_underlying(type) : type
|
||||
# else
|
||||
# define enum_underlying(type)
|
||||
# endif
|
||||
#else
|
||||
# define enum_underlying(type) : type
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
# ifndef nullptr
|
||||
# define nullptr NULL
|
||||
# endif
|
||||
|
||||
# ifndef GEN_REMOVE_PTR
|
||||
# define GEN_REMOVE_PTR(type) typeof(* ( (type) NULL) )
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if ! defined(GEN_PARAM_DEFAULT) && GEN_COMPILER_CPP
|
||||
# define GEN_PARAM_DEFAULT = {}
|
||||
#else
|
||||
# define GEN_PARAM_DEFAULT
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
#define struct_init(type, value) {value}
|
||||
#else
|
||||
#define struct_init(type, value) {value}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifndef GEN_OPTIMIZE_MAPPINGS_BEGIN
|
||||
# define GEN_OPTIMIZE_MAPPINGS_BEGIN _pragma(optimize("gt", on))
|
||||
# define GEN_OPITMIZE_MAPPINGS_END _pragma(optimize("", on))
|
||||
#endif
|
||||
#else
|
||||
# define GEN_OPTIMIZE_MAPPINGS_BEGIN
|
||||
# define GEN_OPITMIZE_MAPPINGS_END
|
||||
#endif
|
||||
|
||||
#pragma endregion Macros
|
||||
@@ -1,34 +1,39 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "printing.cpp"
|
||||
#endif
|
||||
|
||||
#pragma region Memory
|
||||
|
||||
void* mem_copy( void* dest, void const* source, sw n )
|
||||
void* mem_copy( void* dest, void const* source, ssize n )
|
||||
{
|
||||
if ( dest == NULL )
|
||||
if ( dest == nullptr )
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return memcpy( dest, source, n );
|
||||
}
|
||||
|
||||
void const* mem_find( void const* data, u8 c, sw n )
|
||||
void const* mem_find( void const* data, u8 c, ssize n )
|
||||
{
|
||||
u8 const* s = zpl_cast( u8 const* ) data;
|
||||
while ( ( zpl_cast( uptr ) s & ( sizeof( uw ) - 1 ) ) && n && *s != c )
|
||||
u8 const* s = rcast( u8 const*, data);
|
||||
while ( ( rcast( uptr, s) & ( sizeof( usize ) - 1 ) ) && n && *s != c )
|
||||
{
|
||||
s++;
|
||||
n--;
|
||||
}
|
||||
if ( n && *s != c )
|
||||
{
|
||||
sw const* w;
|
||||
sw k = GEN__ONES * c;
|
||||
w = zpl_cast( sw const* ) s;
|
||||
while ( n >= size_of( sw ) && ! GEN__HAS_ZERO( *w ^ k ) )
|
||||
ssize const* w;
|
||||
ssize k = GEN__ONES * c;
|
||||
w = rcast( ssize const*, s);
|
||||
while ( n >= size_of( ssize ) && ! GEN__HAS_ZERO( *w ^ k ) )
|
||||
{
|
||||
w++;
|
||||
n -= size_of( sw );
|
||||
n -= size_of( ssize );
|
||||
}
|
||||
s = zpl_cast( u8 const* ) w;
|
||||
s = rcast( u8 const*, w);
|
||||
while ( n && *s != c )
|
||||
{
|
||||
s++;
|
||||
@@ -36,16 +41,17 @@ void const* mem_find( void const* data, u8 c, sw n )
|
||||
}
|
||||
}
|
||||
|
||||
return n ? zpl_cast( void const* ) s : NULL;
|
||||
return n ? rcast( void const*, s ) : NULL;
|
||||
}
|
||||
|
||||
#define GEN_HEAP_STATS_MAGIC 0xDEADC0DE
|
||||
|
||||
typedef struct _heap_stats _heap_stats;
|
||||
struct _heap_stats
|
||||
{
|
||||
u32 magic;
|
||||
sw used_memory;
|
||||
sw alloc_count;
|
||||
ssize used_memory;
|
||||
ssize alloc_count;
|
||||
};
|
||||
|
||||
global _heap_stats _heap_stats_info;
|
||||
@@ -56,13 +62,13 @@ void heap_stats_init( void )
|
||||
_heap_stats_info.magic = GEN_HEAP_STATS_MAGIC;
|
||||
}
|
||||
|
||||
sw heap_stats_used_memory( void )
|
||||
ssize heap_stats_used_memory( void )
|
||||
{
|
||||
GEN_ASSERT_MSG( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" );
|
||||
return _heap_stats_info.used_memory;
|
||||
}
|
||||
|
||||
sw heap_stats_alloc_count( void )
|
||||
ssize heap_stats_alloc_count( void )
|
||||
{
|
||||
GEN_ASSERT_MSG( _heap_stats_info.magic == GEN_HEAP_STATS_MAGIC, "heap_stats is not initialised yet, call heap_stats_init first!" );
|
||||
return _heap_stats_info.alloc_count;
|
||||
@@ -75,31 +81,32 @@ void heap_stats_check( void )
|
||||
GEN_ASSERT( _heap_stats_info.alloc_count == 0 );
|
||||
}
|
||||
|
||||
typedef struct _heap_alloc_info _heap_alloc_info;
|
||||
struct _heap_alloc_info
|
||||
{
|
||||
sw size;
|
||||
ssize size;
|
||||
void* physical_start;
|
||||
};
|
||||
|
||||
void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
|
||||
void* heap_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
{
|
||||
void* ptr = NULL;
|
||||
void* ptr = nullptr;
|
||||
// unused( allocator_data );
|
||||
// unused( old_size );
|
||||
if ( ! alignment )
|
||||
alignment = GEN_DEFAULT_MEMORY_ALIGNMENT;
|
||||
|
||||
#ifdef GEN_HEAP_ANALYSIS
|
||||
sw alloc_info_size = size_of( _heap_alloc_info );
|
||||
sw alloc_info_remainder = ( alloc_info_size % alignment );
|
||||
sw track_size = max( alloc_info_size, alignment ) + alloc_info_remainder;
|
||||
ssize alloc_info_size = size_of( _heap_alloc_info );
|
||||
ssize alloc_info_remainder = ( alloc_info_size % alignment );
|
||||
ssize track_size = max( alloc_info_size, alignment ) + alloc_info_remainder;
|
||||
switch ( type )
|
||||
{
|
||||
case EAllocation_FREE :
|
||||
{
|
||||
if ( ! old_memory )
|
||||
break;
|
||||
_heap_alloc_info* alloc_info = zpl_cast( _heap_alloc_info* ) old_memory - 1;
|
||||
_heap_alloc_info* alloc_info = rcast( _heap_alloc_info*, old_memory) - 1;
|
||||
_heap_stats_info.used_memory -= alloc_info->size;
|
||||
_heap_stats_info.alloc_count--;
|
||||
old_memory = alloc_info->physical_start;
|
||||
@@ -190,11 +197,11 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali
|
||||
#ifdef GEN_HEAP_ANALYSIS
|
||||
if ( type == EAllocation_ALLOC )
|
||||
{
|
||||
_heap_alloc_info* alloc_info = zpl_cast( _heap_alloc_info* )( zpl_cast( char* ) ptr + alloc_info_remainder );
|
||||
_heap_alloc_info* alloc_info = rcast( _heap_alloc_info*, rcast( char*, ptr) + alloc_info_remainder );
|
||||
zero_item( alloc_info );
|
||||
alloc_info->size = size - track_size;
|
||||
alloc_info->physical_start = ptr;
|
||||
ptr = zpl_cast( void* )( alloc_info + 1 );
|
||||
ptr = rcast( void*, alloc_info + 1 );
|
||||
_heap_stats_info.used_memory += alloc_info->size;
|
||||
_heap_stats_info.alloc_count++;
|
||||
}
|
||||
@@ -203,7 +210,133 @@ void* heap_allocator_proc( void* allocator_data, AllocType type, sw size, sw ali
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
|
||||
#pragma region VirtualMemory
|
||||
VirtualMemory vm_from_memory( void* data, ssize size )
|
||||
{
|
||||
VirtualMemory vm;
|
||||
vm.data = data;
|
||||
vm.size = size;
|
||||
return vm;
|
||||
}
|
||||
|
||||
#if defined( GEN_SYSTEM_WINDOWS )
|
||||
VirtualMemory vm_alloc( void* addr, ssize size )
|
||||
{
|
||||
VirtualMemory vm;
|
||||
GEN_ASSERT( size > 0 );
|
||||
vm.data = VirtualAlloc( addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );
|
||||
vm.size = size;
|
||||
return vm;
|
||||
}
|
||||
|
||||
b32 vm_free( VirtualMemory vm )
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
while ( vm.size > 0 )
|
||||
{
|
||||
if ( VirtualQuery( vm.data, &info, size_of( info ) ) == 0 )
|
||||
return false;
|
||||
if ( info.BaseAddress != vm.data || info.AllocationBase != vm.data || info.State != MEM_COMMIT || info.RegionSize > scast( usize, vm.size) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( VirtualFree( vm.data, 0, MEM_RELEASE ) == 0 )
|
||||
return false;
|
||||
vm.data = pointer_add( vm.data, info.RegionSize );
|
||||
vm.size -= info.RegionSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size )
|
||||
{
|
||||
VirtualMemory new_vm = { 0 };
|
||||
void* ptr;
|
||||
GEN_ASSERT( vm.size >= lead_size + size );
|
||||
|
||||
ptr = pointer_add( vm.data, lead_size );
|
||||
|
||||
vm_free( vm );
|
||||
new_vm = vm_alloc( ptr, size );
|
||||
if ( new_vm.data == ptr )
|
||||
return new_vm;
|
||||
if ( new_vm.data )
|
||||
vm_free( new_vm );
|
||||
return new_vm;
|
||||
}
|
||||
|
||||
b32 vm_purge( VirtualMemory vm )
|
||||
{
|
||||
VirtualAlloc( vm.data, vm.size, MEM_RESET, PAGE_READWRITE );
|
||||
// NOTE: Can this really fail?
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize virtual_memory_page_size( ssize* alignment_out )
|
||||
{
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo( &info );
|
||||
if ( alignment_out )
|
||||
*alignment_out = info.dwAllocationGranularity;
|
||||
return info.dwPageSize;
|
||||
}
|
||||
|
||||
#else
|
||||
# include <sys/mman.h>
|
||||
|
||||
# ifndef MAP_ANONYMOUS
|
||||
# define MAP_ANONYMOUS MAP_ANON
|
||||
# endif
|
||||
VirtualMemory vm_alloc( void* addr, ssize size )
|
||||
{
|
||||
VirtualMemory vm;
|
||||
GEN_ASSERT( size > 0 );
|
||||
vm.data = mmap( addr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0 );
|
||||
vm.size = size;
|
||||
return vm;
|
||||
}
|
||||
|
||||
b32 vm_free( VirtualMemory vm )
|
||||
{
|
||||
munmap( vm.data, vm.size );
|
||||
return true;
|
||||
}
|
||||
|
||||
VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size )
|
||||
{
|
||||
void* ptr;
|
||||
ssize trail_size;
|
||||
GEN_ASSERT( vm.size >= lead_size + size );
|
||||
|
||||
ptr = pointer_add( vm.data, lead_size );
|
||||
trail_size = vm.size - lead_size - size;
|
||||
|
||||
if ( lead_size != 0 )
|
||||
vm_free( vm_from_memory(( vm.data, lead_size ) );
|
||||
if ( trail_size != 0 )
|
||||
vm_free( vm_from_memory( ptr, trail_size ) );
|
||||
return vm_from_memory( ptr, size );
|
||||
}
|
||||
|
||||
b32 vm_purge( VirtualMemory vm )
|
||||
{
|
||||
int err = madvise( vm.data, vm.size, MADV_DONTNEED );
|
||||
return err != 0;
|
||||
}
|
||||
|
||||
ssize virtual_memory_page_size( ssize* alignment_out )
|
||||
{
|
||||
// TODO: Is this always true?
|
||||
ssize result = scast( ssize, sysconf( _SC_PAGE_SIZE ));
|
||||
if ( alignment_out )
|
||||
*alignment_out = result;
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma endregion VirtualMemory
|
||||
|
||||
void* arena_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
{
|
||||
Arena* arena = rcast(Arena*, allocator_data);
|
||||
void* ptr = NULL;
|
||||
@@ -215,16 +348,16 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw a
|
||||
case EAllocation_ALLOC :
|
||||
{
|
||||
void* end = pointer_add( arena->PhysicalStart, arena->TotalUsed );
|
||||
sw total_size = align_forward_i64( size, alignment );
|
||||
ssize total_size = align_forward_s64( size, alignment );
|
||||
|
||||
// NOTE: Out of memory
|
||||
if ( arena->TotalUsed + total_size > (sw) arena->TotalSize )
|
||||
if ( arena->TotalUsed + total_size > (ssize) arena->TotalSize )
|
||||
{
|
||||
// zpl__printf_err("%s", "Arena out of memory\n");
|
||||
fatal("Arena out of memory! (Possibly could not fit for the largest size Arena!!)");
|
||||
return nullptr;
|
||||
GEN_FATAL("Arena out of memory! (Possibly could not fit for the largest size Arena!!)");
|
||||
}
|
||||
|
||||
|
||||
ptr = align_forward( end, alignment );
|
||||
arena->TotalUsed += total_size;
|
||||
|
||||
@@ -253,9 +386,9 @@ void* Arena::allocator_proc( void* allocator_data, AllocType type, sw size, sw a
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw alignment, void* old_memory, sw old_size, u64 flags )
|
||||
void* pool_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags )
|
||||
{
|
||||
Pool* pool = zpl_cast( Pool* ) allocator_data;
|
||||
Pool* pool = rcast( Pool*, allocator_data);
|
||||
void* ptr = NULL;
|
||||
|
||||
// unused( old_size );
|
||||
@@ -270,9 +403,9 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al
|
||||
GEN_ASSERT( alignment == pool->BlockAlign );
|
||||
GEN_ASSERT( pool->FreeList != NULL );
|
||||
|
||||
next_free = *zpl_cast( uptr* ) pool->FreeList;
|
||||
next_free = * rcast( uptr*, pool->FreeList);
|
||||
ptr = pool->FreeList;
|
||||
pool->FreeList = zpl_cast( void* ) next_free;
|
||||
pool->FreeList = rcast( void*, next_free);
|
||||
pool->TotalSize += pool->BlockSize;
|
||||
|
||||
if ( flags & ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
||||
@@ -286,8 +419,8 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al
|
||||
if ( old_memory == NULL )
|
||||
return NULL;
|
||||
|
||||
next = zpl_cast( uptr* ) old_memory;
|
||||
*next = zpl_cast( uptr ) pool->FreeList;
|
||||
next = rcast( uptr*, old_memory);
|
||||
*next = rcast( uptr, pool->FreeList);
|
||||
pool->FreeList = old_memory;
|
||||
pool->TotalSize -= pool->BlockSize;
|
||||
}
|
||||
@@ -295,7 +428,7 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al
|
||||
|
||||
case EAllocation_FREE_ALL :
|
||||
{
|
||||
sw actual_block_size, block_index;
|
||||
ssize actual_block_size, block_index;
|
||||
void* curr;
|
||||
uptr* end;
|
||||
|
||||
@@ -306,13 +439,13 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al
|
||||
curr = pool->PhysicalStart;
|
||||
for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ )
|
||||
{
|
||||
uptr* next = zpl_cast( uptr* ) curr;
|
||||
*next = zpl_cast( uptr ) curr + actual_block_size;
|
||||
uptr* next = rcast( uptr*, curr);
|
||||
* next = rcast( uptr, curr) + actual_block_size;
|
||||
curr = pointer_add( curr, actual_block_size );
|
||||
}
|
||||
|
||||
end = zpl_cast( uptr* ) curr;
|
||||
*end = zpl_cast( uptr ) NULL;
|
||||
end = rcast( uptr*, curr);
|
||||
* end = scast( uptr, NULL);
|
||||
pool->FreeList = pool->PhysicalStart;
|
||||
}
|
||||
break;
|
||||
@@ -326,11 +459,11 @@ void* Pool::allocator_proc( void* allocator_data, AllocType type, sw size, sw al
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Pool Pool::init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw block_align )
|
||||
Pool pool_init_align( AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align )
|
||||
{
|
||||
Pool pool = {};
|
||||
|
||||
sw actual_block_size, pool_size, block_index;
|
||||
ssize actual_block_size, pool_size, block_index;
|
||||
void *data, *curr;
|
||||
uptr* end;
|
||||
|
||||
@@ -364,16 +497,16 @@ Pool Pool::init_align( AllocatorInfo backing, sw num_blocks, sw block_size, sw b
|
||||
return pool;
|
||||
}
|
||||
|
||||
void Pool::clear()
|
||||
void pool_clear(Pool* pool)
|
||||
{
|
||||
sw actual_block_size, block_index;
|
||||
ssize actual_block_size, block_index;
|
||||
void* curr;
|
||||
uptr* end;
|
||||
|
||||
actual_block_size = BlockSize + BlockAlign;
|
||||
actual_block_size = pool->BlockSize + pool->BlockAlign;
|
||||
|
||||
curr = PhysicalStart;
|
||||
for ( block_index = 0; block_index < NumBlocks - 1; block_index++ )
|
||||
curr = pool->PhysicalStart;
|
||||
for ( block_index = 0; block_index < pool->NumBlocks - 1; block_index++ )
|
||||
{
|
||||
uptr* next = ( uptr* ) curr;
|
||||
*next = ( uptr ) curr + actual_block_size;
|
||||
@@ -383,8 +516,7 @@ void Pool::clear()
|
||||
end = ( uptr* ) curr;
|
||||
*end = ( uptr ) NULL;
|
||||
|
||||
FreeList = PhysicalStart;
|
||||
pool->FreeList = pool->PhysicalStart;
|
||||
}
|
||||
|
||||
#pragma endregion Memory
|
||||
|
||||
@@ -0,0 +1,672 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "debug.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Memory
|
||||
|
||||
#define kilobytes( x ) ( ( x ) * ( s64 )( 1024 ) )
|
||||
#define megabytes( x ) ( kilobytes( x ) * ( s64 )( 1024 ) )
|
||||
#define gigabytes( x ) ( megabytes( x ) * ( s64 )( 1024 ) )
|
||||
#define terabytes( x ) ( gigabytes( x ) * ( s64 )( 1024 ) )
|
||||
|
||||
#define GEN__ONES ( scast( GEN_NS usize, - 1) / GEN_U8_MAX )
|
||||
#define GEN__HIGHS ( GEN__ONES * ( GEN_U8_MAX / 2 + 1 ) )
|
||||
#define GEN__HAS_ZERO( x ) ( ( ( x ) - GEN__ONES ) & ~( x ) & GEN__HIGHS )
|
||||
|
||||
template< class Type >
|
||||
void swap( Type& a, Type& b )
|
||||
{
|
||||
Type tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
//! Checks if value is power of 2.
|
||||
b32 is_power_of_two( ssize x );
|
||||
|
||||
//! Aligns address to specified alignment.
|
||||
void* align_forward( void* ptr, ssize alignment );
|
||||
|
||||
//! Aligns value to a specified alignment.
|
||||
s64 align_forward_by_value( s64 value, ssize alignment );
|
||||
|
||||
//! Moves pointer forward by bytes.
|
||||
void* pointer_add( void* ptr, ssize bytes );
|
||||
|
||||
//! Moves pointer forward by bytes.
|
||||
void const* pointer_add_const( void const* ptr, ssize bytes );
|
||||
|
||||
//! Calculates difference between two addresses.
|
||||
ssize pointer_diff( void const* begin, void const* end );
|
||||
|
||||
//! Copy non-overlapping memory from source to destination.
|
||||
GEN_API void* mem_copy( void* dest, void const* source, ssize size );
|
||||
|
||||
//! Search for a constant value within the size limit at memory location.
|
||||
GEN_API void const* mem_find( void const* data, u8 byte_value, ssize size );
|
||||
|
||||
//! Copy memory from source to destination.
|
||||
void* mem_move( void* dest, void const* source, ssize size );
|
||||
|
||||
//! Set constant value at memory location with specified size.
|
||||
void* mem_set( void* data, u8 byte_value, ssize size );
|
||||
|
||||
//! @param ptr Memory location to clear up.
|
||||
//! @param size The size to clear up with.
|
||||
void zero_size( void* ptr, ssize size );
|
||||
|
||||
//! Clears up an item.
|
||||
#define zero_item( t ) zero_size( ( t ), size_of( *( t ) ) ) // NOTE: Pass pointer of struct
|
||||
|
||||
//! Clears up an array.
|
||||
#define zero_array( a, count ) zero_size( ( a ), size_of( *( a ) ) * count )
|
||||
|
||||
enum AllocType : u8
|
||||
{
|
||||
EAllocation_ALLOC,
|
||||
EAllocation_FREE,
|
||||
EAllocation_FREE_ALL,
|
||||
EAllocation_RESIZE,
|
||||
};
|
||||
|
||||
typedef void*(AllocatorProc)( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
|
||||
|
||||
struct AllocatorInfo
|
||||
{
|
||||
AllocatorProc* Proc;
|
||||
void* Data;
|
||||
};
|
||||
|
||||
enum AllocFlag
|
||||
{
|
||||
ALLOCATOR_FLAG_CLEAR_TO_ZERO = bit( 0 ),
|
||||
};
|
||||
|
||||
#ifndef GEN_DEFAULT_MEMORY_ALIGNMENT
|
||||
# define GEN_DEFAULT_MEMORY_ALIGNMENT ( 2 * size_of( void* ) )
|
||||
#endif
|
||||
|
||||
#ifndef GEN_DEFAULT_ALLOCATOR_FLAGS
|
||||
# define GEN_DEFAULT_ALLOCATOR_FLAGS ( ALLOCATOR_FLAG_CLEAR_TO_ZERO )
|
||||
#endif
|
||||
|
||||
//! Allocate memory with default alignment.
|
||||
void* alloc( AllocatorInfo a, ssize size );
|
||||
|
||||
//! Allocate memory with specified alignment.
|
||||
void* alloc_align( AllocatorInfo a, ssize size, ssize alignment );
|
||||
|
||||
//! Free allocated memory.
|
||||
void allocator_free( AllocatorInfo a, void* ptr );
|
||||
|
||||
//! Free all memory allocated by an allocator.
|
||||
void free_all( AllocatorInfo a );
|
||||
|
||||
//! Resize an allocated memory.
|
||||
void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size );
|
||||
|
||||
//! Resize an allocated memory with specified alignment.
|
||||
void* resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment );
|
||||
|
||||
//! Allocate memory for an item.
|
||||
#define alloc_item( allocator_, Type ) ( Type* )alloc( allocator_, size_of( Type ) )
|
||||
|
||||
//! Allocate memory for an array of items.
|
||||
#define alloc_array( allocator_, Type, count ) ( Type* )alloc( allocator_, size_of( Type ) * ( count ) )
|
||||
|
||||
/* heap memory analysis tools */
|
||||
/* define GEN_HEAP_ANALYSIS to enable this feature */
|
||||
/* call zpl_heap_stats_init at the beginning of the entry point */
|
||||
/* you can call zpl_heap_stats_check near the end of the execution to validate any possible leaks */
|
||||
GEN_API void heap_stats_init( void );
|
||||
GEN_API ssize heap_stats_used_memory( void );
|
||||
GEN_API ssize heap_stats_alloc_count( void );
|
||||
GEN_API void heap_stats_check( void );
|
||||
|
||||
//! Allocate/Resize memory using default options.
|
||||
|
||||
//! Use this if you don't need a "fancy" resize allocation
|
||||
void* default_resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment );
|
||||
|
||||
GEN_API void* heap_allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags );
|
||||
|
||||
//! The heap allocator backed by operating system's memory manager.
|
||||
constexpr AllocatorInfo heap( void ) { AllocatorInfo allocator = { heap_allocator_proc, nullptr }; return allocator; }
|
||||
|
||||
//! Helper to allocate memory using heap allocator.
|
||||
#define malloc( sz ) alloc( heap(), sz )
|
||||
|
||||
//! Helper to free memory allocated by heap allocator.
|
||||
#define mfree( ptr ) free( heap(), ptr )
|
||||
|
||||
struct VirtualMemory
|
||||
{
|
||||
void* data;
|
||||
ssize size;
|
||||
};
|
||||
|
||||
//! Initialize virtual memory from existing data.
|
||||
GEN_API VirtualMemory vm_from_memory( void* data, ssize size );
|
||||
|
||||
//! Allocate virtual memory at address with size.
|
||||
|
||||
//! @param addr The starting address of the region to reserve. If NULL, it lets operating system to decide where to allocate it.
|
||||
//! @param size The size to serve.
|
||||
GEN_API VirtualMemory vm_alloc( void* addr, ssize size );
|
||||
|
||||
//! Release the virtual memory.
|
||||
GEN_API b32 vm_free( VirtualMemory vm );
|
||||
|
||||
//! Trim virtual memory.
|
||||
GEN_API VirtualMemory vm_trim( VirtualMemory vm, ssize lead_size, ssize size );
|
||||
|
||||
//! Purge virtual memory.
|
||||
GEN_API b32 vm_purge( VirtualMemory vm );
|
||||
|
||||
//! Retrieve VM's page size and alignment.
|
||||
GEN_API ssize virtual_memory_page_size( ssize* alignment_out );
|
||||
|
||||
#pragma region Arena
|
||||
struct Arena;
|
||||
|
||||
AllocatorInfo arena_allocator_info( Arena* arena );
|
||||
|
||||
// Remove static keyword and rename allocator_proc
|
||||
GEN_API void* arena_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags);
|
||||
|
||||
// Add these declarations after the Arena struct
|
||||
Arena arena_init_from_allocator(AllocatorInfo backing, ssize size);
|
||||
Arena arena_init_from_memory ( void* start, ssize size );
|
||||
|
||||
Arena arena_init_sub (Arena* parent, ssize size);
|
||||
ssize arena_alignment_of (Arena* arena, ssize alignment);
|
||||
void arena_check (Arena* arena);
|
||||
void arena_free (Arena* arena);
|
||||
ssize arena_size_remaining(Arena* arena, ssize alignment);
|
||||
|
||||
struct Arena
|
||||
{
|
||||
AllocatorInfo Backing;
|
||||
void* PhysicalStart;
|
||||
ssize TotalSize;
|
||||
ssize TotalUsed;
|
||||
ssize TempCount;
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
#pragma region Member Mapping
|
||||
forceinline operator AllocatorInfo() { return arena_allocator_info(this); }
|
||||
|
||||
forceinline static void* allocator_proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) { return arena_allocator_proc( allocator_data, type, size, alignment, old_memory, old_size, flags ); }
|
||||
forceinline static Arena init_from_memory( void* start, ssize size ) { return arena_init_from_memory( start, size ); }
|
||||
forceinline static Arena init_from_allocator( AllocatorInfo backing, ssize size ) { return arena_init_from_allocator( backing, size ); }
|
||||
forceinline static Arena init_sub( Arena& parent, ssize size ) { return arena_init_from_allocator( parent.Backing, size ); }
|
||||
forceinline ssize alignment_of( ssize alignment ) { return arena_alignment_of(this, alignment); }
|
||||
forceinline void free() { return arena_free(this); }
|
||||
forceinline ssize size_remaining( ssize alignment ) { return arena_size_remaining(this, alignment); }
|
||||
|
||||
// This id is defined by Unreal for asserts
|
||||
#pragma push_macro("check")
|
||||
#undef check
|
||||
forceinline void check() { arena_check(this); }
|
||||
#pragma pop_macro("check")
|
||||
|
||||
#pragma endregion Member Mapping
|
||||
#endif
|
||||
};
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline AllocatorInfo allocator_info(Arena& arena ) { return arena_allocator_info(& arena); }
|
||||
forceinline Arena init_sub (Arena& parent, ssize size) { return arena_init_sub( & parent, size); }
|
||||
forceinline ssize alignment_of (Arena& arena, ssize alignment) { return arena_alignment_of( & arena, alignment); }
|
||||
forceinline void free (Arena& arena) { return arena_free(& arena); }
|
||||
forceinline ssize size_remaining(Arena& arena, ssize alignment) { return arena_size_remaining(& arena, alignment); }
|
||||
|
||||
// This id is defined by Unreal for asserts
|
||||
#pragma push_macro("check")
|
||||
#undef check
|
||||
forceinline void check(Arena& arena) { return arena_check(& arena); }
|
||||
#pragma pop_macro("check")
|
||||
#endif
|
||||
|
||||
inline
|
||||
AllocatorInfo arena_allocator_info( Arena* arena ) {
|
||||
GEN_ASSERT(arena != nullptr);
|
||||
AllocatorInfo info = { arena_allocator_proc, arena };
|
||||
return info;
|
||||
}
|
||||
|
||||
inline
|
||||
Arena arena_init_from_memory( void* start, ssize size )
|
||||
{
|
||||
Arena arena = {
|
||||
{ nullptr, nullptr },
|
||||
start,
|
||||
size,
|
||||
0,
|
||||
0
|
||||
};
|
||||
return arena;
|
||||
}
|
||||
|
||||
inline
|
||||
Arena arena_init_from_allocator(AllocatorInfo backing, ssize size) {
|
||||
Arena result = {
|
||||
backing,
|
||||
alloc(backing, size),
|
||||
size,
|
||||
0,
|
||||
0
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
Arena arena_init_sub(Arena* parent, ssize size) {
|
||||
GEN_ASSERT(parent != nullptr);
|
||||
return arena_init_from_allocator(parent->Backing, size);
|
||||
}
|
||||
|
||||
inline
|
||||
ssize arena_alignment_of(Arena* arena, ssize alignment)
|
||||
{
|
||||
GEN_ASSERT(arena != nullptr);
|
||||
ssize alignment_offset, result_pointer, mask;
|
||||
GEN_ASSERT(is_power_of_two(alignment));
|
||||
|
||||
alignment_offset = 0;
|
||||
result_pointer = (ssize)arena->PhysicalStart + arena->TotalUsed;
|
||||
mask = alignment - 1;
|
||||
|
||||
if (result_pointer & mask)
|
||||
alignment_offset = alignment - (result_pointer & mask);
|
||||
|
||||
return alignment_offset;
|
||||
}
|
||||
|
||||
inline
|
||||
void arena_check(Arena* arena)
|
||||
{
|
||||
GEN_ASSERT(arena != nullptr );
|
||||
GEN_ASSERT(arena->TempCount == 0);
|
||||
}
|
||||
|
||||
inline
|
||||
void arena_free(Arena* arena)
|
||||
{
|
||||
GEN_ASSERT(arena != nullptr);
|
||||
if (arena->Backing.Proc)
|
||||
{
|
||||
allocator_free(arena->Backing, arena->PhysicalStart);
|
||||
arena->PhysicalStart = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
ssize arena_size_remaining(Arena* arena, ssize alignment)
|
||||
{
|
||||
GEN_ASSERT(arena != nullptr);
|
||||
ssize result = arena->TotalSize - (arena->TotalUsed + arena_alignment_of(arena, alignment));
|
||||
return result;
|
||||
}
|
||||
#pragma endregion Arena
|
||||
|
||||
#pragma region FixedArena
|
||||
template<s32 Size>
|
||||
struct FixedArena;
|
||||
|
||||
template<s32 Size> FixedArena<Size> fixed_arena_init();
|
||||
template<s32 Size> AllocatorInfo fixed_arena_allocator_info(FixedArena<Size>* fixed_arena );
|
||||
template<s32 Size> ssize fixed_arena_size_remaining(FixedArena<Size>* fixed_arena, ssize alignment);
|
||||
template<s32 Size> void fixed_arena_free(FixedArena<Size>* fixed_arena);
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
template<s32 Size> AllocatorInfo allocator_info( FixedArena<Size>& fixed_arena ) { return allocator_info(& fixed_arena); }
|
||||
template<s32 Size> ssize size_remaining(FixedArena<Size>& fixed_arena, ssize alignment) { return size_remaining( & fixed_arena, alignment); }
|
||||
#endif
|
||||
|
||||
// Just a wrapper around using an arena with memory associated with its scope instead of from an allocator.
|
||||
// Used for static segment or stack allocations.
|
||||
template< s32 Size >
|
||||
struct FixedArena
|
||||
{
|
||||
char memory[Size];
|
||||
Arena arena;
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
#pragma region Member Mapping
|
||||
forceinline operator AllocatorInfo() { return fixed_arena_allocator_info(this); }
|
||||
|
||||
forceinline static FixedArena init() { FixedArena result; fixed_arena_init<Size>(result); return result; }
|
||||
forceinline ssize size_remaining(ssize alignment) { fixed_arena_size_remaining(this, alignment); }
|
||||
#pragma endregion Member Mapping
|
||||
#endif
|
||||
};
|
||||
|
||||
template<s32 Size> inline
|
||||
AllocatorInfo fixed_arena_allocator_info( FixedArena<Size>* fixed_arena ) {
|
||||
GEN_ASSERT(fixed_arena);
|
||||
return { arena_allocator_proc, & fixed_arena->arena };
|
||||
}
|
||||
|
||||
template<s32 Size> inline
|
||||
void fixed_arena_init(FixedArena<Size>* result) {
|
||||
zero_size(& result->memory[0], Size);
|
||||
result->arena = arena_init_from_memory(& result->memory[0], Size);
|
||||
}
|
||||
|
||||
template<s32 Size> inline
|
||||
void fixed_arena_free(FixedArena<Size>* fixed_arena) {
|
||||
arena_free( & fixed_arena->arena);
|
||||
}
|
||||
|
||||
template<s32 Size> inline
|
||||
ssize fixed_arena_size_remaining(FixedArena<Size>* fixed_arena, ssize alignment) {
|
||||
return size_remaining(fixed_arena->arena, alignment);
|
||||
}
|
||||
|
||||
using FixedArena_1KB = FixedArena< kilobytes( 1 ) >;
|
||||
using FixedArena_4KB = FixedArena< kilobytes( 4 ) >;
|
||||
using FixedArena_8KB = FixedArena< kilobytes( 8 ) >;
|
||||
using FixedArena_16KB = FixedArena< kilobytes( 16 ) >;
|
||||
using FixedArena_32KB = FixedArena< kilobytes( 32 ) >;
|
||||
using FixedArena_64KB = FixedArena< kilobytes( 64 ) >;
|
||||
using FixedArena_128KB = FixedArena< kilobytes( 128 ) >;
|
||||
using FixedArena_256KB = FixedArena< kilobytes( 256 ) >;
|
||||
using FixedArena_512KB = FixedArena< kilobytes( 512 ) >;
|
||||
using FixedArena_1MB = FixedArena< megabytes( 1 ) >;
|
||||
using FixedArena_2MB = FixedArena< megabytes( 2 ) >;
|
||||
using FixedArena_4MB = FixedArena< megabytes( 4 ) >;
|
||||
#pragma endregion FixedArena
|
||||
|
||||
#pragma region Pool
|
||||
struct Pool;
|
||||
|
||||
GEN_API void* pool_allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags);
|
||||
|
||||
Pool pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size);
|
||||
Pool pool_init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align);
|
||||
AllocatorInfo pool_allocator_info(Pool* pool);
|
||||
GEN_API void pool_clear(Pool* pool);
|
||||
void pool_free(Pool* pool);
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline AllocatorInfo allocator_info(Pool& pool) { return pool_allocator_info(& pool); }
|
||||
forceinline void clear(Pool& pool) { return pool_clear(& pool); }
|
||||
forceinline void free(Pool& pool) { return pool_free(& pool); }
|
||||
#endif
|
||||
|
||||
struct Pool
|
||||
{
|
||||
AllocatorInfo Backing;
|
||||
void* PhysicalStart;
|
||||
void* FreeList;
|
||||
ssize BlockSize;
|
||||
ssize BlockAlign;
|
||||
ssize TotalSize;
|
||||
ssize NumBlocks;
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
#pragma region Member Mapping
|
||||
forceinline operator AllocatorInfo() { return pool_allocator_info(this); }
|
||||
|
||||
forceinline static void* allocator_proc(void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags) { return pool_allocator_proc(allocator_data, type, size, alignment, old_memory, old_size, flags); }
|
||||
forceinline static Pool init(AllocatorInfo backing, ssize num_blocks, ssize block_size) { return pool_init(backing, num_blocks, block_size); }
|
||||
forceinline static Pool init_align(AllocatorInfo backing, ssize num_blocks, ssize block_size, ssize block_align) { return pool_init_align(backing, num_blocks, block_size, block_align); }
|
||||
forceinline void clear() { pool_clear( this); }
|
||||
forceinline void free() { pool_free( this); }
|
||||
#pragma endregion
|
||||
#endif
|
||||
};
|
||||
|
||||
inline
|
||||
AllocatorInfo pool_allocator_info(Pool* pool) {
|
||||
AllocatorInfo info = { pool_allocator_proc, pool };
|
||||
return info;
|
||||
}
|
||||
|
||||
inline
|
||||
Pool pool_init(AllocatorInfo backing, ssize num_blocks, ssize block_size) {
|
||||
return pool_init_align(backing, num_blocks, block_size, GEN_DEFAULT_MEMORY_ALIGNMENT);
|
||||
}
|
||||
|
||||
inline
|
||||
void pool_free(Pool* pool) {
|
||||
if(pool->Backing.Proc) {
|
||||
allocator_free(pool->Backing, pool->PhysicalStart);
|
||||
}
|
||||
}
|
||||
#pragma endregion Pool
|
||||
|
||||
inline
|
||||
b32 is_power_of_two( ssize x ) {
|
||||
if ( x <= 0 )
|
||||
return false;
|
||||
return ! ( x & ( x - 1 ) );
|
||||
}
|
||||
|
||||
inline
|
||||
mem_ptr align_forward( void* ptr, ssize alignment )
|
||||
{
|
||||
GEN_ASSERT( is_power_of_two( alignment ) );
|
||||
uptr p = to_uptr(ptr);
|
||||
uptr forward = (p + ( alignment - 1 ) ) & ~( alignment - 1 );
|
||||
|
||||
return to_mem_ptr(forward);
|
||||
}
|
||||
|
||||
inline s64 align_forward_s64( s64 value, ssize alignment ) { return value + ( alignment - value % alignment ) % alignment; }
|
||||
|
||||
inline void* pointer_add ( void* ptr, ssize bytes ) { return rcast(void*, rcast( u8*, ptr) + bytes ); }
|
||||
inline void const* pointer_add_const( void const* ptr, ssize bytes ) { return rcast(void const*, rcast( u8 const*, ptr) + bytes ); }
|
||||
|
||||
inline sptr pointer_diff( mem_ptr_const begin, mem_ptr_const end ) {
|
||||
return scast( ssize, rcast( u8 const*, end) - rcast(u8 const*, begin) );
|
||||
}
|
||||
|
||||
inline
|
||||
void* mem_move( void* destination, void const* source, ssize byte_count )
|
||||
{
|
||||
if ( destination == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8* dest_ptr = rcast( u8*, destination);
|
||||
u8 const* src_ptr = rcast( u8 const*, source);
|
||||
|
||||
if ( dest_ptr == src_ptr )
|
||||
return dest_ptr;
|
||||
|
||||
if ( src_ptr + byte_count <= dest_ptr || dest_ptr + byte_count <= src_ptr ) // NOTE: Non-overlapping
|
||||
return mem_copy( dest_ptr, src_ptr, byte_count );
|
||||
|
||||
if ( dest_ptr < src_ptr )
|
||||
{
|
||||
if ( to_uptr(src_ptr) % size_of( ssize ) == to_uptr(dest_ptr) % size_of( ssize ) )
|
||||
{
|
||||
while ( pcast( uptr, dest_ptr) % size_of( ssize ) )
|
||||
{
|
||||
if ( ! byte_count-- )
|
||||
return destination;
|
||||
|
||||
*dest_ptr++ = *src_ptr++;
|
||||
}
|
||||
while ( byte_count >= size_of( ssize ) )
|
||||
{
|
||||
* rcast(ssize*, dest_ptr) = * rcast(ssize const*, src_ptr);
|
||||
byte_count -= size_of( ssize );
|
||||
dest_ptr += size_of( ssize );
|
||||
src_ptr += size_of( ssize );
|
||||
}
|
||||
}
|
||||
for ( ; byte_count; byte_count-- )
|
||||
*dest_ptr++ = *src_ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( to_uptr(src_ptr) % size_of( ssize ) ) == ( to_uptr(dest_ptr) % size_of( ssize ) ) )
|
||||
{
|
||||
while ( to_uptr( dest_ptr + byte_count ) % size_of( ssize ) )
|
||||
{
|
||||
if ( ! byte_count-- )
|
||||
return destination;
|
||||
|
||||
dest_ptr[ byte_count ] = src_ptr[ byte_count ];
|
||||
}
|
||||
while ( byte_count >= size_of( ssize ) )
|
||||
{
|
||||
byte_count -= size_of( ssize );
|
||||
* rcast(ssize*, dest_ptr + byte_count ) = * rcast( ssize const*, src_ptr + byte_count );
|
||||
}
|
||||
}
|
||||
while ( byte_count )
|
||||
byte_count--, dest_ptr[ byte_count ] = src_ptr[ byte_count ];
|
||||
}
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
inline
|
||||
void* mem_set( void* destination, u8 fill_byte, ssize byte_count )
|
||||
{
|
||||
if ( destination == NULL )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssize align_offset;
|
||||
u8* dest_ptr = rcast( u8*, destination);
|
||||
u32 fill_word = ( ( u32 )-1 ) / 255 * fill_byte;
|
||||
|
||||
if ( byte_count == 0 )
|
||||
return destination;
|
||||
|
||||
dest_ptr[ 0 ] = dest_ptr[ byte_count - 1 ] = fill_byte;
|
||||
if ( byte_count < 3 )
|
||||
return destination;
|
||||
|
||||
dest_ptr[ 1 ] = dest_ptr[ byte_count - 2 ] = fill_byte;
|
||||
dest_ptr[ 2 ] = dest_ptr[ byte_count - 3 ] = fill_byte;
|
||||
if ( byte_count < 7 )
|
||||
return destination;
|
||||
|
||||
dest_ptr[ 3 ] = dest_ptr[ byte_count - 4 ] = fill_byte;
|
||||
if ( byte_count < 9 )
|
||||
return destination;
|
||||
|
||||
align_offset = -to_sptr( dest_ptr ) & 3;
|
||||
dest_ptr += align_offset;
|
||||
byte_count -= align_offset;
|
||||
byte_count &= -4;
|
||||
|
||||
* rcast( u32*, ( dest_ptr + 0 ) ) = fill_word;
|
||||
* rcast( u32*, ( dest_ptr + byte_count - 4 ) ) = fill_word;
|
||||
if ( byte_count < 9 )
|
||||
return destination;
|
||||
|
||||
* rcast( u32*, dest_ptr + 4 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + 8 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + byte_count - 12 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + byte_count - 8 ) = fill_word;
|
||||
if ( byte_count < 25 )
|
||||
return destination;
|
||||
|
||||
* rcast( u32*, dest_ptr + 12 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + 16 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + 20 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + 24 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + byte_count - 28 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + byte_count - 24 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + byte_count - 20 ) = fill_word;
|
||||
* rcast( u32*, dest_ptr + byte_count - 16 ) = fill_word;
|
||||
|
||||
align_offset = 24 + to_uptr( dest_ptr ) & 4;
|
||||
dest_ptr += align_offset;
|
||||
byte_count -= align_offset;
|
||||
|
||||
{
|
||||
u64 fill_doubleword = ( scast( u64, fill_word) << 32 ) | fill_word;
|
||||
while ( byte_count > 31 )
|
||||
{
|
||||
* rcast( u64*, dest_ptr + 0 ) = fill_doubleword;
|
||||
* rcast( u64*, dest_ptr + 8 ) = fill_doubleword;
|
||||
* rcast( u64*, dest_ptr + 16 ) = fill_doubleword;
|
||||
* rcast( u64*, dest_ptr + 24 ) = fill_doubleword;
|
||||
|
||||
byte_count -= 32;
|
||||
dest_ptr += 32;
|
||||
}
|
||||
}
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
inline
|
||||
void* alloc_align( AllocatorInfo a, ssize size, ssize alignment ) {
|
||||
return a.Proc( a.Data, EAllocation_ALLOC, size, alignment, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS );
|
||||
}
|
||||
|
||||
inline
|
||||
void* alloc( AllocatorInfo a, ssize size ) {
|
||||
return alloc_align( a, size, GEN_DEFAULT_MEMORY_ALIGNMENT );
|
||||
}
|
||||
|
||||
inline
|
||||
void allocator_free( AllocatorInfo a, void* ptr ) {
|
||||
if ( ptr != nullptr )
|
||||
a.Proc( a.Data, EAllocation_FREE, 0, 0, ptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS );
|
||||
}
|
||||
|
||||
inline
|
||||
void free_all( AllocatorInfo a ) {
|
||||
a.Proc( a.Data, EAllocation_FREE_ALL, 0, 0, nullptr, 0, GEN_DEFAULT_ALLOCATOR_FLAGS );
|
||||
}
|
||||
|
||||
inline
|
||||
void* resize( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size ) {
|
||||
return resize_align( a, ptr, old_size, new_size, GEN_DEFAULT_MEMORY_ALIGNMENT );
|
||||
}
|
||||
|
||||
inline
|
||||
void* resize_align( AllocatorInfo a, void* ptr, ssize old_size, ssize new_size, ssize alignment ) {
|
||||
return a.Proc( a.Data, EAllocation_RESIZE, new_size, alignment, ptr, old_size, GEN_DEFAULT_ALLOCATOR_FLAGS );
|
||||
}
|
||||
|
||||
inline
|
||||
void* default_resize_align( AllocatorInfo a, void* old_memory, ssize old_size, ssize new_size, ssize alignment )
|
||||
{
|
||||
if ( ! old_memory )
|
||||
return alloc_align( a, new_size, alignment );
|
||||
|
||||
if ( new_size == 0 )
|
||||
{
|
||||
allocator_free( a, old_memory );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( new_size < old_size )
|
||||
new_size = old_size;
|
||||
|
||||
if ( old_size == new_size )
|
||||
{
|
||||
return old_memory;
|
||||
}
|
||||
else
|
||||
{
|
||||
void* new_memory = alloc_align( a, new_size, alignment );
|
||||
if ( ! new_memory )
|
||||
return nullptr;
|
||||
|
||||
mem_move( new_memory, old_memory, min( new_size, old_size ) );
|
||||
allocator_free( a, old_memory );
|
||||
return new_memory;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void zero_size( void* ptr, ssize size ) {
|
||||
mem_set( ptr, 0, size );
|
||||
}
|
||||
|
||||
#pragma endregion Memory
|
||||
@@ -1,9 +1,14 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "parsing.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region ADT
|
||||
|
||||
#define _adt_fprintf( s_, fmt_, ... ) \
|
||||
do \
|
||||
{ \
|
||||
if ( str_fmt_file( s_, fmt_, ##__VA_ARGS__ ) < 0 ) \
|
||||
if ( c_str_fmt_file( s_, fmt_, ##__VA_ARGS__ ) < 0 ) \
|
||||
return EADT_ERROR_OUT_OF_MEMORY; \
|
||||
} while ( 0 )
|
||||
|
||||
@@ -19,7 +24,7 @@ u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32
|
||||
node->type = type;
|
||||
node->name = name;
|
||||
node->parent = parent;
|
||||
node->nodes = Array<ADT_Node>::init( backing );
|
||||
node->nodes = array_init(ADT_Node, backing );
|
||||
|
||||
if ( ! node->nodes )
|
||||
return EADT_ERROR_OUT_OF_MEMORY;
|
||||
@@ -32,12 +37,12 @@ u8 adt_destroy_branch( ADT_Node* node )
|
||||
GEN_ASSERT_NOT_NULL( node );
|
||||
if ( ( node->type == EADT_TYPE_OBJECT || node->type == EADT_TYPE_ARRAY ) && node->nodes )
|
||||
{
|
||||
for ( sw i = 0; i < node->nodes.num(); ++i )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); ++i )
|
||||
{
|
||||
adt_destroy_branch( node->nodes + i );
|
||||
}
|
||||
|
||||
node->nodes.free();
|
||||
array_free(node->nodes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -62,9 +67,9 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search )
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( sw i = 0; i < node->nodes.num(); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
if ( ! str_compare( node->nodes[ i ].name, name ) )
|
||||
if ( ! c_str_compare( node->nodes[ i ].name, name ) )
|
||||
{
|
||||
return ( node->nodes + i );
|
||||
}
|
||||
@@ -72,7 +77,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search )
|
||||
|
||||
if ( deep_search )
|
||||
{
|
||||
for ( sw i = 0; i < node->nodes.num(); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
ADT_Node* res = adt_find( node->nodes + i, name, deep_search );
|
||||
|
||||
@@ -91,7 +96,7 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value )
|
||||
case EADT_TYPE_MULTISTRING :
|
||||
case EADT_TYPE_STRING :
|
||||
{
|
||||
if ( node->string && ! str_compare( node->string, value ) )
|
||||
if ( node->string && ! c_str_compare( node->string, value ) )
|
||||
{
|
||||
return node;
|
||||
}
|
||||
@@ -107,10 +112,10 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value )
|
||||
file_stream_open( &tmp, heap(), ( u8* )back, size_of( back ), EFileStream_WRITABLE );
|
||||
adt_print_number( &tmp, node );
|
||||
|
||||
sw fsize = 0;
|
||||
ssize fsize = 0;
|
||||
u8* buf = file_stream_buf( &tmp, &fsize );
|
||||
|
||||
if ( ! str_compare( ( char const* )buf, value ) )
|
||||
if ( ! c_str_compare( ( char const* )buf, value ) )
|
||||
{
|
||||
file_close( &tmp );
|
||||
return node;
|
||||
@@ -128,9 +133,9 @@ internal ADT_Node* _adt_get_value( ADT_Node* node, char const* value )
|
||||
|
||||
internal ADT_Node* _adt_get_field( ADT_Node* node, char* name, char* value )
|
||||
{
|
||||
for ( sw i = 0; i < node->nodes.num(); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
if ( ! str_compare( node->nodes[ i ].name, name ) )
|
||||
if ( ! c_str_compare( node->nodes[ i ].name, name ) )
|
||||
{
|
||||
ADT_Node* child = &node->nodes[ i ];
|
||||
if ( _adt_get_value( child, value ) )
|
||||
@@ -163,22 +168,22 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
|
||||
}
|
||||
|
||||
#if defined EADT_URI_DEBUG || 0
|
||||
str_fmt_out( "uri: %s\n", uri );
|
||||
c_str_fmt_out( "uri: %s\n", uri );
|
||||
#endif
|
||||
|
||||
char * p = ( char* )uri, *b = p, *e = p;
|
||||
ADT_Node* found_node = NULL;
|
||||
|
||||
b = p;
|
||||
p = e = ( char* )str_skip( p, '/' );
|
||||
char* buf = str_fmt_buf( "%.*s", ( int )( e - b ), b );
|
||||
p = e = ( char* )c_str_skip( p, '/' );
|
||||
char* buf = c_str_fmt_buf( "%.*s", ( int )( e - b ), b );
|
||||
|
||||
/* handle field value lookup */
|
||||
if ( *b == '[' )
|
||||
{
|
||||
char *l_p = buf + 1, *l_b = l_p, *l_e = l_p, *l_b2 = l_p, *l_e2 = l_p;
|
||||
l_e = ( char* )str_skip( l_p, '=' );
|
||||
l_e2 = ( char* )str_skip( l_p, ']' );
|
||||
l_e = ( char* )c_str_skip( l_p, '=' );
|
||||
l_e2 = ( char* )c_str_skip( l_p, ']' );
|
||||
|
||||
if ( ( ! *l_e && node->type != EADT_TYPE_ARRAY ) || ! *l_e2 )
|
||||
{
|
||||
@@ -203,7 +208,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
|
||||
/* run a value comparison against any child that is an object node */
|
||||
else if ( node->type == EADT_TYPE_ARRAY )
|
||||
{
|
||||
for ( sw i = 0; i < node->nodes.num(); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
ADT_Node* child = &node->nodes[ i ];
|
||||
if ( child->type != EADT_TYPE_OBJECT )
|
||||
@@ -221,7 +226,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
|
||||
/* [value] */
|
||||
else
|
||||
{
|
||||
for ( sw i = 0; i < node->nodes.num(); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(node->nodes)); i++ )
|
||||
{
|
||||
ADT_Node* child = &node->nodes[ i ];
|
||||
if ( _adt_get_value( child, l_b2 ) )
|
||||
@@ -252,8 +257,8 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
|
||||
/* handle array index lookup */
|
||||
else
|
||||
{
|
||||
sw idx = ( sw )str_to_i64( buf, NULL, 10 );
|
||||
if ( idx >= 0 && idx < node->nodes.num() )
|
||||
ssize idx = ( ssize )c_str_to_i64( buf, NULL, 10 );
|
||||
if ( idx >= 0 && idx < scast(ssize, array_num(node->nodes)) )
|
||||
{
|
||||
found_node = &node->nodes[ idx ];
|
||||
|
||||
@@ -268,7 +273,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri )
|
||||
return found_node;
|
||||
}
|
||||
|
||||
ADT_Node* adt_alloc_at( ADT_Node* parent, sw index )
|
||||
ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index )
|
||||
{
|
||||
if ( ! parent || ( parent->type != EADT_TYPE_OBJECT && parent->type != EADT_TYPE_ARRAY ) )
|
||||
{
|
||||
@@ -278,15 +283,16 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, sw index )
|
||||
if ( ! parent->nodes )
|
||||
return NULL;
|
||||
|
||||
if ( index < 0 || index > parent->nodes.num() )
|
||||
if ( index < 0 || index > scast(ssize, array_num(parent->nodes)) )
|
||||
return NULL;
|
||||
|
||||
ADT_Node o = { 0 };
|
||||
o.parent = parent;
|
||||
if ( ! parent->nodes.append_at( o, index ) )
|
||||
if ( ! array_append_at( parent->nodes, o, index ) )
|
||||
return NULL;
|
||||
|
||||
return parent->nodes + index;
|
||||
ADT_Node* node = & parent->nodes[index];
|
||||
return node;
|
||||
}
|
||||
|
||||
ADT_Node* adt_alloc( ADT_Node* parent )
|
||||
@@ -299,7 +305,7 @@ ADT_Node* adt_alloc( ADT_Node* parent )
|
||||
if ( ! parent->nodes )
|
||||
return NULL;
|
||||
|
||||
return adt_alloc_at( parent, parent->nodes.num() );
|
||||
return adt_alloc_at( parent, array_num(parent->nodes) );
|
||||
}
|
||||
|
||||
b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing )
|
||||
@@ -333,7 +339,7 @@ b8 adt_set_int( ADT_Node* obj, char const* name, s64 value )
|
||||
return true;
|
||||
}
|
||||
|
||||
ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index )
|
||||
ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL( node );
|
||||
GEN_ASSERT_NOT_NULL( new_parent );
|
||||
@@ -353,7 +359,7 @@ ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent )
|
||||
GEN_ASSERT_NOT_NULL( node );
|
||||
GEN_ASSERT_NOT_NULL( new_parent );
|
||||
GEN_ASSERT( new_parent->type == EADT_TYPE_ARRAY || new_parent->type == EADT_TYPE_OBJECT );
|
||||
return adt_move_node_at( node, new_parent, new_parent->nodes.num() );
|
||||
return adt_move_node_at( node, new_parent, array_num(new_parent->nodes) );
|
||||
}
|
||||
|
||||
void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node )
|
||||
@@ -362,8 +368,8 @@ void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node )
|
||||
GEN_ASSERT_NOT_NULL( other_node );
|
||||
ADT_Node* parent = node->parent;
|
||||
ADT_Node* other_parent = other_node->parent;
|
||||
sw index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) );
|
||||
sw index2 = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) );
|
||||
ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) );
|
||||
ssize index2 = ( pointer_diff( other_parent->nodes, other_node ) / size_of( ADT_Node ) );
|
||||
ADT_Node temp = parent->nodes[ index ];
|
||||
temp.parent = other_parent;
|
||||
other_parent->nodes[ index2 ].parent = parent;
|
||||
@@ -376,8 +382,8 @@ void adt_remove_node( ADT_Node* node )
|
||||
GEN_ASSERT_NOT_NULL( node );
|
||||
GEN_ASSERT_NOT_NULL( node->parent );
|
||||
ADT_Node* parent = node->parent;
|
||||
sw index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) );
|
||||
parent->nodes.remove_at( index );
|
||||
ssize index = ( pointer_diff( parent->nodes, node ) / size_of( ADT_Node ) );
|
||||
array_remove_at( parent->nodes, index );
|
||||
}
|
||||
|
||||
ADT_Node* adt_append_obj( ADT_Node* parent, char const* name )
|
||||
@@ -385,7 +391,7 @@ ADT_Node* adt_append_obj( ADT_Node* parent, char const* name )
|
||||
ADT_Node* o = adt_alloc( parent );
|
||||
if ( ! o )
|
||||
return NULL;
|
||||
if ( adt_set_obj( o, name, parent->nodes.get_header()->Allocator ) )
|
||||
if ( adt_set_obj( o, name, array_get_header(parent->nodes)->Allocator ) )
|
||||
{
|
||||
adt_remove_node( o );
|
||||
return NULL;
|
||||
@@ -398,7 +404,9 @@ ADT_Node* adt_append_arr( ADT_Node* parent, char const* name )
|
||||
ADT_Node* o = adt_alloc( parent );
|
||||
if ( ! o )
|
||||
return NULL;
|
||||
if ( adt_set_arr( o, name, parent->nodes.get_header()->Allocator ) )
|
||||
|
||||
ArrayHeader* node_header = array_get_header(parent->nodes);
|
||||
if ( adt_set_arr( o, name, node_header->Allocator ) )
|
||||
{
|
||||
adt_remove_node( o );
|
||||
return NULL;
|
||||
@@ -443,7 +451,7 @@ char* adt_parse_number_strict( ADT_Node* node, char* base_str )
|
||||
while ( *e )
|
||||
++e;
|
||||
|
||||
while ( *p && ( str_find( "eE.+-", *p ) || char_is_hex_digit( *p ) ) )
|
||||
while ( *p && ( char_first_occurence( "eE.+-", *p ) || char_is_hex_digit( *p ) ) )
|
||||
{
|
||||
++p;
|
||||
}
|
||||
@@ -472,7 +480,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
u8 node_props = 0;
|
||||
|
||||
/* skip false positives and special cases */
|
||||
if ( ! ! str_find( "eE", *p ) || ( ! ! str_find( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) )
|
||||
if ( ! ! char_first_occurence( "eE", *p ) || ( ! ! char_first_occurence( ".+-", *p ) && ! char_is_hex_digit( *( p + 1 ) ) && *( p + 1 ) != '.' ) )
|
||||
{
|
||||
return ++base_str;
|
||||
}
|
||||
@@ -480,7 +488,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
node_type = EADT_TYPE_INTEGER;
|
||||
neg_zero = false;
|
||||
|
||||
sw ib = 0;
|
||||
ssize ib = 0;
|
||||
char buf[ 48 ] = { 0 };
|
||||
|
||||
if ( *e == '+' )
|
||||
@@ -503,7 +511,7 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! str_compare( e, "0x", 2 ) || ! str_compare( e, "0X", 2 ) )
|
||||
if ( ! c_str_compare_len( e, "0x", 2 ) || ! c_str_compare_len( e, "0X", 2 ) )
|
||||
{
|
||||
node_props = EADT_PROPS_IS_HEX;
|
||||
}
|
||||
@@ -546,9 +554,9 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
|
||||
f32 eb = 10;
|
||||
char expbuf[ 6 ] = { 0 };
|
||||
sw expi = 0;
|
||||
ssize expi = 0;
|
||||
|
||||
if ( *e && ! ! str_find( "eE", *e ) )
|
||||
if ( *e && ! ! char_first_occurence( "eE", *e ) )
|
||||
{
|
||||
++e;
|
||||
if ( *e == '+' || *e == '-' || char_is_digit( *e ) )
|
||||
@@ -567,12 +575,12 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
}
|
||||
}
|
||||
|
||||
orig_exp = exp = ( u8 )str_to_i64( expbuf, NULL, 10 );
|
||||
orig_exp = exp = ( u8 )c_str_to_i64( expbuf, NULL, 10 );
|
||||
}
|
||||
|
||||
if ( node_type == EADT_TYPE_INTEGER )
|
||||
{
|
||||
node->integer = str_to_i64( buf, 0, 0 );
|
||||
node->integer = c_str_to_i64( buf, 0, 0 );
|
||||
#ifndef GEN_PARSER_DISABLE_ANALYSIS
|
||||
/* special case: negative zero */
|
||||
if ( node->integer == 0 && buf[ 0 ] == '-' )
|
||||
@@ -587,19 +595,19 @@ char* adt_parse_number( ADT_Node* node, char* base_str )
|
||||
}
|
||||
else
|
||||
{
|
||||
node->real = str_to_f64( buf, 0 );
|
||||
node->real = c_str_to_f64( buf, 0 );
|
||||
|
||||
#ifndef GEN_PARSER_DISABLE_ANALYSIS
|
||||
char *q = buf, *base_string = q, *base_string2 = q;
|
||||
base_string = zpl_cast( char* ) str_skip( base_string, '.' );
|
||||
base_string = ccast( char*, c_str_skip( base_string, '.' ));
|
||||
*base_string = '\0';
|
||||
base_string2 = base_string + 1;
|
||||
char* base_string_off = base_string2;
|
||||
while ( *base_string_off++ == '0' )
|
||||
char* base_strbuilder_off = base_string2;
|
||||
while ( *base_strbuilder_off++ == '0' )
|
||||
base2_offset++;
|
||||
|
||||
base = ( s32 )str_to_i64( q, 0, 0 );
|
||||
base2 = ( s32 )str_to_i64( base_string2, 0, 0 );
|
||||
base = ( s32 )c_str_to_i64( q, 0, 0 );
|
||||
base2 = ( s32 )c_str_to_i64( base_string2, 0, 0 );
|
||||
if ( exp )
|
||||
{
|
||||
exp = exp * ( ! ( eb == 10.0f ) ? -1 : 1 );
|
||||
@@ -742,9 +750,9 @@ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_
|
||||
|
||||
do
|
||||
{
|
||||
p = str_skip_any( p, escaped_chars );
|
||||
p = c_str_skip_any( p, escaped_chars );
|
||||
_adt_fprintf( file, "%.*s", pointer_diff( b, p ), b );
|
||||
if ( *p && ! ! str_find( escaped_chars, *p ) )
|
||||
if ( *p && ! ! char_first_occurence( escaped_chars, *p ) )
|
||||
{
|
||||
_adt_fprintf( file, "%s%c", escape_symbol, *p );
|
||||
p++;
|
||||
@@ -755,7 +763,7 @@ ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_
|
||||
return EADT_ERROR_NONE;
|
||||
}
|
||||
|
||||
ADT_Error adt_str_to_number( ADT_Node* node )
|
||||
ADT_Error adt_c_str_to_number( ADT_Node* node )
|
||||
{
|
||||
GEN_ASSERT( node );
|
||||
|
||||
@@ -771,7 +779,7 @@ ADT_Error adt_str_to_number( ADT_Node* node )
|
||||
return EADT_ERROR_NONE;
|
||||
}
|
||||
|
||||
ADT_Error adt_str_to_number_strict( ADT_Node* node )
|
||||
ADT_Error adt_c_str_to_number_strict( ADT_Node* node )
|
||||
{
|
||||
GEN_ASSERT( node );
|
||||
|
||||
@@ -812,13 +820,13 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
char* beginChar;
|
||||
char* endChar;
|
||||
|
||||
sw columnIndex = 0;
|
||||
sw totalColumnIndex = 0;
|
||||
ssize columnIndex = 0;
|
||||
ssize totalColumnIndex = 0;
|
||||
|
||||
do
|
||||
{
|
||||
char delimiter = 0;
|
||||
currentChar = zpl_cast( char* ) str_trim( currentChar, false );
|
||||
currentChar = ccast( char*, c_str_trim( currentChar, false ));
|
||||
|
||||
if ( *currentChar == 0 )
|
||||
break;
|
||||
@@ -842,7 +850,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
#endif
|
||||
do
|
||||
{
|
||||
endChar = zpl_cast( char* ) str_skip( endChar, '"' );
|
||||
endChar = ccast( char*, c_str_skip( endChar, '"' ));
|
||||
|
||||
if ( *endChar && *( endChar + 1 ) == '"' )
|
||||
{
|
||||
@@ -861,7 +869,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
}
|
||||
|
||||
*endChar = 0;
|
||||
currentChar = zpl_cast( char* ) str_trim( endChar + 1, true );
|
||||
currentChar = ccast( char*, c_str_trim( endChar + 1, true ));
|
||||
delimiter = * currentChar;
|
||||
|
||||
/* unescape escaped quotes (so that unescaped text escapes :) */
|
||||
@@ -871,7 +879,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
{
|
||||
if ( *escapedChar == '"' && *( escapedChar + 1 ) == '"' )
|
||||
{
|
||||
mem_move( escapedChar, escapedChar + 1, str_len( escapedChar ) );
|
||||
mem_move( escapedChar, escapedChar + 1, c_str_len( escapedChar ) );
|
||||
}
|
||||
escapedChar++;
|
||||
}
|
||||
@@ -898,7 +906,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
|
||||
if ( * endChar )
|
||||
{
|
||||
currentChar = zpl_cast( char* ) str_trim( endChar, true );
|
||||
currentChar = ccast( char*, c_str_trim( endChar, true ));
|
||||
|
||||
while ( char_is_space( *( endChar - 1 ) ) )
|
||||
{
|
||||
@@ -919,7 +927,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
char* num_p = beginChar;
|
||||
|
||||
// We only consider hexadecimal values if they start with 0x
|
||||
if ( str_len(num_p) > 2 && num_p[0] == '0' && (num_p[1] == 'x' || num_p[1] == 'X') )
|
||||
if ( c_str_len(num_p) > 2 && num_p[0] == '0' && (num_p[1] == 'x' || num_p[1] == 'X') )
|
||||
{
|
||||
num_p += 2; // skip '0x' prefix
|
||||
do
|
||||
@@ -938,16 +946,16 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
|
||||
if (!skip_number)
|
||||
{
|
||||
adt_str_to_number(&rowItem);
|
||||
adt_c_str_to_number(&rowItem);
|
||||
}
|
||||
}
|
||||
|
||||
if ( columnIndex >= root->nodes.num() )
|
||||
if ( columnIndex >= scast(ssize, array_num(root->nodes)) )
|
||||
{
|
||||
adt_append_arr( root, NULL );
|
||||
}
|
||||
|
||||
root->nodes[ columnIndex ].nodes.append( rowItem );
|
||||
array_append( root->nodes[ columnIndex ].nodes, rowItem );
|
||||
|
||||
if ( delimiter == delim )
|
||||
{
|
||||
@@ -975,7 +983,7 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
}
|
||||
while ( *currentChar );
|
||||
|
||||
if ( root->nodes.num() == 0 )
|
||||
if (array_num( root->nodes) == 0 )
|
||||
{
|
||||
GEN_CSV_ASSERT( "unexpected end of input. stream is empty." );
|
||||
error = ECSV_Error__UNEXPECTED_END_OF_INPUT;
|
||||
@@ -985,12 +993,12 @@ u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b
|
||||
/* consider first row as a header. */
|
||||
if ( has_header )
|
||||
{
|
||||
for ( sw i = 0; i < root->nodes.num(); i++ )
|
||||
for ( ssize i = 0; i < scast(ssize, array_num(root->nodes)); i++ )
|
||||
{
|
||||
CSV_Object* col = root->nodes + i;
|
||||
CSV_Object* hdr = col->nodes;
|
||||
col->name = hdr->string;
|
||||
col->nodes.remove_at( 0 );
|
||||
array_remove_at(col->nodes, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,16 +1021,16 @@ void _csv_write_record( FileInfo* file, CSV_Object* node )
|
||||
{
|
||||
case EADT_NAME_STYLE_DOUBLE_QUOTE :
|
||||
{
|
||||
str_fmt_file( file, "\"" );
|
||||
c_str_fmt_file( file, "\"" );
|
||||
adt_print_string( file, node, "\"", "\"" );
|
||||
str_fmt_file( file, "\"" );
|
||||
c_str_fmt_file( file, "\"" );
|
||||
}
|
||||
break;
|
||||
|
||||
case EADT_NAME_STYLE_NO_QUOTES :
|
||||
{
|
||||
#endif
|
||||
str_fmt_file( file, "%s", node->string );
|
||||
c_str_fmt_file( file, "%s", node->string );
|
||||
#ifndef GEN_PARSER_DISABLE_ANALYSIS
|
||||
}
|
||||
break;
|
||||
@@ -1053,11 +1061,11 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter )
|
||||
GEN_ASSERT_NOT_NULL( file );
|
||||
GEN_ASSERT_NOT_NULL( obj );
|
||||
GEN_ASSERT( obj->nodes );
|
||||
sw cols = obj->nodes.num();
|
||||
ssize cols = array_num(obj->nodes);
|
||||
if ( cols == 0 )
|
||||
return;
|
||||
|
||||
sw rows = obj->nodes[ 0 ].nodes.num();
|
||||
ssize rows = array_num(obj->nodes[ 0 ].nodes);
|
||||
if ( rows == 0 )
|
||||
return;
|
||||
|
||||
@@ -1065,42 +1073,44 @@ void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delimiter )
|
||||
|
||||
if ( has_headers )
|
||||
{
|
||||
for ( sw i = 0; i < cols; i++ )
|
||||
for ( ssize i = 0; i < cols; i++ )
|
||||
{
|
||||
_csv_write_header( file, &obj->nodes[ i ] );
|
||||
if ( i + 1 != cols )
|
||||
{
|
||||
str_fmt_file( file, "%c", delimiter );
|
||||
c_str_fmt_file( file, "%c", delimiter );
|
||||
}
|
||||
}
|
||||
str_fmt_file( file, "\n" );
|
||||
c_str_fmt_file( file, "\n" );
|
||||
}
|
||||
|
||||
for ( sw r = 0; r < rows; r++ )
|
||||
for ( ssize r = 0; r < rows; r++ )
|
||||
{
|
||||
for ( sw i = 0; i < cols; i++ )
|
||||
for ( ssize i = 0; i < cols; i++ )
|
||||
{
|
||||
_csv_write_record( file, &obj->nodes[ i ].nodes[ r ] );
|
||||
if ( i + 1 != cols )
|
||||
{
|
||||
str_fmt_file( file, "%c", delimiter );
|
||||
c_str_fmt_file( file, "%c", delimiter );
|
||||
}
|
||||
}
|
||||
str_fmt_file( file, "\n" );
|
||||
c_str_fmt_file( file, "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delimiter )
|
||||
StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delimiter )
|
||||
{
|
||||
FileInfo tmp;
|
||||
file_stream_new( &tmp, a );
|
||||
csv_write_delimiter( &tmp, obj, delimiter );
|
||||
sw fsize;
|
||||
|
||||
ssize fsize;
|
||||
u8* buf = file_stream_buf( &tmp, &fsize );
|
||||
String output = String::make_length( a, ( char* )buf, fsize );
|
||||
StrBuilder output = strbuilder_make_length( a, ( char* )buf, fsize );
|
||||
file_close( &tmp );
|
||||
return output;
|
||||
}
|
||||
|
||||
#pragma endregion CSV
|
||||
#undef _adt_fprintf
|
||||
|
||||
#pragma endregion CSV
|
||||
@@ -1,3 +1,8 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "timing.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region ADT
|
||||
|
||||
enum ADT_Type : u32
|
||||
@@ -79,7 +84,7 @@ struct ADT_Node
|
||||
union
|
||||
{
|
||||
char const* string;
|
||||
Array<ADT_Node> nodes; ///< zpl_array
|
||||
Array(ADT_Node) nodes; ///< zpl_array
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -117,7 +122,7 @@ struct ADT_Node
|
||||
* @param is_array
|
||||
* @return error code
|
||||
*/
|
||||
u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array );
|
||||
GEN_API u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32 is_array );
|
||||
|
||||
/**
|
||||
* @brief Destroy an ADT branch and its descendants
|
||||
@@ -125,7 +130,7 @@ u8 adt_make_branch( ADT_Node* node, AllocatorInfo backing, char const* name, b32
|
||||
* @param node
|
||||
* @return error code
|
||||
*/
|
||||
u8 adt_destroy_branch( ADT_Node* node );
|
||||
GEN_API u8 adt_destroy_branch( ADT_Node* node );
|
||||
|
||||
/**
|
||||
* @brief Initialise an ADT leaf
|
||||
@@ -135,7 +140,7 @@ u8 adt_destroy_branch( ADT_Node* node );
|
||||
* @param type Node's type (use zpl_adt_make_branch for container nodes)
|
||||
* @return error code
|
||||
*/
|
||||
u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type );
|
||||
GEN_API u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type );
|
||||
|
||||
|
||||
/**
|
||||
@@ -155,7 +160,7 @@ u8 adt_make_leaf( ADT_Node* node, char const* name, ADT_Type type );
|
||||
*
|
||||
* @see code/apps/examples/json_get.c
|
||||
*/
|
||||
ADT_Node* adt_query( ADT_Node* node, char const* uri );
|
||||
GEN_API ADT_Node* adt_query( ADT_Node* node, char const* uri );
|
||||
|
||||
/**
|
||||
* @brief Find a field node within an object by the given name.
|
||||
@@ -165,7 +170,7 @@ ADT_Node* adt_query( ADT_Node* node, char const* uri );
|
||||
* @param deep_search Perform search recursively
|
||||
* @return zpl_adt_node * node
|
||||
*/
|
||||
ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search );
|
||||
GEN_API ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search );
|
||||
|
||||
/**
|
||||
* @brief Allocate an unitialised node within a container at a specified index.
|
||||
@@ -174,7 +179,7 @@ ADT_Node* adt_find( ADT_Node* node, char const* name, b32 deep_search );
|
||||
* @param index
|
||||
* @return zpl_adt_node * node
|
||||
*/
|
||||
ADT_Node* adt_alloc_at( ADT_Node* parent, sw index );
|
||||
GEN_API ADT_Node* adt_alloc_at( ADT_Node* parent, ssize index );
|
||||
|
||||
/**
|
||||
* @brief Allocate an unitialised node within a container.
|
||||
@@ -182,7 +187,7 @@ ADT_Node* adt_alloc_at( ADT_Node* parent, sw index );
|
||||
* @param parent
|
||||
* @return zpl_adt_node * node
|
||||
*/
|
||||
ADT_Node* adt_alloc( ADT_Node* parent );
|
||||
GEN_API ADT_Node* adt_alloc( ADT_Node* parent );
|
||||
|
||||
/**
|
||||
* @brief Move an existing node to a new container at a specified index.
|
||||
@@ -192,7 +197,7 @@ ADT_Node* adt_alloc( ADT_Node* parent );
|
||||
* @param index
|
||||
* @return zpl_adt_node * node
|
||||
*/
|
||||
ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index );
|
||||
GEN_API ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, ssize index );
|
||||
|
||||
/**
|
||||
* @brief Move an existing node to a new container.
|
||||
@@ -201,7 +206,7 @@ ADT_Node* adt_move_node_at( ADT_Node* node, ADT_Node* new_parent, sw index );
|
||||
* @param new_parent
|
||||
* @return zpl_adt_node * node
|
||||
*/
|
||||
ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent );
|
||||
GEN_API ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent );
|
||||
|
||||
/**
|
||||
* @brief Swap two nodes.
|
||||
@@ -210,7 +215,7 @@ ADT_Node* adt_move_node( ADT_Node* node, ADT_Node* new_parent );
|
||||
* @param other_node
|
||||
* @return
|
||||
*/
|
||||
void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node );
|
||||
GEN_API void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node );
|
||||
|
||||
/**
|
||||
* @brief Remove node from container.
|
||||
@@ -218,7 +223,7 @@ void adt_swap_nodes( ADT_Node* node, ADT_Node* other_node );
|
||||
* @param node
|
||||
* @return
|
||||
*/
|
||||
void adt_remove_node( ADT_Node* node );
|
||||
GEN_API void adt_remove_node( ADT_Node* node );
|
||||
|
||||
/**
|
||||
* @brief Initialise a node as an object
|
||||
@@ -228,7 +233,7 @@ void adt_remove_node( ADT_Node* node );
|
||||
* @param backing
|
||||
* @return
|
||||
*/
|
||||
b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing );
|
||||
GEN_API b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing );
|
||||
|
||||
/**
|
||||
* @brief Initialise a node as an array
|
||||
@@ -238,7 +243,7 @@ b8 adt_set_obj( ADT_Node* obj, char const* name, AllocatorInfo backing );
|
||||
* @param backing
|
||||
* @return
|
||||
*/
|
||||
b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing );
|
||||
GEN_API b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing );
|
||||
|
||||
/**
|
||||
* @brief Initialise a node as a string
|
||||
@@ -248,7 +253,7 @@ b8 adt_set_arr( ADT_Node* obj, char const* name, AllocatorInfo backing );
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
b8 adt_set_str( ADT_Node* obj, char const* name, char const* value );
|
||||
GEN_API b8 adt_set_str( ADT_Node* obj, char const* name, char const* value );
|
||||
|
||||
/**
|
||||
* @brief Initialise a node as a float
|
||||
@@ -258,7 +263,7 @@ b8 adt_set_str( ADT_Node* obj, char const* name, char const* value );
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value );
|
||||
GEN_API b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value );
|
||||
|
||||
/**
|
||||
* @brief Initialise a node as a signed integer
|
||||
@@ -268,7 +273,7 @@ b8 adt_set_flt( ADT_Node* obj, char const* name, f64 value );
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
b8 adt_set_int( ADT_Node* obj, char const* name, s64 value );
|
||||
GEN_API b8 adt_set_int( ADT_Node* obj, char const* name, s64 value );
|
||||
|
||||
/**
|
||||
* @brief Append a new node to a container as an object
|
||||
@@ -277,7 +282,7 @@ b8 adt_set_int( ADT_Node* obj, char const* name, s64 value );
|
||||
* @param name
|
||||
* @return*
|
||||
*/
|
||||
ADT_Node* adt_append_obj( ADT_Node* parent, char const* name );
|
||||
GEN_API ADT_Node* adt_append_obj( ADT_Node* parent, char const* name );
|
||||
|
||||
/**
|
||||
* @brief Append a new node to a container as an array
|
||||
@@ -286,7 +291,7 @@ ADT_Node* adt_append_obj( ADT_Node* parent, char const* name );
|
||||
* @param name
|
||||
* @return*
|
||||
*/
|
||||
ADT_Node* adt_append_arr( ADT_Node* parent, char const* name );
|
||||
GEN_API ADT_Node* adt_append_arr( ADT_Node* parent, char const* name );
|
||||
|
||||
/**
|
||||
* @brief Append a new node to a container as a string
|
||||
@@ -296,7 +301,7 @@ ADT_Node* adt_append_arr( ADT_Node* parent, char const* name );
|
||||
* @param value
|
||||
* @return*
|
||||
*/
|
||||
ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value );
|
||||
GEN_API ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value );
|
||||
|
||||
/**
|
||||
* @brief Append a new node to a container as a float
|
||||
@@ -306,7 +311,7 @@ ADT_Node* adt_append_str( ADT_Node* parent, char const* name, char const* value
|
||||
* @param value
|
||||
* @return*
|
||||
*/
|
||||
ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value );
|
||||
GEN_API ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value );
|
||||
|
||||
/**
|
||||
* @brief Append a new node to a container as a signed integer
|
||||
@@ -316,7 +321,7 @@ ADT_Node* adt_append_flt( ADT_Node* parent, char const* name, f64 value );
|
||||
* @param value
|
||||
* @return*
|
||||
*/
|
||||
ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value );
|
||||
GEN_API ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value );
|
||||
|
||||
/* parser helpers */
|
||||
|
||||
@@ -327,7 +332,7 @@ ADT_Node* adt_append_int( ADT_Node* parent, char const* name, s64 value );
|
||||
* @param base
|
||||
* @return*
|
||||
*/
|
||||
char* adt_parse_number( ADT_Node* node, char* base );
|
||||
GEN_API char* adt_parse_number( ADT_Node* node, char* base );
|
||||
|
||||
/**
|
||||
* @brief Parses a text and stores the result into an unitialised node.
|
||||
@@ -337,7 +342,7 @@ char* adt_parse_number( ADT_Node* node, char* base );
|
||||
* @param base
|
||||
* @return*
|
||||
*/
|
||||
char* adt_parse_number_strict( ADT_Node* node, char* base_str );
|
||||
GEN_API char* adt_parse_number_strict( ADT_Node* node, char* base_str );
|
||||
|
||||
/**
|
||||
* @brief Parses and converts an existing string node into a number.
|
||||
@@ -345,7 +350,7 @@ char* adt_parse_number_strict( ADT_Node* node, char* base_str );
|
||||
* @param node
|
||||
* @return
|
||||
*/
|
||||
ADT_Error adt_str_to_number( ADT_Node* node );
|
||||
GEN_API ADT_Error adt_c_str_to_number( ADT_Node* node );
|
||||
|
||||
/**
|
||||
* @brief Parses and converts an existing string node into a number.
|
||||
@@ -354,7 +359,7 @@ ADT_Error adt_str_to_number( ADT_Node* node );
|
||||
* @param node
|
||||
* @return
|
||||
*/
|
||||
ADT_Error adt_str_to_number_strict( ADT_Node* node );
|
||||
GEN_API ADT_Error adt_c_str_to_number_strict( ADT_Node* node );
|
||||
|
||||
/**
|
||||
* @brief Prints a number into a file stream.
|
||||
@@ -366,7 +371,7 @@ ADT_Error adt_str_to_number_strict( ADT_Node* node );
|
||||
* @param node
|
||||
* @return
|
||||
*/
|
||||
ADT_Error adt_print_number( FileInfo* file, ADT_Node* node );
|
||||
GEN_API ADT_Error adt_print_number( FileInfo* file, ADT_Node* node );
|
||||
|
||||
/**
|
||||
* @brief Prints a string into a file stream.
|
||||
@@ -380,7 +385,7 @@ ADT_Error adt_print_number( FileInfo* file, ADT_Node* node );
|
||||
* @param escape_symbol
|
||||
* @return
|
||||
*/
|
||||
ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol );
|
||||
GEN_API ADT_Error adt_print_string( FileInfo* file, ADT_Node* node, char const* escaped_chars, char const* escape_symbol );
|
||||
|
||||
#pragma endregion ADT
|
||||
|
||||
@@ -396,31 +401,33 @@ enum CSV_Error : u32
|
||||
|
||||
typedef ADT_Node CSV_Object;
|
||||
|
||||
GEN_DEF_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header );
|
||||
u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim );
|
||||
void csv_free( CSV_Object* obj );
|
||||
u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header );
|
||||
GEN_API u8 csv_parse_delimiter( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header, char delim );
|
||||
void csv_free( CSV_Object* obj );
|
||||
|
||||
GEN_DEF_INLINE void csv_write( FileInfo* file, CSV_Object* obj );
|
||||
GEN_DEF_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj );
|
||||
void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim );
|
||||
String csv_write_string_delimiter( AllocatorInfo a, CSV_Object* obj, char delim );
|
||||
void csv_write( FileInfo* file, CSV_Object* obj );
|
||||
StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj );
|
||||
GEN_API void csv_write_delimiter( FileInfo* file, CSV_Object* obj, char delim );
|
||||
GEN_API StrBuilder csv_write_strbuilder_delimiter( AllocatorInfo a, CSV_Object* obj, char delim );
|
||||
|
||||
/* inline */
|
||||
|
||||
GEN_IMPL_INLINE u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header )
|
||||
inline
|
||||
u8 csv_parse( CSV_Object* root, char* text, AllocatorInfo allocator, b32 has_header )
|
||||
{
|
||||
return csv_parse_delimiter( root, text, allocator, has_header, ',' );
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE void csv_write( FileInfo* file, CSV_Object* obj )
|
||||
inline
|
||||
void csv_write( FileInfo* file, CSV_Object* obj )
|
||||
{
|
||||
csv_write_delimiter( file, obj, ',' );
|
||||
}
|
||||
|
||||
GEN_IMPL_INLINE String csv_write_string( AllocatorInfo a, CSV_Object* obj )
|
||||
inline
|
||||
StrBuilder csv_write_string( AllocatorInfo a, CSV_Object* obj )
|
||||
{
|
||||
return csv_write_string_delimiter( a, obj, ',' );
|
||||
return csv_write_strbuilder_delimiter( a, obj, ',' );
|
||||
}
|
||||
|
||||
#pragma endregion CSV
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#pragma region Platform Detection
|
||||
|
||||
/* Platform architecture */
|
||||
@@ -25,12 +29,6 @@
|
||||
# ifndef GEN_SYSTEM_MACOS
|
||||
# define GEN_SYSTEM_MACOS 1
|
||||
# endif
|
||||
# include <TargetConditionals.h>
|
||||
# if TARGET_IPHONE_SIMULATOR == 1 || TARGET_OS_IPHONE == 1
|
||||
# ifndef GEN_SYSTEM_IOS
|
||||
# define GEN_SYSTEM_IOS 1
|
||||
# endif
|
||||
# endif
|
||||
#elif defined( __unix__ )
|
||||
# ifndef GEN_SYSTEM_UNIX
|
||||
# define GEN_SYSTEM_UNIX 1
|
||||
@@ -72,13 +70,21 @@
|
||||
/* Platform compiler */
|
||||
|
||||
#if defined( _MSC_VER )
|
||||
# pragma message("Detected MSVC")
|
||||
// # define GEN_COMPILER_CLANG 0
|
||||
# define GEN_COMPILER_MSVC 1
|
||||
// # define GEN_COMPILER_GCC 0
|
||||
#elif defined( __GNUC__ )
|
||||
# pragma message("Detected GCC")
|
||||
// # define GEN_COMPILER_CLANG 0
|
||||
// # define GEN_COMPILER_MSVC 0
|
||||
# define GEN_COMPILER_GCC 1
|
||||
#elif defined( __clang__ )
|
||||
# pragma message("Detected CLANG")
|
||||
# define GEN_COMPILER_CLANG 1
|
||||
#elif defined( __MINGW32__ )
|
||||
# define GEN_COMPILER_MINGW 1
|
||||
// # define GEN_COMPILER_MSVC 0
|
||||
// # define GEN_COMPILER_GCC 0
|
||||
#else
|
||||
# error Unknown compiler
|
||||
#endif
|
||||
|
||||
@@ -97,26 +103,24 @@
|
||||
# define GEN_GCC_VERSION_CHECK(major,minor,patch) (0)
|
||||
#endif
|
||||
|
||||
#define GEN_DEF_INLINE static
|
||||
#define GEN_IMPL_INLINE static inline
|
||||
|
||||
#ifdef GEN_COMPILER_MSVC
|
||||
# define forceinline __forceinline
|
||||
# define neverinline __declspec( noinline )
|
||||
#elif defined(GEN_COMPILER_GCC)
|
||||
# define forceinline inline __attribute__((__always_inline__))
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
#elif defined(GEN_COMPILER_CLANG)
|
||||
#if __has_attribute(__always_inline__)
|
||||
# define forceinline inline __attribute__((__always_inline__))
|
||||
# define neverinline __attribute__( ( __noinline__ ) )
|
||||
#else
|
||||
# define forceinline
|
||||
# define neverinline
|
||||
#if !defined(GEN_COMPILER_C)
|
||||
# ifdef __cplusplus
|
||||
# define GEN_COMPILER_C 0
|
||||
# define GEN_COMPILER_CPP 1
|
||||
# else
|
||||
# if defined(__STDC__)
|
||||
# define GEN_COMPILER_C 1
|
||||
# define GEN_COMPILER_CPP 0
|
||||
# else
|
||||
// Fallback for very old C compilers
|
||||
# define GEN_COMPILER_C 1
|
||||
# define GEN_COMPILER_CPP 0
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#else
|
||||
# define forceinline
|
||||
# define neverinline
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
#pragma message("GENCPP: Detected C")
|
||||
#endif
|
||||
|
||||
#pragma endregion Platform Detection
|
||||
@@ -130,13 +134,25 @@
|
||||
# include <intrin.h>
|
||||
# endif
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#pragma endregion Mandatory Includes
|
||||
|
||||
#ifdef GEN_DONT_USE_NAMESPACE
|
||||
#if GEN_DONT_USE_NAMESPACE || GEN_COMPILER_C
|
||||
# if GEN_COMPILER_C
|
||||
# define GEN_NS
|
||||
# define GEN_NS_BEGIN
|
||||
# define GEN_NS_END
|
||||
# else
|
||||
# define GEN_NS ::
|
||||
# define GEN_NS_BEGIN
|
||||
# define GEN_NS_END
|
||||
# endif
|
||||
#else
|
||||
# define GEN_NS gen::
|
||||
# define GEN_NS_BEGIN namespace gen {
|
||||
# define GEN_NS_END }
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "strbuilder_ops.cpp"
|
||||
#endif
|
||||
|
||||
#pragma region Printing
|
||||
|
||||
enum
|
||||
@@ -26,6 +31,7 @@ enum
|
||||
GEN_FMT_INTS = GEN_FMT_CHAR | GEN_FMT_SHORT | GEN_FMT_INT | GEN_FMT_LONG | GEN_FMT_LLONG | GEN_FMT_SIZE | GEN_FMT_INTPTR
|
||||
};
|
||||
|
||||
typedef struct _format_info _format_info;
|
||||
struct _format_info
|
||||
{
|
||||
s32 base;
|
||||
@@ -34,22 +40,23 @@ struct _format_info
|
||||
s32 precision;
|
||||
};
|
||||
|
||||
internal sw _print_string( char* text, sw max_len, _format_info* info, char const* str )
|
||||
internal ssize _print_string( char* text, ssize max_len, _format_info* info, char const* str )
|
||||
{
|
||||
sw res = 0, len = 0;
|
||||
sw remaining = max_len;
|
||||
ssize res = 0, len = 0;
|
||||
ssize remaining = max_len;
|
||||
char* begin = text;
|
||||
|
||||
if ( str == NULL && max_len >= 6 )
|
||||
{
|
||||
res += str_copy_nulpad( text, "(null)", 6 );
|
||||
res += c_str_copy_nulpad( text, "(null)", 6 );
|
||||
return res;
|
||||
}
|
||||
|
||||
if ( info && info->precision >= 0 )
|
||||
len = str_len( str, info->precision );
|
||||
// Made the design decision for this library that precision is the length of the string.
|
||||
len = info->precision;
|
||||
else
|
||||
len = str_len( str );
|
||||
len = c_str_len( str );
|
||||
|
||||
if ( info && ( info->width == 0 && info->flags & GEN_FMT_WIDTH ) )
|
||||
{
|
||||
@@ -62,12 +69,12 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons
|
||||
len = info->precision < len ? info->precision : len;
|
||||
if ( res + len > max_len )
|
||||
return res;
|
||||
res += str_copy_nulpad( text, str, len );
|
||||
res += c_str_copy_nulpad( text, str, len );
|
||||
text += res;
|
||||
|
||||
if ( info->width > res )
|
||||
{
|
||||
sw padding = info->width - len;
|
||||
ssize padding = info->width - len;
|
||||
|
||||
char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' ';
|
||||
while ( padding-- > 0 && remaining-- > 0 )
|
||||
@@ -78,7 +85,7 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons
|
||||
{
|
||||
if ( info && ( info->width > res ) )
|
||||
{
|
||||
sw padding = info->width - len;
|
||||
ssize padding = info->width - len;
|
||||
char pad = ( info->flags & GEN_FMT_ZERO ) ? '0' : ' ';
|
||||
while ( padding-- > 0 && remaining-- > 0 )
|
||||
*text++ = pad, res++;
|
||||
@@ -86,30 +93,30 @@ internal sw _print_string( char* text, sw max_len, _format_info* info, char cons
|
||||
|
||||
if ( res + len > max_len )
|
||||
return res;
|
||||
res += str_copy_nulpad( text, str, len );
|
||||
res += c_str_copy_nulpad( text, str, len );
|
||||
}
|
||||
|
||||
if ( info )
|
||||
{
|
||||
if ( info->flags & GEN_FMT_UPPER )
|
||||
str_to_upper( begin );
|
||||
c_str_to_upper( begin );
|
||||
else if ( info->flags & GEN_FMT_LOWER )
|
||||
str_to_lower( begin );
|
||||
c_str_to_lower( begin );
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
internal sw _print_char( char* text, sw max_len, _format_info* info, char arg )
|
||||
internal ssize _print_char( char* text, ssize max_len, _format_info* info, char arg )
|
||||
{
|
||||
char str[ 2 ] = "";
|
||||
str[ 0 ] = arg;
|
||||
return _print_string( text, max_len, info, str );
|
||||
}
|
||||
|
||||
internal sw _print_repeated_char( char* text, sw max_len, _format_info* info, char arg )
|
||||
internal ssize _print_repeated_char( char* text, ssize max_len, _format_info* info, char arg )
|
||||
{
|
||||
sw res = 0;
|
||||
ssize res = 0;
|
||||
s32 rem = ( info ) ? ( info->width > 0 ) ? info->width : 1 : 1;
|
||||
res = rem;
|
||||
while ( rem-- > 0 )
|
||||
@@ -118,24 +125,24 @@ internal sw _print_repeated_char( char* text, sw max_len, _format_info* info, ch
|
||||
return res;
|
||||
}
|
||||
|
||||
internal sw _print_i64( char* text, sw max_len, _format_info* info, s64 value )
|
||||
internal ssize _print_i64( char* text, ssize max_len, _format_info* info, s64 value )
|
||||
{
|
||||
char num[ 130 ];
|
||||
i64_to_str( value, num, info ? info->base : 10 );
|
||||
return _print_string( text, max_len, info, num );
|
||||
}
|
||||
|
||||
internal sw _print_u64( char* text, sw max_len, _format_info* info, u64 value )
|
||||
internal ssize _print_u64( char* text, ssize max_len, _format_info* info, u64 value )
|
||||
{
|
||||
char num[ 130 ];
|
||||
u64_to_str( value, num, info ? info->base : 10 );
|
||||
return _print_string( text, max_len, info, num );
|
||||
}
|
||||
|
||||
internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexadecimal, f64 arg )
|
||||
internal ssize _print_f64( char* text, ssize max_len, _format_info* info, b32 is_hexadecimal, f64 arg )
|
||||
{
|
||||
// TODO: Handle exponent notation
|
||||
sw width, len, remaining = max_len;
|
||||
ssize width, len, remaining = max_len;
|
||||
char* text_begin = text;
|
||||
|
||||
if ( arg )
|
||||
@@ -155,7 +162,7 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad
|
||||
text++;
|
||||
}
|
||||
|
||||
value = zpl_cast( u64 ) arg;
|
||||
value = scast( u64, arg);
|
||||
len = _print_u64( text, remaining, NULL, value );
|
||||
text += len;
|
||||
|
||||
@@ -176,14 +183,14 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad
|
||||
text++;
|
||||
while ( info->precision-- > 0 )
|
||||
{
|
||||
value = zpl_cast( u64 )( arg * mult );
|
||||
value = scast( u64, arg * mult );
|
||||
len = _print_u64( text, remaining, NULL, value );
|
||||
text += len;
|
||||
if ( len >= remaining )
|
||||
remaining = min( remaining, 1 );
|
||||
else
|
||||
remaining -= len;
|
||||
arg -= zpl_cast( f64 ) value / mult;
|
||||
arg -= scast( f64, value / mult);
|
||||
mult *= 10;
|
||||
}
|
||||
}
|
||||
@@ -231,15 +238,15 @@ internal sw _print_f64( char* text, sw max_len, _format_info* info, b32 is_hexad
|
||||
return ( text - text_begin );
|
||||
}
|
||||
|
||||
neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va )
|
||||
neverinline ssize c_str_fmt_va( char* text, ssize max_len, char const* fmt, va_list va )
|
||||
{
|
||||
char const* text_begin = text;
|
||||
sw remaining = max_len, res;
|
||||
ssize remaining = max_len, res;
|
||||
|
||||
while ( *fmt )
|
||||
{
|
||||
_format_info info = { 0 };
|
||||
sw len = 0;
|
||||
ssize len = 0;
|
||||
info.precision = -1;
|
||||
|
||||
while ( *fmt && *fmt != '%' && remaining )
|
||||
@@ -303,7 +310,7 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va )
|
||||
}
|
||||
else
|
||||
{
|
||||
info.width = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 );
|
||||
info.width = scast( s32, c_str_to_i64( fmt, ccast( char**, & fmt), 10 ));
|
||||
if ( info.width != 0 )
|
||||
{
|
||||
info.flags |= GEN_FMT_WIDTH;
|
||||
@@ -321,7 +328,7 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va )
|
||||
}
|
||||
else
|
||||
{
|
||||
info.precision = zpl_cast( s32 ) str_to_i64( fmt, zpl_cast( char** ) & fmt, 10 );
|
||||
info.precision = scast( s32, c_str_to_i64( fmt, ccast( char**, & fmt), 10 ));
|
||||
}
|
||||
info.flags &= ~GEN_FMT_ZERO;
|
||||
}
|
||||
@@ -403,13 +410,32 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va )
|
||||
break;
|
||||
|
||||
case 'c' :
|
||||
len = _print_char( text, remaining, &info, zpl_cast( char ) va_arg( va, int ) );
|
||||
len = _print_char( text, remaining, &info, scast( char, va_arg( va, int ) ));
|
||||
break;
|
||||
|
||||
case 's' :
|
||||
len = _print_string( text, remaining, &info, va_arg( va, char* ) );
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
{
|
||||
if ( *(fmt + 1) == 'B' )
|
||||
{
|
||||
|
||||
++ fmt;
|
||||
StrBuilder gen_str = { va_arg( va, char*) };
|
||||
|
||||
info.precision = strbuilder_length(gen_str);
|
||||
len = _print_string( text, remaining, &info, gen_str );
|
||||
break;
|
||||
}
|
||||
|
||||
Str gen_str = va_arg( va, Str);
|
||||
info.precision = gen_str.Len;
|
||||
len = _print_string( text, remaining, &info, gen_str.Ptr );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r' :
|
||||
len = _print_repeated_char( text, remaining, &info, va_arg( va, int ) );
|
||||
break;
|
||||
@@ -438,25 +464,25 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va )
|
||||
switch ( info.flags & GEN_FMT_INTS )
|
||||
{
|
||||
case GEN_FMT_CHAR :
|
||||
value = zpl_cast( u64 ) zpl_cast( u8 ) va_arg( va, int );
|
||||
value = scast( u64, scast( u8, va_arg( va, int )));
|
||||
break;
|
||||
case GEN_FMT_SHORT :
|
||||
value = zpl_cast( u64 ) zpl_cast( u16 ) va_arg( va, int );
|
||||
value = scast( u64, scast( u16, va_arg( va, int )));
|
||||
break;
|
||||
case GEN_FMT_LONG :
|
||||
value = zpl_cast( u64 ) va_arg( va, unsigned long );
|
||||
case GEN_FMT_LONG:
|
||||
value = scast( u64, va_arg( va, unsigned long ));
|
||||
break;
|
||||
case GEN_FMT_LLONG :
|
||||
value = zpl_cast( u64 ) va_arg( va, unsigned long long );
|
||||
value = scast( u64, va_arg( va, unsigned long long ));
|
||||
break;
|
||||
case GEN_FMT_SIZE :
|
||||
value = zpl_cast( u64 ) va_arg( va, uw );
|
||||
value = scast( u64, va_arg( va, usize ));
|
||||
break;
|
||||
case GEN_FMT_INTPTR :
|
||||
value = zpl_cast( u64 ) va_arg( va, uptr );
|
||||
value = scast( u64, va_arg( va, uptr ));
|
||||
break;
|
||||
default :
|
||||
value = zpl_cast( u64 ) va_arg( va, unsigned int );
|
||||
value = scast( u64, va_arg( va, unsigned int ));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -468,25 +494,25 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va )
|
||||
switch ( info.flags & GEN_FMT_INTS )
|
||||
{
|
||||
case GEN_FMT_CHAR :
|
||||
value = zpl_cast( s64 ) zpl_cast( s8 ) va_arg( va, int );
|
||||
value = scast( s64, scast( s8, va_arg( va, int )));
|
||||
break;
|
||||
case GEN_FMT_SHORT :
|
||||
value = zpl_cast( s64 ) zpl_cast( s16 ) va_arg( va, int );
|
||||
value = scast( s64, scast( s16, va_arg( va, int )));
|
||||
break;
|
||||
case GEN_FMT_LONG :
|
||||
value = zpl_cast( s64 ) va_arg( va, long );
|
||||
value = scast( s64, va_arg( va, long ));
|
||||
break;
|
||||
case GEN_FMT_LLONG :
|
||||
value = zpl_cast( s64 ) va_arg( va, long long );
|
||||
value = scast( s64, va_arg( va, long long ));
|
||||
break;
|
||||
case GEN_FMT_SIZE :
|
||||
value = zpl_cast( s64 ) va_arg( va, uw );
|
||||
value = scast( s64, va_arg( va, usize ));
|
||||
break;
|
||||
case GEN_FMT_INTPTR :
|
||||
value = zpl_cast( s64 ) va_arg( va, uptr );
|
||||
value = scast( s64, va_arg( va, uptr ));
|
||||
break;
|
||||
default :
|
||||
value = zpl_cast( s64 ) va_arg( va, int );
|
||||
value = scast( s64, va_arg( va, int ));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -506,70 +532,69 @@ neverinline sw str_fmt_va( char* text, sw max_len, char const* fmt, va_list va )
|
||||
return ( res >= max_len || res < 0 ) ? -1 : res;
|
||||
}
|
||||
|
||||
char* str_fmt_buf_va( char const* fmt, va_list va )
|
||||
char* c_str_fmt_buf_va( char const* fmt, va_list va )
|
||||
{
|
||||
local_persist thread_local char buffer[ GEN_PRINTF_MAXLEN ];
|
||||
str_fmt_va( buffer, size_of( buffer ), fmt, va );
|
||||
c_str_fmt_va( buffer, size_of( buffer ), fmt, va );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* str_fmt_buf( char const* fmt, ... )
|
||||
char* c_str_fmt_buf( char const* fmt, ... )
|
||||
{
|
||||
va_list va;
|
||||
char* str;
|
||||
va_start( va, fmt );
|
||||
str = str_fmt_buf_va( fmt, va );
|
||||
str = c_str_fmt_buf_va( fmt, va );
|
||||
va_end( va );
|
||||
return str;
|
||||
}
|
||||
|
||||
sw str_fmt_file_va( struct FileInfo* f, char const* fmt, va_list va )
|
||||
ssize c_str_fmt_file_va( FileInfo* f, char const* fmt, va_list va )
|
||||
{
|
||||
local_persist thread_local char buf[ GEN_PRINTF_MAXLEN ];
|
||||
sw len = str_fmt_va( buf, size_of( buf ), fmt, va );
|
||||
ssize len = c_str_fmt_va( buf, size_of( buf ), fmt, va );
|
||||
b32 res = file_write( f, buf, len - 1 ); // NOTE: prevent extra whitespace
|
||||
return res ? len : -1;
|
||||
}
|
||||
|
||||
sw str_fmt_file( struct FileInfo* f, char const* fmt, ... )
|
||||
ssize c_str_fmt_file( FileInfo* f, char const* fmt, ... )
|
||||
{
|
||||
sw res;
|
||||
ssize res;
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
res = str_fmt_file_va( f, fmt, va );
|
||||
res = c_str_fmt_file_va( f, fmt, va );
|
||||
va_end( va );
|
||||
return res;
|
||||
}
|
||||
|
||||
sw str_fmt( char* str, sw n, char const* fmt, ... )
|
||||
ssize c_str_fmt( char* str, ssize n, char const* fmt, ... )
|
||||
{
|
||||
sw res;
|
||||
ssize res;
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
res = str_fmt_va( str, n, fmt, va );
|
||||
res = c_str_fmt_va( str, n, fmt, va );
|
||||
va_end( va );
|
||||
return res;
|
||||
}
|
||||
|
||||
sw str_fmt_out_va( char const* fmt, va_list va )
|
||||
ssize c_str_fmt_out_va( char const* fmt, va_list va )
|
||||
{
|
||||
return str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, va );
|
||||
return c_str_fmt_file_va( file_get_standard( EFileStandard_OUTPUT ), fmt, va );
|
||||
}
|
||||
|
||||
sw str_fmt_out_err_va( char const* fmt, va_list va )
|
||||
ssize c_str_fmt_out_err_va( char const* fmt, va_list va )
|
||||
{
|
||||
return str_fmt_file_va( file_get_standard( EFileStandard_ERROR ), fmt, va );
|
||||
return c_str_fmt_file_va( file_get_standard( EFileStandard_ERROR ), fmt, va );
|
||||
}
|
||||
|
||||
sw str_fmt_out_err( char const* fmt, ... )
|
||||
ssize c_str_fmt_out_err( char const* fmt, ... )
|
||||
{
|
||||
sw res;
|
||||
ssize res;
|
||||
va_list va;
|
||||
va_start( va, fmt );
|
||||
res = str_fmt_out_err_va( fmt, va );
|
||||
res = c_str_fmt_out_err_va( fmt, va );
|
||||
va_end( va );
|
||||
return res;
|
||||
}
|
||||
|
||||
#pragma endregion Printing
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "strbuilder_ops.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Printing
|
||||
|
||||
typedef struct FileInfo FileInfo;
|
||||
|
||||
#ifndef GEN_PRINTF_MAXLEN
|
||||
# define GEN_PRINTF_MAXLEN kilobytes(128)
|
||||
#endif
|
||||
typedef char PrintF_Buffer[GEN_PRINTF_MAXLEN];
|
||||
|
||||
// NOTE: A locally persisting buffer is used internally
|
||||
GEN_API char* c_str_fmt_buf ( char const* fmt, ... );
|
||||
GEN_API char* c_str_fmt_buf_va ( char const* fmt, va_list va );
|
||||
GEN_API ssize c_str_fmt ( char* str, ssize n, char const* fmt, ... );
|
||||
GEN_API ssize c_str_fmt_va ( char* str, ssize n, char const* fmt, va_list va );
|
||||
GEN_API ssize c_str_fmt_out_va ( char const* fmt, va_list va );
|
||||
GEN_API ssize c_str_fmt_out_err ( char const* fmt, ... );
|
||||
GEN_API ssize c_str_fmt_out_err_va( char const* fmt, va_list va );
|
||||
GEN_API ssize c_str_fmt_file ( FileInfo* f, char const* fmt, ... );
|
||||
GEN_API ssize c_str_fmt_file_va ( FileInfo* f, char const* fmt, va_list va );
|
||||
|
||||
constexpr
|
||||
char const* Msg_Invalid_Value = "INVALID VALUE PROVIDED";
|
||||
|
||||
inline
|
||||
ssize log_fmt(char const* fmt, ...)
|
||||
{
|
||||
ssize res;
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
res = c_str_fmt_out_va(fmt, va);
|
||||
va_end(va);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#pragma endregion Printing
|
||||
@@ -1,3 +1,8 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "header_start.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Macros and Includes
|
||||
|
||||
# include <stdio.h>
|
||||
@@ -8,9 +13,9 @@
|
||||
# define _printf_err( fmt, ... ) fprintf( stderr, fmt, __VA_ARGS__ )
|
||||
# define _printf_err_va( fmt, va ) vfprintf( stderr, fmt, va )
|
||||
# else
|
||||
# define _strlen str_len
|
||||
# define _printf_err( fmt, ... ) str_fmt_out_err( fmt, __VA_ARGS__ )
|
||||
# define _printf_err_va( fmt, va ) str_fmt_out_err_va( fmt, va )
|
||||
# define _strlen c_str_len
|
||||
# define _printf_err( fmt, ... ) c_str_fmt_out_err( fmt, __VA_ARGS__ )
|
||||
# define _printf_err_va( fmt, va ) c_str_fmt_out_err_va( fmt, va )
|
||||
# endif
|
||||
# endif
|
||||
#
|
||||
@@ -78,4 +83,3 @@
|
||||
#endif
|
||||
|
||||
#pragma endregion Macros and Includes
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "debug.cpp"
|
||||
#endif
|
||||
|
||||
#pragma region String Ops
|
||||
|
||||
internal
|
||||
sw _scan_zpl_i64( const char* text, s32 base, s64* value )
|
||||
ssize _scan_zpl_i64( const char* text, s32 base, s64* value )
|
||||
{
|
||||
const char* text_begin = text;
|
||||
s64 result = 0;
|
||||
@@ -13,7 +18,7 @@ sw _scan_zpl_i64( const char* text, s32 base, s64* value )
|
||||
text++;
|
||||
}
|
||||
|
||||
if ( base == 16 && str_compare( text, "0x", 2 ) == 0 )
|
||||
if ( base == 16 && c_str_compare_len( text, "0x", 2 ) == 0 )
|
||||
text += 2;
|
||||
|
||||
for ( ;; )
|
||||
@@ -48,14 +53,14 @@ global const char _num_to_char_table[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"@$";
|
||||
|
||||
s64 str_to_i64( const char* str, char** end_ptr, s32 base )
|
||||
s64 c_str_to_i64( const char* str, char** end_ptr, s32 base )
|
||||
{
|
||||
sw len;
|
||||
ssize len;
|
||||
s64 value;
|
||||
|
||||
if ( ! base )
|
||||
{
|
||||
if ( ( str_len( str ) > 2 ) && ( str_compare( str, "0x", 2 ) == 0 ) )
|
||||
if ( ( c_str_len( str ) > 2 ) && ( c_str_compare_len( str, "0x", 2 ) == 0 ) )
|
||||
base = 16;
|
||||
else
|
||||
base = 10;
|
||||
@@ -79,7 +84,7 @@ void i64_to_str( s64 value, char* string, s32 base )
|
||||
value = -value;
|
||||
}
|
||||
|
||||
v = zpl_cast( u64 ) value;
|
||||
v = scast( u64, value);
|
||||
if ( v != 0 )
|
||||
{
|
||||
while ( v > 0 )
|
||||
@@ -95,7 +100,7 @@ void i64_to_str( s64 value, char* string, s32 base )
|
||||
if ( negative )
|
||||
*buf++ = '-';
|
||||
*buf = '\0';
|
||||
str_reverse( string );
|
||||
c_str_reverse( string );
|
||||
}
|
||||
|
||||
void u64_to_str( u64 value, char* string, s32 base )
|
||||
@@ -116,10 +121,10 @@ void u64_to_str( u64 value, char* string, s32 base )
|
||||
}
|
||||
*buf = '\0';
|
||||
|
||||
str_reverse( string );
|
||||
c_str_reverse( string );
|
||||
}
|
||||
|
||||
f64 str_to_f64( const char* str, char** end_ptr )
|
||||
f64 c_str_to_f64( const char* str, char** end_ptr )
|
||||
{
|
||||
f64 result, value, sign, scale;
|
||||
s32 frac;
|
||||
@@ -201,10 +206,9 @@ f64 str_to_f64( const char* str, char** end_ptr )
|
||||
result = sign * ( frac ? ( value / scale ) : ( value * scale ) );
|
||||
|
||||
if ( end_ptr )
|
||||
*end_ptr = zpl_cast( char* ) str;
|
||||
* end_ptr = rcast( char*, ccast(char*, str) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma endregion String Ops
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "memory.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region String Ops
|
||||
|
||||
const char* char_first_occurence( const char* str, char c );
|
||||
|
||||
b32 char_is_alpha( char c );
|
||||
b32 char_is_alphanumeric( char c );
|
||||
b32 char_is_digit( char c );
|
||||
b32 char_is_hex_digit( char c );
|
||||
b32 char_is_space( char c );
|
||||
char char_to_lower( char c );
|
||||
char char_to_upper( char c );
|
||||
|
||||
s32 digit_to_int( char c );
|
||||
s32 hex_digit_to_int( char c );
|
||||
|
||||
s32 c_str_compare( const char* s1, const char* s2 );
|
||||
s32 c_str_compare_len( const char* s1, const char* s2, ssize len );
|
||||
char* c_str_copy( char* dest, const char* source, ssize len );
|
||||
ssize c_str_copy_nulpad( char* dest, const char* source, ssize len );
|
||||
ssize c_str_len( const char* str );
|
||||
ssize c_str_len_capped( const char* str, ssize max_len );
|
||||
char* c_str_reverse( char* str ); // NOTE: ASCII only
|
||||
char const* c_str_skip( char const* str, char c );
|
||||
char const* c_str_skip_any( char const* str, char const* char_list );
|
||||
char const* c_str_trim( char const* str, b32 catch_newline );
|
||||
|
||||
// NOTE: ASCII only
|
||||
void c_str_to_lower( char* str );
|
||||
void c_str_to_upper( char* str );
|
||||
|
||||
GEN_API s64 c_str_to_i64( const char* str, char** end_ptr, s32 base );
|
||||
GEN_API void i64_to_str( s64 value, char* string, s32 base );
|
||||
GEN_API void u64_to_str( u64 value, char* string, s32 base );
|
||||
GEN_API f64 c_str_to_f64( const char* str, char** end_ptr );
|
||||
|
||||
inline
|
||||
const char* char_first_occurence( const char* s, char c )
|
||||
{
|
||||
char ch = c;
|
||||
for ( ; *s != ch; s++ )
|
||||
{
|
||||
if ( *s == '\0' )
|
||||
return NULL;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
inline
|
||||
b32 char_is_alpha( char c )
|
||||
{
|
||||
if ( ( c >= 'A' && c <= 'Z' ) || ( c >= 'a' && c <= 'z' ) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
b32 char_is_alphanumeric( char c )
|
||||
{
|
||||
return char_is_alpha( c ) || char_is_digit( c );
|
||||
}
|
||||
|
||||
inline
|
||||
b32 char_is_digit( char c )
|
||||
{
|
||||
if ( c >= '0' && c <= '9' )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
b32 char_is_hex_digit( char c )
|
||||
{
|
||||
if ( char_is_digit( c ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
b32 char_is_space( char c )
|
||||
{
|
||||
if ( c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
char char_to_lower( char c )
|
||||
{
|
||||
if ( c >= 'A' && c <= 'Z' )
|
||||
return 'a' + ( c - 'A' );
|
||||
return c;
|
||||
}
|
||||
|
||||
inline char char_to_upper( char c )
|
||||
{
|
||||
if ( c >= 'a' && c <= 'z' )
|
||||
return 'A' + ( c - 'a' );
|
||||
return c;
|
||||
}
|
||||
|
||||
inline
|
||||
s32 digit_to_int( char c )
|
||||
{
|
||||
return char_is_digit( c ) ? c - '0' : c - 'W';
|
||||
}
|
||||
|
||||
inline
|
||||
s32 hex_digit_to_int( char c )
|
||||
{
|
||||
if ( char_is_digit( c ) )
|
||||
return digit_to_int( c );
|
||||
else if ( is_between( c, 'a', 'f' ) )
|
||||
return c - 'a' + 10;
|
||||
else if ( is_between( c, 'A', 'F' ) )
|
||||
return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline
|
||||
s32 c_str_compare( const char* s1, const char* s2 )
|
||||
{
|
||||
while ( *s1 && ( *s1 == *s2 ) )
|
||||
{
|
||||
s1++, s2++;
|
||||
}
|
||||
return *( u8* )s1 - *( u8* )s2;
|
||||
}
|
||||
|
||||
inline
|
||||
s32 c_str_compare_len( const char* s1, const char* s2, ssize len )
|
||||
{
|
||||
for ( ; len > 0; s1++, s2++, len-- )
|
||||
{
|
||||
if ( *s1 != *s2 )
|
||||
return ( ( s1 < s2 ) ? -1 : +1 );
|
||||
else if ( *s1 == '\0' )
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline
|
||||
char* c_str_copy( char* dest, const char* source, ssize len )
|
||||
{
|
||||
GEN_ASSERT_NOT_NULL( dest );
|
||||
if ( source )
|
||||
{
|
||||
char* str = dest;
|
||||
while ( len > 0 && *source )
|
||||
{
|
||||
*str++ = *source++;
|
||||
len--;
|
||||
}
|
||||
while ( len > 0 )
|
||||
{
|
||||
*str++ = '\0';
|
||||
len--;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
inline
|
||||
ssize c_str_copy_nulpad( char* dest, const char* source, ssize len )
|
||||
{
|
||||
ssize result = 0;
|
||||
GEN_ASSERT_NOT_NULL( dest );
|
||||
if ( source )
|
||||
{
|
||||
const char* source_start = source;
|
||||
char* str = dest;
|
||||
while ( len > 0 && *source )
|
||||
{
|
||||
*str++ = *source++;
|
||||
len--;
|
||||
}
|
||||
while ( len > 0 )
|
||||
{
|
||||
*str++ = '\0';
|
||||
len--;
|
||||
}
|
||||
|
||||
result = source - source_start;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
ssize c_str_len( const char* str )
|
||||
{
|
||||
if ( str == NULL )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const char* p = str;
|
||||
while ( *str )
|
||||
str++;
|
||||
return str - p;
|
||||
}
|
||||
|
||||
inline
|
||||
ssize c_str_len_capped( const char* str, ssize max_len )
|
||||
{
|
||||
const char* end = rcast(const char*, mem_find( str, 0, max_len ));
|
||||
if ( end )
|
||||
return end - str;
|
||||
return max_len;
|
||||
}
|
||||
|
||||
inline
|
||||
char* c_str_reverse( char* str )
|
||||
{
|
||||
ssize len = c_str_len( str );
|
||||
char* a = str + 0;
|
||||
char* b = str + len - 1;
|
||||
len /= 2;
|
||||
while ( len-- )
|
||||
{
|
||||
swap( *a, *b );
|
||||
a++, b--;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
inline
|
||||
char const* c_str_skip( char const* str, char c )
|
||||
{
|
||||
while ( *str && *str != c )
|
||||
{
|
||||
++str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
inline
|
||||
char const* c_str_skip_any( char const* str, char const* char_list )
|
||||
{
|
||||
char const* closest_ptr = rcast( char const*, pointer_add_const( rcast(mem_ptr_const, str), c_str_len( str ) ));
|
||||
ssize char_list_count = c_str_len( char_list );
|
||||
for ( ssize i = 0; i < char_list_count; i++ )
|
||||
{
|
||||
char const* p = c_str_skip( str, char_list[ i ] );
|
||||
closest_ptr = min( closest_ptr, p );
|
||||
}
|
||||
return closest_ptr;
|
||||
}
|
||||
|
||||
inline
|
||||
char const* c_str_trim( char const* str, b32 catch_newline )
|
||||
{
|
||||
while ( *str && char_is_space( *str ) && ( ! catch_newline || ( catch_newline && *str != '\n' ) ) )
|
||||
{
|
||||
++str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
inline
|
||||
void c_str_to_lower( char* str )
|
||||
{
|
||||
if ( ! str )
|
||||
return;
|
||||
while ( *str )
|
||||
{
|
||||
*str = char_to_lower( *str );
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void c_str_to_upper( char* str )
|
||||
{
|
||||
if ( ! str )
|
||||
return;
|
||||
while ( *str )
|
||||
{
|
||||
*str = char_to_upper( *str );
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion String Ops
|
||||
@@ -0,0 +1,61 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "hashing.cpp"
|
||||
#endif
|
||||
|
||||
#pragma region StrBuilder
|
||||
|
||||
StrBuilder strbuilder_make_length( AllocatorInfo allocator, char const* str, ssize length )
|
||||
{
|
||||
ssize const header_size = sizeof( StrBuilderHeader );
|
||||
|
||||
s32 alloc_size = header_size + length + 1;
|
||||
void* allocation = alloc( allocator, alloc_size );
|
||||
|
||||
if ( allocation == nullptr ) {
|
||||
StrBuilder null_string = {nullptr};
|
||||
return null_string;
|
||||
}
|
||||
|
||||
StrBuilderHeader*
|
||||
header = rcast(StrBuilderHeader*, allocation);
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = length;
|
||||
header->Length = length;
|
||||
|
||||
StrBuilder result = { rcast( char*, allocation) + header_size };
|
||||
|
||||
if ( length && str )
|
||||
mem_copy( result, str, length );
|
||||
else
|
||||
mem_set( result, 0, alloc_size - header_size );
|
||||
|
||||
result[ length ] = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
StrBuilder strbuilder_make_reserve( AllocatorInfo allocator, ssize capacity )
|
||||
{
|
||||
ssize const header_size = sizeof( StrBuilderHeader );
|
||||
|
||||
s32 alloc_size = header_size + capacity + 1;
|
||||
void* allocation = alloc( allocator, alloc_size );
|
||||
|
||||
if ( allocation == nullptr ) {
|
||||
StrBuilder null_string = {nullptr};
|
||||
return null_string;
|
||||
}
|
||||
mem_set( allocation, 0, alloc_size );
|
||||
|
||||
StrBuilderHeader*
|
||||
header = rcast(StrBuilderHeader*, allocation);
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = capacity;
|
||||
header->Length = 0;
|
||||
|
||||
StrBuilder result = { rcast(char*, allocation) + header_size };
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma endregion StrBuilder
|
||||
@@ -0,0 +1,746 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "hashing.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Strings
|
||||
|
||||
struct Str;
|
||||
|
||||
Str to_str_from_c_str (char const* bad_string);
|
||||
bool str_are_equal (Str lhs, Str rhs);
|
||||
char const* str_back (Str str);
|
||||
bool str_contains (Str str, Str substring);
|
||||
Str str_duplicate (Str str, AllocatorInfo allocator);
|
||||
b32 str_starts_with (Str str, Str substring);
|
||||
Str str_visualize_whitespace(Str str, AllocatorInfo allocator);
|
||||
|
||||
// Constant string with length.
|
||||
struct Str
|
||||
{
|
||||
char const* Ptr;
|
||||
ssize Len;
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline operator char const* () const { return Ptr; }
|
||||
forceinline char const& operator[]( ssize index ) const { return Ptr[index]; }
|
||||
|
||||
#if ! GEN_C_LIKE_CPP
|
||||
forceinline bool is_equal (Str rhs) const { return str_are_equal(* this, rhs); }
|
||||
forceinline char const* back () const { return str_back(* this); }
|
||||
forceinline bool contains (Str substring) const { return str_contains(* this, substring); }
|
||||
forceinline Str duplicate (AllocatorInfo allocator) const { return str_duplicate(* this, allocator); }
|
||||
forceinline b32 starts_with (Str substring) const { return str_starts_with(* this, substring); }
|
||||
forceinline Str visualize_whitespace(AllocatorInfo allocator) const { return str_visualize_whitespace(* this, allocator); }
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#define cast_to_str( str ) * rcast( Str*, (str) - sizeof(ssize) )
|
||||
|
||||
#ifndef txt
|
||||
# if GEN_COMPILER_CPP
|
||||
# define txt( text ) GEN_NS Str { ( text ), sizeof( text ) - 1 }
|
||||
# else
|
||||
# define txt( text ) (GEN_NS Str){ ( text ), sizeof( text ) - 1 }
|
||||
# endif
|
||||
#endif
|
||||
|
||||
GEN_API_C_BEGIN
|
||||
forceinline char const* str_begin(Str str) { return str.Ptr; }
|
||||
forceinline char const* str_end (Str str) { return str.Ptr + str.Len; }
|
||||
forceinline char const* str_next (Str str, char const* iter) { return iter + 1; }
|
||||
GEN_API_C_END
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
forceinline char const* begin(Str str) { return str.Ptr; }
|
||||
forceinline char const* end (Str str) { return str.Ptr + str.Len; }
|
||||
forceinline char const* next (Str str, char const* iter) { return iter + 1; }
|
||||
#endif
|
||||
|
||||
inline
|
||||
bool str_are_equal(Str lhs, Str rhs)
|
||||
{
|
||||
if (lhs.Len != rhs.Len)
|
||||
return false;
|
||||
|
||||
for (ssize idx = 0; idx < lhs.Len; ++idx)
|
||||
if (lhs.Ptr[idx] != rhs.Ptr[idx])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
char const* str_back(Str str) {
|
||||
return & str.Ptr[str.Len - 1];
|
||||
}
|
||||
|
||||
inline
|
||||
bool str_contains(Str str, Str substring)
|
||||
{
|
||||
if (substring.Len > str.Len)
|
||||
return false;
|
||||
|
||||
ssize main_len = str.Len;
|
||||
ssize sub_len = substring.Len;
|
||||
for (ssize idx = 0; idx <= main_len - sub_len; ++idx)
|
||||
{
|
||||
if (c_str_compare_len(str.Ptr + idx, substring.Ptr, sub_len) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
b32 str_starts_with(Str str, Str substring) {
|
||||
if (substring.Len > str.Len)
|
||||
return false;
|
||||
|
||||
b32 result = c_str_compare_len(str.Ptr, substring.Ptr, substring.Len) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
Str to_str_from_c_str( char const* bad_str ) {
|
||||
Str result = { bad_str, c_str_len( bad_str ) };
|
||||
return result;
|
||||
}
|
||||
|
||||
// Dynamic StrBuilder
|
||||
// This is directly based off the ZPL string api.
|
||||
// They used a header pattern
|
||||
// I kept it for simplicty of porting but its not necessary to keep it that way.
|
||||
#pragma region StrBuilder
|
||||
struct StrBuilderHeader;
|
||||
|
||||
#if GEN_COMPILER_C
|
||||
typedef char* StrBuilder;
|
||||
#else
|
||||
struct StrBuilder;
|
||||
#endif
|
||||
|
||||
forceinline usize strbuilder_grow_formula(usize value);
|
||||
|
||||
GEN_API StrBuilder strbuilder_make_reserve (AllocatorInfo allocator, ssize capacity);
|
||||
GEN_API StrBuilder strbuilder_make_length (AllocatorInfo allocator, char const* str, ssize length);
|
||||
|
||||
StrBuilder strbuilder_make_c_str (AllocatorInfo allocator, char const* str);
|
||||
StrBuilder strbuilder_make_str (AllocatorInfo allocator, Str str);
|
||||
StrBuilder strbuilder_fmt (AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...);
|
||||
StrBuilder strbuilder_fmt_buf (AllocatorInfo allocator, char const* fmt, ...);
|
||||
StrBuilder strbuilder_join (AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue);
|
||||
bool strbuilder_are_equal (StrBuilder const lhs, StrBuilder const rhs);
|
||||
bool strbuilder_are_equal_str (StrBuilder const lhs, Str rhs);
|
||||
bool strbuilder_make_space_for (StrBuilder* str, char const* to_append, ssize add_len);
|
||||
bool strbuilder_append_char (StrBuilder* str, char c);
|
||||
bool strbuilder_append_c_str (StrBuilder* str, char const* c_str_to_append);
|
||||
bool strbuilder_append_c_str_len (StrBuilder* str, char const* c_str_to_append, ssize length);
|
||||
bool strbuilder_append_str (StrBuilder* str, Str c_str_to_append);
|
||||
bool strbuilder_append_string (StrBuilder* str, StrBuilder const other);
|
||||
bool strbuilder_append_fmt (StrBuilder* str, char const* fmt, ...);
|
||||
ssize strbuilder_avail_space (StrBuilder const str);
|
||||
char* strbuilder_back (StrBuilder str);
|
||||
bool strbuilder_contains_str (StrBuilder const str, Str substring);
|
||||
bool strbuilder_contains_string (StrBuilder const str, StrBuilder const substring);
|
||||
ssize strbuilder_capacity (StrBuilder const str);
|
||||
void strbuilder_clear (StrBuilder str);
|
||||
StrBuilder strbuilder_duplicate (StrBuilder const str, AllocatorInfo allocator);
|
||||
void strbuilder_free (StrBuilder* str);
|
||||
StrBuilderHeader* strbuilder_get_header (StrBuilder str);
|
||||
ssize strbuilder_length (StrBuilder const str);
|
||||
b32 strbuilder_starts_with_str (StrBuilder const str, Str substring);
|
||||
b32 strbuilder_starts_with_string (StrBuilder const str, StrBuilder substring);
|
||||
void strbuilder_skip_line (StrBuilder str);
|
||||
void strbuilder_strip_space (StrBuilder str);
|
||||
Str strbuilder_to_str (StrBuilder str);
|
||||
void strbuilder_trim (StrBuilder str, char const* cut_set);
|
||||
void strbuilder_trim_space (StrBuilder str);
|
||||
StrBuilder strbuilder_visualize_whitespace(StrBuilder const str);
|
||||
|
||||
struct StrBuilderHeader {
|
||||
AllocatorInfo Allocator;
|
||||
ssize Capacity;
|
||||
ssize Length;
|
||||
};
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
struct StrBuilder
|
||||
{
|
||||
char* Data;
|
||||
|
||||
forceinline operator char*() { return Data; }
|
||||
forceinline operator char const*() const { return Data; }
|
||||
forceinline operator Str() const { return { Data, strbuilder_length(* this) }; }
|
||||
|
||||
StrBuilder const& operator=(StrBuilder const& other) const {
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
StrBuilder* this_ = ccast(StrBuilder*, this);
|
||||
this_->Data = other.Data;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
forceinline char& operator[](ssize index) { return Data[index]; }
|
||||
forceinline char const& operator[](ssize index) const { return Data[index]; }
|
||||
|
||||
forceinline bool operator==(std::nullptr_t) const { return Data == nullptr; }
|
||||
forceinline bool operator!=(std::nullptr_t) const { return Data != nullptr; }
|
||||
friend forceinline bool operator==(std::nullptr_t, const StrBuilder str) { return str.Data == nullptr; }
|
||||
friend forceinline bool operator!=(std::nullptr_t, const StrBuilder str) { return str.Data != nullptr; }
|
||||
|
||||
#if ! GEN_C_LIKE_CPP
|
||||
forceinline char* begin() const { return Data; }
|
||||
forceinline char* end() const { return Data + strbuilder_length(* this); }
|
||||
|
||||
#pragma region Member Mapping
|
||||
forceinline static StrBuilder make(AllocatorInfo allocator, char const* str) { return strbuilder_make_c_str(allocator, str); }
|
||||
forceinline static StrBuilder make(AllocatorInfo allocator, Str str) { return strbuilder_make_str(allocator, str); }
|
||||
forceinline static StrBuilder make_reserve(AllocatorInfo allocator, ssize cap) { return strbuilder_make_reserve(allocator, cap); }
|
||||
forceinline static StrBuilder make_length(AllocatorInfo a, char const* s, ssize l) { return strbuilder_make_length(a, s, l); }
|
||||
forceinline static StrBuilder join(AllocatorInfo a, char const** p, ssize n, char const* g) { return strbuilder_join(a, p, n, g); }
|
||||
forceinline static usize grow_formula(usize value) { return strbuilder_grow_formula(value); }
|
||||
|
||||
static
|
||||
StrBuilder fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = c_str_fmt_va(buf, buf_size, fmt, va) - 1;
|
||||
va_end(va);
|
||||
return strbuilder_make_length(allocator, buf, res);
|
||||
}
|
||||
|
||||
static
|
||||
StrBuilder fmt_buf(AllocatorInfo allocator, char const* fmt, ...) {
|
||||
local_persist thread_local
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) - 1;
|
||||
va_end(va);
|
||||
return strbuilder_make_length(allocator, buf, res);
|
||||
}
|
||||
|
||||
forceinline bool make_space_for(char const* str, ssize add_len) { return strbuilder_make_space_for(this, str, add_len); }
|
||||
forceinline bool append(char c) { return strbuilder_append_char(this, c); }
|
||||
forceinline bool append(char const* str) { return strbuilder_append_c_str(this, str); }
|
||||
forceinline bool append(char const* str, ssize length) { return strbuilder_append_c_str_len(this, str, length); }
|
||||
forceinline bool append(Str str) { return strbuilder_append_str(this, str); }
|
||||
forceinline bool append(const StrBuilder other) { return strbuilder_append_string(this, other); }
|
||||
forceinline ssize avail_space() const { return strbuilder_avail_space(* this); }
|
||||
forceinline char* back() { return strbuilder_back(* this); }
|
||||
forceinline bool contains(Str substring) const { return strbuilder_contains_str(* this, substring); }
|
||||
forceinline bool contains(StrBuilder const& substring) const { return strbuilder_contains_string(* this, substring); }
|
||||
forceinline ssize capacity() const { return strbuilder_capacity(* this); }
|
||||
forceinline void clear() { strbuilder_clear(* this); }
|
||||
forceinline StrBuilder duplicate(AllocatorInfo allocator) const { return strbuilder_duplicate(* this, allocator); }
|
||||
forceinline void free() { strbuilder_free(this); }
|
||||
forceinline bool is_equal(StrBuilder const& other) const { return strbuilder_are_equal(* this, other); }
|
||||
forceinline bool is_equal(Str other) const { return strbuilder_are_equal_str(* this, other); }
|
||||
forceinline ssize length() const { return strbuilder_length(* this); }
|
||||
forceinline b32 starts_with(Str substring) const { return strbuilder_starts_with_str(* this, substring); }
|
||||
forceinline b32 starts_with(StrBuilder substring) const { return strbuilder_starts_with_string(* this, substring); }
|
||||
forceinline void skip_line() { strbuilder_skip_line(* this); }
|
||||
forceinline void strip_space() { strbuilder_strip_space(* this); }
|
||||
forceinline Str to_str() { return { Data, strbuilder_length(*this) }; }
|
||||
forceinline void trim(char const* cut_set) { strbuilder_trim(* this, cut_set); }
|
||||
forceinline void trim_space() { strbuilder_trim_space(* this); }
|
||||
forceinline StrBuilder visualize_whitespace() const { return strbuilder_visualize_whitespace(* this); }
|
||||
forceinline StrBuilderHeader& get_header() { return * strbuilder_get_header(* this); }
|
||||
|
||||
bool append_fmt(char const* fmt, ...) {
|
||||
ssize res;
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
res = c_str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1;
|
||||
va_end(va);
|
||||
|
||||
return strbuilder_append_c_str_len(this, buf, res);
|
||||
}
|
||||
#pragma endregion Member Mapping
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
forceinline char* strbuilder_begin(StrBuilder str) { return ((char*) str); }
|
||||
forceinline char* strbuilder_end (StrBuilder str) { return ((char*) str + strbuilder_length(str)); }
|
||||
forceinline char* strbuilder_next (StrBuilder str, char const* iter) { return ((char*) iter + 1); }
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline char* begin(StrBuilder str) { return ((char*) str); }
|
||||
forceinline char* end (StrBuilder str) { return ((char*) str + strbuilder_length(str)); }
|
||||
forceinline char* next (StrBuilder str, char* iter) { return ((char*) iter + 1); }
|
||||
#endif
|
||||
|
||||
#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP
|
||||
forceinline bool make_space_for(StrBuilder& str, char const* to_append, ssize add_len);
|
||||
forceinline bool append(StrBuilder& str, char c);
|
||||
forceinline bool append(StrBuilder& str, char const* c_str_to_append);
|
||||
forceinline bool append(StrBuilder& str, char const* c_str_to_append, ssize length);
|
||||
forceinline bool append(StrBuilder& str, Str c_str_to_append);
|
||||
forceinline bool append(StrBuilder& str, const StrBuilder other);
|
||||
forceinline bool append_fmt(StrBuilder& str, char const* fmt, ...);
|
||||
forceinline char& back(StrBuilder& str);
|
||||
forceinline void clear(StrBuilder& str);
|
||||
forceinline void free(StrBuilder& str);
|
||||
#endif
|
||||
|
||||
forceinline
|
||||
usize strbuilder_grow_formula(usize value) {
|
||||
// Using a very aggressive growth formula to reduce time mem_copying with recursive calls to append in this library.
|
||||
return 4 * value + 8;
|
||||
}
|
||||
|
||||
forceinline
|
||||
StrBuilder strbuilder_make_c_str(AllocatorInfo allocator, char const* str) {
|
||||
ssize length = str ? c_str_len(str) : 0;
|
||||
return strbuilder_make_length(allocator, str, length);
|
||||
}
|
||||
|
||||
forceinline
|
||||
StrBuilder strbuilder_make_str(AllocatorInfo allocator, Str str) {
|
||||
return strbuilder_make_length(allocator, str.Ptr, str.Len);
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder strbuilder_fmt(AllocatorInfo allocator, char* buf, ssize buf_size, char const* fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = c_str_fmt_va(buf, buf_size, fmt, va) - 1;
|
||||
va_end(va);
|
||||
|
||||
return strbuilder_make_length(allocator, buf, res);
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder strbuilder_fmt_buf(AllocatorInfo allocator, char const* fmt, ...)
|
||||
{
|
||||
local_persist thread_local
|
||||
PrintF_Buffer buf = struct_init(PrintF_Buffer, {0});
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
ssize res = c_str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va) -1;
|
||||
va_end(va);
|
||||
|
||||
return strbuilder_make_length(allocator, buf, res);
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder strbuilder_join(AllocatorInfo allocator, char const** parts, ssize num_parts, char const* glue)
|
||||
{
|
||||
StrBuilder result = strbuilder_make_c_str(allocator, "");
|
||||
|
||||
for (ssize idx = 0; idx < num_parts; ++idx)
|
||||
{
|
||||
strbuilder_append_c_str(& result, parts[idx]);
|
||||
|
||||
if (idx < num_parts - 1)
|
||||
strbuilder_append_c_str(& result, glue);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool strbuilder_append_char(StrBuilder* str, char c) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
return strbuilder_append_c_str_len( str, (char const*)& c, (ssize)1);
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool strbuilder_append_c_str(StrBuilder* str, char const* c_str_to_append) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
return strbuilder_append_c_str_len(str, c_str_to_append, c_str_len(c_str_to_append));
|
||||
}
|
||||
|
||||
inline
|
||||
bool strbuilder_append_c_str_len(StrBuilder* str, char const* c_str_to_append, ssize append_length)
|
||||
{
|
||||
GEN_ASSERT(str != nullptr);
|
||||
if ( rcast(sptr, c_str_to_append) > 0)
|
||||
{
|
||||
ssize curr_len = strbuilder_length(* str);
|
||||
|
||||
if ( ! strbuilder_make_space_for(str, c_str_to_append, append_length))
|
||||
return false;
|
||||
|
||||
StrBuilderHeader* header = strbuilder_get_header(* str);
|
||||
|
||||
char* Data = * str;
|
||||
mem_copy( Data + curr_len, c_str_to_append, append_length);
|
||||
|
||||
Data[curr_len + append_length] = '\0';
|
||||
|
||||
header->Length = curr_len + append_length;
|
||||
}
|
||||
return c_str_to_append != nullptr;
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool strbuilder_append_str(StrBuilder* str, Str c_str_to_append) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
return strbuilder_append_c_str_len(str, c_str_to_append.Ptr, c_str_to_append.Len);
|
||||
}
|
||||
|
||||
forceinline
|
||||
bool strbuilder_append_string(StrBuilder* str, StrBuilder const other) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
return strbuilder_append_c_str_len(str, (char const*)other, strbuilder_length(other));
|
||||
}
|
||||
|
||||
inline
|
||||
bool strbuilder_append_fmt(StrBuilder* str, char const* fmt, ...) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
ssize res;
|
||||
char buf[GEN_PRINTF_MAXLEN] = { 0 };
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
res = c_str_fmt_va(buf, count_of(buf) - 1, fmt, va) - 1;
|
||||
va_end(va);
|
||||
|
||||
return strbuilder_append_c_str_len(str, (char const*)buf, res);
|
||||
}
|
||||
|
||||
inline
|
||||
bool strbuilder_are_equal_string(StrBuilder const lhs, StrBuilder const rhs)
|
||||
{
|
||||
if (strbuilder_length(lhs) != strbuilder_length(rhs))
|
||||
return false;
|
||||
|
||||
for (ssize idx = 0; idx < strbuilder_length(lhs); ++idx)
|
||||
if (lhs[idx] != rhs[idx])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool strbuilder_are_equal_str(StrBuilder const lhs, Str rhs)
|
||||
{
|
||||
if (strbuilder_length(lhs) != (rhs.Len))
|
||||
return false;
|
||||
|
||||
for (ssize idx = 0; idx < strbuilder_length(lhs); ++idx)
|
||||
if (lhs[idx] != rhs.Ptr[idx])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
forceinline
|
||||
ssize strbuilder_avail_space(StrBuilder const str) {
|
||||
StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader));
|
||||
return header->Capacity - header->Length;
|
||||
}
|
||||
|
||||
forceinline
|
||||
char* strbuilder_back(StrBuilder str) {
|
||||
return & (str)[strbuilder_length(str) - 1];
|
||||
}
|
||||
|
||||
inline
|
||||
bool strbuilder_contains_StrC(StrBuilder const str, Str substring)
|
||||
{
|
||||
StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader));
|
||||
|
||||
if (substring.Len > header->Length)
|
||||
return false;
|
||||
|
||||
ssize main_len = header->Length;
|
||||
ssize sub_len = substring.Len;
|
||||
|
||||
for (ssize idx = 0; idx <= main_len - sub_len; ++idx)
|
||||
{
|
||||
if (c_str_compare_len(str + idx, substring.Ptr, sub_len) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline
|
||||
bool strbuilder_contains_string(StrBuilder const str, StrBuilder const substring)
|
||||
{
|
||||
StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader));
|
||||
|
||||
if (strbuilder_length(substring) > header->Length)
|
||||
return false;
|
||||
|
||||
ssize main_len = header->Length;
|
||||
ssize sub_len = strbuilder_length(substring);
|
||||
|
||||
for (ssize idx = 0; idx <= main_len - sub_len; ++idx)
|
||||
{
|
||||
if (c_str_compare_len(str + idx, substring, sub_len) == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
forceinline
|
||||
ssize strbuilder_capacity(StrBuilder const str) {
|
||||
StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader));
|
||||
return header->Capacity;
|
||||
}
|
||||
|
||||
forceinline
|
||||
void strbuilder_clear(StrBuilder str) {
|
||||
strbuilder_get_header(str)->Length = 0;
|
||||
}
|
||||
|
||||
forceinline
|
||||
StrBuilder strbuilder_duplicate(StrBuilder const str, AllocatorInfo allocator) {
|
||||
return strbuilder_make_length(allocator, str, strbuilder_length(str));
|
||||
}
|
||||
|
||||
forceinline
|
||||
void strbuilder_free(StrBuilder* str) {
|
||||
GEN_ASSERT(str != nullptr);
|
||||
if (! (* str))
|
||||
return;
|
||||
|
||||
StrBuilderHeader* header = strbuilder_get_header(* str);
|
||||
allocator_free(header->Allocator, header);
|
||||
}
|
||||
|
||||
forceinline
|
||||
StrBuilderHeader* strbuilder_get_header(StrBuilder str) {
|
||||
return (StrBuilderHeader*)(scast(char*, str) - sizeof(StrBuilderHeader));
|
||||
}
|
||||
|
||||
forceinline
|
||||
ssize strbuilder_length(StrBuilder const str)
|
||||
{
|
||||
StrBuilderHeader const* header = rcast(StrBuilderHeader const*, scast(char const*, str) - sizeof(StrBuilderHeader));
|
||||
return header->Length;
|
||||
}
|
||||
|
||||
inline
|
||||
bool strbuilder_make_space_for(StrBuilder* str, char const* to_append, ssize add_len)
|
||||
{
|
||||
ssize available = strbuilder_avail_space(* str);
|
||||
|
||||
if (available >= add_len) {
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssize new_len, old_size, new_size;
|
||||
void* ptr;
|
||||
void* new_ptr;
|
||||
|
||||
AllocatorInfo allocator = strbuilder_get_header(* str)->Allocator;
|
||||
StrBuilderHeader* header = nullptr;
|
||||
|
||||
new_len = strbuilder_grow_formula(strbuilder_length(* str) + add_len);
|
||||
ptr = strbuilder_get_header(* str);
|
||||
old_size = size_of(StrBuilderHeader) + strbuilder_length(* str) + 1;
|
||||
new_size = size_of(StrBuilderHeader) + new_len + 1;
|
||||
|
||||
new_ptr = resize(allocator, ptr, old_size, new_size);
|
||||
|
||||
if (new_ptr == nullptr)
|
||||
return false;
|
||||
|
||||
header = rcast(StrBuilderHeader*, new_ptr);
|
||||
header->Allocator = allocator;
|
||||
header->Capacity = new_len;
|
||||
|
||||
char** Data = rcast(char**, str);
|
||||
* Data = rcast(char*, header + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
forceinline
|
||||
b32 strbuilder_starts_with_str(StrBuilder const str, Str substring) {
|
||||
if (substring.Len > strbuilder_length(str))
|
||||
return false;
|
||||
|
||||
b32 result = c_str_compare_len(str, substring.Ptr, substring.Len) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
forceinline
|
||||
b32 strbuilder_starts_with_string(StrBuilder const str, StrBuilder substring) {
|
||||
if (strbuilder_length(substring) > strbuilder_length(str))
|
||||
return false;
|
||||
|
||||
b32 result = c_str_compare_len(str, substring, strbuilder_length(substring) - 1) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void strbuilder_skip_line(StrBuilder str)
|
||||
{
|
||||
#define current (*scanner)
|
||||
char* scanner = str;
|
||||
while (current != '\r' && current != '\n') {
|
||||
++scanner;
|
||||
}
|
||||
|
||||
s32 new_length = scanner - str;
|
||||
|
||||
if (current == '\r') {
|
||||
new_length += 1;
|
||||
}
|
||||
|
||||
mem_move((char*)str, scanner, new_length);
|
||||
|
||||
StrBuilderHeader* header = strbuilder_get_header(str);
|
||||
header->Length = new_length;
|
||||
#undef current
|
||||
}
|
||||
|
||||
inline
|
||||
void strbuilder_strip_space(StrBuilder str)
|
||||
{
|
||||
char* write_pos = str;
|
||||
char* read_pos = str;
|
||||
|
||||
while (* read_pos)
|
||||
{
|
||||
if (! char_is_space(* read_pos))
|
||||
{
|
||||
* write_pos = * read_pos;
|
||||
write_pos++;
|
||||
}
|
||||
read_pos++;
|
||||
}
|
||||
write_pos[0] = '\0'; // Null-terminate the modified string
|
||||
|
||||
// Update the length if needed
|
||||
strbuilder_get_header(str)->Length = write_pos - str;
|
||||
}
|
||||
|
||||
forceinline
|
||||
Str strbuilder_to_str(StrBuilder str) {
|
||||
Str result = { (char const*)str, strbuilder_length(str) };
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
void strbuilder_trim(StrBuilder str, char const* cut_set)
|
||||
{
|
||||
ssize len = 0;
|
||||
|
||||
char* start_pos = str;
|
||||
char* end_pos = scast(char*, str) + strbuilder_length(str) - 1;
|
||||
|
||||
while (start_pos <= end_pos && char_first_occurence(cut_set, *start_pos))
|
||||
start_pos++;
|
||||
|
||||
while (end_pos > start_pos && char_first_occurence(cut_set, *end_pos))
|
||||
end_pos--;
|
||||
|
||||
len = scast(ssize, (start_pos > end_pos) ? 0 : ((end_pos - start_pos) + 1));
|
||||
|
||||
if (str != start_pos)
|
||||
mem_move(str, start_pos, len);
|
||||
|
||||
str[len] = '\0';
|
||||
|
||||
strbuilder_get_header(str)->Length = len;
|
||||
}
|
||||
|
||||
forceinline
|
||||
void strbuilder_trim_space(StrBuilder str) {
|
||||
strbuilder_trim(str, " \t\r\n\v\f");
|
||||
}
|
||||
|
||||
inline
|
||||
StrBuilder strbuilder_visualize_whitespace(StrBuilder const str)
|
||||
{
|
||||
StrBuilderHeader* header = (StrBuilderHeader*)(scast(char const*, str) - sizeof(StrBuilderHeader));
|
||||
StrBuilder result = strbuilder_make_reserve(header->Allocator, strbuilder_length(str) * 2); // Assume worst case for space requirements.
|
||||
|
||||
for (char const* c = strbuilder_begin(str); c != strbuilder_end(str); c = strbuilder_next(str, c))
|
||||
switch ( * c )
|
||||
{
|
||||
case ' ':
|
||||
strbuilder_append_str(& result, txt("·"));
|
||||
break;
|
||||
case '\t':
|
||||
strbuilder_append_str(& result, txt("→"));
|
||||
break;
|
||||
case '\n':
|
||||
strbuilder_append_str(& result, txt("↵"));
|
||||
break;
|
||||
case '\r':
|
||||
strbuilder_append_str(& result, txt("⏎"));
|
||||
break;
|
||||
case '\v':
|
||||
strbuilder_append_str(& result, txt("⇕"));
|
||||
break;
|
||||
case '\f':
|
||||
strbuilder_append_str(& result, txt("⌂"));
|
||||
break;
|
||||
default:
|
||||
strbuilder_append_char(& result, * c);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#pragma endregion StrBuilder
|
||||
|
||||
#if GEN_COMPILER_CPP
|
||||
struct StrBuilder_POD {
|
||||
char* Data;
|
||||
};
|
||||
static_assert( sizeof( StrBuilder_POD ) == sizeof( StrBuilder ), "StrBuilder is not a POD" );
|
||||
#endif
|
||||
|
||||
forceinline
|
||||
Str str_duplicate(Str str, AllocatorInfo allocator) {
|
||||
Str result = strbuilder_to_str( strbuilder_make_length(allocator, str.Ptr, str.Len));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline
|
||||
Str str_visualize_whitespace(Str str, AllocatorInfo allocator)
|
||||
{
|
||||
StrBuilder result = strbuilder_make_reserve(allocator, str.Len * 2); // Assume worst case for space requirements.
|
||||
for (char const* c = str_begin(str); c != str_end(str); c = str_next(str, c))
|
||||
switch ( * c )
|
||||
{
|
||||
case ' ':
|
||||
strbuilder_append_str(& result, txt("·"));
|
||||
break;
|
||||
case '\t':
|
||||
strbuilder_append_str(& result, txt("→"));
|
||||
break;
|
||||
case '\n':
|
||||
strbuilder_append_str(& result, txt("↵"));
|
||||
break;
|
||||
case '\r':
|
||||
strbuilder_append_str(& result, txt("⏎"));
|
||||
break;
|
||||
case '\v':
|
||||
strbuilder_append_str(& result, txt("⇕"));
|
||||
break;
|
||||
case '\f':
|
||||
strbuilder_append_str(& result, txt("⌂"));
|
||||
break;
|
||||
default:
|
||||
strbuilder_append_char(& result, * c);
|
||||
break;
|
||||
}
|
||||
return strbuilder_to_str(result);
|
||||
}
|
||||
|
||||
// Represents strings cached with the string table.
|
||||
// Should never be modified, if changed string is desired, cache_string( str ) another.
|
||||
typedef Str StrCached;
|
||||
|
||||
// Implements basic string interning. Data structure is based off the ZPL Hashtable.
|
||||
typedef HashTable(StrCached) StringTable;
|
||||
#pragma endregion Strings
|
||||
@@ -1,3 +1,8 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "filesystem.cpp"
|
||||
#endif
|
||||
|
||||
#pragma region Timing
|
||||
|
||||
#ifdef GEN_BENCHMARK
|
||||
@@ -18,7 +23,7 @@
|
||||
{
|
||||
u32 hi, lo;
|
||||
__asm__ __volatile__( "rdtsc" : "=a"( lo ), "=d"( hi ) );
|
||||
return ( zpl_cast( u64 ) lo ) | ( ( zpl_cast( u64 ) hi ) << 32 );
|
||||
return scast( u64, lo ) | ( scast( u64, hi ) << 32 );
|
||||
}
|
||||
#elif defined( __powerpc__ )
|
||||
u64 read_cpu_time_stamp_counter( void )
|
||||
@@ -160,4 +165,3 @@
|
||||
#endif
|
||||
|
||||
#pragma endregion Timing
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
||||
# pragma once
|
||||
# include "filesystem.hpp"
|
||||
#endif
|
||||
|
||||
#pragma region Timing
|
||||
|
||||
#ifdef GEN_BENCHMARK
|
||||
//! Return CPU timestamp.
|
||||
u64 read_cpu_time_stamp_counter( void );
|
||||
GEN_API u64 read_cpu_time_stamp_counter( void );
|
||||
|
||||
//! Return relative time (in seconds) since the application start.
|
||||
f64 time_rel( void );
|
||||
GEN_API f64 time_rel( void );
|
||||
|
||||
//! Return relative time since the application start.
|
||||
u64 time_rel_ms( void );
|
||||
GEN_API u64 time_rel_ms( void );
|
||||
#endif
|
||||
|
||||
#pragma endregion Timing
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
GEN_API, GEN_API
|
||||
|
@@ -0,0 +1,144 @@
|
||||
Invalid
|
||||
Untyped
|
||||
NewLine
|
||||
Comment
|
||||
Access_Private
|
||||
Access_Protected
|
||||
Access_Public
|
||||
PlatformAttributes
|
||||
Class
|
||||
Class_Fwd
|
||||
Class_Body
|
||||
Constructor
|
||||
Constructor_Fwd
|
||||
Destructor
|
||||
Destructor_Fwd
|
||||
Enum
|
||||
Enum_Fwd
|
||||
Enum_Body
|
||||
Enum_Class
|
||||
Enum_Class_Fwd
|
||||
Execution
|
||||
|
||||
Expression
|
||||
|
||||
Expr_Identifier
|
||||
Expr_NumericLiteral
|
||||
Expr_StringLiteral
|
||||
|
||||
Expr_Alignof
|
||||
Expr_ProcCall
|
||||
|
||||
Expr_Assign_Add
|
||||
Expr_Assign_Subtract
|
||||
Expr_Assign_Multiply
|
||||
Expr_Assign_Divide
|
||||
Expr_Assign_Modulo
|
||||
Expr_Assign_Bitwise_And
|
||||
Expr_Assign_Bitwise_Or
|
||||
Expr_Assign_Bitwise_XOr
|
||||
Expr_Assign_LeftShift
|
||||
Expr_Assign_RightShift
|
||||
|
||||
Expr_CStyleCast
|
||||
Expr_FunctionalCast
|
||||
Expr_ConstCast
|
||||
Expr_DynamicCast
|
||||
Expr_ReinterpretCast
|
||||
Expr_StaticCast
|
||||
|
||||
Expr_Unary_Add
|
||||
Expr_Unary_Minus
|
||||
Expr_Unary_Not
|
||||
Expr_Unary_Increment
|
||||
Expr_Unary_Decrement
|
||||
Expr_Indirection
|
||||
Expr_AddressOf,
|
||||
|
||||
Expr_UnaryPost_Increment
|
||||
Expr_UnaryPost_Decrement
|
||||
Expr_Subscript
|
||||
|
||||
Expr_Binary_Add
|
||||
Expr_Binary_Subtract
|
||||
Expr_Binary_Multiply
|
||||
Expr_Binary_Divide
|
||||
Expr_Binary_Modulo
|
||||
Expr_Binary_Bitwise_And
|
||||
Expr_Binary_Bitwise_Or
|
||||
Expr_Binary_Bitwise_XOr
|
||||
Expr_Binary_Bitwise_LeftShift
|
||||
Expr_Binary_Bitwise_RightShift
|
||||
Expr_Binary_Logical_Not
|
||||
Expr_Binary_Logical_And
|
||||
Expr_Binary_Logical_Or
|
||||
Expr_Binary_Equal
|
||||
Expr_Binary_NotEqual
|
||||
Expr_Binary_Lesser
|
||||
Expr_Binary_Greater
|
||||
Expr_Binary_LesserEqual
|
||||
Expr_Binary_GreaterEqual
|
||||
Expr_MemberOfObject,
|
||||
Expr_MemberOfPointer,
|
||||
Expr_PointerToMemberOfObject,
|
||||
Expr_PointerToMemberOfPointer,
|
||||
Expr_Comma,
|
||||
Expr_Tenary,
|
||||
|
||||
Export_Body
|
||||
Extern_Linkage
|
||||
Extern_Linkage_Body
|
||||
Friend
|
||||
Function
|
||||
Function_Fwd
|
||||
Function_Body
|
||||
Global_Body
|
||||
|
||||
Module
|
||||
Namespace
|
||||
Namespace_Body
|
||||
Operator
|
||||
Operator_Fwd
|
||||
Operator_Member
|
||||
Operator_Member_Fwd
|
||||
Operator_Cast
|
||||
Operator_Cast_Fwd
|
||||
Parameters
|
||||
Preprocess_Define
|
||||
Preprocess_Include
|
||||
Preprocess_If
|
||||
Preprocess_IfDef
|
||||
Preprocess_IfNotDef
|
||||
Preprocess_ElIf
|
||||
Preprocess_Else
|
||||
Preprocess_EndIf
|
||||
Preprocess_Pragma
|
||||
Specifiers
|
||||
|
||||
Statement
|
||||
Stmt_Break
|
||||
Stmt_Case
|
||||
Stmt_Continue
|
||||
Stmt_Declaration
|
||||
Stmt_Do
|
||||
Stmt_Expr
|
||||
Stmt_Else
|
||||
Stmt_If
|
||||
Stmt_For
|
||||
Stmt_Goto
|
||||
Stmt_Label
|
||||
Stmt_Switch
|
||||
Stmt_Switch
|
||||
Stmt_While
|
||||
|
||||
Struct
|
||||
Struct_Fwd
|
||||
Struct_Body
|
||||
Template
|
||||
Typedef
|
||||
Typename
|
||||
Union
|
||||
Union_Body
|
||||
Using
|
||||
Using_Namespace
|
||||
Variable
|
||||
|
@@ -0,0 +1,62 @@
|
||||
Invalid, "__NA__"
|
||||
Untyped, "__NA__"
|
||||
NewLine, "__NA__"
|
||||
Comment, "//"
|
||||
Access_Private, "private"
|
||||
Access_Protected, "protected"
|
||||
Access_Public, "public"
|
||||
PlatformAttributes, "__NA__"
|
||||
Class, "class"
|
||||
Class_Fwd, "clsss"
|
||||
Class_Body, "__NA__"
|
||||
Constructor, "__NA__"
|
||||
Constructor_Fwd, "__NA__"
|
||||
Destructor, "__NA__"
|
||||
Destructor_Fwd, "__NA__"
|
||||
Enum, "enum"
|
||||
Enum_Fwd, "enum"
|
||||
Enum_Body, "__NA__"
|
||||
Enum_Class, "enum class"
|
||||
Enum_Class_Fwd, "enum class"
|
||||
Execution, "__NA__"
|
||||
Export_Body, "__NA__"
|
||||
Extern_Linkage, "extern"
|
||||
Extern_Linkage_Body, "extern"
|
||||
Friend, "friend"
|
||||
Function, "__NA__"
|
||||
Function_Fwd, "__NA__"
|
||||
Function_Body, "__NA__"
|
||||
Global_Body, "__NA__"
|
||||
Module, "module"
|
||||
Namespace, "namespace"
|
||||
Namespace_Body, "__NA__"
|
||||
Operator, "operator"
|
||||
Operator_Fwd, "operator"
|
||||
Operator_Member, "operator"
|
||||
Operator_Member_Fwd, "operator"
|
||||
Operator_Cast, "operator"
|
||||
Operator_Cast_Fwd, "operator"
|
||||
Parameters, "__NA__"
|
||||
Parameters_Define, "__NA__"
|
||||
Preprocess_Define, "define"
|
||||
Preprocess_Include, "include"
|
||||
Preprocess_If, "if"
|
||||
Preprocess_IfDef, "ifdef"
|
||||
Preprocess_IfNotDef, "ifndef"
|
||||
Preprocess_ElIf, "elif"
|
||||
Preprocess_Else, "else"
|
||||
Preprocess_EndIf, "endif"
|
||||
Preprocess_Pragma, "pragma"
|
||||
Specifiers, "__NA__"
|
||||
Struct, "struct"
|
||||
Struct_Fwd, "struct"
|
||||
Struct_Body, "__NA__"
|
||||
Template, "template"
|
||||
Typedef, "typedef"
|
||||
Typename, "__NA__"
|
||||
Union, "union"
|
||||
Union_Fwd, "union"
|
||||
Union_Body, "__NA__"
|
||||
Using, "using"
|
||||
Using_Namespace, "using namespace"
|
||||
Variable, "__NA__"
|
||||
|
@@ -41,3 +41,7 @@ MemberOfPointer, "->"
|
||||
PtrToMemOfPtr, "->*"
|
||||
FunctionCall, "()"
|
||||
Comma, ","
|
||||
New, "new"
|
||||
NewArray, "new[]"
|
||||
Delete, "delete"
|
||||
DeleteArray, "delete[]"
|
||||
|
500 Internal Server Error
An error occurred: An error occurred Gitea Version: 28.1.0 |