mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-09-22 17:20:05 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76ce8a79c2 | ||
|
|
932db741fa | ||
|
|
0add3ef72c | ||
|
|
e417a96ce4 | ||
|
|
b2262532a7 | ||
|
|
b24326f502 | ||
|
|
66c1fa337c |
@@ -1,8 +0,0 @@
|
|||||||
*.sh text=auto eol=lf
|
|
||||||
src/lib_rdi/rdi.h text=auto eol=lf
|
|
||||||
src/lib_rdi/rdi.c text=auto eol=lf
|
|
||||||
*.meta.* text=auto eol=lf
|
|
||||||
*.exe filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.pdb filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.elf filter=lfs diff=lfs merge=lfs -text
|
|
||||||
*.rdi filter=lfs diff=lfs merge=lfs -text
|
|
||||||
@@ -8,144 +8,21 @@ on:
|
|||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
|
|
||||||
env:
|
|
||||||
TORTURE_FLAGS: "--gen_crash_dump"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-ubuntu-24-04:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
target:
|
|
||||||
- raddbg
|
|
||||||
- raddbg_non_graphical
|
|
||||||
- radlink
|
|
||||||
- radbin
|
|
||||||
- torture
|
|
||||||
compiler:
|
|
||||||
- clang-22
|
|
||||||
# TODO: - gcc
|
|
||||||
mode:
|
|
||||||
- debug
|
|
||||||
- release
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- name: Install Dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-add-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y clang-22 lld-22 llvm-22 gcc-14 pkg-config libfreetype6-dev libx11-dev libxext-dev libgl1-mesa-dev libegl1-mesa-dev
|
|
||||||
sudo ln -s /usr/bin/llvm-symbolizer-22 /usr/bin/llvm-symbolizer
|
|
||||||
- name: build
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
CC="${{ matrix.compiler }}" ./build.sh "${{ matrix.target }}" "${{ matrix.mode }}"
|
|
||||||
|
|
||||||
build-windows-2022:
|
build-windows-2022:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
|
||||||
target:
|
|
||||||
- raddbg
|
|
||||||
- radlink
|
|
||||||
- radbin
|
|
||||||
- mule_main
|
|
||||||
compiler:
|
|
||||||
- msvc
|
|
||||||
- clang
|
|
||||||
mode:
|
|
||||||
- debug
|
|
||||||
- release
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v2
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- name: build (vs 2022)
|
- name: build (vs 2022)
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_INSTALL=%%i"
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
|
||||||
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
|
call build raddbg msvc debug || exit /b 1
|
||||||
call build meta "${{ matrix.target }}" "${{ matrix.compiler }}" "${{ matrix.mode }}" || exit /b 1
|
call build raddbg_from_pdb msvc debug || exit /b 1
|
||||||
|
call build raddbg_from_dwarf msvc debug || exit /b 1
|
||||||
run-ubuntu-24-04:
|
call build raddbg clang debug || exit /b 1
|
||||||
runs-on: ubuntu-24.04
|
call build raddbg_from_pdb clang debug || exit /b 1
|
||||||
strategy:
|
call build raddbg_from_dwarf clang debug || exit /b 1
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
compiler:
|
|
||||||
- clang-22
|
|
||||||
# TODO: - gcc
|
|
||||||
mode:
|
|
||||||
- debug
|
|
||||||
# TODO: - release
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- name: Install Dependencies
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-add-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y clang-22 lld-22 llvm-22 gcc-14 pkg-config libfreetype6-dev libx11-dev libxext-dev libgl1-mesa-dev libegl1-mesa-dev
|
|
||||||
# crash callstack symbolizer depends on LLVM
|
|
||||||
sudo ln -s /usr/bin/llvm-symbolizer-22 /usr/bin/llvm-symbolizer
|
|
||||||
- name: Run
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
CC="${{ matrix.compiler }}" ./run_tests.sh clang "${{ matrix.mode }}" -- \* $TORTURE_FLAGS
|
|
||||||
- name: Upload Artifacts
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: torture-crash-dumps-${{ matrix.compiler }}-${{ matrix.mode }}
|
|
||||||
path: |
|
|
||||||
build/*.core
|
|
||||||
build/*.exe
|
|
||||||
build/*.pdb
|
|
||||||
build/torture_artifacts/**
|
|
||||||
if-no-files-found: ignore
|
|
||||||
|
|
||||||
run-windows-2022:
|
|
||||||
runs-on: windows-2022
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
compiler:
|
|
||||||
- msvc
|
|
||||||
- clang
|
|
||||||
mode:
|
|
||||||
- debug
|
|
||||||
- release
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
with:
|
|
||||||
lfs: true
|
|
||||||
- name: Run
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_INSTALL=%%i"
|
|
||||||
call "%VS_INSTALL%\VC\Auxiliary\Build\vcvarsall.bat" x64
|
|
||||||
call run_tests.bat ${{ matrix.compiler }} ${{ matrix.mode }} -- * %TORTURE_FLAGS% || exit /b 1
|
|
||||||
- name: Upload Artifacts
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: torture-crash-dumps-${{ matrix.compiler }}-${{ matrix.mode }}
|
|
||||||
path: |
|
|
||||||
build/*.dmp
|
|
||||||
build/*.exe
|
|
||||||
build/*.pdb
|
|
||||||
build/torture_artifacts/**
|
|
||||||
if-no-files-found: ignore
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
/build/
|
/build/
|
||||||
/local/
|
/local/
|
||||||
*~
|
*~
|
||||||
.vs
|
|
||||||
tags
|
|
||||||
-399
@@ -1,399 +0,0 @@
|
|||||||
# v0.9.28-alpha
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
- Implemented `/OPT:ICF` identical COMDAT folding.
|
|
||||||
- Added DEF, and SECTION configuration support.
|
|
||||||
- Improved COMDAT handling for weak symbols, ICF, and zero-sized COMDAT
|
|
||||||
anchors, and stopped emitting empty marker sections that could produce invalid
|
|
||||||
PE images.
|
|
||||||
- Fixed import/export edge cases, including import data-directory bounds and
|
|
||||||
archive member handling for `__imp_*` symbols.
|
|
||||||
- Accepted duplicate identical weak search aliases without reporting multiply
|
|
||||||
defined symbols.
|
|
||||||
- Add support for UTF-16 encoded response files.
|
|
||||||
- Fixed DBI section-contribution image-section range mapping.
|
|
||||||
- Improved debug logging for `/OPT:REF` liveness stats and unresolved symbols
|
|
||||||
referenced by `.llvm_addrsig`.
|
|
||||||
|
|
||||||
# v0.9.27-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Fixed an issue which would rarely cause steps to take a long time.
|
|
||||||
- Drastically improved memory usage of PDB -> RDI conversion for some
|
|
||||||
workloads, notably PDBs with many small compilation units.
|
|
||||||
- Added the ability to disambiguate symbol names by module name, debug info
|
|
||||||
name, or compilation unit name in expressions. This can be done using the
|
|
||||||
usual syntax, e.g. `my_module.dll!foo`, or `my_unit.obj!foo`. `:` can also be
|
|
||||||
used instead of `!`.
|
|
||||||
- Added the ability to redirect debug string output to any label on a
|
|
||||||
per-target basis. Those labels can then be evaluated in any watch window or
|
|
||||||
text visualizer. By default, all targets write to `output`, which is
|
|
||||||
automatically visualized by an `Output` tab. But if you want different
|
|
||||||
targets to route their debug output to different buffers, you can name the
|
|
||||||
buffers differently, and then view those in separate text views.
|
|
||||||
- Added a `Run To Name` command.
|
|
||||||
- Added an `Auto Load Last Project` setting, which will automatically load the
|
|
||||||
most recently loaded project on startup (the old behavior pre-0.9.26). This
|
|
||||||
setting is off by default.
|
|
||||||
- Added right-click menus for watch expressions, to easily find them in a
|
|
||||||
memory view, or to break when their value changes.
|
|
||||||
- Added preliminary support for symbol servers. First, the debugger can attempt
|
|
||||||
to download debug info for any module via the `Download Module Debug Info`
|
|
||||||
command (also accessible by right-clicking a module). Second, the debugger
|
|
||||||
can be configured to automatically do this for all modules which don't have
|
|
||||||
debug info via the `Auto Download Debug Info` setting. The local cache path
|
|
||||||
and server URLs used by the debugger for downloading symbols are parsed from
|
|
||||||
the `_NT_SYMBOL_PATH` environment variable. If that environment variable is
|
|
||||||
not configured, then it falls back to the defaults of `C:/SymbolCache` and
|
|
||||||
`https://msdl.microsoft.com/download/symbols`.
|
|
||||||
- Adjusted the default dark theme.
|
|
||||||
- Made several UI visual improvements.
|
|
||||||
- Fixed a few issues relating to offline symbol evaluation (evaluation of
|
|
||||||
symbols in debug info when not debugging); this was sometimes preventing
|
|
||||||
function listers (e.g. used in `Go To Name`) from working when not debugging.
|
|
||||||
- Fixed the debugger's snap-to-code-location rule when a `Disassembly` tab is
|
|
||||||
occupying the same panel as source code tabs. Previously, the debugger would
|
|
||||||
overly aggressively switch back to source code tabs. Now, it should respect
|
|
||||||
the preference of disassembly correctly.
|
|
||||||
- Improved the stability of the step-over-line operation. Our stepping
|
|
||||||
algorithm would sometimes cause spurious (and rarely, non-spurious)
|
|
||||||
access violation exceptions when a thread would try to execute at address
|
|
||||||
`0x38f`. This most regularly surfaced when an exception on one thread (like a
|
|
||||||
breakpoint being hit) would interrupt stepping on another thread. This has
|
|
||||||
been resolved, and stepping in such scenarios should be much more reliable.
|
|
||||||
- Fixed some crashes in the PDB -> RDI converter. (#792, #803)
|
|
||||||
- Fixed a bug which was sometimes causing a step-over operation to resume the
|
|
||||||
process without catching the target thread after its step completed. (#804)
|
|
||||||
- Adjusted evaluation visualizations to include fully qualified symbol names.
|
|
||||||
(#809)
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
- /OPT:REF Fixed a race in the dead-code-elimination pass where the linker
|
|
||||||
sometimes erroneously removed live sections.
|
|
||||||
- Fixed a bug where the linker emitted relocations for empty COFF resource entries,
|
|
||||||
which lead to "relocating against symbol that is in a removed section" errors.
|
|
||||||
- Added the /RAD_TYPE_SERVER switch to run the type-dedup pass on object files,
|
|
||||||
producing RRT files that can be passed back on the next link to improve
|
|
||||||
linking speed.
|
|
||||||
|
|
||||||
# v0.9.26-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Added scope ending visualizations to the text view, to display the header of
|
|
||||||
a scope at the closing position of the scope. This can be turned off via the
|
|
||||||
`Cursor Scope End Annotations` setting.
|
|
||||||
- Added the ability to evaluate `autos`, which is a collection of expressions
|
|
||||||
that the debugger determines refer to symbols which are being (or about to
|
|
||||||
be) changed by the selected thread.
|
|
||||||
- Added source-inline and disassembly-inline visualization of auto expressions.
|
|
||||||
This can be turned off via the `Show Auto Watches In Source / Disassembly`
|
|
||||||
setting.
|
|
||||||
- Added the ability to evaluate local static variables unambiguously, when the
|
|
||||||
same name is used for multiple local static variables, even when outside the
|
|
||||||
function containing the local static. This can be done by namespacing the
|
|
||||||
variable name with the containing function, either using a `::` or `.`
|
|
||||||
operator. (#359)
|
|
||||||
- Added a setting, `Transient Tabs`, to disable transient tabs being opened,
|
|
||||||
when the debugger automatically snaps to new code locations.
|
|
||||||
- Added a setting, `Display Pointer Addresses Before Contents`, to always
|
|
||||||
force the debugger to show pointer addresses before attempting to visualize
|
|
||||||
to what the pointer points.
|
|
||||||
- Adjusted the `Step Out` command to perform scope-granularity stepping, rather
|
|
||||||
than only being function-frame-granularity. This uses scope information found
|
|
||||||
in debug info to step out of scopes when possible, rather than always exiting
|
|
||||||
the current function frame. This makes the command much more useful for
|
|
||||||
stepping through larger functions with several scopes of larger work, or for
|
|
||||||
stepping out of loops. (#746)
|
|
||||||
- Adjusted the debugger's user & project configuration file behavior to be less
|
|
||||||
idiosyncratic with other programs. Project files are no longer auto-loaded
|
|
||||||
based on the project last loaded during the previous debugger runtime.
|
|
||||||
Creating a new user or project also does not immediately require choosing a
|
|
||||||
path for the file; these can later be specified using the respective `Save`
|
|
||||||
commands. (#743)
|
|
||||||
- Adjusted the debugger to automatically set the current path when loading a
|
|
||||||
project file. (#743)
|
|
||||||
- Added syntax highlighting and tab-completion for view identifiers in
|
|
||||||
watch expressions.
|
|
||||||
- Added more in-debugger documentation for views and their arguments, when
|
|
||||||
written in a watch expression.
|
|
||||||
- Moved configuration data previously treated as project data to being user
|
|
||||||
data, tagged with the associated project. This includes loaded debug info and
|
|
||||||
breakpoints. The effect of this is that project files are much easier to
|
|
||||||
check into source control (they do not change in spurious ways for other
|
|
||||||
users on a project), but project-related user configuration will still be
|
|
||||||
correctly filtered based on whatever project is loaded.
|
|
||||||
- Improved the debugger's behavior with respect to keeping previously-loaded
|
|
||||||
debug info around. Now, when the debugger begins a new debugging session, it
|
|
||||||
will unload all loaded debug info, and it will only reload debug info that is
|
|
||||||
actively found to be needed by debuggees. This preserves the debugger's
|
|
||||||
ability to use debug info without debugging for features like
|
|
||||||
go-to-definition and type evaluation, but it stops the debugger from keeping
|
|
||||||
old and unneeded debug info loaded indefinitely (until it is manually
|
|
||||||
unloaded). (#711)
|
|
||||||
- Adjusted recent project visualization to include the name of the project,
|
|
||||||
specified with the `Project Name` setting.
|
|
||||||
- Renamed `Switch` to `Open Source File From Debug Info`, to better represent
|
|
||||||
the command's functionality.
|
|
||||||
- Adjusted file path evaluation visualization to include the full path to the
|
|
||||||
containing folder, when it is not obvious from context (for instance, if the
|
|
||||||
file evaluation is a child evaluation of a folder evaluation, the containing
|
|
||||||
folder path is not shown; if the file path is evaluated standalone, as it is
|
|
||||||
in the lister generated for the `Open Source File From Debug Info` command,
|
|
||||||
then the containing folder path is shown).
|
|
||||||
- Improved visualization of unmapped addresses in the memory view. Now, instead
|
|
||||||
of bytes at these addresses being displayed as `0` with a special background,
|
|
||||||
they are displayed as `x`, and the annotations for these addresses (displayed
|
|
||||||
at the bottom of the memory view, for the cursor's cell) explicitly label
|
|
||||||
them as being unmapped.
|
|
||||||
- Improved visualization of unmapped addresses in watch expressions. Now,
|
|
||||||
instead of only being colored differently with evaluations reading as zeroed
|
|
||||||
memory, the value will explicitly label addresses as unmapped when possible.
|
|
||||||
- Fixed a leak which most notably manifested during rapid creation/destruction
|
|
||||||
of new threads. (#780)
|
|
||||||
- Fixed a leak related to debugger's config state. This was difficult to
|
|
||||||
reproduce, but it may fix leaks experienced after running the debugger for an
|
|
||||||
extended period of time.
|
|
||||||
- Fixed a bug where cross-module evaluations would resolve to incorrect
|
|
||||||
addresses, due to using the incorrect module's base virtual address. This was
|
|
||||||
also causing broken behavior sometimes in the `Go To Name` lister, and
|
|
||||||
other similar UIs.
|
|
||||||
- Fixed a bug where panels without tabs were unnecessarily keeping the debugger
|
|
||||||
UI awake in some cases.
|
|
||||||
- Fixed a bug preventing hover evaluation from working on indexing expressions.
|
|
||||||
(#707)
|
|
||||||
- Replaced the DWARF -> RDI converter with a new multithreaded version, which
|
|
||||||
should execute much faster on larger DWARF debug info, and produce much
|
|
||||||
smaller RDI output, due to the addition of type deduplication.
|
|
||||||
- Introduced structured namespaces to RDI, which structurally encode namespace
|
|
||||||
hierarchies for debug info symbols, instead of this information being
|
|
||||||
implicitly baked using language-specific conventions into symbol names. This
|
|
||||||
is used to deduplicate repeated namespace prefixes from symbol names, leading
|
|
||||||
to a smaller string footprint for generated RDIs. Symbols now only store
|
|
||||||
their partially-qualified name. For example, for a C++ symbol `A::B::C`, the
|
|
||||||
symbol itself will store its name as `C`, but it will also record its
|
|
||||||
container as being `B`. `B`, then, will record its container as being `A`.
|
|
||||||
This allows users of RDI to dynamically construct the fully-qualified name as
|
|
||||||
needed, and it allows for more reliable and language-agnostic usage of
|
|
||||||
partially-qualified symbol names.
|
|
||||||
- Adjusted the debugger to not rely on `SynchronizationBarrier` functions on
|
|
||||||
Windows when they're not available (pre-Windows-8). (#739)
|
|
||||||
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
|
|
||||||
- Implemented /DEBUG:GHASH
|
|
||||||
- Fixed an issue where an import thunk or import address could be linked from
|
|
||||||
the currently searched library instead of the library where the first import
|
|
||||||
reference was found. For example, if the first pass finds the import thunk in
|
|
||||||
foo.lib and the second pass resolves symbol to the import address in bar.lib,
|
|
||||||
the linker now always linkes the import thunk and import address members from
|
|
||||||
the library where the first reference was found.
|
|
||||||
- /OPT:REF: Fixed an issue with garbage collection of associated sections and
|
|
||||||
weak symbols that led linker to remove live sections.
|
|
||||||
- /OPT:REF Added relocation batching to reduce contention on the global
|
|
||||||
reference list during garbage collection.
|
|
||||||
|
|
||||||
# v0.9.25-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Added a dedicated cursor address bar to the memory view. This can be focused
|
|
||||||
with the keyboard with the `Focus Menu` command. By default, this command is
|
|
||||||
bound to `Alt + D`, but if you have existing configuration, you may need to
|
|
||||||
bind it yourself manually (this can be done in the palette). This address bar
|
|
||||||
accepts any expression, and controls the cursor's address. All other
|
|
||||||
configuration options are still available in the memory view settings.
|
|
||||||
- Added "Peek Types" to the memory view. These control the set of types which
|
|
||||||
are used to interpret bytes at the cursor. Options exist for basic cases,
|
|
||||||
like integers and floats, but the view also supports entering a list of
|
|
||||||
full type expressions, which can include user-defined types like structures.
|
|
||||||
- Added annotations for members of structure variables to the memory view.
|
|
||||||
- Added a dedicated zoom setting for the memory view.
|
|
||||||
- Added a setting for automatically determining the number of columns in the
|
|
||||||
memory view based on the available space.
|
|
||||||
- Fixed many bugs and improved visuals in the memory view. (#690)
|
|
||||||
- Fixed the debugger incorrectly evaluating pointer casts of registers in
|
|
||||||
register space, rather than promoting them to process address space
|
|
||||||
evaluations. This fixes cases where expressions like `(int *)rax` were not
|
|
||||||
evaluating correctly. (#659)
|
|
||||||
- Fixed the debugger incorrectly requiring multiple step operations when source
|
|
||||||
lines mapped to multiple discontiguous ranges of instructions. This most
|
|
||||||
notably showed up with certain styles of `for`-loops, especially with Clang
|
|
||||||
and other non-C/C++ languages, and function prologues in non-C/C++ languages.
|
|
||||||
- Fixed the debugger treating the `foo, x` fastpath for `hex(foo)` differently
|
|
||||||
than `hex(foo)`, in that the hexadecimal setting was not being inherited.
|
|
||||||
- Fixed the debugger leaking debug info conversion process handles. This
|
|
||||||
addresses cases where the debugger was preventing stale debug info from being
|
|
||||||
updated, after a rebuild. (#736)
|
|
||||||
- Fixed the debugger not correctly using target-embedded markup data. (#702)
|
|
||||||
- Fixed the debugger not showing full call stacks when the top instruction
|
|
||||||
pointer is located at a 0 address.
|
|
||||||
- Fixed integer casts producing incorrect values. (#754)
|
|
||||||
- Fixed the PDB -> RDI converter's interpretation of certain empty argument
|
|
||||||
lists in function types in PDB. This fixes some cases where local variables
|
|
||||||
were being interpreted as parameters, which resulted in incorrect evaluation
|
|
||||||
results. (#751)
|
|
||||||
- Fixed several crashes and instabilities. (#735)
|
|
||||||
- Added a dedicated settings button to the focused tab. This opens the same
|
|
||||||
menu as right-clicking the tab, but this makes this menu (and thus all
|
|
||||||
options for all tabs and views) more discoverable.
|
|
||||||
- Added optional cursor trails, to visualize cursor motion. Can be turned off
|
|
||||||
by toggling the `Cursor Trail` setting.
|
|
||||||
- Added project names. When set, this name is used for displaying the project
|
|
||||||
instead of the project filename in the UI and window titles.
|
|
||||||
- Adjusted the rules for explicit file location finding commands (like
|
|
||||||
`Switch`, or `Switch To Partner File`), such that they prefer creating new
|
|
||||||
non-transient tabs, even if the target file is found within an existing
|
|
||||||
transient tab.
|
|
||||||
- Adjusted the source code context menu to activate commands with a single
|
|
||||||
press, rather than the usual double click behavior from general palettes.
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
|
|
||||||
- Optimized debug info generation to reduce memory usage in large links by 25%.
|
|
||||||
- Fixed a determinism issue that caused linker to write unreliable debug info.
|
|
||||||
- Fixed over-reservetaion of PDB pages, reducing the PDB size.
|
|
||||||
- Implemented /INFERASANLIBS
|
|
||||||
- Implemented /WHOLEARCHIVE
|
|
||||||
- Implemented /PDBSTRIPPED
|
|
||||||
- Set correct defaults for unload and bind import tables.
|
|
||||||
|
|
||||||
# v0.9.24-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Added the ability for the debugger to load, use, and evaluate using debug
|
|
||||||
info, even when not actively debugging. The debugger will now keep a process'
|
|
||||||
debug info loaded, even after the process ends. It stores the set of loaded
|
|
||||||
debug info files in the project configuration file, meaning it will also
|
|
||||||
automatically load the same debug info across many runs. Debug info can also
|
|
||||||
be loaded manually (without ever launching a process) with the
|
|
||||||
`Load Debug Info` command. There is also a new tab, `Debug Info`, which allows
|
|
||||||
viewing and managing the set of loaded debug info files.
|
|
||||||
- Improved the debugger's behavior when used as a drag & drop target, to allow
|
|
||||||
for debug info loading as an option (when relevant), and to better handle the
|
|
||||||
case where many files (potentially of different types) are dropped together.
|
|
||||||
- Improved debug info searching performance and reponsiveness in large projects.
|
|
||||||
- Fixed some crashes and incorrect results with the new `list` view.
|
|
||||||
- Fixed some cases where RDIs did not contain some basic types from their
|
|
||||||
originating PDBs.
|
|
||||||
- Allowed `.` and `->` operators to be used with array types.
|
|
||||||
- Fixed the debugger's treatment of quoted command line arguments when building
|
|
||||||
targets. In previous versions, calling `raddbg main.exe "foo bar baz"` would
|
|
||||||
create a target `main.exe` with arguments `foo bar baz` (dropping the quotes).
|
|
||||||
This is now fixed, such that the target's arguments string will also contain
|
|
||||||
the quotes, and pass them to the target when launched.
|
|
||||||
- Fixed the debugger not correctly responding (through font and UI scale) to DPI
|
|
||||||
changes.
|
|
||||||
- Fixed the debugger incorrectly generating conflicting source line info records
|
|
||||||
in PDB -> RDI conversion, which in some scenarios was preventing source line
|
|
||||||
maps from working (leading to breakpoint resolution failing).
|
|
||||||
- Other small fixes, improvements, and tweaks.
|
|
||||||
|
|
||||||
# v0.9.23-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Further improved PDB -> RDI conversion performance & memory usage.
|
|
||||||
- Adjusted limits for the amount of PDB -> RDI conversion work that the
|
|
||||||
debugger will kick off, to prevent PDB -> RDI conversion interfering with
|
|
||||||
debuggee performance.
|
|
||||||
- Reintroduced the `list` lens, which gathers all nodes in a linked list, and
|
|
||||||
visualizes them as a flat list of pointers (the same as how an array of
|
|
||||||
pointers is visualized).
|
|
||||||
- Fixed a crash when closing empty Geometry 3D views. (#652, #657)
|
|
||||||
- Fixed the debugger not visualizing `enum` types when evaluated through a
|
|
||||||
bitfield type. (#655)
|
|
||||||
- Fixed the PDB -> RDI conversion not correctly generating location information
|
|
||||||
for function parameters, when the EXE/PDB were built to include support for
|
|
||||||
Edit and Continue (`-ZI` switch). (#656)
|
|
||||||
|
|
||||||
## Binary Utility Changes
|
|
||||||
|
|
||||||
- Fixed a crash when using the `--compress` option, when generating RDI files.
|
|
||||||
|
|
||||||
# v0.9.22-alpha
|
|
||||||
|
|
||||||
## Debugger Changes
|
|
||||||
|
|
||||||
- Further improved PDB -> RDI conversion performance.
|
|
||||||
- Capped the number of additional threads / processes spawned for PDB -> RDI
|
|
||||||
conversion.
|
|
||||||
- Prioritize PDB -> RDI conversion based on what is actually found to be
|
|
||||||
necessary by the debugger, rather than converting all PDBs in the order in
|
|
||||||
which they're discovered.
|
|
||||||
- Added preliminary support for DWARF -> RDI conversion on Windows.
|
|
||||||
- The debugger now relies on source file checksums to determine whether or not
|
|
||||||
a source file is out-of-date with respect to what was compiled when debug info
|
|
||||||
was produced, rather than just the modification timestamp.
|
|
||||||
- The debugger now will rely on debug info to detect the language of source code
|
|
||||||
files, if it cannot infer from the source file's extension, or view settings.
|
|
||||||
This will enable features like syntax highlighting and hover evaluation in
|
|
||||||
cases like `.inl` files being included in C++ projects.
|
|
||||||
- The debugger now will restore the last focused window when continuing
|
|
||||||
automatically. (#245, #596)
|
|
||||||
- Watch tables have been simplified in that they no longer have a separate
|
|
||||||
column for evaluation types, since this was usually taking a lot more space
|
|
||||||
than it deserved. The type of evaluations is still displayed in watch table
|
|
||||||
cells, and it can always be evaluated directly via `typeof`.
|
|
||||||
- Type evaluations have been simplified in watch tables as well; they no longer
|
|
||||||
have untitled columns for sizes and offsets, this is instead displayed as
|
|
||||||
an extra note by default. Similar behavior to the original behavior can still
|
|
||||||
be obtained using the `columns` view, if needed.
|
|
||||||
- The debugger no longer uses complex `union` types for most registers, and
|
|
||||||
instead just displays the register value plainly.
|
|
||||||
- The hover evaluation UI has been made larger when needed.
|
|
||||||
- The debugger now prefers matching global, function, and type identifiers to
|
|
||||||
the most relevant debug info and module in context; this fixes evaluation in
|
|
||||||
some multi-process debugging contexts. (#581)
|
|
||||||
- Fixed the debugger unnecessarily stripping `enum` type information when
|
|
||||||
accessed through array operators. (#634)
|
|
||||||
- The debugger now understands a standalone `unsigned` keyword as an
|
|
||||||
`unsigned int` type, to match C rules.
|
|
||||||
- The debugger now uses the current working directory to form the working
|
|
||||||
directory for targets specified on the command line, to match behavior when
|
|
||||||
running a command from the command line without the debugger.
|
|
||||||
- Improved call stack computation performance.
|
|
||||||
- Improved debugger memory usage over long periods of time.
|
|
||||||
- Fixed string-pointer comparison not working with not-equal (`!=`) operations.
|
|
||||||
- Fixed a bug which was causing bad debuggee performance on some threads after
|
|
||||||
some interactions with the debugger controller.
|
|
||||||
- Fixed incorrect results when adding two register values. (#642)
|
|
||||||
- Fixed the interpretation of register expressions in visualizers. (#649)
|
|
||||||
- Fixed "forever loading" states in disassembly views in some cases. (#643)
|
|
||||||
- Fixed jittering on window resizing. (#636)
|
|
||||||
- Fixed the bitmap visualizer crashing in some circumstances relating to
|
|
||||||
unsupported bitmap sizes. (#444, #563)
|
|
||||||
- Fixed a crash when an empty `cast()` expression would be evaluated. (#625)
|
|
||||||
- Fixed a crash when an invalid expression would be visualized using the `text`
|
|
||||||
view. (#647)
|
|
||||||
|
|
||||||
## Linker Changes
|
|
||||||
|
|
||||||
- Changed symbol resolution in libaries to match MSVC behavior.
|
|
||||||
- Optimized image building step to reduce memory usage.
|
|
||||||
- Linker memory maps all input files by default to lower memory usage.
|
|
||||||
(`/RAD_MEMORY_MAP_FILES`)
|
|
||||||
- If debug info is available, linker uses it to show file and line number for
|
|
||||||
unresolved relocations.
|
|
||||||
- Improved base relocation build performance for large images, cutting build
|
|
||||||
time by 70%.
|
|
||||||
- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability
|
|
||||||
with existing response files
|
|
||||||
- Implemented section garbage collection (`/OPT:REF`)
|
|
||||||
- Fixed bug where thread local variables pointed to incorrect types.
|
|
||||||
- Changed rules for weak and undefined symbols, now weak symbol is not allowed
|
|
||||||
to replace an undefined symbol.
|
|
||||||
- Linker no longer creates thunks for imports that don't require them.
|
|
||||||
|
|
||||||
## Binary Utility Changes
|
|
||||||
|
|
||||||
- The binary utility, like the debugger, now can convert DWARF debug info to
|
|
||||||
RDI files. When both DWARF and PDB info is present, it can now convert both,
|
|
||||||
and produce a single final RDI file with all information.
|
|
||||||
- Textual dumping of RDI files is now done in parallel, massively improving
|
|
||||||
dumping performance.
|
|
||||||
- PDB -> Breakpad conversion performance has now been parallelized to a greater
|
|
||||||
degree, improving performance.
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) Epic Games Tools
|
Copyright (c) 2024 Epic Games Tools
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the “Software”), to deal in
|
this software and associated documentation files (the “Software”), to deal in
|
||||||
|
|||||||
@@ -1,93 +1,42 @@
|
|||||||
# The RAD Debugger Project
|
# The RAD Debugger Project
|
||||||
|
|
||||||
_**NOTE:** This README does not document usage instructions and tips for the
|
|
||||||
debugger itself, and is intended as a technical overview of the project. The
|
|
||||||
debugger's README, which includes usage instructions and tips, can be found
|
|
||||||
packaged along with debugger releases, or within the `build` folder after a
|
|
||||||
local copy has been built. You can find pre-built release binaries
|
|
||||||
[here](https://github.com/EpicGames/raddebugger/releases)._
|
|
||||||
|
|
||||||
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
The RAD Debugger is a native, user-mode, multi-process, graphical debugger. It
|
||||||
currently only supports local-machine Windows x64 debugging with PDBs, with
|
currently only supports local-machine Windows x64 debugging with PDBs, with
|
||||||
plans to expand and port in the future. In the future we'll expand to also
|
plans to expand and port in the future. In the future we'll expand to also
|
||||||
support native Linux debugging and DWARF debug info.
|
support native Linux debugging and DWARF debug info.
|
||||||
|
|
||||||
The debugger is currently in *ALPHA*. In order to get the debugger
|
The RAD Debugger is currently in *ALPHA*. In order to get the debugger bullet-
|
||||||
bullet-proof, it'd greatly help out if you submitted the issues you find
|
proof, it'd greatly help out if you submitted the issues you find here, along
|
||||||
[here](https://github.com/EpicGames/raddebugger/issues), along with any
|
with any information you can gather, like dump files (along with the build you
|
||||||
information you can gather, like dump files (along with the build you used),
|
used), instructions to reproduce, test executables, and so on.
|
||||||
instructions to reproduce, test executables, and so on.
|
|
||||||
|
|
||||||
In addition to the debugger, we aim to further improve the toolchain with two
|
You can download pre-built binaries for the debugger
|
||||||
additional related technologies: **(1)** the RAD Debug Info (RDI) format, and
|
[here](https://github.com/EpicGames/raddebugger/releases).
|
||||||
**(2)** the RAD Linker.
|
|
||||||
|
|
||||||
## The RAD Debug Info (RDI) Format
|
The RAD Debugger project aims to simplify the debugger by simplifying and
|
||||||
|
unifying the underlying debug info format. In that pursuit we've built
|
||||||
|
the RADDBG debug info format, which is what the debugger parses and uses. To
|
||||||
|
work with existing toolchains, we convert PDB (and eventually PE/ELF files
|
||||||
|
with embedded DWARF) into the RADDBG format on-demand. This conversion process
|
||||||
|
is currently an unoptimized reference version. Nevertheless it's still quite
|
||||||
|
fast for smaller PDB files (in many cases faster than many other programs
|
||||||
|
simply deserialize the PDBs). It is much slower for much larger projects at the
|
||||||
|
moment, but we expect this will vastly improve overtime.
|
||||||
|
|
||||||
The RAD Debug Info (RDI) format is our custom debug information format, which
|
The RADDBG format is currently specified in code, in the files within the
|
||||||
the debugger parses and uses, rather than the debug information natively
|
`src/raddbg_format` folder. The other relevant folders for working with the
|
||||||
produced by toolchains, like PDB or DWARF. To work with these existing
|
format are:
|
||||||
toolchains, we convert PDB (and eventually PE/ELF files with embedded DWARF)
|
|
||||||
into the RDI format on-demand.
|
|
||||||
|
|
||||||
The RDI format is currently specified in code, in the files within the
|
- `raddbg_cons`: The RADDBG construction layer, for constructing RADDBG files.
|
||||||
`src/lib_rdi` folder. In [`rdi.h`](src/lib_rdi/rdi.h) and
|
- `raddbg_convert`: Our implementation of PDB-to-RADDBG (and an in-progress
|
||||||
[`rdi.c`](src/lib_rdi/rdi.c), the types and functions which define the format
|
implementation of a DWARF-to-RADDBG) conversion.
|
||||||
itself are specified. In [`rdi_parse.h`](src/lib_rdi/rdi_parse.h) and
|
- `raddbg_dump`: Code for textually dumping information from RADDBG files.
|
||||||
[`rdi_parse.c`](src/lib_rdi/rdi_parse.c), helpers for parsing the format are
|
|
||||||
included.
|
|
||||||
|
|
||||||
We also have an in-progress library for constructing and serializing RDI data,
|
## Development Setup Instructions
|
||||||
located within the `src/lib_rdi_make` folder.
|
|
||||||
|
|
||||||
Our `radbin` utility (accessible through the debugger too, via the `--bin`
|
**Note: Currently, only x64 Windows development is supported.**
|
||||||
command line argument) is capable of converting native debug information formats
|
|
||||||
to RDI, and of producing textual dumps of contents stored within RDI files.
|
|
||||||
|
|
||||||
## The RAD Linker
|
### 1. Installing the Required Tools (MSVC & Windows SDK)
|
||||||
|
|
||||||
The RAD Linker is a new performance linker for generating x64 PE/COFF binaries.
|
|
||||||
It is designed to be very fast when creating gigantic executables. It generates
|
|
||||||
standard PDB files for debugging, but it can also (optionally) natively create
|
|
||||||
RAD Debug Info too, which is useful both to eliminate on-demand conversion time
|
|
||||||
when debugging, but also for huge executables that otherwise create broken
|
|
||||||
PDBs that overflow internal 32-bit tables.
|
|
||||||
|
|
||||||
The RAD Linker is primarily optimized to handle huge linking projects. In our
|
|
||||||
test cases (where debug info is multiple gigabytes), we see 50% faster link
|
|
||||||
times.
|
|
||||||
|
|
||||||
The command line syntax is fully compatible with MSVC; you can get a full list
|
|
||||||
of implemented switches from `/help`.
|
|
||||||
|
|
||||||
Our current designed-for use case for the linker is to help with the
|
|
||||||
compile-debug cycle of huge projects. We don't yet have support for
|
|
||||||
link-time-optimizations, but this feature is on the road map.
|
|
||||||
|
|
||||||
By default, the linker spawns as many threads as there are cores, so if you plan
|
|
||||||
to run multiple linkers in parallel, you can limit the number of thread workers
|
|
||||||
via `/rad_workers`.
|
|
||||||
|
|
||||||
We also have support for large memory pages, which, when enabled, reduce link
|
|
||||||
time by another 25%. To link with large pages, you need to explicitly request
|
|
||||||
them via `/rad_large_pages`. Large pages are off by default, since Windows
|
|
||||||
support for large pages is a bit buggy; we recommend they only be used in Docker
|
|
||||||
or VM images where the environment is reset after each link. In a standard
|
|
||||||
Windows environment, using large pages otherwise will fragment memory quickly,
|
|
||||||
forcing a reboot. We are working on a Linux port of the linker that will be able
|
|
||||||
to build with large pages robustly.
|
|
||||||
|
|
||||||
A benchmark of the linker's performance is below:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Project Development Setup Instructions
|
|
||||||
|
|
||||||
**NOTE: Currently, only x64 Windows development is supported for the project.**
|
|
||||||
|
|
||||||
## 1. Installing the Required Tools (MSVC & Windows SDK)
|
|
||||||
|
|
||||||
In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools
|
In order to work with the codebase, you'll need the [Microsoft C/C++ Build Tools
|
||||||
v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both
|
v15 (2017) or later](https://aka.ms/vs/17/release/vs_BuildTools.exe), for both
|
||||||
@@ -96,7 +45,7 @@ the Windows SDK and the MSVC compiler and linker.
|
|||||||
If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++
|
If the Windows SDK is installed (e.g. via installation of the Microsoft C/C++
|
||||||
Build Tools), you may also build with [Clang](https://releases.llvm.org/).
|
Build Tools), you may also build with [Clang](https://releases.llvm.org/).
|
||||||
|
|
||||||
## 2. Build Environment Setup
|
### 2. Build Environment Setup
|
||||||
|
|
||||||
Building the codebase can be done in a terminal which is equipped with the
|
Building the codebase can be done in a terminal which is equipped with the
|
||||||
ability to call either MSVC or Clang from command line.
|
ability to call either MSVC or Clang from command line.
|
||||||
@@ -140,63 +89,45 @@ You should see the following output:
|
|||||||
[msvc compile]
|
[msvc compile]
|
||||||
[default mode, assuming `raddbg` build]
|
[default mode, assuming `raddbg` build]
|
||||||
metagen_main.c
|
metagen_main.c
|
||||||
searching C:\devel\raddebugger/src... 458 files found
|
searching C:\devel\raddebugger/src... 299 files found
|
||||||
parsing metadesk... 16 metadesk files parsed
|
parsing metadesk... 12 metadesk files parsed
|
||||||
gathering tables... 97 tables found
|
gathering tables... 37 tables found
|
||||||
generating layer code...
|
generating layer code...
|
||||||
raddbg_main.c
|
raddbg.cpp
|
||||||
```
|
```
|
||||||
|
|
||||||
If everything worked correctly, there will be a `build` folder in the root
|
If everything worked correctly, there will be a `build` folder in the root
|
||||||
level of the codebase, and it will contain a freshly-built `raddbg.exe`.
|
level of the codebase, and it will contain a freshly-built `raddbg.exe`.
|
||||||
|
|
||||||
This `raddbg.exe` will have been built in **debug mode**, which is not built
|
## Short-To-Medium-Term Roadmap
|
||||||
with optimizations, and may perform worse. To produce a
|
|
||||||
**release mode executable**, run `build.bat` with a `release` argument:
|
|
||||||
|
|
||||||
```
|
|
||||||
build release
|
|
||||||
```
|
|
||||||
|
|
||||||
This build will take significantly longer.
|
|
||||||
|
|
||||||
By default, `build.bat` only builds the debugger if no arguments (or just
|
|
||||||
`release`) are passed, but additional arguments can be passed to build the RAD
|
|
||||||
Linker, or the `radbin` CLI binary file utility:
|
|
||||||
|
|
||||||
```
|
|
||||||
build radlink release
|
|
||||||
build radbin release
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Project Roadmap
|
|
||||||
|
|
||||||
### The Initial Alpha Battle-Testing Phase
|
### The Initial Alpha Battle-Testing Phase
|
||||||
|
|
||||||
The first priority for the project is to ensure that the most crucial components
|
The first priority for the project is to ensure that the most crucial debugger
|
||||||
are functioning extremely reliably for local, x64, Windows development.
|
components are functioning extremely reliably for local, x64, Windows
|
||||||
For the debugger, this would include parts like debug info conversion, debug
|
debugging. This would include parts like debug info conversion, debug info
|
||||||
info loading, process control, stepping, evaluation (correct usage of both
|
loading, process control, stepping, evaluation (correct usage of both location
|
||||||
location info and type info), and a robust frontend which ensures the lower
|
info and type info), and a robust frontend which ensures the lower level parts
|
||||||
level parts are usable. For the linker, this is a matter of reliability and
|
are usable.
|
||||||
convergence with existing linker behavior.
|
|
||||||
|
|
||||||
We feel that we've already come a long way in all of these respects, but given
|
We feel that the debugger has already come a long way in all of these respects,
|
||||||
the massive set of possible combinations of languages, build settings,
|
but given the massive set of possible combinations of languages, build
|
||||||
toolchains, used language features, and patterns of generated code, we still
|
settings, toolchains, used language features, and patterns of generated code,
|
||||||
expect some issues, and are prioritizing these issues being resolved first.
|
there are still cases where the debugger has not been tested, and so there are
|
||||||
|
still issues. So, we feel that the top priority is eliminating these issues,
|
||||||
|
such that the debugging experience is rock solid.
|
||||||
|
|
||||||
We also hope to continue to improve performance in this phase. For the debugger,
|
Additionally, the debug info conversion process is not fast (nor wide) enough
|
||||||
this primarily includes frontend performance, introducing caches when economical
|
to support extremely large projects. This is for two reasons: (a) the
|
||||||
to do so, and tightening existing systems up. For the linker, it has been mostly
|
PDB-to-RADDBG converter is an unoptimized reference implementation, and (b) the
|
||||||
tuned thus far for giant projects, and so we'd like to improve linking speed for
|
debugger learns of new modules (and thus which PDBs to load) in a
|
||||||
small-to-mid sized projects as well.
|
serially-dependent way (this is necessarily the case for correct debugging
|
||||||
|
results). We expect that the conversion process' performance can be massively
|
||||||
For the linker, there are also a number of features to come, like
|
improved, and also that some heuristics can be used to begin converting PDBs
|
||||||
dead-code-elimination (`/opt:ref`), and link-time-optimizations with the help
|
to RADDBGs before the debugger knows those PDBs are needed, thus ensuring the
|
||||||
of `clang` (we won't support LTCG from MSVC, since it is undocumented).
|
associated RADDBG files are ready instantaneously when the associated modules
|
||||||
|
are finally loaded by the debugger. Improving this situation is a major part of
|
||||||
|
this phase, as it will make the debugger much more usable for large projects.
|
||||||
|
|
||||||
### Local x64 Linux Debugging Phase
|
### Local x64 Linux Debugging Phase
|
||||||
|
|
||||||
@@ -212,10 +143,11 @@ The major parts of this phase are:
|
|||||||
|
|
||||||
- Porting the `src/demon` layer to implement the Demon local process control
|
- Porting the `src/demon` layer to implement the Demon local process control
|
||||||
abstraction API.
|
abstraction API.
|
||||||
- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer.
|
- Porting the `src/unwind` layer to support x64 ELF unwinding (currently, there
|
||||||
- Creating a DWARF-to-RDI converter (in the same way that we've built a
|
is only an x64 PE unwinding implementation).
|
||||||
PDB-to-RDI converter). A partial implementation of this is in
|
- Creating a DWARF-to-RADDBG converter (in the same way that we've built a PDB-
|
||||||
`src/rdi_from_dwarf`.
|
to-RADDBG converter). A partial implementation of this is in
|
||||||
|
`src/raddbg_convert/dwarf`.
|
||||||
- Porting the `src/render` layer to implement all of the rendering features the
|
- Porting the `src/render` layer to implement all of the rendering features the
|
||||||
frontend needs on a Linux-compatible API (the backend used on Windows is D3D11).
|
frontend needs on a Linux-compatible API (the backend used on Windows is D3D11).
|
||||||
- Porting the `src/font_provider` layer to a Linux-compatible font
|
- Porting the `src/font_provider` layer to a Linux-compatible font
|
||||||
@@ -237,10 +169,6 @@ like remote debugging, porting to different architectures, further improving
|
|||||||
the debugger's features (like improving the visualization engine), and so on.
|
the debugger's features (like improving the visualization engine), and so on.
|
||||||
But for now, we're mostly focused on those first two phases.
|
But for now, we're mostly focused on those first two phases.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Codebase Introduction
|
|
||||||
|
|
||||||
## Top-Level Directory Descriptions
|
## Top-Level Directory Descriptions
|
||||||
|
|
||||||
- `data`: Small binary files which are used when building, either to embed
|
- `data`: Small binary files which are used when building, either to embed
|
||||||
@@ -251,10 +179,9 @@ After setting up the codebase and building, the following directories will
|
|||||||
also exist:
|
also exist:
|
||||||
|
|
||||||
- `build`: All build artifacts. Not checked in to version control.
|
- `build`: All build artifacts. Not checked in to version control.
|
||||||
- `local`: Local files, used for local build configuration input files. Not
|
- `local`: Local files, used for local build configuration input files.
|
||||||
checked in to version control.
|
|
||||||
|
|
||||||
## Layer Descriptions
|
## Codebase Introduction
|
||||||
|
|
||||||
The codebase is organized into *layers*. Layers are separated either to isolate
|
The codebase is organized into *layers*. Layers are separated either to isolate
|
||||||
certain problems, and to allow inclusion into various builds without needing to
|
certain problems, and to allow inclusion into various builds without needing to
|
||||||
@@ -279,88 +206,56 @@ Layers depend on other layers, but circular dependencies would break the
|
|||||||
separability and isolation utility of layers (in effect, forming one big layer),
|
separability and isolation utility of layers (in effect, forming one big layer),
|
||||||
so in other words, layers are arranged into a directed acyclic graph.
|
so in other words, layers are arranged into a directed acyclic graph.
|
||||||
|
|
||||||
A few layers are built to be used completely independently from the rest of the
|
|
||||||
codebase, as libraries in other codebases and projects. As such, these layers do
|
|
||||||
not depend on any other layers in the codebase. The folders which contain these
|
|
||||||
layers are prefixed with `lib_`, like `lib_rdi`.
|
|
||||||
|
|
||||||
A list of the layers in the codebase and their associated namespaces is below:
|
A list of the layers in the codebase and their associated namespaces is below:
|
||||||
- `artifact_cache` (`AC_`): Implements an asynchronously-filled cache of
|
|
||||||
computation artifacts, which are automatically evicted when not accessed. Used
|
|
||||||
for asynchronously streaming and caching process memory and file system
|
|
||||||
contents, as well as asynchronously preparing visualizer data.
|
|
||||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||||
memory allocators, helper macros, command-line parsing, and so on. Requires
|
memory allocators, helper macros, command-line parsing, and so on. Depends
|
||||||
no other codebase layers.
|
on no other codebase layers.
|
||||||
- `codeview` (`CV_`): Code for parsing and writing the CodeView format.
|
- `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File
|
||||||
- `coff` (`COFF_`): Code for parsing and writing the COFF (Common Object File
|
|
||||||
Format) file format.
|
Format) file format.
|
||||||
- `content` (`C_`): Implements a cache for general data blobs, keyed by a
|
|
||||||
128-bit hash of the data. Also implements a keying system on top, where keys
|
|
||||||
refer to a unique identity which corresponds to a history of 128-bit hashes.
|
|
||||||
Used as a general data store by other layers.
|
|
||||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||||
asynchronous process control, stepping, and breakpoints for all attached
|
asynchronous process control, stepping, and breakpoints for all attached
|
||||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||||
processes are halted. When attached processes are running, it is halted.
|
processes are halted. When attached processes are running, it is halted.
|
||||||
Driven by a debugger frontend on another thread.
|
Driven by a debugger frontend on another thread.
|
||||||
- `dbg_engine` (`D_`): Implements the core debugger system, without any
|
- `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for
|
||||||
graphical components. This contains top-level logic for things like stepping,
|
disassembly for a particular virtual address range in a process, and threads
|
||||||
launching, freezing threads, mid-run breakpoint addition, some caches, and so
|
implemented in this layer decode and cache the disassembly for that range.
|
||||||
on.
|
- `dbgi` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug
|
||||||
- `dbg_info` (`DI_`): Implements asynchronous debug info conversion and loading.
|
info stored in the RADDBG format. Users ask for debug info for a particular
|
||||||
Maintains a cache for loaded debug info. Loads RAD Debug Info (RDI) files.
|
executable, and on separate threads, this layer loads the associated debug
|
||||||
Launches separate processes for on-demand conversion to the RDI format if
|
info file. If necessary, it will launch a separate conversion process to
|
||||||
necessary. Also provides various asynchronous operations for using debug info,
|
convert original debug info into the RADDBG format.
|
||||||
like fuzzy searching across all records in loaded debug info.
|
- `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process
|
||||||
- `demon` (`DMN_`): An abstraction layer for local-machine, low-level process
|
|
||||||
control. The abstraction is used to provide a common interface for process
|
control. The abstraction is used to provide a common interface for process
|
||||||
control on target platforms. Used to implement part of `ctrl`.
|
control on target platforms. Used to implement part of `ctrl`.
|
||||||
- `disasm` (`DASM_`): Implements disassembly generation, including exposing the
|
- `df/core` (`DF_`): The debugger's non-graphical frontend. Implements a
|
||||||
ability to compute and cache disassembly asynchronously.
|
debugger "entity cache" (where "entities" include processes, threads, modules,
|
||||||
- `draw` (`DR_`): Implements a high-level graphics drawing API for the
|
breakpoints, source files, targets, and so on). Implements a command loop
|
||||||
debugger's purposes, using the underlying `render` abstraction layer. Provides
|
for driving process control, which is used to implement stepping commands and
|
||||||
high-level APIs for various draw commands, but takes care of batching them,
|
user breakpoints. Implements extractors and caches for various entity-related
|
||||||
and so on.
|
data, like full thread unwinds and local variable maps. Also implements core
|
||||||
- `dwarf` (`DW_`): Code for parsing the DWARF format.
|
building blocks for evaluation and evaluation visualization.
|
||||||
- `eh` (`EH_`): Code for parsing the EH frame format.
|
- `df/gfx` (`DF_`): The debugger's graphical frontend. Builds on top of
|
||||||
- `elf` (`ELF_`): Code for parsing the ELF format.
|
`df/core` to provide all graphical features, including windows, panels, all
|
||||||
- `eval` (`E_`): A compiler for an expression language, built for evaluation of
|
of the various debugger interfaces, and evaluation visualization.
|
||||||
variables, registers, types, and more, from debugger-attached processes,
|
- `draw` (`D_`): Implements a high-level graphics drawing API for the debugger's
|
||||||
debug info, debugger state, and files. Broken into several phases mostly
|
purposes, using the underlying `render` abstraction layer. Provides high-level
|
||||||
corresponding to traditional compiler phases: lexer, parser, type-checker, IR
|
APIs for various draw commands, but takes care of batching them, and so on.
|
||||||
generation, and IR evaluation.
|
- `eval` (`EVAL_`): Implements a compiler for an expression language built for
|
||||||
- `eval_visualization` (`EV_`): Implements the core non-graphical evaluation
|
evaluation of variables, registers, and so on from debugger-attached processes
|
||||||
visualization engine, which can be used to visualize evaluations (provided by
|
and/or debug info. Broken into several phases mostly corresponding to
|
||||||
the `eval` layer) in a number of ways. Implements core data structures and
|
traditional compiler phases - lexer, parser, type-checker, IR generation, and
|
||||||
transforms for watch tables.
|
IR evaluation.
|
||||||
- `file_stream` (`FS_`): Implements asynchronous file streaming, storing the
|
- `font_cache` (`F_`): Implements a cache of rasterized font data, both in CPU-
|
||||||
artifacts inside of the cache implemented by the `content` and
|
side data for text shaping, and in GPU texture atlases for rasterized glyphs.
|
||||||
`artifact_cache` layers, hot-reloading the contents of files when they change.
|
All cache information is sourced from the `font_provider` abstraction layer.
|
||||||
Allows callers to map file paths to data hashes, which can then be used to
|
|
||||||
obtain the file's data.
|
|
||||||
- `font_cache` (`FNT_`): Implements a cache of rasterized font data, both in
|
|
||||||
CPU-side data for text shaping, and in GPU texture atlases for rasterized
|
|
||||||
glyphs. All cache information is sourced from the `font_provider` abstraction
|
|
||||||
layer.
|
|
||||||
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
||||||
and font rasterization backends.
|
and font rasterization backends.
|
||||||
- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user
|
- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU
|
||||||
programs to work with various features in the debugger. Does not depend on
|
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||||
`base`, and can be independently relocated to other codebases.
|
for asynchronously preparing data for memory visualization in the debugger.
|
||||||
- `lib_rdi` (`RDI_`): Standalone library which defines the core RDI types
|
- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a
|
||||||
and helper functions for reading and writing the RDI debug info file format.
|
128-bit hash of the data. Used as a general data store by other layers.
|
||||||
Does not depend on `base`, and can be independently relocated to other
|
|
||||||
codebases.
|
|
||||||
- `lib_rdi_make` (`RDIM_`): Standalone library for constructing RDI debug info
|
|
||||||
data. Does not depend on `base`, and can be independently relocated
|
|
||||||
to other codebases.
|
|
||||||
- `linker` (`LNK_`): The layer which implements the RAD Linker executable
|
|
||||||
itself.
|
|
||||||
- `mdesk` (`MD_`): Code for parsing Metadesk files (stored as `.mdesk`), which
|
|
||||||
is the JSON-like (technically a JSON superset) text format used for the
|
|
||||||
debugger's user and project configuration files and metacode, which is parsed
|
|
||||||
and used to generate code with the `metagen` layer.
|
|
||||||
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
- `metagen` (`MG_`): A metaprogram which is used to generate primarily code and
|
||||||
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and
|
data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and
|
||||||
generates C code which is then included by hand-written C code. Currently, it
|
generates C code which is then included by hand-written C code. Currently, it
|
||||||
@@ -369,13 +264,14 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
tables, which are then used to produce e.g. C `enum`s and a number of
|
tables, which are then used to produce e.g. C `enum`s and a number of
|
||||||
associated data tables. There are also a number of other generation features,
|
associated data tables. There are also a number of other generation features,
|
||||||
like embedding binary files or complex multi-line strings into source code.
|
like embedding binary files or complex multi-line strings into source code.
|
||||||
- `msf` (`MSF_`): Code for parsing and writing the MSF file format.
|
This layer cannot depend on any other layer in the codebase directly,
|
||||||
- `msvc_crt` (`MSCRT_`): Code for parsing that's specific to the MSVC CRT.
|
including `base`, because it may be used to generate code for those layers. To
|
||||||
|
still use `base` and `os` layer features in the `metagen` program, a separate,
|
||||||
|
duplicate version of `base` and `os` are included in this layer. They are
|
||||||
|
updated manually, as needed. This is to ensure the stability of the
|
||||||
|
metaprogram.
|
||||||
- `mule` (no namespace): Test executables for battle testing debugger
|
- `mule` (no namespace): Test executables for battle testing debugger
|
||||||
functionality.
|
functionality.
|
||||||
- `mutable_text` (`MTX_`): Implements an asynchronously-filled-and-mutated
|
|
||||||
cache for text buffers which are mutated across time. In the debugger, this is
|
|
||||||
used to implement the `Output` log.
|
|
||||||
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
- `natvis` (no namespace): NatVis files for type visualization of the codebase's
|
||||||
types in other debuggers.
|
types in other debuggers.
|
||||||
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
- `os/core` (`OS_`): An abstraction layer providing core, non-graphical
|
||||||
@@ -384,29 +280,23 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
- `os/gfx` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||||
graphical operating system features under an abstract API, which is
|
graphical operating system features under an abstract API, which is
|
||||||
implemented per-target-operating-system.
|
implemented per-target-operating-system.
|
||||||
- `pdb` (`PDB_`): Code for parsing and writing the PDB file format.
|
- `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing
|
||||||
- `pe` (`PE_`): Code for parsing and writing the PE (Portable Executable) file
|
networking operating system features under an abstract API, which is
|
||||||
format.
|
implemented per-target-operating-system.
|
||||||
- `radbin` (`RB_`): The layer implementing the `radbin` binary utility
|
- `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable)
|
||||||
executable.
|
file format.
|
||||||
- `raddbg` (`RD_`): The layer which ties everything together for the main
|
- `raddbg` (no namespace): The layer which ties everything together for the main
|
||||||
graphical debugger executable. Implements the debugger's graphical frontend,
|
graphical debugger. Not much "meat", just drives `df`, implements command line
|
||||||
all of the debugger-specific UI, the debugger executable's command line
|
options, and so on.
|
||||||
interface, and all of the built-in visualizers.
|
- `raddbg_cons` (`CONS_`): Implements an API for constructing files of the
|
||||||
- `rdi` (`RDI_`): A layer which includes the `lib_rdi` layer and bundles it with
|
RADDBG debug info file format.
|
||||||
codebase-specific helpers, to easily include the library in codebase programs,
|
- `raddbg_dump` (`DUMP_`): A dumper utility program for dumping textualizations
|
||||||
and have it be integrated with codebase constructs.
|
of RADDBG debug info files.
|
||||||
- `rdi_from_coff` (`C2R_`): Code for converting information in COFF files to the
|
- `raddbg_format` (`RADDBG_`): Standalone types and helper functions for the
|
||||||
equivalent RDI data.
|
RADDBG debug info file format. Does not depend on `base`.
|
||||||
- `rdi_from_dwarf` (`D2R_`): In-progress code for converting DWARF to the
|
- `raddbg_markup` (`RADDBG_`): Standalone header file for marking up user
|
||||||
equivalent RDI data.
|
programs to work with various features in the `raddbg` debugger. Does not
|
||||||
- `rdi_from_elf` (`E2R_`)): Code for converting ELF data to the equivalent RDI
|
depend on `base`.
|
||||||
data.
|
|
||||||
- `rdi_from_pdb` (`P2R_`): Code for converting PDB data to the equivalent RDI
|
|
||||||
data.
|
|
||||||
- `rdi_make` (`RDIM_`): A layer which includes the `lib_rdi_make` layer and
|
|
||||||
bundles it with codebase-specific helpers, to easily include the library in
|
|
||||||
codebase programs, and have it be integrated with codebase constructs.
|
|
||||||
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
|
- `regs` (`REGS_`): Types, helper functions, and metadata for registers on
|
||||||
supported architectures. Used in reading/writing registers in `demon`, or in
|
supported architectures. Used in reading/writing registers in `demon`, or in
|
||||||
looking up register metadata.
|
looking up register metadata.
|
||||||
@@ -415,14 +305,21 @@ A list of the layers in the codebase and their associated namespaces is below:
|
|||||||
level drawing API - this layer is strictly for minimally abstracting on an
|
level drawing API - this layer is strictly for minimally abstracting on an
|
||||||
as-needed basis. Higher level drawing features are implemented in the `draw`
|
as-needed basis. Higher level drawing features are implemented in the `draw`
|
||||||
layer.
|
layer.
|
||||||
- `scratch` (no namespace): Scratch space for small and transient test programs.
|
- `scratch` (no namespace): Scratch space for small and transient test or sample
|
||||||
- `tester` (no namespace): A program used for automated testing.
|
programs.
|
||||||
- `text` (`TXT_`): Implements text processing functions, like parsing line
|
- `texture_cache` (`TEX_`): Implements an asynchronously-filled cache for GPU
|
||||||
breaks, and lexing and parsing source code. Also offers an API to do this
|
texture data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||||
asynchronously.
|
for asynchronously preparing data for memory visualization in the debugger.
|
||||||
- `third_party` (no namespace): External code from other projects, which some
|
- `txti` (`TXTI_`): Machinery for asynchronously-loaded, asynchronously hot-
|
||||||
layers in the codebase depend on. All external code is included and built
|
reloaded, asynchronously parsed, and asynchronously mutated source code files.
|
||||||
directly within the codebase.
|
Used by the debugger to visualize source code files. Users ask for text lines,
|
||||||
|
tokens, and metadata, and it is prepared on background threads.
|
||||||
|
- `type_graph` (`TG_`): Code for analyzing and navigating type structures from
|
||||||
|
RADDBG debug info files, with the additional capability of constructing
|
||||||
|
synthetic types *not* found in debug info. Used in `eval` and for various
|
||||||
|
visualization features.
|
||||||
- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a
|
- `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a
|
||||||
core immediate mode hierarchical user interface data structure building
|
core immediate mode hierarchical user interface data structure building
|
||||||
API, and has helper layers for building some higher-level widgets.
|
API, and has helper layers for building some higher-level widgets.
|
||||||
|
- `unwind` (`UNW_`): Code for generating unwind information from threads, for
|
||||||
|
supported operating systems and architectures.
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
@echo off
|
@echo off
|
||||||
setlocal enabledelayedexpansion
|
setlocal
|
||||||
cd /D "%~dp0"
|
cd /D "%~dp0"
|
||||||
:restart
|
|
||||||
|
|
||||||
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
||||||
::
|
::
|
||||||
:: This is a central build script for the RAD Debugger project, for use in
|
:: This is a central build script for the RAD Debugger project. It takes a list
|
||||||
:: Windows development environments. It takes a list of simple alphanumeric-
|
:: of simple alphanumeric-only arguments which control (a) what is built, (b)
|
||||||
:: only arguments which control (a) what is built, (b) which compiler & linker
|
:: which compiler & linker are used, and (c) extra high-level build options. By
|
||||||
:: are used, and (c) extra high-level build options. By default, if no options
|
:: default, if no options are passed, then the main "raddbg" graphical debugger
|
||||||
:: are passed, then the main "raddbg" graphical debugger is built.
|
:: is built.
|
||||||
::
|
::
|
||||||
:: Below is a non-exhaustive list of possible ways to use the script:
|
:: Below is a non-exhaustive list of possible ways to use the script:
|
||||||
:: `build raddbg`
|
:: `build raddbg`
|
||||||
:: `build raddbg clang`
|
:: `build raddbg clang`
|
||||||
:: `build raddbg release`
|
:: `build raddbg release`
|
||||||
:: `build raddbg asan telemetry`
|
:: `build raddbg asan telemetry`
|
||||||
:: `build rdi_from_pdb`
|
:: `build raddbg_from_pdb`
|
||||||
::
|
::
|
||||||
:: For a full list of possible build targets and their build command lines,
|
:: For a full list of possible build targets and their build command lines,
|
||||||
:: search for @build_targets in this file.
|
:: search for @build_targets in this file.
|
||||||
@@ -24,91 +23,55 @@ cd /D "%~dp0"
|
|||||||
:: Below is a list of all possible non-target command line options:
|
:: Below is a list of all possible non-target command line options:
|
||||||
::
|
::
|
||||||
:: - `asan`: enable address sanitizer
|
:: - `asan`: enable address sanitizer
|
||||||
:: - `ubsan`: enable undefined-behavior sanitizer
|
|
||||||
:: - `telemetry`: enable RAD telemetry profiling support
|
:: - `telemetry`: enable RAD telemetry profiling support
|
||||||
:: - `spall`: enable spall profiling support
|
|
||||||
|
|
||||||
:: --- Unpack Arguments -------------------------------------------------------
|
:: --- Unpack Arguments -------------------------------------------------------
|
||||||
for %%a in (%*) do set "%%~a=1"
|
for %%a in (%*) do set "%%a=1"
|
||||||
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
|
if not "%msvc%"=="1" if not "%clang%"=="1" set msvc=1
|
||||||
if not "%release%"=="1" set debug=1
|
if not "%release%"=="1" set debug=1
|
||||||
if "%debug%"=="1" set release=0 && echo [debug mode]
|
if "%debug%"=="1" set release=0 && echo [debug mode]
|
||||||
if "%release%"=="1" set debug=0 && echo [release mode]
|
if "%release%"=="1" set debug=0 && echo [release mode]
|
||||||
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
if "%msvc%"=="1" set clang=0 && echo [msvc compile]
|
||||||
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
if "%clang%"=="1" set msvc=0 && echo [clang compile]
|
||||||
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1
|
if "%~1"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1
|
||||||
if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && set raddbg=1&& set com_shim=1&& set raddbg_com_shim=1
|
|
||||||
|
|
||||||
:: --- Unpack Command Line Build Arguments ------------------------------------
|
:: --- Unpack Command Line Build Arguments ------------------------------------
|
||||||
set auto_compile_flags=
|
set auto_compile_flags=
|
||||||
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
||||||
if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled]
|
|
||||||
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||||
if "%ubsan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=undefined && echo [ubsan enabled]
|
|
||||||
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
|
|
||||||
if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info]
|
|
||||||
if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview
|
|
||||||
if "%pgo%"=="1" (
|
|
||||||
where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1
|
|
||||||
if "%clang%"=="1" (
|
|
||||||
if "%pgo_run%" == "1" (
|
|
||||||
call llvm-profdata merge %LLVM_PROFILE_FILE% -output=%~dp0build\build.profdata || exit /b 1
|
|
||||||
set auto_compile_flags=%auto_compile_flags% -fprofile-use=%~dp0build\build.profdata
|
|
||||||
set pgo_run=0
|
|
||||||
) else (
|
|
||||||
echo [pgo enabled]
|
|
||||||
set auto_compile_flags=%auto_compile_flags% -fprofile-generate -mllvm -vp-counters-per-site=5
|
|
||||||
set LLVM_PROFILE_FILE=%~dp0build\build.profraw
|
|
||||||
set pgo_run=1
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
echo ERROR: PGO build is not supported with current compiler
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
:: --- Compile/Link Line Definitions ------------------------------------------
|
:: --- Compile/Link Line Definitions ------------------------------------------
|
||||||
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /Zc:preprocessor
|
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7
|
||||||
set cl_debug= call cl /Od /Ob1 /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags%
|
set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf
|
||||||
set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
set cl_debug= call cl /Od %cl_common% %auto_compile_flags%
|
||||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf
|
set cl_release= call cl /O2 /DNDEBUG %cl_common% %auto_compile_flags%
|
||||||
|
set clang_debug= call clang -g -O0 %clang_common% %auto_compile_flags%
|
||||||
|
set clang_release= call clang -g -O2 -DNDEBUG %clang_common% %auto_compile_flags%
|
||||||
|
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" logo.res
|
||||||
|
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res
|
||||||
set cl_out= /out:
|
set cl_out= /out:
|
||||||
set cl_obj_out= /Fo:
|
|
||||||
set cl_linker=
|
|
||||||
set clang_common= -mcx16 -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000
|
|
||||||
set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 -D_DEBUG %clang_common% %auto_compile_flags%
|
|
||||||
set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 -DNDEBUG %clang_common% %auto_compile_flags%
|
|
||||||
set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:noicf
|
|
||||||
set clang_out= -o
|
set clang_out= -o
|
||||||
set clang_obj_out= -o
|
|
||||||
set clang_linker= -Xlinker
|
|
||||||
|
|
||||||
:: --- Per-Build Settings -----------------------------------------------------
|
:: --- Per-Build Settings -----------------------------------------------------
|
||||||
set link_icon=logo.res
|
set gfx=-DOS_FEATURE_GRAPHICAL=1
|
||||||
if "%msvc%"=="1" set linker=%cl_linker%
|
set net=-DOS_FEATURE_SOCKET=1
|
||||||
if "%clang%"=="1" set linker=%clang_linker%
|
set link_dll=-DLL
|
||||||
if "%msvc%"=="1" set only_compile=/c
|
if "%msvc%"=="1" set only_compile=/c
|
||||||
if "%clang%"=="1" set only_compile=-c
|
if "%clang%"=="1" set only_compile=-c
|
||||||
if "%msvc%"=="1" set EHsc=/EHsc
|
if "%msvc%"=="1" set EHsc=/EHsc
|
||||||
if "%clang%"=="1" set EHsc=
|
if "%clang%"=="1" set EHsc=
|
||||||
if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO
|
if "%msvc%"=="1" set rc=rc.exe
|
||||||
if "%clang%"=="1" set no_aslr=-Wl,/DYNAMICBASE:NO
|
if "%clang%"=="1" set rc=llvm-rc.exe
|
||||||
if "%msvc%"=="1" set rc=call rc
|
|
||||||
if "%clang%"=="1" set rc=call llvm-rc
|
|
||||||
if "%msvc%"=="1" set link_dll=/link /DLL
|
|
||||||
if "%clang%"=="1" set link_dll=-Xlinker -DLL
|
|
||||||
|
|
||||||
:: --- Choose Compile/Link Lines ----------------------------------------------
|
:: --- Choose Compile/Link Lines ----------------------------------------------
|
||||||
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
if "%msvc%"=="1" set compile_debug=%cl_debug%
|
||||||
if "%msvc%"=="1" set compile_release=%cl_release%
|
if "%msvc%"=="1" set compile_release=%cl_release%
|
||||||
if "%msvc%"=="1" set compile_link=%cl_link%
|
if "%msvc%"=="1" set compile_link=%cl_link%
|
||||||
if "%msvc%"=="1" set out=%cl_out%
|
if "%msvc%"=="1" set out=%cl_out%
|
||||||
if "%msvc%"=="1" set obj_out=%cl_obj_out%
|
|
||||||
if "%clang%"=="1" set compile_debug=%clang_debug%
|
if "%clang%"=="1" set compile_debug=%clang_debug%
|
||||||
if "%clang%"=="1" set compile_release=%clang_release%
|
if "%clang%"=="1" set compile_release=%clang_release%
|
||||||
if "%clang%"=="1" set compile_link=%clang_link%
|
if "%clang%"=="1" set compile_link=%clang_link%
|
||||||
if "%clang%"=="1" set out=%clang_out%
|
if "%clang%"=="1" set out=%clang_out%
|
||||||
if "%clang%"=="1" set obj_out=%clang_obj_out%
|
|
||||||
if "%debug%"=="1" set compile=%compile_debug%
|
if "%debug%"=="1" set compile=%compile_debug%
|
||||||
if "%release%"=="1" set compile=%compile_release%
|
if "%release%"=="1" set compile=%compile_release%
|
||||||
|
|
||||||
@@ -122,68 +85,36 @@ pushd build
|
|||||||
popd
|
popd
|
||||||
|
|
||||||
:: --- Get Current Git Commit Id ----------------------------------------------
|
:: --- Get Current Git Commit Id ----------------------------------------------
|
||||||
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\"
|
for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DRADDBG_GIT=\"%%i\"
|
||||||
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
|
|
||||||
|
|
||||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||||
pushd build
|
if "%no_meta%"=="1" echo [skipping metagen]
|
||||||
if "%meta%"=="1" (
|
if not "%no_meta%"=="1" (
|
||||||
echo [building metagen]
|
pushd build
|
||||||
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
|
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
|
||||||
)
|
|
||||||
if "%no_meta%"=="" if exist metagen.exe (
|
|
||||||
echo [running metagen]
|
|
||||||
metagen.exe || exit /b 1
|
metagen.exe || exit /b 1
|
||||||
|
popd
|
||||||
)
|
)
|
||||||
popd
|
|
||||||
|
|
||||||
:: --- Build Everything (@build_targets) --------------------------------------
|
:: --- Build Everything (@build_targets) --------------------------------------
|
||||||
pushd build
|
pushd build
|
||||||
if "%raddbg%"=="1" set didbuild=1 && %compile% ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg.exe || exit /b 1
|
if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1
|
||||||
if "%raddbg_non_graphical%"=="1" set didbuild=1 && %compile% -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB ..\src\raddbg\raddbg_main.c %compile_link% %link_icon% %out%raddbg_non_graphical.exe || exit /b 1
|
if "%raddbg_from_pdb%"=="1" %compile% ..\src\raddbg_convert\pdb\raddbg_from_pdb_main.c %compile_link% %out%raddbg_from_pdb.exe || exit /b 1
|
||||||
if "%com_shim%"=="1" set didbuild=1 && %compile% ..\src\com_shim\com_shim_main.c %compile_link% %out%com_shim.exe || exit /b 1
|
if "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.exe || exit /b 1
|
||||||
if "%radlink%"=="1" set didbuild=1 && %compile% ..\src\linker\lnk.c %compile_link% %linker% /NOIMPLIB %linker% /NATVIS:"%~dp0\src\linker\linker.natvis" %out%radlink.exe || exit /b 1
|
if "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.exe || exit /b 1
|
||||||
if "%radbin%"=="1" set didbuild=1 && %compile% ..\src\radbin\radbin_main.c %compile_link% %out%radbin.exe || exit /b 1
|
if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
|
||||||
if "%raddump%"=="1" set didbuild=1 && %compile% ..\src\raddump\raddump_main.c %compile_link% %out%raddump.exe || exit /b 1
|
if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1
|
||||||
if "%ryan_scratch%"=="1" set didbuild=1 && %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1
|
if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1
|
||||||
if "%textperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\textperf.c %compile_link% %out%textperf.exe || exit /b 1
|
if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %out%mule_main.exe || exit /b 1
|
||||||
if "%convertperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\convertperf.c %compile_link% %out%convertperf.exe || exit /b 1
|
if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1
|
||||||
if "%debugstringperf%"=="1" set didbuild=1 && %compile% ..\src\scratch\debugstringperf.c %compile_link% %out%debugstringperf.exe || exit /b 1
|
if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
|
||||||
if "%parse_inline_sites%"=="1" set didbuild=1 && %compile% ..\src\scratch\parse_inline_sites.c %compile_link% %out%parse_inline_sites.exe || exit /b 1
|
|
||||||
if "%strip_lib_debug%"=="1" set didbuild=1 && %compile% ..\src\strip_lib_debug\strip_lib_debug.c %compile_link% %out%strip_lib_debug.exe || exit /b 1
|
|
||||||
if "%mule_main%"=="1" set didbuild=1 && del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp %obj_out%mule_inline.obj && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp %obj_out%mule_o2.obj && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1
|
|
||||||
if "%mule_module%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_module.cpp %link_dll% %out%mule_module.dll || exit /b 1
|
|
||||||
if "%mule_hotload%"=="1" set didbuild=1 && %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1
|
|
||||||
if "%torture%"=="1" set didbuild=1 && %compile% ..\src\torture\torture_main.c %compile_link% %out%torture.exe || exit /b1
|
|
||||||
if "%dwarf_expr_test%"=="1" set didbuild=1 && %compile% ..\src\torture\dwarf_expr_test.c %compile_link% %out%dwarf_expr_test.exe || exit /b1
|
|
||||||
if "%unit_sizes_from_pdb%"=="1" set didbuild=1 && %compile% ..\src\scratch\unit_sizes_from_pdb.c %compile_link% %out%unit_sizes_from_pdb.exe || exit /b1
|
|
||||||
if "%mule_peb_trample%"=="1" (
|
|
||||||
set didbuild=1
|
|
||||||
if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe
|
|
||||||
if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb
|
|
||||||
if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi
|
|
||||||
%compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1
|
|
||||||
move mule_peb_trample_new.exe mule_peb_trample.exe
|
|
||||||
)
|
|
||||||
popd
|
popd
|
||||||
|
|
||||||
:: --- Set Up Debugger Com Shim -----------------------------------------------
|
:: --- Unset ------------------------------------------------------------------
|
||||||
pushd build
|
for %%a in (%*) do set "%%a=0"
|
||||||
if "%raddbg_com_shim%"=="1" copy /y com_shim.exe raddbg.com
|
set raddbg=
|
||||||
popd
|
set compile=
|
||||||
|
set compile_link=
|
||||||
:: --- Warn On No Builds ------------------------------------------------------
|
set out=
|
||||||
if "%didbuild%"=="" (
|
set msvc=
|
||||||
echo [WARNING] no valid build target specified; must use build target names as arguments to this script, like `build raddbg` or `build rdi_from_pdb`.
|
set debug=
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
:: --- PGO Run ----------------------------------------------------------------
|
|
||||||
if "%pgo_run%"=="1" (
|
|
||||||
if "%radlink%"=="1" (
|
|
||||||
pushd local\lyra_pgo
|
|
||||||
call %~dp0build\radlink @lyra.rsp || exit /b 1
|
|
||||||
popd
|
|
||||||
)
|
|
||||||
goto restart
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
# --- Unpack Arguments --------------------------------------------------------
|
|
||||||
for arg in "$@"; do declare $arg='1'; done
|
|
||||||
if [[ "$#" == "0" ]]; then raddbg='1'; fi
|
|
||||||
|
|
||||||
cc_sanitize=""
|
|
||||||
if [[ "${asan:-0}" == "1" ]]; then
|
|
||||||
echo "[asan enabled]"
|
|
||||||
cc_sanitize="-fsanitize=address"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Get Current Git Commit Id -----------------------------------------------
|
|
||||||
git_hash=$(git describe --always --dirty)
|
|
||||||
git_hash_full=$(git rev-parse HEAD)
|
|
||||||
|
|
||||||
# --- Compile/Link Line Definitions -------------------------------------------
|
|
||||||
cc_cflags_gcc=""
|
|
||||||
cc_cflags_clang=${cc_sanitize}" -fdiagnostics-absolute-paths -Wno-for-loop-analysis -Wno-incompatible-pointer-types-discards-qualifiers -Wno-initializer-overrides -Wno-compare-distinct-pointer-types -Wno-single-bit-bitfield-constant-conversion -Wno-deprecated-declarations -Wno-writable-strings -Wno-unknown-warning-option -Wno-deprecated-register -Wno-unused-local-typedef -msse2"
|
|
||||||
cc_common="-mcx16 -I../src/ -I../local/ -D_GNU_SOURCE -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wall -Wno-missing-braces -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-value -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
|
|
||||||
cc_debug="-g -O0 -DBUILD_DEBUG=1 ${cc_common}"
|
|
||||||
cc_release="-g -O2 -DBUILD_DEBUG=0 ${cc_common}"
|
|
||||||
cc_link="-lpthread -lm -lrt -ldl"
|
|
||||||
|
|
||||||
# --- Per-Build Settings ------------------------------------------------------
|
|
||||||
cc_link_dll="-fPIC"
|
|
||||||
|
|
||||||
# --- External Libraries ------------------------------------------------------
|
|
||||||
# sudo apt install -y pkg-config libfreetype6-dev libx11-dev libxext-dev libgl-dev libegl-dev
|
|
||||||
if [[ -x "$(command -v pkg-config)" ]]; then
|
|
||||||
cc_font_provider="$(pkg-config --cflags --libs freetype2)"
|
|
||||||
cc_os_gfx="$(pkg-config --cflags --libs x11 xext)"
|
|
||||||
cc_render="$(pkg-config --cflags --libs gl egl)"
|
|
||||||
else
|
|
||||||
cc_font_provider="-I/usr/include/freetype2 -lfreetype"
|
|
||||||
cc_os_gfx="-lX11 -lXext"
|
|
||||||
cc_render="-lGL -lEGL"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Choose Compile/Link Lines -----------------------------------------------
|
|
||||||
if [[ "${gcc:-0}" == "1" ]]; then compiler="${CC:-gcc} $cc_cflags_gcc"; echo "[gcc compile]";
|
|
||||||
elif [[ "${clang:-1}" == "1" ]]; then compiler="${CC:-clang} $cc_cflags_clang"; echo "[clang compile]";
|
|
||||||
fi
|
|
||||||
if [[ "${release:-0}" == "1" ]]; then echo "[release mode]"; compile="$compiler $cc_release";
|
|
||||||
elif [[ "${debug:-1}" == "1" ]]; then echo "[debug mode]"; compile="$compiler $cc_debug";
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Prep Directories --------------------------------------------------------
|
|
||||||
mkdir -p build local
|
|
||||||
|
|
||||||
# --- Build & Run Metaprogram -------------------------------------------------
|
|
||||||
if [[ "${no_meta:-0}" == "0" ]]
|
|
||||||
then
|
|
||||||
echo "[building metagen]"
|
|
||||||
cd build
|
|
||||||
$compiler $cc_debug ../src/metagen/metagen_main.c $cc_link -o metagen
|
|
||||||
./metagen
|
|
||||||
cd ..
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Build Everything (@build_targets) ---------------------------------------
|
|
||||||
cd build
|
|
||||||
if [[ "${raddbg:-0}" == "1" ]]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $cc_link $cc_os_gfx $cc_render $cc_font_provider -o raddbg; fi
|
|
||||||
if [[ "${raddbg_non_graphical:-0}" == "1" ]]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c -DWM_STUB=1 -DR_BACKEND=R_BACKEND_STUB $cc_link $cc_os_gfx $cc_render $cc_font_provider -o raddbg_non_graphical; fi
|
|
||||||
if [[ "${radbin:-0}" == "1" ]]; then didbuild=1 && $compile ../src/radbin/radbin_main.c $cc_link -o radbin; fi
|
|
||||||
if [[ "${radlink:-0}" == "1" ]]; then didbuild=1 && $compile ../src/linker/lnk.c $cc_link -o radlink; fi
|
|
||||||
if [[ "${torture:-0}" == "1" ]]; then didbuild=1 && $compile ../src/torture/torture_main.c $cc_link $cc_os_gfx $cc_render $cc_font_provider -o torture; fi
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
# --- Warn On No Builds -------------------------------------------------------
|
|
||||||
if [[ "${didbuild:-0}" == "0" ]]
|
|
||||||
then
|
|
||||||
echo "[WARNING] no valid build target specified; must use build target names as arguments to this script, like \`./build.sh raddbg\` or \`./build.sh radlink\`."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,93 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.2.1",
|
|
||||||
"defaults": {},
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "cppdbg",
|
|
||||||
"name": "launch - torture",
|
|
||||||
"request": "launch",
|
|
||||||
"project": "c://windows//system32//cmd.exe",
|
|
||||||
"cwd": "build/",
|
|
||||||
"program": "torture",
|
|
||||||
"args": [ "d2r_checksums" ],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"pipeTransport": {
|
|
||||||
"pipeCwd": "${workspaceRoot}",
|
|
||||||
"pipeProgram": "wsl",
|
|
||||||
"pipeArgs": [ "${debuggerCommand}" ]
|
|
||||||
},
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "-gdb-set follow-fork-mode parent" },
|
|
||||||
{ "text": "-gdb-set detach-on-fork on" },
|
|
||||||
{ "text": "handle SIGUSR1 nostop" }
|
|
||||||
],
|
|
||||||
"MIMode": "gdb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "cppdbg",
|
|
||||||
"name": "launch - radbin",
|
|
||||||
"request": "launch",
|
|
||||||
"project": "c://windows//system32//cmd.exe",
|
|
||||||
"cwd": "build/",
|
|
||||||
"program": "radbin",
|
|
||||||
"args": [ "-voff2line", "-voff:0x1000", "torture_artifacts/d2r_line_table/a.rdi" ],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"pipeTransport": {
|
|
||||||
"pipeCwd": "${workspaceRoot}",
|
|
||||||
"pipeProgram": "wsl",
|
|
||||||
"pipeArgs": [ "${debuggerCommand}" ]
|
|
||||||
},
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "-gdb-set follow-fork-mode parent" },
|
|
||||||
{ "text": "-gdb-set detach-on-fork on" },
|
|
||||||
{ "text": "handle SIGUSR1 nostop" }
|
|
||||||
],
|
|
||||||
"MIMode": "gdb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "cppdbg",
|
|
||||||
"name": "launch - radlink",
|
|
||||||
"request": "launch",
|
|
||||||
"project": "c://windows//system32//cmd.exe",
|
|
||||||
"cwd": "/mnt/c/devel/raddebugger/build/torture_artifacts/debug_p_sig_mismatch",
|
|
||||||
"program": "/mnt/c/devel/raddebugger/build/radlink",
|
|
||||||
"args": [ "/subsystem:console", "/entry:entry", "/out:a.exe", "/debug:full", "a.obj", "b.obj", "entry.obj" ],
|
|
||||||
"stopAtEntry": false,
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"pipeTransport": {
|
|
||||||
"pipeCwd": "${workspaceRoot}",
|
|
||||||
"pipeProgram": "wsl",
|
|
||||||
"pipeArgs": [ "${debuggerCommand}" ]
|
|
||||||
},
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "handle SIGUSR1 nostop" }
|
|
||||||
],
|
|
||||||
"MIMode": "gdb"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "cppdbg",
|
|
||||||
"name": "launch - raddbg",
|
|
||||||
"request": "launch",
|
|
||||||
"project": "c://windows//system32//cmd.exe",
|
|
||||||
"cwd": "build/",
|
|
||||||
"program": "/mnt/c/devel/raddebugger/build/raddbg",
|
|
||||||
//"processId": "65821",
|
|
||||||
"environment": [],
|
|
||||||
"externalConsole": false,
|
|
||||||
"pipeTransport": {
|
|
||||||
"pipeCwd": "${workspaceRoot}",
|
|
||||||
"pipeProgram": "wsl",
|
|
||||||
"pipeArgs": [ "${debuggerCommand}" ]
|
|
||||||
},
|
|
||||||
"setupCommands": [
|
|
||||||
{ "text": "handle SIGUSR1 nostop" }
|
|
||||||
],
|
|
||||||
"MIMode": "gdb"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,73 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_DUMP_H
|
|
||||||
#define DWARF_DUMP_H
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_DumperCacheFlag_InfoRanges = (1 << 0),
|
|
||||||
DW_DumperCacheFlag_CuArr = (1 << 1),
|
|
||||||
DW_DumperCacheFlag_LineVmMap = (1 << 2),
|
|
||||||
DW_DumperCacheFlag_TagTrees = (1 << 3),
|
|
||||||
} DW_DumperCacheFlags;
|
|
||||||
|
|
||||||
typedef struct DW_Dumper
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
Arch arch;
|
|
||||||
B32 is_relaxed;
|
|
||||||
B32 is_verbose;
|
|
||||||
DW_Raw *input;
|
|
||||||
DW_DumperCacheFlags cache_flags;
|
|
||||||
struct {
|
|
||||||
Rng1U64Array info_ranges;
|
|
||||||
DW_CompUnit *cu_arr;
|
|
||||||
HashTable *line_vm_map;
|
|
||||||
DW_TagTree *tag_trees;
|
|
||||||
} cache;
|
|
||||||
} DW_Dumper;
|
|
||||||
|
|
||||||
#define DW_PRINTER(name) void name(Arena *arena, String8List *strings, int indent, DW_Dumper *dumper)
|
|
||||||
typedef DW_PRINTER(DW_Printer);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
// cache
|
|
||||||
internal Rng1U64Array dw_get_info_ranges(DW_Dumper *dumper);
|
|
||||||
internal DW_CompUnit * dw_get_cu_arr(DW_Dumper *dumper);
|
|
||||||
internal HashTable * dw_get_line_vm_map(DW_Dumper *dumper);
|
|
||||||
internal DW_TagTree * dw_get_tag_trees(DW_Dumper *dumper);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Stringification Helpers
|
|
||||||
|
|
||||||
internal String8List dw_string_list_from_cfi_program(Arena *arena, U64 cu_base, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format, U64 pc_begin, DW_CIE *cie, DW_DecodePtr *decode_ptr_func, void *deocde_ptr_ud, String8 program);
|
|
||||||
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
|
||||||
|
|
||||||
internal String8 dw_string_from_reg_off (Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off);
|
|
||||||
internal String8 dw_string_from_attrib_value(Arena *arena, DW_Raw *input, Arch arch, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
|
|
||||||
internal String8 dw_string_from_expression (Arena *arena, String8 expr, U64 cu_base, U64 addr_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
|
||||||
internal String8 dw_string_from_cfa (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFA cfa);
|
|
||||||
internal String8 dw_string_from_cfi_row (Arena *arena, Arch arch, U64 address_size, DW_Version version, DW_Ext ext, DW_Format format, DW_CFI_Row *row);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx);
|
|
||||||
internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
|
|
||||||
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
|
|
||||||
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_addr (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_loclists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges, Arch arch);
|
|
||||||
internal void dw_print_debug_rnglists (Arena *arena, String8List *out, String8 indent, DW_Raw *input, Rng1U64Array segment_vranges);
|
|
||||||
internal void dw_print_debug_pubnames (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_pubtypes (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_line_str (Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
internal void dw_print_debug_str_offsets(Arena *arena, String8List *out, String8 indent, DW_Raw *input);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Dump Entry Point
|
|
||||||
|
|
||||||
internal String8List dw_dump_list_from_sections(Arena *arena, DW_Raw *input, Arch arch, DW_SectionFlags dump_sections, B32 is_verbose);
|
|
||||||
|
|
||||||
#endif // DWARF_DUMP_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,233 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_EXPR_H
|
|
||||||
#define DWARF_EXPR_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// evaluator
|
|
||||||
|
|
||||||
#define DW_ExprValueType_IsSigned(x) ((x) == DW_ExprValueType_S8 || (x) == DW_ExprValueType_S16 || (x) == DW_ExprValueType_S32 || (x) == DW_ExprValueType_S64 || (x) == DW_ExprValueType_S128 || (x) == DW_ExprValueType_S256 || (x) == DW_ExprValueType_S512)
|
|
||||||
#define DW_ExprValueType_IsUnsigned(x) ((x) == DW_ExprValueType_U8 || (x) == DW_ExprValueType_U16 || (x) == DW_ExprValueType_U32 || (x) == DW_ExprValueType_U64 || (x) == DW_ExprValueType_U128 || (x) == DW_ExprValueType_U256 || (x) == DW_ExprValueType_U512)
|
|
||||||
#define DW_ExprValueType_IsFloat(x) ((x) == DW_ExprValueType_F32 || (x) == DW_ExprValueType_F64)
|
|
||||||
#define DW_ExprValueType_IsInt(x) (DW_ExprValueType_IsSigned(x) || DW_ExprValueType_IsUnsigned(x) || (x) == DW_ExprValueType_Addr)
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_ExprValueType_Generic,
|
|
||||||
DW_ExprValueType_U8,
|
|
||||||
DW_ExprValueType_U16,
|
|
||||||
DW_ExprValueType_U32,
|
|
||||||
DW_ExprValueType_U64,
|
|
||||||
DW_ExprValueType_U128,
|
|
||||||
DW_ExprValueType_U256,
|
|
||||||
DW_ExprValueType_U512,
|
|
||||||
DW_ExprValueType_S8,
|
|
||||||
DW_ExprValueType_S16,
|
|
||||||
DW_ExprValueType_S32,
|
|
||||||
DW_ExprValueType_S64,
|
|
||||||
DW_ExprValueType_S128,
|
|
||||||
DW_ExprValueType_S256,
|
|
||||||
DW_ExprValueType_S512,
|
|
||||||
DW_ExprValueType_F32,
|
|
||||||
DW_ExprValueType_F64,
|
|
||||||
DW_ExprValueType_Addr,
|
|
||||||
DW_ExprValueType_Implicit,
|
|
||||||
DW_ExprValueType_Bool,
|
|
||||||
} DW_ExprValueType;
|
|
||||||
|
|
||||||
typedef S8 DW_ExprBool;
|
|
||||||
|
|
||||||
typedef struct DW_ExprValue
|
|
||||||
{
|
|
||||||
DW_ExprValueType type;
|
|
||||||
Rng1U64Array ranges;
|
|
||||||
U64 *offsets;
|
|
||||||
union {
|
|
||||||
U8 u8;
|
|
||||||
U16 u16;
|
|
||||||
U32 u32;
|
|
||||||
U64 u64;
|
|
||||||
U128 u128;
|
|
||||||
U256 u256;
|
|
||||||
U512 u512;
|
|
||||||
S8 s8;
|
|
||||||
S16 s16;
|
|
||||||
S32 s32;
|
|
||||||
S64 s64;
|
|
||||||
F32 f32;
|
|
||||||
F64 f64;
|
|
||||||
U64 addr;
|
|
||||||
DW_ExprBool boolean;
|
|
||||||
String8 implicit;
|
|
||||||
String8 generic;
|
|
||||||
};
|
|
||||||
} DW_ExprValue;
|
|
||||||
|
|
||||||
typedef struct DW_ExprValueNode
|
|
||||||
{
|
|
||||||
DW_ExprValue v;
|
|
||||||
struct DW_ExprValueNode *next;
|
|
||||||
} DW_ExprValueNode;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_PieceKind_Null,
|
|
||||||
DW_PieceKind_Value,
|
|
||||||
DW_PieceKind_Undefined,
|
|
||||||
} DW_PieceKind;
|
|
||||||
|
|
||||||
typedef struct DW_Piece
|
|
||||||
{
|
|
||||||
DW_PieceKind kind;
|
|
||||||
U64 bit_size;
|
|
||||||
U8 *value;
|
|
||||||
} DW_Piece;
|
|
||||||
|
|
||||||
typedef struct DW_PieceNode
|
|
||||||
{
|
|
||||||
DW_Piece v;
|
|
||||||
struct DW_PieceNode *next;
|
|
||||||
} DW_PieceNode;
|
|
||||||
|
|
||||||
typedef struct DW_PieceList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_PieceNode *first;
|
|
||||||
DW_PieceNode *last;
|
|
||||||
} DW_PieceList;
|
|
||||||
|
|
||||||
typedef struct DW_ExprStack
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_ExprValueNode *top;
|
|
||||||
} DW_ExprStack;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_ExprEvalResult_Fail,
|
|
||||||
DW_ExprEvalResult_Ok,
|
|
||||||
DW_ExprEvalResult_Maybe,
|
|
||||||
DW_ExprEvalResult_ExecOpLimitReached,
|
|
||||||
} DW_ExprEvalResult;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// encoder
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_ExprEncType_Null,
|
|
||||||
DW_ExprEncType_Op,
|
|
||||||
DW_ExprEncType_U8,
|
|
||||||
DW_ExprEncType_U16,
|
|
||||||
DW_ExprEncType_U32,
|
|
||||||
DW_ExprEncType_U64,
|
|
||||||
DW_ExprEncType_S8,
|
|
||||||
DW_ExprEncType_S16,
|
|
||||||
DW_ExprEncType_S32,
|
|
||||||
DW_ExprEncType_S64,
|
|
||||||
DW_ExprEncType_ULEB128,
|
|
||||||
DW_ExprEncType_SLEB128,
|
|
||||||
DW_ExprEncType_Addr,
|
|
||||||
DW_ExprEncType_Block,
|
|
||||||
DW_ExprEncType_DwarfUInt,
|
|
||||||
DW_ExprEncType_Label,
|
|
||||||
DW_ExprEncType_DeclLabel,
|
|
||||||
} DW_ExprEncType;
|
|
||||||
|
|
||||||
typedef struct DW_ExprEnc
|
|
||||||
{
|
|
||||||
DW_ExprEncType type;
|
|
||||||
union {
|
|
||||||
DW_ExprOp op;
|
|
||||||
U8 u8;
|
|
||||||
U16 u16;
|
|
||||||
U32 u32;
|
|
||||||
U64 u64;
|
|
||||||
S8 s8;
|
|
||||||
S16 s16;
|
|
||||||
S32 s32;
|
|
||||||
S64 s64;
|
|
||||||
U64 addr;
|
|
||||||
String8 block;
|
|
||||||
String8 label;
|
|
||||||
};
|
|
||||||
} DW_ExprEnc;
|
|
||||||
|
|
||||||
#define DW_ExprEnc_Op(v) { .type = DW_ExprEncType_Op, .op = DW_ExprOp_##v }
|
|
||||||
#define DW_ExprEnc_U8(v) { .type = DW_ExprEncType_U8, .u8 = v }
|
|
||||||
#define DW_ExprEnc_U16(v) { .type = DW_ExprEncType_U16, .u16 = v }
|
|
||||||
#define DW_ExprEnc_U32(v) { .type = DW_ExprEncType_U32, .u32 = v }
|
|
||||||
#define DW_ExprEnc_U64(v) { .type = DW_ExprEncType_U64, .u64 = v }
|
|
||||||
#define DW_ExprEnc_S8(v) { .type = DW_ExprEncType_S8, .s8 = v }
|
|
||||||
#define DW_ExprEnc_S16(v) { .type = DW_ExprEncType_S16, .s16 = v }
|
|
||||||
#define DW_ExprEnc_S32(v) { .type = DW_ExprEncType_S32, .s32 = v }
|
|
||||||
#define DW_ExprEnc_S64(v) { .type = DW_ExprEncType_S64, .s64 = v }
|
|
||||||
#define DW_ExprEnc_ULEB128(v) { .type = DW_ExprEncType_ULEB128, .u64 = v }
|
|
||||||
#define DW_ExprEnc_SLEB128(v) { .type = DW_ExprEncType_SLEB128, .s64 = v }
|
|
||||||
#define DW_ExprEnc_Addr(v) { .type = DW_ExprEncType_Addr, .addr = v }
|
|
||||||
#define DW_ExprEnc_Block(v) { .type = DW_ExprEncType_Block, .block = v }
|
|
||||||
#define DW_ExprEnc_UInt(v) { .type = DW_ExprEncType_DwarfUInt, .u64 = v }
|
|
||||||
#define DW_ExprEnc_Label(v) { .type = DW_ExprEncType_Label, .label = str8_lit_comp(v) }
|
|
||||||
#define DW_ExprEnc_DeclLabel(v) { .type = DW_ExprEncType_DeclLabel, .label = str8_lit_comp(v) }
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
// pieces
|
|
||||||
internal DW_PieceNode * dw_piece_list_push(Arena *arena, DW_PieceList *list, DW_Piece v);
|
|
||||||
|
|
||||||
// size -> type
|
|
||||||
internal DW_ExprValueType dw_expr_unsigned_value_type_from_bit_size(U64 bit_size);
|
|
||||||
internal DW_ExprValueType dw_expr_signed_value_type_from_bit_size(U64 bit_size);
|
|
||||||
internal DW_ExprValueType dw_expr_float_type_from_bit_size(U64 bit_size);
|
|
||||||
|
|
||||||
// type -> size
|
|
||||||
internal U64 dw_expr_byte_size_from_value_type(U64 addr_size, DW_ExprValueType k);
|
|
||||||
|
|
||||||
// typer
|
|
||||||
internal DW_ExprValueType dw_expr_pick_common_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
|
|
||||||
internal DW_ExprValueType dw_expr_pick_common_compar_value_type(DW_ExprValueType rhs, DW_ExprValueType lhs);
|
|
||||||
internal DW_ExprValue dw_expr_cast(DW_ExprValue value, DW_ExprValueType type);
|
|
||||||
|
|
||||||
// arithmetic operators
|
|
||||||
internal DW_ExprValue dw_expr_add (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_minus(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_mul (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_div (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_mod (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
|
|
||||||
// comparison operators
|
|
||||||
internal DW_ExprValue dw_expr_eq(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_ge(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_gt(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_le(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_lt(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_ne(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
|
|
||||||
// bitwise operators
|
|
||||||
internal DW_ExprValue dw_expr_xor (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_and (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_or (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_shl (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_shr (DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
internal DW_ExprValue dw_expr_shra(DW_ExprValue rhs, DW_ExprValue lhs);
|
|
||||||
|
|
||||||
// unary operators
|
|
||||||
internal DW_ExprValue dw_expr_abs(DW_ExprValue value);
|
|
||||||
internal DW_ExprValue dw_expr_neg(DW_ExprValue value);
|
|
||||||
internal DW_ExprValue dw_expr_not(DW_ExprValue value);
|
|
||||||
|
|
||||||
// stack
|
|
||||||
internal DW_ExprValueNode * dw_expr_stack_push(Arena *arena, DW_ExprStack *stack, DW_ExprValue value);
|
|
||||||
internal DW_ExprValueNode * dw_expr_stack_push_unsigned(Arena *arena, DW_ExprStack *stack, void *value, U64 value_size);
|
|
||||||
internal DW_ExprValue dw_expr_stack_pop(DW_ExprStack *stack);
|
|
||||||
internal DW_ExprValue dw_expr_stack_peek(DW_ExprStack *stack);
|
|
||||||
internal DW_ExprValueNode * dw_expr_stack_pick(DW_ExprStack *stack, U64 idx);
|
|
||||||
|
|
||||||
// value helpers
|
|
||||||
internal String8 dw_string_from_expr_value(Arena *arena, U64 addr_size, DW_ExprValue v);
|
|
||||||
|
|
||||||
// evaluator
|
|
||||||
internal DW_ExprEvalResult dw_eval_expr(Arena *arena, Arch arch, DW_Format format, U64 frame_base, U64 cfa, U64 tls_base, U64 op_limit, DW_Expr expr, void *reg_block, MachineOp_MemRead *mem_read, void *mem_read_ud, DW_ExprValue *value_out);
|
|
||||||
|
|
||||||
#endif //DWARF_EXPR_H
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,528 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_PARSE_H
|
|
||||||
#define DWARF_PARSE_H
|
|
||||||
|
|
||||||
typedef struct DW_Section
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 data;
|
|
||||||
B32 is_dwo;
|
|
||||||
} DW_Section;
|
|
||||||
|
|
||||||
typedef struct DW_Raw
|
|
||||||
{
|
|
||||||
DW_Section sec[DW_Section_COUNT];
|
|
||||||
DW_Section sup[DW_Section_COUNT];
|
|
||||||
} DW_Raw;
|
|
||||||
|
|
||||||
typedef struct DW_ListUnit
|
|
||||||
{
|
|
||||||
DW_Version version;
|
|
||||||
U64 address_size;
|
|
||||||
U64 segment_selector_size;
|
|
||||||
U64 entry_size;
|
|
||||||
String8 entries;
|
|
||||||
} DW_ListUnit;
|
|
||||||
|
|
||||||
typedef struct DW_ListUnitInput
|
|
||||||
{
|
|
||||||
U64 addr_count;
|
|
||||||
U64 str_offset_count;
|
|
||||||
U64 rnglist_count;
|
|
||||||
U64 loclist_count;
|
|
||||||
Rng1U64Array addr_ranges;
|
|
||||||
Rng1U64Array str_offset_ranges;
|
|
||||||
Rng1U64Array rnglist_ranges;
|
|
||||||
Rng1U64Array loclist_ranges;
|
|
||||||
DW_ListUnit *addrs;
|
|
||||||
DW_ListUnit *str_offsets;
|
|
||||||
DW_ListUnit *rnglists;
|
|
||||||
DW_ListUnit *loclists;
|
|
||||||
} DW_ListUnitInput;
|
|
||||||
|
|
||||||
typedef struct DW_AbbrevTableEntry
|
|
||||||
{
|
|
||||||
U64 id;
|
|
||||||
U64 off;
|
|
||||||
} DW_AbbrevTableEntry;
|
|
||||||
|
|
||||||
typedef struct DW_AbbrevTable DW_AbbrevTable;
|
|
||||||
struct DW_AbbrevTable
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_AbbrevTableEntry *entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum DW_AbbrevKind
|
|
||||||
{
|
|
||||||
DW_Abbrev_Null,
|
|
||||||
DW_Abbrev_Tag,
|
|
||||||
DW_Abbrev_Attrib,
|
|
||||||
DW_Abbrev_AttribSequenceEnd,
|
|
||||||
DW_Abbrev_DIEBegin,
|
|
||||||
DW_Abbrev_DIEEnd,
|
|
||||||
} DW_AbbrevKind;
|
|
||||||
|
|
||||||
typedef U32 DW_AbbrevFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
DW_AbbrevFlag_HasImplicitConst = (1 << 0),
|
|
||||||
DW_AbbrevFlag_HasChildren = (1 << 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct DW_Abbrev
|
|
||||||
{
|
|
||||||
DW_AbbrevKind kind;
|
|
||||||
U64 sub_kind;
|
|
||||||
U64 id;
|
|
||||||
S64 implicit_const;
|
|
||||||
DW_AbbrevFlags flags;
|
|
||||||
} DW_Abbrev;
|
|
||||||
|
|
||||||
typedef struct DW_Attrib
|
|
||||||
{
|
|
||||||
U64 info_off;
|
|
||||||
U64 abbrev_off;
|
|
||||||
U64 abbrev_id;
|
|
||||||
DW_AttribKind attrib_kind;
|
|
||||||
DW_Form form;
|
|
||||||
} DW_Attrib;
|
|
||||||
|
|
||||||
typedef struct DW_AttribNode
|
|
||||||
{
|
|
||||||
struct DW_AttribNode *next;
|
|
||||||
DW_Attrib v;
|
|
||||||
} DW_AttribNode;
|
|
||||||
|
|
||||||
typedef struct DW_AttribList
|
|
||||||
{
|
|
||||||
DW_AttribNode *first;
|
|
||||||
DW_AttribNode *last;
|
|
||||||
U64 count;
|
|
||||||
} DW_AttribList;
|
|
||||||
|
|
||||||
typedef U8 DW_TagSpare;
|
|
||||||
typedef struct DW_Tag
|
|
||||||
{
|
|
||||||
B32 has_children;
|
|
||||||
U64 abbrev_id;
|
|
||||||
DW_TagKind kind;
|
|
||||||
DW_AttribList attribs;
|
|
||||||
U64 info_off;
|
|
||||||
DW_TagSpare v;
|
|
||||||
} DW_Tag;
|
|
||||||
|
|
||||||
typedef struct DW_TagNode
|
|
||||||
{
|
|
||||||
DW_Tag tag;
|
|
||||||
struct DW_TagNode *sibling;
|
|
||||||
struct DW_TagNode *first_child;
|
|
||||||
struct DW_TagNode *last_child;
|
|
||||||
} DW_TagNode;
|
|
||||||
|
|
||||||
typedef struct DW_Loc
|
|
||||||
{
|
|
||||||
Rng1U64 range;
|
|
||||||
String8 expr;
|
|
||||||
} DW_Loc;
|
|
||||||
|
|
||||||
typedef struct DW_LocNode
|
|
||||||
{
|
|
||||||
DW_Loc v;
|
|
||||||
struct DW_LocNode *next;
|
|
||||||
} DW_LocNode;
|
|
||||||
|
|
||||||
typedef struct DW_LocList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_LocNode *first;
|
|
||||||
DW_LocNode *last;
|
|
||||||
} DW_LocList;
|
|
||||||
|
|
||||||
typedef struct DW_CompUnit
|
|
||||||
{
|
|
||||||
B32 relaxed;
|
|
||||||
DW_Ext ext;
|
|
||||||
DW_CompUnitKind kind;
|
|
||||||
DW_Version version;
|
|
||||||
DW_Format format;
|
|
||||||
U64 address_size;
|
|
||||||
U64 abbrev_off;
|
|
||||||
Rng1U64 info_range;
|
|
||||||
U64 first_tag_info_off;
|
|
||||||
DW_AbbrevTable abbrev_table;
|
|
||||||
DW_ListUnit *addr_lu;
|
|
||||||
DW_ListUnit *str_offsets_lu;
|
|
||||||
DW_ListUnit *rnglists_lu;
|
|
||||||
DW_ListUnit *loclists_lu;
|
|
||||||
U64 low_pc;
|
|
||||||
U64 dwo_id;
|
|
||||||
DW_Tag tag;
|
|
||||||
HashTable *tag_ht;
|
|
||||||
} DW_CompUnit;
|
|
||||||
|
|
||||||
typedef struct DW_TagTree
|
|
||||||
{
|
|
||||||
DW_TagNode *root;
|
|
||||||
U64 tag_count;
|
|
||||||
} DW_TagTree;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
typedef struct DW_LineFile
|
|
||||||
{
|
|
||||||
String8 path;
|
|
||||||
U64 dir_idx;
|
|
||||||
U64 time_stamp;
|
|
||||||
U64 size;
|
|
||||||
U128 md5;
|
|
||||||
String8 source;
|
|
||||||
} DW_LineFile;
|
|
||||||
|
|
||||||
typedef struct DW_LineFileNode
|
|
||||||
{
|
|
||||||
struct DW_LineFileNode *next;
|
|
||||||
DW_LineFile file;
|
|
||||||
} DW_LineFileNode;
|
|
||||||
|
|
||||||
typedef struct DW_LineFileList
|
|
||||||
{
|
|
||||||
U64 node_count;
|
|
||||||
DW_LineFileNode *first;
|
|
||||||
DW_LineFileNode *last;
|
|
||||||
} DW_LineFileList;
|
|
||||||
|
|
||||||
typedef struct DW_LineFileArray
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_LineFile *v;
|
|
||||||
} DW_LineFileArray;
|
|
||||||
|
|
||||||
typedef struct DW_LineVMHeader
|
|
||||||
{
|
|
||||||
U64 unit_length;
|
|
||||||
DW_Version version;
|
|
||||||
U8 address_size; // Duplicates size from the compilation unit but is needed to support stripped exe that just have .debug_line and .debug_line_str.
|
|
||||||
U8 segment_selector_size;
|
|
||||||
U64 header_length;
|
|
||||||
U8 min_inst_len;
|
|
||||||
U8 max_ops_for_inst;
|
|
||||||
U8 default_is_stmt;
|
|
||||||
S8 line_base;
|
|
||||||
U8 line_range;
|
|
||||||
U8 opcode_base;
|
|
||||||
U64 num_opcode_lens;
|
|
||||||
U8 *opcode_lens;
|
|
||||||
U64 line_program_off;
|
|
||||||
String8Array dir_table;
|
|
||||||
DW_LineFileArray file_table;
|
|
||||||
} DW_LineVMHeader;
|
|
||||||
|
|
||||||
typedef struct DW_LineVMState
|
|
||||||
{
|
|
||||||
U64 address; // Address of a machine instruction.
|
|
||||||
U32 op_index; // This is used by the VLIW instructions to indicate index of operation inside the instruction.
|
|
||||||
|
|
||||||
// Line table doesn't contain full path to a file, instead
|
|
||||||
// DWARF encodes path as two indices. First index will point into a directory
|
|
||||||
// table, and second points into a file name table.
|
|
||||||
U64 file_index;
|
|
||||||
|
|
||||||
U64 line;
|
|
||||||
U64 column;
|
|
||||||
|
|
||||||
B32 is_stmt; // Indicates that "address" points to place suitable for a breakpoint.
|
|
||||||
B32 basic_block; // Indicates that the "address" is inside a basic block.
|
|
||||||
|
|
||||||
// Indicates that "address" points to place where function starts.
|
|
||||||
// Usually prologue is the place where compiler emits instructions to
|
|
||||||
// prepare stack for a function.
|
|
||||||
B32 prologue_end;
|
|
||||||
|
|
||||||
B32 epilogue_begin; // Indicates that "address" points to section where function exits and unwinds stack.
|
|
||||||
U64 isa; // Instruction set that is used.
|
|
||||||
U64 discriminator; // Arbitrary id that indicates to which block these instructions belong.
|
|
||||||
B32 end_sequence; // Indicates that "address" points to the first instruction in the instruction block that follows.
|
|
||||||
} DW_LineVMState;
|
|
||||||
|
|
||||||
typedef struct DW_LineVM
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
U64 cursor;
|
|
||||||
String8 program;
|
|
||||||
DW_LineVMHeader header;
|
|
||||||
B32 new_line;
|
|
||||||
B32 new_seq;
|
|
||||||
B32 skip_opcode;
|
|
||||||
DW_LineVMState state;
|
|
||||||
U64 advance;
|
|
||||||
U64 opcode_off;
|
|
||||||
DW_StdOpcode opcode;
|
|
||||||
DW_ExtOpcode ext_opcode;
|
|
||||||
U64 ext_length;
|
|
||||||
U64 line_advance;
|
|
||||||
U64 addr_advance;
|
|
||||||
HashTable *ext_file_ht;
|
|
||||||
struct {
|
|
||||||
union {
|
|
||||||
String8 string;
|
|
||||||
U64 u64;
|
|
||||||
S64 s64;
|
|
||||||
};
|
|
||||||
} operands[4];
|
|
||||||
String8 error;
|
|
||||||
} DW_LineVM;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// .debug_pubnames and .debug_pubtypes
|
|
||||||
|
|
||||||
typedef struct DW_PubStringsBucket
|
|
||||||
{
|
|
||||||
struct DW_PubStringsBucket *next;
|
|
||||||
String8 string;
|
|
||||||
U64 info_off;
|
|
||||||
U64 cu_info_off;
|
|
||||||
} DW_PubStringsBucket;
|
|
||||||
|
|
||||||
typedef struct DW_PubStringsTable
|
|
||||||
{
|
|
||||||
U64 size;
|
|
||||||
DW_PubStringsBucket **buckets;
|
|
||||||
} DW_PubStringsTable;
|
|
||||||
|
|
||||||
typedef struct DW_Reference
|
|
||||||
{
|
|
||||||
DW_CompUnit *cu;
|
|
||||||
U64 info_off; // global .debug_info offset
|
|
||||||
} DW_Reference;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Expression
|
|
||||||
|
|
||||||
typedef union DW_ExprOperand
|
|
||||||
{
|
|
||||||
U8 u8;
|
|
||||||
U16 u16;
|
|
||||||
U32 u32;
|
|
||||||
U64 u64;
|
|
||||||
|
|
||||||
S8 s8;
|
|
||||||
S16 s16;
|
|
||||||
S32 s32;
|
|
||||||
S64 s64;
|
|
||||||
|
|
||||||
String8 block;
|
|
||||||
} DW_ExprOperand;
|
|
||||||
|
|
||||||
typedef struct DW_ExprInst
|
|
||||||
{
|
|
||||||
DW_ExprOp opcode;
|
|
||||||
DW_ExprOperand *operands;
|
|
||||||
U64 size;
|
|
||||||
struct DW_ExprInst *next;
|
|
||||||
struct DW_ExprInst *prev;
|
|
||||||
} DW_ExprInst;
|
|
||||||
|
|
||||||
typedef struct DW_Expr
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_ExprInst *first;
|
|
||||||
DW_ExprInst *last;
|
|
||||||
} DW_Expr;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// .debug_frame
|
|
||||||
|
|
||||||
typedef struct DW_CIE
|
|
||||||
{
|
|
||||||
String8 insts;
|
|
||||||
String8 aug_string;
|
|
||||||
String8 aug_data;
|
|
||||||
U64 code_align_factor;
|
|
||||||
S64 data_align_factor;
|
|
||||||
U64 ret_addr_reg;
|
|
||||||
U64 ext[4];
|
|
||||||
DW_Format format;
|
|
||||||
U8 version;
|
|
||||||
U8 address_size;
|
|
||||||
U8 segment_selector_size;
|
|
||||||
} DW_CIE;
|
|
||||||
|
|
||||||
typedef struct DW_FDE
|
|
||||||
{
|
|
||||||
DW_Format format;
|
|
||||||
U64 cie_pointer;
|
|
||||||
Rng1U64 pc_range;
|
|
||||||
String8 insts;
|
|
||||||
} DW_FDE;
|
|
||||||
|
|
||||||
typedef union DW_CFA_Operand
|
|
||||||
{
|
|
||||||
U64 u64;
|
|
||||||
S64 s64;
|
|
||||||
String8 block;
|
|
||||||
} DW_CFA_Operand;
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
DW_CFA_ParseErrorCode_NewInst,
|
|
||||||
DW_CFA_ParseErrorCode_End,
|
|
||||||
DW_CFA_ParseErrorCode_OutOfData
|
|
||||||
} DW_CFA_ParseErrorCode;
|
|
||||||
|
|
||||||
typedef struct DW_CFA_Inst
|
|
||||||
{
|
|
||||||
DW_CFA_Opcode opcode;
|
|
||||||
DW_CFA_Operand operands[DW_CFA_OperandMax];
|
|
||||||
} DW_CFA_Inst;
|
|
||||||
|
|
||||||
typedef struct DW_CFA_InstNode
|
|
||||||
{
|
|
||||||
DW_CFA_Inst v;
|
|
||||||
struct DW_CFA_InstNode *next;
|
|
||||||
} DW_CFA_InstNode;
|
|
||||||
|
|
||||||
typedef struct DW_CFA_InstList
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
DW_CFA_InstNode *first;
|
|
||||||
DW_CFA_InstNode *last;
|
|
||||||
} DW_CFA_InstList;
|
|
||||||
|
|
||||||
#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out)
|
|
||||||
typedef DW_DECODE_PTR(DW_DecodePtr);
|
|
||||||
|
|
||||||
// hasher
|
|
||||||
|
|
||||||
internal U64 dw_hash_from_string(String8 string);
|
|
||||||
|
|
||||||
// deserial helpers
|
|
||||||
|
|
||||||
internal U64 str8_deserial_read_dwarf_packed_size(String8 string, U64 off, U64 *size_out);
|
|
||||||
internal U64 str8_deserial_read_dwarf_uint (String8 string, U64 off, DW_Format format, U64 *uint_out);
|
|
||||||
internal U64 str8_deserial_read_uleb128_array(Arena *arena, String8 string, U64 off, U64 count, U64 **arr_out);
|
|
||||||
internal U64 str8_deserial_read_sleb128_array(Arena *arena, String8 string, U64 off, U64 count, S64 **arr_out);
|
|
||||||
|
|
||||||
internal Rng1U64List dw_unit_ranges_from_data(Arena *arena, String8 data);
|
|
||||||
internal Rng1U64Array dw_unit_ranges_from_data_arr(Arena *arena, String8 data);
|
|
||||||
|
|
||||||
// list units
|
|
||||||
|
|
||||||
internal U64 dw_read_list_unit_header_addr (String8 unit_data, DW_ListUnit *lu_out);
|
|
||||||
internal U64 dw_read_list_unit_header_str_offsets(String8 unit_data, DW_ListUnit *lu_out);
|
|
||||||
internal U64 dw_read_list_unit_header_list (String8 unit_data, DW_ListUnit *lu_out);
|
|
||||||
|
|
||||||
internal DW_ListUnitInput dw_list_unit_input_from_input(Arena *arena, DW_Raw *input);
|
|
||||||
|
|
||||||
internal U64 dw_offset_from_list_unit(DW_ListUnit *lu, U64 index);
|
|
||||||
internal U64 dw_addr_from_list_unit (DW_ListUnit *lu, U64 index);
|
|
||||||
|
|
||||||
// abbrev table
|
|
||||||
|
|
||||||
internal U64 dw_read_abbrev_tag (String8 data, U64 offset, DW_Abbrev *out_abbrev);
|
|
||||||
internal U64 dw_read_abbrev_attrib(String8 data, U64 offset, DW_Abbrev *out_abbrev);
|
|
||||||
|
|
||||||
internal DW_AbbrevTable dw_read_abbrev_table(Arena *arena, String8 abbrev_data, U64 abbrev_base);
|
|
||||||
internal U64 dw_abbrev_offset_from_abbrev_id(DW_AbbrevTable table, U64 abbrev_id);
|
|
||||||
|
|
||||||
// form and tag
|
|
||||||
|
|
||||||
internal B32 dw_read_form (String8 data, DW_Version version, DW_Format unit_format, U64 address_size, DW_FormKind form_kind, S64 implicit_const, DW_Form *form_out, U64 *bytes_read_out);
|
|
||||||
internal U64 dw_read_tag (Arena *arena, DW_Raw *input, DW_AbbrevTable abbrev_table, DW_Version version, DW_Format format, U64 address_size, Rng1U64 cu_info_range, U64 tag_info_off, DW_Tag *tag_out);
|
|
||||||
internal U64 dw_read_tag_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 info_off, DW_Tag *tag_out);
|
|
||||||
|
|
||||||
// attrib interp
|
|
||||||
|
|
||||||
internal U64 dw_interp_sec_offset(DW_Form form);
|
|
||||||
internal String8 dw_interp_exprloc (DW_Form form);
|
|
||||||
internal U128 dw_interp_const_u128(DW_Form form);
|
|
||||||
internal U64 dw_interp_const_u64 (DW_Form form);
|
|
||||||
internal U32 dw_interp_const_u32 (DW_Form form);
|
|
||||||
internal S64 dw_interp_const_s64 (DW_Form form);
|
|
||||||
internal S32 dw_interp_const_s32 (DW_Form form);
|
|
||||||
internal B32 dw_interp_flag (DW_Form form);
|
|
||||||
internal U64 dw_interp_address (U64 address_size, U64 base_addr, DW_ListUnit *addr_xlist, DW_Form form);
|
|
||||||
internal String8 dw_interp_block (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
|
|
||||||
internal String8 dw_interp_string (DW_Raw *input, DW_Format unit_format, DW_ListUnit *str_offsets, DW_Form form);
|
|
||||||
internal String8 dw_interp_line_ptr (DW_Raw *input, DW_Form form);
|
|
||||||
internal DW_LineFile * dw_interp_file (DW_LineVM *line_vm, DW_Form form);
|
|
||||||
internal DW_Reference dw_interp_ref (DW_Raw *input, DW_CompUnit *cu, DW_Form form);
|
|
||||||
internal DW_LocList dw_interp_loclist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
|
|
||||||
internal Rng1U64List dw_interp_rnglist (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Form form);
|
|
||||||
|
|
||||||
internal String8 dw_exprloc_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal U128 dw_const_u128_from_attrib(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal U64 dw_const_u64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal U32 dw_const_u32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal S64 dw_const_s64_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal S32 dw_const_s32_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal B32 dw_flag_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal U64 dw_address_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal String8 dw_block_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal String8 dw_string_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal String8 dw_line_ptr_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal DW_LineFile * dw_file_from_attrib (DW_CompUnit *cu, DW_LineVM *line_vm, DW_Attrib *attrib);
|
|
||||||
internal DW_Reference dw_ref_from_attrib (DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal DW_LocList dw_loclist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
internal Rng1U64List dw_rnglist_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
|
|
||||||
internal String8 dw_exprloc_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal U128 dw_const_u128_from_tag_attrib_kind(DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal U64 dw_const_u64_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal U32 dw_const_u32_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal B32 dw_flag_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal U64 dw_address_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal String8 dw_block_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal String8 dw_string_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal String8 dw_line_ptr_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal DW_LineFile * dw_file_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_LineVM *line_vm, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal DW_Reference dw_ref_from_tag_attrib_kind (DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal DW_LocList dw_loclist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal Rng1U64List dw_rnglist_from_tag_attrib_kind (Arena *arena, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
|
|
||||||
internal B32 dw_is_attrib_var_ref(DW_Raw *input, DW_CompUnit *cu, DW_Attrib *attrib);
|
|
||||||
|
|
||||||
// compile unit
|
|
||||||
|
|
||||||
internal DW_CompUnit dw_cu_from_info_off(Arena *arena, DW_Raw *input, DW_ListUnitInput lu_input, U64 offset, B32 relaxed);
|
|
||||||
internal DW_TagTree dw_tag_tree_from_cu(Arena *arena, DW_Raw *input, DW_CompUnit *cu);
|
|
||||||
internal HashTable * dw_make_tag_hash_table(Arena *arena, DW_TagTree tag_tree);
|
|
||||||
internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off);
|
|
||||||
|
|
||||||
// line VM
|
|
||||||
|
|
||||||
internal U64 dw_read_line_vm_header(Arena *arena, DW_Raw *input, String8 cu_stmt_list, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out);
|
|
||||||
internal DW_LineVM * dw_line_vm_init(DW_Raw *input, DW_CompUnit *cu);
|
|
||||||
internal void dw_line_vm_release(DW_LineVM *vm);
|
|
||||||
internal void dw_line_vm_advance(DW_LineVM *vm, U64 advance);
|
|
||||||
internal B32 dw_line_vm_step(DW_LineVM *vm);
|
|
||||||
internal DW_LineFile * dw_line_vm_find_file(DW_LineVM *vm, U64 file_idx);
|
|
||||||
internal String8 dw_path_from_file(Arena *arena, String8Array dir_table, DW_LineFile *file);
|
|
||||||
|
|
||||||
// helper for .debug_pubtypes and .debug_pubnames
|
|
||||||
|
|
||||||
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Raw *input, DW_SectionKind section_kind);
|
|
||||||
|
|
||||||
// expression
|
|
||||||
|
|
||||||
internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data);
|
|
||||||
|
|
||||||
// debug frame
|
|
||||||
|
|
||||||
internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n);
|
|
||||||
internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v);
|
|
||||||
|
|
||||||
internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out);
|
|
||||||
|
|
||||||
internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out);
|
|
||||||
internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out);
|
|
||||||
internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIE *cie, DW_FDE *fde_out);
|
|
||||||
internal B32 dw_parse_cfi(String8 data, U64 fde_offset, Arch arch, DW_CIE *cie_out, DW_FDE *fde_out);
|
|
||||||
|
|
||||||
internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out);
|
|
||||||
internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
|
|
||||||
|
|
||||||
#endif // DWARF_PARSE_H
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal DW_CFI_Row *
|
|
||||||
dw_make_cfi_row(Arena *arena, U64 reg_count)
|
|
||||||
{
|
|
||||||
DW_CFI_Row *row = push_array(arena, DW_CFI_Row, 1);
|
|
||||||
row->regs = push_array(arena, DW_CFI_Register, reg_count);
|
|
||||||
for EachIndex(reg_idx, reg_count) {
|
|
||||||
row->regs[reg_idx].rule = DW_CFI_RegisterRule_SameValue;
|
|
||||||
}
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
dw_memcpy_cfi_row(DW_CFI_Row *dst, DW_CFI_Row *src, U64 reg_count)
|
|
||||||
{
|
|
||||||
dst->cfa = src->cfa;
|
|
||||||
MemoryCopyTyped(dst->regs, src->regs, reg_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DW_CFI_Row *
|
|
||||||
dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count)
|
|
||||||
{
|
|
||||||
DW_CFI_Row *new_row = dw_make_cfi_row(arena, reg_count);
|
|
||||||
dw_memcpy_cfi_row(new_row, row, reg_count);
|
|
||||||
return new_row;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DW_CFI_Unwind *
|
|
||||||
dw_cfi_unwind_init(Arena *arena,
|
|
||||||
Arch arch,
|
|
||||||
DW_CIE *cie,
|
|
||||||
DW_FDE *fde,
|
|
||||||
DW_DecodePtr *decode_ptr_func,
|
|
||||||
void *decode_ptr_ud)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
DW_CFI_Unwind *uw = push_array(arena, DW_CFI_Unwind, 1);
|
|
||||||
uw->insts = dw_parse_cfa_inst_list(arena, fde->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
|
|
||||||
uw->cie = cie;
|
|
||||||
uw->fde = fde;
|
|
||||||
uw->pc = fde->pc_range.min;
|
|
||||||
uw->arch = arch;
|
|
||||||
uw->reg_count = dw_reg_count_from_arch(arch);
|
|
||||||
|
|
||||||
// setup initial register rules
|
|
||||||
DW_CFA_InstList initial_insts = dw_parse_cfa_inst_list(scratch.arena, cie->insts, cie->code_align_factor, cie->data_align_factor, decode_ptr_func, decode_ptr_ud);
|
|
||||||
uw->row = dw_make_cfi_row(arena, uw->reg_count);
|
|
||||||
uw->curr_inst = initial_insts.first;
|
|
||||||
if (!dw_cfi_next_row(arena, uw)) {
|
|
||||||
AssertAlways(0 && "unable to interpret initial row instructions");
|
|
||||||
}
|
|
||||||
|
|
||||||
// make first row from initial rules
|
|
||||||
uw->initial_row = uw->row;
|
|
||||||
uw->row = dw_copy_cfi_row(arena, uw->initial_row, uw->reg_count);
|
|
||||||
uw->curr_inst = uw->insts.first;
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return uw;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw)
|
|
||||||
{
|
|
||||||
B32 is_row_valid = 0;
|
|
||||||
DW_CFA_InstNode *row_inst = uw->curr_inst;
|
|
||||||
|
|
||||||
// skip leading nops
|
|
||||||
while (uw->curr_inst) {
|
|
||||||
if (uw->curr_inst->v.opcode != DW_CFA_Nop) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
uw->curr_inst = uw->curr_inst->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (uw->curr_inst) {
|
|
||||||
DW_CFA_Inst *inst = &uw->curr_inst->v;
|
|
||||||
|
|
||||||
// validate register operands
|
|
||||||
DW_CFA_OperandType *operand_types = dw_operand_types_from_cfa_op(inst->opcode);
|
|
||||||
U64 operand_count = dw_operand_count_from_cfa_opcode(inst->opcode);
|
|
||||||
for EachIndex(operand_idx, operand_count) {
|
|
||||||
if (operand_types[operand_idx] == DW_CFA_OperandType_Register) {
|
|
||||||
if (inst->operands[operand_idx].u64 >= uw->reg_count) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (inst->opcode) {
|
|
||||||
// Row Creation Instructions
|
|
||||||
case DW_CFA_SetLoc: {
|
|
||||||
uw->pc = inst->operands[0].u64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_AdvanceLoc:
|
|
||||||
case DW_CFA_AdvanceLoc1:
|
|
||||||
case DW_CFA_AdvanceLoc2:
|
|
||||||
case DW_CFA_AdvanceLoc4: {
|
|
||||||
uw->pc += inst->operands[0].u64;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// CFA Definition Instructions
|
|
||||||
case DW_CFA_DefCfa:
|
|
||||||
case DW_CFA_DefCfaSf: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
S64 off = inst->operands[1].s64;
|
|
||||||
uw->row->cfa.rule = DW_CFA_Rule_RegOff;
|
|
||||||
uw->row->cfa.reg = reg;
|
|
||||||
uw->row->cfa.off = off;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_DefCfaRegister: {
|
|
||||||
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
|
|
||||||
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->cfa.reg = reg;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_DefCfaOffset:
|
|
||||||
case DW_CFA_DefCfaOffsetSf: {
|
|
||||||
// TODO: report error: this operation is valid only if the current CFA rule is defined to register+offset
|
|
||||||
if (uw->row->cfa.rule != DW_CFA_Rule_RegOff) { goto exit; }
|
|
||||||
uw->row->cfa.off = inst->operands[0].s64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_DefCfaExpr: {
|
|
||||||
uw->row->cfa.rule = DW_CFA_Rule_Expression;
|
|
||||||
uw->row->cfa.expr = inst->operands[0].block;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// Register Rule Instructions
|
|
||||||
case DW_CFA_Undefined: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Undefined;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_SameValue: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_SameValue;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_Offset:
|
|
||||||
case DW_CFA_OffsetExt:
|
|
||||||
case DW_CFA_OffsetExtSf: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Offset;
|
|
||||||
uw->row->regs[reg].n = inst->operands[1].s64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_ValOffset:
|
|
||||||
case DW_CFA_ValOffsetSf: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValOffset;
|
|
||||||
uw->row->regs[reg].n = inst->operands[1].s64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_Register: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Register;
|
|
||||||
uw->row->regs[reg].n = inst->operands[1].s64;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_Expr: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_Expression;
|
|
||||||
uw->row->regs[reg].expr = inst->operands[1].block;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_ValExpr: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg].rule = DW_CFI_RegisterRule_ValExpression;
|
|
||||||
uw->row->regs[reg].expr = inst->operands[1].block;
|
|
||||||
} break;
|
|
||||||
case DW_CFA_Restore:
|
|
||||||
case DW_CFA_RestoreExt: {
|
|
||||||
U64 reg = inst->operands[0].u64;
|
|
||||||
uw->row->regs[reg] = uw->initial_row->regs[reg];
|
|
||||||
} break;
|
|
||||||
|
|
||||||
// Row State Instructions
|
|
||||||
case DW_CFA_RememberState: {
|
|
||||||
DW_CFI_Row *new_row = dw_copy_cfi_row(arena, uw->row, uw->reg_count);
|
|
||||||
SLLStackPush(uw->row, new_row);
|
|
||||||
} break;
|
|
||||||
case DW_CFA_RestoreState: {
|
|
||||||
if (uw->row == 0) { goto exit; } // TODO: report error: unbalanced number of pushes and pops
|
|
||||||
DW_CFI_Row *free_row = uw->row;
|
|
||||||
SLLStackPop(uw->row);
|
|
||||||
SLLStackPush(uw->free_rows, free_row);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case DW_CFA_Nop: {} break;
|
|
||||||
|
|
||||||
default: { NotImplemented; } break; // TODO: report error: unknown CFA opcode
|
|
||||||
}
|
|
||||||
|
|
||||||
uw->curr_inst = uw->curr_inst->next;
|
|
||||||
if (uw->curr_inst) {
|
|
||||||
if (dw_is_new_row_cfa_opcode(uw->curr_inst->v.opcode)) { break; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is_row_valid = row_inst != 0;
|
|
||||||
exit:;
|
|
||||||
return is_row_valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DW_CFI_Row *
|
|
||||||
dw_cfi_row_from_pc(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
|
|
||||||
B32 is_row_found = 0;
|
|
||||||
U64 reg_count = dw_reg_count_from_arch(arch);
|
|
||||||
DW_CFI_Unwind *uw = dw_cfi_unwind_init(scratch.arena, arch, cie, fde, decode_ptr_func, decode_ptr_ctx);
|
|
||||||
DW_CFI_Row *row = dw_copy_cfi_row(scratch.arena, uw->row, uw->reg_count);
|
|
||||||
U64 prev_pc = uw->pc;
|
|
||||||
while (dw_cfi_next_row(scratch.arena, uw)) {
|
|
||||||
if (prev_pc <= pc && pc < uw->pc) {
|
|
||||||
is_row_found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dw_memcpy_cfi_row(row, uw->row, uw->reg_count);
|
|
||||||
prev_pc = uw->pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle last row
|
|
||||||
if (!is_row_found) {
|
|
||||||
if (contains_1u64(fde->pc_range, pc)) {
|
|
||||||
row = uw->row;
|
|
||||||
is_row_found = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy out final row
|
|
||||||
DW_CFI_Row *result = 0;
|
|
||||||
if (is_row_found) {
|
|
||||||
result = dw_copy_cfi_row(arena, row, reg_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal MachineOpResult
|
|
||||||
dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out)
|
|
||||||
{
|
|
||||||
MachineOpResult unwind_status = MachineOpResult_Fail;
|
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
|
||||||
switch(row->cfa.rule)
|
|
||||||
{
|
|
||||||
case DW_CFA_Rule_Null:{}break;
|
|
||||||
case DW_CFA_Rule_RegOff:
|
|
||||||
{
|
|
||||||
// TODO: report error (invalid register read)
|
|
||||||
U64 cfa_reg_value = 0;
|
|
||||||
U64 reg_size = dw_reg_size_from_code(arch, row->cfa.reg);
|
|
||||||
AssertAlways(reg_size <= sizeof(cfa_reg_value));
|
|
||||||
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, row->cfa.reg);
|
|
||||||
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
|
|
||||||
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, &cfa_reg_value))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*cfa_out = cfa_reg_value + row->cfa.off;
|
|
||||||
unwind_status = MachineOpResult_Ok;
|
|
||||||
}break;
|
|
||||||
case DW_CFA_Rule_Expression:
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0,0);
|
|
||||||
DW_ExprValue value = {0};
|
|
||||||
DW_Expr expr = dw_expr_from_data(scratch.arena, DW_Format_32Bit, byte_size_from_arch(arch), row->cfa.expr);
|
|
||||||
DW_ExprEvalResult eval_result = dw_eval_expr(scratch.arena, arch, DW_Format_32Bit, 0, 0, 0, 9999, expr, reg_block, mem_read_func, mem_read_ud, &value);
|
|
||||||
if (eval_result == DW_ExprEvalResult_Ok) {
|
|
||||||
if (DW_ExprValueType_IsInt(value.type)) {
|
|
||||||
*cfa_out = value.u64;
|
|
||||||
unwind_status = MachineOpResult_Ok;
|
|
||||||
}
|
|
||||||
} else if (eval_result == DW_ExprEvalResult_Maybe) {
|
|
||||||
unwind_status = MachineOpResult_Maybe;
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
return unwind_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal MachineOpResult
|
|
||||||
dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0,0);
|
|
||||||
MachineOpResult unwind_status = MachineOpResult_Ok;
|
|
||||||
|
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
|
||||||
|
|
||||||
U64 max_reg_size = dw_reg_max_size_from_arch(arch);
|
|
||||||
void *reg_buffer = push_array(scratch.arena, U8, max_reg_size);
|
|
||||||
|
|
||||||
U64 reg_count = dw_reg_count_from_arch(arch);
|
|
||||||
for EachIndex(reg_idx, reg_count)
|
|
||||||
{
|
|
||||||
DW_CFI_Register *reg = &row->regs[reg_idx];
|
|
||||||
ARCH_RegCode reg_code = arch_reg_code_from_dw(arch, reg_idx);
|
|
||||||
Rng1U16 reg_rng = arch_info->reg_code_rng_table[reg_code];
|
|
||||||
switch(reg->rule)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case DW_CFI_RegisterRule_Undefined: {} break;
|
|
||||||
case DW_CFI_RegisterRule_SameValue: {} break;
|
|
||||||
case DW_CFI_RegisterRule_Offset:
|
|
||||||
{
|
|
||||||
// read register value from memory
|
|
||||||
U64 addr = cfa + reg->n;
|
|
||||||
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
|
|
||||||
unwind_status = mem_read_func(addr, reg_buffer, reg_size, mem_read_ud);
|
|
||||||
if (unwind_status != MachineOpResult_Ok) { goto exit; }
|
|
||||||
|
|
||||||
// write register value to the thread context
|
|
||||||
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
|
|
||||||
{
|
|
||||||
unwind_status = MachineOpResult_Fail;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_ValOffset:
|
|
||||||
{
|
|
||||||
// compute register value
|
|
||||||
U64 reg_value = cfa + reg->n;
|
|
||||||
|
|
||||||
// write register value to the thread context
|
|
||||||
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
|
|
||||||
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, ®_value))
|
|
||||||
{
|
|
||||||
unwind_status = MachineOpResult_Fail;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_Register:
|
|
||||||
{
|
|
||||||
// read register value from another register
|
|
||||||
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
|
|
||||||
if(!arch_reg_block_read_range(arch_info, reg_block, reg_rng, reg_buffer))
|
|
||||||
{
|
|
||||||
unwind_status = MachineOpResult_Fail;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write register value to the thread context
|
|
||||||
if(!arch_reg_block_write_range(arch_info, reg_block, reg_rng, reg_buffer))
|
|
||||||
{
|
|
||||||
unwind_status = MachineOpResult_Fail;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
if (unwind_status != MachineOpResult_Ok) { goto exit; }
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_Expression:
|
|
||||||
{
|
|
||||||
// TODO: evaluate expression
|
|
||||||
NotImplemented;
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_ValExpression:
|
|
||||||
{
|
|
||||||
// TODO: evaluate expression
|
|
||||||
NotImplemented;
|
|
||||||
}break;
|
|
||||||
case DW_CFI_RegisterRule_Architectural:
|
|
||||||
{
|
|
||||||
NotImplemented;
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update stack pointer
|
|
||||||
arch_reg_block_write_sp(arch_info, reg_block, cfa);
|
|
||||||
|
|
||||||
exit:;
|
|
||||||
scratch_end(scratch);
|
|
||||||
return unwind_status;
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef DWARF_UNWIND_H
|
|
||||||
#define DWARF_UNWIND_H
|
|
||||||
|
|
||||||
typedef enum DW_CFI_RegisterRule
|
|
||||||
{
|
|
||||||
DW_CFI_RegisterRule_Undefined,
|
|
||||||
DW_CFI_RegisterRule_SameValue,
|
|
||||||
DW_CFI_RegisterRule_Offset,
|
|
||||||
DW_CFI_RegisterRule_ValOffset,
|
|
||||||
DW_CFI_RegisterRule_Register,
|
|
||||||
DW_CFI_RegisterRule_Expression,
|
|
||||||
DW_CFI_RegisterRule_ValExpression,
|
|
||||||
DW_CFI_RegisterRule_Architectural
|
|
||||||
} DW_CFI_RegisterRule;
|
|
||||||
|
|
||||||
typedef enum DW_CFA_Rule
|
|
||||||
{
|
|
||||||
DW_CFA_Rule_Null,
|
|
||||||
DW_CFA_Rule_RegOff,
|
|
||||||
DW_CFA_Rule_Expression
|
|
||||||
} DW_CFA_Rule;
|
|
||||||
|
|
||||||
typedef struct DW_CFA
|
|
||||||
{
|
|
||||||
DW_CFA_Rule rule;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
DW_Reg reg;
|
|
||||||
S64 off;
|
|
||||||
};
|
|
||||||
String8 expr;
|
|
||||||
};
|
|
||||||
} DW_CFA;
|
|
||||||
|
|
||||||
typedef struct DW_CFI_Register
|
|
||||||
{
|
|
||||||
DW_CFI_RegisterRule rule;
|
|
||||||
union {
|
|
||||||
S64 n;
|
|
||||||
String8 expr;
|
|
||||||
};
|
|
||||||
} DW_CFI_Register;
|
|
||||||
|
|
||||||
typedef struct DW_CFI_Row
|
|
||||||
{
|
|
||||||
DW_CFA cfa;
|
|
||||||
DW_CFI_Register *regs;
|
|
||||||
struct DW_CFI_Row *next;
|
|
||||||
} DW_CFI_Row;
|
|
||||||
|
|
||||||
typedef struct DW_CFI_Unwind
|
|
||||||
{
|
|
||||||
DW_CFA_InstList insts;
|
|
||||||
DW_CIE *cie;
|
|
||||||
DW_FDE *fde;
|
|
||||||
DW_CFI_Row *initial_row;
|
|
||||||
DW_CFI_Row *row;
|
|
||||||
DW_CFA_InstNode *curr_inst;
|
|
||||||
DW_CFI_Row *free_rows;
|
|
||||||
U64 pc;
|
|
||||||
Arch arch;
|
|
||||||
U64 reg_count;
|
|
||||||
} DW_CFI_Unwind;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal DW_CFI_Row * dw_make_cfi_row(Arena *arena, U64 reg_count);
|
|
||||||
internal DW_CFI_Row * dw_copy_cfi_row(Arena *arena, DW_CFI_Row *row, U64 reg_count);
|
|
||||||
|
|
||||||
internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
|
|
||||||
internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw);
|
|
||||||
|
|
||||||
internal DW_CFI_Row * dw_cfi_row_from_pc(Arena *arena, Arch arch, struct DW_CIE *cie, struct DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ctx, U64 pc);
|
|
||||||
internal MachineOpResult dw_compute_cfa(Arch arch, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud, U64 *cfa_out);
|
|
||||||
internal MachineOpResult dw_cfi_apply_register_rules(Arch arch, U64 cfa, DW_CFI_Row *row, void *reg_block, MachineOp_MemRead *mem_read_func, void *mem_read_ud);
|
|
||||||
|
|
||||||
#endif // DWARF_UNWIND_H
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,275 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef RDI_FROM_DWARF_H
|
|
||||||
#define RDI_FROM_DWARF_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Conversion
|
|
||||||
|
|
||||||
typedef struct D2R_ConvertParams
|
|
||||||
{
|
|
||||||
String8 dbg_name;
|
|
||||||
String8 dbg_data;
|
|
||||||
String8 exe_name;
|
|
||||||
String8 exe_data;
|
|
||||||
ExecutableImageKind exe_kind;
|
|
||||||
RDIM_SubsetFlags subset_flags;
|
|
||||||
B32 deterministic;
|
|
||||||
B32 is_parse_relaxed;
|
|
||||||
} D2R_ConvertParams;
|
|
||||||
|
|
||||||
#define D2R_UNIT_CHUNK_CAP 512
|
|
||||||
#define D2R_UDT_CHUNK_CAP 1024
|
|
||||||
#define D2R_TYPE_CHUNK_CAP 1024
|
|
||||||
#define D2R_SRC_FILE_CAP 1024
|
|
||||||
#define D2R_LINE_TABLE_CAP 1024
|
|
||||||
#define D2R_GVAR_CHUNK_CAP 1024
|
|
||||||
#define D2R_TVAR_CHUNK_CAP 1024
|
|
||||||
#define D2R_LOCATIONS_CAP 4096
|
|
||||||
#define D2R_PROC_CHUNK_CAP 4096
|
|
||||||
#define D2R_SCOPE_CHUNK_CAP 4096
|
|
||||||
#define D2R_INLINE_SITE_CHUNK_CAP 4096
|
|
||||||
|
|
||||||
typedef struct D2R_Shared
|
|
||||||
{
|
|
||||||
RDIM_TopLevelInfo top_level_info;
|
|
||||||
RDIM_BinarySectionList binary_sections;
|
|
||||||
RDIM_UnitChunkList units;
|
|
||||||
RDIM_UDTChunkList udts;
|
|
||||||
RDIM_TypeChunkList types;
|
|
||||||
RDIM_SrcFileChunkList src_files;
|
|
||||||
RDIM_LineTableChunkList line_tables;
|
|
||||||
} D2R_Shared;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Value Types
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
D2R_ArithmeticType_Null,
|
|
||||||
D2R_ArithmeticType_Signed,
|
|
||||||
D2R_ArithmeticType_Unsigned,
|
|
||||||
D2R_ArithmeticType_Float,
|
|
||||||
} D2R_ArithmeticType;
|
|
||||||
|
|
||||||
#define D2R_ValueType_Signed_XList \
|
|
||||||
X(S8, Signed, 1 ) \
|
|
||||||
X(S16, Signed, 2 ) \
|
|
||||||
X(S32, Signed, 4 ) \
|
|
||||||
X(S64, Signed, 8 ) \
|
|
||||||
X(S128, Signed, 16) \
|
|
||||||
X(S256, Signed, 32) \
|
|
||||||
X(S512, Signed, 64)
|
|
||||||
|
|
||||||
#define D2R_ValueType_Unsigned_XList \
|
|
||||||
X(U8, Unsigned, 1 ) \
|
|
||||||
X(U16, Unsigned, 2 ) \
|
|
||||||
X(U32, Unsigned, 4 ) \
|
|
||||||
X(U64, Unsigned, 8 ) \
|
|
||||||
X(U128, Unsigned, 16) \
|
|
||||||
X(U256, Unsigned, 32) \
|
|
||||||
X(U512, Unsigned, 64)
|
|
||||||
|
|
||||||
#define D2R_ValueType_Float_XList \
|
|
||||||
X(F16, Float, 2 ) \
|
|
||||||
X(F32, Float, 4 ) \
|
|
||||||
X(F48, Float, 6 ) \
|
|
||||||
X(F64, Float, 8 ) \
|
|
||||||
X(F80, Float, 10) \
|
|
||||||
X(F96, Float, 12) \
|
|
||||||
X(F128, Float, 16)
|
|
||||||
|
|
||||||
#define D2R_ValueType_XList \
|
|
||||||
X(Generic, Null, 0 ) \
|
|
||||||
X(ImplicitValue, Null, 0 ) \
|
|
||||||
X(Address, Unsigned, 0 ) \
|
|
||||||
D2R_ValueType_Signed_XList \
|
|
||||||
D2R_ValueType_Unsigned_XList \
|
|
||||||
D2R_ValueType_Float_XList
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
#define X(t, ...) D2R_ValueType_##t,
|
|
||||||
D2R_ValueType_XList
|
|
||||||
#undef X
|
|
||||||
D2R_ValueType_Bool = D2R_ValueType_S8,
|
|
||||||
} D2R_ValueType;
|
|
||||||
|
|
||||||
typedef struct D2R_ValueTypeNode
|
|
||||||
{
|
|
||||||
D2R_ValueType type;
|
|
||||||
struct D2R_ValueTypeNode *next;
|
|
||||||
} D2R_ValueTypeNode;
|
|
||||||
|
|
||||||
typedef struct D2R_ValueTypeStack
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
D2R_ValueTypeNode *top;
|
|
||||||
D2R_ValueTypeNode *free_list;
|
|
||||||
} D2R_ValueTypeStack;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Type Table
|
|
||||||
|
|
||||||
typedef struct D2R_TypeTable
|
|
||||||
{
|
|
||||||
HashTable *ht;
|
|
||||||
RDIM_TypeChunkList *types;
|
|
||||||
U64 type_chunk_cap;
|
|
||||||
RDIM_Type **builtin_types;
|
|
||||||
} D2R_TypeTable;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Tag Iterator
|
|
||||||
|
|
||||||
typedef DW_TagSpare D2R_TagFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
D2R_TagFlags_TypeConverted = (1 << 0),
|
|
||||||
D2R_TagFlags_UdtConverted = (1 << 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct D2R_TagFrame
|
|
||||||
{
|
|
||||||
DW_TagNode *node;
|
|
||||||
RDIM_Scope *scope;
|
|
||||||
struct D2R_TagFrame *next;
|
|
||||||
} D2R_TagFrame;
|
|
||||||
|
|
||||||
typedef struct D2R_TagIterator
|
|
||||||
{
|
|
||||||
D2R_TagFrame *free_list;
|
|
||||||
D2R_TagFrame *stack;
|
|
||||||
DW_TagNode *null_tag_node;
|
|
||||||
DW_TagNode *tag_node;
|
|
||||||
B32 visit_children;
|
|
||||||
} D2R_TagIterator;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Line Table Conversion
|
|
||||||
|
|
||||||
typedef struct D2R_SrcFileLookup
|
|
||||||
{
|
|
||||||
DW_LineFile *file;
|
|
||||||
DW_LineVM *vm;
|
|
||||||
RDIM_SrcFile *src_file;
|
|
||||||
} D2R_SrcFileLookup;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Contrib Map
|
|
||||||
|
|
||||||
typedef struct D2R_CompUnitContribMap
|
|
||||||
{
|
|
||||||
U64 count;
|
|
||||||
U64 *info_off_arr;
|
|
||||||
RDIM_Rng1U64ChunkList *voff_range_arr;
|
|
||||||
} D2R_CompUnitContribMap;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ RDIM Bytecode Extensions
|
|
||||||
|
|
||||||
internal B32 rdim_is_eval_bytecode_static (RDIM_EvalBytecode bc);
|
|
||||||
internal B32 rdim_static_eval_bytecode_to_voff(RDIM_EvalBytecode bc, U64 image_base, U64 *voff_out);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ DWARF -> RDI Enums
|
|
||||||
|
|
||||||
internal RDI_Language d2r_rdi_language_from_dw_language(DW_Language v);
|
|
||||||
internal RDI_RegCodeX64 d2r_rdi_reg_code_from_dw_reg_x64 (DW_RegX64 v);
|
|
||||||
internal RDI_RegCode d2r_rdi_reg_code_from_dw_reg (Arch arch, DW_Reg v);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Value Type
|
|
||||||
|
|
||||||
internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type);
|
|
||||||
internal D2R_ValueType d2r_value_type_stack_pop (D2R_ValueTypeStack *stack);
|
|
||||||
internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack);
|
|
||||||
|
|
||||||
internal D2R_ValueType d2r_signed_value_type_from_bit_size (U64 bit_size);
|
|
||||||
internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size);
|
|
||||||
internal D2R_ValueType d2r_float_type_from_bit_size (U64 bit_size);
|
|
||||||
|
|
||||||
internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type);
|
|
||||||
internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v);
|
|
||||||
internal D2R_ArithmeticType d2r_arithmetic_type_from_value_type(D2R_ValueType v);
|
|
||||||
internal B32 d2r_is_value_type_signed (D2R_ValueType v);
|
|
||||||
internal B32 d2r_is_value_type_integral(D2R_ValueType v);
|
|
||||||
internal B32 d2r_is_value_type_unsigned(D2R_ValueType v);
|
|
||||||
internal B32 d2r_is_value_type_float (D2R_ValueType v);
|
|
||||||
|
|
||||||
internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs);
|
|
||||||
internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v);
|
|
||||||
|
|
||||||
internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc);
|
|
||||||
internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
|
|
||||||
internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Expression Conversion
|
|
||||||
|
|
||||||
internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Raw *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out);
|
|
||||||
internal RDIM_Location d2r_transpile_expression (Arena *arena, DW_Raw *input, U64 image_base, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr);
|
|
||||||
internal RDIM_Location d2r_location_from_attrib (Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal RDIM_LocationCaseList d2r_locset_from_attrib (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal RDIM_LocationCaseList d2r_var_locset_from_tag (Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, DW_Raw *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Type Table
|
|
||||||
|
|
||||||
internal RDIM_Type * d2r_create_type (Arena *arena, D2R_TypeTable *type_table);
|
|
||||||
internal RDIM_Type * d2r_create_type_from_offset(Arena *arena, D2R_TypeTable *type_table, U64 info_off);
|
|
||||||
internal RDIM_Type * d2r_type_from_offset(D2R_TypeTable *type_table, U64 info_off);
|
|
||||||
internal RDIM_Type * d2r_type_from_attrib(D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Tag Iterator
|
|
||||||
|
|
||||||
internal D2R_TagIterator * d2r_tag_iterator_init(Arena *arena, DW_TagNode *root);
|
|
||||||
internal void d2r_tag_iterator_next(Arena *arena, D2R_TagIterator *iter);
|
|
||||||
internal void d2r_tag_iterator_skip_children (D2R_TagIterator *iter);
|
|
||||||
internal DW_TagNode * d2r_tag_iterator_parent_tag_node(D2R_TagIterator *iter);
|
|
||||||
internal DW_Tag d2r_tag_iterator_parent_tag (D2R_TagIterator *iter);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Type Conversion
|
|
||||||
|
|
||||||
internal void d2r_flag_converted_tag(DW_TagNode *tag_node);
|
|
||||||
internal B8 d2r_is_tag_converted (DW_TagNode *tag_node);
|
|
||||||
internal RDIM_Type * d2r_find_or_convert_type(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, Arch arch, DW_Tag tag, DW_AttribKind kind);
|
|
||||||
internal void d2r_convert_types(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, Arch arch, DW_TagNode *root);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ UDT Conversion
|
|
||||||
|
|
||||||
internal B8 d2r_is_udt_tag_converted (DW_TagNode *tag_node);
|
|
||||||
internal void d2r_flag_converted_udt_tag(DW_TagNode *tag_node);
|
|
||||||
internal void d2r_inline_anonymous_udt_member(Arena *arena, RDIM_UDT *top_udt, U64 base_off, RDIM_UDT *udt);
|
|
||||||
internal void d2r_convert_udts(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, DW_TagNode *root);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Symbol Conversion
|
|
||||||
|
|
||||||
internal RDIM_Scope * d2r_push_scope (Arena *arena, RDIM_ScopeChunkList *scopes, U64 scope_chunk_cap, D2R_TagFrame *tag_stack, Rng1U64List ranges);
|
|
||||||
internal RDIM_Type ** d2r_collect_proc_params(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_TagNode *cur_node, U64 *param_count_out);
|
|
||||||
internal Rng1U64List d2r_range_list_from_tag(Arena *arena, DW_Raw *input, DW_CompUnit *cu, U64 image_base, DW_Tag tag);
|
|
||||||
internal void d2r_convert_symbols(Arena *arena, D2R_TypeTable *type_table, DW_Raw *input, DW_CompUnit *cu, DW_Language cu_lang, U64 image_base, Arch arch, DW_TagNode *root, RDIM_Unit *unit_rdi);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Line Table Conversion
|
|
||||||
|
|
||||||
internal U64 d2r_hash_line_file(String8 dir_path, DW_LineFile *file);
|
|
||||||
internal void d2r_sort_ptrs(void **ptrs, U64 count, int (* is_before)(void *a, void *b));
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Contrib Map
|
|
||||||
|
|
||||||
internal D2R_CompUnitContribMap d2r_cu_contrib_map_from_aranges(Arena *arena, DW_Raw *input, U64 image_base);
|
|
||||||
internal RDIM_Rng1U64ChunkList d2r_voff_ranges_from_cu_info_off(D2R_CompUnitContribMap map, U64 info_off);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ Entry Point
|
|
||||||
|
|
||||||
internal RDIM_BakeParams d2r_convert(Arena *arena, D2R_ConvertParams *params);
|
|
||||||
|
|
||||||
#endif // RDI_FROM_DWARF_H
|
|
||||||
+86
-62
@@ -45,77 +45,101 @@ load_paths =
|
|||||||
|
|
||||||
commands =
|
commands =
|
||||||
{
|
{
|
||||||
//- rjf: [raddbg]
|
.rjf_f1 =
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg telemetry",
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build torture && build ryan_scratch && pushd build && torture eval2/* && ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
//- rjf: [raddbg wsl]
|
.save_dirty_files = true,
|
||||||
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
//- rjf: [scratch]
|
.rjf_f2 =
|
||||||
// .f2 = { .win = "pushd build && for /l %i in (1, 1, 3) do (radbin --rdi raddbg.exe --out:raddbg_%i.rdi && radbin --dump raddbg_%i.rdi --out:raddbg_%i.dump)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
.f2 = { .win = "pushd build && radbin --rdi raddbg.exe --thread_count=1 --out:1.rdi && radbin --rdi raddbg.exe --thread_count=8 --out:8.rdi && radbin --dump 1.rdi --out:1.dump && radbin --dump 8.rdi --out:8.dump)", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg_from_pdb",
|
||||||
|
.linux = "",
|
||||||
//- rjf: [textperf]
|
.out = "*compilation*",
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta telemetry textperf && raddbg_stable --ipc bring_to_front && raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
//- rjf: [tester]
|
.cursor_at_end = false,
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build no_meta tester", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
|
.rjf_f3 =
|
||||||
//- rjf: [radbin]
|
{
|
||||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "pushd build && raddbg.exe --user:local_dev.raddbg_user --profile:local_dev.raddbg_profile && popd",
|
||||||
|
.linux = "",
|
||||||
//- rjf: running target
|
.out = "*compilation*",
|
||||||
.f3 = { .win = "raddbg_stable --ipc run", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
// .f3 = { .win = "build torture", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
// .f3 = { .win = "wsl ./build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
// .f3 = { .win = "pushd build && raddbg --user:dev.raddbg_user && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
// .f3 = { .win = "C:/devel/raddebugger/build/raddbg.exe --capture --user:C:/devel/raddebugger/build/local_dev.raddbg_user --project:C:/devel/raddebugger/build/local_dev.raddbg_project", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.build_raddbg =
|
||||||
// .f3 = { .win = "wsl_launch /mnt/c/devel/raddebugger/build/raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
|
.win = "build raddbg",
|
||||||
//- rjf: local target builds
|
.linux = "",
|
||||||
.build_raddbg = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
.build_rdi_from_pdb = { .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
.build_rdi_from_dwarf = { .win = "build rdi_from_dwarf", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
.build_rdi_dump = { .win = "build rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
.build_rdi_breakpad_from_pdb = { .win = "build rdi_breakpad_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
.build_ryan_scratch = { .win = "build ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.build_raddbg_release_telemetry =
|
||||||
.build_mule_main = { .win = "build mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
.build_mule_module = { .win = "build mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg release telemetry",
|
||||||
.build_mule_hotload = { .win = "build mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.build_mule_peb_trample = { .win = "build mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
//- rjf: wsl target builds
|
.save_dirty_files = true,
|
||||||
.build_raddbg_wsl = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
.build_rdi_from_pdb_wsl = { .win = "wsl ./build.sh rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
},
|
||||||
.build_rdi_from_dwarf_wsl = { .win = "wsl ./build.sh rdi_from_dwarf", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.build_raddbg_from_pdb =
|
||||||
.build_rdi_dump_wsl = { .win = "wsl ./build.sh rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
.build_rdi_breakpad_from_pdb_wsl = { .win = "wsl ./build.sh rdi_breakpad_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.win = "build raddbg_from_pdb",
|
||||||
.build_ryan_scratch_wsl = { .win = "wsl ./build.sh ryan_scratch", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.linux = "",
|
||||||
.build_mule_main_wsl = { .win = "wsl ./build.sh mule_main", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.out = "*compilation*",
|
||||||
.build_mule_module_wsl = { .win = "wsl ./build.sh mule_module", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.footer_panel = true,
|
||||||
.build_mule_hotload_wsl = { .win = "wsl ./build.sh mule_hotload", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.save_dirty_files = true,
|
||||||
.build_mule_peb_trample_wsl = { .win = "wsl ./build.sh mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
//- rjf: local target runs
|
.build_raddbg_dump =
|
||||||
.run_raddbg = { .win = "pushd build && raddbg.exe && popd", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
{
|
||||||
|
.win = "build raddbg_dump",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
.build_mule_main =
|
||||||
|
{
|
||||||
|
.win = "build mule_main",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
|
.run_raddbg =
|
||||||
|
{
|
||||||
|
.win = "pushd build && raddbg.exe && popd",
|
||||||
|
.linux = "",
|
||||||
|
.out = "*compilation*",
|
||||||
|
.footer_panel = true,
|
||||||
|
.save_dirty_files = true,
|
||||||
|
.cursor_at_end = false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
fkey_command =
|
fkey_command =
|
||||||
{
|
{
|
||||||
.F1 = "f1",
|
.F1 = "build_raddbg",
|
||||||
.F2 = "f2",
|
.F3 = "run_raddbg",
|
||||||
.F3 = "f3",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fkey_command_override =
|
fkey_command_override =
|
||||||
{
|
{
|
||||||
.rjf =
|
.rjf =
|
||||||
{
|
{
|
||||||
.F1 = "f1",
|
.F1 = "rjf_f1",
|
||||||
.F2 = "f2",
|
.F2 = "rjf_f2",
|
||||||
.F3 = "f3",
|
.F3 = "rjf_f3",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
// raddbg 0.9.28 project file
|
|
||||||
|
|
||||||
name: "The RAD Debugger"
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/raddbg.exe"
|
|
||||||
working_directory: "../raddebugger"
|
|
||||||
arguments: "--user:C:/devel/raddebugger/build/raddbg_test.user"
|
|
||||||
debug_subprocesses: 0
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/raddbg.exe"
|
|
||||||
working_directory: "../raddebugger"
|
|
||||||
arguments: "--user:test123"
|
|
||||||
debug_subprocesses: 0
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/mule_main.exe"
|
|
||||||
working_directory: build
|
|
||||||
output_label: output_a
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/torture.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "eval2/*"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/metagen.exe"
|
|
||||||
working_directory: build
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/radbin.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "--rdi raddbg"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/release_version/raddbg.exe"
|
|
||||||
working_directory: "build/release_version"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/radbin.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "--rdi fat.so --capture"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/radbin.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "--rdi fat.debug --capture"
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/radbin.exe"
|
|
||||||
working_directory: build
|
|
||||||
arguments: "--rdi raddbg"
|
|
||||||
}
|
|
||||||
watch_pin: expression: tag_hash_slots
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "build/ryan_scratch.exe"
|
|
||||||
working_directory: build
|
|
||||||
enabled: 1
|
|
||||||
}
|
|
||||||
target:
|
|
||||||
{
|
|
||||||
executable: "../../Program Files/SuperTux/bin/supertux2.exe"
|
|
||||||
working_directory: "../../Program Files/SuperTux/bin"
|
|
||||||
}
|
|
||||||
-126
@@ -1,126 +0,0 @@
|
|||||||
@echo off
|
|
||||||
setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
set TARGET_VALUES=radlink radbin mule_main mule_module torture
|
|
||||||
set CC_VALUES=msvc clang
|
|
||||||
set MODE_VALUES=debug release
|
|
||||||
set RAW_ARGS=%*
|
|
||||||
set TORTURE_ARGS=
|
|
||||||
set RUN_TORTURE=1
|
|
||||||
|
|
||||||
:: Make test data directories
|
|
||||||
if not exist local mkdir local
|
|
||||||
pushd local
|
|
||||||
if not exist test_data mkdir test_data
|
|
||||||
popd
|
|
||||||
|
|
||||||
:: Check if we need new test data version
|
|
||||||
pushd local
|
|
||||||
set need_test_data=0
|
|
||||||
curl -sfL -o test_data_version_latest.txt https://data.raddbg.com/public/raddbg_test_data_version.txt || exit /b 1
|
|
||||||
if exist "test_data_version_current.txt" (
|
|
||||||
fc /b "test_data_version_latest.txt" "test_data_version_current.txt" > nul
|
|
||||||
) else (
|
|
||||||
echo Test data not present.
|
|
||||||
set need_test_data=1
|
|
||||||
)
|
|
||||||
if errorlevel 1 (
|
|
||||||
echo Test data out-of-date.
|
|
||||||
set need_test_data=1
|
|
||||||
)
|
|
||||||
popd
|
|
||||||
|
|
||||||
:: Download test data if stale
|
|
||||||
if "%need_test_data%"=="1" (
|
|
||||||
echo Downloading test data...
|
|
||||||
pushd local
|
|
||||||
pushd test_data
|
|
||||||
curl -sfL -o test_data.zip https://data.raddbg.com/public/raddbg_test_data.zip || exit /b 1
|
|
||||||
tar -xf test_data.zip || exit /b 1
|
|
||||||
del test_data.zip
|
|
||||||
popd
|
|
||||||
copy /y test_data_version_latest.txt test_data_version_current.txt
|
|
||||||
popd
|
|
||||||
)
|
|
||||||
popd
|
|
||||||
|
|
||||||
:parse_args
|
|
||||||
if "%~1" == "" goto parse_done
|
|
||||||
if "%~1" == "--" goto parse_torture_args
|
|
||||||
if /i "%~1" == "msvc" set CC_VALUES=msvc && shift /1 && goto parse_args
|
|
||||||
if /i "%~1" == "clang" set CC_VALUES=clang && shift /1 && goto parse_args
|
|
||||||
if /i "%~1" == "debug" set MODE_VALUES=debug && shift /1 && goto parse_args
|
|
||||||
if /i "%~1" == "release" set MODE_VALUES=release && shift /1 && goto parse_args
|
|
||||||
if /i "%~1" == "no_torture" set RUN_TORTURE=0 && shift /1 && goto parse_args
|
|
||||||
echo usage: %~nx0 [msvc^|clang] [debug^|release] [no_torture] [-- torture-args]
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:parse_torture_args
|
|
||||||
shift /1
|
|
||||||
if "%~1" == "" set "TORTURE_ARGS=" && goto parse_done
|
|
||||||
set "TORTURE_ARGS=%RAW_ARGS%"
|
|
||||||
if "%TORTURE_ARGS:~0,3%" == "-- " set "TORTURE_ARGS=%TORTURE_ARGS:~3%" && goto parse_done
|
|
||||||
set "TORTURE_ARGS=%TORTURE_ARGS:* -- =%"
|
|
||||||
|
|
||||||
:parse_done
|
|
||||||
if not defined TORTURE_ARGS set "TORTURE_ARGS=*
|
|
||||||
|
|
||||||
for %%m in (%MODE_VALUES%) do for %%c in (%CC_VALUES%) do (
|
|
||||||
setlocal
|
|
||||||
|
|
||||||
:: nuke artifacts from last run
|
|
||||||
if exist build/torture_artifacts rmdir /s /q build\torture_artifacts
|
|
||||||
if exist build\metagen.exe del /q build\metagen.exe
|
|
||||||
for %%t in (%TARGET_VALUES%) do (
|
|
||||||
if exist build\%%t.exe del /q build\%%t.exe
|
|
||||||
if exist build\%%t.pdb del /q build\%%t.pdb
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%%c" == "clang" (
|
|
||||||
:: Prefer standalone LLVM clang over Visual Studio clang so ASAN runtime files match the compiler.
|
|
||||||
set "clang_path="
|
|
||||||
for /f "tokens=*" %%i in ('where clang') do (
|
|
||||||
set "candidate_clang_path=%%~dpi"
|
|
||||||
if "!candidate_clang_path:Microsoft Visual Studio=!"=="!candidate_clang_path!" (
|
|
||||||
if not defined clang_path set "clang_path=!candidate_clang_path!"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if not defined clang_path (
|
|
||||||
echo ERROR: standalone LLVM clang not found in PATH
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
set PATH=!clang_path!;!PATH!
|
|
||||||
for /f "tokens=3 delims=. " %%v in ('clang -v 2^>^&1 ^| findstr version') do set clang_version=%%v
|
|
||||||
if not defined clang_version (
|
|
||||||
echo ERROR: failed to detect clang version
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
set PATH=!clang_path!..\lib\clang\!clang_version!\lib\windows;!PATH!
|
|
||||||
)
|
|
||||||
|
|
||||||
:: TODO: unblock asan
|
|
||||||
call build.bat meta %%c %%m raddbg raddbg_non_graphical || (endlocal exit /b 1)
|
|
||||||
|
|
||||||
:: clang does not compile with asan in release mode because it runs out of memory
|
|
||||||
if "%%c" equ "clang" (
|
|
||||||
if /i "%%m" equ "release" (
|
|
||||||
call build.bat no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
|
|
||||||
) else (
|
|
||||||
call build.bat asan no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
call build.bat asan no_meta %%c %%m !TARGET_VALUES! || (endlocal exit /b 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%RUN_TORTURE%" equ "1" (
|
|
||||||
pushd build
|
|
||||||
torture %TORTURE_ARGS%
|
|
||||||
popd
|
|
||||||
if errorlevel 1 (
|
|
||||||
endlocal
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
endlocal
|
|
||||||
)
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -eu
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
target_values=(raddbg raddbg_non_graphical radlink radbin torture)
|
|
||||||
cc_values=(clang gcc)
|
|
||||||
mode_values=(debug release)
|
|
||||||
run_torture=1
|
|
||||||
torture_args=()
|
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
torture_args=("$@")
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
clang)
|
|
||||||
cc_values=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
gcc)
|
|
||||||
cc_values=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
debug|release)
|
|
||||||
mode_values=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
no_torture)
|
|
||||||
run_torture=0
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "usage: $0 [clang|gcc] [debug|release] [no_torture] [-- torture-args]"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "${#torture_args[@]}" == "0" ]]; then
|
|
||||||
torture_args=("*")
|
|
||||||
fi
|
|
||||||
|
|
||||||
for m in "${mode_values[@]}"; do
|
|
||||||
for c in "${cc_values[@]}"; do
|
|
||||||
# nuke artifacts from last run
|
|
||||||
rm -rf build/torture_artifacts
|
|
||||||
rm -f build/metagen
|
|
||||||
for t in "${target_values[@]}"; do
|
|
||||||
rm -f "build/$t"
|
|
||||||
done
|
|
||||||
|
|
||||||
# build targets
|
|
||||||
./build.sh meta "$c" "$m" "${target_values[@]}"
|
|
||||||
|
|
||||||
# run torture from build folder
|
|
||||||
if [[ "$run_torture" == "1" ]]; then
|
|
||||||
torture_compiler_args=()
|
|
||||||
has_clang_arg=0
|
|
||||||
has_gcc_arg=0
|
|
||||||
for arg in "${torture_args[@]}"; do
|
|
||||||
case "$arg" in
|
|
||||||
-clang:*|--clang:*) has_clang_arg=1 ;;
|
|
||||||
-gcc:*|--gcc:*) has_gcc_arg=1 ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
if [[ "$c" == clang && "$has_clang_arg" == "0" ]]; then
|
|
||||||
torture_compiler_args=("-clang:$(command -v "${CC:-clang}")")
|
|
||||||
elif [[ "$c" == gcc && "$has_gcc_arg" == "0" ]]; then
|
|
||||||
torture_compiler_args=("-gcc:$(command -v "${CC:-gcc}")")
|
|
||||||
fi
|
|
||||||
(cd build && ./torture "${torture_compiler_args[@]}" "${torture_args[@]}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
done
|
|
||||||
@@ -4,6 +4,7 @@ $path_root = git rev-parse --show-toplevel
|
|||||||
|
|
||||||
if ($IsWindows) {
|
if ($IsWindows) {
|
||||||
$devshell = Join-Path $path_root 'scripts/helpers/devshell.ps1'
|
$devshell = Join-Path $path_root 'scripts/helpers/devshell.ps1'
|
||||||
|
# This HandmadeHero implementation is only designed for 64-bit systems
|
||||||
& $devshell -arch amd64
|
& $devshell -arch amd64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-174
@@ -1,174 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Abstracted Architecture Functions
|
|
||||||
|
|
||||||
internal ARCH_Info *
|
|
||||||
arch_info_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
ARCH_Info *result = &arch_info_nil;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
#if defined(X64_H)
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
local_persist U8 trap_inst_bytes[] = {0xcc};
|
|
||||||
local_persist read_only ARCH_Info info =
|
|
||||||
{
|
|
||||||
.reg_block_size = sizeof(X64_RegBlock),
|
|
||||||
.instruction_pointer_reg_code = X64_RegCode_rip,
|
|
||||||
.stack_pointer_reg_code = X64_RegCode_rsp,
|
|
||||||
.reg_code_count = X64_RegCode_COUNT,
|
|
||||||
.trap_instruction = {trap_inst_bytes, sizeof(trap_inst_bytes)},
|
|
||||||
.reg_code_rng_table = x64_reg_code_rng_table,
|
|
||||||
.reg_code_name_table = x64_reg_code_name_table,
|
|
||||||
.reg_code_base_table = x64_reg_code_base_table,
|
|
||||||
.reg_code_is_vector_table = x64_reg_code_is_vector_table,
|
|
||||||
};
|
|
||||||
result = &info;
|
|
||||||
}break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal ARCH_RegCode
|
|
||||||
arch_reg_code_from_name(ARCH_Info *arch_info, String8 name)
|
|
||||||
{
|
|
||||||
ARCH_RegCode result = 0;
|
|
||||||
for EachIndex(code, arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
if(str8_match(arch_info->reg_code_name_table[code], name, 0))
|
|
||||||
{
|
|
||||||
result = code;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
{
|
|
||||||
Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size);
|
|
||||||
Rng1U16 try_range = range;
|
|
||||||
Rng1U16 read_range = intersect_1u16(legal_range, try_range);
|
|
||||||
U64 read_size = dim_1u16(read_range);
|
|
||||||
if(read_size != 0)
|
|
||||||
{
|
|
||||||
MemoryCopy(dst, (U8 *)block + read_range.min, read_size);
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
Rng1U16 legal_range = r1u16(0, arch_info->reg_block_size);
|
|
||||||
Rng1U16 try_range = range;
|
|
||||||
Rng1U16 write_range = intersect_1u16(legal_range, try_range);
|
|
||||||
U64 write_size = dim_1u16(write_range);
|
|
||||||
if(write_size != 0)
|
|
||||||
{
|
|
||||||
MemoryCopy((U8 *)block + write_range.min, src, write_size);
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
arch_ip_from_reg_block(ARCH_Info *arch_info, void *block)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code;
|
|
||||||
if(reg_code < arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
arch_sp_from_reg_block(ARCH_Info *arch_info, void *block)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code;
|
|
||||||
if(reg_code < arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
arch_reg_block_read_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
ARCH_RegCode reg_code = arch_info->instruction_pointer_reg_code;
|
|
||||||
if(reg_code < arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &ip);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
ARCH_RegCode reg_code = arch_info->stack_pointer_reg_code;
|
|
||||||
if(reg_code < arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
result = arch_reg_block_write_range(arch_info, block, arch_info->reg_code_rng_table[reg_code], &sp);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(RDI_H)
|
|
||||||
internal ARCH_RegCode
|
|
||||||
arch_reg_code_from_rdi(Arch arch, RDI_RegCode code)
|
|
||||||
{
|
|
||||||
ARCH_RegCode result = 0;
|
|
||||||
{
|
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
|
||||||
U8 *rdi_from_reg_code_table = arch_rdi_from_reg_code_table_from_arch(arch);
|
|
||||||
for EachIndex(c, arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
if(rdi_from_reg_code_table[c] == code)
|
|
||||||
{
|
|
||||||
result = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(DWARF_H)
|
|
||||||
internal ARCH_RegCode
|
|
||||||
arch_reg_code_from_dw(Arch arch, DW_RegCode code)
|
|
||||||
{
|
|
||||||
ARCH_RegCode result = 0;
|
|
||||||
{
|
|
||||||
ARCH_Info *arch_info = arch_info_from_arch(arch);
|
|
||||||
U8 *dw_from_reg_code_table = arch_dw_from_reg_code_table_from_arch(arch);
|
|
||||||
for EachIndex(c, arch_info->reg_code_count)
|
|
||||||
{
|
|
||||||
if(dw_from_reg_code_table[c] == code)
|
|
||||||
{
|
|
||||||
result = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_H
|
|
||||||
#define ARCH_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Abstraction Backend Info
|
|
||||||
|
|
||||||
typedef U8 ARCH_RegCode;
|
|
||||||
|
|
||||||
typedef struct ARCH_Info ARCH_Info;
|
|
||||||
struct ARCH_Info
|
|
||||||
{
|
|
||||||
U16 reg_block_size;
|
|
||||||
ARCH_RegCode instruction_pointer_reg_code;
|
|
||||||
ARCH_RegCode stack_pointer_reg_code;
|
|
||||||
U16 reg_code_count;
|
|
||||||
String8 trap_instruction;
|
|
||||||
Rng1U16 *reg_code_rng_table;
|
|
||||||
String8 *reg_code_name_table;
|
|
||||||
U8 *reg_code_base_table;
|
|
||||||
B8 *reg_code_is_vector_table;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
global read_only Rng1U16 arch_reg_code_rng_nil = {0};
|
|
||||||
global read_only String8 arch_reg_code_name_nil = {0};
|
|
||||||
global read_only U8 arch_reg_code_u8_nil = 0;
|
|
||||||
global read_only B8 arch_reg_code_b8_nil = 0;
|
|
||||||
global read_only ARCH_Info arch_info_nil = {0, 0, 0, 0, {0}, &arch_reg_code_rng_nil, &arch_reg_code_name_nil, &arch_reg_code_u8_nil, &arch_reg_code_b8_nil};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Abstracted Architecture Functions
|
|
||||||
|
|
||||||
internal ARCH_Info *arch_info_from_arch(Arch arch);
|
|
||||||
internal ARCH_RegCode arch_reg_code_from_name(ARCH_Info *arch_info, String8 name);
|
|
||||||
internal B32 arch_reg_block_read_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *dst);
|
|
||||||
internal B32 arch_reg_block_write_range(ARCH_Info *arch_info, void *block, Rng1U16 range, void *src);
|
|
||||||
internal U64 arch_ip_from_reg_block(ARCH_Info *arch_info, void *block);
|
|
||||||
internal U64 arch_sp_from_reg_block(ARCH_Info *arch_info, void *block);
|
|
||||||
internal B32 arch_reg_block_write_ip(ARCH_Info *arch_info, void *block, U64 ip);
|
|
||||||
internal B32 arch_reg_block_write_sp(ARCH_Info *arch_info, void *block, U64 sp);
|
|
||||||
|
|
||||||
#if defined(RDI_H)
|
|
||||||
internal ARCH_RegCode arch_reg_code_from_rdi(Arch arch, RDI_RegCode code);
|
|
||||||
#endif
|
|
||||||
#if defined(DWARF_H)
|
|
||||||
internal ARCH_RegCode arch_reg_code_from_dw(Arch arch, DW_RegCode code);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // REGS_H
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#include "arch/arch.c"
|
|
||||||
#include "arch/os/arch_os.c"
|
|
||||||
#if defined(DWARF_H)
|
|
||||||
# include "arch/dwarf/arch_dwarf.c"
|
|
||||||
#endif
|
|
||||||
#if defined(RDI_H)
|
|
||||||
# include "arch/rdi/arch_rdi.c"
|
|
||||||
#endif
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_INC_H
|
|
||||||
#define ARCH_INC_H
|
|
||||||
|
|
||||||
#include "arch/arch.h"
|
|
||||||
#include "arch/os/arch_os.h"
|
|
||||||
#if defined(DWARF_H)
|
|
||||||
# include "arch/dwarf/arch_dwarf.h"
|
|
||||||
#endif
|
|
||||||
#if defined(RDI_H)
|
|
||||||
# include "arch/rdi/arch_rdi.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ARCH_INC_H
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal U8 *
|
|
||||||
arch_dw_from_reg_code_table_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
U8 *result = &arch_reg_code_u8_nil;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
#if defined(X64_H)
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
result = dw_reg_code_from_x64_table;
|
|
||||||
}break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_DWARF_H
|
|
||||||
#define ARCH_DWARF_H
|
|
||||||
|
|
||||||
internal U8 *arch_dw_from_reg_code_table_from_arch(Arch arch);
|
|
||||||
|
|
||||||
#endif // ARCH_DWARF_H
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
arch_os_write_reg_block_from_thread_ctx(Arch arch, OperatingSystem os, void *reg_block, void *thread_ctx)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
if(0){}
|
|
||||||
#define Case(arch_, os_, impl) else if((arch) == arch_ && (os) == os_) do {result = impl(reg_block, thread_ctx);}while(0)
|
|
||||||
#if defined(X64_H) && defined(WIN32_X64_H)
|
|
||||||
Case(Arch_x64, OperatingSystem_Windows, w32_x64_write_reg_block_from_thread_ctx);
|
|
||||||
#endif
|
|
||||||
#undef Case
|
|
||||||
else{}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_OS_H
|
|
||||||
#define ARCH_OS_H
|
|
||||||
|
|
||||||
internal B32 arch_os_write_reg_block_from_thread_ctx(Arch arch, OperatingSystem os, void *reg_block, void *thread_ctx);
|
|
||||||
|
|
||||||
#endif // ARCH_OS_H
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal U8 *
|
|
||||||
arch_rdi_from_reg_code_table_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
U8 *result = &arch_reg_code_u8_nil;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
#if defined(X64_H)
|
|
||||||
case Arch_x64:
|
|
||||||
{
|
|
||||||
result = rdi_reg_code_from_x64_table;
|
|
||||||
}break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARCH_RDI_H
|
|
||||||
#define ARCH_RDI_H
|
|
||||||
|
|
||||||
internal U8 *arch_rdi_from_reg_code_table_from_arch(Arch arch);
|
|
||||||
|
|
||||||
#endif // ARCH_RDI_H
|
|
||||||
@@ -1,735 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Layer Initialization
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_init(void)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
ac_shared = push_array(arena, AC_Shared, 1);
|
|
||||||
ac_shared->arena = arena;
|
|
||||||
ac_shared->cache_slots_count = 256;
|
|
||||||
ac_shared->cache_slots = push_array(arena, AC_Cache *, ac_shared->cache_slots_count);
|
|
||||||
ac_shared->cache_stripes = stripe_array_alloc(arena);
|
|
||||||
for EachElement(idx, ac_shared->req_batches)
|
|
||||||
{
|
|
||||||
ac_shared->req_batches[idx].mutex = mutex_alloc();
|
|
||||||
ac_shared->req_batches[idx].arena = arena_alloc();
|
|
||||||
}
|
|
||||||
ac_shared->cancel_thread_semaphore = semaphore_alloc(0, 1, str8_zero());
|
|
||||||
ac_shared->cancel_thread = thread_launch(ac_cancel_thread_entry_point, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Lookups
|
|
||||||
|
|
||||||
internal AC_Artifact
|
|
||||||
ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
AC_RequestBatch *req_batch = &ac_shared->req_batches[params->flags & AC_Flag_HighPriority ? 0 : 1];
|
|
||||||
|
|
||||||
//- rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(¶ms->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == params->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(write_mode && cache == 0)
|
|
||||||
{
|
|
||||||
cache = push_array(cache_stripe->arena, AC_Cache, 1);
|
|
||||||
SLLStackPush(ac_shared->cache_slots[cache_slot_idx], cache);
|
|
||||||
cache->create = params->create;
|
|
||||||
cache->destroy = params->destroy;
|
|
||||||
cache->slots_count = Max(256, params->slots_count);
|
|
||||||
cache->slots = push_array(cache_stripe->arena, AC_Slot, cache->slots_count);
|
|
||||||
cache->stripes = stripe_array_alloc(cache_stripe->arena);
|
|
||||||
cache->stripe_free_node_ptrs = push_array(cache_stripe->arena, AC_NodePtr *, cache->stripes.count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(cache != 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: unpack key
|
|
||||||
U64 hash = u64_hash_from_str8(key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
|
|
||||||
//- rjf: unpack thread context
|
|
||||||
B32 is_node_work_active = (ac_tctx != 0);
|
|
||||||
|
|
||||||
//- rjf: cache * key -> existing artifact
|
|
||||||
B32 artifact_is_stale = 1;
|
|
||||||
B32 got_artifact = 0;
|
|
||||||
B32 need_request = 0;
|
|
||||||
AC_Artifact artifact = {0};
|
|
||||||
RWMutexScope(stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, key, 0))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(&n->last_requested_gen, params->gen);
|
|
||||||
B32 is_stale = (n->last_completed_gen != params->gen);
|
|
||||||
if(ins_atomic_u64_eval(&n->completion_count) != 0 && (!is_stale || !(params->flags & AC_Flag_WaitForFresh)))
|
|
||||||
{
|
|
||||||
got_artifact = 1;
|
|
||||||
artifact_is_stale = is_stale;
|
|
||||||
artifact = n->val;
|
|
||||||
access_touch(access, &n->access_pt, stripe->cv);
|
|
||||||
ins_atomic_u64_eval_assign(&n->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
|
|
||||||
}
|
|
||||||
if(is_stale)
|
|
||||||
{
|
|
||||||
B32 got_task = (ins_atomic_u64_eval_cond_assign(&n->working_count, 1, 0) == 0);
|
|
||||||
need_request = got_task;
|
|
||||||
if(is_node_work_active)
|
|
||||||
{
|
|
||||||
ins_atomic_u32_eval_assign(&n->other_nodes_depend_on_me, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: didn't get artifact we want? -> fall back to slow path
|
|
||||||
if(!got_artifact || need_request)
|
|
||||||
{
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1) for(;;)
|
|
||||||
{
|
|
||||||
B32 out_of_time = (now_time_us() >= endt_us);
|
|
||||||
|
|
||||||
// rjf: find node in cache
|
|
||||||
AC_Node *node = 0;
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, key, 0))
|
|
||||||
{
|
|
||||||
node = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: no node? -> create
|
|
||||||
if(node == 0)
|
|
||||||
{
|
|
||||||
need_request = 1;
|
|
||||||
node = stripe->free;
|
|
||||||
if(node)
|
|
||||||
{
|
|
||||||
stripe->free = node->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = push_array_no_zero(stripe->arena, AC_Node, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(node);
|
|
||||||
DLLPushBack(slot->first, slot->last, node);
|
|
||||||
// TODO(rjf): string allocator for keys
|
|
||||||
node->key = str8_copy(stripe->arena, key);
|
|
||||||
node->working_count = 1;
|
|
||||||
node->evict_threshold_us = params->evict_threshold_us;
|
|
||||||
if(is_node_work_active)
|
|
||||||
{
|
|
||||||
node->other_nodes_depend_on_me = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node->access_pt.last_time_touched_us = now_time_us();
|
|
||||||
node->access_pt.last_update_idx_touched = update_tick_idx();
|
|
||||||
|
|
||||||
// rjf: request
|
|
||||||
if(need_request)
|
|
||||||
{
|
|
||||||
need_request = 0;
|
|
||||||
MutexScope(req_batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(req_batch->arena, AC_RequestNode, 1);
|
|
||||||
if(params->flags & AC_Flag_Wide)
|
|
||||||
{
|
|
||||||
SLLQueuePush(req_batch->first_wide, req_batch->last_wide, n);
|
|
||||||
req_batch->wide_count += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SLLQueuePush(req_batch->first_thin, req_batch->last_thin, n);
|
|
||||||
req_batch->thin_count += 1;
|
|
||||||
}
|
|
||||||
n->v.key = str8_copy(req_batch->arena, key);
|
|
||||||
n->v.gen = params->gen;
|
|
||||||
n->v.cancel_signal = &node->cancelled;
|
|
||||||
n->v.create = params->create;
|
|
||||||
}
|
|
||||||
cond_var_broadcast(async_tick_start_cond_var);
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
if(params->flags & AC_Flag_HighPriority)
|
|
||||||
{
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: get value from node, if possible
|
|
||||||
if(!got_artifact && ins_atomic_u64_eval(&node->completion_count) != 0 && ((node->last_completed_gen == params->gen) || !(params->flags & AC_Flag_WaitForFresh) || out_of_time))
|
|
||||||
{
|
|
||||||
got_artifact = 1;
|
|
||||||
artifact_is_stale = (node->last_completed_gen != params->gen);
|
|
||||||
artifact = node->val;
|
|
||||||
access_touch(access, &node->access_pt, stripe->cv);
|
|
||||||
ins_atomic_u64_eval_assign(&node->last_touched_ac_request_gen, ins_atomic_u64_eval(&ac_shared->request_gen));
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: abort if needed
|
|
||||||
if(out_of_time || got_artifact || is_async_thread)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: wait for results
|
|
||||||
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, endt_us);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: report staleness
|
|
||||||
if(params->stale_out)
|
|
||||||
{
|
|
||||||
params->stale_out[0] = artifact_is_stale;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
return artifact;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Asynchronous Tick
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_async_tick(void)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: enable cancellation scanning
|
|
||||||
//
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
semaphore_drop(ac_shared->cancel_thread_semaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: do eviction pass across all caches
|
|
||||||
//
|
|
||||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
|
||||||
{
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
|
|
||||||
{
|
|
||||||
Rng1U64 slot_range = lane_range(cache->slots_count);
|
|
||||||
for EachInRange(slot_idx, slot_range)
|
|
||||||
{
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
B32 slot_has_work = 0;
|
|
||||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
|
||||||
{
|
|
||||||
next = n->next;
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) &&
|
|
||||||
ins_atomic_u64_eval(&n->working_count) == 0 &&
|
|
||||||
(ins_atomic_u32_eval(&n->other_nodes_depend_on_me) == 0 || ac_shared->request_gen > n->last_touched_ac_request_gen))
|
|
||||||
{
|
|
||||||
slot_has_work = 1;
|
|
||||||
if(!write_mode)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DLLRemove(slot->first, slot->last, n);
|
|
||||||
n->next = (AC_Node *)stripe->free;
|
|
||||||
stripe->free = n;
|
|
||||||
if(cache->destroy)
|
|
||||||
{
|
|
||||||
cache->destroy(n->val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!slot_has_work)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: gather requests
|
|
||||||
//
|
|
||||||
typedef struct RequestBatchTask RequestBatchTask;
|
|
||||||
struct RequestBatchTask
|
|
||||||
{
|
|
||||||
AC_Request *wide;
|
|
||||||
U64 wide_count;
|
|
||||||
AC_Request *thin;
|
|
||||||
U64 thin_count;
|
|
||||||
};
|
|
||||||
RequestBatchTask *tasks = 0;
|
|
||||||
U64 tasks_count = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
tasks_count = 2;
|
|
||||||
tasks = push_array(scratch.arena, RequestBatchTask, tasks_count);
|
|
||||||
for EachElement(task_idx, ac_shared->req_batches)
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
tasks[task_idx].wide_count = batch->wide_count;
|
|
||||||
tasks[task_idx].thin_count = batch->thin_count;
|
|
||||||
tasks[task_idx].wide = push_array(scratch.arena, AC_Request, tasks[task_idx].wide_count);
|
|
||||||
tasks[task_idx].thin = push_array(scratch.arena, AC_Request, tasks[task_idx].thin_count);
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for EachNode(n, AC_RequestNode, batch->first_wide)
|
|
||||||
{
|
|
||||||
MemoryCopyStruct(&tasks[task_idx].wide[idx], &n->v);
|
|
||||||
tasks[task_idx].wide[idx].key = str8_copy(scratch.arena, tasks[task_idx].wide[idx].key);
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for EachNode(n, AC_RequestNode, batch->first_thin)
|
|
||||||
{
|
|
||||||
MemoryCopyStruct(&tasks[task_idx].thin[idx], &n->v);
|
|
||||||
tasks[task_idx].thin[idx].key = str8_copy(scratch.arena, tasks[task_idx].thin[idx].key);
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arena_clear(batch->arena);
|
|
||||||
batch->first_wide = batch->last_wide = batch->first_thin = batch->last_thin = 0;
|
|
||||||
batch->wide_count = batch->thin_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync_u64(&tasks, 0);
|
|
||||||
lane_sync_u64(&tasks_count, 0);
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: set up artifact cache thread context
|
|
||||||
//
|
|
||||||
ac_tctx = push_array(scratch.arena, AC_TCTX, 1);
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: do all requests
|
|
||||||
//
|
|
||||||
for EachIndex(task_idx, tasks_count)
|
|
||||||
{
|
|
||||||
lane_sync();
|
|
||||||
RequestBatchTask *task = &tasks[task_idx];
|
|
||||||
|
|
||||||
//- rjf: set up cancellation signal
|
|
||||||
U64 cancelled = 0;
|
|
||||||
U64 *cancelled_ptr = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
cancelled_ptr = &cancelled;
|
|
||||||
}
|
|
||||||
lane_sync_u64(&cancelled_ptr, 0);
|
|
||||||
|
|
||||||
//- rjf: do all wide requests for this priority
|
|
||||||
U64 done_wide_count = 0;
|
|
||||||
ProfScope("wide requests (p%I64u)", task_idx)
|
|
||||||
{
|
|
||||||
for EachIndex(idx, task->wide_count)
|
|
||||||
{
|
|
||||||
lane_sync();
|
|
||||||
AC_Request *r = &task->wide[idx];
|
|
||||||
|
|
||||||
// rjf: any new higher priority tasks? -> cancel
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
if(task_idx == 1 && idx != 0 && ins_atomic_u32_eval(&async_loop_again_high_priority))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
// rjf: cancelled? -> exit
|
|
||||||
if(ins_atomic_u32_eval(cancelled_ptr))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: compute val
|
|
||||||
AC_Status status = AC_Status_Good;
|
|
||||||
U64 gen = r->gen;
|
|
||||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &status, &gen);
|
|
||||||
|
|
||||||
// rjf: retry? -> resubmit request
|
|
||||||
if(status == AC_Status_NeedRetry && lane_idx() == 0 && !ins_atomic_u32_eval(r->cancel_signal))
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_wide, batch->last_wide, n);
|
|
||||||
batch->wide_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
if(status != AC_Status_NeedRetry && lane_idx() == 0)
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == r->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: write value into cache
|
|
||||||
if(status != AC_Status_NeedRetry && lane_idx() == 0)
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(r->key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, r->key, 0))
|
|
||||||
{
|
|
||||||
B32 got_new_value = (status == AC_Status_Good);
|
|
||||||
|
|
||||||
// rjf: eliminate existing values, if any, if they do not match the current
|
|
||||||
if(got_new_value && cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
|
|
||||||
{
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
|
|
||||||
{
|
|
||||||
cache->destroy(n->val);
|
|
||||||
MemoryZeroStruct(&n->val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: write new value
|
|
||||||
if(got_new_value)
|
|
||||||
{
|
|
||||||
n->val = val;
|
|
||||||
}
|
|
||||||
n->last_completed_gen = gen;
|
|
||||||
ins_atomic_u64_dec_eval(&n->working_count);
|
|
||||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cond_var_broadcast(stripe->cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: increment count
|
|
||||||
lane_sync();
|
|
||||||
done_wide_count += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//- rjf: do all thin requests for this priority
|
|
||||||
U64 done_thin_count = 0;
|
|
||||||
ProfScope("thin requests (p%I64u)", task_idx)
|
|
||||||
{
|
|
||||||
U64 req_take_counter = 0;
|
|
||||||
U64 *req_take_counter_ptr = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
req_take_counter_ptr = &req_take_counter;
|
|
||||||
}
|
|
||||||
lane_sync_u64(&req_take_counter_ptr, 0);
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// rjf: any new higher priority tasks? -> cancel
|
|
||||||
if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2 &&
|
|
||||||
ins_atomic_u32_eval(&async_loop_again_high_priority))
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: cancelled? -> exit
|
|
||||||
if(ins_atomic_u64_eval(cancelled_ptr))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: take next task
|
|
||||||
U64 req_idx = ins_atomic_u64_inc_eval(req_take_counter_ptr) - 1;
|
|
||||||
if(req_idx >= task->thin_count) { break; }
|
|
||||||
AC_Request *r = &task->thin[req_idx];
|
|
||||||
|
|
||||||
// rjf: push thin lane ctx
|
|
||||||
U64 thin_lane_ctx_broadcast_memory = 0;
|
|
||||||
LaneCtx thin_lane_ctx = {0, 1, {0}, &thin_lane_ctx_broadcast_memory};
|
|
||||||
LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx);
|
|
||||||
|
|
||||||
// rjf: compute val
|
|
||||||
AC_Status status = AC_Status_Good;
|
|
||||||
U64 gen = r->gen;
|
|
||||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &status, &gen);
|
|
||||||
|
|
||||||
// rjf: restore wide lane ctx
|
|
||||||
lane_ctx(lane_ctx_restore);
|
|
||||||
|
|
||||||
// rjf: retry? -> resubmit request
|
|
||||||
if(status == AC_Status_NeedRetry && !ins_atomic_u32_eval(r->cancel_signal))
|
|
||||||
{
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_thin, batch->last_thin, n);
|
|
||||||
batch->thin_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: create function -> cache
|
|
||||||
AC_Cache *cache = 0;
|
|
||||||
if(status != AC_Status_NeedRetry)
|
|
||||||
{
|
|
||||||
U64 cache_hash = u64_hash_from_str8(str8_struct(&r->create));
|
|
||||||
U64 cache_slot_idx = cache_hash%ac_shared->cache_slots_count;
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for(AC_Cache *c = ac_shared->cache_slots[cache_slot_idx]; c != 0; c = c->next)
|
|
||||||
{
|
|
||||||
if(c->create == r->create)
|
|
||||||
{
|
|
||||||
cache = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: write value into cache
|
|
||||||
if(status != AC_Status_NeedRetry)
|
|
||||||
{
|
|
||||||
U64 hash = u64_hash_from_str8(r->key);
|
|
||||||
U64 slot_idx = hash%cache->slots_count;
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
RWMutexScope(stripe->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->key, r->key, 0))
|
|
||||||
{
|
|
||||||
B32 got_new_value = (status == AC_Status_Good);
|
|
||||||
|
|
||||||
// rjf: eliminate existing values, if any, if they do not match the current
|
|
||||||
if(got_new_value && cache->destroy != 0 && !MemoryMatchStruct(&n->val, &val) && ins_atomic_u64_eval(&n->completion_count) > 0) for(;;)
|
|
||||||
{
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = 0, .update_idxs = 0))
|
|
||||||
{
|
|
||||||
cache->destroy(n->val);
|
|
||||||
MemoryZeroStruct(&n->val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cond_var_wait_rw(stripe->cv, stripe->rw_mutex, 1, max_U64);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: store
|
|
||||||
if(got_new_value)
|
|
||||||
{
|
|
||||||
n->val = val;
|
|
||||||
}
|
|
||||||
n->last_completed_gen = gen;
|
|
||||||
ins_atomic_u64_dec_eval(&n->working_count);
|
|
||||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cond_var_broadcast(stripe->cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
done_thin_count = ins_atomic_u64_eval(req_take_counter_ptr);
|
|
||||||
lane_sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: cancelled early, unfinished tasks? -> defer to next tick
|
|
||||||
if(lane_idx() == 0 && task_idx > 0)
|
|
||||||
{
|
|
||||||
B32 need_another_try = (done_wide_count < task->wide_count || done_thin_count < task->thin_count);
|
|
||||||
AC_RequestBatch *batch = &ac_shared->req_batches[task_idx];
|
|
||||||
MutexScope(batch->mutex)
|
|
||||||
{
|
|
||||||
// rjf: push leftover wide tasks
|
|
||||||
for(U64 idx = done_wide_count; idx < task->wide_count; idx += 1)
|
|
||||||
{
|
|
||||||
AC_Request *r = &task->wide[idx];
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_wide, batch->last_wide, n);
|
|
||||||
batch->wide_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push leftover thin tasks
|
|
||||||
for(U64 idx = done_thin_count; idx < task->thin_count; idx += 1)
|
|
||||||
{
|
|
||||||
AC_Request *r = &task->thin[idx];
|
|
||||||
AC_RequestNode *n = push_array(batch->arena, AC_RequestNode, 1);
|
|
||||||
SLLQueuePush(batch->first_thin, batch->last_thin, n);
|
|
||||||
batch->thin_count += 1;
|
|
||||||
MemoryCopyStruct(&n->v, r);
|
|
||||||
n->v.key = str8_copy(batch->arena, n->v.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(need_another_try)
|
|
||||||
{
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: increment the request gen, only if all requests are empty
|
|
||||||
//
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
B32 have_live_requests = 0;
|
|
||||||
for EachElement(idx, ac_shared->req_batches)
|
|
||||||
{
|
|
||||||
MutexScope(ac_shared->req_batches[idx].mutex)
|
|
||||||
{
|
|
||||||
have_live_requests = (ac_shared->req_batches[idx].wide_count != 0 || ac_shared->req_batches[idx].thin_count != 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!have_live_requests)
|
|
||||||
{
|
|
||||||
ac_shared->request_gen += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: reset thread context
|
|
||||||
//
|
|
||||||
ac_tctx = 0;
|
|
||||||
|
|
||||||
//////////////////////////////
|
|
||||||
//- rjf: disable cancellation scanning
|
|
||||||
//
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cancel Thread
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ac_cancel_thread_entry_point(void *p)
|
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
sleep_ms(50);
|
|
||||||
semaphore_take(ac_shared->cancel_thread_semaphore, max_U64);
|
|
||||||
{
|
|
||||||
for EachIndex(cache_slot_idx, ac_shared->cache_slots_count)
|
|
||||||
{
|
|
||||||
Stripe *cache_stripe = stripe_from_slot_idx(&ac_shared->cache_stripes, cache_slot_idx);
|
|
||||||
RWMutexScope(cache_stripe->rw_mutex, 0)
|
|
||||||
{
|
|
||||||
for EachNode(cache, AC_Cache, ac_shared->cache_slots[cache_slot_idx])
|
|
||||||
{
|
|
||||||
Rng1U64 slot_range = lane_range(cache->slots_count);
|
|
||||||
for EachInRange(slot_idx, slot_range)
|
|
||||||
{
|
|
||||||
AC_Slot *slot = &cache->slots[slot_idx];
|
|
||||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
|
||||||
for(B32 write_mode = 0; write_mode <= 1; write_mode += 1)
|
|
||||||
{
|
|
||||||
B32 slot_has_work = 0;
|
|
||||||
RWMutexScope(stripe->rw_mutex, write_mode)
|
|
||||||
{
|
|
||||||
for(AC_Node *n = slot->first, *next = 0; n != 0; n = next)
|
|
||||||
{
|
|
||||||
next = n->next;
|
|
||||||
if(access_pt_is_expired(&n->access_pt, .time = n->evict_threshold_us) && ins_atomic_u64_eval(&n->working_count) > 0)
|
|
||||||
{
|
|
||||||
slot_has_work = 1;
|
|
||||||
if(!write_mode)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n->cancelled = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!slot_has_work)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
semaphore_drop(ac_shared->cancel_thread_semaphore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef ARTIFACT_CACHE_H
|
|
||||||
#define ARTIFACT_CACHE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Artifact Computation Statuses
|
|
||||||
|
|
||||||
typedef enum AC_Status
|
|
||||||
{
|
|
||||||
AC_Status_Good,
|
|
||||||
AC_Status_NeedRetry,
|
|
||||||
AC_Status_Failed,
|
|
||||||
}
|
|
||||||
AC_Status;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Artifact Handle Type
|
|
||||||
|
|
||||||
typedef struct AC_Artifact AC_Artifact;
|
|
||||||
struct AC_Artifact
|
|
||||||
{
|
|
||||||
U64 u64[4];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Artifact Computation Function Types
|
|
||||||
|
|
||||||
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, AC_Status *status_out, U64 *gen_out);
|
|
||||||
typedef void AC_DestroyFunctionType(AC_Artifact artifact);
|
|
||||||
|
|
||||||
typedef U32 AC_Flags;
|
|
||||||
typedef enum AC_FlagsEnum
|
|
||||||
{
|
|
||||||
AC_Flag_WaitForFresh = (1<<0),
|
|
||||||
AC_Flag_HighPriority = (1<<1),
|
|
||||||
AC_Flag_Wide = (1<<2),
|
|
||||||
}
|
|
||||||
AC_FlagsEnum;
|
|
||||||
|
|
||||||
typedef struct AC_ArtifactParams AC_ArtifactParams;
|
|
||||||
struct AC_ArtifactParams
|
|
||||||
{
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
AC_DestroyFunctionType *destroy;
|
|
||||||
U64 slots_count;
|
|
||||||
U64 gen;
|
|
||||||
U64 evict_threshold_us;
|
|
||||||
B32 *stale_out;
|
|
||||||
AC_Flags flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Types
|
|
||||||
|
|
||||||
typedef struct AC_Request AC_Request;
|
|
||||||
struct AC_Request
|
|
||||||
{
|
|
||||||
String8 key;
|
|
||||||
U64 gen;
|
|
||||||
B32 *cancel_signal;
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_RequestNode AC_RequestNode;
|
|
||||||
struct AC_RequestNode
|
|
||||||
{
|
|
||||||
AC_RequestNode *next;
|
|
||||||
AC_Request v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_NodePtr AC_NodePtr;
|
|
||||||
struct AC_NodePtr
|
|
||||||
{
|
|
||||||
AC_NodePtr *next;
|
|
||||||
struct AC_Node *node;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Node AC_Node;
|
|
||||||
struct AC_Node
|
|
||||||
{
|
|
||||||
AC_Node *next;
|
|
||||||
AC_Node *prev;
|
|
||||||
|
|
||||||
// rjf: key/gen/value
|
|
||||||
String8 key;
|
|
||||||
U64 last_requested_gen;
|
|
||||||
U64 last_completed_gen;
|
|
||||||
AC_Artifact val;
|
|
||||||
|
|
||||||
// rjf: metadata
|
|
||||||
AccessPt access_pt;
|
|
||||||
U64 working_count;
|
|
||||||
U64 completion_count;
|
|
||||||
U64 evict_threshold_us;
|
|
||||||
U64 last_touched_ac_request_gen;
|
|
||||||
B32 cancelled;
|
|
||||||
B32 other_nodes_depend_on_me;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Slot AC_Slot;
|
|
||||||
struct AC_Slot
|
|
||||||
{
|
|
||||||
AC_Node *first;
|
|
||||||
AC_Node *last;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Cache AC_Cache;
|
|
||||||
struct AC_Cache
|
|
||||||
{
|
|
||||||
// rjf: link / key for cache-cache
|
|
||||||
AC_Cache *next;
|
|
||||||
AC_CreateFunctionType *create;
|
|
||||||
AC_DestroyFunctionType *destroy;
|
|
||||||
|
|
||||||
// rjf: artifact cache
|
|
||||||
U64 slots_count;
|
|
||||||
AC_Slot *slots;
|
|
||||||
StripeArray stripes;
|
|
||||||
AC_NodePtr **stripe_free_node_ptrs;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_RequestBatch AC_RequestBatch;
|
|
||||||
struct AC_RequestBatch
|
|
||||||
{
|
|
||||||
Mutex mutex;
|
|
||||||
Arena *arena;
|
|
||||||
AC_RequestNode *first_wide;
|
|
||||||
AC_RequestNode *last_wide;
|
|
||||||
AC_RequestNode *first_thin;
|
|
||||||
AC_RequestNode *last_thin;
|
|
||||||
U64 wide_count;
|
|
||||||
U64 thin_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_TCTX AC_TCTX;
|
|
||||||
struct AC_TCTX
|
|
||||||
{
|
|
||||||
U64 _unused_;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AC_Shared AC_Shared;
|
|
||||||
struct AC_Shared
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
U64 request_gen;
|
|
||||||
|
|
||||||
// rjf: cache cache
|
|
||||||
U64 cache_slots_count;
|
|
||||||
AC_Cache **cache_slots;
|
|
||||||
StripeArray cache_stripes;
|
|
||||||
|
|
||||||
// rjf: requests
|
|
||||||
AC_RequestBatch req_batches[2]; // 0: high priority, 1: low priority
|
|
||||||
|
|
||||||
// rjf: cancel thread
|
|
||||||
Thread cancel_thread;
|
|
||||||
Semaphore cancel_thread_semaphore;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
global AC_Shared *ac_shared = 0;
|
|
||||||
thread_static AC_TCTX *ac_tctx = 0;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Layer Initialization
|
|
||||||
|
|
||||||
internal void ac_init(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cache Lookups
|
|
||||||
|
|
||||||
internal AC_Artifact ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U64 endt_us);
|
|
||||||
#define ac_artifact_from_key(access, key, create_fn, destroy_fn, endt_us, ...) ac_artifact_from_key_((access), (key), &(AC_ArtifactParams){.create = (create_fn), .destroy = (destroy_fn), .evict_threshold_us = (2000000), __VA_ARGS__}, (endt_us))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Asynchronous Tick
|
|
||||||
|
|
||||||
#if !defined(NEED_ASYNC)
|
|
||||||
# define NEED_ASYNC 1
|
|
||||||
#endif
|
|
||||||
internal void ac_async_tick(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Cancel Thread
|
|
||||||
|
|
||||||
internal void ac_cancel_thread_entry_point(void *p);
|
|
||||||
|
|
||||||
#endif // ARTIFACT_CACHE_H
|
|
||||||
+226
-301
@@ -1,139 +1,86 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Global Arena Table
|
// Implementation
|
||||||
|
|
||||||
#if ARENA_TABLE_DEBUG
|
|
||||||
typedef struct ArenaTableNode ArenaTableNode;
|
|
||||||
struct ArenaTableNode
|
|
||||||
{
|
|
||||||
ArenaTableNode *next;
|
|
||||||
Arena *arena;
|
|
||||||
};
|
|
||||||
global U64 arena_table_take_init = 0;
|
|
||||||
global U64 arena_table_inited = 0;
|
|
||||||
global U64 arena_table_lock = 0;
|
|
||||||
global ArenaTableNode *arena_table = 0;
|
|
||||||
global U64 arena_table_count = 0;
|
|
||||||
global U64 arena_table_cap = 0;
|
|
||||||
global ArenaTableNode *free_arena_table_node = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Arena Functions
|
|
||||||
|
|
||||||
//- rjf: arena creation/destruction
|
|
||||||
|
|
||||||
internal Arena *
|
internal Arena *
|
||||||
arena_alloc_(ArenaParams *params)
|
arena_alloc__sized(U64 init_res, U64 init_cmt)
|
||||||
|
{
|
||||||
|
ProfBeginFunction();
|
||||||
|
Assert(ARENA_HEADER_SIZE < init_cmt && init_cmt <= init_res);
|
||||||
|
|
||||||
|
void *memory = 0;
|
||||||
|
U64 res = 0;
|
||||||
|
U64 cmt = 0;
|
||||||
|
B32 large_pages = os_large_pages_enabled();
|
||||||
|
if(large_pages)
|
||||||
|
{
|
||||||
|
U64 page_size = os_large_page_size();
|
||||||
|
res = AlignPow2(init_res, page_size);
|
||||||
|
#if OS_WINDOWS
|
||||||
|
cmt = res;
|
||||||
|
#else
|
||||||
|
cmt = AlignPow2(init_cmt, page_size);
|
||||||
|
#endif
|
||||||
|
memory = os_reserve_large(res);
|
||||||
|
if(!os_commit_large(memory, cmt))
|
||||||
|
{
|
||||||
|
memory = 0;
|
||||||
|
os_release(memory, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
U64 page_size = os_page_size();
|
||||||
|
res = AlignPow2(init_res, page_size);
|
||||||
|
cmt = AlignPow2(init_cmt, page_size);
|
||||||
|
memory = os_reserve(res);
|
||||||
|
if(!os_commit(memory, cmt))
|
||||||
|
{
|
||||||
|
memory = 0;
|
||||||
|
os_release(memory, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena *arena = (Arena*)memory;
|
||||||
|
if(arena)
|
||||||
|
{
|
||||||
|
AsanPoisonMemoryRegion(memory, cmt);
|
||||||
|
AsanUnpoisonMemoryRegion(memory, ARENA_HEADER_SIZE);
|
||||||
|
arena->prev = 0;
|
||||||
|
arena->current = arena;
|
||||||
|
arena->base_pos = 0;
|
||||||
|
arena->pos = ARENA_HEADER_SIZE;
|
||||||
|
arena->cmt = cmt;
|
||||||
|
arena->res = res;
|
||||||
|
arena->align = 8;
|
||||||
|
#if ENABLE_DEV
|
||||||
|
arena->dev = 0;
|
||||||
|
#endif
|
||||||
|
arena->grow = 1;
|
||||||
|
arena->large_pages = large_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfEnd();
|
||||||
|
return arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Arena *
|
||||||
|
arena_alloc(void)
|
||||||
{
|
{
|
||||||
ProfBeginFunction();
|
ProfBeginFunction();
|
||||||
|
|
||||||
U64 reserve_size = params->reserve_size;
|
U64 init_res, init_cmt;
|
||||||
U64 commit_size = params->commit_size;
|
if (os_large_pages_enabled()) {
|
||||||
|
init_res = ARENA_RESERVE_SIZE_LARGE_PAGES;
|
||||||
// rjf: reserve/commit initial block
|
init_cmt = ARENA_COMMIT_SIZE_LARGE_PAGES;
|
||||||
void *base = params->optional_backing_buffer;
|
} else {
|
||||||
if(base == 0)
|
init_res = ARENA_RESERVE_SIZE;
|
||||||
{
|
init_cmt = ARENA_COMMIT_SIZE;
|
||||||
// rjf: round up reserve/commit sizes
|
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
|
||||||
{
|
|
||||||
reserve_size = AlignPow2(reserve_size, get_system_info()->large_page_size);
|
|
||||||
commit_size = AlignPow2(commit_size, get_system_info()->large_page_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reserve_size = AlignPow2(reserve_size, get_system_info()->page_size);
|
|
||||||
commit_size = AlignPow2(commit_size, get_system_info()->page_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(params->flags & ArenaFlag_LargePages)
|
Arena *arena = arena_alloc__sized(init_res, init_cmt);
|
||||||
{
|
|
||||||
base = reserve_memory_large(reserve_size);
|
|
||||||
commit_memory_large(base, commit_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
base = reserve_memory(reserve_size);
|
|
||||||
commit_memory(base, commit_size);
|
|
||||||
}
|
|
||||||
AsanPoisonMemoryRegion(base, commit_size);
|
|
||||||
// TODO(rjf): we need to reintroduce this later when we have the ability to remove annotations...
|
|
||||||
// raddbg_annotate_vaddr_range(base, reserve_size, "arena %s:%i", params->allocation_site_file, params->allocation_site_line);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AsanPoisonMemoryRegion(base, params->reserve_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: panic on arena creation failure
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
|
||||||
if(Unlikely(base == 0))
|
|
||||||
{
|
|
||||||
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
|
||||||
abort_self(1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// rjf: extract arena header & fill
|
|
||||||
AsanUnpoisonMemoryRegion(base, ARENA_HEADER_SIZE);
|
|
||||||
Arena *arena = base;
|
|
||||||
arena->current = arena;
|
|
||||||
arena->flags = params->flags;
|
|
||||||
arena->cmt_size = params->commit_size;
|
|
||||||
arena->res_size = params->reserve_size;
|
|
||||||
arena->base_pos = 0;
|
|
||||||
arena->pos = ARENA_HEADER_SIZE;
|
|
||||||
arena->cmt = commit_size;
|
|
||||||
arena->res = reserve_size;
|
|
||||||
arena->allocation_site_file = params->allocation_site_file;
|
|
||||||
arena->allocation_site_line = params->allocation_site_line;
|
|
||||||
arena->name = params->name;
|
|
||||||
#if ARENA_FREE_LIST
|
|
||||||
arena->free_last = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// rjf: store in global arena table
|
|
||||||
#if ARENA_TABLE_DEBUG
|
|
||||||
if(ins_atomic_u64_eval_cond_assign(&arena_table_take_init, 1, 0) == 0)
|
|
||||||
{
|
|
||||||
arena_table = reserve_memory(GB(256));
|
|
||||||
arena_table_cap = 4096;
|
|
||||||
commit_memory(arena_table, arena_table_cap * sizeof(arena_table[0]));
|
|
||||||
ins_atomic_u64_inc_eval(&arena_table_inited);
|
|
||||||
}
|
|
||||||
for(;!ins_atomic_u64_eval(&arena_table_inited);) {}
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
B32 got_lock = (ins_atomic_u64_eval_cond_assign(&arena_table_lock, 1, 0) == 0);
|
|
||||||
if(got_lock)
|
|
||||||
{
|
|
||||||
ArenaTableNode *node = free_arena_table_node;
|
|
||||||
if(node != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(free_arena_table_node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = &arena_table[arena_table_count];
|
|
||||||
if(arena_table_count >= arena_table_cap)
|
|
||||||
{
|
|
||||||
U64 arena_table_cap__pre_grow = arena_table_cap;
|
|
||||||
arena_table_cap *= 2;
|
|
||||||
U64 arena_table_cap__post_grow = arena_table_cap;
|
|
||||||
commit_memory(arena_table + arena_table_cap__pre_grow, sizeof(arena_table[0]) * (arena_table_cap__post_grow - arena_table_cap__pre_grow));
|
|
||||||
}
|
|
||||||
arena_table_count += 1;
|
|
||||||
}
|
|
||||||
node->arena = arena;
|
|
||||||
arena->table_node = node;
|
|
||||||
ins_atomic_u64_eval_assign(&arena_table_lock, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ProfEnd();
|
ProfEnd();
|
||||||
return arena;
|
return arena;
|
||||||
@@ -142,168 +89,88 @@ arena_alloc_(ArenaParams *params)
|
|||||||
internal void
|
internal void
|
||||||
arena_release(Arena *arena)
|
arena_release(Arena *arena)
|
||||||
{
|
{
|
||||||
ProfBeginFunction();
|
for (Arena *node = arena->current, *prev = 0; node != 0; node = prev) {
|
||||||
|
prev = node->prev;
|
||||||
#if PROFILE_TELEMETRY
|
os_release(node, node->res);
|
||||||
{
|
|
||||||
Arena *base_arena = arena;
|
|
||||||
while (base_arena->prev) base_arena = base_arena->prev;
|
|
||||||
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, 0, "%s/%p", base_arena->name, base_arena);
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ARENA_TABLE_DEBUG
|
|
||||||
for(Arena *n = arena->current; n != 0; n = n->prev)
|
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
B32 got_lock = (ins_atomic_u64_eval_cond_assign(&arena_table_lock, 1, 0) == 0);
|
|
||||||
if(got_lock)
|
|
||||||
{
|
|
||||||
ArenaTableNode *table_node = n->table_node;
|
|
||||||
MemoryZeroStruct(table_node);
|
|
||||||
SLLStackPush(free_arena_table_node, table_node);
|
|
||||||
ins_atomic_u64_eval_assign(&arena_table_lock, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(Arena *n = arena->current, *prev = 0; n != 0; n = prev)
|
|
||||||
{
|
|
||||||
prev = n->prev;
|
|
||||||
AsanUnpoisonMemoryRegion(n, n->cmt);
|
|
||||||
release_memory(n, n->res);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: arena push/pop core functions
|
internal U64
|
||||||
|
arena_huge_push_threshold(void)
|
||||||
|
{
|
||||||
|
U64 reserve_size = os_large_pages_enabled() ? ARENA_RESERVE_SIZE_LARGE_PAGES : ARENA_RESERVE_SIZE;
|
||||||
|
U64 threshold = (reserve_size - ARENA_HEADER_SIZE) / 2 + 1;
|
||||||
|
return threshold;
|
||||||
|
}
|
||||||
|
|
||||||
internal void *
|
internal void *
|
||||||
arena_push(Arena *arena, U64 size, U64 align, B32 zero)
|
arena_push__impl(Arena *arena, U64 size)
|
||||||
{
|
{
|
||||||
Arena *current = arena->current;
|
Arena *current = arena->current;
|
||||||
U64 pos_pre = AlignPow2(current->pos, align);
|
U64 pos_mem = AlignPow2(current->pos, arena->align);
|
||||||
U64 pos_pst = pos_pre + size;
|
U64 pos_new = pos_mem + size;
|
||||||
|
|
||||||
// TODO: Newly allocated arenas already have zeroed commited pages,
|
if (current->res < pos_new && arena->grow) {
|
||||||
// so this unnecessarily zeroes them again.
|
Arena *new_block;
|
||||||
//
|
|
||||||
// rjf: compute the size we need to zero
|
|
||||||
U64 size_to_zero = 0;
|
|
||||||
if(zero)
|
|
||||||
{
|
|
||||||
size_to_zero = Min(current->cmt, pos_pst) - pos_pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: chain, if needed
|
|
||||||
if(current->res < pos_pst && !(arena->flags & ArenaFlag_NoChain))
|
|
||||||
{
|
|
||||||
Arena *new_block = 0;
|
|
||||||
|
|
||||||
#if ARENA_FREE_LIST
|
|
||||||
{
|
|
||||||
Arena *prev_block;
|
|
||||||
for(new_block = arena->free_last, prev_block = 0; new_block != 0; prev_block = new_block, new_block = new_block->prev)
|
|
||||||
{
|
|
||||||
if(new_block->res >= AlignPow2(new_block->pos, align) + size)
|
|
||||||
{
|
|
||||||
if(prev_block)
|
|
||||||
{
|
|
||||||
prev_block->prev = new_block->prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arena->free_last = new_block->prev;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(new_block == 0)
|
|
||||||
{
|
|
||||||
U64 res_size = current->res_size;
|
|
||||||
U64 cmt_size = current->cmt_size;
|
|
||||||
if(size + ARENA_HEADER_SIZE > res_size)
|
|
||||||
{
|
|
||||||
res_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
|
||||||
cmt_size = AlignPow2(size + ARENA_HEADER_SIZE, align);
|
|
||||||
}
|
|
||||||
new_block = arena_alloc(.reserve_size = res_size,
|
|
||||||
.commit_size = cmt_size,
|
|
||||||
.flags = current->flags,
|
|
||||||
.allocation_site_file = current->allocation_site_file,
|
|
||||||
.allocation_site_line = current->allocation_site_line);
|
|
||||||
|
|
||||||
size_to_zero = 0;
|
// normal growth path
|
||||||
|
if (size < arena_huge_push_threshold()) {
|
||||||
|
new_block = arena_alloc();
|
||||||
}
|
}
|
||||||
else
|
// huge growth path
|
||||||
{
|
else {
|
||||||
size_to_zero = size;
|
U64 new_block_size = size + ARENA_HEADER_SIZE;
|
||||||
|
new_block = arena_alloc__sized(new_block_size, new_block_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_block) {
|
||||||
new_block->base_pos = current->base_pos + current->res;
|
new_block->base_pos = current->base_pos + current->res;
|
||||||
SLLStackPush_N(arena->current, new_block, prev);
|
SLLStackPush_N(arena->current, new_block, prev);
|
||||||
|
|
||||||
current = new_block;
|
current = new_block;
|
||||||
pos_pre = AlignPow2(current->pos, align);
|
pos_mem = AlignPow2(current->pos, current->align);
|
||||||
pos_pst = pos_pre + size;
|
pos_new = pos_mem + size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: commit new pages, if needed
|
if (current->cmt < pos_new) {
|
||||||
if(current->cmt < pos_pst)
|
U64 cmt_new_aligned, cmt_new_clamped, cmt_new_size;
|
||||||
{
|
B32 is_cmt_ok;
|
||||||
U64 cmt_pst_aligned = pos_pst + current->cmt_size-1;
|
|
||||||
cmt_pst_aligned -= cmt_pst_aligned%current->cmt_size;
|
if (current->large_pages) {
|
||||||
U64 cmt_pst_clamped = ClampTop(cmt_pst_aligned, current->res);
|
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE_LARGE_PAGES);
|
||||||
U64 cmt_size = cmt_pst_clamped - current->cmt;
|
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
|
||||||
U8 *cmt_ptr = (U8 *)current + current->cmt;
|
cmt_new_size = cmt_new_clamped - current->cmt;
|
||||||
if(current->flags & ArenaFlag_LargePages)
|
is_cmt_ok = os_commit_large((U8*)current + current->cmt, cmt_new_size);
|
||||||
{
|
} else {
|
||||||
commit_memory_large(cmt_ptr, cmt_size);
|
cmt_new_aligned = AlignPow2(pos_new, ARENA_COMMIT_SIZE);
|
||||||
}
|
cmt_new_clamped = ClampTop(cmt_new_aligned, current->res);
|
||||||
else
|
cmt_new_size = cmt_new_clamped - current->cmt;
|
||||||
{
|
is_cmt_ok = os_commit((U8*)current + current->cmt, cmt_new_size);
|
||||||
commit_memory(cmt_ptr, cmt_size);
|
|
||||||
}
|
|
||||||
AsanPoisonMemoryRegion(cmt_ptr, cmt_size);
|
|
||||||
current->cmt = cmt_pst_clamped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: push onto current block
|
if (is_cmt_ok) {
|
||||||
void *result = 0;
|
current->cmt = cmt_new_clamped;
|
||||||
if(current->cmt >= pos_pst)
|
}
|
||||||
{
|
|
||||||
result = (U8 *)current+pos_pre;
|
|
||||||
current->pos = pos_pst;
|
|
||||||
AsanUnpoisonMemoryRegion(result, size);
|
|
||||||
MemoryZero(result, size_to_zero);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if PROFILE_TELEMETRY
|
void *memory = 0;
|
||||||
if(size > KB(1))
|
|
||||||
{
|
if (current->cmt >= pos_new) {
|
||||||
Arena *base_arena = arena;
|
memory = (U8*)current + pos_mem;
|
||||||
while (base_arena->prev) base_arena = base_arena->prev;
|
current->pos = pos_new;
|
||||||
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, (double)(current->base_pos + current->pos) / 1024.0 / 1024.0, "%s/%p", base_arena->name, base_arena);
|
AsanUnpoisonMemoryRegion(memory, size);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// rjf: panic on failure
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
#if OS_FEATURE_GRAPHICAL
|
||||||
if(Unlikely(result == 0))
|
if(Unlikely(memory == 0))
|
||||||
{
|
{
|
||||||
wm_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
os_graphical_message(1, str8_lit("Fatal Allocation Failure"), str8_lit("Unexpected memory allocation failure."));
|
||||||
abort_self(1);
|
os_exit_process(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal U64
|
internal U64
|
||||||
@@ -315,45 +182,95 @@ arena_pos(Arena *arena)
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
arena_pop_to(Arena *arena, U64 pos)
|
arena_pop_to(Arena *arena, U64 big_pos_unclamped)
|
||||||
{
|
{
|
||||||
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, pos);
|
U64 big_pos = ClampBot(ARENA_HEADER_SIZE, big_pos_unclamped);
|
||||||
Arena *current = arena->current;
|
|
||||||
|
|
||||||
#if ARENA_FREE_LIST
|
// unroll the chain
|
||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
Arena *current = arena->current;
|
||||||
{
|
for (Arena *prev = 0; current->base_pos >= big_pos; current = prev) {
|
||||||
prev = current->prev;
|
prev = current->prev;
|
||||||
current->pos = ARENA_HEADER_SIZE;
|
os_release(current, current->res);
|
||||||
SLLStackPush_N(arena->free_last, current, prev);
|
|
||||||
AsanPoisonMemoryRegion((U8*)current + ARENA_HEADER_SIZE, current->res - ARENA_HEADER_SIZE);
|
|
||||||
}
|
}
|
||||||
#else
|
AssertAlways(current);
|
||||||
for(Arena *prev = 0; current->base_pos >= big_pos; current = prev)
|
|
||||||
{
|
|
||||||
prev = current->prev;
|
|
||||||
AsanUnpoisonMemoryRegion(current, current->cmt);
|
|
||||||
release_memory(current, current->res);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
arena->current = current;
|
arena->current = current;
|
||||||
|
|
||||||
|
// compute arena-relative position
|
||||||
U64 new_pos = big_pos - current->base_pos;
|
U64 new_pos = big_pos - current->base_pos;
|
||||||
AssertAlways(new_pos <= current->pos);
|
AssertAlways(new_pos <= current->pos);
|
||||||
|
|
||||||
|
// poison popped memory block
|
||||||
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
AsanPoisonMemoryRegion((U8*)current + new_pos, (current->pos - new_pos));
|
||||||
|
|
||||||
|
// update position
|
||||||
current->pos = new_pos;
|
current->pos = new_pos;
|
||||||
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
if((pos - (new_pos + current->base_pos)) > KB(1))
|
|
||||||
{
|
|
||||||
Arena *base_arena = arena;
|
|
||||||
while (base_arena->prev) base_arena = base_arena->prev;
|
|
||||||
tmPlot(0, TM_PLOT_UNITS_MEMORY, TM_PLOT_DRAW_LINE, (double)(current->base_pos + current->pos) / 1024.0 / 1024.0, "%s/%p", base_arena->name, base_arena);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: arena push/pop helpers
|
internal void
|
||||||
|
arena_absorb(Arena *arena, Arena *sub)
|
||||||
|
{
|
||||||
|
#if ENABLE_DEV
|
||||||
|
arena_annotate_absorb__dev(arena, sub);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// base adjustment
|
||||||
|
Arena *current = arena->current;
|
||||||
|
U64 base_adjust = current->base_pos + current->res;
|
||||||
|
for (Arena *node = sub->current; node != 0; node = node->prev) {
|
||||||
|
node->base_pos += base_adjust;
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach sub to arena
|
||||||
|
sub->prev = arena->current;
|
||||||
|
arena->current = sub->current;
|
||||||
|
sub->current = sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Wrappers
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
arena_push(Arena *arena, U64 size)
|
||||||
|
{
|
||||||
|
void *memory = arena_push__impl(arena, size);
|
||||||
|
#if ENABLE_DEV
|
||||||
|
arena_annotate_push__dev(arena, size, memory);
|
||||||
|
#endif
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void *
|
||||||
|
arena_push_contiguous(Arena *arena, U64 size)
|
||||||
|
{
|
||||||
|
B32 restore = arena->grow;
|
||||||
|
arena->grow = 0;
|
||||||
|
void *memory = arena_push(arena, size);
|
||||||
|
arena->grow = restore;
|
||||||
|
#if ENABLE_DEV
|
||||||
|
arena_annotate_push__dev(arena, size, memory);
|
||||||
|
#endif
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_push_align(Arena *arena, U64 align)
|
||||||
|
{
|
||||||
|
Assert(IsPow2(align));
|
||||||
|
U64 amt = AlignPadPow2(arena->pos, align);
|
||||||
|
void *ptr = arena_push(arena, amt);
|
||||||
|
MemoryZero(ptr, amt);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_put_back(Arena *arena, U64 amt)
|
||||||
|
{
|
||||||
|
U64 pos_old = arena_pos(arena);
|
||||||
|
U64 pos_new = pos_old;
|
||||||
|
if (amt < pos_old) {
|
||||||
|
pos_new = pos_old - amt;
|
||||||
|
}
|
||||||
|
arena_pop_to(arena, pos_new);
|
||||||
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
arena_clear(Arena *arena)
|
arena_clear(Arena *arena)
|
||||||
@@ -361,20 +278,6 @@ arena_clear(Arena *arena)
|
|||||||
arena_pop_to(arena, 0);
|
arena_pop_to(arena, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
|
||||||
arena_pop(Arena *arena, U64 amt)
|
|
||||||
{
|
|
||||||
U64 pos_old = arena_pos(arena);
|
|
||||||
U64 pos_new = pos_old;
|
|
||||||
if(amt < pos_old)
|
|
||||||
{
|
|
||||||
pos_new = pos_old - amt;
|
|
||||||
}
|
|
||||||
arena_pop_to(arena, pos_new);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: temporary arena scopes
|
|
||||||
|
|
||||||
internal Temp
|
internal Temp
|
||||||
temp_begin(Arena *arena)
|
temp_begin(Arena *arena)
|
||||||
{
|
{
|
||||||
@@ -388,3 +291,25 @@ temp_end(Temp temp)
|
|||||||
{
|
{
|
||||||
arena_pop_to(temp.arena, temp.pos);
|
arena_pop_to(temp.arena, temp.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): "Mini-Arena" Helper
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
ensure_commit(void **cmtptr, void *pos, U64 cmt_block_size){
|
||||||
|
B32 result = 0;
|
||||||
|
U8 *cmt = (U8*)*cmtptr;
|
||||||
|
if (cmt < (U8*)pos){
|
||||||
|
U64 cmt_size_raw = (U8*)pos - cmt;
|
||||||
|
U64 cmt_size = AlignPow2(cmt_size_raw, cmt_block_size);
|
||||||
|
if (os_commit(cmt, cmt_size)){
|
||||||
|
*cmtptr = cmt + cmt_size;
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+52
-51
@@ -1,56 +1,45 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_ARENA_H
|
#ifndef BASE_ARENA_H
|
||||||
#define BASE_ARENA_H
|
#define BASE_ARENA_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Arena Types
|
//~ rjf: Constants
|
||||||
|
|
||||||
#define ARENA_HEADER_SIZE 128
|
#define ARENA_HEADER_SIZE 128
|
||||||
|
|
||||||
typedef U64 ArenaFlags;
|
#ifndef ARENA_RESERVE_SIZE
|
||||||
enum
|
# define ARENA_RESERVE_SIZE MB(64)
|
||||||
{
|
#endif
|
||||||
ArenaFlag_NoChain = (1<<0),
|
#ifndef ARENA_COMMIT_SIZE
|
||||||
ArenaFlag_LargePages = (1<<1),
|
# define ARENA_COMMIT_SIZE KB(64)
|
||||||
};
|
#endif
|
||||||
|
|
||||||
typedef struct ArenaParams ArenaParams;
|
#ifndef ARENA_RESERVE_SIZE_LARGE_PAGES
|
||||||
struct ArenaParams
|
# define ARENA_RESERVE_SIZE_LARGE_PAGES MB(8)
|
||||||
{
|
#endif
|
||||||
ArenaFlags flags;
|
#ifndef ARENA_COMMIT_SIZE_LARGE_PAGES
|
||||||
U64 reserve_size;
|
# define ARENA_COMMIT_SIZE_LARGE_PAGES MB(2)
|
||||||
U64 commit_size;
|
#endif
|
||||||
void *optional_backing_buffer;
|
|
||||||
char *allocation_site_file;
|
////////////////////////////////
|
||||||
int allocation_site_line;
|
//~ rjf: Arena Types
|
||||||
char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Arena Arena;
|
typedef struct Arena Arena;
|
||||||
struct Arena
|
struct Arena
|
||||||
{
|
{
|
||||||
Arena *prev; // previous arena in chain
|
struct Arena *prev;
|
||||||
Arena *current; // current arena in chain
|
struct Arena *current;
|
||||||
ArenaFlags flags;
|
|
||||||
U64 cmt_size;
|
|
||||||
U64 res_size;
|
|
||||||
U64 base_pos;
|
U64 base_pos;
|
||||||
U64 pos;
|
U64 pos;
|
||||||
U64 cmt;
|
U64 cmt;
|
||||||
U64 res;
|
U64 res;
|
||||||
char *allocation_site_file;
|
U64 align;
|
||||||
int allocation_site_line;
|
struct ArenaDev *dev;
|
||||||
char *name;
|
B8 grow;
|
||||||
#if ARENA_FREE_LIST
|
B8 large_pages;
|
||||||
Arena *free_last;
|
|
||||||
#endif
|
|
||||||
#if ARENA_TABLE_DEBUG
|
|
||||||
struct ArenaTableNode *table_node;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
StaticAssert(sizeof(Arena) <= ARENA_HEADER_SIZE, arena_header_size_check);
|
|
||||||
|
|
||||||
typedef struct Temp Temp;
|
typedef struct Temp Temp;
|
||||||
struct Temp
|
struct Temp
|
||||||
@@ -60,34 +49,46 @@ struct Temp
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Arena Functions
|
// Implementation
|
||||||
|
|
||||||
global U64 arena_default_reserve_size = MB(64);
|
internal Arena* arena_alloc__sized(U64 init_res, U64 init_cmt);
|
||||||
global U64 arena_default_commit_size = KB(64);
|
|
||||||
global ArenaFlags arena_default_flags = 0;
|
|
||||||
|
|
||||||
//- rjf: arena creation/destruction
|
internal Arena* arena_alloc(void);
|
||||||
internal Arena *arena_alloc_(ArenaParams *params);
|
|
||||||
#define arena_alloc(...) arena_alloc_(&(ArenaParams){.reserve_size = arena_default_reserve_size, .commit_size = arena_default_commit_size, .flags = arena_default_flags, .allocation_site_file = __FILE__, .allocation_site_line = __LINE__, __VA_ARGS__})
|
|
||||||
internal void arena_release(Arena *arena);
|
internal void arena_release(Arena *arena);
|
||||||
|
|
||||||
//- rjf: arena push/pop/pos core functions
|
internal void* arena_push__impl(Arena *arena, U64 size);
|
||||||
internal void *arena_push(Arena *arena, U64 size, U64 align, B32 zero);
|
|
||||||
internal U64 arena_pos(Arena *arena);
|
internal U64 arena_pos(Arena *arena);
|
||||||
internal void arena_pop_to(Arena *arena, U64 pos);
|
internal void arena_pop_to(Arena *arena, U64 pos);
|
||||||
|
|
||||||
//- rjf: arena push/pop helpers
|
internal void arena_absorb(Arena *arena, Arena *sub);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Wrappers
|
||||||
|
|
||||||
|
internal void* arena_push(Arena *arena, U64 size);
|
||||||
|
internal void* arena_push_contiguous(Arena *arena, U64 size);
|
||||||
internal void arena_clear(Arena *arena);
|
internal void arena_clear(Arena *arena);
|
||||||
internal void arena_pop(Arena *arena, U64 amt);
|
internal void arena_push_align(Arena *arena, U64 align);
|
||||||
|
internal void arena_put_back(Arena *arena, U64 amt);
|
||||||
|
|
||||||
//- rjf: temporary arena scopes
|
|
||||||
internal Temp temp_begin(Arena *arena);
|
internal Temp temp_begin(Arena *arena);
|
||||||
internal void temp_end(Temp temp);
|
internal void temp_end(Temp temp);
|
||||||
|
|
||||||
//- rjf: push helper macros
|
////////////////////////////////
|
||||||
#define push_array_no_zero_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (0))
|
//~ NOTE(allen): "Mini-Arena" Helper
|
||||||
#define push_array_aligned(a, T, c, align) (T *)arena_push((a), sizeof(T)*(c), (align), (1))
|
|
||||||
#define push_array_no_zero(a, T, c) push_array_no_zero_aligned(a, T, c, Max(8, AlignOf(T)))
|
internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size);
|
||||||
#define push_array(a, T, c) push_array_aligned(a, T, c, Max(8, AlignOf(T)))
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): Main API Macros
|
||||||
|
|
||||||
|
#if !ENABLE_DEV
|
||||||
|
# define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
|
||||||
|
#else
|
||||||
|
# define push_array_no_zero(a,T,c) (tctx_write_this_srcloc(), (T*)arena_push((a), sizeof(T)*(c)))
|
||||||
|
#endif
|
||||||
|
#define push_array_no_zero__no_annotation(a,T,c) (T*)arena_push__impl((a), sizeof(T)*(c))
|
||||||
|
|
||||||
|
#define push_array(a,T,c) (T*)MemoryZero(push_array_no_zero(a,T,c), sizeof(T)*(c))
|
||||||
|
|
||||||
#endif // BASE_ARENA_H
|
#endif // BASE_ARENA_H
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Dev Arena
|
||||||
|
|
||||||
|
#if ENABLE_DEV
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_annotate_push__dev(Arena *arena, U64 size, void *ptr){
|
||||||
|
ArenaDev *dev = arena->dev;
|
||||||
|
if (dev != 0 && ptr != 0){
|
||||||
|
//- read location
|
||||||
|
char *file_name = 0;
|
||||||
|
U64 line_number = 0;
|
||||||
|
tctx_read_srcloc(&file_name, &line_number);
|
||||||
|
tctx_write_srcloc(0, 0);
|
||||||
|
|
||||||
|
//- profile
|
||||||
|
ArenaProf *prof = dev->prof;
|
||||||
|
if (prof != 0){
|
||||||
|
// c string -> string
|
||||||
|
String8 file_name_str = str8_lit("(null)");
|
||||||
|
if (file_name != 0){
|
||||||
|
file_name_str = str8_cstring(file_name);
|
||||||
|
}
|
||||||
|
// record
|
||||||
|
arena_prof_inc_counters__dev(dev->arena, prof, file_name_str, line_number, size, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_annotate_absorb__dev(Arena *arena, Arena *sub){
|
||||||
|
ArenaDev *dev = arena->dev;
|
||||||
|
ArenaDev *sub_dev = sub->dev;
|
||||||
|
if (dev != 0 && sub_dev != 0){
|
||||||
|
//- merge profiles
|
||||||
|
ArenaProf *prof = dev->prof;
|
||||||
|
ArenaProf *sub_prof = sub_dev->prof;
|
||||||
|
if (prof != 0 && sub_prof != 0){
|
||||||
|
for (ArenaProfNode *sub_node = sub_prof->first;
|
||||||
|
sub_node != 0;
|
||||||
|
sub_node = sub_node->next){
|
||||||
|
arena_prof_inc_counters__dev(dev->arena, prof, sub_node->file_name, sub_node->line,
|
||||||
|
sub_node->size, sub_node->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//- release the sub dev memory
|
||||||
|
if (sub_dev != 0){
|
||||||
|
arena_release(sub_dev->arena);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ArenaDev*
|
||||||
|
arena_equip__dev(Arena *arena){
|
||||||
|
ArenaDev *result = arena->dev;
|
||||||
|
if (result == 0){
|
||||||
|
Arena *dev_arena = arena_alloc();
|
||||||
|
ArenaDev *dev = (ArenaDev*)arena_push__impl(dev_arena, sizeof(ArenaDev));
|
||||||
|
MemoryZeroStruct(dev);
|
||||||
|
dev->arena = dev_arena;
|
||||||
|
arena->dev = dev;
|
||||||
|
result = dev;
|
||||||
|
}
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_equip_profile__dev(Arena *arena){
|
||||||
|
ArenaDev *dev = arena_equip__dev(arena);
|
||||||
|
if (dev->prof == 0){
|
||||||
|
dev->prof = (ArenaProf*)arena_push__impl(dev->arena, sizeof(ArenaProf));
|
||||||
|
MemoryZeroStruct(dev->prof);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out){
|
||||||
|
Assert(arena != out_arena);
|
||||||
|
|
||||||
|
//- get dev & disable
|
||||||
|
ArenaDev *dev = arena->dev;
|
||||||
|
arena->dev = 0;
|
||||||
|
|
||||||
|
//- get prof
|
||||||
|
ArenaProf *prof = (dev != 0)?dev->prof:0;
|
||||||
|
|
||||||
|
//- not equipped with prof
|
||||||
|
if (prof == 0){
|
||||||
|
str8_list_push(out_arena, out, str8_lit("not equipped with a memory profile\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//- print prof
|
||||||
|
if (prof != 0){
|
||||||
|
Temp scratch = temp_begin(dev->arena);
|
||||||
|
|
||||||
|
//- make flat array
|
||||||
|
U64 note_count = prof->count;
|
||||||
|
ArenaProfNode **notes = push_array_no_zero__no_annotation(scratch.arena, ArenaProfNode*, note_count);
|
||||||
|
{
|
||||||
|
ArenaProfNode **note_ptr = notes;
|
||||||
|
for (ArenaProfNode *node = prof->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next, note_ptr += 1){
|
||||||
|
*note_ptr = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- file name size
|
||||||
|
U64 max_file_name_size = 0;
|
||||||
|
{
|
||||||
|
ArenaProfNode **note_ptr = notes;
|
||||||
|
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||||
|
max_file_name_size = Max(max_file_name_size, (**note_ptr).file_name.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- sort (> size, < [address])
|
||||||
|
for (U64 i = 0; i < note_count; i += 1){
|
||||||
|
ArenaProfNode **i_note = notes + i;
|
||||||
|
ArenaProfNode **min_note = i_note;
|
||||||
|
for (U64 j = i + 1; j < note_count; j += 1){
|
||||||
|
ArenaProfNode **j_note = notes + j;
|
||||||
|
if ((**j_note).size > (**min_note).size ||
|
||||||
|
((**j_note).size == (**min_note).size && *j_note < *min_note)){
|
||||||
|
min_note = j_note;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (min_note != i_note){
|
||||||
|
ArenaProfNode *t = *i_note;
|
||||||
|
*i_note = *min_note;
|
||||||
|
*min_note = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- total size
|
||||||
|
U64 total_size = 0;
|
||||||
|
{
|
||||||
|
ArenaProfNode **note_ptr = notes;
|
||||||
|
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||||
|
ArenaProfNode *note = *note_ptr;
|
||||||
|
total_size += note->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//- print
|
||||||
|
{
|
||||||
|
str8_list_pushf(out_arena, out, "memory total: %llu\n", total_size);
|
||||||
|
|
||||||
|
ArenaProfNode **note_ptr = notes;
|
||||||
|
for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){
|
||||||
|
ArenaProfNode *note = *note_ptr;
|
||||||
|
String8 location = push_str8f(scratch.arena, "%S:%5llu:",
|
||||||
|
note->file_name, note->line);
|
||||||
|
F32 percent = 100.f*((F32)note->size)/total_size;
|
||||||
|
str8_list_pushf(out_arena, out, "%*.*s %12llu %5.2f%% [%5llu]\n",
|
||||||
|
max_file_name_size + 7, str8_varg(location),
|
||||||
|
note->size, percent, note->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_end(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- restore dev
|
||||||
|
arena->dev = dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line,
|
||||||
|
U64 size, U64 count){
|
||||||
|
// find existing profile node
|
||||||
|
ArenaProfNode *prof_node = 0;
|
||||||
|
for (ArenaProfNode *node = prof->first;
|
||||||
|
node != 0;
|
||||||
|
node = node->next){
|
||||||
|
if (node->line == line && str8_match(file_name, node->file_name, 0)){
|
||||||
|
prof_node = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// make new histogram node if necessary
|
||||||
|
if (prof_node == 0){
|
||||||
|
prof_node = (ArenaProfNode*)arena_push(dev_arena, sizeof(*prof_node));
|
||||||
|
SLLQueuePush(prof->first, prof->last, prof_node);
|
||||||
|
prof->count += 1;
|
||||||
|
prof_node->file_name = file_name;
|
||||||
|
prof_node->line = line;
|
||||||
|
}
|
||||||
|
// record this allocation
|
||||||
|
prof_node->size += size;
|
||||||
|
prof_node->count += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_ARENA_DEV_H
|
||||||
|
#define BASE_ARENA_DEV_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): Dev Arena Types
|
||||||
|
|
||||||
|
typedef struct ArenaDev ArenaDev;
|
||||||
|
struct ArenaDev
|
||||||
|
{
|
||||||
|
Arena *arena;
|
||||||
|
struct ArenaProf *prof;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ArenaProf ArenaProf;
|
||||||
|
struct ArenaProf
|
||||||
|
{
|
||||||
|
struct ArenaProfNode *first;
|
||||||
|
struct ArenaProfNode *last;
|
||||||
|
U64 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ArenaProfNode ArenaProfNode;
|
||||||
|
struct ArenaProfNode
|
||||||
|
{
|
||||||
|
ArenaProfNode *next;
|
||||||
|
String8 file_name;
|
||||||
|
U64 line;
|
||||||
|
U64 size;
|
||||||
|
U64 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): Dev Arena Functions
|
||||||
|
|
||||||
|
#if ENABLE_DEV
|
||||||
|
internal void arena_annotate_push__dev(Arena *arena, U64 size, void *ptr);
|
||||||
|
internal void arena_annotate_absorb__dev(Arena *arena, Arena *sub);
|
||||||
|
internal ArenaDev* arena_equip__dev(Arena *arena);
|
||||||
|
internal void arena_equip_profile__dev(Arena *arena);
|
||||||
|
internal void arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out);
|
||||||
|
internal void arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, U64 size, U64 count);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BASE_ARENA_DEV_H
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set16(U16 val)
|
||||||
|
{
|
||||||
|
return __popcnt16(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set32(U32 val)
|
||||||
|
{
|
||||||
|
return __popcnt(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set64(U64 val)
|
||||||
|
{
|
||||||
|
return __popcnt64(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
ctz32(U32 mask)
|
||||||
|
{
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanForward(&idx, mask);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
ctz64(U64 mask)
|
||||||
|
{
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanForward64(&idx, mask);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
clz32(U32 mask)
|
||||||
|
{
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanReverse(&idx, mask);
|
||||||
|
return 31 - idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
clz64(U64 mask)
|
||||||
|
{
|
||||||
|
unsigned long idx;
|
||||||
|
_BitScanReverse64(&idx, mask);
|
||||||
|
return 63 - idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set16(U16 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set32(U32 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
count_bits_set64(U64 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
ctz32(U32 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
clz32(U32 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
clz64(U64 val)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error "bits not defined for this target"
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_BITS_H
|
||||||
|
#define BASE_BITS_H
|
||||||
|
|
||||||
|
#define ExtractBit(word, idx) (((word) >> (idx)) & 1)
|
||||||
|
|
||||||
|
internal U64 count_bits_set16(U16 val);
|
||||||
|
internal U64 count_bits_set32(U32 val);
|
||||||
|
internal U64 count_bits_set64(U64 val);
|
||||||
|
|
||||||
|
internal U64 ctz32(U32 val);
|
||||||
|
internal U64 ctz64(U64 val);
|
||||||
|
internal U64 clz32(U32 val);
|
||||||
|
internal U64 clz64(U64 val);
|
||||||
|
|
||||||
|
#endif // BASE_BITS_H
|
||||||
@@ -1,8 +1,19 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Command Line Parsing Functions
|
//~ NOTE(rjf): Command Line Option Parsing
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
cmd_line_hash_from_string(String8 string)
|
||||||
|
{
|
||||||
|
U64 result = 5381;
|
||||||
|
for(U64 i = 0; i < string.size; i += 1)
|
||||||
|
{
|
||||||
|
result = ((result << 5) + result) + string.str[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
internal CmdLineOpt **
|
internal CmdLineOpt **
|
||||||
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
||||||
@@ -10,7 +21,7 @@ cmd_line_slot_from_string(CmdLine *cmd_line, String8 string)
|
|||||||
CmdLineOpt **slot = 0;
|
CmdLineOpt **slot = 0;
|
||||||
if(cmd_line->option_table_size != 0)
|
if(cmd_line->option_table_size != 0)
|
||||||
{
|
{
|
||||||
U64 hash = u64_hash_from_str8(string);
|
U64 hash = cmd_line_hash_from_string(string);
|
||||||
U64 bucket = hash % cmd_line->option_table_size;
|
U64 bucket = hash % cmd_line->option_table_size;
|
||||||
slot = &cmd_line->option_table[bucket];
|
slot = &cmd_line->option_table[bucket];
|
||||||
}
|
}
|
||||||
@@ -53,7 +64,7 @@ cmd_line_insert_opt(Arena *arena, CmdLine *cmd_line, String8 string, String8List
|
|||||||
{
|
{
|
||||||
var = push_array(arena, CmdLineOpt, 1);
|
var = push_array(arena, CmdLineOpt, 1);
|
||||||
var->hash_next = *slot;
|
var->hash_next = *slot;
|
||||||
var->hash = u64_hash_from_str8(string);
|
var->hash = cmd_line_hash_from_string(string);
|
||||||
var->string = push_str8_copy(arena, string);
|
var->string = push_str8_copy(arena, string);
|
||||||
var->value_strings = values;
|
var->value_strings = values;
|
||||||
StringJoin join = {0};
|
StringJoin join = {0};
|
||||||
@@ -71,26 +82,26 @@ internal CmdLine
|
|||||||
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
cmd_line_from_string_list(Arena *arena, String8List command_line)
|
||||||
{
|
{
|
||||||
CmdLine parsed = {0};
|
CmdLine parsed = {0};
|
||||||
parsed.exe_name = command_line.first->string;
|
|
||||||
parsed.option_table_size = 64;
|
|
||||||
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
|
||||||
|
|
||||||
//- rjf: parse options / inputs
|
// NOTE(rjf): Set up config option table.
|
||||||
|
{
|
||||||
|
parsed.option_table_size = 4096;
|
||||||
|
parsed.option_table = push_array(arena, CmdLineOpt *, parsed.option_table_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(rjf): Parse command line.
|
||||||
B32 after_passthrough_option = 0;
|
B32 after_passthrough_option = 0;
|
||||||
B32 first_passthrough = 1;
|
|
||||||
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next)
|
||||||
{
|
{
|
||||||
next = node->next;
|
next = node->next;
|
||||||
|
|
||||||
//- rjf: look at --, -, or / (only on Windows) at the start of an
|
|
||||||
// argument to determine if it's a flag option. all arguments after a
|
|
||||||
// single "--" (with no trailing string on the command line will be
|
|
||||||
// considered as passthrough input strings.
|
|
||||||
B32 is_option = 0;
|
|
||||||
String8 option_name = node->string;
|
String8 option_name = node->string;
|
||||||
if(!after_passthrough_option)
|
|
||||||
|
// NOTE(rjf): Look at -- or - at the start of an argument to determine if it's
|
||||||
|
// a flag option. All arguments after a single "--" (with no trailing string
|
||||||
|
// on the command line will be considered as input files.
|
||||||
|
B32 is_option = 1;
|
||||||
|
if(after_passthrough_option == 0)
|
||||||
{
|
{
|
||||||
is_option = 1;
|
|
||||||
if(str8_match(node->string, str8_lit("--"), 0))
|
if(str8_match(node->string, str8_lit("--"), 0))
|
||||||
{
|
{
|
||||||
after_passthrough_option = 1;
|
after_passthrough_option = 1;
|
||||||
@@ -104,79 +115,69 @@ cmd_line_from_string_list(Arena *arena, String8List command_line)
|
|||||||
{
|
{
|
||||||
option_name = str8_skip(option_name, 1);
|
option_name = str8_skip(option_name, 1);
|
||||||
}
|
}
|
||||||
else if(OperatingSystem_CURRENT == OperatingSystem_Windows &&
|
|
||||||
str8_match(str8_prefix(node->string, 1), str8_lit("/"), 0))
|
|
||||||
{
|
|
||||||
option_name = str8_skip(option_name, 1);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
is_option = 0;
|
is_option = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
is_option = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//- rjf: string is an option
|
// NOTE(rjf): This string is an option.
|
||||||
if(is_option)
|
if(is_option)
|
||||||
{
|
{
|
||||||
// rjf: unpack option prefix
|
B32 has_arguments = 0;
|
||||||
B32 has_values = 0;
|
U64 arg_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
||||||
U64 value_signifier_position1 = str8_find_needle(option_name, 0, str8_lit(":"), 0);
|
U64 arg_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
||||||
U64 value_signifier_position2 = str8_find_needle(option_name, 0, str8_lit("="), 0);
|
U64 arg_signifier_position = Min(arg_signifier_position1, arg_signifier_position2);
|
||||||
U64 value_signifier_position = Min(value_signifier_position1, value_signifier_position2);
|
String8 arg_portion_this_string = str8_skip(option_name, arg_signifier_position+1);
|
||||||
String8 value_portion_this_string = str8_skip(option_name, value_signifier_position+1);
|
if(arg_signifier_position < option_name.size)
|
||||||
if(value_signifier_position < option_name.size)
|
|
||||||
{
|
{
|
||||||
has_values = 1;
|
has_arguments = 1;
|
||||||
}
|
}
|
||||||
option_name = str8_prefix(option_name, value_signifier_position);
|
option_name = str8_prefix(option_name, arg_signifier_position);
|
||||||
|
|
||||||
// rjf: parse option's values
|
String8List arguments = {0};
|
||||||
String8List values = {0};
|
|
||||||
if(has_values)
|
// NOTE(rjf): Parse arguments.
|
||||||
|
if(has_arguments)
|
||||||
{
|
{
|
||||||
for(String8Node *n = node; n; n = n->next)
|
for(String8Node *n = node; n; n = n->next)
|
||||||
{
|
{
|
||||||
next = n->next;
|
next = n->next;
|
||||||
|
|
||||||
String8 string = n->string;
|
String8 string = n->string;
|
||||||
if(n == node)
|
if(n == node)
|
||||||
{
|
{
|
||||||
string = value_portion_this_string;
|
string = arg_portion_this_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
U8 splits[] = { ',' };
|
U8 splits[] = { ',' };
|
||||||
String8List values_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
String8List args_in_this_string = str8_split(arena, string, splits, ArrayCount(splits), 0);
|
||||||
for(String8Node *sub_val = values_in_this_string.first; sub_val; sub_val = sub_val->next)
|
for(String8Node *sub_arg = args_in_this_string.first; sub_arg; sub_arg = sub_arg->next)
|
||||||
{
|
{
|
||||||
str8_list_push(arena, &values, sub_val->string);
|
str8_list_push(arena, &arguments, sub_arg->string);
|
||||||
}
|
}
|
||||||
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
if(!str8_match(str8_postfix(n->string, 1), str8_lit(","), 0) &&
|
||||||
(n != node || value_portion_this_string.size != 0))
|
(n != node || arg_portion_this_string.size != 0))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// rjf: store
|
// NOTE(rjf): Register config variable.
|
||||||
cmd_line_insert_opt(arena, &parsed, option_name, values);
|
cmd_line_insert_opt(arena, &parsed, option_name, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: default path - treat as a passthrough input
|
// NOTE(rjf): Default path, treat as a passthrough config option to be
|
||||||
else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough)
|
// handled by tool-specific code.
|
||||||
|
else if(!str8_match(node->string, str8_lit("--"), 0))
|
||||||
{
|
{
|
||||||
str8_list_push(arena, &parsed.inputs, node->string);
|
str8_list_push(arena, &parsed.inputs, node->string);
|
||||||
first_passthrough = 0;
|
after_passthrough_option = 1;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: fill argc/argv
|
|
||||||
parsed.argc = command_line.node_count;
|
|
||||||
parsed.argv = push_array(arena, char *, parsed.argc);
|
|
||||||
{
|
|
||||||
U64 idx = 0;
|
|
||||||
for(String8Node *n = command_line.first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
parsed.argv[idx] = (char *)push_str8_copy(arena, n->string).str;
|
|
||||||
idx += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,12 +218,12 @@ internal B32
|
|||||||
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
cmd_line_has_flag(CmdLine *cmd_line, String8 name)
|
||||||
{
|
{
|
||||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||||
return (var != 0);
|
return(var != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal B32
|
internal B32
|
||||||
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
cmd_line_has_argument(CmdLine *cmd_line, String8 name)
|
||||||
{
|
{
|
||||||
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
CmdLineOpt *var = cmd_line_opt_from_string(cmd_line, name);
|
||||||
return (var != 0 && var->value_strings.node_count > 0);
|
return(var != 0 && var->value_strings.node_count > 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_COMMAND_LINE_H
|
#ifndef BASE_COMMAND_LINE_H
|
||||||
@@ -29,18 +29,16 @@ struct CmdLineOptList
|
|||||||
typedef struct CmdLine CmdLine;
|
typedef struct CmdLine CmdLine;
|
||||||
struct CmdLine
|
struct CmdLine
|
||||||
{
|
{
|
||||||
String8 exe_name;
|
|
||||||
CmdLineOptList options;
|
CmdLineOptList options;
|
||||||
String8List inputs;
|
String8List inputs;
|
||||||
U64 option_table_size;
|
U64 option_table_size;
|
||||||
CmdLineOpt **option_table;
|
CmdLineOpt **option_table;
|
||||||
U64 argc;
|
|
||||||
char **argv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Command Line Parsing Functions
|
//~ NOTE(rjf): Command Line Option Parsing
|
||||||
|
|
||||||
|
internal U64 cmd_line_hash_from_string(String8 string);
|
||||||
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
internal CmdLineOpt** cmd_line_slot_from_string(CmdLine *cmd_line, String8 string);
|
||||||
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
internal CmdLineOpt* cmd_line_opt_from_slot(CmdLineOpt **slot, String8 string);
|
||||||
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
internal void cmd_line_push_opt(CmdLineOptList *list, CmdLineOpt *var);
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_CONTEXT_CRACKING_H
|
#ifndef BASE_CONTEXT_CRACKING_H
|
||||||
#define BASE_CONTEXT_CRACKING_H
|
#define BASE_CONTEXT_CRACKING_H
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Clang OS/Arch Cracking
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
|
|
||||||
# define COMPILER_CLANG 1
|
# define COMPILER_CLANG 1
|
||||||
@@ -18,7 +15,7 @@
|
|||||||
# elif defined(__APPLE__) && defined(__MACH__)
|
# elif defined(__APPLE__) && defined(__MACH__)
|
||||||
# define OS_MAC 1
|
# define OS_MAC 1
|
||||||
# else
|
# else
|
||||||
# error This compiler/OS combo is not supported.
|
# error This compiler/platform combo is not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||||
@@ -30,40 +27,17 @@
|
|||||||
# elif defined(__arm__)
|
# elif defined(__arm__)
|
||||||
# define ARCH_ARM32 1
|
# define ARCH_ARM32 1
|
||||||
# else
|
# else
|
||||||
# error Architecture not supported.
|
# error architecture not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MSVC OS/Arch Cracking
|
|
||||||
|
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
# define COMPILER_MSVC 1
|
# define COMPILER_CL 1
|
||||||
|
|
||||||
# if _MSC_VER >= 1920
|
|
||||||
# define COMPILER_MSVC_YEAR 2019
|
|
||||||
# elif _MSC_VER >= 1910
|
|
||||||
# define COMPILER_MSVC_YEAR 2017
|
|
||||||
# elif _MSC_VER >= 1900
|
|
||||||
# define COMPILER_MSVC_YEAR 2015
|
|
||||||
# elif _MSC_VER >= 1800
|
|
||||||
# define COMPILER_MSVC_YEAR 2013
|
|
||||||
# elif _MSC_VER >= 1700
|
|
||||||
# define COMPILER_MSVC_YEAR 2012
|
|
||||||
# elif _MSC_VER >= 1600
|
|
||||||
# define COMPILER_MSVC_YEAR 2010
|
|
||||||
# elif _MSC_VER >= 1500
|
|
||||||
# define COMPILER_MSVC_YEAR 2008
|
|
||||||
# elif _MSC_VER >= 1400
|
|
||||||
# define COMPILER_MSVC_YEAR 2005
|
|
||||||
# else
|
|
||||||
# define COMPILER_MSVC_YEAR 0
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(_WIN32)
|
# if defined(_WIN32)
|
||||||
# define OS_WINDOWS 1
|
# define OS_WINDOWS 1
|
||||||
# else
|
# else
|
||||||
# error This compiler/OS combo is not supported.
|
# error This compiler/platform combo is not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(_M_AMD64)
|
# if defined(_M_AMD64)
|
||||||
@@ -75,12 +49,9 @@
|
|||||||
# elif defined(_M_ARM)
|
# elif defined(_M_ARM)
|
||||||
# define ARCH_ARM32 1
|
# define ARCH_ARM32 1
|
||||||
# else
|
# else
|
||||||
# error Architecture not supported.
|
# error architecture not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: GCC OS/Arch Cracking
|
|
||||||
|
|
||||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||||
|
|
||||||
# define COMPILER_GCC 1
|
# define COMPILER_GCC 1
|
||||||
@@ -88,7 +59,7 @@
|
|||||||
# if defined(__gnu_linux__) || defined(__linux__)
|
# if defined(__gnu_linux__) || defined(__linux__)
|
||||||
# define OS_LINUX 1
|
# define OS_LINUX 1
|
||||||
# else
|
# else
|
||||||
# error This compiler/OS combo is not supported.
|
# error This compiler/platform combo is not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
|
||||||
@@ -100,100 +71,26 @@
|
|||||||
# elif defined(__arm__)
|
# elif defined(__arm__)
|
||||||
# define ARCH_ARM32 1
|
# define ARCH_ARM32 1
|
||||||
# else
|
# else
|
||||||
# error Architecture not supported.
|
# error architecture not supported yet
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# error Compiler not supported.
|
# error This compiler is not supported yet
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Arch Cracking
|
|
||||||
|
|
||||||
#if defined(ARCH_X64)
|
#if defined(ARCH_X64)
|
||||||
# define ARCH_64BIT 1
|
# define ARCH_64BIT 1
|
||||||
#elif defined(ARCH_X86)
|
#elif defined(ARCH_X86)
|
||||||
# define ARCH_32BIT 1
|
# define ARCH_32BIT 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
|
||||||
# define ARCH_LITTLE_ENDIAN 1
|
|
||||||
#else
|
|
||||||
# error Endianness of this architecture not understood by context cracker.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Language Cracking
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
# define LANG_CPP 1
|
# define LANG_CPP 1
|
||||||
#else
|
#else
|
||||||
# define LANG_C 1
|
# define LANG_C 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
// zeroify
|
||||||
//~ rjf: Build Option Cracking
|
|
||||||
|
|
||||||
#if !defined(BUILD_DEBUG)
|
|
||||||
# define BUILD_DEBUG 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_TESTS)
|
|
||||||
# define BUILD_TESTS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_SUPPLEMENTARY_UNIT)
|
|
||||||
# define BUILD_SUPPLEMENTARY_UNIT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_ENTRY_DEFINING_UNIT)
|
|
||||||
# define BUILD_ENTRY_DEFINING_UNIT 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_CONSOLE_INTERFACE)
|
|
||||||
# define BUILD_CONSOLE_INTERFACE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_MAJOR)
|
|
||||||
# define BUILD_VERSION_MAJOR 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_MINOR)
|
|
||||||
# define BUILD_VERSION_MINOR 9
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_VERSION_PATCH)
|
|
||||||
# define BUILD_VERSION_PATCH 28
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
|
||||||
#if BUILD_DEBUG
|
|
||||||
# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]"
|
|
||||||
#else
|
|
||||||
# define BUILD_MODE_STRING_LITERAL_APPEND ""
|
|
||||||
#endif
|
|
||||||
#if defined(BUILD_GIT_HASH)
|
|
||||||
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]"
|
|
||||||
#else
|
|
||||||
# define BUILD_GIT_HASH_STRING_LITERAL_APPEND ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_TITLE)
|
|
||||||
# define BUILD_TITLE "Untitled"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL)
|
|
||||||
# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL)
|
|
||||||
# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGames/raddebugger/issues"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BUILD_TITLE_STRING_LITERAL BUILD_TITLE " (" BUILD_VERSION_STRING_LITERAL " " BUILD_RELEASE_PHASE_STRING_LITERAL ") - " __DATE__ "" BUILD_GIT_HASH_STRING_LITERAL_APPEND BUILD_MODE_STRING_LITERAL_APPEND
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Zero All Undefined Options
|
|
||||||
|
|
||||||
#if !defined(ARCH_32BIT)
|
#if !defined(ARCH_32BIT)
|
||||||
# define ARCH_32BIT 0
|
# define ARCH_32BIT 0
|
||||||
@@ -213,8 +110,8 @@
|
|||||||
#if !defined(ARCH_ARM32)
|
#if !defined(ARCH_ARM32)
|
||||||
# define ARCH_ARM32 0
|
# define ARCH_ARM32 0
|
||||||
#endif
|
#endif
|
||||||
#if !defined(COMPILER_MSVC)
|
#if !defined(COMPILER_CL)
|
||||||
# define COMPILER_MSVC 0
|
# define COMPILER_CL 0
|
||||||
#endif
|
#endif
|
||||||
#if !defined(COMPILER_GCC)
|
#if !defined(COMPILER_GCC)
|
||||||
# define COMPILER_GCC 0
|
# define COMPILER_GCC 0
|
||||||
@@ -238,58 +135,10 @@
|
|||||||
# define LANG_C 0
|
# define LANG_C 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86
|
||||||
//~ rjf: Unsupported Errors
|
# define ARCH_LITTLE_ENDIAN 1
|
||||||
|
#else
|
||||||
#if ARCH_X86
|
# error Endianness of this architecture not understood by context cracker
|
||||||
# error You tried to build in x86 (32 bit) mode, but currently, only building in x64 (64 bit) mode is supported.
|
|
||||||
#endif
|
|
||||||
#if !ARCH_X64
|
|
||||||
# error You tried to build with an unsupported architecture. Currently, only building in x64 mode is supported.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// extra intrinisc includes, so older clang versions are happy
|
|
||||||
// when optiona intrinsics like avx2 & avx512 are used later
|
|
||||||
// these must come first before any other intrinsic includes
|
|
||||||
// otherwise compiler will define macros that prevent declarations
|
|
||||||
// of intrinsics when included next time
|
|
||||||
|
|
||||||
#if ARCH_X64 && COMPILER_CLANG
|
|
||||||
# if defined(__IMMINTRIN_H)
|
|
||||||
# error "include this header before immintrin.h / x86intrin.h / intrin.h"
|
|
||||||
# endif
|
|
||||||
# pragma clang diagnostic push
|
|
||||||
# pragma clang diagnostic ignored "-Wreserved-macro-identifier"
|
|
||||||
# pragma push_macro("__SHA__")
|
|
||||||
# pragma push_macro("__AVX__")
|
|
||||||
# pragma push_macro("__AVX2__")
|
|
||||||
# pragma push_macro("__BMI2__")
|
|
||||||
# pragma push_macro("__SSE4_1__")
|
|
||||||
# pragma push_macro("__AVX512F__")
|
|
||||||
# pragma push_macro("__AVX512VL__")
|
|
||||||
# pragma push_macro("__AVX512BW__")
|
|
||||||
# pragma push_macro("__AVX512VBMI__")
|
|
||||||
# define __SHA__ 1
|
|
||||||
# define __AVX__ 1
|
|
||||||
# define __AVX2__ 1
|
|
||||||
# define __BMI2__ 1
|
|
||||||
# define __SSE4_1__ 1
|
|
||||||
# define __AVX512F__ 1
|
|
||||||
# define __AVX512VL__ 1
|
|
||||||
# define __AVX512BW__ 1
|
|
||||||
# define __AVX512VBMI__ 1
|
|
||||||
# include <immintrin.h>
|
|
||||||
# pragma pop_macro("__AVX512VBMI__")
|
|
||||||
# pragma pop_macro("__AVX512BW__")
|
|
||||||
# pragma pop_macro("__AVX512VL__")
|
|
||||||
# pragma pop_macro("__AVX512F__")
|
|
||||||
# pragma pop_macro("__SSE4_1__")
|
|
||||||
# pragma pop_macro("__BMI2__")
|
|
||||||
# pragma pop_macro("__AVX2__")
|
|
||||||
# pragma pop_macro("__AVX__")
|
|
||||||
# pragma pop_macro("__SHA__")
|
|
||||||
# pragma clang diagnostic pop
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // BASE_CONTEXT_CRACKING_H
|
#endif // BASE_CONTEXT_CRACKING_H
|
||||||
|
|||||||
@@ -1,809 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Safe Casts
|
|
||||||
|
|
||||||
internal U16
|
|
||||||
safe_cast_u16(U32 x)
|
|
||||||
{
|
|
||||||
AssertAlways(x <= max_U16);
|
|
||||||
U16 result = (U16)x;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U32
|
|
||||||
safe_cast_u32(U64 x)
|
|
||||||
{
|
|
||||||
AssertAlways(x <= max_U32);
|
|
||||||
U32 result = (U32)x;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal S32
|
|
||||||
safe_cast_s32(S64 x)
|
|
||||||
{
|
|
||||||
AssertAlways(x <= max_S32);
|
|
||||||
S32 result = (S32)x;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Large Base Type Functions
|
|
||||||
|
|
||||||
internal U128
|
|
||||||
u128_zero(void)
|
|
||||||
{
|
|
||||||
U128 v = {0};
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U128
|
|
||||||
u128_make(U64 v0, U64 v1)
|
|
||||||
{
|
|
||||||
U128 v = { .u64 = { v0, v1 }};
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
u128_match(U128 a, U128 b)
|
|
||||||
{
|
|
||||||
return MemoryMatchStruct(&a, &b);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Bit Patterns
|
|
||||||
|
|
||||||
internal U32
|
|
||||||
u32_from_u64_saturate(U64 x){
|
|
||||||
U32 x32 = (x > max_U32)?max_U32:(U32)x;
|
|
||||||
return(x32);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
u64_up_to_pow2(U64 x){
|
|
||||||
if (x == 0){
|
|
||||||
x = 1;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
x -= 1;
|
|
||||||
x |= (x >> 1);
|
|
||||||
x |= (x >> 2);
|
|
||||||
x |= (x >> 4);
|
|
||||||
x |= (x >> 8);
|
|
||||||
x |= (x >> 16);
|
|
||||||
x |= (x >> 32);
|
|
||||||
x += 1;
|
|
||||||
}
|
|
||||||
return(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal S32
|
|
||||||
extend_sign32(U32 x, U32 size)
|
|
||||||
{
|
|
||||||
U32 n = size * 8;
|
|
||||||
U32 m = (U32)1 << (n - 1);
|
|
||||||
S32 r = (S32)((x ^ m) - m);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal S64
|
|
||||||
extend_sign64(U64 x, U64 size)
|
|
||||||
{
|
|
||||||
U64 n = size * 8;
|
|
||||||
U64 m = (U64)1 << (n - 1);
|
|
||||||
S64 r = (S64)((x ^ m) - m);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal F32
|
|
||||||
inf32(void){
|
|
||||||
union { U32 u; F32 f; } x;
|
|
||||||
x.u = exponent32;
|
|
||||||
return(x.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal F32
|
|
||||||
neg_inf32(void){
|
|
||||||
union { U32 u; F32 f; } x;
|
|
||||||
x.u = sign32 | exponent32;
|
|
||||||
return(x.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U16
|
|
||||||
bswap_u16(U16 x)
|
|
||||||
{
|
|
||||||
U16 result = (((x & 0xFF00) >> 8) |
|
|
||||||
((x & 0x00FF) << 8));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U32
|
|
||||||
bswap_u32(U32 x)
|
|
||||||
{
|
|
||||||
U32 result = (((x & 0xFF000000) >> 24) |
|
|
||||||
((x & 0x00FF0000) >> 8) |
|
|
||||||
((x & 0x0000FF00) << 8) |
|
|
||||||
((x & 0x000000FF) << 24));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
bswap_u64(U64 x)
|
|
||||||
{
|
|
||||||
// TODO(nick): naive bswap, replace with something that is faster like an intrinsic
|
|
||||||
U64 result = (((x & 0xFF00000000000000ULL) >> 56) |
|
|
||||||
((x & 0x00FF000000000000ULL) >> 40) |
|
|
||||||
((x & 0x0000FF0000000000ULL) >> 24) |
|
|
||||||
((x & 0x000000FF00000000ULL) >> 8) |
|
|
||||||
((x & 0x00000000FF000000ULL) << 8) |
|
|
||||||
((x & 0x0000000000FF0000ULL) << 24) |
|
|
||||||
((x & 0x000000000000FF00ULL) << 40) |
|
|
||||||
((x & 0x00000000000000FFULL) << 56));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS)
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
count_bits_set32(U32 val)
|
|
||||||
{
|
|
||||||
return __popcnt(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
count_bits_set64(U64 val)
|
|
||||||
{
|
|
||||||
return __popcnt64(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
ctz32(U32 mask)
|
|
||||||
{
|
|
||||||
unsigned long idx;
|
|
||||||
_BitScanForward(&idx, mask);
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
ctz64(U64 mask)
|
|
||||||
{
|
|
||||||
unsigned long idx;
|
|
||||||
_BitScanForward64(&idx, mask);
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
clz32(U32 mask)
|
|
||||||
{
|
|
||||||
unsigned long idx;
|
|
||||||
_BitScanReverse(&idx, mask);
|
|
||||||
return 31 - idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
clz64(U64 mask)
|
|
||||||
{
|
|
||||||
unsigned long idx;
|
|
||||||
_BitScanReverse64(&idx, mask);
|
|
||||||
return 63 - idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif COMPILER_CLANG || COMPILER_GCC
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
count_bits_set32(U32 val)
|
|
||||||
{
|
|
||||||
return __builtin_popcount(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
count_bits_set64(U64 val)
|
|
||||||
{
|
|
||||||
return __builtin_popcountll(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
ctz32(U32 val)
|
|
||||||
{
|
|
||||||
return __builtin_ctz(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
clz32(U32 val)
|
|
||||||
{
|
|
||||||
return __builtin_clz(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
ctz64(U64 val)
|
|
||||||
{
|
|
||||||
return __builtin_ctzll(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
clz64(U64 val)
|
|
||||||
{
|
|
||||||
return __builtin_clzll(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
# error "Bit intrinsic functions not defined for this compiler."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Enum -> Sign
|
|
||||||
|
|
||||||
internal S32
|
|
||||||
sign_from_side_S32(Side side){
|
|
||||||
return((side == Side_Min)?-1:1);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal F32
|
|
||||||
sign_from_side_F32(Side side){
|
|
||||||
return((side == Side_Min)?-1.f:1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Memory Functions
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
memory_is_zero(void *ptr, U64 size)
|
|
||||||
{
|
|
||||||
B32 result = 1;
|
|
||||||
|
|
||||||
// break down size
|
|
||||||
U64 extra = (size&0x7);
|
|
||||||
U64 count8 = (size >> 3);
|
|
||||||
|
|
||||||
// check with 8-byte stride
|
|
||||||
U64 *p64 = (U64*)ptr;
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
for(U64 i = 0; i < count8; i += 1, p64 += 1)
|
|
||||||
{
|
|
||||||
if(*p64 != 0)
|
|
||||||
{
|
|
||||||
result = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check extra
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
U8 *p8 = (U8*)p64;
|
|
||||||
for(U64 i = 0; i < extra; i += 1, p8 += 1)
|
|
||||||
{
|
|
||||||
if(*p8 != 0)
|
|
||||||
{
|
|
||||||
result = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
done:;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void UBSAN_NO_ALIGN
|
|
||||||
memory_write16(void *ptr, U16 v)
|
|
||||||
{
|
|
||||||
MemoryCopy(ptr, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void UBSAN_NO_ALIGN
|
|
||||||
memory_write32(void *ptr, U32 v)
|
|
||||||
{
|
|
||||||
MemoryCopy(ptr, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void UBSAN_NO_ALIGN
|
|
||||||
memory_write64(void *ptr, U64 v)
|
|
||||||
{
|
|
||||||
MemoryCopy(ptr, &v, sizeof(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U8 UBSAN_NO_ALIGN
|
|
||||||
memory_read8(void *ptr)
|
|
||||||
{
|
|
||||||
U8 result;
|
|
||||||
MemoryCopy(&result, ptr, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U16 UBSAN_NO_ALIGN
|
|
||||||
memory_read16(void *ptr)
|
|
||||||
{
|
|
||||||
U16 result;
|
|
||||||
MemoryCopy(&result, ptr, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U32 UBSAN_NO_ALIGN
|
|
||||||
memory_read32(void *ptr)
|
|
||||||
{
|
|
||||||
U32 result;
|
|
||||||
MemoryCopy(&result, ptr, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64 UBSAN_NO_ALIGN
|
|
||||||
memory_read64(void *ptr)
|
|
||||||
{
|
|
||||||
U64 result;
|
|
||||||
MemoryCopy(&result, ptr, sizeof(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Text 2D Coordinate/Range Functions
|
|
||||||
|
|
||||||
internal TxtPt
|
|
||||||
txt_pt(S64 line, S64 column)
|
|
||||||
{
|
|
||||||
TxtPt p = {0};
|
|
||||||
p.line = line;
|
|
||||||
p.column = column;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
txt_pt_match(TxtPt a, TxtPt b)
|
|
||||||
{
|
|
||||||
return a.line == b.line && a.column == b.column;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
txt_pt_less_than(TxtPt a, TxtPt b)
|
|
||||||
{
|
|
||||||
B32 result = 0;
|
|
||||||
if(a.line < b.line)
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
else if(a.line == b.line)
|
|
||||||
{
|
|
||||||
result = a.column < b.column;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal TxtPt
|
|
||||||
txt_pt_min(TxtPt a, TxtPt b)
|
|
||||||
{
|
|
||||||
TxtPt result = b;
|
|
||||||
if(txt_pt_less_than(a, b))
|
|
||||||
{
|
|
||||||
result = a;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal TxtPt
|
|
||||||
txt_pt_max(TxtPt a, TxtPt b)
|
|
||||||
{
|
|
||||||
TxtPt result = a;
|
|
||||||
if(txt_pt_less_than(a, b))
|
|
||||||
{
|
|
||||||
result = b;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal TxtRng
|
|
||||||
txt_rng(TxtPt min, TxtPt max)
|
|
||||||
{
|
|
||||||
TxtRng range = {0};
|
|
||||||
if(txt_pt_less_than(min, max))
|
|
||||||
{
|
|
||||||
range.min = min;
|
|
||||||
range.max = max;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
range.min = max;
|
|
||||||
range.max = min;
|
|
||||||
}
|
|
||||||
return range;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal TxtRng
|
|
||||||
txt_rng_intersect(TxtRng a, TxtRng b)
|
|
||||||
{
|
|
||||||
TxtRng result = {0};
|
|
||||||
result.min = txt_pt_max(a.min, b.min);
|
|
||||||
result.max = txt_pt_min(a.max, b.max);
|
|
||||||
if(txt_pt_less_than(result.max, result.min))
|
|
||||||
{
|
|
||||||
MemoryZeroStruct(&result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal TxtRng
|
|
||||||
txt_rng_union(TxtRng a, TxtRng b)
|
|
||||||
{
|
|
||||||
TxtRng result = {0};
|
|
||||||
result.min = txt_pt_min(a.min, b.min);
|
|
||||||
result.max = txt_pt_max(a.max, b.max);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
txt_rng_contains(TxtRng r, TxtPt pt)
|
|
||||||
{
|
|
||||||
B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) &&
|
|
||||||
txt_pt_less_than(pt, r.max));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Toolchain/Environment Enum Functions
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
bit_size_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
// TODO(rjf): metacode
|
|
||||||
U64 arch_bitsize = 0;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
case Arch_x64: arch_bitsize = 64; break;
|
|
||||||
case Arch_x86: arch_bitsize = 32; break;
|
|
||||||
case Arch_arm64: arch_bitsize = 64; break;
|
|
||||||
case Arch_arm32: arch_bitsize = 32; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
return arch_bitsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
byte_size_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
return bit_size_from_arch(arch) / 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
max_ops_per_instruction_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
U64 max_ops = 0;
|
|
||||||
switch (arch)
|
|
||||||
{
|
|
||||||
case Arch_Null: break;
|
|
||||||
case Arch_x64: max_ops = 1; break;
|
|
||||||
case Arch_x86:
|
|
||||||
case Arch_arm32:
|
|
||||||
case Arch_arm64: NotImplemented; break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
return max_ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
min_instruction_size_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
U64 min_instruction_size = 0;
|
|
||||||
switch(arch)
|
|
||||||
{
|
|
||||||
case Arch_Null: break;
|
|
||||||
case Arch_x64: min_instruction_size = 1; break;
|
|
||||||
case Arch_x86:
|
|
||||||
case Arch_arm32:
|
|
||||||
case Arch_arm64: NotImplemented; break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
return min_instruction_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
max_instruction_size_from_arch(Arch arch)
|
|
||||||
{
|
|
||||||
// TODO(rjf): make this real
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Time Functions
|
|
||||||
|
|
||||||
internal DenseTime
|
|
||||||
dense_time_from_date_time(DateTime date_time){
|
|
||||||
DenseTime result = 0;
|
|
||||||
result += date_time.year;
|
|
||||||
result *= 12;
|
|
||||||
result += date_time.mon;
|
|
||||||
result *= 31;
|
|
||||||
result += date_time.day;
|
|
||||||
result *= 24;
|
|
||||||
result += date_time.hour;
|
|
||||||
result *= 60;
|
|
||||||
result += date_time.min;
|
|
||||||
result *= 61;
|
|
||||||
result += date_time.sec;
|
|
||||||
result *= 1000;
|
|
||||||
result += date_time.msec;
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DateTime
|
|
||||||
date_time_from_dense_time(DenseTime time){
|
|
||||||
DateTime result = {0};
|
|
||||||
result.msec = time%1000;
|
|
||||||
time /= 1000;
|
|
||||||
result.sec = time%61;
|
|
||||||
time /= 61;
|
|
||||||
result.min = time%60;
|
|
||||||
time /= 60;
|
|
||||||
result.hour = time%24;
|
|
||||||
time /= 24;
|
|
||||||
result.day = time%31;
|
|
||||||
time /= 31;
|
|
||||||
result.mon = time%12;
|
|
||||||
time /= 12;
|
|
||||||
Assert(time <= max_U32);
|
|
||||||
result.year = (U32)time;
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DateTime
|
|
||||||
date_time_from_micro_seconds(U64 time){
|
|
||||||
DateTime result = {0};
|
|
||||||
result.micro_sec = time%1000;
|
|
||||||
time /= 1000;
|
|
||||||
result.msec = time%1000;
|
|
||||||
time /= 1000;
|
|
||||||
result.sec = time%60;
|
|
||||||
time /= 60;
|
|
||||||
result.min = time%60;
|
|
||||||
time /= 60;
|
|
||||||
result.hour = time%24;
|
|
||||||
time /= 24;
|
|
||||||
result.day = time%31;
|
|
||||||
time /= 31;
|
|
||||||
result.mon = time%12;
|
|
||||||
time /= 12;
|
|
||||||
Assert(time <= max_U32);
|
|
||||||
result.year = (U32)time;
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DateTime
|
|
||||||
date_time_from_unix_time(U64 unix_time)
|
|
||||||
{
|
|
||||||
DateTime date = {0};
|
|
||||||
date.year = 1970;
|
|
||||||
date.day = 1 + (unix_time / 86400);
|
|
||||||
date.sec = (U32)unix_time % 60;
|
|
||||||
date.min = (U32)(unix_time / 60) % 60;
|
|
||||||
date.hour = (U32)(unix_time / 3600) % 24;
|
|
||||||
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
for(date.month = 0; date.month < 12; ++date.month)
|
|
||||||
{
|
|
||||||
U64 c = 0;
|
|
||||||
switch(date.month)
|
|
||||||
{
|
|
||||||
case Month_Jan: c = 31; break;
|
|
||||||
case Month_Feb:
|
|
||||||
{
|
|
||||||
if((date.year % 4 == 0) && ((date.year % 100) != 0 || (date.year % 400) == 0))
|
|
||||||
{
|
|
||||||
c = 29;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c = 28;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case Month_Mar: c = 31; break;
|
|
||||||
case Month_Apr: c = 30; break;
|
|
||||||
case Month_May: c = 31; break;
|
|
||||||
case Month_Jun: c = 30; break;
|
|
||||||
case Month_Jul: c = 31; break;
|
|
||||||
case Month_Aug: c = 31; break;
|
|
||||||
case Month_Sep: c = 30; break;
|
|
||||||
case Month_Oct: c = 31; break;
|
|
||||||
case Month_Nov: c = 30; break;
|
|
||||||
case Month_Dec: c = 31; break;
|
|
||||||
default: InvalidPath;
|
|
||||||
}
|
|
||||||
if(date.day <= c)
|
|
||||||
{
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
date.day -= c;
|
|
||||||
}
|
|
||||||
++date.year;
|
|
||||||
}
|
|
||||||
exit:;
|
|
||||||
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Wrapped Ring Buffer Reads/Writes
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
wrapped_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
|
|
||||||
{
|
|
||||||
Assert(src_data_size <= ring_size);
|
|
||||||
{
|
|
||||||
U64 ring_off = ring_pos%ring_size;
|
|
||||||
U64 bytes_before_split = ring_size-ring_off;
|
|
||||||
U64 pre_split_bytes = Min(bytes_before_split, src_data_size);
|
|
||||||
U64 pst_split_bytes = src_data_size-pre_split_bytes;
|
|
||||||
void *pre_split_data = src_data;
|
|
||||||
void *pst_split_data = ((U8 *)src_data + pre_split_bytes);
|
|
||||||
MemoryCopy(ring_base+ring_off, pre_split_data, pre_split_bytes);
|
|
||||||
MemoryCopy(ring_base+0, pst_split_data, pst_split_bytes);
|
|
||||||
}
|
|
||||||
return src_data_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
wrapped_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
|
|
||||||
{
|
|
||||||
Assert(read_size <= ring_size);
|
|
||||||
{
|
|
||||||
U64 ring_off = ring_pos%ring_size;
|
|
||||||
U64 bytes_before_split = ring_size-ring_off;
|
|
||||||
U64 pre_split_bytes = Min(bytes_before_split, read_size);
|
|
||||||
U64 pst_split_bytes = read_size-pre_split_bytes;
|
|
||||||
MemoryCopy(dst_data, ring_base+ring_off, pre_split_bytes);
|
|
||||||
MemoryCopy((U8 *)dst_data + pre_split_bytes, ring_base+0, pst_split_bytes);
|
|
||||||
}
|
|
||||||
return read_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
u64_array_bsearch(U64 *arr, U64 count, U64 value)
|
|
||||||
{
|
|
||||||
if(count > 1 && arr[0] <= value && value < arr[count-1])
|
|
||||||
{
|
|
||||||
U64 l = 0;
|
|
||||||
U64 r = count - 1;
|
|
||||||
for(; l <= r; )
|
|
||||||
{
|
|
||||||
U64 m = l + (r - l) / 2;
|
|
||||||
if(arr[m] == value)
|
|
||||||
{
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
else if(arr[m] < value)
|
|
||||||
{
|
|
||||||
l = m + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r = m - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (count == 1 && arr[0] == value)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return max_U64;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
|
|
||||||
internal U32
|
|
||||||
idx_of_zero_byte64(U8 *ptr, U64 size)
|
|
||||||
{
|
|
||||||
Assert(size == 8);
|
|
||||||
#if ARCH_X64
|
|
||||||
__m128i v = _mm_loadl_epi64((__m128i*)ptr);
|
|
||||||
__m128i m = _mm_cmpeq_epi8(v, _mm_setzero_si128());
|
|
||||||
U32 bits = _mm_movemask_epi8(m);
|
|
||||||
return ctz32(bits);
|
|
||||||
#else
|
|
||||||
U64 x;
|
|
||||||
MemoryCopyStruct(&x, ptr);
|
|
||||||
U64 splat = ~0ULL / 255;
|
|
||||||
U64 mask_lsb = 0x01 * splat;
|
|
||||||
U64 mask_msb = 0x80 * splat;
|
|
||||||
U64 t = (x - mask_lsb) & (~x & mask_msb);
|
|
||||||
return ctz64(t) / 8;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
index_of_zero_u32(U32 *ptr, U64 count)
|
|
||||||
{
|
|
||||||
for (U64 i = 0; i < count; i += 1) {
|
|
||||||
if (ptr[i] == 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max_U64;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
index_of_zero_u64(U64 *ptr, U64 count)
|
|
||||||
{
|
|
||||||
for (U64 i = 0; i < count; i += 1) {
|
|
||||||
if (ptr[i] == 0) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max_U64;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
count_digits_u64(U64 v, U64 radix)
|
|
||||||
{
|
|
||||||
if (v == 0) { return 1; }
|
|
||||||
U64 count = 0;
|
|
||||||
for (U64 x = v; x > 0; x /= radix) { count += 1; }
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Third Party Includes
|
|
||||||
|
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wsign-conversion"
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#pragma warning (push, 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
# define STB_SPRINTF_IMPLEMENTATION
|
|
||||||
# define STB_SPRINTF_STATIC
|
|
||||||
# include "third_party/stb/stb_sprintf.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#pragma warning (pop, 0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: String <-> Integer Tables
|
|
||||||
|
|
||||||
read_only global U8 integer_symbols[16] =
|
|
||||||
{
|
|
||||||
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',
|
|
||||||
};
|
|
||||||
|
|
||||||
// NOTE(rjf): Includes reverses for uppercase and lowercase hex.
|
|
||||||
read_only global U8 integer_symbol_reverse[128] =
|
|
||||||
{
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
read_only global U8 base64[64] =
|
|
||||||
{
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
|
||||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
|
||||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
|
||||||
'_', '$',
|
|
||||||
};
|
|
||||||
|
|
||||||
read_only global U8 base64_reverse[128] =
|
|
||||||
{
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0xFF,0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,
|
|
||||||
0xFF,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,
|
|
||||||
0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0xFF,0x3E,
|
|
||||||
0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
|
|
||||||
0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0xFF,0xFF,0xFF,0xFF,0xFF,
|
|
||||||
};
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_DYNAMIC_LIBARIES_H
|
|
||||||
#define BASE_DYNAMIC_LIBARIES_H
|
|
||||||
|
|
||||||
typedef struct Library Library;
|
|
||||||
struct Library
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Dynamically-Loaded Libraries
|
|
||||||
|
|
||||||
internal Library library_open(String8 path);
|
|
||||||
internal void library_close(Library lib);
|
|
||||||
internal VoidProc *library_load_proc(Library lib, String8 name);
|
|
||||||
|
|
||||||
#endif // BASE_DYNAMIC_LIBARIES_H
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
global U64 global_update_tick_idx = 0;
|
|
||||||
global U64 async_threads_count = 0;
|
|
||||||
global CondVar async_tick_start_cond_var = {0};
|
|
||||||
global Mutex async_tick_start_mutex = {0};
|
|
||||||
global Mutex async_tick_stop_mutex = {0};
|
|
||||||
global B32 async_loop_again = 0;
|
|
||||||
global B32 async_loop_again_high_priority = 0;
|
|
||||||
global B32 global_async_exit = 0;
|
|
||||||
thread_static B32 is_async_thread = 0;
|
|
||||||
|
|
||||||
// NOTE(rjf): defined by target
|
|
||||||
raddbg_entry_point(entry_point);
|
|
||||||
internal void entry_point(CmdLine *cmdline);
|
|
||||||
|
|
||||||
internal void
|
|
||||||
main_thread_base_entry_point(int arguments_count, char **arguments)
|
|
||||||
{
|
|
||||||
ThreadNameF("main_thread");
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
|
|
||||||
//- rjf: set up async thread group info
|
|
||||||
async_tick_start_cond_var = cond_var_alloc();
|
|
||||||
async_tick_start_mutex = mutex_alloc();
|
|
||||||
async_tick_stop_mutex = mutex_alloc();
|
|
||||||
|
|
||||||
//- rjf: set up telemetry
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
local_persist char tm_data[MB(64)];
|
|
||||||
tmLoadLibrary(TM_RELEASE);
|
|
||||||
tmSetMaxThreadCount(256);
|
|
||||||
tmInitialize(sizeof(tm_data), tm_data);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: set up spall
|
|
||||||
#if PROFILE_SPALL
|
|
||||||
spall_profile = spall_init_file_ex("spall_capture", 1, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: parse command line
|
|
||||||
String8List command_line_argument_strings = {0};
|
|
||||||
{
|
|
||||||
for EachIndex(idx, arguments_count)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &command_line_argument_strings, str8_cstring(arguments[idx]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings);
|
|
||||||
|
|
||||||
//- rjf: begin captures
|
|
||||||
B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture"));
|
|
||||||
if(capture)
|
|
||||||
{
|
|
||||||
ProfBeginCapture(arguments[0]);
|
|
||||||
ProfMsg(BUILD_TITLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: initialize all included layers
|
|
||||||
#if defined(HTTP_H) && !defined(HTTP_INIT_MANUAL)
|
|
||||||
http_init();
|
|
||||||
#endif
|
|
||||||
#if defined(SYMBOL_SERVER_H) && !defined(SMSV_INIT_MANUAL)
|
|
||||||
smsv_init();
|
|
||||||
#endif
|
|
||||||
#if defined(ARTIFACT_CACHE_H) && !defined(AC_INIT_MANUAL)
|
|
||||||
ac_init();
|
|
||||||
#endif
|
|
||||||
#if defined(CONTENT_H) && !defined(C_INIT_MANUAL)
|
|
||||||
c_init();
|
|
||||||
#endif
|
|
||||||
#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL)
|
|
||||||
fs_init();
|
|
||||||
#endif
|
|
||||||
#if defined(MUTABLE_TEXT_H) && !defined(MTX_INIT_MANUAL)
|
|
||||||
mtx_init();
|
|
||||||
#endif
|
|
||||||
#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL)
|
|
||||||
di_init(&cmdline);
|
|
||||||
#endif
|
|
||||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
|
||||||
dmn_init();
|
|
||||||
#endif
|
|
||||||
#if defined(DBG_ENGINE_CORE_H) && !defined(D_INIT_MANUAL)
|
|
||||||
d_init();
|
|
||||||
#endif
|
|
||||||
#if defined(WINDOW_MANAGER_H) && !defined(WM_INIT_MANUAL)
|
|
||||||
wm_init();
|
|
||||||
#endif
|
|
||||||
#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL)
|
|
||||||
fp_init();
|
|
||||||
#endif
|
|
||||||
#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL)
|
|
||||||
r_init(&cmdline);
|
|
||||||
#endif
|
|
||||||
#if defined(FONT_CACHE_H) && !defined(FNT_INIT_MANUAL)
|
|
||||||
fnt_init();
|
|
||||||
#endif
|
|
||||||
#if defined(RADDBG_CORE_H) && !defined(RD_INIT_MANUAL)
|
|
||||||
rd_init(&cmdline);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: launch async threads
|
|
||||||
#if NEED_ASYNC
|
|
||||||
Thread *async_threads = 0;
|
|
||||||
U64 lane_broadcast_val = 0;
|
|
||||||
{
|
|
||||||
U64 num_main_threads = 1;
|
|
||||||
#if defined(DBG_ENGINE_CORE_H)
|
|
||||||
num_main_threads += 1;
|
|
||||||
#endif
|
|
||||||
U64 num_async_threads = get_system_info()->logical_processor_count;
|
|
||||||
U64 num_main_threads_clamped = Min(num_async_threads, num_main_threads);
|
|
||||||
num_async_threads -= num_main_threads_clamped;
|
|
||||||
String8 num_async_threads_string = cmd_line_string(&cmdline, str8_lit("async_thread_count"));
|
|
||||||
if(num_async_threads_string.size != 0)
|
|
||||||
{
|
|
||||||
try_u64_from_str8_c_rules(num_async_threads_string, &num_async_threads);
|
|
||||||
}
|
|
||||||
num_async_threads = Max(1, num_async_threads);
|
|
||||||
Barrier barrier = barrier_alloc(num_async_threads);
|
|
||||||
LaneCtx *lane_ctxs = push_array(scratch.arena, LaneCtx, num_async_threads);
|
|
||||||
async_threads_count = num_async_threads;
|
|
||||||
async_threads = push_array(scratch.arena, Thread, async_threads_count);
|
|
||||||
for EachIndex(idx, num_async_threads)
|
|
||||||
{
|
|
||||||
lane_ctxs[idx].lane_idx = idx;
|
|
||||||
lane_ctxs[idx].lane_count = async_threads_count;
|
|
||||||
lane_ctxs[idx].barrier = barrier;
|
|
||||||
lane_ctxs[idx].broadcast_memory = &lane_broadcast_val;
|
|
||||||
async_threads[idx] = thread_launch(async_thread_entry_point, &lane_ctxs[idx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: call into entry point
|
|
||||||
entry_point(&cmdline);
|
|
||||||
|
|
||||||
//- rjf: join async threads
|
|
||||||
#if NEED_ASYNC
|
|
||||||
ins_atomic_u32_inc_eval(&global_async_exit);
|
|
||||||
ins_atomic_u32_inc_eval(&async_loop_again);
|
|
||||||
cond_var_broadcast(async_tick_start_cond_var);
|
|
||||||
for EachIndex(idx, async_threads_count)
|
|
||||||
{
|
|
||||||
thread_join(async_threads[idx], max_U64);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//- rjf: end captures
|
|
||||||
if(capture)
|
|
||||||
{
|
|
||||||
ProfEndCapture();
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_alloc();
|
|
||||||
tctx_select(tctx);
|
|
||||||
entry_point(params);
|
|
||||||
tctx_release(tctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
update_tick_idx(void)
|
|
||||||
{
|
|
||||||
U64 result = ins_atomic_u64_eval(&global_update_tick_idx);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
update(void)
|
|
||||||
{
|
|
||||||
ProfTick(0);
|
|
||||||
ins_atomic_u64_inc_eval(&global_update_tick_idx);
|
|
||||||
#if defined(FONT_CACHE_H)
|
|
||||||
fnt_frame();
|
|
||||||
#endif
|
|
||||||
#if OS_FEATURE_GRAPHICAL
|
|
||||||
B32 result = frame();
|
|
||||||
#else
|
|
||||||
B32 result = 0;
|
|
||||||
#endif
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
async_thread_entry_point(void *params)
|
|
||||||
{
|
|
||||||
LaneCtx lctx = *(LaneCtx *)params;
|
|
||||||
lane_ctx(lctx);
|
|
||||||
is_async_thread = 1;
|
|
||||||
ThreadNameF("async_thread_%I64u", lane_idx());
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
// rjf: wait for signal if we need, otherwise reset loop signal & continue
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
if(!ins_atomic_u32_eval(&async_loop_again))
|
|
||||||
{
|
|
||||||
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, now_time_us()+1000000);
|
|
||||||
}
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again, 0);
|
|
||||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0);
|
|
||||||
}
|
|
||||||
lane_sync();
|
|
||||||
|
|
||||||
// rjf: do all ticks for all layers
|
|
||||||
ProfScope("async tick")
|
|
||||||
{
|
|
||||||
#if defined(ARTIFACT_CACHE_H)
|
|
||||||
ac_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(CONTENT_H)
|
|
||||||
c_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(FILE_STREAM_H)
|
|
||||||
fs_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(HTTP_H)
|
|
||||||
http_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(SYMBOL_SERVER_H)
|
|
||||||
smsv_async_tick();
|
|
||||||
#endif
|
|
||||||
#if defined(DBG_INFO_H)
|
|
||||||
di_async_tick();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: take exit signal; break if set
|
|
||||||
lane_sync();
|
|
||||||
B32 need_exit = 0;
|
|
||||||
if(lane_idx() == 0)
|
|
||||||
{
|
|
||||||
need_exit = ins_atomic_u32_eval(&global_async_exit);
|
|
||||||
}
|
|
||||||
lane_sync_u64(&need_exit, 0);
|
|
||||||
if(need_exit)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_ENTRY_POINT_H
|
|
||||||
#define BASE_ENTRY_POINT_H
|
|
||||||
|
|
||||||
internal void main_thread_base_entry_point(int argc, char **argv);
|
|
||||||
internal void supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params);
|
|
||||||
internal U64 update_tick_idx(void);
|
|
||||||
internal B32 update(void);
|
|
||||||
internal void async_thread_entry_point(void *params);
|
|
||||||
|
|
||||||
#endif // BASE_ENTRY_POINT_H
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Handle Type Functions
|
|
||||||
|
|
||||||
internal File
|
|
||||||
file_zero(void)
|
|
||||||
{
|
|
||||||
File f = {0};
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
file_match(File a, File b)
|
|
||||||
{
|
|
||||||
B32 result = MemoryMatchStruct(&a, &b);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
data_from_file_path(Arena *arena, String8 path)
|
|
||||||
{
|
|
||||||
File file = file_open(AccessFlag_Read|AccessFlag_ShareRead, path);
|
|
||||||
FileProperties props = properties_from_file(file);
|
|
||||||
String8 data = string_from_file_range(arena, file, r1u64(0, props.size));
|
|
||||||
file_close(file);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
write_data_to_file_path(String8 path, String8 data)
|
|
||||||
{
|
|
||||||
B32 good = 0;
|
|
||||||
File file = file_open(AccessFlag_Write, path);
|
|
||||||
if(!file_match(file, file_zero()))
|
|
||||||
{
|
|
||||||
U64 bytes_written = file_write(file, r1u64(0, data.size), data.str);
|
|
||||||
good = (bytes_written == data.size);
|
|
||||||
file_close(file);
|
|
||||||
}
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
write_data_list_to_file_path(String8 path, String8List list)
|
|
||||||
{
|
|
||||||
B32 good = 0;
|
|
||||||
File file = file_open(AccessFlag_Write, path);
|
|
||||||
if(!file_match(file, file_zero()))
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
U64 write_buffer_size = KB(64);
|
|
||||||
U8 *write_buffer = push_array_no_zero(scratch.arena, U8, write_buffer_size);
|
|
||||||
U64 write_buffer_write_pos = 0;
|
|
||||||
U64 write_buffer_read_pos = 0;
|
|
||||||
U64 file_off = 0;
|
|
||||||
{
|
|
||||||
for(String8Node *n = list.first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
for(U64 n_off = 0; n_off < n->string.size;)
|
|
||||||
{
|
|
||||||
U64 write_buffer_unconsumed_size = (write_buffer_write_pos - write_buffer_read_pos);
|
|
||||||
U64 write_buffer_available_size = (write_buffer_size - write_buffer_unconsumed_size);
|
|
||||||
if(write_buffer_available_size == 0)
|
|
||||||
{
|
|
||||||
U64 file_write_size = file_write(file, r1u64(file_off, file_off+write_buffer_size), write_buffer);
|
|
||||||
if(file_write_size != write_buffer_size)
|
|
||||||
{
|
|
||||||
goto dbl_break;
|
|
||||||
}
|
|
||||||
file_off += write_buffer_size;
|
|
||||||
write_buffer_read_pos += write_buffer_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
U64 bytes_to_copy = Min(write_buffer_available_size, n->string.size - n_off);
|
|
||||||
write_buffer_write_pos += wrapped_write(write_buffer, write_buffer_size, write_buffer_write_pos, n->string.str + n_off, bytes_to_copy);
|
|
||||||
n_off += bytes_to_copy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(write_buffer_write_pos > write_buffer_read_pos)
|
|
||||||
{
|
|
||||||
U64 file_write_size = file_write(file, r1u64(file_off, file_off + (write_buffer_write_pos-write_buffer_read_pos)), write_buffer);
|
|
||||||
file_off += file_write_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dbl_break:;
|
|
||||||
good = (file_off == list.total_size);
|
|
||||||
file_close(file);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
append_data_to_file_path(String8 path, String8 data)
|
|
||||||
{
|
|
||||||
B32 good = 0;
|
|
||||||
if(data.size != 0)
|
|
||||||
{
|
|
||||||
File file = file_open(AccessFlag_Write|AccessFlag_Append, path);
|
|
||||||
if(!file_match(file, file_zero()))
|
|
||||||
{
|
|
||||||
U64 pos = properties_from_file(file).size;
|
|
||||||
U64 bytes_written = file_write(file, r1u64(pos, pos+data.size), data.str);
|
|
||||||
good = (bytes_written == data.size);
|
|
||||||
file_close(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal FileID
|
|
||||||
id_from_file_path(String8 path)
|
|
||||||
{
|
|
||||||
File file = file_open(AccessFlag_Read|AccessFlag_ShareRead, path);
|
|
||||||
FileID id = id_from_file(file);
|
|
||||||
file_close(file);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal S64
|
|
||||||
file_id_compare(FileID a, FileID b)
|
|
||||||
{
|
|
||||||
S64 cmp = MemoryCompare((void*)&a.v[0], (void*)&b.v[0], sizeof(a.v));
|
|
||||||
return cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
string_from_file_range(Arena *arena, File file, Rng1U64 range)
|
|
||||||
{
|
|
||||||
U64 pre_pos = arena_pos(arena);
|
|
||||||
String8 result;
|
|
||||||
result.size = dim_1u64(range);
|
|
||||||
result.str = push_array_no_zero(arena, U8, result.size);
|
|
||||||
U64 actual_read_size = file_read(file, range, result.str);
|
|
||||||
if(actual_read_size < result.size)
|
|
||||||
{
|
|
||||||
arena_pop_to(arena, pre_pos + actual_read_size);
|
|
||||||
result.size = actual_read_size;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
file_read_cstring(Arena *arena, File file, U64 off)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List block_list = {0};
|
|
||||||
for(U64 cursor = off, stride = 256;; cursor += stride)
|
|
||||||
{
|
|
||||||
U8 *raw_block = push_array_no_zero(scratch.arena, U8, stride);
|
|
||||||
U64 read_size = file_read(file, r1u64(cursor, cursor + stride), raw_block);
|
|
||||||
String8 block = str8_cstring_capped(raw_block, raw_block+read_size);
|
|
||||||
str8_list_push(scratch.arena, &block_list, block);
|
|
||||||
if(read_size != stride || (block.size+1 <= read_size && block.str[block.size] == 0))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String8 result = str8_list_join(arena, &block_list, 0);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_FILES_H
|
|
||||||
#define BASE_FILES_H
|
|
||||||
|
|
||||||
typedef U32 FileIterFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
FileIterFlag_SkipFolders = (1 << 0),
|
|
||||||
FileIterFlag_SkipFiles = (1 << 1),
|
|
||||||
FileIterFlag_SkipHiddenFiles = (1 << 2),
|
|
||||||
FileIterFlag_Done = (1 << 31),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct FileIter FileIter;
|
|
||||||
struct FileIter
|
|
||||||
{
|
|
||||||
FileIterFlags flags;
|
|
||||||
U8 memory[800];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct FileInfo FileInfo;
|
|
||||||
struct FileInfo
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
FileProperties props;
|
|
||||||
};
|
|
||||||
|
|
||||||
// nick: on-disk file identifier
|
|
||||||
typedef struct FileID FileID;
|
|
||||||
struct FileID
|
|
||||||
{
|
|
||||||
U64 v[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct File File;
|
|
||||||
struct File
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct FileMap FileMap;
|
|
||||||
struct FileMap
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Handle Type Functions
|
|
||||||
|
|
||||||
internal File file_zero(void);
|
|
||||||
internal B32 file_match(File a, File b);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Filesystem Helpers (Helpers, Implemented Once)
|
|
||||||
|
|
||||||
internal String8 data_from_file_path(Arena *arena, String8 path);
|
|
||||||
internal B32 write_data_to_file_path(String8 path, String8 data);
|
|
||||||
internal B32 write_data_list_to_file_path(String8 path, String8List list);
|
|
||||||
internal B32 append_data_to_file_path(String8 path, String8 data);
|
|
||||||
internal FileID id_from_file_path(String8 path);
|
|
||||||
internal S64 file_id_compare(FileID a, FileID b);
|
|
||||||
internal String8 string_from_file_range(Arena *arena, File file, Rng1U64 range);
|
|
||||||
internal String8 file_read_cstring(Arena *arena, File file, U64 off);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl File System (Implemented Per-OS)
|
|
||||||
|
|
||||||
//- rjf: files
|
|
||||||
internal File file_open(AccessFlags flags, String8 path);
|
|
||||||
internal void file_close(File file);
|
|
||||||
internal U64 file_read(File file, Rng1U64 rng, void *out_data);
|
|
||||||
#define file_read_struct(f, off, ptr) file_read((f), r1u64((off), (off)+sizeof(*(ptr))), (ptr))
|
|
||||||
internal U64 file_write(File file, Rng1U64 rng, void *data);
|
|
||||||
internal B32 file_set_times(File file, DateTime time);
|
|
||||||
internal FileProperties properties_from_file(File file);
|
|
||||||
internal FileID id_from_file(File file);
|
|
||||||
internal B32 file_reserve_size(File file, U64 size);
|
|
||||||
internal B32 delete_file_at_path(String8 path);
|
|
||||||
internal B32 copy_file_path(String8 dst, String8 src);
|
|
||||||
internal B32 move_file_path(String8 dst, String8 src);
|
|
||||||
internal String8 full_path_from_path(Arena *arena, String8 path);
|
|
||||||
internal B32 file_path_exists(String8 path);
|
|
||||||
internal B32 folder_path_exists(String8 path);
|
|
||||||
internal FileProperties properties_from_file_path(String8 path);
|
|
||||||
|
|
||||||
//- rjf: file maps
|
|
||||||
internal FileMap file_map_open(AccessFlags flags, File file);
|
|
||||||
internal void file_map_close(FileMap map);
|
|
||||||
internal void * file_map_view_open(FileMap map, AccessFlags flags, Rng1U64 range);
|
|
||||||
internal void file_map_view_close(FileMap map, void *ptr, Rng1U64 range);
|
|
||||||
|
|
||||||
//- rjf: directory iteration
|
|
||||||
internal FileIter *file_iter_begin(Arena *arena, String8 path, FileIterFlags flags);
|
|
||||||
internal B32 file_iter_next(Arena *arena, FileIter *iter, FileInfo *info_out);
|
|
||||||
internal void file_iter_end(FileIter *iter);
|
|
||||||
|
|
||||||
//- rjf: directory creation
|
|
||||||
internal B32 make_directory(String8 path);
|
|
||||||
|
|
||||||
#endif // BASE_FILES_H
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MD5
|
|
||||||
|
|
||||||
#include "third_party/martins_hash/md5.h"
|
|
||||||
|
|
||||||
internal MD5
|
|
||||||
md5_from_data(String8 data)
|
|
||||||
{
|
|
||||||
md5_ctx ctx = {0};
|
|
||||||
md5_init(&ctx);
|
|
||||||
md5_update(&ctx, (void*)data.str, data.size);
|
|
||||||
MD5 result = {0};
|
|
||||||
md5_finish(&ctx, result.u8);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: SHA
|
|
||||||
|
|
||||||
#include "third_party/martins_hash/sha1.h"
|
|
||||||
#include "third_party/martins_hash/sha256.h"
|
|
||||||
|
|
||||||
internal SHA1
|
|
||||||
sha1_from_data(String8 data)
|
|
||||||
{
|
|
||||||
SHA1 result = {0};
|
|
||||||
{
|
|
||||||
sha1_ctx ctx = {0};
|
|
||||||
sha1_init(&ctx);
|
|
||||||
sha1_update(&ctx, data.str, data.size);
|
|
||||||
sha1_finish(&ctx, result.u8);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal SHA256
|
|
||||||
sha256_from_data(String8 data)
|
|
||||||
{
|
|
||||||
SHA256 result = {0};
|
|
||||||
{
|
|
||||||
sha256_ctx ctx = {0};
|
|
||||||
sha256_init(&ctx);
|
|
||||||
sha256_update(&ctx, data.str, data.size);
|
|
||||||
sha256_finish(&ctx, result.u8);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_HASH_H
|
|
||||||
#define BASE_HASH_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Hash Result Types
|
|
||||||
|
|
||||||
typedef union MD5 MD5;
|
|
||||||
union MD5
|
|
||||||
{
|
|
||||||
U8 u8[16];
|
|
||||||
U16 u16[8];
|
|
||||||
U32 u32[4];
|
|
||||||
U64 u64[2];
|
|
||||||
U128 u128;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union SHA1 SHA1;
|
|
||||||
union SHA1
|
|
||||||
{
|
|
||||||
U8 u8[20];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union SHA256 SHA256;
|
|
||||||
union SHA256
|
|
||||||
{
|
|
||||||
U8 u8[32];
|
|
||||||
U16 u16[16];
|
|
||||||
U32 u32[8];
|
|
||||||
U64 u64[4];
|
|
||||||
U128 u128[2];
|
|
||||||
U256 u256;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: MD5
|
|
||||||
|
|
||||||
internal MD5 md5_from_data(String8 data);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: SHA
|
|
||||||
|
|
||||||
internal SHA1 sha1_from_data(String8 data);
|
|
||||||
internal SHA256 sha256_from_data(String8 data);
|
|
||||||
|
|
||||||
#endif // BASE_HASH_H
|
|
||||||
+8
-29
@@ -1,39 +1,18 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Base Includes
|
//~ rjf: Base Includes
|
||||||
|
|
||||||
#undef LAYER_COLOR
|
#undef RADDBG_LAYER_COLOR
|
||||||
#define LAYER_COLOR 0x3399ccff
|
#define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f
|
||||||
|
|
||||||
#include "base_core.c"
|
#include "base_types.c"
|
||||||
#include "base_profile.c"
|
#include "base_markup.c"
|
||||||
#include "base_memory.c"
|
|
||||||
#include "base_arena.c"
|
#include "base_arena.c"
|
||||||
#include "base_math.c"
|
#include "base_math.c"
|
||||||
#include "base_strings.c"
|
#include "base_string.c"
|
||||||
#include "base_memory_map.c"
|
|
||||||
#include "base_hash.c"
|
|
||||||
#include "base_system.c"
|
|
||||||
#include "base_threads.c"
|
|
||||||
#include "base_ring.c"
|
|
||||||
#include "base_thread_context.c"
|
#include "base_thread_context.c"
|
||||||
#include "base_files.c"
|
|
||||||
#include "base_shared_memory.c"
|
|
||||||
#include "base_processes.c"
|
|
||||||
#include "base_dynamic_libraries.c"
|
|
||||||
#include "base_command_line.c"
|
#include "base_command_line.c"
|
||||||
#include "base_markup.c"
|
#include "base_arena_dev.c"
|
||||||
#include "base_meta.c"
|
#include "base_bits.c"
|
||||||
#include "base_log.c"
|
|
||||||
#include "base_test.c"
|
|
||||||
#include "base_entry_point.c"
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
# include "win32/base/win32_base.c"
|
|
||||||
#elif OS_LINUX
|
|
||||||
# include "linux/base/linux_base.c"
|
|
||||||
#else
|
|
||||||
# error Operating system backend not found for base layer.
|
|
||||||
#endif
|
|
||||||
|
|||||||
+8
-28
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_INC_H
|
#ifndef BASE_INC_H
|
||||||
@@ -8,36 +8,16 @@
|
|||||||
//~ rjf: Base Includes
|
//~ rjf: Base Includes
|
||||||
|
|
||||||
#include "base_context_cracking.h"
|
#include "base_context_cracking.h"
|
||||||
|
#include "base_types.h"
|
||||||
#include "base_core.h"
|
#include "base_markup.h"
|
||||||
#include "base_profile.h"
|
#include "base_ins.h"
|
||||||
#include "base_memory.h"
|
#include "base_linked_lists.h"
|
||||||
#include "base_arena.h"
|
#include "base_arena.h"
|
||||||
#include "base_math.h"
|
#include "base_math.h"
|
||||||
#include "base_strings.h"
|
#include "base_string.h"
|
||||||
#include "base_memory_map.h"
|
|
||||||
#include "base_hash.h"
|
|
||||||
#include "base_system.h"
|
|
||||||
#include "base_threads.h"
|
|
||||||
#include "base_ring.h"
|
|
||||||
#include "base_thread_context.h"
|
#include "base_thread_context.h"
|
||||||
#include "base_files.h"
|
|
||||||
#include "base_shared_memory.h"
|
|
||||||
#include "base_processes.h"
|
|
||||||
#include "base_dynamic_libraries.h"
|
|
||||||
#include "base_command_line.h"
|
#include "base_command_line.h"
|
||||||
#include "base_markup.h"
|
#include "base_arena_dev.h"
|
||||||
#include "base_meta.h"
|
#include "base_bits.h"
|
||||||
#include "base_log.h"
|
|
||||||
#include "base_test.h"
|
|
||||||
#include "base_entry_point.h"
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
# include "win32/base/win32_base.h"
|
|
||||||
#elif OS_LINUX
|
|
||||||
# include "linux/base/linux_base.h"
|
|
||||||
#else
|
|
||||||
# error Operating system backend not found for base layer.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // BASE_INC_H
|
#endif // BASE_INC_H
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_INS_H
|
||||||
|
#define BASE_INS_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Implementations of Intrinsics
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
|
||||||
|
# include <windows.h>
|
||||||
|
# include <tmmintrin.h>
|
||||||
|
# include <wmmintrin.h>
|
||||||
|
# include <intrin.h>
|
||||||
|
|
||||||
|
# if ARCH_X64
|
||||||
|
# define ins_atomic_u64_eval(x) InterlockedAdd((volatile LONG *)(x), 0)
|
||||||
|
# define ins_atomic_u64_inc_eval(x) InterlockedIncrement64((volatile __int64 *)(x))
|
||||||
|
# define ins_atomic_u64_dec_eval(x) InterlockedDecrement64((volatile __int64 *)(x))
|
||||||
|
# define ins_atomic_u64_eval_assign(x,c) InterlockedExchange64((volatile __int64 *)(x),(c))
|
||||||
|
# define ins_atomic_u64_add_eval(x,c) InterlockedAdd((volatile LONG *)(x), c)
|
||||||
|
# define ins_atomic_u32_eval_assign(x,c) InterlockedExchange((volatile LONG *)(x),(c))
|
||||||
|
# define ins_atomic_u32_eval_cond_assign(x,k,c) InterlockedCompareExchange((volatile LONG *)(x),(k),(c))
|
||||||
|
# define ins_atomic_ptr_eval_assign(x,c) (void*)ins_atomic_u64_eval_assign((volatile __int64 *)(x), (__int64)(c))
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif OS_LINUX
|
||||||
|
|
||||||
|
# if ARCH_X64
|
||||||
|
# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
// TODO(allen):
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// NOTE(allen): Intrinsic Checks
|
||||||
|
|
||||||
|
#if ARCH_X64
|
||||||
|
|
||||||
|
# if !defined(ins_atomic_u64_inc_eval)
|
||||||
|
# error missing: ins_atomic_u64_inc_eval
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# error the intrinsic set for this arch is not developed
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif //BASE_INS_H
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_LINKED_LIST_H
|
||||||
|
#define BASE_LINKED_LIST_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Helpers
|
||||||
|
|
||||||
|
#define CheckNil(nil,p) ((p) == 0 || (p) == nil)
|
||||||
|
#define SetNil(nil,p) ((p) = nil)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Base Macros
|
||||||
|
|
||||||
|
//- rjf: Base Doubly-Linked-List Macros
|
||||||
|
#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \
|
||||||
|
((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\
|
||||||
|
CheckNil(nil,p) ? \
|
||||||
|
((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\
|
||||||
|
((p)==(l)) ? \
|
||||||
|
((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\
|
||||||
|
(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p))))
|
||||||
|
#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev)
|
||||||
|
#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next)
|
||||||
|
#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\
|
||||||
|
((n) == (l) ? (l) = (l)->prev : (0)),\
|
||||||
|
(CheckNil(nil,(n)->prev) ? (0) :\
|
||||||
|
((n)->prev->next = (n)->next)),\
|
||||||
|
(CheckNil(nil,(n)->next) ? (0) :\
|
||||||
|
((n)->next->prev = (n)->prev)))
|
||||||
|
|
||||||
|
//- rjf: Base Singly-Linked-List Queue Macros
|
||||||
|
#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||||
|
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||||
|
((l)->next=(n),(l)=(n),SetNil(nil,(n)->next)))
|
||||||
|
#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\
|
||||||
|
((f)=(l)=(n),SetNil(nil,(n)->next)):\
|
||||||
|
((n)->next=(f),(f)=(n)))
|
||||||
|
#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\
|
||||||
|
(SetNil(nil,f),SetNil(nil,l)):\
|
||||||
|
((f)=(f)->next))
|
||||||
|
|
||||||
|
//- rjf: Base Singly-Linked-List Stack Macros
|
||||||
|
#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n))
|
||||||
|
#define SLLStackPop_N(f,next) ((f)=(f)->next)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Convenience Wrappers
|
||||||
|
|
||||||
|
//- rjf: Doubly-Linked-List Wrappers
|
||||||
|
#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
||||||
|
#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev)
|
||||||
|
#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev)
|
||||||
|
#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev)
|
||||||
|
|
||||||
|
//- rjf: Singly-Linked-List Queue Wrappers
|
||||||
|
#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next)
|
||||||
|
#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next)
|
||||||
|
#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next)
|
||||||
|
#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next)
|
||||||
|
#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next)
|
||||||
|
#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next)
|
||||||
|
|
||||||
|
//- rjf: Singly-Linked-List Stack Wrappers
|
||||||
|
#define SLLStackPush(f,n) SLLStackPush_N(f,n,next)
|
||||||
|
#define SLLStackPop(f) SLLStackPop_N(f,next)
|
||||||
|
|
||||||
|
#endif //BASE_LINKED_LIST_H
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals/Thread-Locals
|
|
||||||
|
|
||||||
C_LINKAGE thread_static Log *log_active;
|
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
|
||||||
C_LINKAGE thread_static Log *log_active = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
String8 g_logs_folder;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Creation/Selection
|
|
||||||
|
|
||||||
internal Log *
|
|
||||||
log_alloc(void)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
Log *log = push_array(arena, Log, 1);
|
|
||||||
log->arena = arena;
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_release(Log *log)
|
|
||||||
{
|
|
||||||
arena_release(log->arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_select(Log *log)
|
|
||||||
{
|
|
||||||
log_active = log;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Building/Clearing
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_msg(LogMsgKind kind, String8 string)
|
|
||||||
{
|
|
||||||
if(log_active != 0 && log_active->top_scope != 0)
|
|
||||||
{
|
|
||||||
String8 string_copy = push_str8_copy(log_active->arena, string);
|
|
||||||
str8_list_push(log_active->arena, &log_active->top_scope->strings[kind], string_copy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_msgf(LogMsgKind kind, char *fmt, ...)
|
|
||||||
{
|
|
||||||
if(log_active != 0)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
log_msg(kind, string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Scopes
|
|
||||||
|
|
||||||
internal void
|
|
||||||
log_scope_begin(void)
|
|
||||||
{
|
|
||||||
if(log_active != 0)
|
|
||||||
{
|
|
||||||
U64 pos = arena_pos(log_active->arena);
|
|
||||||
LogScope *scope = push_array(log_active->arena, LogScope, 1);
|
|
||||||
scope->pos = pos;
|
|
||||||
SLLStackPush(log_active->top_scope, scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal LogScopeResult
|
|
||||||
log_scope_end(Arena *arena)
|
|
||||||
{
|
|
||||||
LogScopeResult result = {0};
|
|
||||||
if(log_active != 0)
|
|
||||||
{
|
|
||||||
LogScope *scope = log_active->top_scope;
|
|
||||||
if(scope != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(log_active->top_scope);
|
|
||||||
if(arena != 0)
|
|
||||||
{
|
|
||||||
for EachEnumVal(LogMsgKind, kind)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8 result_unindented = str8_list_join(scratch.arena, &scope->strings[kind], 0);
|
|
||||||
result.strings[kind] = indented_from_string(arena, result_unindented);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arena_pop_to(log_active->arena, scope->pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_LOG_H
|
|
||||||
#define BASE_LOG_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Types
|
|
||||||
|
|
||||||
typedef enum LogMsgKind
|
|
||||||
{
|
|
||||||
LogMsgKind_Info,
|
|
||||||
LogMsgKind_UserError,
|
|
||||||
LogMsgKind_COUNT
|
|
||||||
}
|
|
||||||
LogMsgKind;
|
|
||||||
|
|
||||||
typedef struct LogScope LogScope;
|
|
||||||
struct LogScope
|
|
||||||
{
|
|
||||||
LogScope *next;
|
|
||||||
U64 pos;
|
|
||||||
String8List strings[LogMsgKind_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct LogScopeResult LogScopeResult;
|
|
||||||
struct LogScopeResult
|
|
||||||
{
|
|
||||||
String8 strings[LogMsgKind_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Log Log;
|
|
||||||
struct Log
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
LogScope *top_scope;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// Globals
|
|
||||||
|
|
||||||
extern String8 g_logs_folder;
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Creation/Selection
|
|
||||||
|
|
||||||
internal Log *log_alloc(void);
|
|
||||||
internal void log_release(Log *log);
|
|
||||||
internal void log_select(Log *log);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Building
|
|
||||||
|
|
||||||
internal void log_msg(LogMsgKind kind, String8 string);
|
|
||||||
internal void log_msgf(LogMsgKind kind, char *fmt, ...);
|
|
||||||
#define log_info(s) log_msg(LogMsgKind_Info, (s))
|
|
||||||
#define log_infof(...) log_msgf(LogMsgKind_Info, __VA_ARGS__)
|
|
||||||
#define log_user_error(s) log_msg(LogMsgKind_UserError, (s))
|
|
||||||
#define log_user_errorf(...) log_msgf(LogMsgKind_UserError, __VA_ARGS__)
|
|
||||||
|
|
||||||
#define LogInfoNamedBlock(s) DeferLoop(log_infof("%S:\n{\n", (s)), log_infof("}\n"))
|
|
||||||
#define LogInfoNamedBlockF(...) DeferLoop((log_infof(__VA_ARGS__), log_infof(":\n{\n")), log_infof("}\n"))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Log Scopes
|
|
||||||
|
|
||||||
internal void log_scope_begin(void);
|
|
||||||
internal LogScopeResult log_scope_end(Arena *arena);
|
|
||||||
|
|
||||||
#endif // BASE_LOG_H
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|||||||
+69
-10
@@ -1,20 +1,79 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_MARKUP_H
|
#ifndef BASE_MARKUP_H
|
||||||
#define BASE_MARKUP_H
|
#define BASE_MARKUP_H
|
||||||
|
|
||||||
#define RADDBG_MARKUP_IMPLEMENTATION
|
////////////////////////////////
|
||||||
#define RADDBG_MARKUP_VSNPRINTF raddbg_vsnprintf
|
//~ rjf: Zero Settings
|
||||||
#if OS_LINUX
|
|
||||||
# define RADDBG_MARKUP_STUBS
|
|
||||||
#endif
|
|
||||||
#include "lib_raddbg_markup/raddbg_markup.h"
|
|
||||||
|
|
||||||
#if !defined(LAYER_COLOR)
|
#if !defined(PROFILE_TELEMETRY)
|
||||||
# define LAYER_COLOR 0x404040ff
|
# define PROFILE_TELEMETRY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ThreadNameF(...) (set_thread_namef(__VA_ARGS__), raddbg_thread_color_u32(LAYER_COLOR))
|
#if !defined(MARKUP_LAYER_COLOR)
|
||||||
|
# define MARKUP_LAYER_COLOR 1.00f, 0.00f, 1.00f
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Third Party Includes
|
||||||
|
|
||||||
|
#if PROFILE_TELEMETRY
|
||||||
|
# include "rad_tm.h"
|
||||||
|
# if OS_WINDOWS
|
||||||
|
# pragma comment(lib, "rad_tm_win64.lib")
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Telemetry Profile Defines
|
||||||
|
|
||||||
|
#if PROFILE_TELEMETRY
|
||||||
|
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
|
||||||
|
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||||
|
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
|
||||||
|
# define ProfTick(...) tmTick(0)
|
||||||
|
# define ProfIsCapturing(...) tmRunning()
|
||||||
|
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
|
||||||
|
# define ProfEndCapture(...) tmClose(0)
|
||||||
|
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
|
||||||
|
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
||||||
|
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
|
||||||
|
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
||||||
|
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
||||||
|
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
||||||
|
# define ProfColor(color) tmZoneColorSticky(color)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Zeroify Undefined Defines
|
||||||
|
|
||||||
|
#if !defined(ProfBegin)
|
||||||
|
# define ProfBegin(...) (0)
|
||||||
|
# define ProfBeginDynamic(...) (0)
|
||||||
|
# define ProfEnd(...) (0)
|
||||||
|
# define ProfTick(...) (0)
|
||||||
|
# define ProfIsCapturing(...) (0)
|
||||||
|
# define ProfBeginCapture(...) (0)
|
||||||
|
# define ProfEndCapture(...) (0)
|
||||||
|
# define ProfThreadName(...) (0)
|
||||||
|
# define ProfMsg(...) (0)
|
||||||
|
# define ProfBeginLockWait(...) (0)
|
||||||
|
# define ProfEndLockWait(...) (0)
|
||||||
|
# define ProfLockTake(...) (0)
|
||||||
|
# define ProfLockDrop(...) (0)
|
||||||
|
# define ProfColor(...) (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Helper Wrappers
|
||||||
|
|
||||||
|
#define ProfBeginFunction(...) ProfBegin(this_function_name)
|
||||||
|
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: General Markup
|
||||||
|
|
||||||
|
#define ThreadName(...) (ProfThreadName(__VA_ARGS__))
|
||||||
|
|
||||||
#endif // BASE_MARKUP_H
|
#endif // BASE_MARKUP_H
|
||||||
|
|||||||
+22
-255
@@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Scalar Math Ops
|
//~ rjf: Scalar Ops
|
||||||
|
|
||||||
internal F32
|
internal F32
|
||||||
mix_1f32(F32 a, F32 b, F32 t)
|
mix_1f32(F32 a, F32 b, F32 t)
|
||||||
@@ -42,6 +42,7 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s) {Vec2S64 c = {v.
|
|||||||
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;}
|
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b) {S64 c = a.x*b.x + a.y*b.y; return c;}
|
||||||
internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;}
|
internal S64 length_squared_2s64(Vec2S64 v) {S64 c = v.x*v.x + v.y*v.y; return c;}
|
||||||
internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;}
|
internal S64 length_2s64(Vec2S64 v) {S64 c = (S64)sqrt_f64((F64)(v.x*v.x + v.y*v.y)); return c;}
|
||||||
|
internal Vec2S64 normalize_2s64(Vec2S64 v) {v = scale_2s64(v, (S64)(1.f/length_2s64(v))); return v;}
|
||||||
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t) {Vec2S64 c = {(S64)mix_1f32((F32)a.x, (F32)b.x, t), (S64)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||||
|
|
||||||
internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;}
|
internal Vec2S32 vec_2s32(S32 x, S32 y) {Vec2S32 v = {x, y}; return v;}
|
||||||
@@ -53,6 +54,7 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s) {Vec2S32 c = {v.
|
|||||||
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;}
|
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b) {S32 c = a.x*b.x + a.y*b.y; return c;}
|
||||||
internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;}
|
internal S32 length_squared_2s32(Vec2S32 v) {S32 c = v.x*v.x + v.y*v.y; return c;}
|
||||||
internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;}
|
internal S32 length_2s32(Vec2S32 v) {S32 c = (S32)sqrt_f32((F32)v.x*(F32)v.x + (F32)v.y*(F32)v.y); return c;}
|
||||||
|
internal Vec2S32 normalize_2s32(Vec2S32 v) {v = scale_2s32(v, (S32)(1.f/length_2s32(v))); return v;}
|
||||||
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t) {Vec2S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||||
|
|
||||||
internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;}
|
internal Vec2S16 vec_2s16(S16 x, S16 y) {Vec2S16 v = {x, y}; return v;}
|
||||||
@@ -64,6 +66,7 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s) {Vec2S16 c = {(S
|
|||||||
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;}
|
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b) {S16 c = a.x*b.x + a.y*b.y; return c;}
|
||||||
internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;}
|
internal S16 length_squared_2s16(Vec2S16 v) {S16 c = v.x*v.x + v.y*v.y; return c;}
|
||||||
internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;}
|
internal S16 length_2s16(Vec2S16 v) {S16 c = (S16)sqrt_f32((F32)(v.x*v.x + v.y*v.y)); return c;}
|
||||||
|
internal Vec2S16 normalize_2s16(Vec2S16 v) {v = scale_2s16(v, (S16)(1.f/length_2s16(v))); return v;}
|
||||||
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t) {Vec2S16 c = {(S16)mix_1f32((F32)a.x, (F32)b.x, t), (S16)mix_1f32((F32)a.y, (F32)b.y, t)}; return c;}
|
||||||
|
|
||||||
internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;}
|
internal Vec3F32 vec_3f32(F32 x, F32 y, F32 z) {Vec3F32 v = {x, y, z}; return v;}
|
||||||
@@ -78,14 +81,6 @@ internal F32 length_3f32(Vec3F32 v) {F32 c = sqrt_f3
|
|||||||
internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;}
|
internal Vec3F32 normalize_3f32(Vec3F32 v) {v = scale_3f32(v, 1.f/length_3f32(v)); return v;}
|
||||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;}
|
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t) {Vec3F32 c = {mix_1f32(a.x, b.x, t), mix_1f32(a.y, b.y, t), mix_1f32(a.z, b.z, t)}; return c;}
|
||||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b) {Vec3F32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
||||||
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m)
|
|
||||||
{
|
|
||||||
Vec3F32 result;
|
|
||||||
result.x = v.x*m.v[0][0] + v.y*m.v[1][0] + v.z*m.v[2][0];
|
|
||||||
result.y = v.x*m.v[0][1] + v.y*m.v[1][1] + v.z*m.v[2][1];
|
|
||||||
result.z = v.x*m.v[0][2] + v.y*m.v[1][2] + v.z*m.v[2][2];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;}
|
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z) {Vec3S32 v = {x, y, z}; return v;}
|
||||||
internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;}
|
internal Vec3S32 add_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.x+b.x, a.y+b.y, a.z+b.z}; return c;}
|
||||||
@@ -96,6 +91,7 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s) {Vec3S32 c = {v.
|
|||||||
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;}
|
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z; return c;}
|
||||||
internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;}
|
internal S32 length_squared_3s32(Vec3S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z; return c;}
|
||||||
internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;}
|
internal S32 length_3s32(Vec3S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z)); return c;}
|
||||||
|
internal Vec3S32 normalize_3s32(Vec3S32 v) {v = scale_3s32(v, (S32)(1.f/length_3s32(v))); return v;}
|
||||||
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;}
|
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t) {Vec3S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t)}; return c;}
|
||||||
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b) {Vec3S32 c = {a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x}; return c;}
|
||||||
|
|
||||||
@@ -120,6 +116,7 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s) {Vec4S32 c = {v.
|
|||||||
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;}
|
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b) {S32 c = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; return c;}
|
||||||
internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;}
|
internal S32 length_squared_4s32(Vec4S32 v) {S32 c = v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w; return c;}
|
||||||
internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;}
|
internal S32 length_4s32(Vec4S32 v) {S32 c = (S32)sqrt_f32((F32)(v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w)); return c;}
|
||||||
|
internal Vec4S32 normalize_4s32(Vec4S32 v) {v = scale_4s32(v, (S32)(1.f/length_4s32(v))); return v;}
|
||||||
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;}
|
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t) {Vec4S32 c = {(S32)mix_1f32((F32)a.x, (F32)b.x, t), (S32)mix_1f32((F32)a.y, (F32)b.y, t), (S32)mix_1f32((F32)a.z, (F32)b.z, t), (S32)mix_1f32((F32)a.w, (F32)b.w, t)}; return c;}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -389,50 +386,15 @@ derotate_4x4f32(Mat4x4F32 mat)
|
|||||||
return mat;
|
return mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Mat4x4F32
|
|
||||||
transpose_4x4f32(Mat4x4F32 mat)
|
|
||||||
{
|
|
||||||
Mat4x4F32 result =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
mat.v[0][0], mat.v[1][0], mat.v[2][0], mat.v[3][0],
|
|
||||||
mat.v[0][1], mat.v[1][1], mat.v[2][1], mat.v[3][1],
|
|
||||||
mat.v[0][2], mat.v[1][2], mat.v[2][2], mat.v[3][2],
|
|
||||||
mat.v[0][3], mat.v[1][3], mat.v[2][3], mat.v[3][3],
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range Ops
|
//~ rjf: Range Ops
|
||||||
|
|
||||||
internal Rng1U8 rng_1u8(U8 min, U8 max) {Rng1U8 r = {min, max}; if(r.min > r.max) { Swap(U8, r.min, r.max); } return r;}
|
|
||||||
internal Rng1U8 shift_1u8(Rng1U8 r, U8 x) {r.min += x; r.max += x; return r;}
|
|
||||||
internal Rng1U8 pad_1u8(Rng1U8 r, U8 x) {r.min -= x; r.max += x; return r;}
|
|
||||||
internal U8 center_1u8(Rng1U8 r) {U8 c = (r.min+r.max)/2; return c;}
|
|
||||||
internal B32 contains_1u8(Rng1U8 r, U8 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
|
||||||
internal U8 dim_1u8(Rng1U8 r) {U8 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
|
||||||
internal Rng1U8 union_1u8(Rng1U8 a, Rng1U8 b) {Rng1U8 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
|
||||||
internal Rng1U8 intersect_1u8(Rng1U8 a, Rng1U8 b) {Rng1U8 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
|
||||||
internal U8 clamp_1u8(Rng1U8 r, U8 v) {v = Clamp(r.min, v, r.max); return v;}
|
|
||||||
|
|
||||||
internal Rng1U16 rng_1u16(U16 min, U16 max) {Rng1U16 r = {min, max}; if(r.min > r.max) { Swap(U16, r.min, r.max); } return r;}
|
|
||||||
internal Rng1U16 shift_1u16(Rng1U16 r, U16 x) {r.min += x; r.max += x; return r;}
|
|
||||||
internal Rng1U16 pad_1u16(Rng1U16 r, U16 x) {r.min -= x; r.max += x; return r;}
|
|
||||||
internal U16 center_1u16(Rng1U16 r) {U16 c = (r.min+r.max)/2; return c;}
|
|
||||||
internal B32 contains_1u16(Rng1U16 r, U16 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
|
||||||
internal U16 dim_1u16(Rng1U16 r) {U16 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
|
||||||
internal Rng1U16 union_1u16(Rng1U16 a, Rng1U16 b) {Rng1U16 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
|
||||||
internal Rng1U16 intersect_1u16(Rng1U16 a, Rng1U16 b) {Rng1U16 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
|
||||||
internal U16 clamp_1u16(Rng1U16 r, U16 v) {v = Clamp(r.min, v, r.max); return v;}
|
|
||||||
|
|
||||||
internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;}
|
internal Rng1U32 rng_1u32(U32 min, U32 max) {Rng1U32 r = {min, max}; if(r.min > r.max) { Swap(U32, r.min, r.max); } return r;}
|
||||||
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;}
|
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x) {r.min += x; r.max += x; return r;}
|
||||||
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;}
|
internal U32 center_1u32(Rng1U32 r) {U32 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1u32(Rng1U32 r, U32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal U32 dim_1u32(Rng1U32 r) {U32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal U32 dim_1u32(Rng1U32 r) {U32 c = r.max-r.min; return c;}
|
||||||
internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1U32 union_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b) {Rng1U32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal U32 clamp_1u32(Rng1U32 r, U32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -442,7 +404,7 @@ internal Rng1S32 shift_1s32(Rng1S32 r, S32 x) {r.min += x; r.m
|
|||||||
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;}
|
internal S32 center_1s32(Rng1S32 r) {S32 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1s32(Rng1S32 r, S32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal S32 dim_1s32(Rng1S32 r) {S32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal S32 dim_1s32(Rng1S32 r) {S32 c = r.max-r.min; return c;}
|
||||||
internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1S32 union_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b) {Rng1S32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal S32 clamp_1s32(Rng1S32 r, S32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -452,7 +414,7 @@ internal Rng1U64 shift_1u64(Rng1U64 r, U64 x) {r.min += x; r.m
|
|||||||
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;}
|
internal U64 center_1u64(Rng1U64 r) {U64 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1u64(Rng1U64 r, U64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal U64 dim_1u64(Rng1U64 r) {U64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal U64 dim_1u64(Rng1U64 r) {U64 c = r.max-r.min; return c;}
|
||||||
internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1U64 union_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b) {Rng1U64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal U64 clamp_1u64(Rng1U64 r, U64 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -462,7 +424,7 @@ internal Rng1S64 shift_1s64(Rng1S64 r, S64 x) {r.min += x; r.m
|
|||||||
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;}
|
internal S64 center_1s64(Rng1S64 r) {S64 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1s64(Rng1S64 r, S64 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal S64 dim_1s64(Rng1S64 r) {S64 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal S64 dim_1s64(Rng1S64 r) {S64 c = r.max-r.min; return c;}
|
||||||
internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1S64 union_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b) {Rng1S64 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal S64 clamp_1s64(Rng1S64 r, S64 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -472,7 +434,7 @@ internal Rng1F32 shift_1f32(Rng1F32 r, F32 x) {r.min += x; r.m
|
|||||||
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;}
|
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x) {r.min -= x; r.max += x; return r;}
|
||||||
internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;}
|
internal F32 center_1f32(Rng1F32 r) {F32 c = (r.min+r.max)/2; return c;}
|
||||||
internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
internal B32 contains_1f32(Rng1F32 r, F32 x) {B32 c = (r.min <= x && x < r.max); return c;}
|
||||||
internal F32 dim_1f32(Rng1F32 r) {F32 c = ((r.max > r.min) ? (r.max - r.min) : 0); return c;}
|
internal F32 dim_1f32(Rng1F32 r) {F32 c = r.max-r.min; return c;}
|
||||||
internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
internal Rng1F32 union_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Min(a.min, b.min), Max(a.max, b.max)}; return c;}
|
||||||
internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b) {Rng1F32 c = {Max(a.min, b.min), Min(a.max, b.max)}; return c;}
|
||||||
internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;}
|
internal F32 clamp_1f32(Rng1F32 r, F32 v) {v = Clamp(r.min, v, r.max); return v;}
|
||||||
@@ -482,7 +444,7 @@ internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x) {r.min = add_2s1
|
|||||||
internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;}
|
internal Rng2S16 pad_2s16(Rng2S16 r, S16 x) {Vec2S16 xv = {x, x}; r.min = sub_2s16(r.min, xv); r.max = add_2s16(r.max, xv); return r;}
|
||||||
internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;}
|
internal Vec2S16 center_2s16(Rng2S16 r) {Vec2S16 c = {(S16)((r.min.x+r.max.x)/2), (S16)((r.min.y+r.max.y)/2)}; return c;}
|
||||||
internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
internal B32 contains_2s16(Rng2S16 r, Vec2S16 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||||
internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0)), (S16)(((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0))}; return dim;}
|
internal Vec2S16 dim_2s16(Rng2S16 r) {Vec2S16 dim = {(S16)(r.max.x-r.min.x), (S16)(r.max.y-r.min.y)}; return dim;}
|
||||||
internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
internal Rng2S16 union_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||||
internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b) {Rng2S16 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||||
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||||
@@ -492,7 +454,7 @@ internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x) {r.min = add_2s3
|
|||||||
internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;}
|
internal Rng2S32 pad_2s32(Rng2S32 r, S32 x) {Vec2S32 xv = {x, x}; r.min = sub_2s32(r.min, xv); r.max = add_2s32(r.max, xv); return r;}
|
||||||
internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
internal Vec2S32 center_2s32(Rng2S32 r) {Vec2S32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||||
internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
internal B32 contains_2s32(Rng2S32 r, Vec2S32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||||
internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
internal Vec2S32 dim_2s32(Rng2S32 r) {Vec2S32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
|
||||||
internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
internal Rng2S32 union_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||||
internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b) {Rng2S32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||||
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||||
@@ -502,7 +464,7 @@ internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x) {r.min = add_2s6
|
|||||||
internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;}
|
internal Rng2S64 pad_2s64(Rng2S64 r, S64 x) {Vec2S64 xv = {x, x}; r.min = sub_2s64(r.min, xv); r.max = add_2s64(r.max, xv); return r;}
|
||||||
internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
internal Vec2S64 center_2s64(Rng2S64 r) {Vec2S64 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||||
internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
internal B32 contains_2s64(Rng2S64 r, Vec2S64 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||||
internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
internal Vec2S64 dim_2s64(Rng2S64 r) {Vec2S64 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
|
||||||
internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
internal Rng2S64 union_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||||
internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b) {Rng2S64 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||||
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||||
@@ -512,15 +474,13 @@ internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x) {r.min = add_2f3
|
|||||||
internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;}
|
internal Rng2F32 pad_2f32(Rng2F32 r, F32 x) {Vec2F32 xv = {x, x}; r.min = sub_2f32(r.min, xv); r.max = add_2f32(r.max, xv); return r;}
|
||||||
internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
internal Vec2F32 center_2f32(Rng2F32 r) {Vec2F32 c = {(r.min.x+r.max.x)/2, (r.min.y+r.max.y)/2}; return c;}
|
||||||
internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
internal B32 contains_2f32(Rng2F32 r, Vec2F32 x) {B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); return c;}
|
||||||
internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {((r.max.x > r.min.x) ? (r.max.x - r.min.x) : 0), ((r.max.y > r.min.y) ? (r.max.y - r.min.y) : 0)}; return dim;}
|
internal Vec2F32 dim_2f32(Rng2F32 r) {Vec2F32 dim = {r.max.x-r.min.x, r.max.y-r.min.y}; return dim;}
|
||||||
internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
internal Rng2F32 union_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Min(a.min.x, b.min.x); c.p0.y = Min(a.min.y, b.min.y); c.p1.x = Max(a.max.x, b.max.x); c.p1.y = Max(a.max.y, b.max.y); return c;}
|
||||||
internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b) {Rng2F32 c; c.p0.x = Max(a.min.x, b.min.x); c.p0.y = Max(a.min.y, b.min.y); c.p1.x = Min(a.max.x, b.max.x); c.p1.y = Min(a.max.y, b.max.y); return c;}
|
||||||
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v) {v.x = Clamp(r.min.x, v.x, r.max.x); v.y = Clamp(r.min.y, v.y, r.max.y); return v;}
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Color Operations
|
//~ rjf: Miscellaneous Ops
|
||||||
|
|
||||||
//- rjf: hsv <-> rgb
|
|
||||||
|
|
||||||
internal Vec3F32
|
internal Vec3F32
|
||||||
hsv_from_rgb(Vec3F32 rgb)
|
hsv_from_rgb(Vec3F32 rgb)
|
||||||
@@ -607,102 +567,16 @@ rgba_from_hsva(Vec4F32 hsva)
|
|||||||
return rgba;
|
return rgba;
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: srgb <-> linear
|
|
||||||
|
|
||||||
internal Vec3F32
|
|
||||||
linear_from_srgb(Vec3F32 srgb)
|
|
||||||
{
|
|
||||||
Vec3F32 result;
|
|
||||||
for EachElement(idx, srgb.v)
|
|
||||||
{
|
|
||||||
result.v[idx] = (srgb.v[idx] < 0.0404482362771082f ? srgb.v[idx] / 12.92f : pow_f32((srgb.v[idx] + 0.055f) / 1.055f, 2.4f));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec3F32
|
|
||||||
srgb_from_linear(Vec3F32 linear)
|
|
||||||
{
|
|
||||||
Vec3F32 result;
|
|
||||||
for EachElement(idx, linear.v)
|
|
||||||
{
|
|
||||||
result.v[idx] = (0 <= linear.v[idx] && linear.v[idx] < 0.00313066844250063) ? linear.v[idx]*12.92f : 1.05f * pow_f32(linear.v[idx], 1.f/2.4f) - 0.055f;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec4F32
|
internal Vec4F32
|
||||||
linear_from_srgba(Vec4F32 srgba)
|
rgba_from_u32(U32 hex)
|
||||||
{
|
{
|
||||||
Vec4F32 result;
|
Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f,
|
||||||
result.xyz = linear_from_srgb(srgba.xyz);
|
((hex&0x00ff0000)>>16)/255.f,
|
||||||
result.w = srgba.w;
|
((hex&0x0000ff00)>> 8)/255.f,
|
||||||
|
((hex&0x000000ff)>> 0)/255.f);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec4F32
|
|
||||||
srgba_from_linear(Vec4F32 linear)
|
|
||||||
{
|
|
||||||
Vec4F32 result;
|
|
||||||
result.xyz = srgb_from_linear(linear.xyz);
|
|
||||||
result.w = linear.w;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: oklab <-> linear
|
|
||||||
|
|
||||||
internal Vec3F32
|
|
||||||
oklab_from_linear(Vec3F32 linear)
|
|
||||||
{
|
|
||||||
F32 l = (0.4122214708f * linear.x + 0.5363325363f * linear.y + 0.0514459929f * linear.z);
|
|
||||||
F32 m = (0.2119034982f * linear.x + 0.6806995451f * linear.y + 0.1073969566f * linear.z);
|
|
||||||
F32 s = (0.0883024619f * linear.x + 0.2817188376f * linear.y + 0.6299787005f * linear.z);
|
|
||||||
F32 l_ = cbrt_f32(l);
|
|
||||||
F32 m_ = cbrt_f32(m);
|
|
||||||
F32 s_ = cbrt_f32(s);
|
|
||||||
Vec3F32 result;
|
|
||||||
result.x = 0.2104542553f*l_ + 0.7936177850f*m_ - 0.0040720468f*s_;
|
|
||||||
result.y = 1.9779984951f*l_ - 2.4285922050f*m_ + 0.4505937099f*s_;
|
|
||||||
result.z = 0.0259040371f*l_ + 0.7827717662f*m_ - 0.8086757660f*s_;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec3F32
|
|
||||||
linear_from_oklab(Vec3F32 oklab)
|
|
||||||
{
|
|
||||||
F32 l_ = oklab.x + 0.3963377774f * oklab.y + 0.2158037573f * oklab.z;
|
|
||||||
F32 m_ = oklab.x - 0.1055613458f * oklab.y - 0.0638541728f * oklab.z;
|
|
||||||
F32 s_ = oklab.x - 0.0894841775f * oklab.y - 1.2914855480f * oklab.z;
|
|
||||||
F32 l = l_*l_*l_;
|
|
||||||
F32 m = m_*m_*m_;
|
|
||||||
F32 s = s_*s_*s_;
|
|
||||||
Vec3F32 result;
|
|
||||||
result.x = +4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s;
|
|
||||||
result.y = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s;
|
|
||||||
result.z = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec4F32
|
|
||||||
oklab_from_lineara(Vec4F32 lineara)
|
|
||||||
{
|
|
||||||
Vec4F32 result;
|
|
||||||
result.xyz = oklab_from_linear(lineara.xyz);
|
|
||||||
result.w = lineara.w;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Vec4F32
|
|
||||||
lineara_from_oklab(Vec4F32 oklab)
|
|
||||||
{
|
|
||||||
Vec4F32 result;
|
|
||||||
result.xyz = linear_from_oklab(oklab.xyz);
|
|
||||||
result.w = oklab.w;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: rgba <-> u32
|
|
||||||
|
|
||||||
internal U32
|
internal U32
|
||||||
u32_from_rgba(Vec4F32 rgba)
|
u32_from_rgba(Vec4F32 rgba)
|
||||||
{
|
{
|
||||||
@@ -714,99 +588,9 @@ u32_from_rgba(Vec4F32 rgba)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Vec4F32
|
|
||||||
rgba_from_u32(U32 hex)
|
|
||||||
{
|
|
||||||
Vec4F32 result = v4f32(((hex&0xff000000)>>24)/255.f,
|
|
||||||
((hex&0x00ff0000)>>16)/255.f,
|
|
||||||
((hex&0x0000ff00)>> 8)/255.f,
|
|
||||||
((hex&0x000000ff)>> 0)/255.f);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: List Type Functions
|
//~ rjf: List Type Functions
|
||||||
|
|
||||||
internal void
|
|
||||||
rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n)
|
|
||||||
{
|
|
||||||
SLLQueuePush(list->first, list->last, n);
|
|
||||||
list->count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Rng1U64Node *
|
|
||||||
rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng)
|
|
||||||
{
|
|
||||||
Rng1U64Node *n = push_array(arena, Rng1U64Node, 1);
|
|
||||||
MemoryCopyStruct(&n->v, &rng);
|
|
||||||
rng1u64_list_push_node(list, n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat)
|
|
||||||
{
|
|
||||||
if(to_concat->first)
|
|
||||||
{
|
|
||||||
if(list->first)
|
|
||||||
{
|
|
||||||
list->last->next = to_concat->first;
|
|
||||||
list->last = to_concat->last;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list->first = to_concat->first;
|
|
||||||
list->last = to_concat->last;
|
|
||||||
}
|
|
||||||
list->count += to_concat->count;
|
|
||||||
MemoryZeroStruct(to_concat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Rng1U64Array
|
|
||||||
rng1u64_array_from_list(Arena *arena, Rng1U64List *list)
|
|
||||||
{
|
|
||||||
Rng1U64Array arr = {0};
|
|
||||||
arr.count = list->count;
|
|
||||||
arr.v = push_array_no_zero(arena, Rng1U64, arr.count);
|
|
||||||
U64 idx = 0;
|
|
||||||
for(Rng1U64Node *n = list->first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
arr.v[idx] = n->v;
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value)
|
|
||||||
{
|
|
||||||
U64 result = 0;
|
|
||||||
if(array->count > 0 && array->v[0].min <= value && value < array->v[array->count-1].max)
|
|
||||||
{
|
|
||||||
U64 min_idx = 0;
|
|
||||||
U64 max_idx = array->count - 1;
|
|
||||||
for(;min_idx <= max_idx;)
|
|
||||||
{
|
|
||||||
U64 mid_idx = min_idx + (max_idx - min_idx) / 2;
|
|
||||||
if(contains_1u64(array->v[mid_idx], value))
|
|
||||||
{
|
|
||||||
result = mid_idx+1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if(array->v[mid_idx].min < value)
|
|
||||||
{
|
|
||||||
min_idx = mid_idx + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
max_idx = mid_idx - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng)
|
rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng)
|
||||||
{
|
{
|
||||||
@@ -830,20 +614,3 @@ rng1s64_array_from_list(Arena *arena, Rng1S64List *list)
|
|||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: N -> M Element Subdivision
|
|
||||||
|
|
||||||
internal Rng1U64
|
|
||||||
m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count)
|
|
||||||
{
|
|
||||||
U64 main_idxes_per_lane = m_count/n_count;
|
|
||||||
U64 leftover_idxes_count = m_count - main_idxes_per_lane*n_count;
|
|
||||||
U64 leftover_idxes_before_this_lane_count = Min(n_idx, leftover_idxes_count);
|
|
||||||
U64 lane_base_idx = n_idx*main_idxes_per_lane + leftover_idxes_before_this_lane_count;
|
|
||||||
U64 lane_base_idx__clamped = Min(lane_base_idx, m_count);
|
|
||||||
U64 lane_opl_idx = lane_base_idx__clamped + main_idxes_per_lane + ((n_idx < leftover_idxes_count) ? 1 : 0);
|
|
||||||
U64 lane_opl_idx__clamped = Min(lane_opl_idx, m_count);
|
|
||||||
Rng1U64 result = r1u64(lane_base_idx__clamped, lane_opl_idx__clamped);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
+16
-117
@@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_MATH_H
|
#ifndef BASE_MATH_H
|
||||||
@@ -177,28 +177,6 @@ struct Mat4x4F32
|
|||||||
|
|
||||||
//- rjf: 1-range
|
//- rjf: 1-range
|
||||||
|
|
||||||
typedef union Rng1U8 Rng1U8;
|
|
||||||
union Rng1U8
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
U8 min;
|
|
||||||
U8 max;
|
|
||||||
};
|
|
||||||
U8 v[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union Rng1U16 Rng1U16;
|
|
||||||
union Rng1U16
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
U16 min;
|
|
||||||
U16 max;
|
|
||||||
};
|
|
||||||
U16 v[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union Rng1U32 Rng1U32;
|
typedef union Rng1U32 Rng1U32;
|
||||||
union Rng1U32
|
union Rng1U32
|
||||||
{
|
{
|
||||||
@@ -349,29 +327,7 @@ union Rng2S64
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range List Types
|
//~ rjf: List Types
|
||||||
|
|
||||||
typedef struct Rng1U64Node Rng1U64Node;
|
|
||||||
struct Rng1U64Node
|
|
||||||
{
|
|
||||||
Rng1U64Node *next;
|
|
||||||
Rng1U64 v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1U64List Rng1U64List;
|
|
||||||
struct Rng1U64List
|
|
||||||
{
|
|
||||||
Rng1U64Node *first;
|
|
||||||
Rng1U64Node *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1U64Array Rng1U64Array;
|
|
||||||
struct Rng1U64Array
|
|
||||||
{
|
|
||||||
Rng1U64 *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Rng1S64Node Rng1S64Node;
|
typedef struct Rng1S64Node Rng1S64Node;
|
||||||
struct Rng1S64Node
|
struct Rng1S64Node
|
||||||
@@ -396,20 +352,19 @@ struct Rng1S64Array
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Scalar Math Ops
|
//~ rjf: Scalar Ops
|
||||||
|
|
||||||
#define abs_s64(v) (S64)llabs(v)
|
#define abs_s64(v) (S64)llabs(v)
|
||||||
|
|
||||||
#define sqrt_f32(v) sqrtf(v)
|
#define sqrt_f32(v) sqrtf(v)
|
||||||
#define cbrt_f32(v) cbrtf(v)
|
|
||||||
#define mod_f32(a, b) fmodf((a), (b))
|
#define mod_f32(a, b) fmodf((a), (b))
|
||||||
#define pow_f32(b, e) powf((b), (e))
|
#define pow_f32(b, e) powf((b), (e))
|
||||||
#define ceil_f32(v) ceilf(v)
|
#define ceil_f32(v) ceilf(v)
|
||||||
#define floor_f32(v) floorf(v)
|
#define floor_f32(v) floorf(v)
|
||||||
#define round_f32(v) roundf(v)
|
#define round_f32(v) roundf(v)
|
||||||
#define abs_f32(v) fabsf(v)
|
#define abs_f32(v) fabsf(v)
|
||||||
#define radians_from_turns_f32(v) ((v)*(2*3.1415926535897f))
|
#define radians_from_turns_f32(v) ((v)*2*3.1415926535897f)
|
||||||
#define turns_from_radians_f32(v) ((v)/(2*3.1415926535897f))
|
#define turns_from_radians_f32(v) ((v)/2*3.1415926535897f)
|
||||||
#define degrees_from_turns_f32(v) ((v)*360.f)
|
#define degrees_from_turns_f32(v) ((v)*360.f)
|
||||||
#define turns_from_degrees_f32(v) ((v)/360.f)
|
#define turns_from_degrees_f32(v) ((v)/360.f)
|
||||||
#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v)))
|
#define degrees_from_radians_f32(v) (degrees_from_turns_f32(turns_from_radians_f32(v)))
|
||||||
@@ -419,15 +374,14 @@ struct Rng1S64Array
|
|||||||
#define tan_f32(v) tanf(radians_from_turns_f32(v))
|
#define tan_f32(v) tanf(radians_from_turns_f32(v))
|
||||||
|
|
||||||
#define sqrt_f64(v) sqrt(v)
|
#define sqrt_f64(v) sqrt(v)
|
||||||
#define cbrt_f64(v) cbrt(v)
|
|
||||||
#define mod_f64(a, b) fmod((a), (b))
|
#define mod_f64(a, b) fmod((a), (b))
|
||||||
#define pow_f64(b, e) pow((b), (e))
|
#define pow_f64(b, e) pow((b), (e))
|
||||||
#define ceil_f64(v) ceil(v)
|
#define ceil_f64(v) ceil(v)
|
||||||
#define floor_f64(v) floor(v)
|
#define floor_f64(v) floor(v)
|
||||||
#define round_f64(v) round(v)
|
#define round_f64(v) round(v)
|
||||||
#define abs_f64(v) fabs(v)
|
#define abs_f64(v) fabs(v)
|
||||||
#define radians_from_turns_f64(v) ((v)*(2*3.1415926535897))
|
#define radians_from_turns_f64(v) ((v)*2*3.1415926535897)
|
||||||
#define turns_from_radians_f64(v) ((v)/(2*3.1415926535897))
|
#define turns_from_radians_f64(v) ((v)/2*3.1415926535897)
|
||||||
#define degrees_from_turns_f64(v) ((v)*360.0)
|
#define degrees_from_turns_f64(v) ((v)*360.0)
|
||||||
#define turns_from_degrees_f64(v) ((v)/360.0)
|
#define turns_from_degrees_f64(v) ((v)/360.0)
|
||||||
#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v)))
|
#define degrees_from_radians_f64(v) (degrees_from_turns_f64(turns_from_radians_f64(v)))
|
||||||
@@ -465,6 +419,7 @@ internal Vec2S64 scale_2s64(Vec2S64 v, S64 s);
|
|||||||
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
|
internal S64 dot_2s64(Vec2S64 a, Vec2S64 b);
|
||||||
internal S64 length_squared_2s64(Vec2S64 v);
|
internal S64 length_squared_2s64(Vec2S64 v);
|
||||||
internal S64 length_2s64(Vec2S64 v);
|
internal S64 length_2s64(Vec2S64 v);
|
||||||
|
internal Vec2S64 normalize_2s64(Vec2S64 v);
|
||||||
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t);
|
internal Vec2S64 mix_2s64(Vec2S64 a, Vec2S64 b, F32 t);
|
||||||
|
|
||||||
#define v2s32(x, y) vec_2s32((x), (y))
|
#define v2s32(x, y) vec_2s32((x), (y))
|
||||||
@@ -477,6 +432,7 @@ internal Vec2S32 scale_2s32(Vec2S32 v, S32 s);
|
|||||||
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b);
|
internal S32 dot_2s32(Vec2S32 a, Vec2S32 b);
|
||||||
internal S32 length_squared_2s32(Vec2S32 v);
|
internal S32 length_squared_2s32(Vec2S32 v);
|
||||||
internal S32 length_2s32(Vec2S32 v);
|
internal S32 length_2s32(Vec2S32 v);
|
||||||
|
internal Vec2S32 normalize_2s32(Vec2S32 v);
|
||||||
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t);
|
internal Vec2S32 mix_2s32(Vec2S32 a, Vec2S32 b, F32 t);
|
||||||
|
|
||||||
#define v2s16(x, y) vec_2s16((x), (y))
|
#define v2s16(x, y) vec_2s16((x), (y))
|
||||||
@@ -489,6 +445,7 @@ internal Vec2S16 scale_2s16(Vec2S16 v, S16 s);
|
|||||||
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b);
|
internal S16 dot_2s16(Vec2S16 a, Vec2S16 b);
|
||||||
internal S16 length_squared_2s16(Vec2S16 v);
|
internal S16 length_squared_2s16(Vec2S16 v);
|
||||||
internal S16 length_2s16(Vec2S16 v);
|
internal S16 length_2s16(Vec2S16 v);
|
||||||
|
internal Vec2S16 normalize_2s16(Vec2S16 v);
|
||||||
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t);
|
internal Vec2S16 mix_2s16(Vec2S16 a, Vec2S16 b, F32 t);
|
||||||
|
|
||||||
#define v3f32(x, y, z) vec_3f32((x), (y), (z))
|
#define v3f32(x, y, z) vec_3f32((x), (y), (z))
|
||||||
@@ -504,7 +461,6 @@ internal F32 length_3f32(Vec3F32 v);
|
|||||||
internal Vec3F32 normalize_3f32(Vec3F32 v);
|
internal Vec3F32 normalize_3f32(Vec3F32 v);
|
||||||
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
|
internal Vec3F32 mix_3f32(Vec3F32 a, Vec3F32 b, F32 t);
|
||||||
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
|
internal Vec3F32 cross_3f32(Vec3F32 a, Vec3F32 b);
|
||||||
internal Vec3F32 xform_3f32(Vec3F32 v, Mat3x3F32 m);
|
|
||||||
|
|
||||||
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
|
#define v3s32(x, y, z) vec_3s32((x), (y), (z))
|
||||||
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
|
internal Vec3S32 vec_3s32(S32 x, S32 y, S32 z);
|
||||||
@@ -516,6 +472,7 @@ internal Vec3S32 scale_3s32(Vec3S32 v, S32 s);
|
|||||||
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b);
|
internal S32 dot_3s32(Vec3S32 a, Vec3S32 b);
|
||||||
internal S32 length_squared_3s32(Vec3S32 v);
|
internal S32 length_squared_3s32(Vec3S32 v);
|
||||||
internal S32 length_3s32(Vec3S32 v);
|
internal S32 length_3s32(Vec3S32 v);
|
||||||
|
internal Vec3S32 normalize_3s32(Vec3S32 v);
|
||||||
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t);
|
internal Vec3S32 mix_3s32(Vec3S32 a, Vec3S32 b, F32 t);
|
||||||
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b);
|
internal Vec3S32 cross_3s32(Vec3S32 a, Vec3S32 b);
|
||||||
|
|
||||||
@@ -542,6 +499,7 @@ internal Vec4S32 scale_4s32(Vec4S32 v, S32 s);
|
|||||||
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b);
|
internal S32 dot_4s32(Vec4S32 a, Vec4S32 b);
|
||||||
internal S32 length_squared_4s32(Vec4S32 v);
|
internal S32 length_squared_4s32(Vec4S32 v);
|
||||||
internal S32 length_4s32(Vec4S32 v);
|
internal S32 length_4s32(Vec4S32 v);
|
||||||
|
internal Vec4S32 normalize_4s32(Vec4S32 v);
|
||||||
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t);
|
internal Vec4S32 mix_4s32(Vec4S32 a, Vec4S32 b, F32 t);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -563,37 +521,11 @@ internal Mat4x4F32 mul_4x4f32(Mat4x4F32 a, Mat4x4F32 b);
|
|||||||
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
|
internal Mat4x4F32 scale_4x4f32(Mat4x4F32 m, F32 scale);
|
||||||
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
|
internal Mat4x4F32 inverse_4x4f32(Mat4x4F32 m);
|
||||||
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
|
internal Mat4x4F32 derotate_4x4f32(Mat4x4F32 mat);
|
||||||
internal Mat4x4F32 transpose_4x4f32(Mat4x4F32 mat);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Range Ops
|
//~ rjf: Range Ops
|
||||||
|
|
||||||
#define r1u8(min, max) rng_1u8((min), (max))
|
|
||||||
#define r1u8s(min, size) rng_1u8((min), (min)+(size))
|
|
||||||
internal Rng1U8 rng_1u8(U8 min, U8 max);
|
|
||||||
internal Rng1U8 shift_1u8(Rng1U8 r, U8 x);
|
|
||||||
internal Rng1U8 pad_1u8(Rng1U8 r, U8 x);
|
|
||||||
internal U8 center_1u8(Rng1U8 r);
|
|
||||||
internal B32 contains_1u8(Rng1U8 r, U8 x);
|
|
||||||
internal U8 dim_1u8(Rng1U8 r);
|
|
||||||
internal Rng1U8 union_1u8(Rng1U8 a, Rng1U8 b);
|
|
||||||
internal Rng1U8 intersect_1u8(Rng1U8 a, Rng1U8 b);
|
|
||||||
internal U8 clamp_1u8(Rng1U8 r, U8 v);
|
|
||||||
|
|
||||||
#define r1u16(min, max) rng_1u16((min), (max))
|
|
||||||
#define r1u16s(min, size) rng_1u16((min), (min)+(size))
|
|
||||||
internal Rng1U16 rng_1u16(U16 min, U16 max);
|
|
||||||
internal Rng1U16 shift_1u16(Rng1U16 r, U16 x);
|
|
||||||
internal Rng1U16 pad_1u16(Rng1U16 r, U16 x);
|
|
||||||
internal U16 center_1u16(Rng1U16 r);
|
|
||||||
internal B32 contains_1u16(Rng1U16 r, U16 x);
|
|
||||||
internal U16 dim_1u16(Rng1U16 r);
|
|
||||||
internal Rng1U16 union_1u16(Rng1U16 a, Rng1U16 b);
|
|
||||||
internal Rng1U16 intersect_1u16(Rng1U16 a, Rng1U16 b);
|
|
||||||
internal U16 clamp_1u16(Rng1U16 r, U16 v);
|
|
||||||
|
|
||||||
#define r1u32(min, max) rng_1u32((min), (max))
|
#define r1u32(min, max) rng_1u32((min), (max))
|
||||||
#define r1u32s(min, size) rng_1u32((min), (min)+(size))
|
|
||||||
internal Rng1U32 rng_1u32(U32 min, U32 max);
|
internal Rng1U32 rng_1u32(U32 min, U32 max);
|
||||||
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
|
internal Rng1U32 shift_1u32(Rng1U32 r, U32 x);
|
||||||
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x);
|
internal Rng1U32 pad_1u32(Rng1U32 r, U32 x);
|
||||||
@@ -605,7 +537,6 @@ internal Rng1U32 intersect_1u32(Rng1U32 a, Rng1U32 b);
|
|||||||
internal U32 clamp_1u32(Rng1U32 r, U32 v);
|
internal U32 clamp_1u32(Rng1U32 r, U32 v);
|
||||||
|
|
||||||
#define r1s32(min, max) rng_1s32((min), (max))
|
#define r1s32(min, max) rng_1s32((min), (max))
|
||||||
#define r1s32s(min,size) rng_1s32((min), (min)+(size))
|
|
||||||
internal Rng1S32 rng_1s32(S32 min, S32 max);
|
internal Rng1S32 rng_1s32(S32 min, S32 max);
|
||||||
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
|
internal Rng1S32 shift_1s32(Rng1S32 r, S32 x);
|
||||||
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x);
|
internal Rng1S32 pad_1s32(Rng1S32 r, S32 x);
|
||||||
@@ -617,7 +548,6 @@ internal Rng1S32 intersect_1s32(Rng1S32 a, Rng1S32 b);
|
|||||||
internal S32 clamp_1s32(Rng1S32 r, S32 v);
|
internal S32 clamp_1s32(Rng1S32 r, S32 v);
|
||||||
|
|
||||||
#define r1u64(min, max) rng_1u64((min), (max))
|
#define r1u64(min, max) rng_1u64((min), (max))
|
||||||
#define r1u64s(min, size) rng_1u64((min), (min)+(size))
|
|
||||||
internal Rng1U64 rng_1u64(U64 min, U64 max);
|
internal Rng1U64 rng_1u64(U64 min, U64 max);
|
||||||
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
|
internal Rng1U64 shift_1u64(Rng1U64 r, U64 x);
|
||||||
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x);
|
internal Rng1U64 pad_1u64(Rng1U64 r, U64 x);
|
||||||
@@ -629,7 +559,6 @@ internal Rng1U64 intersect_1u64(Rng1U64 a, Rng1U64 b);
|
|||||||
internal U64 clamp_1u64(Rng1U64 r, U64 v);
|
internal U64 clamp_1u64(Rng1U64 r, U64 v);
|
||||||
|
|
||||||
#define r1s64(min, max) rng_1s64((min), (max))
|
#define r1s64(min, max) rng_1s64((min), (max))
|
||||||
#define r1s64s(min, size) rng_1s64((min), (min)+(size))
|
|
||||||
internal Rng1S64 rng_1s64(S64 min, S64 max);
|
internal Rng1S64 rng_1s64(S64 min, S64 max);
|
||||||
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
|
internal Rng1S64 shift_1s64(Rng1S64 r, S64 x);
|
||||||
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x);
|
internal Rng1S64 pad_1s64(Rng1S64 r, S64 x);
|
||||||
@@ -641,7 +570,6 @@ internal Rng1S64 intersect_1s64(Rng1S64 a, Rng1S64 b);
|
|||||||
internal S64 clamp_1s64(Rng1S64 r, S64 v);
|
internal S64 clamp_1s64(Rng1S64 r, S64 v);
|
||||||
|
|
||||||
#define r1f32(min, max) rng_1f32((min), (max))
|
#define r1f32(min, max) rng_1f32((min), (max))
|
||||||
#define r1f32s(min, size) rng_1f32((min), (min)+(size))
|
|
||||||
internal Rng1F32 rng_1f32(F32 min, F32 max);
|
internal Rng1F32 rng_1f32(F32 min, F32 max);
|
||||||
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
|
internal Rng1F32 shift_1f32(Rng1F32 r, F32 x);
|
||||||
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x);
|
internal Rng1F32 pad_1f32(Rng1F32 r, F32 x);
|
||||||
@@ -653,7 +581,6 @@ internal Rng1F32 intersect_1f32(Rng1F32 a, Rng1F32 b);
|
|||||||
internal F32 clamp_1f32(Rng1F32 r, F32 v);
|
internal F32 clamp_1f32(Rng1F32 r, F32 v);
|
||||||
|
|
||||||
#define r2s16(min, max) rng_2s16((min), (max))
|
#define r2s16(min, max) rng_2s16((min), (max))
|
||||||
#define r2s16s(min, size) r2s16((min), (min)+(size))
|
|
||||||
#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w)))
|
#define r2s16p(x, y, z, w) r2s16(v2s16((x), (y)), v2s16((z), (w)))
|
||||||
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
|
internal Rng2S16 rng_2s16(Vec2S16 min, Vec2S16 max);
|
||||||
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x);
|
internal Rng2S16 shift_2s16(Rng2S16 r, Vec2S16 x);
|
||||||
@@ -666,7 +593,6 @@ internal Rng2S16 intersect_2s16(Rng2S16 a, Rng2S16 b);
|
|||||||
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v);
|
internal Vec2S16 clamp_2s16(Rng2S16 r, Vec2S16 v);
|
||||||
|
|
||||||
#define r2s32(min, max) rng_2s32((min), (max))
|
#define r2s32(min, max) rng_2s32((min), (max))
|
||||||
#define r2s32s(min, size) r2s32((min), (min)+(size))
|
|
||||||
#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w)))
|
#define r2s32p(x, y, z, w) r2s32(v2s32((x), (y)), v2s32((z), (w)))
|
||||||
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
|
internal Rng2S32 rng_2s32(Vec2S32 min, Vec2S32 max);
|
||||||
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x);
|
internal Rng2S32 shift_2s32(Rng2S32 r, Vec2S32 x);
|
||||||
@@ -679,7 +605,6 @@ internal Rng2S32 intersect_2s32(Rng2S32 a, Rng2S32 b);
|
|||||||
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v);
|
internal Vec2S32 clamp_2s32(Rng2S32 r, Vec2S32 v);
|
||||||
|
|
||||||
#define r2s64(min, max) rng_2s64((min), (max))
|
#define r2s64(min, max) rng_2s64((min), (max))
|
||||||
#define r2s64s(min, size) r2s64((min), (min)+(size))
|
|
||||||
#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w)))
|
#define r2s64p(x, y, z, w) r2s64(v2s64((x), (y)), v2s64((z), (w)))
|
||||||
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
|
internal Rng2S64 rng_2s64(Vec2S64 min, Vec2S64 max);
|
||||||
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x);
|
internal Rng2S64 shift_2s64(Rng2S64 r, Vec2S64 x);
|
||||||
@@ -692,7 +617,6 @@ internal Rng2S64 intersect_2s64(Rng2S64 a, Rng2S64 b);
|
|||||||
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v);
|
internal Vec2S64 clamp_2s64(Rng2S64 r, Vec2S64 v);
|
||||||
|
|
||||||
#define r2f32(min, max) rng_2f32((min), (max))
|
#define r2f32(min, max) rng_2f32((min), (max))
|
||||||
#define r2f32s(min, size) r2f32((min), (min)+(size))
|
|
||||||
#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w)))
|
#define r2f32p(x, y, z, w) r2f32(v2f32((x), (y)), v2f32((z), (w)))
|
||||||
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
|
internal Rng2F32 rng_2f32(Vec2F32 min, Vec2F32 max);
|
||||||
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x);
|
internal Rng2F32 shift_2f32(Rng2F32 r, Vec2F32 x);
|
||||||
@@ -705,46 +629,21 @@ internal Rng2F32 intersect_2f32(Rng2F32 a, Rng2F32 b);
|
|||||||
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v);
|
internal Vec2F32 clamp_2f32(Rng2F32 r, Vec2F32 v);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Color Operations
|
//~ rjf: Miscellaneous Ops
|
||||||
|
|
||||||
//- rjf: hsv <-> rgb
|
|
||||||
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
|
internal Vec3F32 hsv_from_rgb(Vec3F32 rgb);
|
||||||
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
|
internal Vec3F32 rgb_from_hsv(Vec3F32 hsv);
|
||||||
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
|
internal Vec4F32 hsva_from_rgba(Vec4F32 rgba);
|
||||||
internal Vec4F32 rgba_from_hsva(Vec4F32 hsva);
|
internal Vec4F32 rgba_from_hsva(Vec4F32 hsva);
|
||||||
|
|
||||||
//- rjf: srgb <-> linear
|
|
||||||
internal Vec3F32 linear_from_srgb(Vec3F32 srgb);
|
|
||||||
internal Vec3F32 srgb_from_linear(Vec3F32 linear);
|
|
||||||
internal Vec4F32 linear_from_srgba(Vec4F32 srgba);
|
|
||||||
internal Vec4F32 srgba_from_linear(Vec4F32 linear);
|
|
||||||
|
|
||||||
//- rjf: oklab <-> linear
|
|
||||||
internal Vec3F32 oklab_from_linear(Vec3F32 linear);
|
|
||||||
internal Vec3F32 linear_from_oklab(Vec3F32 oklab);
|
|
||||||
internal Vec4F32 oklab_from_lineara(Vec4F32 lineara);
|
|
||||||
internal Vec4F32 lineara_from_oklab(Vec4F32 oklab);
|
|
||||||
|
|
||||||
//- rjf: rgba <-> u32
|
|
||||||
internal U32 u32_from_rgba(Vec4F32 rgba);
|
|
||||||
internal Vec4F32 rgba_from_u32(U32 hex);
|
internal Vec4F32 rgba_from_u32(U32 hex);
|
||||||
|
internal U32 u32_from_rgba(Vec4F32 rgba);
|
||||||
|
|
||||||
#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f }
|
#define rgba_from_u32_lit_comp(h) { (((h)&0xff000000)>>24)/255.f, (((h)&0x00ff0000)>>16)/255.f, (((h)&0x0000ff00)>> 8)/255.f, (((h)&0x000000ff)>> 0)/255.f }
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: List Type Functions
|
//~ rjf: List Type Functions
|
||||||
|
|
||||||
internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n);
|
|
||||||
internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
|
|
||||||
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
|
|
||||||
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
|
|
||||||
internal U64 rng1u64_array_num_from_value__binary_search(Rng1U64Array *array, U64 value);
|
|
||||||
|
|
||||||
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
|
internal void rng1s64_list_push(Arena *arena, Rng1S64List *list, Rng1S64 rng);
|
||||||
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
|
internal Rng1S64Array rng1s64_array_from_list(Arena *arena, Rng1S64List *list);
|
||||||
|
|
||||||
////////////////////////////////
|
#endif // BASE_MATH_H
|
||||||
//~ rjf: N -> M Element Subdivision
|
|
||||||
|
|
||||||
internal Rng1U64 m_range_from_n_idx_m_count(U64 n_idx, U64 n_count, U64 m_count);
|
|
||||||
|
|
||||||
#endif //BASE_MATH_H
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_MEMORY_H
|
|
||||||
#define BASE_MEMORY_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Platform Memory Allocation
|
|
||||||
|
|
||||||
//- rjf: basic
|
|
||||||
internal void *reserve_memory(U64 size);
|
|
||||||
internal B32 commit_memory(void *ptr, U64 size);
|
|
||||||
internal void decommit_memory(void *ptr, U64 size);
|
|
||||||
internal void release_memory(void *ptr, U64 size);
|
|
||||||
|
|
||||||
//- rjf: large pages
|
|
||||||
internal void *reserve_memory_large(U64 size);
|
|
||||||
internal B32 commit_memory_large(void *ptr, U64 size);
|
|
||||||
|
|
||||||
#endif // BASE_MEMORY_H
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Memory Map Functions
|
|
||||||
|
|
||||||
internal void
|
|
||||||
memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data)
|
|
||||||
{
|
|
||||||
MemoryMapRangeNode *n = push_array(arena, MemoryMapRangeNode, 1);
|
|
||||||
n->v.vaddr_range = vaddr_range;
|
|
||||||
n->v.base = data;
|
|
||||||
SLLQueuePush(map->first_range, map->last_range, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal U64
|
|
||||||
memory_map_read(MemoryMap *map, Rng1U64 range, void *dst)
|
|
||||||
{
|
|
||||||
U64 dst_vaddr = range.min;
|
|
||||||
{
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
U64 start_dst_vaddr = dst_vaddr;
|
|
||||||
B32 found = 0;
|
|
||||||
for(MemoryMapRangeNode *n = map->first_range; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(contains_1u64(n->v.vaddr_range, dst_vaddr))
|
|
||||||
{
|
|
||||||
U64 src_off = dst_vaddr - n->v.vaddr_range.min;
|
|
||||||
U64 num_bytes_possible = n->v.vaddr_range.max - dst_vaddr;
|
|
||||||
U64 num_bytes_needed = range.max - dst_vaddr;
|
|
||||||
U64 num_bytes_to_read = Min(num_bytes_needed, num_bytes_possible);
|
|
||||||
MemoryCopy((U8 *)dst + (dst_vaddr - range.min), (U8 *)n->v.base + src_off, num_bytes_to_read);
|
|
||||||
dst_vaddr += num_bytes_to_read;
|
|
||||||
found = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!found || start_dst_vaddr == dst_vaddr)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
U64 bytes_read = (dst_vaddr - range.min);
|
|
||||||
return bytes_read;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
memory_map_data_from_range(Arena *arena, MemoryMap *map, Rng1U64 range)
|
|
||||||
{
|
|
||||||
String8 result = {0};
|
|
||||||
result.size = dim_1u64(range);
|
|
||||||
result.str = push_array(arena, U8, result.size);
|
|
||||||
memory_map_read(map, range, result.str);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_MEMORY_MAP_H
|
|
||||||
#define BASE_MEMORY_MAP_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Memory Map Types
|
|
||||||
|
|
||||||
typedef struct MemoryMapRange MemoryMapRange;
|
|
||||||
struct MemoryMapRange
|
|
||||||
{
|
|
||||||
Rng1U64 vaddr_range;
|
|
||||||
void *base;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct MemoryMapRangeNode MemoryMapRangeNode;
|
|
||||||
struct MemoryMapRangeNode
|
|
||||||
{
|
|
||||||
MemoryMapRangeNode *next;
|
|
||||||
MemoryMapRange v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct MemoryMap MemoryMap;
|
|
||||||
struct MemoryMap
|
|
||||||
{
|
|
||||||
MemoryMapRangeNode *first_range;
|
|
||||||
MemoryMapRangeNode *last_range;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Memory Map Functions
|
|
||||||
|
|
||||||
internal void memory_map_push(Arena *arena, MemoryMap *map, Rng1U64 vaddr_range, void *data);
|
|
||||||
internal U64 memory_map_read(MemoryMap *map, Rng1U64 range, void *dst);
|
|
||||||
#define memory_map_read_struct(map, vaddr, ptr) memory_map_read((map), r1u64((vaddr), (vaddr)+sizeof(*(ptr))), (ptr))
|
|
||||||
internal String8 memory_map_data_from_range(Arena *arena, MemoryMap *map, Rng1U64 range);
|
|
||||||
|
|
||||||
#endif // BASE_MEMORY_MAP_H
|
|
||||||
@@ -1,421 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Lookups
|
|
||||||
|
|
||||||
internal Member *
|
|
||||||
member_from_name(Type *type, String8 name)
|
|
||||||
{
|
|
||||||
Member *member = &member_nil;
|
|
||||||
if(type->members != 0 && name.size != 0)
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < type->count; idx += 1)
|
|
||||||
{
|
|
||||||
if(str8_match(type->members[idx].name, name, 0))
|
|
||||||
{
|
|
||||||
member = &type->members[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info * Instance Operations
|
|
||||||
|
|
||||||
internal void
|
|
||||||
typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
typedef struct RebaseTypeTask RebaseTypeTask;
|
|
||||||
struct RebaseTypeTask
|
|
||||||
{
|
|
||||||
RebaseTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U8 *ptr;
|
|
||||||
};
|
|
||||||
RebaseTypeTask start_task = {0, type, data.str};
|
|
||||||
RebaseTypeTask *first_task = &start_task;
|
|
||||||
RebaseTypeTask *last_task = first_task;
|
|
||||||
for(RebaseTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
default:{}break;
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
*(U64 *)t->ptr = ((U64)(*(U8 **)t->ptr - (U8 *)base_ptr));
|
|
||||||
}break;
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
|
||||||
{
|
|
||||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->ptr = t->ptr + t->type->direct->size * idx;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->type->count; idx += 1)
|
|
||||||
{
|
|
||||||
Member *member = &t->type->members[idx];
|
|
||||||
RebaseTypeTask *task = push_array(scratch.arena, RebaseTypeTask, 1);
|
|
||||||
task->type = member->type;
|
|
||||||
task->ptr = t->ptr + member->value;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8List strings = {0};
|
|
||||||
str8_serial_begin(scratch.arena, &strings);
|
|
||||||
{
|
|
||||||
typedef struct SerializeTypeTask SerializeTypeTask;
|
|
||||||
struct SerializeTypeTask
|
|
||||||
{
|
|
||||||
SerializeTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U64 count;
|
|
||||||
U8 *src;
|
|
||||||
Type *containing_type;
|
|
||||||
U8 *containing_ptr;
|
|
||||||
B32 is_post_header;
|
|
||||||
};
|
|
||||||
SerializeTypeTask start_task = {0, type, 1, data.str};
|
|
||||||
SerializeTypeTask *first_task = &start_task;
|
|
||||||
SerializeTypeTask *last_task = first_task;
|
|
||||||
for(SerializeTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
//- rjf: leaf -> just copy the data directly
|
|
||||||
default:
|
|
||||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
|
||||||
{
|
|
||||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise just write as plain data
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
// rjf: unpack info about this pointer
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
|
||||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
|
||||||
{
|
|
||||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
|
||||||
{
|
|
||||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: indexification -> subtract base, divide direct size, write index
|
|
||||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = ((U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->indexify_base)/t->type->direct->size);
|
|
||||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: offsetification -> subtract base, write offsets
|
|
||||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t->src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = (U64)((U8 *)ptr_value - (U8 *)ptr_ref_info->offsetify_base);
|
|
||||||
str8_serial_push_struct(scratch.arena, &strings, &ptr_write_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
|
||||||
// delimit our size, so push a new post-header task for pointer.
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type;
|
|
||||||
task->count = t->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
task->is_post_header = 1;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
|
||||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
|
||||||
// destination contents
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
|
||||||
{
|
|
||||||
// rjf: determine count of this pointer
|
|
||||||
U64 count = 0;
|
|
||||||
{
|
|
||||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
|
||||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: push task
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = count;
|
|
||||||
task->src = *(void **)t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: catch-all: write pointer value
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str8_serial_push_string(scratch.arena, &strings, str8(t->src, t->type->size*t->count));
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: arrays -> descend to underlying type, + count
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->type->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: struct -> descend to members
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
U64 off = 0;
|
|
||||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
|
||||||
{
|
|
||||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
|
||||||
{
|
|
||||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->members[member_idx].type;
|
|
||||||
task->count = 1;
|
|
||||||
task->src = t->src + idx*t->type->size + t->type->members[member_idx].value;
|
|
||||||
task->containing_type = t->type;
|
|
||||||
task->containing_ptr = t->src;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: enum -> descend to basic type interpretation
|
|
||||||
case TypeKind_Enum:
|
|
||||||
{
|
|
||||||
SerializeTypeTask *task = push_array(scratch.arena, SerializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->count;
|
|
||||||
task->src = t->src;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String8 result = str8_serial_end(arena, &strings);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
String8 result = {0};
|
|
||||||
result.size = type->size;
|
|
||||||
result.str = push_array(arena, U8, result.size);
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
typedef struct DeserializeTypeTask DeserializeTypeTask;
|
|
||||||
struct DeserializeTypeTask
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *next;
|
|
||||||
Type *type;
|
|
||||||
U64 count;
|
|
||||||
U8 *dst;
|
|
||||||
Type *containing_type;
|
|
||||||
U8 *containing_ptr;
|
|
||||||
B32 is_post_header;
|
|
||||||
};
|
|
||||||
U64 read_off = 0;
|
|
||||||
DeserializeTypeTask start_task = {0, type, 1, result.str};
|
|
||||||
DeserializeTypeTask *first_task = &start_task;
|
|
||||||
DeserializeTypeTask *last_task = first_task;
|
|
||||||
for(DeserializeTypeTask *t = first_task; t != 0; t = t->next)
|
|
||||||
{
|
|
||||||
U8 *t_src = data.str + read_off;
|
|
||||||
switch(t->type->kind)
|
|
||||||
{
|
|
||||||
//- rjf: leaf -> copy the data directly
|
|
||||||
default:
|
|
||||||
if(TypeKind_FirstLeaf <= t->type->kind && t->type->kind <= TypeKind_LastLeaf)
|
|
||||||
{
|
|
||||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
|
||||||
read_off += t->type->size*t->count;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: pointers -> try to interpret/understand pointer & read/write, otherwise skip
|
|
||||||
case TypeKind_Ptr:
|
|
||||||
{
|
|
||||||
// rjf: unpack info about this pointer
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_info = 0;
|
|
||||||
for(U64 idx = 0; idx < params->ptr_ref_infos_count; idx += 1)
|
|
||||||
{
|
|
||||||
if(params->ptr_ref_infos[idx].type == t->type->direct)
|
|
||||||
{
|
|
||||||
ptr_ref_info = ¶ms->ptr_ref_infos[idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: indexification -> add base, multiply direct size
|
|
||||||
if(ptr_ref_info != 0 && ptr_ref_info->indexify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = (ptr_value + (U64)ptr_ref_info->indexify_base) * t->type->direct->size;
|
|
||||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
|
||||||
read_off += sizeof(ptr_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: offsetification -> subtract base, write offsets
|
|
||||||
else if(ptr_ref_info != 0 && ptr_ref_info->offsetify_base != 0)
|
|
||||||
{
|
|
||||||
U64 ptr_value = 0;
|
|
||||||
MemoryCopy(&ptr_value, t_src, sizeof(ptr_value));
|
|
||||||
U64 ptr_write_value = ptr_value + (U64)ptr_ref_info->offsetify_base;
|
|
||||||
MemoryCopy(t->dst, &ptr_write_value, sizeof(ptr_write_value));
|
|
||||||
read_off += sizeof(ptr_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (pre-header): still potentially dependent on other members which
|
|
||||||
// delimit our size, so push a new post-header task for pointer.
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && !t->is_post_header)
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type;
|
|
||||||
task->count = t->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
task->is_post_header = 1;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: size-by-member (post-header): all flat parts of containing struct have been
|
|
||||||
// iterated, so now we can read the size, & descend to new task to read pointer
|
|
||||||
// destination contents
|
|
||||||
else if(t->type->count_delimiter_name.size != 0 && t->is_post_header)
|
|
||||||
{
|
|
||||||
// rjf: determine count of this pointer
|
|
||||||
U64 count = 0;
|
|
||||||
{
|
|
||||||
Member *count_member = member_from_name(t->containing_type, t->type->count_delimiter_name);
|
|
||||||
MemoryCopy(&count, t->containing_ptr + count_member->value, count_member->type->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: allocate buffer for pointer destination; write address into pointer value slot
|
|
||||||
U64 ptr_dest_buffer_size = (count+1)*t->type->direct->size;
|
|
||||||
U8 *ptr_dest_buffer = push_array(arena, U8, ptr_dest_buffer_size);
|
|
||||||
MemoryCopy(t->dst, &ptr_dest_buffer, sizeof(ptr_dest_buffer));
|
|
||||||
|
|
||||||
// rjf: push task
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = count;
|
|
||||||
task->dst = ptr_dest_buffer;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: catch-all: read pointer value
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MemoryCopy(t->dst, t_src, t->type->size*t->count);
|
|
||||||
read_off += t->type->size*t->count;
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: arrays -> descend to underlying type, + count
|
|
||||||
case TypeKind_Array:
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->type->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: struct -> descend to members
|
|
||||||
case TypeKind_Struct:
|
|
||||||
{
|
|
||||||
for(U64 idx = 0; idx < t->count; idx += 1)
|
|
||||||
{
|
|
||||||
for(U64 member_idx = 0; member_idx < t->type->count; member_idx += 1)
|
|
||||||
{
|
|
||||||
if(t->type->members[member_idx].flags & MemberFlag_DoNotSerialize)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->members[member_idx].type;
|
|
||||||
task->count = 1;
|
|
||||||
task->dst = t->dst + idx*t->type->size + t->type->members[member_idx].value;
|
|
||||||
task->containing_type = t->type;
|
|
||||||
task->containing_ptr = t->dst;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}break;
|
|
||||||
|
|
||||||
//- rjf: enum -> descend to basic type interpretation
|
|
||||||
case TypeKind_Enum:
|
|
||||||
{
|
|
||||||
DeserializeTypeTask *task = push_array(scratch.arena, DeserializeTypeTask, 1);
|
|
||||||
task->type = t->type->direct;
|
|
||||||
task->count = t->count;
|
|
||||||
task->dst = t->dst;
|
|
||||||
task->containing_type = t->containing_type;
|
|
||||||
task->containing_ptr = t->containing_ptr;
|
|
||||||
SLLQueuePush(first_task, last_task, task);
|
|
||||||
}break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(params->advance_out != 0)
|
|
||||||
{
|
|
||||||
params->advance_out[0] = read_off;
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(&arena, 1);
|
|
||||||
String8 data_srlz = serialized_from_typed_data(scratch.arena, type, data, params);
|
|
||||||
String8 data_copy = deserialized_from_typed_data(arena, type, data_srlz, params);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return data_copy;
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_META_H
|
|
||||||
#define BASE_META_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Meta Markup Features
|
|
||||||
|
|
||||||
#define EmbedFile(name, path)
|
|
||||||
#define TweakB32(name, default) (TWEAK_##name)
|
|
||||||
#define TweakF32(name, default, min, max) (TWEAK_##name)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Tweak Info Tables
|
|
||||||
|
|
||||||
typedef struct TweakB32Info TweakB32Info;
|
|
||||||
struct TweakB32Info
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
B32 default_value;
|
|
||||||
B32 *value_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakF32Info TweakF32Info;
|
|
||||||
struct TweakF32Info
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
F32 default_value;
|
|
||||||
Rng1F32 value_range;
|
|
||||||
F32 *value_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakB32InfoTable TweakB32InfoTable;
|
|
||||||
struct TweakB32InfoTable
|
|
||||||
{
|
|
||||||
TweakB32Info *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TweakF32InfoTable TweakF32InfoTable;
|
|
||||||
struct TweakF32InfoTable
|
|
||||||
{
|
|
||||||
TweakF32Info *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct EmbedInfo EmbedInfo;
|
|
||||||
struct EmbedInfo
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 *data;
|
|
||||||
U128 *hash;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct EmbedInfoTable EmbedInfoTable;
|
|
||||||
struct EmbedInfoTable
|
|
||||||
{
|
|
||||||
EmbedInfo *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Types
|
|
||||||
|
|
||||||
typedef enum TypeKind
|
|
||||||
{
|
|
||||||
TypeKind_Null,
|
|
||||||
|
|
||||||
// rjf: leaves
|
|
||||||
TypeKind_Void, TypeKind_FirstLeaf = TypeKind_Void,
|
|
||||||
TypeKind_U8,
|
|
||||||
TypeKind_U16,
|
|
||||||
TypeKind_U32,
|
|
||||||
TypeKind_U64,
|
|
||||||
TypeKind_S8,
|
|
||||||
TypeKind_S16,
|
|
||||||
TypeKind_S32,
|
|
||||||
TypeKind_S64,
|
|
||||||
TypeKind_B8,
|
|
||||||
TypeKind_B16,
|
|
||||||
TypeKind_B32,
|
|
||||||
TypeKind_B64,
|
|
||||||
TypeKind_F32,
|
|
||||||
TypeKind_F64, TypeKind_LastLeaf = TypeKind_F64,
|
|
||||||
|
|
||||||
// rjf: operators
|
|
||||||
TypeKind_Ptr,
|
|
||||||
TypeKind_Array,
|
|
||||||
|
|
||||||
// rjf: user-defined-types
|
|
||||||
TypeKind_Struct,
|
|
||||||
TypeKind_Union,
|
|
||||||
TypeKind_Enum,
|
|
||||||
|
|
||||||
TypeKind_COUNT
|
|
||||||
}
|
|
||||||
TypeKind;
|
|
||||||
|
|
||||||
typedef U32 TypeFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
TypeFlag_IsPlainText = (1<<0),
|
|
||||||
TypeFlag_IsCodeText = (1<<1),
|
|
||||||
TypeFlag_IsPathText = (1<<2),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef U32 MemberFlags;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
MemberFlag_DoNotSerialize = (1<<0),
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Type Type;
|
|
||||||
typedef struct Member Member;
|
|
||||||
struct Member
|
|
||||||
{
|
|
||||||
String8 name;
|
|
||||||
String8 pretty_name;
|
|
||||||
Type *type;
|
|
||||||
U64 value;
|
|
||||||
MemberFlags flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Type Type;
|
|
||||||
struct Type
|
|
||||||
{
|
|
||||||
TypeKind kind;
|
|
||||||
TypeFlags flags;
|
|
||||||
U64 size;
|
|
||||||
Type *direct;
|
|
||||||
String8 name;
|
|
||||||
String8 count_delimiter_name; // gathered from surrounding members, turns *->[1] into *->[N]
|
|
||||||
U64 count;
|
|
||||||
Member *members;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Serialization Parameters
|
|
||||||
|
|
||||||
typedef struct TypeSerializePtrRefInfo TypeSerializePtrRefInfo;
|
|
||||||
struct TypeSerializePtrRefInfo
|
|
||||||
{
|
|
||||||
Type *type; // pointers to this
|
|
||||||
void *indexify_base; // can be indexified using this
|
|
||||||
void *offsetify_base; // can be offsetified using this
|
|
||||||
void *nil_ptr; // is terminal if matching 0 or this
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TypeSerializeParams TypeSerializeParams;
|
|
||||||
struct TypeSerializeParams
|
|
||||||
{
|
|
||||||
U64 *advance_out;
|
|
||||||
TypeSerializePtrRefInfo *ptr_ref_infos;
|
|
||||||
U64 ptr_ref_infos_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Name -> Type Info
|
|
||||||
|
|
||||||
#define type(T) (&T##__type)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Table Initializer Helpers
|
|
||||||
|
|
||||||
#define member_lit_comp(S, ti, m, ...) {str8_lit_comp(#m), {0}, (ti), OffsetOf(S, m), __VA_ARGS__}
|
|
||||||
#define struct_members(S) read_only global Member S##__members[] =
|
|
||||||
#define struct_type(S, ...) read_only global Type S##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#S), {0}, ArrayCount(S##__members), S##__members, __VA_ARGS__}
|
|
||||||
#define named_struct_type(name, S, ...) read_only global Type name##__type = {TypeKind_Struct, 0, sizeof(S), &type_nil, str8_lit_comp(#name), {0}, ArrayCount(name##__members), name##__members, __VA_ARGS__}
|
|
||||||
#define ptr_type(name, ti, ...) read_only global Type name = {TypeKind_Ptr, 0, sizeof(void *), (ti), __VA_ARGS__}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Globals
|
|
||||||
|
|
||||||
read_only global Type type_nil = {TypeKind_Null, 0, 0, &type_nil};
|
|
||||||
read_only global Member member_nil = {{0}, {0}, &type_nil};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Built-In Types
|
|
||||||
|
|
||||||
//- rjf: leaves
|
|
||||||
read_only global Type void__type = {TypeKind_Void, 0, 0, &type_nil, str8_lit_comp("void")};
|
|
||||||
read_only global Type U8__type = {TypeKind_U8, 0, sizeof(U8), &type_nil, str8_lit_comp("U8")};
|
|
||||||
read_only global Type U16__type = {TypeKind_U16, 0, sizeof(U16), &type_nil, str8_lit_comp("U16")};
|
|
||||||
read_only global Type U32__type = {TypeKind_U32, 0, sizeof(U32), &type_nil, str8_lit_comp("U32")};
|
|
||||||
read_only global Type U64__type = {TypeKind_U64, 0, sizeof(U64), &type_nil, str8_lit_comp("U64")};
|
|
||||||
read_only global Type S8__type = {TypeKind_S8, 0, sizeof(S8), &type_nil, str8_lit_comp("S8")};
|
|
||||||
read_only global Type S16__type = {TypeKind_S16, 0, sizeof(S16), &type_nil, str8_lit_comp("S16")};
|
|
||||||
read_only global Type S32__type = {TypeKind_S32, 0, sizeof(S32), &type_nil, str8_lit_comp("S32")};
|
|
||||||
read_only global Type S64__type = {TypeKind_S64, 0, sizeof(S64), &type_nil, str8_lit_comp("S64")};
|
|
||||||
read_only global Type B8__type = {TypeKind_B8, 0, sizeof(B8), &type_nil, str8_lit_comp("B8")};
|
|
||||||
read_only global Type B16__type = {TypeKind_B16, 0, sizeof(B16), &type_nil, str8_lit_comp("B16")};
|
|
||||||
read_only global Type B32__type = {TypeKind_B32, 0, sizeof(B32), &type_nil, str8_lit_comp("B32")};
|
|
||||||
read_only global Type B64__type = {TypeKind_B64, 0, sizeof(B64), &type_nil, str8_lit_comp("B64")};
|
|
||||||
read_only global Type F32__type = {TypeKind_F32, 0, sizeof(F32), &type_nil, str8_lit_comp("F32")};
|
|
||||||
read_only global Type F64__type = {TypeKind_F64, 0, sizeof(F64), &type_nil, str8_lit_comp("F64")};
|
|
||||||
read_only global Type *type_kind_type_table[] =
|
|
||||||
{
|
|
||||||
&type_nil,
|
|
||||||
type(void),
|
|
||||||
type(U8),
|
|
||||||
type(U16),
|
|
||||||
type(U32),
|
|
||||||
type(U64),
|
|
||||||
type(S8),
|
|
||||||
type(S16),
|
|
||||||
type(S32),
|
|
||||||
type(S64),
|
|
||||||
type(B8),
|
|
||||||
type(B16),
|
|
||||||
type(B32),
|
|
||||||
type(B64),
|
|
||||||
type(F32),
|
|
||||||
type(F64),
|
|
||||||
&type_nil,
|
|
||||||
&type_nil,
|
|
||||||
&type_nil,
|
|
||||||
&type_nil,
|
|
||||||
&type_nil,
|
|
||||||
};
|
|
||||||
|
|
||||||
//- rjf: Rng1U64
|
|
||||||
struct_members(Rng1U64)
|
|
||||||
{
|
|
||||||
member_lit_comp(Rng1U64, type(U64), min),
|
|
||||||
member_lit_comp(Rng1U64, type(U64), max),
|
|
||||||
};
|
|
||||||
struct_type(Rng1U64);
|
|
||||||
|
|
||||||
//- rjf: String8
|
|
||||||
ptr_type(String8__str_ptr_type, type(U8), str8_lit_comp("size"));
|
|
||||||
struct_members(String8)
|
|
||||||
{
|
|
||||||
member_lit_comp(String8, &String8__str_ptr_type, str),
|
|
||||||
member_lit_comp(String8, type(U64), size),
|
|
||||||
};
|
|
||||||
struct_type(String8);
|
|
||||||
|
|
||||||
//- rjf: String8Node
|
|
||||||
extern Type String8Node__type;
|
|
||||||
Type String8Node__ptr_type = {TypeKind_Ptr, 0, sizeof(void *), &String8Node__type};
|
|
||||||
Member String8Node__members[] =
|
|
||||||
{
|
|
||||||
{str8_lit_comp("next"), {0}, &String8Node__ptr_type, OffsetOf(String8Node, next)},
|
|
||||||
{str8_lit_comp("string"), {0}, type(String8), OffsetOf(String8Node, string)},
|
|
||||||
};
|
|
||||||
Type String8Node__type =
|
|
||||||
{
|
|
||||||
TypeKind_Struct,
|
|
||||||
0,
|
|
||||||
sizeof(String8Node),
|
|
||||||
&type_nil,
|
|
||||||
str8_lit_comp("String8Node"),
|
|
||||||
{0},
|
|
||||||
ArrayCount(String8Node__members),
|
|
||||||
String8Node__members,
|
|
||||||
};
|
|
||||||
|
|
||||||
//- rjf: String8List
|
|
||||||
Member String8List__members[] =
|
|
||||||
{
|
|
||||||
{str8_lit_comp("first"), {0}, &String8Node__ptr_type, OffsetOf(String8List, first)},
|
|
||||||
{str8_lit_comp("last"), {0}, &String8Node__ptr_type, OffsetOf(String8List, last), MemberFlag_DoNotSerialize},
|
|
||||||
{str8_lit_comp("node_count"), {0}, type(U64), OffsetOf(String8List, node_count)},
|
|
||||||
{str8_lit_comp("total_size"), {0}, type(U64), OffsetOf(String8List, total_size)},
|
|
||||||
};
|
|
||||||
Type String8List__type =
|
|
||||||
{
|
|
||||||
TypeKind_Struct,
|
|
||||||
0,
|
|
||||||
sizeof(String8List),
|
|
||||||
&type_nil,
|
|
||||||
str8_lit_comp("String8List"),
|
|
||||||
{0},
|
|
||||||
ArrayCount(String8List__members),
|
|
||||||
String8List__members,
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info Lookups
|
|
||||||
|
|
||||||
internal Member *member_from_name(Type *type, String8 name);
|
|
||||||
#define EachMember(T, it) (Member *it = (type(T))->members; it != 0 && it < (type(T))->members + (type(T))->count; it += 1)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Type Info * Instance Operations
|
|
||||||
|
|
||||||
internal void typed_data_rebase_ptrs(Type *type, String8 data, void *base_ptr);
|
|
||||||
internal String8 serialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
internal String8 deserialized_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
internal String8 deep_copy_from_typed_data(Arena *arena, Type *type, String8 data, TypeSerializeParams *params);
|
|
||||||
#define struct_rebase_ptrs(T, ptr, base) typed_data_rebase_ptrs(type(T), str8_struct(ptr), (base))
|
|
||||||
#define serialized_from_struct(arena, T, ptr, ...) serialized_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__})
|
|
||||||
#define struct_from_serialized(arena, T, string, ...) (T *)deserialized_from_typed_data((arena), type(T), (string), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
|
||||||
#define deep_copy_from_struct(arena, T, ptr, ...) (T *)deep_copy_from_typed_data((arena), type(T), str8_struct(ptr), &(TypeSerializeParams){.ptr_ref_infos = 0, __VA_ARGS__}).str
|
|
||||||
|
|
||||||
#endif // BASE_META_H
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Handle Type Functions
|
|
||||||
|
|
||||||
internal Process
|
|
||||||
process_zero(void)
|
|
||||||
{
|
|
||||||
Process p = {0};
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
process_match(Process a, Process b)
|
|
||||||
{
|
|
||||||
B32 result = MemoryMatchStruct(&a, &b);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
process_list_push(Arena *arena, ProcessList *list, Process p)
|
|
||||||
{
|
|
||||||
ProcessNode *n = push_array(arena, ProcessNode, 1);
|
|
||||||
SLLQueuePush(list->first, list->last, n);
|
|
||||||
n->v = p;
|
|
||||||
list->count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Process Launcher Helpers
|
|
||||||
|
|
||||||
internal Process
|
|
||||||
launch_cmd_line(String8 string)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
U8 split_chars[] = {' '};
|
|
||||||
String8List parts = str8_split(scratch.arena, string, split_chars, ArrayCount(split_chars), 0);
|
|
||||||
Process process = {0};
|
|
||||||
if(parts.node_count != 0)
|
|
||||||
{
|
|
||||||
// rjf: unpack exe part
|
|
||||||
String8 exe = parts.first->string;
|
|
||||||
String8 exe_folder = str8_chop_last_slash(exe);
|
|
||||||
if(exe_folder.size == 0)
|
|
||||||
{
|
|
||||||
exe_folder = get_current_path(scratch.arena);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: find stdout delimiter
|
|
||||||
String8Node *stdout_delimiter_n = 0;
|
|
||||||
for(String8Node *n = parts.first; n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
if(str8_match(n->string, str8_lit(">"), 0))
|
|
||||||
{
|
|
||||||
stdout_delimiter_n = n;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: read stdout path
|
|
||||||
String8 stdout_path = {0};
|
|
||||||
if(stdout_delimiter_n && stdout_delimiter_n->next)
|
|
||||||
{
|
|
||||||
stdout_path = stdout_delimiter_n->next->string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: open stdout handle
|
|
||||||
File stdout_handle = {0};
|
|
||||||
if(stdout_path.size != 0)
|
|
||||||
{
|
|
||||||
File file = file_open(AccessFlag_Write|AccessFlag_Read, stdout_path);
|
|
||||||
file_close(file);
|
|
||||||
stdout_handle = file_open(AccessFlag_Write|AccessFlag_Append|AccessFlag_ShareRead|AccessFlag_ShareWrite|AccessFlag_Inherited, stdout_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: form command line
|
|
||||||
String8List cmdline = {0};
|
|
||||||
for(String8Node *n = parts.first; n != stdout_delimiter_n && n != 0; n = n->next)
|
|
||||||
{
|
|
||||||
str8_list_push(scratch.arena, &cmdline, n->string);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: launch
|
|
||||||
ProcessLaunchParams params = {0};
|
|
||||||
params.cmd_line = cmdline;
|
|
||||||
params.path = exe_folder;
|
|
||||||
params.inherit_env = 1;
|
|
||||||
params.stdout_file = stdout_handle;
|
|
||||||
process = process_launch(¶ms);
|
|
||||||
|
|
||||||
// rjf: close stdout handle
|
|
||||||
{
|
|
||||||
if(stdout_path.size != 0)
|
|
||||||
{
|
|
||||||
file_close(stdout_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scratch_end(scratch);
|
|
||||||
return process;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Process
|
|
||||||
launch_cmd_linef(char *fmt, ...)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = str8fv(scratch.arena, fmt, args);
|
|
||||||
Process result = launch_cmd_line(string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_PROCESSES_H
|
|
||||||
#define BASE_PROCESSES_H
|
|
||||||
|
|
||||||
typedef struct ProcessInfo ProcessInfo;
|
|
||||||
struct ProcessInfo
|
|
||||||
{
|
|
||||||
U32 pid;
|
|
||||||
B32 large_pages_allowed;
|
|
||||||
String8 binary_file_path;
|
|
||||||
String8 binary_path;
|
|
||||||
String8 initial_path;
|
|
||||||
String8 user_program_config_data_path;
|
|
||||||
String8 user_program_cache_data_path;
|
|
||||||
String8 user_program_logs_data_path;
|
|
||||||
String8List module_load_paths;
|
|
||||||
String8List environment;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Process Process;
|
|
||||||
struct Process
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ProcessNode ProcessNode;
|
|
||||||
struct ProcessNode
|
|
||||||
{
|
|
||||||
ProcessNode *next;
|
|
||||||
Process v;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ProcessList ProcessList;
|
|
||||||
struct ProcessList
|
|
||||||
{
|
|
||||||
ProcessNode *first;
|
|
||||||
ProcessNode *last;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ProcessLaunchParams ProcessLaunchParams;
|
|
||||||
struct ProcessLaunchParams
|
|
||||||
{
|
|
||||||
String8List cmd_line;
|
|
||||||
String8 path;
|
|
||||||
String8List env;
|
|
||||||
B32 inherit_env;
|
|
||||||
B32 debug_subprocesses;
|
|
||||||
B32 consoleless;
|
|
||||||
File stdout_file;
|
|
||||||
File stderr_file;
|
|
||||||
File stdin_file;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Handle Type Functions
|
|
||||||
|
|
||||||
internal Process process_zero(void);
|
|
||||||
internal B32 process_match(Process a, Process b);
|
|
||||||
internal void process_list_push(Arena *arena, ProcessList *list, Process p);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Process Launcher Helpers
|
|
||||||
|
|
||||||
internal Process launch_cmd_line(String8 string);
|
|
||||||
internal Process launch_cmd_linef(char *fmt, ...);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Aborting
|
|
||||||
|
|
||||||
internal void abort_self(U64 exit_code);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Process Info
|
|
||||||
|
|
||||||
internal ProcessInfo *get_process_info(void);
|
|
||||||
internal String8 get_current_path(Arena *arena);
|
|
||||||
internal U32 get_process_start_time_unix(void);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Child Processes
|
|
||||||
|
|
||||||
internal Process process_launch(ProcessLaunchParams *params);
|
|
||||||
internal U64 pid_from_process(Process process);
|
|
||||||
internal B32 process_join(Process process, U64 endt_us, U64 *exit_code_out);
|
|
||||||
internal void process_detach(Process process);
|
|
||||||
internal B32 process_kill(Process process);
|
|
||||||
|
|
||||||
#endif // BASE_PROCESSES_H
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#if PROFILE_SPALL
|
|
||||||
internal inline void
|
|
||||||
spall_begin(char *fmt, ...)
|
|
||||||
{
|
|
||||||
if(spall_buffer.data == 0)
|
|
||||||
{
|
|
||||||
spall_buffer.length = MB(1);
|
|
||||||
spall_buffer.data = os_reserve(spall_buffer.length);
|
|
||||||
os_commit(spall_buffer.data, spall_buffer.length);
|
|
||||||
spall_buffer_init(&spall_profile, &spall_buffer);
|
|
||||||
}
|
|
||||||
if(spall_pid == 0)
|
|
||||||
{
|
|
||||||
spall_pid = os_get_process_info()->pid;
|
|
||||||
}
|
|
||||||
if(spall_tid == 0)
|
|
||||||
{
|
|
||||||
spall_tid = os_tid();
|
|
||||||
}
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
spall_buffer_begin_ex(&spall_profile, &spall_buffer, string.str, string.size, now_time_us(), spall_tid, spall_pid);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_PROFILE_H
|
|
||||||
#define BASE_PROFILE_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Zero Settings
|
|
||||||
|
|
||||||
#if !defined(PROFILE_TELEMETRY)
|
|
||||||
# define PROFILE_TELEMETRY 0
|
|
||||||
#endif
|
|
||||||
#if !defined(PROFILE_SPALL)
|
|
||||||
# define PROFILE_SPALL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Third Party Includes
|
|
||||||
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
# include "rad_tm.h"
|
|
||||||
# if OS_WINDOWS
|
|
||||||
# pragma comment(lib, "ws2_32.lib")
|
|
||||||
# pragma comment(lib, "rad_tm_win64.lib")
|
|
||||||
# endif
|
|
||||||
#elif PROFILE_SPALL
|
|
||||||
# include "spall.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Telemetry Profile Defines
|
|
||||||
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__)
|
|
||||||
# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
|
||||||
# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0)
|
|
||||||
# define ProfTick(...) tmTick(0)
|
|
||||||
# define ProfIsCapturing(...) tmRunning()
|
|
||||||
# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100)
|
|
||||||
# define ProfEndCapture(...) tmClose(0)
|
|
||||||
# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0)
|
|
||||||
# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0)
|
|
||||||
# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__)
|
|
||||||
# define ProfEndLockWait(...) tmEndWaitForLock(0)
|
|
||||||
# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__)
|
|
||||||
# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__)
|
|
||||||
# define ProfColor(color) tmZoneColor((((color) & 0xff000000) >> 24) / 255.f, (((color) & 0x00ff0000) >> 16) / 255.f, (((color) & 0x0000ff00) >> 8) / 255.f)
|
|
||||||
# define ProfBeginV(...) \
|
|
||||||
if (TM_API_PTR) { \
|
|
||||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
|
||||||
Temp scratch = scratch_begin(0,0); \
|
|
||||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
|
||||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
|
||||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
|
||||||
TM_API_PTR->_tmEnterZoneFast_Core(0, 0, file_id, __LINE__, hash); \
|
|
||||||
scratch_end(scratch); \
|
|
||||||
}
|
|
||||||
# define ProfNoteV(...) \
|
|
||||||
if (TM_API_PTR) { \
|
|
||||||
static tm_uint64 file_id = 0; TM_API_PTR->_tmStaticString(&file_id, __FILE__); \
|
|
||||||
Temp scratch = scratch_begin(0,0); \
|
|
||||||
String8 string = push_str8f(scratch.arena, __VA_ARGS__); \
|
|
||||||
tm_uint64 hash = TM_API_PTR->_tmHash((char*)string.str, string.size); \
|
|
||||||
hash = TM_API_PTR->_tmSendDynamicString(hash, (char*)string.str); \
|
|
||||||
TM_API_PTR->_tmMessageFast_Core(0, TMMF_ICON_NOTE, file_id, __LINE__, hash); \
|
|
||||||
scratch_end(scratch); \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Spall Profile Defines
|
|
||||||
|
|
||||||
#if PROFILE_SPALL
|
|
||||||
global U64 spall_capturing = 0;
|
|
||||||
global SpallProfile spall_profile = {0};
|
|
||||||
thread_static SpallBuffer spall_buffer = {0};
|
|
||||||
thread_static U32 spall_tid = 0;
|
|
||||||
thread_static U32 spall_pid = 0;
|
|
||||||
internal inline void spall_begin(char *fmt, ...);
|
|
||||||
# define ProfBegin(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
|
||||||
# define ProfBeginDynamic(...) (spall_capturing ? (spall_begin(__VA_ARGS__), 0) : 0)
|
|
||||||
# define ProfEnd(...) (spall_capturing ? (spall_buffer_end_ex(&spall_profile, &spall_buffer, now_time_us(), spall_tid, spall_pid)), 0 : 0)
|
|
||||||
# define ProfTick(...)
|
|
||||||
# define ProfIsCapturing(...) (!!spall_capturing)
|
|
||||||
# define ProfBeginCapture(...) (spall_capturing = 1)
|
|
||||||
# define ProfEndCapture(...) (spall_capturing = 0, spall_flush(&spall_profile))
|
|
||||||
# define ProfThreadName(...)
|
|
||||||
# define ProfMsg(...)
|
|
||||||
# define ProfBeginLockWait(...)
|
|
||||||
# define ProfEndLockWait(...)
|
|
||||||
# define ProfLockTake(...)
|
|
||||||
# define ProfLockDrop(...)
|
|
||||||
# define ProfColor(color)
|
|
||||||
# define ProfBeginV(...)
|
|
||||||
# define ProfNoteV(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Zeroify Undefined Defines
|
|
||||||
|
|
||||||
#if !defined(ProfBegin)
|
|
||||||
# define ProfBegin(...) (0)
|
|
||||||
# define ProfBeginDynamic(...) (0)
|
|
||||||
# define ProfEnd(...) (0)
|
|
||||||
# define ProfTick(...) (0)
|
|
||||||
# define ProfIsCapturing(...) (0)
|
|
||||||
# define ProfBeginCapture(...) (0)
|
|
||||||
# define ProfEndCapture(...) (0)
|
|
||||||
# define ProfThreadName(...) (0)
|
|
||||||
# define ProfMsg(...) (0)
|
|
||||||
# define ProfBeginLockWait(...) (0)
|
|
||||||
# define ProfEndLockWait(...) (0)
|
|
||||||
# define ProfLockTake(...) (0)
|
|
||||||
# define ProfLockDrop(...) (0)
|
|
||||||
# define ProfColor(...) (0)
|
|
||||||
# define ProfBeginV(...) (0)
|
|
||||||
# define ProfNoteV(...) (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Helper Wrappers
|
|
||||||
|
|
||||||
#define ProfBeginFunction(...) ProfBegin(this_function_name)
|
|
||||||
#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd())
|
|
||||||
|
|
||||||
#endif // BASE_PROFILE_H
|
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Ring Functions
|
|
||||||
|
|
||||||
internal Ring *
|
|
||||||
make_ring(Arena *arena, U64 size)
|
|
||||||
{
|
|
||||||
Ring *ring = push_array(arena, Ring, 1);
|
|
||||||
ring->size = size;
|
|
||||||
ring->base = push_array(arena, U8, ring->size);
|
|
||||||
return ring;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
ring_try_write(Ring *ring, U64 size, void *ptr)
|
|
||||||
{
|
|
||||||
U64 bytes_unconsumed = (ring->write_pos - ring->read_pos);
|
|
||||||
U64 bytes_available = ring->size - bytes_unconsumed;
|
|
||||||
B32 result = 0;
|
|
||||||
if(bytes_available >= size)
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
ring->write_pos += wrapped_write(ring->base, ring->size, ring->write_pos, ptr, size);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
ring_try_read(Ring *ring, U64 size, void *ptr)
|
|
||||||
{
|
|
||||||
U64 bytes_unconsumed = (ring->write_pos - ring->read_pos);
|
|
||||||
B32 result = 0;
|
|
||||||
if(bytes_unconsumed >= size)
|
|
||||||
{
|
|
||||||
result = 1;
|
|
||||||
ring->read_pos += wrapped_read(ring->base, ring->size, ring->read_pos, ptr, size);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Guarded Ring Functions
|
|
||||||
|
|
||||||
internal GuardedRing *
|
|
||||||
guarded_ring_alloc(Arena *arena, U64 size)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
GuardedRing *gr = push_array(arena, GuardedRing, 1);
|
|
||||||
gr->ring = make_ring(arena, size);
|
|
||||||
gr->mutex = mutex_alloc();
|
|
||||||
gr->cv = cond_var_alloc();
|
|
||||||
ProfEnd();
|
|
||||||
return gr;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
guarded_ring_release(GuardedRing *ring)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
mutex_release(ring->mutex);
|
|
||||||
cond_var_release(ring->cv);
|
|
||||||
ProfEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal RingGuard
|
|
||||||
guarded_ring_open(GuardedRing *ring)
|
|
||||||
{
|
|
||||||
RingGuard guard = {ring};
|
|
||||||
mutex_take(ring->mutex);
|
|
||||||
return guard;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
guarded_ring_close(RingGuard *guard)
|
|
||||||
{
|
|
||||||
mutex_drop(guard->r->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
guarded_ring_try_write(RingGuard *guard, U64 size, void *ptr)
|
|
||||||
{
|
|
||||||
B32 result = ring_try_write(guard->r->ring, size, ptr);
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
cond_var_broadcast(guard->r->cv);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
guarded_ring_try_read(RingGuard *guard, U64 size, void *ptr)
|
|
||||||
{
|
|
||||||
B32 result = ring_try_read(guard->r->ring, size, ptr);
|
|
||||||
if(result)
|
|
||||||
{
|
|
||||||
cond_var_broadcast(guard->r->cv);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
guarded_ring_write_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us)
|
|
||||||
{
|
|
||||||
B32 write_good = 0;
|
|
||||||
for(;!write_good;)
|
|
||||||
{
|
|
||||||
write_good = guarded_ring_try_write(guard, size, ptr);
|
|
||||||
if(now_time_us() >= endt_us)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!write_good)
|
|
||||||
{
|
|
||||||
cond_var_wait(guard->r->cv, guard->r->mutex, endt_us);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return write_good;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
guarded_ring_read_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us)
|
|
||||||
{
|
|
||||||
B32 read_good = 0;
|
|
||||||
for(;!read_good;)
|
|
||||||
{
|
|
||||||
read_good = guarded_ring_try_read(guard, size, ptr);
|
|
||||||
if(now_time_us() >= endt_us)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!read_good)
|
|
||||||
{
|
|
||||||
cond_var_wait(guard->r->cv, guard->r->mutex, endt_us);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return read_good;
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_RING_H
|
|
||||||
#define BASE_RING_H
|
|
||||||
|
|
||||||
typedef struct Ring Ring;
|
|
||||||
struct Ring
|
|
||||||
{
|
|
||||||
U8 *base;
|
|
||||||
U64 size;
|
|
||||||
U64 write_pos;
|
|
||||||
U64 read_pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct GuardedRing GuardedRing;
|
|
||||||
struct GuardedRing
|
|
||||||
{
|
|
||||||
Ring *ring;
|
|
||||||
Mutex mutex;
|
|
||||||
CondVar cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct RingGuard RingGuard;
|
|
||||||
struct RingGuard
|
|
||||||
{
|
|
||||||
GuardedRing *r;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Ring Functions
|
|
||||||
|
|
||||||
internal Ring *make_ring(Arena *arena, U64 size);
|
|
||||||
internal B32 ring_try_write(Ring *ring, U64 size, void *ptr);
|
|
||||||
internal B32 ring_try_read(Ring *ring, U64 size, void *ptr);
|
|
||||||
#define ring_try_write_struct(ring, ptr) ring_try_write((ring), sizeof(*(ptr)), (ptr))
|
|
||||||
#define ring_try_read_struct(ring, ptr) ring_try_read((ring), sizeof(*(ptr)), (ptr))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Guarded Ring Functions
|
|
||||||
|
|
||||||
internal GuardedRing *guarded_ring_alloc(Arena *arena, U64 size);
|
|
||||||
internal void guarded_ring_release(GuardedRing *ring);
|
|
||||||
internal RingGuard guarded_ring_open(GuardedRing *ring);
|
|
||||||
internal void guarded_ring_close(RingGuard *guard);
|
|
||||||
internal B32 guarded_ring_try_write(RingGuard *guard, U64 size, void *ptr);
|
|
||||||
internal B32 guarded_ring_try_read(RingGuard *guard, U64 size, void *ptr);
|
|
||||||
#define guarded_ring_try_write_struct(ring, ptr) guarded_ring_try_write((ring), sizeof(*(ptr)), (ptr))
|
|
||||||
#define guarded_ring_try_read_struct(ring, ptr) guarded_ring_try_read((ring), sizeof(*(ptr)), (ptr))
|
|
||||||
internal B32 guarded_ring_write_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us);
|
|
||||||
internal B32 guarded_ring_read_or_wait(RingGuard *guard, U64 size, void *ptr, U64 endt_us);
|
|
||||||
#define guarded_ring_write_struct_or_wait(ring, ptr, endt_us) guarded_ring_write_or_wait((ring), sizeof(*(ptr)), (ptr), (endt_us))
|
|
||||||
#define guarded_ring_read_struct_or_wait(ring, ptr, endt_us) guarded_ring_read_or_wait((ring), sizeof(*(ptr)), (ptr), (endt_us))
|
|
||||||
#define guarded_ring_write_string_or_wait(ring, string, endt_us) guarded_ring_write_or_wait((ring), (string).size, (string).str, (endt_us))
|
|
||||||
|
|
||||||
#endif // BASE_RING_H
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_SHARED_MEMORY_H
|
|
||||||
#define BASE_SHARED_MEMORY_H
|
|
||||||
|
|
||||||
typedef struct SharedMemory SharedMemory;
|
|
||||||
struct SharedMemory
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Shared Memory
|
|
||||||
|
|
||||||
internal SharedMemory shared_memory_alloc(U64 size, String8 name);
|
|
||||||
internal SharedMemory shared_memory_open(String8 name);
|
|
||||||
internal void shared_memory_close(SharedMemory handle);
|
|
||||||
internal void * shared_memory_view_open(SharedMemory handle, Rng1U64 range);
|
|
||||||
internal void shared_memory_view_close(SharedMemory handle, void *ptr, Rng1U64 range);
|
|
||||||
|
|
||||||
#endif // BASE_SHARED_MEMORY_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,14 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_STRINGS_H
|
#ifndef BASE_STRING_H
|
||||||
#define BASE_STRINGS_H
|
#define BASE_STRING_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Third Party Includes
|
||||||
|
|
||||||
|
#define STB_SPRINTF_DECORATE(name) raddbg_##name
|
||||||
|
#include "third_party/stb/stb_sprintf.h"
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Types
|
//~ rjf: String Types
|
||||||
@@ -38,6 +44,13 @@ struct String8Node
|
|||||||
String8 string;
|
String8 string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct String8MetaNode String8MetaNode;
|
||||||
|
struct String8MetaNode
|
||||||
|
{
|
||||||
|
String8MetaNode *next;
|
||||||
|
String8Node *node;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct String8List String8List;
|
typedef struct String8List String8List;
|
||||||
struct String8List
|
struct String8List
|
||||||
{
|
{
|
||||||
@@ -50,9 +63,8 @@ struct String8List
|
|||||||
typedef struct String8Array String8Array;
|
typedef struct String8Array String8Array;
|
||||||
struct String8Array
|
struct String8Array
|
||||||
{
|
{
|
||||||
String8 *v;
|
String8 *strings;
|
||||||
U64 count;
|
U64 count;
|
||||||
U64 total_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -74,7 +86,6 @@ enum
|
|||||||
|
|
||||||
typedef enum PathStyle
|
typedef enum PathStyle
|
||||||
{
|
{
|
||||||
PathStyle_Null,
|
|
||||||
PathStyle_Relative,
|
PathStyle_Relative,
|
||||||
PathStyle_WindowsAbsolute,
|
PathStyle_WindowsAbsolute,
|
||||||
PathStyle_UnixAbsolute,
|
PathStyle_UnixAbsolute,
|
||||||
@@ -84,7 +95,7 @@ typedef enum PathStyle
|
|||||||
#elif OS_LINUX
|
#elif OS_LINUX
|
||||||
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
PathStyle_SystemAbsolute = PathStyle_UnixAbsolute
|
||||||
#else
|
#else
|
||||||
# error Absolute path style is undefined for this OS.
|
# error "absolute path style is undefined for this OS"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
PathStyle;
|
PathStyle;
|
||||||
@@ -146,9 +157,9 @@ internal B32 char_is_lower(U8 c);
|
|||||||
internal B32 char_is_alpha(U8 c);
|
internal B32 char_is_alpha(U8 c);
|
||||||
internal B32 char_is_slash(U8 c);
|
internal B32 char_is_slash(U8 c);
|
||||||
internal B32 char_is_digit(U8 c, U32 base);
|
internal B32 char_is_digit(U8 c, U32 base);
|
||||||
internal U8 lower_from_char(U8 c);
|
internal U8 char_to_lower(U8 c);
|
||||||
internal U8 upper_from_char(U8 c);
|
internal U8 char_to_upper(U8 c);
|
||||||
internal U8 correct_slash_from_char(U8 c);
|
internal U8 char_to_correct_slash(U8 c);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: C-String Measurement
|
//~ rjf: C-String Measurement
|
||||||
@@ -160,11 +171,8 @@ internal U64 cstring32_length(U32 *c);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Constructors
|
//~ rjf: String Constructors
|
||||||
|
|
||||||
#define s(S) str8_lit(S)
|
|
||||||
|
|
||||||
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
#define str8_lit(S) str8((U8*)(S), sizeof(S) - 1)
|
||||||
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
|
#define str8_lit_comp(S) {(U8*)(S), sizeof(S) - 1,}
|
||||||
#define str8_lit_cstr(S) str8((U8*)(S), sizeof(S))
|
|
||||||
#define str8_varg(S) (int)((S).size), ((S).str)
|
#define str8_varg(S) (int)((S).size), ((S).str)
|
||||||
|
|
||||||
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
#define str8_array(S,C) str8((U8*)(S), sizeof(*(S))*(C))
|
||||||
@@ -184,7 +192,6 @@ internal String8 str8_cstring(char *c);
|
|||||||
internal String16 str16_cstring(U16 *c);
|
internal String16 str16_cstring(U16 *c);
|
||||||
internal String32 str32_cstring(U32 *c);
|
internal String32 str32_cstring(U32 *c);
|
||||||
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
internal String8 str8_cstring_capped(void *cstr, void *cap);
|
||||||
internal String16 str16_cstring_capped(void *cstr, void *cap);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Stylization
|
//~ rjf: String Stylization
|
||||||
@@ -196,17 +203,9 @@ internal String8 backslashed_from_str8(Arena *arena, String8 string);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Matching
|
//~ rjf: String Matching
|
||||||
|
|
||||||
#define str8_match_lit(a_lit, b, flags) str8_match(str8_lit(a_lit), (b), (flags))
|
|
||||||
#define str8_match_cstr(a_cstr, b, flags) str8_match(str8_cstring(a_cstr), (b), (flags))
|
|
||||||
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
internal B32 str8_match(String8 a, String8 b, StringMatchFlags flags);
|
||||||
#define str8_matchi(a, b) str8_match(a, b, StringMatchFlag_CaseInsensitive)
|
|
||||||
internal B32 str8_match_wildcard(String8 string, String8 pattern, StringMatchFlags flags);
|
|
||||||
internal B32 str8_starts_with(String8 string, String8 expected_prefix);
|
|
||||||
internal B32 str8_starts_withi(String8 string, String8 expected_prefix);
|
|
||||||
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
internal U64 str8_find_needle(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
||||||
internal U64 str8_find_needle_reverse(String8 string, U64 start_pos, String8 needle, StringMatchFlags flags);
|
internal B32 str8_ends_with(String8 string, String8 end, StringMatchFlags flags);
|
||||||
internal B32 str8_is_before(String8 a, String8 b);
|
|
||||||
#define str8_ends_with(string, end, flags) str8_match(str8_postfix((string), (end).size), (end), (flags))
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Slicing
|
//~ rjf: String Slicing
|
||||||
@@ -216,23 +215,15 @@ internal String8 str8_prefix(String8 str, U64 size);
|
|||||||
internal String8 str8_skip(String8 str, U64 amt);
|
internal String8 str8_skip(String8 str, U64 amt);
|
||||||
internal String8 str8_postfix(String8 str, U64 size);
|
internal String8 str8_postfix(String8 str, U64 size);
|
||||||
internal String8 str8_chop(String8 str, U64 amt);
|
internal String8 str8_chop(String8 str, U64 amt);
|
||||||
internal String8 str8_chop_line(String8 *str);
|
|
||||||
internal String8 str8_skip_chop_whitespace(String8 string);
|
internal String8 str8_skip_chop_whitespace(String8 string);
|
||||||
internal String8 str8_skip_chop_slashes(String8 string);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Formatting & Copying
|
//~ rjf: String Formatting & Copying
|
||||||
|
|
||||||
internal String8 str8_cat(Arena *arena, String8 s1, String8 s2);
|
internal String8 push_str8_cat(Arena *arena, String8 s1, String8 s2);
|
||||||
internal String8 str8_copy(Arena *arena, String8 s);
|
internal String8 push_str8_copy(Arena *arena, String8 s);
|
||||||
internal String8 str8fv(Arena *arena, char *fmt, va_list args);
|
internal String8 push_str8fv(Arena *arena, char *fmt, va_list args);
|
||||||
internal String8 str8f(Arena *arena, char *fmt, ...);
|
internal String8 push_str8f(Arena *arena, char *fmt, ...);
|
||||||
// TODO(rjf): remove these once we're ready to convert all usages:
|
|
||||||
#define push_str8_cat(arena, s1, s2) str8_cat((arena), (s1), (s2))
|
|
||||||
#define push_str8_copy(arena, s) str8_copy((arena), (s))
|
|
||||||
#define push_str8fv(arena, fmt, args) str8fv((arena), (fmt), (args))
|
|
||||||
#define push_str8f(arena, ...) str8f((arena), __VA_ARGS__)
|
|
||||||
internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unnecessary - this is implied by `push_str8_copy`. need to remove.
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String <=> Integer Conversions
|
//~ rjf: String <=> Integer Conversions
|
||||||
@@ -240,19 +231,13 @@ internal String8 push_cstr(Arena *arena, String8 str); // TODO(rjf): this is unn
|
|||||||
//- rjf: string -> integer
|
//- rjf: string -> integer
|
||||||
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
internal S64 sign_from_str8(String8 string, String8 *string_tail);
|
||||||
internal B32 str8_is_integer(String8 string, U32 radix);
|
internal B32 str8_is_integer(String8 string, U32 radix);
|
||||||
internal B32 str8_is_integer_signed(String8 string, U32 radix);
|
|
||||||
internal U64 u64_from_str8(String8 string, U32 radix);
|
internal U64 u64_from_str8(String8 string, U32 radix);
|
||||||
internal S64 s64_from_str8(String8 string, U32 radix);
|
internal S64 s64_from_str8(String8 string, U32 radix);
|
||||||
internal U32 u32_from_str8(String8 string, U32 radix);
|
|
||||||
internal S32 s32_from_str8(String8 string, U32 radix);
|
|
||||||
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
|
||||||
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
|
||||||
|
|
||||||
//- rjf: integer -> string
|
//- rjf: integer -> string
|
||||||
internal String8 str8_from_memory_size(Arena *arena, U64 size);
|
internal String8 str8_from_memory_size(Arena *arena, U64 z);
|
||||||
internal String8 str8_from_count(Arena *arena, U64 count);
|
|
||||||
internal String8 str8_from_bits_u32(Arena *arena, U32 x);
|
|
||||||
internal String8 str8_from_bits_u64(Arena *arena, U64 x);
|
|
||||||
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||||
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
internal String8 str8_from_s64(Arena *arena, S64 s64, U32 radix, U8 min_digits, U8 digit_group_separator);
|
||||||
|
|
||||||
@@ -264,19 +249,17 @@ internal F64 f64_from_str8(String8 string);
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String List Construction Functions
|
//~ rjf: String List Construction Functions
|
||||||
|
|
||||||
internal String8Node *str8_list_push_node(String8List *list, String8Node *node);
|
internal String8Node* str8_list_push_node(String8List *list, String8Node *node);
|
||||||
internal String8Node *str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
internal String8Node* str8_list_push_node_set_string(String8List *list, String8Node *node, String8 string);
|
||||||
internal String8Node *str8_list_push_node_front(String8List *list, String8Node *node);
|
internal String8Node* str8_list_push_node_front(String8List *list, String8Node *node);
|
||||||
internal String8Node *str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
internal String8Node* str8_list_push_node_front_set_string(String8List *list, String8Node *node, String8 string);
|
||||||
internal String8Node *str8_list_push(Arena *arena, String8List *list, String8 string);
|
internal String8Node* str8_list_push(Arena *arena, String8List *list, String8 string);
|
||||||
internal String8Node *str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
internal String8Node* str8_list_push_front(Arena *arena, String8List *list, String8 string);
|
||||||
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
internal void str8_list_concat_in_place(String8List *list, String8List *to_push);
|
||||||
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
internal String8Node* str8_list_push_aligner(Arena *arena, String8List *list, U64 min, U64 align);
|
||||||
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
internal String8Node* str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);
|
||||||
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
internal String8Node* str8_list_push_frontf(Arena *arena, String8List *list, char *fmt, ...);
|
||||||
internal String8Node* str8_list_pop_front(String8List *list);
|
|
||||||
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
internal String8List str8_list_copy(Arena *arena, String8List *list);
|
||||||
internal String8List str8_list_substr(Arena *arena, String8List list, Rng1U64 range);
|
|
||||||
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
#define str8_list_first(list) ((list)->first ? (list)->first->string : str8_zero())
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
@@ -284,46 +267,19 @@ internal String8List str8_list_substr(Arena *arena, String8List list, Rng1U64 r
|
|||||||
|
|
||||||
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
internal String8List str8_split(Arena *arena, String8 string, U8 *split_chars, U64 split_char_count, StringSplitFlags flags);
|
||||||
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
internal String8List str8_split_by_string_chars(Arena *arena, String8 string, String8 split_chars, StringSplitFlags flags);
|
||||||
|
internal String8List str8_list_split_by_string_chars(Arena *arena, String8List list, String8 split_chars, StringSplitFlags flags);
|
||||||
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
internal String8 str8_list_join(Arena *arena, String8List *list, StringJoin *optional_params);
|
||||||
|
internal void str8_list_from_flags(Arena *arena, String8List *list, U32 flags, String8 *flag_string_table, U32 flag_string_count);
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Data Stringification Helpers
|
|
||||||
|
|
||||||
internal String8List numeric_str8_list_from_data(Arena *arena, U32 radix, String8 data, U64 stride);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf; String Arrays
|
//~ rjf; String Arrays
|
||||||
|
|
||||||
internal String8Array str8_array_zero(void);
|
|
||||||
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
internal String8Array str8_array_from_list(Arena *arena, String8List *list);
|
||||||
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
internal String8Array str8_array_reserve(Arena *arena, U64 count);
|
||||||
internal String8Array str8_array_copy(Arena *arena, String8Array array);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: String <-> Version Helpers
|
|
||||||
|
|
||||||
internal U64 version_from_str8(String8 string);
|
|
||||||
internal String8 str8_from_version(Arena *arena, U64 version);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String Path Helpers
|
//~ rjf: String Path Helpers
|
||||||
|
|
||||||
global read_only struct
|
|
||||||
{
|
|
||||||
String8 string;
|
|
||||||
PathStyle path_style;
|
|
||||||
}
|
|
||||||
g_path_style_map[] =
|
|
||||||
{
|
|
||||||
{ str8_lit_comp(""), PathStyle_Null },
|
|
||||||
{ str8_lit_comp("relative"), PathStyle_Relative },
|
|
||||||
{ str8_lit_comp("windows"), PathStyle_WindowsAbsolute },
|
|
||||||
{ str8_lit_comp("unix"), PathStyle_UnixAbsolute },
|
|
||||||
{ str8_lit_comp("system"), PathStyle_SystemAbsolute },
|
|
||||||
};
|
|
||||||
|
|
||||||
internal String8 program_ext_postfix_from_os(OperatingSystem os, B32 require_ext);
|
|
||||||
|
|
||||||
internal String8 str8_chop_last_slash(String8 string);
|
internal String8 str8_chop_last_slash(String8 string);
|
||||||
internal String8 str8_skip_last_slash(String8 string);
|
internal String8 str8_skip_last_slash(String8 string);
|
||||||
internal String8 str8_chop_last_dot(String8 string);
|
internal String8 str8_chop_last_dot(String8 string);
|
||||||
@@ -336,29 +292,6 @@ internal String8 str8_path_list_join_by_style(Arena *arena, String8List *pat
|
|||||||
|
|
||||||
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
internal String8TxtPtPair str8_txt_pt_pair_from_string(String8 string);
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Relative <-> Absolute Path
|
|
||||||
|
|
||||||
internal String8 path_relative_dst_from_absolute_dst_src(Arena *arena, String8 dst, String8 src);
|
|
||||||
internal String8 path_absolute_dst_from_relative_dst_src(Arena *arena, String8 dst, String8 src);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Path Normalization
|
|
||||||
|
|
||||||
internal String8List path_normalized_list_from_string(Arena *arena, String8 path, PathStyle *style_out);
|
|
||||||
internal String8 path_normalized_from_string(Arena *arena, String8 path);
|
|
||||||
internal B32 path_match_normalized(String8 left, String8 right);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Misc. Path Helpers
|
|
||||||
|
|
||||||
internal PathStyle path_style_from_string(String8 string);
|
|
||||||
internal String8 string_from_path_style(PathStyle style);
|
|
||||||
internal String8 path_separator_string_from_style(PathStyle style);
|
|
||||||
internal StringMatchFlags path_match_flags_from_os(OperatingSystem os);
|
|
||||||
internal String8 path_convert_slashes(Arena *arena, String8 path, PathStyle path_style);
|
|
||||||
internal String8 path_replace_file_extension(Arena *arena, String8 file_name, String8 ext);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
//~ rjf: UTF-8 & UTF-16 Decoding/Encoding
|
||||||
|
|
||||||
@@ -366,6 +299,7 @@ internal UnicodeDecode utf8_decode(U8 *str, U64 max);
|
|||||||
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
internal UnicodeDecode utf16_decode(U16 *str, U64 max);
|
||||||
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
internal U32 utf8_encode(U8 *str, U32 codepoint);
|
||||||
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
internal U32 utf16_encode(U16 *str, U32 codepoint);
|
||||||
|
internal U32 utf8_from_utf32_single(U8 *buffer, U32 character);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Unicode String Conversions
|
//~ rjf: Unicode String Conversions
|
||||||
@@ -376,42 +310,22 @@ internal String8 str8_from_32(Arena *arena, String32 in);
|
|||||||
internal String32 str32_from_8(Arena *arena, String8 in);
|
internal String32 str32_from_8(Arena *arena, String8 in);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Basic Types & Space Enum <-> String Conversions
|
//~ rjf: Basic Types & Space Enum -> String Conversions
|
||||||
|
|
||||||
internal OperatingSystem operating_system_from_string(String8 string);
|
|
||||||
internal String8 string_from_dimension(Dimension dimension);
|
internal String8 string_from_dimension(Dimension dimension);
|
||||||
internal String8 string_from_side(Side side);
|
internal String8 string_from_side(Side side);
|
||||||
internal String8 string_from_operating_system(OperatingSystem os);
|
internal String8 string_from_operating_system(OperatingSystem os);
|
||||||
internal String8 string_from_arch(Arch arch);
|
internal String8 string_from_architecture(Architecture arch);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Time Types -> String
|
||||||
|
|
||||||
internal String8 string_from_week_day(WeekDay week_day);
|
internal String8 string_from_week_day(WeekDay week_day);
|
||||||
internal String8 string_from_month(Month month);
|
internal String8 string_from_month(Month month);
|
||||||
internal String8 string_from_date_time(Arena *arena, DateTime *date_time);
|
internal String8 push_date_time_string(Arena *arena, DateTime *date_time);
|
||||||
internal String8 string_from_date_time__file_name(Arena *arena, DateTime *date_time);
|
internal String8 push_file_name_date_time_string(Arena *arena, DateTime *date_time);
|
||||||
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
internal String8 string_from_elapsed_time(Arena *arena, DateTime dt);
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: String <-> Globally Unique IDs
|
|
||||||
|
|
||||||
internal String8 string_from_guid(Arena *arena, Guid guid);
|
|
||||||
internal B32 try_guid_from_string(String8 string, Guid *guid_out);
|
|
||||||
internal Guid guid_from_string(String8 string);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic Text Indentation
|
|
||||||
|
|
||||||
internal String8 indented_from_string(Arena *arena, String8 string);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Text Escaping
|
|
||||||
|
|
||||||
internal String8 escaped_from_raw_str8(Arena *arena, String8 string);
|
|
||||||
internal String8 raw_from_escaped_str8(Arena *arena, String8 string);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Text Wrapping
|
|
||||||
|
|
||||||
internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: String <-> Color
|
//~ rjf: String <-> Color
|
||||||
|
|
||||||
@@ -434,12 +348,12 @@ internal U64 str8_serial_push_align(Arena *arena, String8List *srl, U64 alig
|
|||||||
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
internal void * str8_serial_push_size(Arena *arena, String8List *srl, U64 size);
|
||||||
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
internal void * str8_serial_push_data(Arena *arena, String8List *srl, void *data, U64 size);
|
||||||
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
internal void str8_serial_push_data_list(Arena *arena, String8List *srl, String8Node *first);
|
||||||
internal void * str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
internal void str8_serial_push_u64(Arena *arena, String8List *srl, U64 x);
|
||||||
internal void * str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
|
internal void str8_serial_push_u32(Arena *arena, String8List *srl, U32 x);
|
||||||
internal void * str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
internal void str8_serial_push_u16(Arena *arena, String8List *srl, U16 x);
|
||||||
internal void * str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
internal void str8_serial_push_u8(Arena *arena, String8List *srl, U8 x);
|
||||||
internal void * str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
internal void str8_serial_push_cstr(Arena *arena, String8List *srl, String8 str);
|
||||||
internal void * str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
internal void str8_serial_push_string(Arena *arena, String8List *srl, String8 str);
|
||||||
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
#define str8_serial_push_array(arena, srl, ptr, count) str8_serial_push_data(arena, srl, ptr, sizeof(*(ptr)) * (count))
|
||||||
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
|
#define str8_serial_push_struct(arena, srl, ptr) str8_serial_push_array(arena, srl, ptr, 1)
|
||||||
|
|
||||||
@@ -448,33 +362,10 @@ internal void * str8_serial_push_string(Arena *arena, String8List *srl, String8
|
|||||||
|
|
||||||
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
internal U64 str8_deserial_read(String8 string, U64 off, void *read_dst, U64 read_size, U64 granularity);
|
||||||
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
internal U64 str8_deserial_find_first_match(String8 string, U64 off, U16 scan_val);
|
||||||
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);
|
internal void * str8_deserial_get_raw_ptr(String8 string, U64 off, U64 size);internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
||||||
internal U64 str8_deserial_read_cstr(String8 string, U64 off, String8 *cstr_out);
|
|
||||||
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
internal U64 str8_deserial_read_windows_utf16_string16(String8 string, U64 off, String16 *str_out);
|
||||||
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, String8 *block_out);
|
||||||
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
#define str8_deserial_read_array(string, off, ptr, count) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr))*(count), sizeof(*(ptr)))
|
||||||
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read_array(string, off, ptr, 1)
|
#define str8_deserial_read_struct(string, off, ptr) str8_deserial_read((string), (off), (ptr), sizeof(*(ptr)), sizeof(*(ptr)))
|
||||||
internal U64 str8_deserial_read_uleb128(String8 string, U64 off, U64 *value_out);
|
|
||||||
internal U64 str8_deserial_read_sleb128(String8 string, U64 off, S64 *value_out);
|
|
||||||
|
|
||||||
////////////////////////////////
|
#endif // BASE_STRING_H
|
||||||
//~ string buffer
|
|
||||||
|
|
||||||
internal B32 str8_buffer_skip(String8Node *buf, U64 *pos, U64 skip);
|
|
||||||
internal U64 str8_buffer_read(String8Node *buf, U64 *pos, U64 read_size, void *out);
|
|
||||||
internal U64 str8_buffer_peek(String8Node *buf, U64 *pos, U64 read_size, void *out);
|
|
||||||
internal U64 str8_buffer_write(String8Node *buf, U64 *pos, String8 data);
|
|
||||||
internal U64 str8_buffer_write_u16(String8Node *buf, U64 *pos, U16 v);
|
|
||||||
internal U64 str8_buffer_write_u32(String8Node *buf, U64 *pos, U32 v);
|
|
||||||
internal U64 str8_buffer_write_zeroes(String8Node *buf, U64 *pos, U64 size);
|
|
||||||
internal U64 str8_buffer_write_string_list(String8Node *buf, U64 *pos, String8List list);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Basic String Hashes
|
|
||||||
|
|
||||||
internal U64 u64_hash_from_seed_str8(U64 seed, String8 string);
|
|
||||||
internal U64 u64_hash_from_str8(String8 string);
|
|
||||||
internal U128 u128_hash_from_seed_str8(U64 seed, String8 string);
|
|
||||||
internal U128 u128_hash_from_str8(String8 string);
|
|
||||||
|
|
||||||
#endif // BASE_STRINGS_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,2 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_SYSTEM_H
|
|
||||||
#define BASE_SYSTEM_H
|
|
||||||
|
|
||||||
typedef struct SystemInfo SystemInfo;
|
|
||||||
struct SystemInfo
|
|
||||||
{
|
|
||||||
U32 logical_processor_count;
|
|
||||||
U64 page_size;
|
|
||||||
U64 large_page_size;
|
|
||||||
U64 allocation_granularity;
|
|
||||||
String8 machine_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl System Info
|
|
||||||
|
|
||||||
internal SystemInfo *get_system_info(void);
|
|
||||||
|
|
||||||
#endif // BASE_SYSTEM_H
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#if BUILD_TESTS
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
test_build_exe_path(Arena *arena, String8 name)
|
|
||||||
{
|
|
||||||
String8 folder = get_process_info()->binary_path;
|
|
||||||
String8 path = str8f(arena, "%S/%S%S", folder, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 0));
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
test_input_path(Arena *arena, TestCtx *ctx, String8 name)
|
|
||||||
{
|
|
||||||
String8 path = str8f(arena, "%S/%S", ctx->input_data_path, name);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
test_input_exe_path(Arena *arena, TestCtx *ctx, String8 name)
|
|
||||||
{
|
|
||||||
String8 path = str8f(arena, "%S/%S%S", ctx->input_data_path, name, program_ext_postfix_from_os(OperatingSystem_CURRENT, 1));
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
test_exemplar_path(Arena *arena, TestCtx *ctx, String8 name)
|
|
||||||
{
|
|
||||||
String8 path = str8f(arena, "%S/%S", ctx->exemplars_path, name);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
base_register_test(char *func_name_cstr, TestFunctionType *fn, char *file_path_cstr, int line, int skip)
|
|
||||||
{
|
|
||||||
String8 file_path = str8_cstring(file_path_cstr);
|
|
||||||
U64 src_min = str8_find_needle(file_path, 0, s("src/"), StringMatchFlag_SlashInsensitive);
|
|
||||||
U64 src_max = src_min + str8_lit("src/").size;
|
|
||||||
U64 layer_slash_max = str8_find_needle(file_path, src_max, s("/"), StringMatchFlag_SlashInsensitive);
|
|
||||||
|
|
||||||
TestInfo *t = &test_infos[test_infos_count++];
|
|
||||||
t->layer = str8_substr(file_path, r1u64(src_max, layer_slash_max));
|
|
||||||
t->label = str8_cstring(func_name_cstr);
|
|
||||||
t->decl_line = line;
|
|
||||||
t->skip = skip;
|
|
||||||
t->test_fn = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_TEST_H
|
|
||||||
#define BASE_TEST_H
|
|
||||||
|
|
||||||
typedef enum TestStatus
|
|
||||||
{
|
|
||||||
TestStatus_Fail,
|
|
||||||
TestStatus_Crash,
|
|
||||||
TestStatus_Pass,
|
|
||||||
TestStatus_Skip,
|
|
||||||
TestStatus_COUNT
|
|
||||||
}
|
|
||||||
TestStatus;
|
|
||||||
|
|
||||||
typedef struct TestResult TestResult;
|
|
||||||
struct TestResult
|
|
||||||
{
|
|
||||||
TestStatus status;
|
|
||||||
char *fail_file;
|
|
||||||
int fail_line;
|
|
||||||
char *fail_cond;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct TestCtx TestCtx;
|
|
||||||
struct TestCtx
|
|
||||||
{
|
|
||||||
CmdLine *cmdline;
|
|
||||||
String8 exemplars_path;
|
|
||||||
String8 artifacts_path;
|
|
||||||
String8 input_data_path;
|
|
||||||
TestResult *result_out;
|
|
||||||
String8List *test_out;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define TEST_FUNCTION_SIG(name) void name(Arena *arena, TestCtx *ctx)
|
|
||||||
#define TEST_FUNCTION_DEF(name) TEST_FUNCTION_SIG(test__##name)
|
|
||||||
typedef TEST_FUNCTION_SIG(TestFunctionType);
|
|
||||||
|
|
||||||
typedef struct TestInfo TestInfo;
|
|
||||||
struct TestInfo
|
|
||||||
{
|
|
||||||
String8 layer;
|
|
||||||
String8 label;
|
|
||||||
S64 decl_line;
|
|
||||||
B32 skip;
|
|
||||||
TestFunctionType *test_fn;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if BUILD_TESTS
|
|
||||||
|
|
||||||
// alloc storage for the tests
|
|
||||||
global U16 test_infos_count = 0;
|
|
||||||
global TestInfo test_infos[0xffff] = {0};
|
|
||||||
|
|
||||||
internal String8 test_build_exe_path(Arena *arena, String8 name);
|
|
||||||
internal String8 test_input_path(Arena *arena, TestCtx *ctx, String8 name);
|
|
||||||
internal String8 test_input_exe_path(Arena *arena, TestCtx *ctx, String8 name);
|
|
||||||
internal String8 test_exemplar_path(Arena *arena, TestCtx *ctx, String8 name);
|
|
||||||
internal void base_register_test(char *func_name, TestFunctionType *fn, char *file_path, int line, int skip);
|
|
||||||
|
|
||||||
#define AddTest(name, file_path, line, skip_, ...) \
|
|
||||||
TEST_FUNCTION_DEF(name); \
|
|
||||||
__VA_ARGS__ void add_test__##name(void) { base_register_test(Stringify(name), test__##name, file_path, line, skip_); }
|
|
||||||
|
|
||||||
# if COMPILER_MSVC
|
|
||||||
# pragma section(".CRT$XCU", read)
|
|
||||||
# define DeclareTest(name, skip) \
|
|
||||||
/* register test */ AddTest(name, __FILE__, __LINE__, (skip)) \
|
|
||||||
/* alloc function pointer */ __declspec(allocate(".CRT$XCU")) void (*add_test_ptr__##name)(void) = add_test__##name; \
|
|
||||||
/* do not GC test caller */ __pragma(comment(linker, "/include:" Stringify(add_test_ptr__##name)))
|
|
||||||
# elif COMPILER_GCC || COMPILER_CLANG
|
|
||||||
// clang and gcc allocate memory for the function pointer automatically
|
|
||||||
# define DeclareTest(name, skip) AddTest(name, __FILE__, __LINE__, (skip), __attribute__((constructor)))
|
|
||||||
# else
|
|
||||||
# error DeclareTest not defined for this compiler.
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define DeclareTest(name, skip)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define Test(name) DeclareTest(name, 0) TEST_FUNCTION_DEF(name)
|
|
||||||
#define SkippedTest(name) DeclareTest(name, 1) TEST_FUNCTION_DEF(name)
|
|
||||||
|
|
||||||
#define TestCheck(c) do { if (!(c)) { \
|
|
||||||
/* record failed check */ ctx->result_out[0] = (TestResult){ .fail_file = __FILE__, .fail_line = __LINE__, .fail_cond = Stringify(c) }; \
|
|
||||||
/* under debugger? -> trap */ if(debugger_is_attached()) { Trap(); } \
|
|
||||||
/* exit test */ return; \
|
|
||||||
} } while(0)
|
|
||||||
|
|
||||||
#define TestSkip() do { \
|
|
||||||
ctx->result_out[0] = (TestResult){ .status = TestStatus_Skip }; \
|
|
||||||
return; \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
// test log
|
|
||||||
#define test_out(string) str8_list_push(arena, ctx->test_out, (string))
|
|
||||||
#define test_outf(...) str8_list_pushf(arena, ctx->test_out, __VA_ARGS__)
|
|
||||||
|
|
||||||
#endif // BASE_TEST_H
|
|
||||||
+31
-187
@@ -1,234 +1,78 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Globals
|
// NOTE(allen): Thread Context Functions
|
||||||
|
|
||||||
C_LINKAGE thread_static TCTX *tctx_thread_local;
|
C_LINKAGE thread_static TCTX* tctx_thread_local;
|
||||||
#if !BUILD_SUPPLEMENTARY_UNIT
|
#if !SUPPLEMENT_UNIT
|
||||||
C_LINKAGE thread_static TCTX *tctx_thread_local = 0;
|
C_LINKAGE thread_static TCTX* tctx_thread_local = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Context Functions
|
|
||||||
|
|
||||||
//- rjf: thread-context allocation & selection
|
|
||||||
|
|
||||||
internal TCTX *
|
|
||||||
tctx_alloc(void)
|
|
||||||
{
|
|
||||||
#if PROFILE_TELEMETRY
|
|
||||||
thread_static static char name[2][1024];
|
|
||||||
raddbg_snprintf(name[0], sizeof(name[0]), "Scratch/0[TID:%u]", tid());
|
|
||||||
raddbg_snprintf(name[1], sizeof(name[1]), "Scratch/1[TID:%u]", tid());
|
|
||||||
Arena *arena_0 = arena_alloc(.name = name[0]);
|
|
||||||
Arena *arena_1 = arena_alloc(.name = name[1]);
|
|
||||||
#else
|
|
||||||
Arena *arena_0 = arena_alloc();
|
|
||||||
Arena *arena_1 = arena_alloc();
|
|
||||||
#endif
|
|
||||||
TCTX *tctx = push_array(arena_0, TCTX, 1);
|
|
||||||
tctx->arenas[0] = arena_0;
|
|
||||||
tctx->arenas[1] = arena_1;
|
|
||||||
tctx->lane_ctx.lane_count = 1;
|
|
||||||
return tctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
tctx_release(TCTX *tctx)
|
tctx_init_and_equip(TCTX *tctx){
|
||||||
{
|
MemoryZeroStruct(tctx);
|
||||||
arena_release(tctx->arenas[1]);
|
Arena **arena_ptr = tctx->arenas;
|
||||||
arena_release(tctx->arenas[0]);
|
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||||
}
|
*arena_ptr = arena_alloc();
|
||||||
|
}
|
||||||
internal void
|
|
||||||
tctx_select(TCTX *tctx)
|
|
||||||
{
|
|
||||||
tctx_thread_local = tctx;
|
tctx_thread_local = tctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal TCTX *
|
internal TCTX*
|
||||||
tctx_selected(void)
|
tctx_get_equipped(void){
|
||||||
{
|
return(tctx_thread_local);
|
||||||
return tctx_thread_local;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: scratch arenas
|
internal Arena*
|
||||||
|
tctx_get_scratch(Arena **conflicts, U64 count){
|
||||||
|
TCTX *tctx = tctx_get_equipped();
|
||||||
|
|
||||||
internal Arena *
|
|
||||||
tctx_get_scratch(Arena **conflicts, U64 count)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
Arena *result = 0;
|
Arena *result = 0;
|
||||||
Arena **arena_ptr = tctx->arenas;
|
Arena **arena_ptr = tctx->arenas;
|
||||||
for(U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1)
|
for (U64 i = 0; i < ArrayCount(tctx->arenas); i += 1, arena_ptr += 1){
|
||||||
{
|
|
||||||
Arena **conflict_ptr = conflicts;
|
Arena **conflict_ptr = conflicts;
|
||||||
B32 has_conflict = 0;
|
B32 has_conflict = 0;
|
||||||
for(U64 j = 0; j < count; j += 1, conflict_ptr += 1)
|
for (U64 j = 0; j < count; j += 1, conflict_ptr += 1){
|
||||||
{
|
if (*arena_ptr == *conflict_ptr){
|
||||||
if(*arena_ptr == *conflict_ptr)
|
|
||||||
{
|
|
||||||
has_conflict = 1;
|
has_conflict = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!has_conflict)
|
if (!has_conflict){
|
||||||
{
|
|
||||||
result = *arena_ptr;
|
result = *arena_ptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: lane metadata
|
return(result);
|
||||||
|
|
||||||
internal LaneCtx
|
|
||||||
tctx_set_lane_ctx(LaneCtx lane_ctx)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
LaneCtx restore = tctx->lane_ctx;
|
|
||||||
tctx->lane_ctx = lane_ctx;
|
|
||||||
return restore;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx)
|
tctx_set_thread_name(String8 string){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
ProfBeginFunction();
|
|
||||||
ProfColor(0x00000ff);
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> copy to broadcast memory on source lane
|
|
||||||
U64 broadcast_size_clamped = ClampTop(broadcast_size, sizeof(tctx->lane_ctx.broadcast_memory[0]));
|
|
||||||
if(broadcast_ptr != 0 && lane_idx() == broadcast_src_lane_idx)
|
|
||||||
{
|
|
||||||
MemoryCopy(tctx->lane_ctx.broadcast_memory, broadcast_ptr, broadcast_size_clamped);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: all cases: barrier
|
|
||||||
barrier_wait(tctx->lane_ctx.barrier);
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> copy from broadcast memory on destination lanes
|
|
||||||
if(broadcast_ptr != 0 && lane_idx() != broadcast_src_lane_idx)
|
|
||||||
{
|
|
||||||
MemoryCopy(broadcast_ptr, tctx->lane_ctx.broadcast_memory, broadcast_size_clamped);
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: doing broadcast -> barrier on all lanes
|
|
||||||
if(broadcast_ptr != 0)
|
|
||||||
{
|
|
||||||
barrier_wait(tctx->lane_ctx.barrier);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: thread names
|
|
||||||
|
|
||||||
internal void
|
|
||||||
tctx_set_thread_name(String8 string)
|
|
||||||
{
|
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
U64 size = ClampTop(string.size, sizeof(tctx->thread_name));
|
||||||
MemoryCopy(tctx->thread_name, string.str, size);
|
MemoryCopy(tctx->thread_name, string.str, size);
|
||||||
tctx->thread_name_size = size;
|
tctx->thread_name_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal String8
|
internal String8
|
||||||
tctx_get_thread_name(void)
|
tctx_get_thread_name(void){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
String8 result = str8(tctx->thread_name, tctx->thread_name_size);
|
||||||
return result;
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
//- rjf: thread source-locations
|
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
tctx_write_srcloc(char *file_name, U64 line_number)
|
tctx_write_srcloc(char *file_name, U64 line_number){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
tctx->file_name = file_name;
|
tctx->file_name = file_name;
|
||||||
tctx->line_number = line_number;
|
tctx->line_number = line_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
tctx_read_srcloc(char **file_name, U64 *line_number)
|
tctx_read_srcloc(char **file_name, U64 *line_number){
|
||||||
{
|
TCTX *tctx = tctx_get_equipped();
|
||||||
TCTX *tctx = tctx_selected();
|
|
||||||
*file_name = tctx->file_name;
|
*file_name = tctx->file_name;
|
||||||
*line_number = tctx->line_number;
|
*line_number = tctx->line_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Touch Scope Functions
|
|
||||||
|
|
||||||
internal Access *
|
|
||||||
access_open(void)
|
|
||||||
{
|
|
||||||
if(tctx_thread_local->access_arena == 0)
|
|
||||||
{
|
|
||||||
tctx_thread_local->access_arena = arena_alloc();
|
|
||||||
}
|
|
||||||
Access *access = tctx_thread_local->free_access;
|
|
||||||
if(access != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(tctx_thread_local->free_access);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
access = push_array_no_zero(tctx_thread_local->access_arena, Access, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(access);
|
|
||||||
return access;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
access_close(Access *access)
|
|
||||||
{
|
|
||||||
for(Touch *touch = access->top_touch, *next = 0; touch != 0; touch = next)
|
|
||||||
{
|
|
||||||
next = touch->next;
|
|
||||||
ins_atomic_u64_dec_eval(&touch->pt->access_refcount);
|
|
||||||
if(touch->cv.u64[0] != 0) { cond_var_broadcast(touch->cv); }
|
|
||||||
SLLStackPush(tctx_thread_local->free_touch, touch);
|
|
||||||
}
|
|
||||||
SLLStackPush(tctx_thread_local->free_access, access);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
access_touch(Access *access, AccessPt *pt, CondVar cv)
|
|
||||||
{
|
|
||||||
ins_atomic_u64_inc_eval(&pt->access_refcount);
|
|
||||||
ins_atomic_u64_eval_assign(&pt->last_time_touched_us, now_time_us());
|
|
||||||
ins_atomic_u64_eval_assign(&pt->last_update_idx_touched, update_tick_idx());
|
|
||||||
Touch *touch = tctx_thread_local->free_touch;
|
|
||||||
if(touch != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(tctx_thread_local->free_touch);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
touch = push_array_no_zero(tctx_thread_local->access_arena, Touch, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(touch);
|
|
||||||
SLLStackPush(access->top_touch, touch);
|
|
||||||
touch->cv = cv;
|
|
||||||
touch->pt = pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: access points
|
|
||||||
|
|
||||||
internal B32
|
|
||||||
access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params)
|
|
||||||
{
|
|
||||||
U64 access_refcount = ins_atomic_u64_eval(&pt->access_refcount);
|
|
||||||
U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us);
|
|
||||||
U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched);
|
|
||||||
B32 result = (access_refcount == 0 &&
|
|
||||||
last_time_touched_us + params->time <= now_time_us() &&
|
|
||||||
last_update_idx_touched + params->update_idxs <= update_tick_idx());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,132 +1,40 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
#ifndef BASE_THREAD_CONTEXT_H
|
#ifndef BASE_THREAD_CONTEXT_H
|
||||||
#define BASE_THREAD_CONTEXT_H
|
#define BASE_THREAD_CONTEXT_H
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Lane Context
|
// NOTE(allen): Thread Context
|
||||||
|
|
||||||
typedef struct LaneCtx LaneCtx;
|
|
||||||
struct LaneCtx
|
|
||||||
{
|
|
||||||
U64 lane_idx;
|
|
||||||
U64 lane_count;
|
|
||||||
Barrier barrier;
|
|
||||||
U64 *broadcast_memory;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Access Scopes
|
|
||||||
|
|
||||||
typedef struct AccessPt AccessPt;
|
|
||||||
struct AccessPt
|
|
||||||
{
|
|
||||||
U64 access_refcount;
|
|
||||||
U64 last_time_touched_us;
|
|
||||||
U64 last_update_idx_touched;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AccessPtExpireParams AccessPtExpireParams;
|
|
||||||
struct AccessPtExpireParams
|
|
||||||
{
|
|
||||||
U64 time;
|
|
||||||
U64 update_idxs;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Touch Touch;
|
|
||||||
struct Touch
|
|
||||||
{
|
|
||||||
Touch *next;
|
|
||||||
AccessPt *pt;
|
|
||||||
CondVar cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Access Access;
|
|
||||||
struct Access
|
|
||||||
{
|
|
||||||
Access *next;
|
|
||||||
Touch *top_touch;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Base Per-Thread State Bundle
|
|
||||||
|
|
||||||
typedef struct TCTX TCTX;
|
typedef struct TCTX TCTX;
|
||||||
struct TCTX
|
struct TCTX
|
||||||
{
|
{
|
||||||
// rjf: scratch arenas
|
|
||||||
Arena *arenas[2];
|
Arena *arenas[2];
|
||||||
|
|
||||||
// rjf: thread name
|
|
||||||
U8 thread_name[32];
|
U8 thread_name[32];
|
||||||
U64 thread_name_size;
|
U64 thread_name_size;
|
||||||
|
|
||||||
// rjf: lane context
|
|
||||||
LaneCtx lane_ctx;
|
|
||||||
|
|
||||||
// rjf: source location info
|
|
||||||
char *file_name;
|
char *file_name;
|
||||||
U64 line_number;
|
U64 line_number;
|
||||||
|
|
||||||
// rjf: accesses
|
|
||||||
Arena *access_arena;
|
|
||||||
Access *free_access;
|
|
||||||
Touch *free_touch;
|
|
||||||
|
|
||||||
// rjf: progress
|
|
||||||
U64 *progress_counter_ptr;
|
|
||||||
U64 *progress_target_ptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
//~ rjf: Thread Context Functions
|
// NOTE(allen): Thread Context Functions
|
||||||
|
|
||||||
//- rjf: thread-context allocation & selection
|
internal void tctx_init_and_equip(TCTX *tctx);
|
||||||
internal TCTX *tctx_alloc(void);
|
internal TCTX* tctx_get_equipped(void);
|
||||||
internal void tctx_release(TCTX *tctx);
|
|
||||||
internal void tctx_select(TCTX *tctx);
|
|
||||||
internal TCTX *tctx_selected(void);
|
|
||||||
|
|
||||||
//- rjf: scratch arenas
|
internal Arena* tctx_get_scratch(Arena **conflicts, U64 count);
|
||||||
internal Arena *tctx_get_scratch(Arena **conflicts, U64 count);
|
|
||||||
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
|
||||||
#define scratch_end(scratch) temp_end(scratch)
|
|
||||||
|
|
||||||
//- rjf: lane metadata
|
|
||||||
internal LaneCtx tctx_set_lane_ctx(LaneCtx lane_ctx);
|
|
||||||
internal void tctx_lane_barrier_wait(void *broadcast_ptr, U64 broadcast_size, U64 broadcast_src_lane_idx);
|
|
||||||
#define lane_idx() (tctx_selected()->lane_ctx.lane_idx)
|
|
||||||
#define lane_count() (tctx_selected()->lane_ctx.lane_count)
|
|
||||||
#define lane_from_task_idx(idx) ((idx)%lane_count())
|
|
||||||
#define lane_ctx(ctx) tctx_set_lane_ctx((ctx))
|
|
||||||
#define lane_sync() tctx_lane_barrier_wait(0, 0, 0)
|
|
||||||
#define lane_sync_u64(ptr, src_lane_idx) tctx_lane_barrier_wait((ptr), sizeof(*(ptr)), (src_lane_idx))
|
|
||||||
#define lane_range(count) m_range_from_n_idx_m_count(lane_idx(), lane_count(), (count))
|
|
||||||
|
|
||||||
//- rjf: thread names
|
|
||||||
internal void tctx_set_thread_name(String8 name);
|
internal void tctx_set_thread_name(String8 name);
|
||||||
internal String8 tctx_get_thread_name(void);
|
internal String8 tctx_get_thread_name(void);
|
||||||
|
|
||||||
//- rjf: thread source-locations
|
|
||||||
internal void tctx_write_srcloc(char *file_name, U64 line_number);
|
internal void tctx_write_srcloc(char *file_name, U64 line_number);
|
||||||
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
|
internal void tctx_read_srcloc(char **file_name, U64 *line_number);
|
||||||
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
|
#define tctx_write_this_srcloc() tctx_write_srcloc(__FILE__, __LINE__)
|
||||||
|
|
||||||
//- rjf: access scopes
|
#define scratch_begin(conflicts, count) temp_begin(tctx_get_scratch((conflicts), (count)))
|
||||||
internal Access *access_open(void);
|
#define scratch_end(scratch) temp_end(scratch)
|
||||||
internal void access_close(Access *access);
|
|
||||||
internal void access_touch(Access *access, AccessPt *pt, CondVar cv);
|
|
||||||
|
|
||||||
//- rjf: access points
|
#endif //BASE_THREAD_CONTEXT_H
|
||||||
internal B32 access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params);
|
|
||||||
#define access_pt_is_expired(pt, ...) access_pt_is_expired_((pt), &(AccessPtExpireParams){.time = 2000000, .update_idxs = 2, __VA_ARGS__})
|
|
||||||
|
|
||||||
//- rjf: progress counters
|
|
||||||
#define set_progress_ptr(ptr) (tctx_selected()->progress_counter_ptr = (ptr))
|
|
||||||
#define set_progress_target_ptr(ptr) (tctx_selected()->progress_target_ptr = (ptr))
|
|
||||||
#define set_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
|
|
||||||
#define add_progress(val) (tctx_selected()->progress_counter_ptr ? ins_atomic_u64_add_eval(tctx_selected()->progress_counter_ptr, (val)) : (void)0)
|
|
||||||
#define set_progress_target(val) (tctx_selected()->progress_target_ptr ? ins_atomic_u64_eval_assign(tctx_selected()->progress_target_ptr, (val)) : (void)0)
|
|
||||||
|
|
||||||
#endif // BASE_THREAD_CONTEXT_H
|
|
||||||
|
|||||||
@@ -1,204 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Table Stripe Functions
|
|
||||||
|
|
||||||
internal StripeArray
|
|
||||||
stripe_array_alloc(Arena *arena)
|
|
||||||
{
|
|
||||||
StripeArray array = {0};
|
|
||||||
array.count = get_system_info()->logical_processor_count;
|
|
||||||
array.v = push_array(arena, Stripe, array.count);
|
|
||||||
for EachIndex(idx, array.count)
|
|
||||||
{
|
|
||||||
array.v[idx].arena = arena_alloc();
|
|
||||||
array.v[idx].rw_mutex = rw_mutex_alloc();
|
|
||||||
array.v[idx].cv = cond_var_alloc();
|
|
||||||
}
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
stripe_array_release(StripeArray *stripes)
|
|
||||||
{
|
|
||||||
for EachIndex(idx, stripes->count)
|
|
||||||
{
|
|
||||||
arena_release(stripes->v[idx].arena);
|
|
||||||
rw_mutex_release(stripes->v[idx].rw_mutex);
|
|
||||||
cond_var_release(stripes->v[idx].cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Stripe *
|
|
||||||
stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx)
|
|
||||||
{
|
|
||||||
Stripe *stripe = &stripes->v[slot_idx%stripes->count];
|
|
||||||
return stripe;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Info Helpers
|
|
||||||
|
|
||||||
internal void
|
|
||||||
set_thread_name(String8 string)
|
|
||||||
{
|
|
||||||
ProfThreadName("%.*s", str8_varg(string));
|
|
||||||
set_platform_thread_name(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
set_thread_namef(char *fmt, ...)
|
|
||||||
{
|
|
||||||
Temp scratch = scratch_begin(0, 0);
|
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
|
||||||
set_thread_name(string);
|
|
||||||
va_end(args);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
|
|
||||||
|
|
||||||
//- rjf: slow barriers
|
|
||||||
|
|
||||||
typedef struct BarrierNode BarrierNode;
|
|
||||||
struct BarrierNode
|
|
||||||
{
|
|
||||||
BarrierNode *next;
|
|
||||||
U64 count;
|
|
||||||
U64 threads_left_to_enter;
|
|
||||||
U64 threads_left_to_leave;
|
|
||||||
RWMutex rw_mutex;
|
|
||||||
CondVar cv;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct BarrierTCTX BarrierTCTX;
|
|
||||||
struct BarrierTCTX
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
BarrierNode *free_barrier_node;
|
|
||||||
};
|
|
||||||
|
|
||||||
thread_static BarrierTCTX *barrier_tctx = 0;
|
|
||||||
|
|
||||||
internal Barrier
|
|
||||||
slow_barrier_alloc(U64 count)
|
|
||||||
{
|
|
||||||
if(barrier_tctx == 0)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
barrier_tctx = push_array(arena, BarrierTCTX, 1);
|
|
||||||
barrier_tctx->arena = arena;
|
|
||||||
}
|
|
||||||
BarrierNode *n = barrier_tctx->free_barrier_node;
|
|
||||||
if(n != 0)
|
|
||||||
{
|
|
||||||
SLLStackPop(barrier_tctx->free_barrier_node);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
n = push_array_no_zero(barrier_tctx->arena, BarrierNode, 1);
|
|
||||||
}
|
|
||||||
MemoryZeroStruct(n);
|
|
||||||
n->count = count;
|
|
||||||
n->threads_left_to_enter = count;
|
|
||||||
n->rw_mutex = rw_mutex_alloc();
|
|
||||||
n->cv = cond_var_alloc();
|
|
||||||
Barrier result = {(U64)n};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
slow_barrier_release(Barrier barrier)
|
|
||||||
{
|
|
||||||
if(barrier_tctx == 0)
|
|
||||||
{
|
|
||||||
Arena *arena = arena_alloc();
|
|
||||||
barrier_tctx = push_array(arena, BarrierTCTX, 1);
|
|
||||||
barrier_tctx->arena = arena;
|
|
||||||
}
|
|
||||||
BarrierNode *n = (BarrierNode *)barrier.u64[0];
|
|
||||||
rw_mutex_release(n->rw_mutex);
|
|
||||||
cond_var_release(n->cv);
|
|
||||||
SLLStackPush(barrier_tctx->free_barrier_node, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
slow_barrier_wait(Barrier barrier)
|
|
||||||
{
|
|
||||||
ProfBeginFunction();
|
|
||||||
BarrierNode *n = (BarrierNode *)barrier.u64[0];
|
|
||||||
U64 threads_left_to_enter = ins_atomic_u64_dec_eval(&n->threads_left_to_enter);
|
|
||||||
|
|
||||||
//- rjf: threads left to enter > 0 => wait
|
|
||||||
if(threads_left_to_enter > 0)
|
|
||||||
{
|
|
||||||
// rjf: first try a spin loop
|
|
||||||
B32 done_waiting = 0;
|
|
||||||
ProfScope("spin loop wait") for(U64 spin_count = 0; spin_count < 10000; spin_count += 1)
|
|
||||||
{
|
|
||||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
|
|
||||||
{
|
|
||||||
done_waiting = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: not done waiting -> need to do slow wait on condition variable
|
|
||||||
if(!done_waiting) ProfScope("slow wait")
|
|
||||||
{
|
|
||||||
RWMutexScope(n->rw_mutex, 0) for(;;)
|
|
||||||
{
|
|
||||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) != 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cond_var_wait_rw(n->cv, n->rw_mutex, 0, max_U64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rjf: decrement leave counter
|
|
||||||
if(ins_atomic_u64_dec_eval(&n->threads_left_to_leave) > 0)
|
|
||||||
{
|
|
||||||
ProfScope("signal") cond_var_signal(n->cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: threads left to enter == 0 -> last thread, wakeup
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(&n->threads_left_to_enter, n->count);
|
|
||||||
ProfScope("wake up") RWMutexScope(n->rw_mutex, 1)
|
|
||||||
{
|
|
||||||
ins_atomic_u64_eval_assign(&n->threads_left_to_leave, n->count-1);
|
|
||||||
}
|
|
||||||
ProfScope("signal") cond_var_signal(n->cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
//- rjf: wait for threads left to leave == 0
|
|
||||||
ProfScope("wait for threads to leave")
|
|
||||||
{
|
|
||||||
for(U64 spin_count = 0;; spin_count += 1)
|
|
||||||
{
|
|
||||||
if(ins_atomic_u64_eval(&n->threads_left_to_leave) == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProfEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
///~ Semaphore
|
|
||||||
|
|
||||||
internal void
|
|
||||||
semaphore_drop(Semaphore semaphore)
|
|
||||||
{
|
|
||||||
semaphore_drop_count(semaphore, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef BASE_THREADS_H
|
|
||||||
#define BASE_THREADS_H
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Types
|
|
||||||
|
|
||||||
typedef struct Thread Thread;
|
|
||||||
struct Thread
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
typedef void ThreadEntryPointFunctionType(void *p);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Synchronization Primitive Types
|
|
||||||
|
|
||||||
typedef struct Mutex Mutex;
|
|
||||||
struct Mutex
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct RWMutex RWMutex;
|
|
||||||
struct RWMutex
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct CondVar CondVar;
|
|
||||||
struct CondVar
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Semaphore Semaphore;
|
|
||||||
struct Semaphore
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Barrier Barrier;
|
|
||||||
struct Barrier
|
|
||||||
{
|
|
||||||
U64 u64[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Table Stripes
|
|
||||||
|
|
||||||
typedef struct Stripe Stripe;
|
|
||||||
struct Stripe
|
|
||||||
{
|
|
||||||
Arena *arena;
|
|
||||||
RWMutex rw_mutex;
|
|
||||||
CondVar cv;
|
|
||||||
void *free;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct StripeArray StripeArray;
|
|
||||||
struct StripeArray
|
|
||||||
{
|
|
||||||
Stripe *v;
|
|
||||||
U64 count;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Table Stripe Functions
|
|
||||||
|
|
||||||
internal StripeArray stripe_array_alloc(Arena *arena);
|
|
||||||
internal void stripe_array_release(StripeArray *stripes);
|
|
||||||
internal Stripe *stripe_from_slot_idx(StripeArray *stripes, U64 slot_idx);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Thread Info Helpers
|
|
||||||
|
|
||||||
internal void set_thread_name(String8 string);
|
|
||||||
internal void set_thread_namef(char *fmt, ...);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Current Thread Info
|
|
||||||
|
|
||||||
internal U32 tid(void);
|
|
||||||
internal void set_platform_thread_name(String8 name);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Thread Functions
|
|
||||||
|
|
||||||
internal Thread thread_launch(ThreadEntryPointFunctionType *f, void *p);
|
|
||||||
internal B32 thread_join(Thread thread, U64 endt_us);
|
|
||||||
internal void thread_detach(Thread thread);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Synchronization Primitive Functions
|
|
||||||
|
|
||||||
//- rjf: recursive mutexes
|
|
||||||
internal Mutex mutex_alloc(void);
|
|
||||||
internal void mutex_release(Mutex mutex);
|
|
||||||
internal void mutex_take(Mutex mutex);
|
|
||||||
internal void mutex_drop(Mutex mutex);
|
|
||||||
|
|
||||||
//- rjf: reader/writer mutexes
|
|
||||||
internal RWMutex rw_mutex_alloc(void);
|
|
||||||
internal void rw_mutex_release(RWMutex mutex);
|
|
||||||
internal void rw_mutex_take(RWMutex mutex, B32 write_mode);
|
|
||||||
internal void rw_mutex_drop(RWMutex mutex, B32 write_mode);
|
|
||||||
#define rw_mutex_take_r(m) rw_mutex_take((m), (0))
|
|
||||||
#define rw_mutex_take_w(m) rw_mutex_take((m), (1))
|
|
||||||
#define rw_mutex_drop_r(m) rw_mutex_drop((m), (0))
|
|
||||||
#define rw_mutex_drop_w(m) rw_mutex_drop((m), (1))
|
|
||||||
|
|
||||||
//- rjf: condition variables
|
|
||||||
internal CondVar cond_var_alloc(void);
|
|
||||||
internal void cond_var_release(CondVar cv);
|
|
||||||
// returns false on timeout, true on signal, (max_wait_ms = max_U64) -> no timeout
|
|
||||||
internal B32 cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us);
|
|
||||||
internal B32 cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us);
|
|
||||||
#define cond_var_wait_rw_r(cv, m, endt) cond_var_wait_rw((cv), (m), (0), (endt))
|
|
||||||
#define cond_var_wait_rw_w(cv, m, endt) cond_var_wait_rw((cv), (m), (1), (endt))
|
|
||||||
internal void cond_var_signal(CondVar cv);
|
|
||||||
internal void cond_var_broadcast(CondVar cv);
|
|
||||||
|
|
||||||
//- rjf: cross-process semaphores
|
|
||||||
internal Semaphore semaphore_alloc(U32 initial_count, U32 max_count, String8 name);
|
|
||||||
internal void semaphore_release(Semaphore semaphore);
|
|
||||||
internal Semaphore semaphore_open(String8 name);
|
|
||||||
internal void semaphore_close(Semaphore semaphore);
|
|
||||||
internal B32 semaphore_take(Semaphore semaphore, U64 endt_us);
|
|
||||||
internal void semaphore_drop(Semaphore semaphore);
|
|
||||||
internal void semaphore_drop_count(Semaphore semaphore, U64 drop_count);
|
|
||||||
|
|
||||||
//- rjf: barriers
|
|
||||||
internal Barrier barrier_alloc(U64 count);
|
|
||||||
internal void barrier_release(Barrier barrier);
|
|
||||||
internal void barrier_wait(Barrier barrier);
|
|
||||||
|
|
||||||
//- rjf: scope macros
|
|
||||||
#define MutexScope(mutex) DeferLoop(mutex_take(mutex), mutex_drop(mutex))
|
|
||||||
#define RWMutexScope(mutex, write_mode) DeferLoop(rw_mutex_take((mutex), (write_mode)), rw_mutex_drop((mutex), (write_mode)))
|
|
||||||
#define MutexScopeR(mutex) DeferLoop(rw_mutex_take_r(mutex), rw_mutex_drop_r(mutex))
|
|
||||||
#define MutexScopeW(mutex) DeferLoop(rw_mutex_take_w(mutex), rw_mutex_drop_w(mutex))
|
|
||||||
#define MutexScopeRWPromote(mutex) DeferLoop((rw_mutex_drop_r(mutex), rw_mutex_take_w(mutex)), (rw_mutex_drop_w(mutex), rw_mutex_take_r(mutex)))
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: Platform-Abstracted Synchronization Primitive Functions
|
|
||||||
|
|
||||||
//- rjf: slow barriers
|
|
||||||
internal Barrier slow_barrier_alloc(U64 count);
|
|
||||||
internal void slow_barrier_release(Barrier barrier);
|
|
||||||
internal void slow_barrier_wait(Barrier barrier);
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: @per_os_impl Safe Calls
|
|
||||||
|
|
||||||
internal void safe_call(ThreadEntryPointFunctionType *func, ThreadEntryPointFunctionType *fail_handler, void *ptr);
|
|
||||||
|
|
||||||
#endif // BASE_THREADS_H
|
|
||||||
@@ -0,0 +1,454 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ Safe Casts
|
||||||
|
|
||||||
|
internal U16
|
||||||
|
safe_cast_u16(U32 x)
|
||||||
|
{
|
||||||
|
AssertAlways(x <= max_U16);
|
||||||
|
U16 result = (U16)x;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U32
|
||||||
|
safe_cast_u32(U64 x)
|
||||||
|
{
|
||||||
|
AssertAlways(x <= max_U32);
|
||||||
|
U32 result = (U32)x;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal S32
|
||||||
|
safe_cast_s32(S64 x)
|
||||||
|
{
|
||||||
|
AssertAlways(x <= max_S32);
|
||||||
|
S32 result = (S32)x;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Large Base Type Functions
|
||||||
|
|
||||||
|
internal U128
|
||||||
|
u128_zero(void)
|
||||||
|
{
|
||||||
|
U128 v = {0};
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U128
|
||||||
|
u128_make(U64 v0, U64 v1)
|
||||||
|
{
|
||||||
|
U128 v = {v0, v1};
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
u128_match(U128 a, U128 b)
|
||||||
|
{
|
||||||
|
return MemoryMatchStruct(&a, &b);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Bit Patterns
|
||||||
|
|
||||||
|
internal U32
|
||||||
|
u32_from_u64_saturate(U64 x){
|
||||||
|
U32 x32 = (x > max_U32)?max_U32:(U32)x;
|
||||||
|
return(x32);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
u64_up_to_pow2(U64 x){
|
||||||
|
if (x == 0){
|
||||||
|
x = 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
x -= 1;
|
||||||
|
x |= (x >> 1);
|
||||||
|
x |= (x >> 2);
|
||||||
|
x |= (x >> 4);
|
||||||
|
x |= (x >> 8);
|
||||||
|
x |= (x >> 16);
|
||||||
|
x |= (x >> 32);
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
return(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal S32
|
||||||
|
extend_sign32(U32 x, U32 size){
|
||||||
|
U32 high_bit = size * 8;
|
||||||
|
U32 shift = 32 - high_bit;
|
||||||
|
S32 result = ((S32)x << shift) >> shift;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal S64
|
||||||
|
extend_sign64(U64 x, U64 size){
|
||||||
|
U64 high_bit = size * 8;
|
||||||
|
U64 shift = 64 - high_bit;
|
||||||
|
S64 result = ((S64)x << shift) >> shift;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal F32
|
||||||
|
inf32(void){
|
||||||
|
union { U32 u; F32 f; } x;
|
||||||
|
x.u = exponent32;
|
||||||
|
return(x.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal F32
|
||||||
|
neg_inf32(void){
|
||||||
|
union { U32 u; F32 f; } x;
|
||||||
|
x.u = sign32 | exponent32;
|
||||||
|
return(x.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U16
|
||||||
|
bswap_u16(U16 x)
|
||||||
|
{
|
||||||
|
U16 result = (((x & 0xFF00) >> 8) |
|
||||||
|
((x & 0x00FF) << 8));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U32
|
||||||
|
bswap_u32(U32 x)
|
||||||
|
{
|
||||||
|
U32 result = (((x & 0xFF000000) >> 24) |
|
||||||
|
((x & 0x00FF0000) >> 8) |
|
||||||
|
((x & 0x0000FF00) << 8) |
|
||||||
|
((x & 0x000000FF) << 24));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
bswap_u64(U64 x)
|
||||||
|
{
|
||||||
|
// TODO(nick): naive bswap, replace with something that is faster like an intrinsic
|
||||||
|
U64 result = (((x & 0xFF00000000000000ULL) >> 56) |
|
||||||
|
((x & 0x00FF000000000000ULL) >> 40) |
|
||||||
|
((x & 0x0000FF0000000000ULL) >> 24) |
|
||||||
|
((x & 0x000000FF00000000ULL) >> 8) |
|
||||||
|
((x & 0x00000000FF000000ULL) << 8) |
|
||||||
|
((x & 0x0000000000FF0000ULL) << 24) |
|
||||||
|
((x & 0x000000000000FF00ULL) << 40) |
|
||||||
|
((x & 0x00000000000000FFULL) << 56));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Enum -> Sign
|
||||||
|
|
||||||
|
internal S32
|
||||||
|
sign_from_side_S32(Side side){
|
||||||
|
return((side == Side_Min)?-1:1);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal F32
|
||||||
|
sign_from_side_F32(Side side){
|
||||||
|
return((side == Side_Min)?-1.f:1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Memory Functions
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
memory_is_zero(void *ptr, U64 size){
|
||||||
|
B32 result = 1;
|
||||||
|
|
||||||
|
// break down size
|
||||||
|
U64 extra = (size&0x7);
|
||||||
|
U64 count8 = (size >> 3);
|
||||||
|
|
||||||
|
// check with 8-byte stride
|
||||||
|
U64 *p64 = (U64*)ptr;
|
||||||
|
if(result)
|
||||||
|
{
|
||||||
|
for (U64 i = 0; i < count8; i += 1, p64 += 1){
|
||||||
|
if (*p64 != 0){
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check extra
|
||||||
|
if(result)
|
||||||
|
{
|
||||||
|
U8 *p8 = (U8*)p64;
|
||||||
|
for (U64 i = 0; i < extra; i += 1, p8 += 1){
|
||||||
|
if (*p8 != 0){
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Text 2D Coordinate/Range Functions
|
||||||
|
|
||||||
|
internal TxtPt
|
||||||
|
txt_pt(S64 line, S64 column)
|
||||||
|
{
|
||||||
|
TxtPt p = {0};
|
||||||
|
p.line = line;
|
||||||
|
p.column = column;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
txt_pt_match(TxtPt a, TxtPt b)
|
||||||
|
{
|
||||||
|
return a.line == b.line && a.column == b.column;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal B32
|
||||||
|
txt_pt_less_than(TxtPt a, TxtPt b)
|
||||||
|
{
|
||||||
|
B32 result = 0;
|
||||||
|
if(a.line < b.line)
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else if(a.line == b.line)
|
||||||
|
{
|
||||||
|
result = a.column < b.column;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TxtPt
|
||||||
|
txt_pt_min(TxtPt a, TxtPt b)
|
||||||
|
{
|
||||||
|
TxtPt result = b;
|
||||||
|
if(txt_pt_less_than(a, b))
|
||||||
|
{
|
||||||
|
result = a;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TxtPt
|
||||||
|
txt_pt_max(TxtPt a, TxtPt b)
|
||||||
|
{
|
||||||
|
TxtPt result = a;
|
||||||
|
if(txt_pt_less_than(a, b))
|
||||||
|
{
|
||||||
|
result = b;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TxtRng
|
||||||
|
txt_rng(TxtPt min, TxtPt max)
|
||||||
|
{
|
||||||
|
TxtRng range = {0};
|
||||||
|
if(txt_pt_less_than(min, max))
|
||||||
|
{
|
||||||
|
range.min = min;
|
||||||
|
range.max = max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
range.min = max;
|
||||||
|
range.max = min;
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TxtRng
|
||||||
|
txt_rng_intersect(TxtRng a, TxtRng b)
|
||||||
|
{
|
||||||
|
TxtRng result = {0};
|
||||||
|
result.min = txt_pt_max(a.min, b.min);
|
||||||
|
result.max = txt_pt_min(a.max, b.max);
|
||||||
|
if(txt_pt_less_than(result.max, result.min))
|
||||||
|
{
|
||||||
|
MemoryZeroStruct(&result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TxtRng
|
||||||
|
txt_rng_union(TxtRng a, TxtRng b)
|
||||||
|
{
|
||||||
|
TxtRng result = {0};
|
||||||
|
result.min = txt_pt_min(a.min, b.min);
|
||||||
|
result.max = txt_pt_max(a.max, b.max);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Toolchain/Environment Enum Functions
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
bit_size_from_arch(Architecture arch)
|
||||||
|
{
|
||||||
|
// TODO(rjf): metacode
|
||||||
|
U64 arch_bitsize = 0;
|
||||||
|
switch(arch)
|
||||||
|
{
|
||||||
|
case Architecture_x64: arch_bitsize = 64; break;
|
||||||
|
case Architecture_x86: arch_bitsize = 32; break;
|
||||||
|
case Architecture_arm64: arch_bitsize = 64; break;
|
||||||
|
case Architecture_arm32: arch_bitsize = 32; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return arch_bitsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
max_instruction_size_from_arch(Architecture arch)
|
||||||
|
{
|
||||||
|
// TODO(rjf): make this real
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal OperatingSystem
|
||||||
|
operating_system_from_context(void){
|
||||||
|
OperatingSystem os = OperatingSystem_Null;
|
||||||
|
#if OS_WINDOWS
|
||||||
|
os = OperatingSystem_Windows;
|
||||||
|
#elif OS_LINUX
|
||||||
|
os = OperatingSystem_Linux;
|
||||||
|
#elif OS_MAC
|
||||||
|
os = OperatingSystem_Mac;
|
||||||
|
#endif
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Architecture
|
||||||
|
architecture_from_context(void){
|
||||||
|
Architecture arch = Architecture_Null;
|
||||||
|
#if ARCH_X64
|
||||||
|
arch = Architecture_x64;
|
||||||
|
#elif ARCH_X86
|
||||||
|
arch = Architecture_x86;
|
||||||
|
#elif ARCH_ARM64
|
||||||
|
arch = Architecture_arm64;
|
||||||
|
#elif ARCH_ARM32
|
||||||
|
arch = Architecture_arm32;
|
||||||
|
#endif
|
||||||
|
return arch;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Compiler
|
||||||
|
compiler_from_context(void){
|
||||||
|
Compiler compiler = Compiler_Null;
|
||||||
|
#if COMPILER_CL
|
||||||
|
compiler = Compiler_cl;
|
||||||
|
#elif COMPILER_GCC
|
||||||
|
compiler = Compiler_gcc;
|
||||||
|
#elif COMPILER_CLANG
|
||||||
|
compiler = Compiler_clang;
|
||||||
|
#endif
|
||||||
|
return compiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Time Functions
|
||||||
|
|
||||||
|
internal DenseTime
|
||||||
|
dense_time_from_date_time(DateTime date_time){
|
||||||
|
DenseTime result = 0;
|
||||||
|
result += date_time.year;
|
||||||
|
result *= 12;
|
||||||
|
result += date_time.mon;
|
||||||
|
result *= 31;
|
||||||
|
result += date_time.day;
|
||||||
|
result *= 24;
|
||||||
|
result += date_time.hour;
|
||||||
|
result *= 60;
|
||||||
|
result += date_time.min;
|
||||||
|
result *= 61;
|
||||||
|
result += date_time.sec;
|
||||||
|
result *= 1000;
|
||||||
|
result += date_time.msec;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DateTime
|
||||||
|
date_time_from_dense_time(DenseTime time){
|
||||||
|
DateTime result = {0};
|
||||||
|
result.msec = time%1000;
|
||||||
|
time /= 1000;
|
||||||
|
result.sec = time%61;
|
||||||
|
time /= 61;
|
||||||
|
result.min = time%60;
|
||||||
|
time /= 60;
|
||||||
|
result.hour = time%24;
|
||||||
|
time /= 24;
|
||||||
|
result.day = time%31;
|
||||||
|
time /= 31;
|
||||||
|
result.mon = time%12;
|
||||||
|
time /= 12;
|
||||||
|
Assert(time <= max_U32);
|
||||||
|
result.year = (U32)time;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DateTime
|
||||||
|
date_time_from_micro_seconds(U64 time){
|
||||||
|
DateTime result = {0};
|
||||||
|
result.micro_sec = time%1000;
|
||||||
|
time /= 1000;
|
||||||
|
result.msec = time%1000;
|
||||||
|
time /= 1000;
|
||||||
|
result.sec = time%60;
|
||||||
|
time /= 60;
|
||||||
|
result.min = time%60;
|
||||||
|
time /= 60;
|
||||||
|
result.hour = time%24;
|
||||||
|
time /= 24;
|
||||||
|
result.day = time%31;
|
||||||
|
time /= 31;
|
||||||
|
result.mon = time%12;
|
||||||
|
time /= 12;
|
||||||
|
Assert(time <= max_U32);
|
||||||
|
result.year = (U32)time;
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size)
|
||||||
|
{
|
||||||
|
Assert(src_data_size <= ring_size);
|
||||||
|
{
|
||||||
|
U64 ring_off = ring_pos%ring_size;
|
||||||
|
U64 bytes_before_split = ring_size-ring_off;
|
||||||
|
U64 pre_split_bytes = Min(bytes_before_split, src_data_size);
|
||||||
|
U64 pst_split_bytes = src_data_size-pre_split_bytes;
|
||||||
|
void *pre_split_data = src_data;
|
||||||
|
void *pst_split_data = ((U8 *)src_data + pre_split_bytes);
|
||||||
|
MemoryCopy(ring_base+ring_off, pre_split_data, pre_split_bytes);
|
||||||
|
MemoryCopy(ring_base+0, pst_split_data, pst_split_bytes);
|
||||||
|
}
|
||||||
|
return src_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal U64
|
||||||
|
ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size)
|
||||||
|
{
|
||||||
|
Assert(read_size <= ring_size);
|
||||||
|
{
|
||||||
|
U64 ring_off = ring_pos%ring_size;
|
||||||
|
U64 bytes_before_split = ring_size-ring_off;
|
||||||
|
U64 pre_split_bytes = Min(bytes_before_split, read_size);
|
||||||
|
U64 pst_split_bytes = read_size-pre_split_bytes;
|
||||||
|
MemoryCopy(dst_data, ring_base+ring_off, pre_split_bytes);
|
||||||
|
MemoryCopy((U8 *)dst_data + pre_split_bytes, ring_base+0, pst_split_bytes);
|
||||||
|
}
|
||||||
|
return read_size;
|
||||||
|
}
|
||||||
@@ -0,0 +1,680 @@
|
|||||||
|
// Copyright (c) 2024 Epic Games Tools
|
||||||
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||||
|
|
||||||
|
#ifndef BASE_TYPES_H
|
||||||
|
#define BASE_TYPES_H
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Foreign Includes
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Build Configuration
|
||||||
|
|
||||||
|
#if !defined(ENABLE_DEV)
|
||||||
|
# define ENABLE_DEV 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SUPPLEMENT_UNIT)
|
||||||
|
# define SUPPLEMENT_UNIT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Codebase Keywords
|
||||||
|
|
||||||
|
#define internal static
|
||||||
|
#define global static
|
||||||
|
#define local_persist static
|
||||||
|
|
||||||
|
#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS)
|
||||||
|
# pragma section(".rdata$", read)
|
||||||
|
# define read_only __declspec(allocate(".rdata$"))
|
||||||
|
#elif (COMPILER_CLANG && OS_LINUX)
|
||||||
|
# define read_only __attribute__((section(".rodata")))
|
||||||
|
#else
|
||||||
|
// NOTE(rjf): I don't know of a useful way to do this in GCC land.
|
||||||
|
// __attribute__((section(".rodata"))) looked promising, but it introduces a
|
||||||
|
// strange warning about malformed section attributes, and it doesn't look
|
||||||
|
// like writing to that section reliably produces access violations, strangely
|
||||||
|
// enough. (It does on Clang)
|
||||||
|
# define read_only
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Memory Operation Macros
|
||||||
|
|
||||||
|
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
|
||||||
|
#define MemorySet(dst, byte, size) memset((dst), (byte), (size))
|
||||||
|
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
|
||||||
|
#define MemoryStrlen(ptr) strlen(ptr)
|
||||||
|
|
||||||
|
#define MemoryCopyStruct(d,s) MemoryCopy((d),(s),sizeof(*(d)))
|
||||||
|
#define MemoryCopyArray(d,s) MemoryCopy((d),(s),sizeof(d))
|
||||||
|
#define MemoryCopyTyped(d,s,c) MemoryCopy((d),(s),sizeof(*(d))*(c))
|
||||||
|
|
||||||
|
#define MemoryZero(s,z) memset((s),0,(z))
|
||||||
|
#define MemoryZeroStruct(s) MemoryZero((s),sizeof(*(s)))
|
||||||
|
#define MemoryZeroArray(a) MemoryZero((a),sizeof(a))
|
||||||
|
#define MemoryZeroTyped(m,c) MemoryZero((m),sizeof(*(m))*(c))
|
||||||
|
|
||||||
|
#define MemoryMatch(a,b,z) (MemoryCompare((a),(b),(z)) == 0)
|
||||||
|
#define MemoryMatchStruct(a,b) MemoryMatch((a),(b),sizeof(*(a)))
|
||||||
|
#define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a))
|
||||||
|
|
||||||
|
#define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) )
|
||||||
|
#define MemoryConsume(T,p,e) \
|
||||||
|
( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) )
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Units
|
||||||
|
|
||||||
|
#define KB(n) (((U64)(n)) << 10)
|
||||||
|
#define MB(n) (((U64)(n)) << 20)
|
||||||
|
#define GB(n) (((U64)(n)) << 30)
|
||||||
|
#define TB(n) (((U64)(n)) << 40)
|
||||||
|
#define Thousand(n) ((n)*1000)
|
||||||
|
#define Million(n) ((n)*1000000)
|
||||||
|
#define Billion(n) ((n)*1000000000)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Asserts
|
||||||
|
|
||||||
|
#if COMPILER_CL
|
||||||
|
# define Trap() __debugbreak()
|
||||||
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
|
# define Trap() __builtin_trap()
|
||||||
|
# else
|
||||||
|
# error "undefined trap"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define AssertAlways(x) do{if(!(x)) {Trap();}}while(0)
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
# define Assert(x) AssertAlways(x)
|
||||||
|
#else
|
||||||
|
# define Assert(x) (void)(x)
|
||||||
|
#endif
|
||||||
|
#define AssertImplies(a,b) Assert(!(a) || b)
|
||||||
|
#define AssertIff(a,b) Assert(!!(a) == !!(b))
|
||||||
|
#define InvalidPath Assert(!"Invalid Path!")
|
||||||
|
#define NotImplemented Assert(!"Not Implemented!")
|
||||||
|
|
||||||
|
#define StaticAssert(C,ID) global U8 Glue(ID,__LINE__)[(C)?1:-1]
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Branch Predictor Hints
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
# define Expect(expr, val) __builtin_expect((expr), (val))
|
||||||
|
#else
|
||||||
|
# define Expect(expr, val) (expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Likely(expr) Expect(expr,1)
|
||||||
|
#define Unlikely(expr) Expect(expr,0)
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Misc. Helper Macros
|
||||||
|
|
||||||
|
#define ArrayCount(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
#define Stmnt(S) do{ S }while(0)
|
||||||
|
|
||||||
|
#define Stringify_(S) #S
|
||||||
|
#define Stringify(S) Stringify_(S)
|
||||||
|
|
||||||
|
#define Glue_(A,B) A##B
|
||||||
|
#define Glue(A,B) Glue_(A,B)
|
||||||
|
|
||||||
|
#define Min(A,B) ( ((A)<(B))?(A):(B) )
|
||||||
|
#define Max(A,B) ( ((A)>(B))?(A):(B) )
|
||||||
|
|
||||||
|
#define ClampTop(A,X) Min(A,X)
|
||||||
|
#define ClampBot(X,B) Max(X,B)
|
||||||
|
#define Clamp(A,X,B) ( ((X)<(A))?(A):((X)>(B))?(B):(X) )
|
||||||
|
|
||||||
|
#define PtrClampTop(A,X) ClampTop(A,X)
|
||||||
|
#define PtrClampBot(X,B) ClampBot(X,B)
|
||||||
|
#define PtrClamp(A,X,B) Clamp(A,X,B)
|
||||||
|
|
||||||
|
#define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b))
|
||||||
|
|
||||||
|
#define Swap(T,a,b) Stmnt( T t__ = a; a = b; b = t__; )
|
||||||
|
|
||||||
|
#if ARCH_64BIT
|
||||||
|
# define IntFromPtr(ptr) ((U64)(ptr))
|
||||||
|
#elif ARCH_32BIT
|
||||||
|
# define IntFromPtr(ptr) ((U32)(ptr))
|
||||||
|
#else
|
||||||
|
# error missing ptr cast for this architecture
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PtrFromInt(i) (void*)((U8*)0 + (i))
|
||||||
|
|
||||||
|
#define Member(T,m) (((T*)0)->m)
|
||||||
|
#define OffsetOf(T,m) IntFromPtr(&Member(T,m))
|
||||||
|
#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off)))
|
||||||
|
#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m))
|
||||||
|
|
||||||
|
#define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b));
|
||||||
|
#define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1)))
|
||||||
|
#define AlignDownPow2(x,b) ((x)&(~((b) - 1)))
|
||||||
|
#define AlignPadPow2(x,b) ((0-(x)) & ((b) - 1))
|
||||||
|
#define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0)
|
||||||
|
#define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0)
|
||||||
|
|
||||||
|
#define DeferLoop(begin, end) for(int _i_ = ((begin), 0); !_i_; _i_ += 1, (end))
|
||||||
|
#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end))
|
||||||
|
|
||||||
|
#if LANG_CPP
|
||||||
|
# define zero_struct {}
|
||||||
|
#else
|
||||||
|
# define zero_struct {0}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if COMPILER_MSVC && COMPILER_MSVC_YEAR < 2015
|
||||||
|
# define this_function_name "unknown"
|
||||||
|
#else
|
||||||
|
# define this_function_name __func__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LANG_CPP
|
||||||
|
# define C_LINKAGE_BEGIN extern "C"{
|
||||||
|
# define C_LINKAGE_END }
|
||||||
|
# define C_LINKAGE extern "C"
|
||||||
|
#else
|
||||||
|
# define C_LINKAGE_BEGIN
|
||||||
|
# define C_LINKAGE_END
|
||||||
|
# define C_LINKAGE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if COMPILER_CL
|
||||||
|
# define thread_static __declspec(thread)
|
||||||
|
#elif COMPILER_CLANG || COMPILER_GCC
|
||||||
|
# define thread_static __thread
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
# define shared_function C_LINKAGE __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
# define shared_function C_LINKAGE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ ASAN
|
||||||
|
|
||||||
|
#if COMPILER_CL
|
||||||
|
# if defined(__SANITIZE_ADDRESS__)
|
||||||
|
# define ASAN_ENABLED 1
|
||||||
|
# define NO_ASAN __declspec(no_sanitize_address)
|
||||||
|
# else
|
||||||
|
# define NO_ASAN
|
||||||
|
# endif
|
||||||
|
#elif COMPILER_CLANG
|
||||||
|
# if defined(__has_feature)
|
||||||
|
# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
|
||||||
|
# define ASAN_ENABLED 1
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# define NO_ASAN __attribute__((no_sanitize("address")))
|
||||||
|
#else
|
||||||
|
# error "NO_ASAN is not defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ASAN_ENABLED
|
||||||
|
|
||||||
|
#pragma comment(lib, "clang_rt.asan-x86_64.lib")
|
||||||
|
|
||||||
|
C_LINKAGE_BEGIN
|
||||||
|
void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
||||||
|
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
||||||
|
C_LINKAGE_END
|
||||||
|
|
||||||
|
# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size))
|
||||||
|
# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size))
|
||||||
|
#else
|
||||||
|
# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
|
||||||
|
# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Base Types
|
||||||
|
|
||||||
|
typedef uint8_t U8;
|
||||||
|
typedef uint16_t U16;
|
||||||
|
typedef uint32_t U32;
|
||||||
|
typedef uint64_t U64;
|
||||||
|
typedef int8_t S8;
|
||||||
|
typedef int16_t S16;
|
||||||
|
typedef int32_t S32;
|
||||||
|
typedef int64_t S64;
|
||||||
|
typedef S8 B8;
|
||||||
|
typedef S16 B16;
|
||||||
|
typedef S32 B32;
|
||||||
|
typedef S64 B64;
|
||||||
|
typedef float F32;
|
||||||
|
typedef double F64;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Large Base Types
|
||||||
|
|
||||||
|
typedef struct U128 U128;
|
||||||
|
struct U128
|
||||||
|
{
|
||||||
|
U64 u64[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Basic Types & Spaces
|
||||||
|
|
||||||
|
typedef void VoidProc(void);
|
||||||
|
|
||||||
|
typedef enum Dimension
|
||||||
|
{
|
||||||
|
Dimension_X,
|
||||||
|
Dimension_Y,
|
||||||
|
Dimension_Z,
|
||||||
|
Dimension_W,
|
||||||
|
}
|
||||||
|
Dimension;
|
||||||
|
|
||||||
|
typedef enum Side
|
||||||
|
{
|
||||||
|
Side_Invalid = -1,
|
||||||
|
Side_Min,
|
||||||
|
Side_Max,
|
||||||
|
Side_COUNT,
|
||||||
|
}
|
||||||
|
Side;
|
||||||
|
#define side_flip(s) ((Side)(!(s)))
|
||||||
|
|
||||||
|
typedef enum Axis2
|
||||||
|
{
|
||||||
|
Axis2_Invalid = -1,
|
||||||
|
Axis2_X,
|
||||||
|
Axis2_Y,
|
||||||
|
Axis2_COUNT,
|
||||||
|
}
|
||||||
|
Axis2;
|
||||||
|
#define axis2_flip(a) ((Axis2)(!(a)))
|
||||||
|
|
||||||
|
typedef enum Corner
|
||||||
|
{
|
||||||
|
Corner_Invalid = -1,
|
||||||
|
Corner_00,
|
||||||
|
Corner_01,
|
||||||
|
Corner_10,
|
||||||
|
Corner_11,
|
||||||
|
Corner_COUNT
|
||||||
|
}
|
||||||
|
Corner;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Toolchain/Environment Enums
|
||||||
|
|
||||||
|
typedef enum OperatingSystem
|
||||||
|
{
|
||||||
|
OperatingSystem_Null,
|
||||||
|
OperatingSystem_Windows,
|
||||||
|
OperatingSystem_Linux,
|
||||||
|
OperatingSystem_Mac,
|
||||||
|
OperatingSystem_COUNT,
|
||||||
|
}
|
||||||
|
OperatingSystem;
|
||||||
|
|
||||||
|
typedef enum Architecture
|
||||||
|
{
|
||||||
|
Architecture_Null,
|
||||||
|
Architecture_x64,
|
||||||
|
Architecture_x86,
|
||||||
|
Architecture_arm64,
|
||||||
|
Architecture_arm32,
|
||||||
|
Architecture_COUNT,
|
||||||
|
}
|
||||||
|
Architecture;
|
||||||
|
|
||||||
|
typedef enum Compiler
|
||||||
|
{
|
||||||
|
Compiler_Null,
|
||||||
|
Compiler_cl,
|
||||||
|
Compiler_gcc,
|
||||||
|
Compiler_clang,
|
||||||
|
Compiler_COUNT,
|
||||||
|
}
|
||||||
|
Compiler;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Text 2D Coordinates & Ranges
|
||||||
|
|
||||||
|
typedef struct TxtPt TxtPt;
|
||||||
|
struct TxtPt
|
||||||
|
{
|
||||||
|
S64 line;
|
||||||
|
S64 column;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct TxtRng TxtRng;
|
||||||
|
struct TxtRng
|
||||||
|
{
|
||||||
|
TxtPt min;
|
||||||
|
TxtPt max;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ NOTE(allen): Constants
|
||||||
|
|
||||||
|
global U32 sign32 = 0x80000000;
|
||||||
|
global U32 exponent32 = 0x7F800000;
|
||||||
|
global U32 mantissa32 = 0x007FFFFF;
|
||||||
|
|
||||||
|
global F32 big_golden32 = 1.61803398875f;
|
||||||
|
global F32 small_golden32 = 0.61803398875f;
|
||||||
|
|
||||||
|
global F32 pi32 = 3.1415926535897f;
|
||||||
|
|
||||||
|
global F64 machine_epsilon64 = 4.94065645841247e-324;
|
||||||
|
|
||||||
|
global U64 max_U64 = 0xffffffffffffffffull;
|
||||||
|
global U32 max_U32 = 0xffffffff;
|
||||||
|
global U16 max_U16 = 0xffff;
|
||||||
|
global U8 max_U8 = 0xff;
|
||||||
|
|
||||||
|
global S64 max_S64 = (S64)0x7fffffffffffffffull;
|
||||||
|
global S32 max_S32 = (S32)0x7fffffff;
|
||||||
|
global S16 max_S16 = (S16)0x7fff;
|
||||||
|
global S8 max_S8 = (S8)0x7f;
|
||||||
|
|
||||||
|
global S64 min_S64 = (S64)0xffffffffffffffffull;
|
||||||
|
global S32 min_S32 = (S32)0xffffffff;
|
||||||
|
global S16 min_S16 = (S16)0xffff;
|
||||||
|
global S8 min_S8 = (S8)0xff;
|
||||||
|
|
||||||
|
global const U32 bitmask1 = 0x00000001;
|
||||||
|
global const U32 bitmask2 = 0x00000003;
|
||||||
|
global const U32 bitmask3 = 0x00000007;
|
||||||
|
global const U32 bitmask4 = 0x0000000f;
|
||||||
|
global const U32 bitmask5 = 0x0000001f;
|
||||||
|
global const U32 bitmask6 = 0x0000003f;
|
||||||
|
global const U32 bitmask7 = 0x0000007f;
|
||||||
|
global const U32 bitmask8 = 0x000000ff;
|
||||||
|
global const U32 bitmask9 = 0x000001ff;
|
||||||
|
global const U32 bitmask10 = 0x000003ff;
|
||||||
|
global const U32 bitmask11 = 0x000007ff;
|
||||||
|
global const U32 bitmask12 = 0x00000fff;
|
||||||
|
global const U32 bitmask13 = 0x00001fff;
|
||||||
|
global const U32 bitmask14 = 0x00003fff;
|
||||||
|
global const U32 bitmask15 = 0x00007fff;
|
||||||
|
global const U32 bitmask16 = 0x0000ffff;
|
||||||
|
global const U32 bitmask17 = 0x0001ffff;
|
||||||
|
global const U32 bitmask18 = 0x0003ffff;
|
||||||
|
global const U32 bitmask19 = 0x0007ffff;
|
||||||
|
global const U32 bitmask20 = 0x000fffff;
|
||||||
|
global const U32 bitmask21 = 0x001fffff;
|
||||||
|
global const U32 bitmask22 = 0x003fffff;
|
||||||
|
global const U32 bitmask23 = 0x007fffff;
|
||||||
|
global const U32 bitmask24 = 0x00ffffff;
|
||||||
|
global const U32 bitmask25 = 0x01ffffff;
|
||||||
|
global const U32 bitmask26 = 0x03ffffff;
|
||||||
|
global const U32 bitmask27 = 0x07ffffff;
|
||||||
|
global const U32 bitmask28 = 0x0fffffff;
|
||||||
|
global const U32 bitmask29 = 0x1fffffff;
|
||||||
|
global const U32 bitmask30 = 0x3fffffff;
|
||||||
|
global const U32 bitmask31 = 0x7fffffff;
|
||||||
|
global const U32 bitmask32 = 0xffffffff;
|
||||||
|
|
||||||
|
global const U64 bitmask33 = 0x00000001ffffffffull;
|
||||||
|
global const U64 bitmask34 = 0x00000003ffffffffull;
|
||||||
|
global const U64 bitmask35 = 0x00000007ffffffffull;
|
||||||
|
global const U64 bitmask36 = 0x0000000fffffffffull;
|
||||||
|
global const U64 bitmask37 = 0x0000001fffffffffull;
|
||||||
|
global const U64 bitmask38 = 0x0000003fffffffffull;
|
||||||
|
global const U64 bitmask39 = 0x0000007fffffffffull;
|
||||||
|
global const U64 bitmask40 = 0x000000ffffffffffull;
|
||||||
|
global const U64 bitmask41 = 0x000001ffffffffffull;
|
||||||
|
global const U64 bitmask42 = 0x000003ffffffffffull;
|
||||||
|
global const U64 bitmask43 = 0x000007ffffffffffull;
|
||||||
|
global const U64 bitmask44 = 0x00000fffffffffffull;
|
||||||
|
global const U64 bitmask45 = 0x00001fffffffffffull;
|
||||||
|
global const U64 bitmask46 = 0x00003fffffffffffull;
|
||||||
|
global const U64 bitmask47 = 0x00007fffffffffffull;
|
||||||
|
global const U64 bitmask48 = 0x0000ffffffffffffull;
|
||||||
|
global const U64 bitmask49 = 0x0001ffffffffffffull;
|
||||||
|
global const U64 bitmask50 = 0x0003ffffffffffffull;
|
||||||
|
global const U64 bitmask51 = 0x0007ffffffffffffull;
|
||||||
|
global const U64 bitmask52 = 0x000fffffffffffffull;
|
||||||
|
global const U64 bitmask53 = 0x001fffffffffffffull;
|
||||||
|
global const U64 bitmask54 = 0x003fffffffffffffull;
|
||||||
|
global const U64 bitmask55 = 0x007fffffffffffffull;
|
||||||
|
global const U64 bitmask56 = 0x00ffffffffffffffull;
|
||||||
|
global const U64 bitmask57 = 0x01ffffffffffffffull;
|
||||||
|
global const U64 bitmask58 = 0x03ffffffffffffffull;
|
||||||
|
global const U64 bitmask59 = 0x07ffffffffffffffull;
|
||||||
|
global const U64 bitmask60 = 0x0fffffffffffffffull;
|
||||||
|
global const U64 bitmask61 = 0x1fffffffffffffffull;
|
||||||
|
global const U64 bitmask62 = 0x3fffffffffffffffull;
|
||||||
|
global const U64 bitmask63 = 0x7fffffffffffffffull;
|
||||||
|
global const U64 bitmask64 = 0xffffffffffffffffull;
|
||||||
|
|
||||||
|
global const U32 bit1 = (1<<0);
|
||||||
|
global const U32 bit2 = (1<<1);
|
||||||
|
global const U32 bit3 = (1<<2);
|
||||||
|
global const U32 bit4 = (1<<3);
|
||||||
|
global const U32 bit5 = (1<<4);
|
||||||
|
global const U32 bit6 = (1<<5);
|
||||||
|
global const U32 bit7 = (1<<6);
|
||||||
|
global const U32 bit8 = (1<<7);
|
||||||
|
global const U32 bit9 = (1<<8);
|
||||||
|
global const U32 bit10 = (1<<9);
|
||||||
|
global const U32 bit11 = (1<<10);
|
||||||
|
global const U32 bit12 = (1<<11);
|
||||||
|
global const U32 bit13 = (1<<12);
|
||||||
|
global const U32 bit14 = (1<<13);
|
||||||
|
global const U32 bit15 = (1<<14);
|
||||||
|
global const U32 bit16 = (1<<15);
|
||||||
|
global const U32 bit17 = (1<<16);
|
||||||
|
global const U32 bit18 = (1<<17);
|
||||||
|
global const U32 bit19 = (1<<18);
|
||||||
|
global const U32 bit20 = (1<<19);
|
||||||
|
global const U32 bit21 = (1<<20);
|
||||||
|
global const U32 bit22 = (1<<21);
|
||||||
|
global const U32 bit23 = (1<<22);
|
||||||
|
global const U32 bit24 = (1<<23);
|
||||||
|
global const U32 bit25 = (1<<24);
|
||||||
|
global const U32 bit26 = (1<<25);
|
||||||
|
global const U32 bit27 = (1<<26);
|
||||||
|
global const U32 bit28 = (1<<27);
|
||||||
|
global const U32 bit29 = (1<<28);
|
||||||
|
global const U32 bit30 = (1<<29);
|
||||||
|
global const U32 bit31 = (1<<30);
|
||||||
|
global const U32 bit32 = (1<<31);
|
||||||
|
|
||||||
|
global const U64 bit33 = (1ull<<32);
|
||||||
|
global const U64 bit34 = (1ull<<33);
|
||||||
|
global const U64 bit35 = (1ull<<34);
|
||||||
|
global const U64 bit36 = (1ull<<35);
|
||||||
|
global const U64 bit37 = (1ull<<36);
|
||||||
|
global const U64 bit38 = (1ull<<37);
|
||||||
|
global const U64 bit39 = (1ull<<38);
|
||||||
|
global const U64 bit40 = (1ull<<39);
|
||||||
|
global const U64 bit41 = (1ull<<40);
|
||||||
|
global const U64 bit42 = (1ull<<41);
|
||||||
|
global const U64 bit43 = (1ull<<42);
|
||||||
|
global const U64 bit44 = (1ull<<43);
|
||||||
|
global const U64 bit45 = (1ull<<44);
|
||||||
|
global const U64 bit46 = (1ull<<45);
|
||||||
|
global const U64 bit47 = (1ull<<46);
|
||||||
|
global const U64 bit48 = (1ull<<47);
|
||||||
|
global const U64 bit49 = (1ull<<48);
|
||||||
|
global const U64 bit50 = (1ull<<49);
|
||||||
|
global const U64 bit51 = (1ull<<50);
|
||||||
|
global const U64 bit52 = (1ull<<51);
|
||||||
|
global const U64 bit53 = (1ull<<52);
|
||||||
|
global const U64 bit54 = (1ull<<53);
|
||||||
|
global const U64 bit55 = (1ull<<54);
|
||||||
|
global const U64 bit56 = (1ull<<55);
|
||||||
|
global const U64 bit57 = (1ull<<56);
|
||||||
|
global const U64 bit58 = (1ull<<57);
|
||||||
|
global const U64 bit59 = (1ull<<58);
|
||||||
|
global const U64 bit60 = (1ull<<59);
|
||||||
|
global const U64 bit61 = (1ull<<60);
|
||||||
|
global const U64 bit62 = (1ull<<61);
|
||||||
|
global const U64 bit63 = (1ull<<62);
|
||||||
|
global const U64 bit64 = (1ull<<63);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ allen: Time
|
||||||
|
|
||||||
|
typedef enum WeekDay
|
||||||
|
{
|
||||||
|
WeekDay_Sun,
|
||||||
|
WeekDay_Mon,
|
||||||
|
WeekDay_Tue,
|
||||||
|
WeekDay_Wed,
|
||||||
|
WeekDay_Thu,
|
||||||
|
WeekDay_Fri,
|
||||||
|
WeekDay_Sat,
|
||||||
|
WeekDay_COUNT,
|
||||||
|
}
|
||||||
|
WeekDay;
|
||||||
|
|
||||||
|
typedef enum Month
|
||||||
|
{
|
||||||
|
Month_Jan,
|
||||||
|
Month_Feb,
|
||||||
|
Month_Mar,
|
||||||
|
Month_Apr,
|
||||||
|
Month_May,
|
||||||
|
Month_Jun,
|
||||||
|
Month_Jul,
|
||||||
|
Month_Aug,
|
||||||
|
Month_Sep,
|
||||||
|
Month_Oct,
|
||||||
|
Month_Nov,
|
||||||
|
Month_Dec,
|
||||||
|
Month_COUNT,
|
||||||
|
}
|
||||||
|
Month;
|
||||||
|
|
||||||
|
typedef struct DateTime DateTime;
|
||||||
|
struct DateTime
|
||||||
|
{
|
||||||
|
U16 micro_sec; // [0,999]
|
||||||
|
U16 msec; // [0,999]
|
||||||
|
U16 sec; // [0,60]
|
||||||
|
U16 min; // [0,59]
|
||||||
|
U16 hour; // [0,24]
|
||||||
|
U16 day; // [0,30]
|
||||||
|
union{
|
||||||
|
WeekDay week_day;
|
||||||
|
U32 wday;
|
||||||
|
};
|
||||||
|
union{
|
||||||
|
Month month;
|
||||||
|
U32 mon;
|
||||||
|
};
|
||||||
|
U32 year; // 1 = 1 CE, 0 = 1 BC
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef U64 DenseTime;
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ allen: Files
|
||||||
|
|
||||||
|
typedef U32 FilePropertyFlags;
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
FilePropertyFlag_IsFolder = (1 << 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct FileProperties FileProperties;
|
||||||
|
struct FileProperties
|
||||||
|
{
|
||||||
|
U64 size;
|
||||||
|
DenseTime modified;
|
||||||
|
DenseTime created;
|
||||||
|
FilePropertyFlags flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ Safe Casts
|
||||||
|
|
||||||
|
internal U16 safe_cast_u16(U32 x);
|
||||||
|
internal U32 safe_cast_u32(U64 x);
|
||||||
|
internal S32 safe_cast_s32(S64 x);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Large Base Type Functions
|
||||||
|
|
||||||
|
internal U128 u128_zero(void);
|
||||||
|
internal U128 u128_make(U64 v0, U64 v1);
|
||||||
|
internal B32 u128_match(U128 a, U128 b);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Bit Patterns
|
||||||
|
|
||||||
|
internal U32 u32_from_u64_saturate(U64 x);
|
||||||
|
internal U64 u64_up_to_pow2(U64 x);
|
||||||
|
internal S32 extend_sign32(U32 x, U32 size);
|
||||||
|
internal S64 extend_sign64(U64 x, U64 size);
|
||||||
|
|
||||||
|
internal F32 inf32(void);
|
||||||
|
internal F32 neg_inf32(void);
|
||||||
|
|
||||||
|
internal U16 bswap_u16(U16 x);
|
||||||
|
internal U32 bswap_u32(U32 x);
|
||||||
|
internal U64 bswap_u64(U64 x);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Enum -> Sign
|
||||||
|
|
||||||
|
internal S32 sign_from_side_S32(Side side);
|
||||||
|
internal F32 sign_from_side_F32(Side side);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Memory Functions
|
||||||
|
|
||||||
|
internal B32 memory_is_zero(void *ptr, U64 size);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Text 2D Coordinate/Range Functions
|
||||||
|
|
||||||
|
internal TxtPt txt_pt(S64 line, S64 column);
|
||||||
|
internal B32 txt_pt_match(TxtPt a, TxtPt b);
|
||||||
|
internal B32 txt_pt_less_than(TxtPt a, TxtPt b);
|
||||||
|
internal TxtPt txt_pt_min(TxtPt a, TxtPt b);
|
||||||
|
internal TxtPt txt_pt_max(TxtPt a, TxtPt b);
|
||||||
|
internal TxtRng txt_rng(TxtPt min, TxtPt max);
|
||||||
|
internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b);
|
||||||
|
internal TxtRng txt_rng_union(TxtRng a, TxtRng b);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Toolchain/Environment Enum Functions
|
||||||
|
|
||||||
|
internal U64 bit_size_from_arch(Architecture arch);
|
||||||
|
internal U64 max_instruction_size_from_arch(Architecture arch);
|
||||||
|
|
||||||
|
internal OperatingSystem operating_system_from_context(void);
|
||||||
|
internal Architecture architecture_from_context(void);
|
||||||
|
internal Compiler compiler_from_context(void);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Time Functions
|
||||||
|
|
||||||
|
internal DenseTime dense_time_from_date_time(DateTime date_time);
|
||||||
|
internal DateTime date_time_from_dense_time(DenseTime time);
|
||||||
|
internal DateTime date_time_from_micro_seconds(U64 time);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
//~ rjf: Non-Fancy Ring Buffer Reads/Writes
|
||||||
|
|
||||||
|
internal U64 ring_write(U8 *ring_base, U64 ring_size, U64 ring_pos, void *src_data, U64 src_data_size);
|
||||||
|
internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_data, U64 read_size);
|
||||||
|
#define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
||||||
|
#define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr)))
|
||||||
|
|
||||||
|
#endif // BASE_TYPES_H
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
Test(str8_list_substr)
|
|
||||||
{
|
|
||||||
String8List zero_list = {0};
|
|
||||||
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "a");
|
|
||||||
str8_list_pushf(arena, &list, "b");
|
|
||||||
str8_list_pushf(arena, &list, "c");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(0, 3));
|
|
||||||
String8 result = str8_list_join(arena, &list, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("abc"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "a");
|
|
||||||
str8_list_pushf(arena, &list, "b");
|
|
||||||
str8_list_pushf(arena, &list, "c");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(0, max_U64));
|
|
||||||
String8 result = str8_list_join(arena, &list, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("abc"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "a");
|
|
||||||
str8_list_pushf(arena, &list, "bcd");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(2, 3));
|
|
||||||
String8 result = str8_list_join(arena, &sub, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("c"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "a");
|
|
||||||
str8_list_pushf(arena, &list, "bcd");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(1, 2));
|
|
||||||
String8 result = str8_list_join(arena, &sub, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("b"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "ab");
|
|
||||||
str8_list_pushf(arena, &list, "cd");
|
|
||||||
str8_list_pushf(arena, &list, "ef");
|
|
||||||
String8List sub = str8_list_substr(arena, list, r1u64(1, 5));
|
|
||||||
String8 result = str8_list_join(arena, &sub, 0);
|
|
||||||
T_Ok(str8_match(result, str8_lit("bcde"), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
String8List list = {0};
|
|
||||||
str8_list_pushf(arena, &list, "abc");
|
|
||||||
|
|
||||||
String8List zero = str8_list_substr(arena, list, r1u64(0, 0));
|
|
||||||
T_Ok(MemoryMatchStruct(&zero, &zero_list));
|
|
||||||
|
|
||||||
String8List out_of_bounds_range = str8_list_substr(arena, list, r1u64(max_U64/2, max_U64));
|
|
||||||
T_Ok(MemoryMatchStruct(&out_of_bounds_range, &zero_list));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(bit_array)
|
|
||||||
{
|
|
||||||
for (U64 start=0; start<32*3; start++) {
|
|
||||||
for (U64 end=start; end<32*3; end++) {
|
|
||||||
U32 v[3] = { 0 };
|
|
||||||
for (U64 i=start; i<end; i++) {
|
|
||||||
v[i/32] |= 1 << (i%32);
|
|
||||||
}
|
|
||||||
for (U64 lo=0; lo<32*3; lo++) {
|
|
||||||
for (U64 hi=0; hi<32*3; hi++) {
|
|
||||||
U64 expected_idx = Min(hi, end) - 1;
|
|
||||||
B32 expected_r = hi <= start || lo >= end || lo >= hi || start >= end ? 0 : 1;
|
|
||||||
U64 idx = bit_array_scan_right_to_left32((U32Array){.v=v, .count=ArrayCount(v)}, lo, hi, 1);
|
|
||||||
B32 r = idx < hi;
|
|
||||||
T_Ok(r == expected_r);
|
|
||||||
if (r) {
|
|
||||||
T_Ok(idx == expected_idx);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(count_digits)
|
|
||||||
{
|
|
||||||
T_Ok(count_digits_u64(0, 10) == 1);
|
|
||||||
T_Ok(count_digits_u64(99, 10) == 2);
|
|
||||||
T_Ok(count_digits_u64(999, 10) == 3);
|
|
||||||
T_Ok(count_digits_u64(9999, 10) == 4);
|
|
||||||
T_Ok(count_digits_u64(99999, 10) == 5);
|
|
||||||
T_Ok(count_digits_u64(999999, 10) == 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(match_wildcard)
|
|
||||||
{
|
|
||||||
// empty strings
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit(""), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("**"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?*"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit(""), 0) == 0);
|
|
||||||
|
|
||||||
// exact
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("a"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), 0) == 0);
|
|
||||||
|
|
||||||
// ?
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("?"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("a?"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?b"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("??"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a?c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("???"), 0) == 0);
|
|
||||||
|
|
||||||
// *
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("b*"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("**"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a**c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("a*b*c"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*a*d*"), 0) == 0);
|
|
||||||
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abcd"), str8_lit("a*d"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abefcdgiescdfimde"), str8_lit("ab*cd?i*de"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("mississippi"), str8_lit("m*iss*ppi"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*b"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("aa"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("aa"), str8_lit("a"), 0) == 0);
|
|
||||||
|
|
||||||
// case insensitive
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("A"), StringMatchFlag_CaseInsensitive) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("FooBar"), str8_lit("foobar"), StringMatchFlag_CaseInsensitive) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("Foobar"), str8_lit("foo*"), StringMatchFlag_CaseInsensitive) == 1);
|
|
||||||
|
|
||||||
// right side sloppy
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("ab"), StringMatchFlag_RightSideSloppy) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit(""), StringMatchFlag_RightSideSloppy) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("a"), StringMatchFlag_RightSideSloppy) == 0);
|
|
||||||
|
|
||||||
// slash insensitive
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a/b"), str8_lit("a\\b"), StringMatchFlag_SlashInsensitive) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a/b/c"), str8_lit("a\\*\\c"), StringMatchFlag_SlashInsensitive) == 1);
|
|
||||||
|
|
||||||
// combined
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("Ab\\Cde"), str8_lit("ab/*e"), StringMatchFlag_CaseInsensitive|StringMatchFlag_SlashInsensitive) == 1);
|
|
||||||
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("*?*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("*?*"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit(""), str8_lit("*?*"), 0) == 0);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("abc"), str8_lit("?*?"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("ab"), str8_lit("?*?"), 0) == 1);
|
|
||||||
T_Ok(str8_match_wildcard(str8_lit("a"), str8_lit("?*?"), 0) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(hash_map)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 test_count = 256;
|
|
||||||
for EachIndex(i, test_count) { hash_map_push_u64_u64(arena, &hm, i, i*2); }
|
|
||||||
|
|
||||||
// test tombstone reuse
|
|
||||||
for (U64 i = 10; i < test_count; ++i) {
|
|
||||||
HashMapNode *test_node = hash_map_search(&hm, hash_map_hasher(str8_struct(&i)), (HashMapKey){ .key_u64 = i }, hash_map_match_u64);
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, i) == 1);
|
|
||||||
T_Ok(hash_map_push_u64_u64(arena, &hm, i, 10) == test_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete some items and after search them
|
|
||||||
for (U64 i = 0; i < 10; ++i) {
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, i));
|
|
||||||
}
|
|
||||||
T_Ok(hm.tombstone_count == 10);
|
|
||||||
for (U64 i = 0; i < 10; ++i) {
|
|
||||||
T_Ok(hash_map_search_u64_raw(&hm, i) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// extract pairs and test sorting
|
|
||||||
HashMapKeyValue *pairs = key_value_from_hash_map(arena, &hm);
|
|
||||||
sort_hash_map_key_value_u64(pairs, hm.count);
|
|
||||||
for (U64 i = 1; i < hm.count; ++i) {
|
|
||||||
T_Ok(pairs[i-1].key.key_u64 < pairs[i].key.key_u64);
|
|
||||||
}
|
|
||||||
|
|
||||||
// did purge put all the nodes on free list?
|
|
||||||
hash_map_purge(&hm);
|
|
||||||
U64 free_list_count = 0;
|
|
||||||
for (HashMapNode *n = hm.free_list; n != 0; n = n->next) { free_list_count += 1; }
|
|
||||||
T_Ok(free_list_count == test_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// test search through tombstones
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 hash = 12345;
|
|
||||||
|
|
||||||
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 1 }, .value = { .value_u64 = 10 } }, hash_map_match_u64);
|
|
||||||
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 2 }, .value = { .value_u64 = 20 } }, hash_map_match_u64);
|
|
||||||
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = 3 }, .value = { .value_u64 = 30 } }, hash_map_match_u64);
|
|
||||||
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, 1));
|
|
||||||
|
|
||||||
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = 2 }, hash_map_match_u64)->v.value.value_u64 == 20);
|
|
||||||
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = 3 }, hash_map_match_u64)->v.value.value_u64 == 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
// interleaved purges
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
for EachIndex(round, 100) {
|
|
||||||
for EachIndex(i, 256) { hash_map_push_u64_u64(arena, &hm, i, round); }
|
|
||||||
for (U64 i = 0; i < 256; i += 2) { hash_map_purge_u64(&hm, i); }
|
|
||||||
for (U64 i = 0; i < 256; i += 2) { hash_map_push_u64_u64(arena, &hm, i, round + 1); }
|
|
||||||
|
|
||||||
T_Ok(hm.count == 256);
|
|
||||||
T_Ok(hm.tombstone_count == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for EachIndex(i, 100) {
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, 123123123 + i) == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// empty hash map test
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
T_Ok(hash_map_search_u64_raw(&hm, 123) == 0);
|
|
||||||
T_Ok(hash_map_purge_u64(&hm, 123) == 0);
|
|
||||||
|
|
||||||
HashMapKeyValue *pairs = key_value_from_hash_map(arena, &hm);
|
|
||||||
T_Ok(pairs == 0 || hm.count == 0);
|
|
||||||
|
|
||||||
hash_map_purge(&hm);
|
|
||||||
T_Ok(hm.count == 0);
|
|
||||||
T_Ok(hm.tombstone_count == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// heavy collision
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 hash = 12345;
|
|
||||||
U64 count = 1024;
|
|
||||||
|
|
||||||
for EachIndex(i, count) {
|
|
||||||
hash_map_push(arena, &hm, hash, (HashMapKeyValue){ .key = { .key_u64 = i }, .value = { .value_u64 = i*3 } }, hash_map_match_u64);
|
|
||||||
}
|
|
||||||
|
|
||||||
for EachIndex(i, count) {
|
|
||||||
T_Ok(hash_map_search(&hm, hash, (HashMapKey){ .key_u64 = i }, hash_map_match_u64)->v.value.value_u64 == i*3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// duplicate key test
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 a = 1;
|
|
||||||
U64 b = 2;
|
|
||||||
|
|
||||||
HashMapNode *n0 = hash_map_push_u64_u64(arena, &hm, 1, a);
|
|
||||||
HashMapNode *n1 = hash_map_push_u64_u64(arena, &hm, 1, b);
|
|
||||||
|
|
||||||
T_Ok(hm.count == 1);
|
|
||||||
T_Ok(n0 == n1);
|
|
||||||
U64 test = *hash_map_search_u64_u64(&hm, 1);
|
|
||||||
T_Ok(test != b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// test paths
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 foo = 0;
|
|
||||||
U64 bar = 1;
|
|
||||||
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("c:/DEVEL/test"), &foo);
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("c:\\DEVEL\\test"), &foo);
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("c:/devel\\test"), &foo);
|
|
||||||
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("/mnt/devel"), &bar);
|
|
||||||
hash_map_push_path_raw(arena, &hm, str8_lit("/MNT/devel"), &bar);
|
|
||||||
|
|
||||||
T_Ok(hm.count == 2);
|
|
||||||
|
|
||||||
T_Ok(hash_map_search_path_raw(&hm, str8_lit("c:/devel/test")) == &foo);
|
|
||||||
T_Ok(hash_map_search_path_raw(&hm, str8_lit("c:\\devel\\TEST")) == &foo);
|
|
||||||
T_Ok(hash_map_search_path_raw(&hm, str8_lit("/mnt/devel")) == &bar);
|
|
||||||
T_Ok(hash_map_search_path_raw(&hm, str8_lit("/MNT/DEVEL")) == &bar);
|
|
||||||
}
|
|
||||||
|
|
||||||
// test strings
|
|
||||||
{
|
|
||||||
HashMap hm = {0};
|
|
||||||
|
|
||||||
U64 foo = 0;
|
|
||||||
U64 bar = 1;
|
|
||||||
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("c:/DEVEL/test"), &foo);
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("c:\\DEVEL\\test"), &foo);
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("c:/devel\\test"), &foo);
|
|
||||||
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("/mnt/devel"), &bar);
|
|
||||||
hash_map_push_string_raw(arena, &hm, str8_lit("/MNT/devel"), &bar);
|
|
||||||
|
|
||||||
T_Ok(hm.count == 5);
|
|
||||||
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:/DEVEL/test")) == &foo);
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:\\DEVEL\\test")) == &foo);
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("c:/devel\\test")) == &foo);
|
|
||||||
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("/mnt/devel")) == &bar);
|
|
||||||
T_Ok(hash_map_search_string_raw(&hm, str8_lit("/MNT/devel")) == &bar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,630 +0,0 @@
|
|||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Numerics
|
|
||||||
|
|
||||||
@table(name val)
|
|
||||||
CV_NumericKindTable:
|
|
||||||
{
|
|
||||||
{CHAR 0x8000}
|
|
||||||
{SHORT 0x8001}
|
|
||||||
{USHORT 0x8002}
|
|
||||||
{LONG 0x8003}
|
|
||||||
{ULONG 0x8004}
|
|
||||||
{FLOAT32 0x8005}
|
|
||||||
{FLOAT64 0x8006}
|
|
||||||
{FLOAT80 0x8007}
|
|
||||||
{FLOAT128 0x8008}
|
|
||||||
{QUADWORD 0x8009}
|
|
||||||
{UQUADWORD 0x800a}
|
|
||||||
{FLOAT48 0x800b}
|
|
||||||
{COMPLEX32 0x800c}
|
|
||||||
{COMPLEX64 0x800d}
|
|
||||||
{COMPLEX80 0x800e}
|
|
||||||
{COMPLEX128 0x800f}
|
|
||||||
{VARSTRING 0x8010}
|
|
||||||
{OCTWORD 0x8017}
|
|
||||||
{UOCTWORD 0x8018}
|
|
||||||
{DECIMAL 0x8019}
|
|
||||||
{DATE 0x801a}
|
|
||||||
{UTF8STRING 0x801b}
|
|
||||||
{FLOAT16 0x801c}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_NumericKind:
|
|
||||||
{
|
|
||||||
@expand(CV_NumericKindTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_NumericKind)
|
|
||||||
cv_string_from_numeric_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_NumericKindTable a) `case CV_NumericKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Architectures
|
|
||||||
|
|
||||||
@table(name val)
|
|
||||||
CV_ArchTable:
|
|
||||||
{
|
|
||||||
{8080 0x00}
|
|
||||||
{8086 0x01}
|
|
||||||
{80286 0x02}
|
|
||||||
{80386 0x03}
|
|
||||||
{80486 0x04}
|
|
||||||
{PENTIUM 0x05}
|
|
||||||
{PENTIUMII 0x06}
|
|
||||||
{PENTIUMIII 0x07}
|
|
||||||
{MIPS 0x10}
|
|
||||||
{MIPS16 0x11}
|
|
||||||
{MIPS32 0x12}
|
|
||||||
{MIPS64 0x13}
|
|
||||||
{MIPSI 0x14}
|
|
||||||
{MIPSII 0x15}
|
|
||||||
{MIPSIII 0x16}
|
|
||||||
{MIPSIV 0x17}
|
|
||||||
{MIPSV 0x18}
|
|
||||||
{M68000 0x20}
|
|
||||||
{M68010 0x21}
|
|
||||||
{M68020 0x22}
|
|
||||||
{M68030 0x23}
|
|
||||||
{M68040 0x24}
|
|
||||||
{ALPHA 0x30}
|
|
||||||
{ALPHA_21164 0x31}
|
|
||||||
{ALPHA_21164A 0x32}
|
|
||||||
{ALPHA_21264 0x33}
|
|
||||||
{ALPHA_21364 0x34}
|
|
||||||
{PPC601 0x40}
|
|
||||||
{PPC603 0x41}
|
|
||||||
{PPC604 0x42}
|
|
||||||
{PPC620 0x43}
|
|
||||||
{PPCFP 0x44}
|
|
||||||
{PPCBE 0x45}
|
|
||||||
{SH3 0x50}
|
|
||||||
{SH3E 0x51}
|
|
||||||
{SH3DSP 0x52}
|
|
||||||
{SH4 0x53}
|
|
||||||
{SHMEDIA 0x54}
|
|
||||||
{ARM3 0x60}
|
|
||||||
{ARM4 0x61}
|
|
||||||
{ARM4T 0x62}
|
|
||||||
{ARM5 0x63}
|
|
||||||
{ARM5T 0x64}
|
|
||||||
{ARM6 0x65}
|
|
||||||
{ARM_XMAC 0x66}
|
|
||||||
{ARM_WMMX 0x67}
|
|
||||||
{ARM7 0x68}
|
|
||||||
{OMNI 0x70}
|
|
||||||
{IA64_1 0x80}
|
|
||||||
{IA64_2 0x81}
|
|
||||||
{CEE 0x90}
|
|
||||||
{AM33 0xA0}
|
|
||||||
{M32R 0xB0}
|
|
||||||
{TRICORE 0xC0}
|
|
||||||
{X64 0xD0}
|
|
||||||
{EBC 0xE0}
|
|
||||||
{THUMB 0xF0}
|
|
||||||
{ARMNT 0xF4}
|
|
||||||
{ARM64 0xF6}
|
|
||||||
{D3D11_SHADER 0x100}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_Arch:
|
|
||||||
{
|
|
||||||
@expand(CV_ArchTable a) `$(a.name) = $(a.val)`,
|
|
||||||
`IA64 = CV_Arch_IA64_1`,
|
|
||||||
`PENTIUMPRO = CV_Arch_PENTIUMII`,
|
|
||||||
`MIPSR4000 = CV_Arch_MIPS`,
|
|
||||||
`ALPHA_21064 = CV_Arch_ALPHA`,
|
|
||||||
`AMD64 = CV_Arch_X64`,
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_Arch)
|
|
||||||
cv_string_from_arch:
|
|
||||||
{
|
|
||||||
@expand(CV_ArchTable a) `case CV_Arch_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Registers
|
|
||||||
|
|
||||||
@table(name val) CV_AllRegTable:
|
|
||||||
{
|
|
||||||
{ERR 30000}
|
|
||||||
{TEB 30001}
|
|
||||||
{TIMER 30002}
|
|
||||||
{EFAD1 30003}
|
|
||||||
{EFAD2 30004}
|
|
||||||
{EFAD3 30005}
|
|
||||||
{VFRAME 30006}
|
|
||||||
{HANDLE 30007}
|
|
||||||
{PARAMS 30008}
|
|
||||||
{LOCALS 30009}
|
|
||||||
{TID 30010}
|
|
||||||
{ENV 30011}
|
|
||||||
{CMDLN 30012}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_AllReg:
|
|
||||||
{
|
|
||||||
@expand(CV_AllRegTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Sym Kinds
|
|
||||||
|
|
||||||
@table(name header_type_name val) CV_SymKindTable:
|
|
||||||
{
|
|
||||||
{COMPILE Compile 0x0001}
|
|
||||||
{REGISTER_16t - 0x0002}
|
|
||||||
{CONSTANT_16t - 0x0003}
|
|
||||||
{UDT_16t - 0x0004}
|
|
||||||
{SSEARCH StartSearch 0x0005}
|
|
||||||
{END - 0x0006}
|
|
||||||
{SKIP - 0x0007}
|
|
||||||
{CVRESERVE - 0x0008}
|
|
||||||
{OBJNAME_ST - 0x0009}
|
|
||||||
{ENDARG - 0x000a}
|
|
||||||
{COBOLUDT_16t - 0x000b}
|
|
||||||
{MANYREG_16t - 0x000c}
|
|
||||||
{RETURN Return 0x000d}
|
|
||||||
{ENTRYTHIS - 0x000e}
|
|
||||||
{BPREL16 - 0x0100}
|
|
||||||
{LDATA16 - 0x0101}
|
|
||||||
{GDATA16 - 0x0102}
|
|
||||||
{PUB16 - 0x0103}
|
|
||||||
{LPROC16 - 0x0104}
|
|
||||||
{GPROC16 - 0x0105}
|
|
||||||
{THUNK16 - 0x0106}
|
|
||||||
{BLOCK16 - 0x0107}
|
|
||||||
{WITH16 - 0x0108}
|
|
||||||
{LABEL16 - 0x0109}
|
|
||||||
{CEXMODEL16 - 0x010a}
|
|
||||||
{VFTABLE16 - 0x010b}
|
|
||||||
{REGREL16 - 0x010c}
|
|
||||||
{BPREL32_16t - 0x0200}
|
|
||||||
{LDATA32_16t - 0x0201}
|
|
||||||
{GDATA32_16t - 0x0202}
|
|
||||||
{PUB32_16t - 0x0203}
|
|
||||||
{LPROC32_16t - 0x0204}
|
|
||||||
{GPROC32_16t - 0x0205}
|
|
||||||
{THUNK32_ST - 0x0206}
|
|
||||||
{BLOCK32_ST - 0x0207}
|
|
||||||
{WITH32_ST - 0x0208}
|
|
||||||
{LABEL32_ST - 0x0209}
|
|
||||||
{CEXMODEL32 - 0x020a}
|
|
||||||
{VFTABLE32_16t - 0x020b}
|
|
||||||
{REGREL32_16t - 0x020c}
|
|
||||||
{LTHREAD32_16t - 0x020d}
|
|
||||||
{GTHREAD32_16t - 0x020e}
|
|
||||||
{SLINK32 SLink32 0x020f}
|
|
||||||
{LPROCMIPS_16t - 0x0300}
|
|
||||||
{GPROCMIPS_16t - 0x0301}
|
|
||||||
{PROCREF_ST - 0x0400}
|
|
||||||
{DATAREF_ST - 0x0401}
|
|
||||||
{ALIGN - 0x0402}
|
|
||||||
{LPROCREF_ST - 0x0403}
|
|
||||||
{OEM OEM 0x0404}
|
|
||||||
{TI16_MAX - 0x1000}
|
|
||||||
{CONSTANT_ST - 0x1002}
|
|
||||||
{UDT_ST - 0x1003}
|
|
||||||
{COBOLUDT_ST - 0x1004}
|
|
||||||
{MANYREG_ST - 0x1005}
|
|
||||||
{BPREL32_ST - 0x1006}
|
|
||||||
{LDATA32_ST - 0x1007}
|
|
||||||
{GDATA32_ST - 0x1008}
|
|
||||||
{PUB32_ST - 0x1009}
|
|
||||||
{LPROC32_ST - 0x100a}
|
|
||||||
{GPROC32_ST - 0x100b}
|
|
||||||
{VFTABLE32 VPath32 0x100c}
|
|
||||||
{REGREL32_ST - 0x100d}
|
|
||||||
{LTHREAD32_ST - 0x100e}
|
|
||||||
{GTHREAD32_ST - 0x100f}
|
|
||||||
{LPROCMIPS_ST - 0x1010}
|
|
||||||
{GPROCMIPS_ST - 0x1011}
|
|
||||||
{FRAMEPROC Frameproc 0x1012}
|
|
||||||
{COMPILE2_ST - 0x1013}
|
|
||||||
{MANYREG2_ST - 0x1014}
|
|
||||||
{LPROCIA64_ST - 0x1015}
|
|
||||||
{GPROCIA64_ST - 0x1016}
|
|
||||||
{LOCALSLOT_ST - 0x1017}
|
|
||||||
{PARAMSLOT_ST - 0x1018}
|
|
||||||
{ANNOTATION Annotation 0x1019}
|
|
||||||
{GMANPROC_ST - 0x101a}
|
|
||||||
{LMANPROC_ST - 0x101b}
|
|
||||||
{RESERVED1 - 0x101c}
|
|
||||||
{RESERVED2 - 0x101d}
|
|
||||||
{RESERVED3 - 0x101e}
|
|
||||||
{RESERVED4 - 0x101f}
|
|
||||||
{LMANDATA_ST - 0x1020}
|
|
||||||
{GMANDATA_ST - 0x1021}
|
|
||||||
{MANFRAMEREL_ST - 0x1022}
|
|
||||||
{MANREGISTER_ST - 0x1023}
|
|
||||||
{MANSLOT_ST - 0x1024}
|
|
||||||
{MANMANYREG_ST - 0x1025}
|
|
||||||
{MANREGREL_ST - 0x1026}
|
|
||||||
{MANMANYREG2_ST - 0x1027}
|
|
||||||
{MANTYPREF - 0x1028}
|
|
||||||
{UNAMESPACE_ST - 0x1029}
|
|
||||||
{ST_MAX - 0x1100}
|
|
||||||
{OBJNAME ObjName 0x1101}
|
|
||||||
{THUNK32 Thunk32 0x1102}
|
|
||||||
{BLOCK32 Block32 0x1103}
|
|
||||||
{WITH32 - 0x1104}
|
|
||||||
{LABEL32 Label32 0x1105}
|
|
||||||
{REGISTER Register 0x1106}
|
|
||||||
{CONSTANT Constant 0x1107}
|
|
||||||
{UDT UDT 0x1108}
|
|
||||||
{COBOLUDT - 0x1109}
|
|
||||||
{MANYREG Manyreg 0x110a}
|
|
||||||
{BPREL32 BPRel32 0x110b}
|
|
||||||
{LDATA32 Data32 0x110c}
|
|
||||||
{GDATA32 Data32 0x110d}
|
|
||||||
{PUB32 Pub32 0x110e}
|
|
||||||
{LPROC32 Proc32 0x110f}
|
|
||||||
{GPROC32 Proc32 0x1110}
|
|
||||||
{REGREL32 Regrel32 0x1111}
|
|
||||||
{LTHREAD32 Thread32 0x1112}
|
|
||||||
{GTHREAD32 Thread32 0x1113}
|
|
||||||
{LPROCMIPS - 0x1114}
|
|
||||||
{GPROCMIPS - 0x1115}
|
|
||||||
{COMPILE2 Compile2 0x1116}
|
|
||||||
{MANYREG2 Manyreg2 0x1117}
|
|
||||||
{LPROCIA64 - 0x1118}
|
|
||||||
{GPROCIA64 - 0x1119}
|
|
||||||
{LOCALSLOT Slot 0x111a}
|
|
||||||
{PARAMSLOT - 0x111b}
|
|
||||||
{LMANDATA - 0x111c}
|
|
||||||
{GMANDATA - 0x111d}
|
|
||||||
{MANFRAMEREL AttrFrameRel 0x111e}
|
|
||||||
{MANREGISTER AttrReg 0x111f}
|
|
||||||
{MANSLOT - 0x1120}
|
|
||||||
{MANMANYREG AttrManyReg 0x1121}
|
|
||||||
{MANREGREL AttrRegRel 0x1122}
|
|
||||||
{MANMANYREG2 - 0x1123}
|
|
||||||
{UNAMESPACE UNamespace 0x1124}
|
|
||||||
{PROCREF Ref2 0x1125}
|
|
||||||
{DATAREF Ref2 0x1126}
|
|
||||||
{LPROCREF Ref2 0x1127}
|
|
||||||
{ANNOTATIONREF - 0x1128}
|
|
||||||
{TOKENREF - 0x1129}
|
|
||||||
{GMANPROC - 0x112a}
|
|
||||||
{LMANPROC - 0x112b}
|
|
||||||
{TRAMPOLINE Trampoline 0x112c}
|
|
||||||
{MANCONSTANT - 0x112d}
|
|
||||||
{ATTR_FRAMEREL AttrFrameRel 0x112e}
|
|
||||||
{ATTR_REGISTER AttrReg 0x112f}
|
|
||||||
{ATTR_REGREL AttrRegRel 0x1130}
|
|
||||||
{ATTR_MANYREG AttrManyReg 0x1131}
|
|
||||||
{SEPCODE Sepcode 0x1132}
|
|
||||||
{DEFRANGE_2005 - 0x1134}
|
|
||||||
{DEFRANGE2_2005 - 0x1135}
|
|
||||||
{SECTION Section 0x1136}
|
|
||||||
{COFFGROUP CoffGroup 0x1137}
|
|
||||||
{EXPORT Export 0x1138}
|
|
||||||
{CALLSITEINFO CallSiteInfo 0x1139}
|
|
||||||
{FRAMECOOKIE FrameCookie 0x113a}
|
|
||||||
{DISCARDED Discarded 0x113b}
|
|
||||||
{COMPILE3 Compile3 0x113c}
|
|
||||||
{ENVBLOCK EnvBlock 0x113d}
|
|
||||||
{LOCAL Local 0x113e}
|
|
||||||
{DEFRANGE - 0x113f}
|
|
||||||
{DEFRANGE_SUBFIELD DefrangeSubfield 0x1140}
|
|
||||||
{DEFRANGE_REGISTER DefrangeRegister 0x1141}
|
|
||||||
{DEFRANGE_FRAMEPOINTER_REL DefrangeFramepointerRel 0x1142}
|
|
||||||
{DEFRANGE_SUBFIELD_REGISTER DefrangeSubfieldRegister 0x1143}
|
|
||||||
{DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE DefrangeFramepointerRelFullScope 0x1144}
|
|
||||||
{DEFRANGE_REGISTER_REL DefrangeRegisterRel 0x1145}
|
|
||||||
{LPROC32_ID - 0x1146}
|
|
||||||
{GPROC32_ID - 0x1147}
|
|
||||||
{LPROCMIPS_ID - 0x1148}
|
|
||||||
{GPROCMIPS_ID - 0x1149}
|
|
||||||
{LPROCIA64_ID - 0x114a}
|
|
||||||
{GPROCIA64_ID - 0x114b}
|
|
||||||
{BUILDINFO BuildInfo 0x114c}
|
|
||||||
{INLINESITE InlineSite 0x114d}
|
|
||||||
{INLINESITE_END - 0x114e}
|
|
||||||
{PROC_ID_END - 0x114f}
|
|
||||||
{DEFRANGE_HLSL - 0x1150}
|
|
||||||
{GDATA_HLSL - 0x1151}
|
|
||||||
{LDATA_HLSL - 0x1152}
|
|
||||||
{FILESTATIC FileStatic 0x1153}
|
|
||||||
{LPROC32_DPC - 0x1155}
|
|
||||||
{LPROC32_DPC_ID - 0x1156}
|
|
||||||
{DEFRANGE_DPC_PTR_TAG - 0x1157}
|
|
||||||
{DPC_SYM_TAG_MAP - 0x1158}
|
|
||||||
{ARMSWITCHTABLE - 0x1159}
|
|
||||||
{CALLEES FunctionList 0x115a}
|
|
||||||
{CALLERS FunctionList 0x115b}
|
|
||||||
{POGODATA PogoInfo 0x115c}
|
|
||||||
{INLINESITE2 InlineSite2 0x115d}
|
|
||||||
{HEAPALLOCSITE HeapAllocSite 0x115e}
|
|
||||||
{MOD_TYPEREF ModTypeRef 0x115f}
|
|
||||||
{REF_MINIPDB RefMiniPdb 0x1160}
|
|
||||||
{PDBMAP - 0x1161}
|
|
||||||
{GDATA_HLSL32 - 0x1162}
|
|
||||||
{LDATA_HLSL32 - 0x1163}
|
|
||||||
{GDATA_HLSL32_EX - 0x1164}
|
|
||||||
{LDATA_HLSL32_EX - 0x1165}
|
|
||||||
{FASTLINK FastLink 0x1167}
|
|
||||||
{INLINEES Inlinees 0x1168}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_SymKind:
|
|
||||||
{
|
|
||||||
@expand(CV_SymKindTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_SymKind)
|
|
||||||
cv_string_from_sym_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_SymKindTable a) `case CV_SymKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions)
|
|
||||||
{
|
|
||||||
`internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions) @c_file
|
|
||||||
{
|
|
||||||
`internal U64`;
|
|
||||||
`cv_header_struct_size_from_sym_kind(CV_SymKind v)`;
|
|
||||||
`{`;
|
|
||||||
`U64 result = 0;`;
|
|
||||||
`switch(v)`;
|
|
||||||
`{`;
|
|
||||||
`default:{}break;`;
|
|
||||||
@expand(CV_SymKindTable a) `$(a.header_type_name != "-" -> "case CV_SymKind_"..a.name..":{result = sizeof(CV_Sym"..a.header_type_name..");}break;")`;
|
|
||||||
`}`;
|
|
||||||
`return result;`;
|
|
||||||
`}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Basic Types
|
|
||||||
|
|
||||||
@table(name val type_name)
|
|
||||||
CV_BasicTypeTable:
|
|
||||||
{
|
|
||||||
{NOTYPE 0x00 "" }
|
|
||||||
{ABS 0x01 "" }
|
|
||||||
{SEGMENT 0x02 "" }
|
|
||||||
{VOID 0x03 "void" }
|
|
||||||
{CURRENCY 0x04 "" }
|
|
||||||
{NBASICSTR 0x05 "" }
|
|
||||||
{FBASICSTR 0x06 "" }
|
|
||||||
{NOTTRANS 0x07 "" }
|
|
||||||
{HRESULT 0x08 "HRESULT" }
|
|
||||||
{CHAR 0x10 "CHAR" }
|
|
||||||
{SHORT 0x11 "SHORT" }
|
|
||||||
{LONG 0x12 "LONG" }
|
|
||||||
{QUAD 0x13 "QUAD" }
|
|
||||||
{OCT 0x14 "OCT" }
|
|
||||||
{UCHAR 0x20 "UCHAR" }
|
|
||||||
{USHORT 0x21 "USHORT" }
|
|
||||||
{ULONG 0x22 "ULONG" }
|
|
||||||
{UQUAD 0x23 "UQUAD" }
|
|
||||||
{UOCT 0x24 "UOCT" }
|
|
||||||
{BOOL8 0x30 "BOOL8" }
|
|
||||||
{BOOL16 0x31 "BOOL16" }
|
|
||||||
{BOOL32 0x32 "BOOL32" }
|
|
||||||
{BOOL64 0x33 "BOOL64" }
|
|
||||||
{FLOAT32 0x40 "FLOAT32" }
|
|
||||||
{FLOAT64 0x41 "FLOAT64" }
|
|
||||||
{FLOAT80 0x42 "FLOAT80" }
|
|
||||||
{FLOAT128 0x43 "FLOAT128" }
|
|
||||||
{FLOAT48 0x44 "FLOAT48" }
|
|
||||||
{FLOAT32PP 0x45 "FLOAT32PP" }
|
|
||||||
{FLOAT16 0x46 "FLOAT16" }
|
|
||||||
{COMPLEX32 0x50 "ComplexF32" }
|
|
||||||
{COMPLEX64 0x51 "ComplexF64" }
|
|
||||||
{COMPLEX80 0x52 "ComplexF80" }
|
|
||||||
{COMPLEX128 0x53 "ComplexF128" }
|
|
||||||
{BIT 0x60 "" }
|
|
||||||
{PASCHAR 0x61 "" }
|
|
||||||
{BOOL32FF 0x62 "BOOL32FF" }
|
|
||||||
{INT8 0x68 "int8" }
|
|
||||||
{UINT8 0x69 "uint8" }
|
|
||||||
{RCHAR 0x70 "char" }
|
|
||||||
{WCHAR 0x71 "WCHAR" }
|
|
||||||
{INT16 0x72 "int16" }
|
|
||||||
{UINT16 0x73 "uint16" }
|
|
||||||
{INT32 0x74 "int32" }
|
|
||||||
{UINT32 0x75 "uint32" }
|
|
||||||
{INT64 0x76 "int64" }
|
|
||||||
{UINT64 0x77 "uint64" }
|
|
||||||
{INT128 0x78 "int128" }
|
|
||||||
{UINT128 0x79 "uint128" }
|
|
||||||
{CHAR16 0x7a "char16" }
|
|
||||||
{CHAR32 0x7b "char32" }
|
|
||||||
{CHAR8 0x7c "char" }
|
|
||||||
{PTR 0xf0 "PTR" }
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U8) CV_BasicType:
|
|
||||||
{
|
|
||||||
@expand(CV_BasicTypeTable a) `$(a.name) = $(a.val)`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_BasicType) cv_string_from_basic_type:
|
|
||||||
{
|
|
||||||
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.name)");}break`
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_BasicType) cv_type_name_from_basic_type:
|
|
||||||
{
|
|
||||||
@expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.type_name)");}break`
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
//~ rjf: CV Leaf Kinds
|
|
||||||
|
|
||||||
@table(name header_type_name val)
|
|
||||||
CV_LeafKindTable:
|
|
||||||
{
|
|
||||||
{NOTYPE - 0x0000}
|
|
||||||
{MODIFIER_16t - 0x0001}
|
|
||||||
{POINTER_16t - 0x0002}
|
|
||||||
{ARRAY_16t - 0x0003}
|
|
||||||
{CLASS_16t - 0x0004}
|
|
||||||
{STRUCTURE_16t - 0x0005}
|
|
||||||
{UNION_16t - 0x0006}
|
|
||||||
{ENUM_16t - 0x0007}
|
|
||||||
{PROCEDURE_16t - 0x0008}
|
|
||||||
{MFUNCTION_16t - 0x0009}
|
|
||||||
{VTSHAPE VTShape 0x000a}
|
|
||||||
{COBOL0_16t - 0x000b}
|
|
||||||
{COBOL1 - 0x000c}
|
|
||||||
{BARRAY_16t - 0x000d}
|
|
||||||
{LABEL Label 0x000e}
|
|
||||||
{NULL - 0x000f}
|
|
||||||
{NOTTRAN - 0x0010}
|
|
||||||
{DIMARRAY_16t - 0x0011}
|
|
||||||
{VFTPATH_16t - 0x0012}
|
|
||||||
{PRECOMP_16t - 0x0013}
|
|
||||||
{ENDPRECOMP - 0x0014}
|
|
||||||
{OEM_16t - 0x0015}
|
|
||||||
{TYPESERVER_ST - 0x0016}
|
|
||||||
{SKIP_16t - 0x0200}
|
|
||||||
{ARGLIST_16t - 0x0201}
|
|
||||||
{DEFARG_16t - 0x0202}
|
|
||||||
{LIST - 0x0203}
|
|
||||||
{FIELDLIST_16t - 0x0204}
|
|
||||||
{DERIVED_16t - 0x0205}
|
|
||||||
{BITFIELD_16t - 0x0206}
|
|
||||||
{METHODLIST_16t - 0x0207}
|
|
||||||
{DIMCONU_16t - 0x0208}
|
|
||||||
{DIMCONLU_16t - 0x0209}
|
|
||||||
{DIMVARU_16t - 0x020a}
|
|
||||||
{DIMVARLU_16t - 0x020b}
|
|
||||||
{REFSYM - 0x020c}
|
|
||||||
{BCLASS_16t - 0x0400}
|
|
||||||
{VBCLASS_16t - 0x0401}
|
|
||||||
{IVBCLASS_16t - 0x0402}
|
|
||||||
{ENUMERATE_ST - 0x0403}
|
|
||||||
{FRIENDFCN_16t - 0x0404}
|
|
||||||
{INDEX_16t - 0x0405}
|
|
||||||
{MEMBER_16t - 0x0406}
|
|
||||||
{STMEMBER_16t - 0x0407}
|
|
||||||
{METHOD_16t - 0x0408}
|
|
||||||
{NESTTYPE_16t - 0x0409}
|
|
||||||
{VFUNCTAB_16t - 0x040a}
|
|
||||||
{FRIENDCLS_16t - 0x040b}
|
|
||||||
{ONEMETHOD_16t - 0x040c}
|
|
||||||
{VFUNCOFF_16t - 0x040d}
|
|
||||||
{TI16_MAX - 0x1000}
|
|
||||||
{MODIFIER Modifier 0x1001}
|
|
||||||
{POINTER Pointer 0x1002}
|
|
||||||
{ARRAY_ST - 0x1003}
|
|
||||||
{CLASS_ST - 0x1004}
|
|
||||||
{STRUCTURE_ST - 0x1005}
|
|
||||||
{UNION_ST - 0x1006}
|
|
||||||
{ENUM_ST - 0x1007}
|
|
||||||
{PROCEDURE Procedure 0x1008}
|
|
||||||
{MFUNCTION MFunction 0x1009}
|
|
||||||
{COBOL0 - 0x100a}
|
|
||||||
{BARRAY - 0x100b}
|
|
||||||
{DIMARRAY_ST - 0x100c}
|
|
||||||
{VFTPATH VFPath 0x100d}
|
|
||||||
{PRECOMP_ST - 0x100e}
|
|
||||||
{OEM - 0x100f}
|
|
||||||
{ALIAS_ST - 0x1010}
|
|
||||||
{OEM2 - 0x1011}
|
|
||||||
{SKIP Skip 0x1200}
|
|
||||||
{ARGLIST ArgList 0x1201}
|
|
||||||
{DEFARG_ST - 0x1202}
|
|
||||||
{FIELDLIST - 0x1203}
|
|
||||||
{DERIVED - 0x1204}
|
|
||||||
{BITFIELD BitField 0x1205}
|
|
||||||
{METHODLIST MethodListMember 0x1206}
|
|
||||||
{DIMCONU - 0x1207}
|
|
||||||
{DIMCONLU - 0x1208}
|
|
||||||
{DIMVARU - 0x1209}
|
|
||||||
{DIMVARLU - 0x120a}
|
|
||||||
{BCLASS BClass 0x1400}
|
|
||||||
{VBCLASS VBClass 0x1401}
|
|
||||||
{IVBCLASS - 0x1402}
|
|
||||||
{FRIENDFCN_ST - 0x1403}
|
|
||||||
{INDEX Index 0x1404}
|
|
||||||
{MEMBER_ST - 0x1405}
|
|
||||||
{STMEMBER_ST - 0x1406}
|
|
||||||
{METHOD_ST - 0x1407}
|
|
||||||
{NESTTYPE_ST - 0x1408}
|
|
||||||
{VFUNCTAB VFuncTab 0x1409}
|
|
||||||
{FRIENDCLS - 0x140a}
|
|
||||||
{ONEMETHOD_ST - 0x140b}
|
|
||||||
{VFUNCOFF VFuncOff 0x140c}
|
|
||||||
{NESTTYPEEX_ST - 0x140d}
|
|
||||||
{MEMBERMODIFY_ST - 0x140e}
|
|
||||||
{MANAGED_ST - 0x140f}
|
|
||||||
{ST_MAX - 0x1500}
|
|
||||||
{TYPESERVER TypeServer 0x1501}
|
|
||||||
{ENUMERATE Enumerate 0x1502}
|
|
||||||
{ARRAY Array 0x1503}
|
|
||||||
{CLASS Struct 0x1504}
|
|
||||||
{STRUCTURE Struct 0x1505}
|
|
||||||
{UNION Union 0x1506}
|
|
||||||
{ENUM Enum 0x1507}
|
|
||||||
{DIMARRAY - 0x1508}
|
|
||||||
{PRECOMP PreComp 0x1509}
|
|
||||||
{ALIAS Alias 0x150a}
|
|
||||||
{DEFARG - 0x150b}
|
|
||||||
{FRIENDFCN - 0x150c}
|
|
||||||
{MEMBER Member 0x150d}
|
|
||||||
{STMEMBER StMember 0x150e}
|
|
||||||
{METHOD Method 0x150f}
|
|
||||||
{NESTTYPE NestType 0x1510}
|
|
||||||
{ONEMETHOD OneMethod 0x1511}
|
|
||||||
{NESTTYPEEX NestTypeEx 0x1512}
|
|
||||||
{MEMBERMODIFY - 0x1513}
|
|
||||||
{MANAGED - 0x1514}
|
|
||||||
{TYPESERVER2 TypeServer2 0x1515}
|
|
||||||
{STRIDED_ARRAY - 0x1516}
|
|
||||||
{HLSL - 0x1517}
|
|
||||||
{MODIFIER_EX - 0x1518}
|
|
||||||
{INTERFACE Struct 0x1519}
|
|
||||||
{BINTERFACE - 0x151a}
|
|
||||||
{VECTOR - 0x151b}
|
|
||||||
{MATRIX - 0x151c}
|
|
||||||
{VFTABLE - 0x151d}
|
|
||||||
{FUNC_ID FuncId 0x1601}
|
|
||||||
{MFUNC_ID MFuncId 0x1602}
|
|
||||||
{BUILDINFO BuildInfo 0x1603}
|
|
||||||
{SUBSTR_LIST SubstrList 0x1604}
|
|
||||||
{STRING_ID StringId 0x1605}
|
|
||||||
{UDT_SRC_LINE UDTSrcLine 0x1606}
|
|
||||||
{UDT_MOD_SRC_LINE UDTModSrcLine 0x1607}
|
|
||||||
{CLASS2 Struct2 0x1608}
|
|
||||||
{STRUCT2 Struct2 0x1609}
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum(U16) CV_LeafKind:
|
|
||||||
{
|
|
||||||
@expand(CV_LeafKindTable a) `$(a.name) = $(a.val)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@enum2string_switch(CV_LeafKind)
|
|
||||||
cv_string_from_leaf_kind:
|
|
||||||
{
|
|
||||||
@expand(CV_LeafKindTable a) `case CV_LeafKind_$(a.name):{result = str8_lit("$(a.name)");}break`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions)
|
|
||||||
{
|
|
||||||
`internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);`;
|
|
||||||
}
|
|
||||||
|
|
||||||
@gen(functions) @c_file
|
|
||||||
{
|
|
||||||
`internal U64`;
|
|
||||||
`cv_header_struct_size_from_leaf_kind(CV_LeafKind v)`;
|
|
||||||
`{`;
|
|
||||||
`U64 result = 0;`;
|
|
||||||
`switch(v)`;
|
|
||||||
`{`;
|
|
||||||
`default:{}break;`;
|
|
||||||
@expand(CV_LeafKindTable a) `$(a.header_type_name != "-" -> "case CV_LeafKind_"..a.name..":{result = sizeof(CV_Leaf"..a.header_type_name..");}break;")`;
|
|
||||||
`}`;
|
|
||||||
`return result;`;
|
|
||||||
`}`;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
internal String8
|
|
||||||
cv_string_from_numeric(Arena *arena, CV_NumericParsed num)
|
|
||||||
{
|
|
||||||
String8 result = str8_zero();
|
|
||||||
switch (num.kind) {
|
|
||||||
case CV_NumericKind_FLOAT16: NotImplemented; break; // TODO: format float16
|
|
||||||
case CV_NumericKind_FLOAT32: result = push_str8f(arena, "%f", (F64)(*(F32*)num.val)); break;
|
|
||||||
case CV_NumericKind_FLOAT48: NotImplemented; break; // TODO: format float48
|
|
||||||
case CV_NumericKind_FLOAT64: result = push_str8f(arena, "%f", *(F64*)num.val); break;
|
|
||||||
case CV_NumericKind_FLOAT80: NotImplemented; break; // TODO: format float80
|
|
||||||
case CV_NumericKind_FLOAT128: NotImplemented; break; // TODO: format float128
|
|
||||||
case CV_NumericKind_CHAR: result = push_str8f(arena, "%d", *(S8 *)num.val); break;
|
|
||||||
case CV_NumericKind_SHORT: result = push_str8f(arena, "%d", *(S16*)num.val); break;
|
|
||||||
case CV_NumericKind_LONG: result = push_str8f(arena, "%d", *(S32*)num.val); break;
|
|
||||||
case CV_NumericKind_QUADWORD: result = push_str8f(arena, "%lld", *(S64*)num.val); break;
|
|
||||||
case CV_NumericKind_USHORT: result = push_str8f(arena, "%u", *(U16*)num.val); break;
|
|
||||||
case CV_NumericKind_ULONG: result = push_str8f(arena, "%u", *(U32*)num.val); break;
|
|
||||||
case CV_NumericKind_UQUADWORD: result = push_str8f(arena, "%llu", *(U64*)num.val); break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
// Copyright (c) Epic Games Tools
|
|
||||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
||||||
|
|
||||||
#ifndef CODEVIEW_DUMP_H
|
|
||||||
#define CODEVIEW_DUMP_H
|
|
||||||
|
|
||||||
internal String8 cv_string_from_numeric(Arena *arena, CV_NumericParsed num);
|
|
||||||
|
|
||||||
#endif // CODEVIEW_DUMP_H
|
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user